From 89f76e6cd97299bc21967ecb473d301e40f21b00 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Tue, 17 Mar 2026 08:32:05 -0700 Subject: [PATCH 01/28] feat(mcp): Add plugin-scoped MCP tool support Add plugin manifest support for HTTP MCP servers and a turn-local MCP tool manager that progressively exposes plugin tools when matching skills load. Pause turns on MCP auth challenges and resume the same session after the callback instead of failing the turn. Persist loaded skills and active MCP providers across resume, and align the resumed callback path with normal reply delivery and thread-state persistence so Slack state stays consistent. Co-Authored-By: Codex --- packages/junior/package.json | 1 + packages/junior/src/chat/mcp/auth-store.ts | 220 + packages/junior/src/chat/mcp/client.ts | 164 + .../junior/src/chat/mcp/oauth-provider.ts | 166 + packages/junior/src/chat/mcp/oauth.ts | 122 + packages/junior/src/chat/mcp/tool-manager.ts | 288 + packages/junior/src/chat/oauth-flow.ts | 2 +- packages/junior/src/chat/plugins/manifest.ts | 47 + packages/junior/src/chat/plugins/registry.ts | 27 + packages/junior/src/chat/plugins/types.ts | 9 + packages/junior/src/chat/respond.ts | 310 +- packages/junior/src/chat/skills.ts | 8 +- packages/junior/src/chat/state.ts | 39 + packages/junior/src/chat/turn/errors.ts | 9 +- .../junior/src/handlers/mcp-oauth-callback.ts | 529 + packages/junior/src/handlers/router.ts | 29 +- packages/junior/tests/handlers-router.test.ts | 125 +- .../junior/tests/mcp-oauth-callback.test.ts | 397 + .../tests/plugin-registry-packages.test.ts | 167 + .../tests/unit/mcp/tool-manager.test.ts | 179 + .../tests/unit/skills-plugin-provider.test.ts | 93 + pnpm-lock.yaml | 17100 ++++++---------- specs/agent-session-resumability-spec.md | 15 +- specs/oauth-flows-spec.md | 62 +- specs/plugin-spec.md | 28 +- 25 files changed, 9343 insertions(+), 10793 deletions(-) create mode 100644 packages/junior/src/chat/mcp/auth-store.ts create mode 100644 packages/junior/src/chat/mcp/client.ts create mode 100644 packages/junior/src/chat/mcp/oauth-provider.ts create mode 100644 packages/junior/src/chat/mcp/oauth.ts create mode 100644 packages/junior/src/chat/mcp/tool-manager.ts create mode 100644 packages/junior/src/handlers/mcp-oauth-callback.ts create mode 100644 packages/junior/tests/mcp-oauth-callback.test.ts create mode 100644 packages/junior/tests/unit/mcp/tool-manager.test.ts create mode 100644 packages/junior/tests/unit/skills-plugin-provider.test.ts diff --git a/packages/junior/package.json b/packages/junior/package.json index 568109a8..3d753bad 100644 --- a/packages/junior/package.json +++ b/packages/junior/package.json @@ -42,6 +42,7 @@ "@chat-adapter/state-redis": "4.20.2", "@mariozechner/pi-agent-core": "^0.59.0", "@mariozechner/pi-ai": "^0.59.0", + "@modelcontextprotocol/sdk": "1.27.1", "@sinclair/typebox": "^0.34.48", "@slack/web-api": "^7.15.0", "@vercel/queue": "^0.1.4", diff --git a/packages/junior/src/chat/mcp/auth-store.ts b/packages/junior/src/chat/mcp/auth-store.ts new file mode 100644 index 00000000..be1a3b70 --- /dev/null +++ b/packages/junior/src/chat/mcp/auth-store.ts @@ -0,0 +1,220 @@ +import type { + OAuthClientInformationMixed, + OAuthTokens, +} from "@modelcontextprotocol/sdk/shared/auth.js"; +import type { OAuthDiscoveryState } from "@modelcontextprotocol/sdk/client/auth.js"; +import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; +import { getStateAdapter } from "@/chat/state"; + +const MCP_AUTH_SESSION_PREFIX = "junior:mcp_auth_session"; +const MCP_AUTH_CREDENTIALS_PREFIX = "junior:mcp_auth_credentials"; +const MCP_AUTH_SESSION_TTL_MS = 24 * 60 * 60 * 1000; +const MCP_AUTH_CREDENTIALS_TTL_MS = 30 * 24 * 60 * 60 * 1000; + +export interface McpAuthSessionState { + authSessionId: string; + provider: string; + userId: string; + conversationId: string; + sessionId: string; + userMessage: string; + channelId?: string; + threadTs?: string; + toolChannelId?: string; + configuration?: Record; + artifactState?: ThreadArtifactsState; + authorizationUrl?: string; + codeVerifier?: string; + createdAtMs: number; + updatedAtMs: number; +} + +export interface McpStoredOAuthCredentials { + clientInformation?: OAuthClientInformationMixed; + discoveryState?: OAuthDiscoveryState; + tokens?: OAuthTokens; +} + +function sessionKey(authSessionId: string): string { + return `${MCP_AUTH_SESSION_PREFIX}:${authSessionId}`; +} + +function credentialsKey(userId: string, provider: string): string { + return `${MCP_AUTH_CREDENTIALS_PREFIX}:${userId}:${provider}`; +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null; +} + +function parseMcpAuthSession(value: unknown): McpAuthSessionState | undefined { + if (typeof value !== "string") { + return undefined; + } + + try { + const parsed = JSON.parse(value) as Record; + if (!isRecord(parsed)) { + return undefined; + } + + if ( + typeof parsed.authSessionId !== "string" || + typeof parsed.provider !== "string" || + typeof parsed.userId !== "string" || + typeof parsed.conversationId !== "string" || + typeof parsed.sessionId !== "string" || + typeof parsed.userMessage !== "string" || + typeof parsed.createdAtMs !== "number" || + typeof parsed.updatedAtMs !== "number" + ) { + return undefined; + } + + return { + authSessionId: parsed.authSessionId, + provider: parsed.provider, + userId: parsed.userId, + conversationId: parsed.conversationId, + sessionId: parsed.sessionId, + userMessage: parsed.userMessage, + createdAtMs: parsed.createdAtMs, + updatedAtMs: parsed.updatedAtMs, + ...(typeof parsed.channelId === "string" + ? { channelId: parsed.channelId } + : {}), + ...(typeof parsed.threadTs === "string" + ? { threadTs: parsed.threadTs } + : {}), + ...(typeof parsed.toolChannelId === "string" + ? { toolChannelId: parsed.toolChannelId } + : {}), + ...(isRecord(parsed.configuration) + ? { configuration: parsed.configuration } + : {}), + ...(isRecord(parsed.artifactState) + ? { artifactState: parsed.artifactState as ThreadArtifactsState } + : {}), + ...(typeof parsed.authorizationUrl === "string" + ? { authorizationUrl: parsed.authorizationUrl } + : {}), + ...(typeof parsed.codeVerifier === "string" + ? { codeVerifier: parsed.codeVerifier } + : {}), + }; + } catch { + return undefined; + } +} + +function parseStoredCredentials( + value: unknown, +): McpStoredOAuthCredentials | undefined { + if (typeof value !== "string") { + return undefined; + } + + try { + const parsed = JSON.parse(value) as Record; + if (!isRecord(parsed)) { + return undefined; + } + + return { + ...(isRecord(parsed.clientInformation) + ? { + clientInformation: + parsed.clientInformation as OAuthClientInformationMixed, + } + : {}), + ...(isRecord(parsed.discoveryState) + ? { + discoveryState: + parsed.discoveryState as unknown as OAuthDiscoveryState, + } + : {}), + ...(isRecord(parsed.tokens) + ? { tokens: parsed.tokens as OAuthTokens } + : {}), + }; + } catch { + return undefined; + } +} + +export async function getMcpAuthSession( + authSessionId: string, +): Promise { + await getStateAdapter().connect(); + return parseMcpAuthSession( + await getStateAdapter().get(sessionKey(authSessionId)), + ); +} + +export async function putMcpAuthSession( + session: McpAuthSessionState, + ttlMs: number = MCP_AUTH_SESSION_TTL_MS, +): Promise { + await getStateAdapter().connect(); + await getStateAdapter().set( + sessionKey(session.authSessionId), + JSON.stringify(session), + ttlMs, + ); +} + +export async function patchMcpAuthSession( + authSessionId: string, + patch: Partial, +): Promise { + const current = await getMcpAuthSession(authSessionId); + if (!current) { + throw new Error(`Unknown MCP auth session: ${authSessionId}`); + } + + const next: McpAuthSessionState = { + ...current, + ...patch, + authSessionId: current.authSessionId, + provider: current.provider, + userId: current.userId, + conversationId: current.conversationId, + sessionId: current.sessionId, + userMessage: current.userMessage, + createdAtMs: current.createdAtMs, + updatedAtMs: Date.now(), + }; + await putMcpAuthSession(next); + return next; +} + +export async function deleteMcpAuthSession( + authSessionId: string, +): Promise { + await getStateAdapter().connect(); + await getStateAdapter().delete(sessionKey(authSessionId)); +} + +export async function getMcpStoredOAuthCredentials( + userId: string, + provider: string, +): Promise { + await getStateAdapter().connect(); + return parseStoredCredentials( + await getStateAdapter().get(credentialsKey(userId, provider)), + ); +} + +export async function putMcpStoredOAuthCredentials( + userId: string, + provider: string, + value: McpStoredOAuthCredentials, + ttlMs: number = MCP_AUTH_CREDENTIALS_TTL_MS, +): Promise { + await getStateAdapter().connect(); + await getStateAdapter().set( + credentialsKey(userId, provider), + JSON.stringify(value), + ttlMs, + ); +} diff --git a/packages/junior/src/chat/mcp/client.ts b/packages/junior/src/chat/mcp/client.ts new file mode 100644 index 00000000..f512031c --- /dev/null +++ b/packages/junior/src/chat/mcp/client.ts @@ -0,0 +1,164 @@ +import { Client } from "@modelcontextprotocol/sdk/client"; +import { + UnauthorizedError, + type OAuthClientProvider, +} from "@modelcontextprotocol/sdk/client/auth.js"; +import { + StreamableHTTPClientTransport, + StreamableHTTPError, +} from "@modelcontextprotocol/sdk/client/streamableHttp.js"; +import type { PluginDefinition } from "@/chat/plugins/types"; + +type ListedTool = Awaited>["tools"][number]; +type ToolCallResult = Awaited>; + +const MCP_CLIENT_INFO = { + name: "junior-mcp-client", + version: "1.0.0", +}; + +export class McpAuthorizationRequiredError extends Error { + readonly provider: string; + + constructor(provider: string, message: string) { + super(message); + this.name = "McpAuthorizationRequiredError"; + this.provider = provider; + } +} + +export interface PluginMcpClientOptions { + authProvider?: OAuthClientProvider; + fetch?: typeof fetch; + sessionId?: string; +} + +export class PluginMcpClient { + private client?: Client; + private transport?: StreamableHTTPClientTransport; + private listedTools?: ListedTool[]; + + constructor( + private readonly plugin: PluginDefinition, + private readonly options: PluginMcpClientOptions = {}, + ) {} + + async listTools(): Promise { + if (this.listedTools) { + return [...this.listedTools]; + } + + const client = await this.getClient(); + const discovered: ListedTool[] = []; + const seen = new Set(); + let cursor: string | undefined; + + do { + const result = await this.wrapAuth( + client.listTools(cursor ? { cursor } : undefined), + ); + for (const tool of result.tools) { + if (seen.has(tool.name)) { + continue; + } + seen.add(tool.name); + discovered.push(tool); + } + cursor = result.nextCursor; + } while (cursor); + + this.listedTools = discovered.sort((left, right) => + left.name.localeCompare(right.name), + ); + return [...this.listedTools]; + } + + async callTool( + name: string, + args: Record | undefined, + ): Promise { + const client = await this.getClient(); + return await this.wrapAuth( + client.callTool({ + name, + ...(args && Object.keys(args).length > 0 ? { arguments: args } : {}), + }), + ); + } + + async close(): Promise { + this.listedTools = undefined; + + const transport = this.transport; + this.transport = undefined; + this.client = undefined; + + if (transport) { + await transport.close(); + } + } + + private async getClient(): Promise { + if (this.client) { + return this.client; + } + + const mcp = this.plugin.manifest.mcp; + if (!mcp) { + throw new Error( + `Plugin "${this.plugin.manifest.name}" does not declare MCP config`, + ); + } + + const requestInit: RequestInit = {}; + if (mcp.headers && Object.keys(mcp.headers).length > 0) { + requestInit.headers = new Headers(mcp.headers); + } + + const transport = new StreamableHTTPClientTransport(new URL(mcp.url), { + ...(Object.keys(requestInit).length > 0 ? { requestInit } : {}), + ...(this.options.fetch ? { fetch: this.options.fetch } : {}), + ...(this.options.authProvider + ? { authProvider: this.options.authProvider } + : {}), + ...(this.options.sessionId ? { sessionId: this.options.sessionId } : {}), + }); + const client = new Client(MCP_CLIENT_INFO, { + capabilities: {}, + }); + + await this.wrapAuth(client.connect(transport)); + + this.transport = transport; + this.client = client; + return client; + } + + private async wrapAuth(promise: Promise): Promise { + try { + return await promise; + } catch (error) { + if (error instanceof McpAuthorizationRequiredError) { + throw error; + } + if (error instanceof UnauthorizedError) { + throw new McpAuthorizationRequiredError( + this.plugin.manifest.name, + `MCP authorization required for plugin "${this.plugin.manifest.name}"`, + ); + } + if (error instanceof StreamableHTTPError && error.code === 401) { + throw new McpAuthorizationRequiredError( + this.plugin.manifest.name, + `MCP authorization required for plugin "${this.plugin.manifest.name}"`, + ); + } + throw error; + } + } +} + +export type { + ListedTool as PluginMcpListedTool, + ToolCallResult as PluginMcpToolCallResult, +}; diff --git a/packages/junior/src/chat/mcp/oauth-provider.ts b/packages/junior/src/chat/mcp/oauth-provider.ts new file mode 100644 index 00000000..67f334ea --- /dev/null +++ b/packages/junior/src/chat/mcp/oauth-provider.ts @@ -0,0 +1,166 @@ +import type { + OAuthClientInformationMixed, + OAuthClientMetadata, + OAuthTokens, +} from "@modelcontextprotocol/sdk/shared/auth.js"; +import type { + OAuthClientProvider, + OAuthDiscoveryState, +} from "@modelcontextprotocol/sdk/client/auth.js"; +import { + getMcpAuthSession, + getMcpStoredOAuthCredentials, + patchMcpAuthSession, + putMcpStoredOAuthCredentials, +} from "./auth-store"; + +function createClientMetadata(callbackUrl: string): OAuthClientMetadata { + return { + client_name: "Junior MCP Client", + redirect_uris: [callbackUrl], + grant_types: ["authorization_code", "refresh_token"], + response_types: ["code"], + token_endpoint_auth_method: "none", + }; +} + +export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { + readonly clientMetadata: OAuthClientMetadata; + + constructor( + readonly authSessionId: string, + private readonly callbackUrl: string, + ) { + this.clientMetadata = createClientMetadata(callbackUrl); + } + + get redirectUrl(): string { + return this.callbackUrl; + } + + async state(): Promise { + return this.authSessionId; + } + + async clientInformation(): Promise { + const session = await this.requireSession(); + const credentials = await getMcpStoredOAuthCredentials( + session.userId, + session.provider, + ); + return credentials?.clientInformation; + } + + async saveClientInformation( + clientInformation: OAuthClientInformationMixed, + ): Promise { + const session = await this.requireSession(); + const credentials = + (await getMcpStoredOAuthCredentials(session.userId, session.provider)) ?? + {}; + await putMcpStoredOAuthCredentials(session.userId, session.provider, { + ...credentials, + clientInformation, + }); + } + + async tokens(): Promise { + const session = await this.requireSession(); + const credentials = await getMcpStoredOAuthCredentials( + session.userId, + session.provider, + ); + return credentials?.tokens; + } + + async saveTokens(tokens: OAuthTokens): Promise { + const session = await this.requireSession(); + const credentials = + (await getMcpStoredOAuthCredentials(session.userId, session.provider)) ?? + {}; + await putMcpStoredOAuthCredentials(session.userId, session.provider, { + ...credentials, + tokens, + }); + } + + async redirectToAuthorization(authorizationUrl: URL): Promise { + await patchMcpAuthSession(this.authSessionId, { + authorizationUrl: authorizationUrl.toString(), + }); + } + + async saveCodeVerifier(codeVerifier: string): Promise { + await patchMcpAuthSession(this.authSessionId, { codeVerifier }); + } + + async codeVerifier(): Promise { + const session = await this.requireSession(); + if (!session.codeVerifier) { + throw new Error("Missing MCP OAuth code verifier"); + } + return session.codeVerifier; + } + + async saveDiscoveryState(state: OAuthDiscoveryState): Promise { + const session = await this.requireSession(); + const credentials = + (await getMcpStoredOAuthCredentials(session.userId, session.provider)) ?? + {}; + await putMcpStoredOAuthCredentials(session.userId, session.provider, { + ...credentials, + discoveryState: state, + }); + } + + async discoveryState(): Promise { + const session = await this.requireSession(); + const credentials = await getMcpStoredOAuthCredentials( + session.userId, + session.provider, + ); + return credentials?.discoveryState; + } + + async invalidateCredentials( + scope: "all" | "client" | "tokens" | "verifier" | "discovery", + ): Promise { + const session = await this.requireSession(); + const credentials = + (await getMcpStoredOAuthCredentials(session.userId, session.provider)) ?? + {}; + + await putMcpStoredOAuthCredentials(session.userId, session.provider, { + ...(scope === "tokens" || scope === "all" + ? {} + : credentials.tokens + ? { tokens: credentials.tokens } + : {}), + ...(scope === "client" || scope === "all" + ? {} + : credentials.clientInformation + ? { clientInformation: credentials.clientInformation } + : {}), + ...(scope === "discovery" || scope === "all" + ? {} + : credentials.discoveryState + ? { discoveryState: credentials.discoveryState } + : {}), + }); + + if (scope === "verifier" || scope === "all") { + await patchMcpAuthSession(this.authSessionId, { + codeVerifier: undefined, + authorizationUrl: scope === "all" ? undefined : undefined, + }); + } + } + + private async requireSession() { + const session = await getMcpAuthSession(this.authSessionId); + if (!session) { + throw new Error(`Unknown MCP auth session: ${this.authSessionId}`); + } + return session; + } +} diff --git a/packages/junior/src/chat/mcp/oauth.ts b/packages/junior/src/chat/mcp/oauth.ts new file mode 100644 index 00000000..743ee867 --- /dev/null +++ b/packages/junior/src/chat/mcp/oauth.ts @@ -0,0 +1,122 @@ +import { randomUUID } from "node:crypto"; +import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; +import { resolveBaseUrl } from "@/chat/oauth-flow"; +import { getPluginDefinition } from "@/chat/plugins/registry"; +import type { PluginDefinition } from "@/chat/plugins/types"; +import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; +import { + getMcpAuthSession, + putMcpAuthSession, + type McpAuthSessionState, +} from "./auth-store"; +import { StateBackedMcpOAuthClientProvider } from "./oauth-provider"; + +export function getMcpOAuthCallbackPath(provider: string): string { + return `/api/oauth/callback/mcp/${provider}`; +} + +function requirePluginWithMcp(provider: string): PluginDefinition { + const plugin = getPluginDefinition(provider); + if (!plugin?.manifest.mcp) { + throw new Error(`Plugin "${provider}" does not support MCP`); + } + return plugin; +} + +export async function createMcpOAuthClientProvider(input: { + provider: string; + conversationId: string; + sessionId: string; + userId: string; + userMessage: string; + channelId?: string; + threadTs?: string; + toolChannelId?: string; + configuration?: Record; + artifactState?: ThreadArtifactsState; +}): Promise { + requirePluginWithMcp(input.provider); + + const baseUrl = resolveBaseUrl(); + if (!baseUrl) { + throw new Error( + "Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)", + ); + } + + const authSessionId = randomUUID(); + const callbackUrl = `${baseUrl}${getMcpOAuthCallbackPath(input.provider)}`; + const session: McpAuthSessionState = { + authSessionId, + provider: input.provider, + userId: input.userId, + conversationId: input.conversationId, + sessionId: input.sessionId, + userMessage: input.userMessage, + createdAtMs: Date.now(), + updatedAtMs: Date.now(), + ...(input.channelId ? { channelId: input.channelId } : {}), + ...(input.threadTs ? { threadTs: input.threadTs } : {}), + ...(input.toolChannelId ? { toolChannelId: input.toolChannelId } : {}), + ...(input.configuration ? { configuration: input.configuration } : {}), + ...(input.artifactState ? { artifactState: input.artifactState } : {}), + }; + await putMcpAuthSession(session); + + return new StateBackedMcpOAuthClientProvider(authSessionId, callbackUrl); +} + +export async function finalizeMcpAuthorization( + provider: string, + authSessionId: string, + authorizationCode: string, +): Promise { + const plugin = requirePluginWithMcp(provider); + const mcp = plugin.manifest.mcp; + if (!mcp) { + throw new Error(`Plugin "${provider}" does not support MCP`); + } + const session = await getMcpAuthSession(authSessionId); + if (!session) { + throw new Error(`Unknown MCP auth session: ${authSessionId}`); + } + if (session.provider !== provider) { + throw new Error( + `MCP auth session provider mismatch: expected "${provider}", got "${session.provider}"`, + ); + } + + const baseUrl = resolveBaseUrl(); + if (!baseUrl) { + throw new Error( + "Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)", + ); + } + + const callbackUrl = `${baseUrl}${getMcpOAuthCallbackPath(provider)}`; + const authProvider = new StateBackedMcpOAuthClientProvider( + authSessionId, + callbackUrl, + ); + const requestInit: RequestInit = {}; + if (mcp.headers && Object.keys(mcp.headers).length > 0) { + requestInit.headers = new Headers(mcp.headers); + } + const transport = new StreamableHTTPClientTransport(new URL(mcp.url), { + ...(Object.keys(requestInit).length > 0 ? { requestInit } : {}), + authProvider, + }); + + try { + await transport.finishAuth(authorizationCode); + } finally { + await transport.close(); + } + + const nextSession = await getMcpAuthSession(authSessionId); + if (!nextSession) { + throw new Error(`Unknown MCP auth session: ${authSessionId}`); + } + + return nextSession; +} diff --git a/packages/junior/src/chat/mcp/tool-manager.ts b/packages/junior/src/chat/mcp/tool-manager.ts new file mode 100644 index 00000000..bcd8d1cf --- /dev/null +++ b/packages/junior/src/chat/mcp/tool-manager.ts @@ -0,0 +1,288 @@ +import type { AgentTool } from "@mariozechner/pi-agent-core"; +import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; +import type { TSchema } from "@sinclair/typebox"; +import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"; +import type { SkillMetadata } from "@/chat/skills"; +import type { PluginDefinition } from "@/chat/plugins/types"; +import { + McpAuthorizationRequiredError, + PluginMcpClient, + type PluginMcpListedTool, + type PluginMcpToolCallResult, +} from "./client"; + +function normalizeMcpToolName(provider: string, toolName: string): string { + return `mcp__${provider}__${toolName}`; +} + +function summarizeStructuredContent(value: unknown): string | undefined { + if (!value || typeof value !== "object") { + return undefined; + } + return JSON.stringify(value, null, 2); +} + +function summarizeResourcePart(part: { + type: "resource"; + resource: + | { uri: string; text: string; mimeType?: string } + | { uri: string; blob: string; mimeType?: string }; +}): string { + if ("text" in part.resource) { + return part.resource.text; + } + + return [ + `Resource: ${part.resource.uri}`, + ...(part.resource.mimeType ? [`Mime Type: ${part.resource.mimeType}`] : []), + `Blob bytes (base64): ${part.resource.blob.length}`, + ].join("\n"); +} + +function toAgentToolContent( + result: PluginMcpToolCallResult, +): Array { + if ("toolResult" in result) { + return [ + { + type: "text", + text: JSON.stringify(result.toolResult, null, 2), + }, + ]; + } + + const content: Array = []; + + for (const part of result.content) { + if (part.type === "text") { + content.push({ type: "text", text: part.text }); + continue; + } + if (part.type === "image") { + content.push({ + type: "image", + data: part.data, + mimeType: part.mimeType, + }); + continue; + } + if (part.type === "audio") { + content.push({ + type: "text", + text: `Audio output (${part.mimeType}, ${part.data.length} base64 chars)`, + }); + continue; + } + if (part.type === "resource_link") { + content.push({ + type: "text", + text: part.uri, + }); + continue; + } + content.push({ + type: "text", + text: summarizeResourcePart(part), + }); + } + + if (content.length > 0) { + return content; + } + + const structured = summarizeStructuredContent(result.structuredContent); + if (structured) { + return [{ type: "text", text: structured }]; + } + + return [{ type: "text", text: "ok" }]; +} + +function describeMcpTool(provider: string, tool: PluginMcpListedTool): string { + const prefix = `[${provider}]`; + const details = tool.description?.trim() || tool.title?.trim() || tool.name; + return `${prefix} ${details}`; +} + +function extractMcpErrorMessage(result: PluginMcpToolCallResult): string { + if ("toolResult" in result) { + return JSON.stringify(result.toolResult, null, 2); + } + + const textParts = result.content + .filter( + (part): part is Extract => + part.type === "text", + ) + .map((part) => part.text.trim()) + .filter((text) => text.length > 0); + if (textParts.length > 0) { + return textParts.join("\n\n"); + } + + const structured = summarizeStructuredContent(result.structuredContent); + if (structured) { + return structured; + } + + return "MCP tool call failed"; +} + +export interface McpToolManagerOptions { + authProviderFactory?: ( + plugin: PluginDefinition, + ) => + | OAuthClientProvider + | undefined + | Promise; + fetch?: typeof fetch; + onAuthorizationRequired?: ( + provider: string, + error: McpAuthorizationRequiredError, + ) => Promise | void; + sessionId?: string; +} + +export class McpToolManager { + private readonly pluginsByProvider = new Map(); + private readonly activeProviders = new Set(); + private readonly clientsByProvider = new Map(); + private readonly toolsByProvider = new Map[]>(); + + constructor( + plugins: PluginDefinition[], + private readonly options: McpToolManagerOptions = {}, + ) { + for (const plugin of plugins) { + if (plugin.manifest.mcp) { + this.pluginsByProvider.set(plugin.manifest.name, plugin); + } + } + } + + getActiveProviders(): string[] { + return [...this.activeProviders].sort((left, right) => + left.localeCompare(right), + ); + } + + getActiveTools(): AgentTool[] { + return this.getActiveProviders().flatMap( + (provider) => this.toolsByProvider.get(provider) ?? [], + ); + } + + async activateForSkill( + skill: Pick, + ): Promise { + if (!skill.pluginProvider) { + return false; + } + + return await this.activateProvider(skill.pluginProvider); + } + + async activateProvider(provider: string): Promise { + if (this.activeProviders.has(provider)) { + return false; + } + + const plugin = this.pluginsByProvider.get(provider); + if (!plugin?.manifest.mcp) { + return false; + } + + const client = await this.getClient(plugin); + + try { + const tools = await client.listTools(); + this.toolsByProvider.set( + provider, + tools.map((tool) => this.toAgentTool(plugin, client, tool)), + ); + this.activeProviders.add(provider); + return true; + } catch (error) { + if ( + error instanceof McpAuthorizationRequiredError && + this.options.onAuthorizationRequired + ) { + await this.options.onAuthorizationRequired(plugin.manifest.name, error); + } + throw error; + } + } + + async close(): Promise { + for (const client of this.clientsByProvider.values()) { + await client.close(); + } + this.clientsByProvider.clear(); + this.toolsByProvider.clear(); + this.activeProviders.clear(); + } + + private async getClient(plugin: PluginDefinition): Promise { + const existing = this.clientsByProvider.get(plugin.manifest.name); + if (existing) { + return existing; + } + + const authProvider = this.options.authProviderFactory + ? await this.options.authProviderFactory(plugin) + : undefined; + const client = new PluginMcpClient(plugin, { + ...(authProvider ? { authProvider } : {}), + ...(this.options.fetch ? { fetch: this.options.fetch } : {}), + ...(this.options.sessionId ? { sessionId: this.options.sessionId } : {}), + }); + this.clientsByProvider.set(plugin.manifest.name, client); + return client; + } + + private toAgentTool( + plugin: PluginDefinition, + client: PluginMcpClient, + tool: PluginMcpListedTool, + ): AgentTool { + return { + name: normalizeMcpToolName(plugin.manifest.name, tool.name), + label: tool.title?.trim() || tool.name, + description: describeMcpTool(plugin.manifest.name, tool), + parameters: tool.inputSchema as unknown as TSchema, + execute: async (_toolCallId, params) => { + const args = + typeof params === "object" && params !== null + ? (params as Record) + : {}; + + try { + const result = await client.callTool(tool.name, args); + if ("isError" in result && result.isError) { + throw new Error(extractMcpErrorMessage(result)); + } + + return { + content: toAgentToolContent(result), + details: { + provider: plugin.manifest.name, + tool: tool.name, + rawResult: result, + }, + }; + } catch (error) { + if ( + error instanceof McpAuthorizationRequiredError && + this.options.onAuthorizationRequired + ) { + await this.options.onAuthorizationRequired( + plugin.manifest.name, + error, + ); + } + throw error; + } + }, + }; + } +} diff --git a/packages/junior/src/chat/oauth-flow.ts b/packages/junior/src/chat/oauth-flow.ts index f451eca1..fe987f9f 100644 --- a/packages/junior/src/chat/oauth-flow.ts +++ b/packages/junior/src/chat/oauth-flow.ts @@ -45,7 +45,7 @@ export function resolveBaseUrl(): string | undefined { * Authorization links must only be visible to the requesting user. * Try in-context private delivery first, then fall back to a DM. */ -async function deliverPrivateMessage(input: { +export async function deliverPrivateMessage(input: { channelId?: string; threadTs?: string; userId: string; diff --git a/packages/junior/src/chat/plugins/manifest.ts b/packages/junior/src/chat/plugins/manifest.ts index 14894d5a..43727312 100644 --- a/packages/junior/src/chat/plugins/manifest.ts +++ b/packages/junior/src/chat/plugins/manifest.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { parse as parseYaml } from "yaml"; import type { GitHubAppCredentials, + PluginMcpConfig, OAuthBearerCredentials, PluginCredentials, PluginManifest, @@ -187,6 +188,16 @@ const oauthSourceSchema = z }) .passthrough(); +const mcpSourceSchema = z + .object({ + transport: nonEmptyTrimmedString.refine((value) => value === "http", { + error: 'must be "http"', + }), + url: httpsUrlString, + headers: stringMapSchema.optional(), + }) + .passthrough(); + const targetSourceSchema = z .object({ type: z.literal("repo", { @@ -227,6 +238,11 @@ const manifestSourceSchema = z error: "must be an array", }) .optional(), + mcp: z + .record(z.string(), z.unknown(), { + error: "must be an object", + }) + .optional(), oauth: z .record(z.string(), z.unknown(), { error: "must be an object", @@ -497,6 +513,30 @@ function normalizeRuntimePostinstall( return parsed.length > 0 ? parsed : undefined; } +function normalizeMcp( + data: Record, + name: string, +): PluginMcpConfig { + const result = mcpSourceSchema.safeParse(data); + if (!result.success) { + throw new Error(issueMessage(result.error, `Plugin ${name} mcp`)); + } + + return { + transport: "http", + url: result.data.url, + ...(result.data.headers + ? { + headers: normalizeStringMap( + result.data.headers, + `Plugin ${name} mcp.headers`, + { forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }, + ), + } + : {}), + } satisfies PluginMcpConfig; +} + export function parsePluginManifest(raw: string, dir: string): PluginManifest { let parsedYaml: unknown; try { @@ -552,6 +592,11 @@ export function parsePluginManifest(raw: string, dir: string): PluginManifest { `Plugin ${(parsedYaml as { name?: string }).name ?? "unknown"} runtime-postinstall must be an array`, ); } + if (path === "mcp") { + throw new Error( + `Plugin ${(parsedYaml as { name?: string }).name ?? "unknown"} mcp must be an object`, + ); + } if (path === "oauth") { throw new Error( `Plugin ${(parsedYaml as { name?: string }).name ?? "unknown"} oauth must be an object`, @@ -591,6 +636,7 @@ export function parsePluginManifest(raw: string, dir: string): PluginManifest { const runtimePostinstall = data["runtime-postinstall"] ? normalizeRuntimePostinstall(data["runtime-postinstall"], data.name) : undefined; + const mcp = data.mcp ? normalizeMcp(data.mcp, data.name) : undefined; const manifest: PluginManifest = { name: data.name, @@ -600,6 +646,7 @@ export function parsePluginManifest(raw: string, dir: string): PluginManifest { ...(credentials ? { credentials } : {}), ...(runtimeDependencies ? { runtimeDependencies } : {}), ...(runtimePostinstall ? { runtimePostinstall } : {}), + ...(mcp ? { mcp } : {}), }; if (data.oauth) { diff --git a/packages/junior/src/chat/plugins/registry.ts b/packages/junior/src/chat/plugins/registry.ts index b56ea3b3..f3f032ac 100644 --- a/packages/junior/src/chat/plugins/registry.ts +++ b/packages/junior/src/chat/plugins/registry.ts @@ -190,6 +190,11 @@ export function getPluginProviders(): PluginDefinition[] { return [...pluginDefinitions]; } +export function getPluginMcpProviders(): PluginDefinition[] { + ensurePluginsLoaded(); + return pluginDefinitions.filter((plugin) => Boolean(plugin.manifest.mcp)); +} + export function getPluginRuntimeDependencies(): PluginRuntimeDependency[] { ensurePluginsLoaded(); const seen = new Set(); @@ -284,6 +289,28 @@ export function getPluginSkillRoots(): string[] { ]; } +export function getPluginForSkillPath( + skillPath: string, +): PluginDefinition | undefined { + ensurePluginsLoaded(); + const resolvedSkillPath = path.resolve(skillPath); + + return pluginDefinitions.find((plugin) => { + const resolvedSkillsDir = path.resolve(plugin.skillsDir); + return ( + resolvedSkillPath === resolvedSkillsDir || + resolvedSkillPath.startsWith(`${resolvedSkillsDir}${path.sep}`) + ); + }); +} + +export function getPluginDefinition( + provider: string, +): PluginDefinition | undefined { + ensurePluginsLoaded(); + return pluginsByName.get(provider); +} + export function isPluginProvider(provider: string): boolean { ensurePluginsLoaded(); return pluginsByName.has(provider); diff --git a/packages/junior/src/chat/plugins/types.ts b/packages/junior/src/chat/plugins/types.ts index bfe60fce..167935a3 100644 --- a/packages/junior/src/chat/plugins/types.ts +++ b/packages/junior/src/chat/plugins/types.ts @@ -64,6 +64,14 @@ export interface PluginRuntimePostinstallCommand { sudo?: boolean; } +export interface PluginMcpHttpConfig { + transport: "http"; + url: string; + headers?: Record; +} + +export type PluginMcpConfig = PluginMcpHttpConfig; + export interface PluginManifest { name: string; description: string; @@ -72,6 +80,7 @@ export interface PluginManifest { credentials?: PluginCredentials; runtimeDependencies?: PluginRuntimeDependency[]; runtimePostinstall?: PluginRuntimePostinstallCommand[]; + mcp?: PluginMcpConfig; oauth?: PluginOAuthConfig; target?: { type: "repo"; diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index aae3853a..b85a8e7c 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -7,6 +7,8 @@ import { extractGenAiUsageAttributes, serializeGenAiAttribute, } from "@/chat/gen-ai-attributes"; +import { createMcpOAuthClientProvider } from "@/chat/mcp/oauth"; +import { getMcpAuthSession, patchMcpAuthSession } from "@/chat/mcp/auth-store"; import { logException, logInfo, @@ -17,6 +19,7 @@ import { withSpan, type ObservabilityContext, } from "@/chat/observability"; +import { deliverPrivateMessage, formatProviderLabel } from "@/chat/oauth-flow"; import { buildSystemPrompt } from "@/chat/prompt"; import { createSkillCapabilityRuntime, @@ -37,7 +40,11 @@ import { parseSkillInvocation, type Skill, } from "@/chat/skills"; -import { getPluginProviders } from "@/chat/plugins/registry"; +import { + getPluginMcpProviders, + getPluginProviders, +} from "@/chat/plugins/registry"; +import { McpToolManager } from "@/chat/mcp/tool-manager"; import { SlackActionError } from "@/chat/slack-actions/client"; import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; import { createTools } from "@/chat/tools"; @@ -66,6 +73,7 @@ import { } from "@/chat/status-format"; import { RetryableTurnError, isRetryableTurnError } from "@/chat/turn/errors"; import { enforceAttachmentClaimTruth } from "@/chat/attachment-claims"; +import { mergeArtifactsState } from "@/chat/runtime/thread-state"; export interface ReplyRequestContext { skillDirs?: string[]; @@ -165,6 +173,16 @@ class AgentTurnTimeoutError extends Error { } } +class McpAuthorizationPauseError extends Error { + readonly provider: string; + + constructor(provider: string) { + super(`MCP authorization started for ${provider}`); + this.name = "McpAuthorizationPauseError"; + this.provider = provider; + } +} + async function maybeReplaceAgentMessages( agent: Agent, messages: unknown[], @@ -541,6 +559,22 @@ function extractAssistantText(message: AssistantMessage): string { .join("\n"); } +function upsertActiveSkill(activeSkills: Skill[], next: Skill): void { + const existing = activeSkills.find((skill) => skill.name === next.name); + if (existing) { + existing.body = next.body; + existing.description = next.description; + existing.skillPath = next.skillPath; + existing.allowedTools = next.allowedTools; + existing.requiresCapabilities = next.requiresCapabilities; + existing.usesConfig = next.usesConfig; + existing.pluginProvider = next.pluginProvider; + return; + } + + activeSkills.push(next); +} + function collectRelevantConfigurationKeys( activeSkills: Array<{ usesConfig?: string[] }>, explicitSkill?: { usesConfig?: string[] } | null, @@ -915,6 +949,10 @@ export async function generateAssistantReply( let lastKnownSandboxId: string | undefined = context.sandbox?.sandboxId; let lastKnownSandboxDependencyProfileHash: string | undefined = context.sandbox?.sandboxDependencyProfileHash; + let loadedSkillNamesForResume: string[] = []; + let activeMcpProvidersForResume: string[] = []; + let mcpToolManager: McpToolManager | undefined; + let pendingMcpAuthorizationPause: McpAuthorizationPauseError | undefined; try { const shouldTrace = shouldEmitDevAgentTrace(); @@ -981,6 +1019,24 @@ export async function generateAssistantReply( : null; const activeSkills: Skill[] = []; const skillSandbox = new SkillSandbox(availableSkills, activeSkills); + const { conversationId: sessionConversationId, sessionId } = + getSessionIdentifiers(context); + const canUseTurnSession = Boolean(sessionConversationId && sessionId); + timeoutResumeConversationId = sessionConversationId; + timeoutResumeSessionId = sessionId; + const existingTurnCheckpoint = + canUseTurnSession && sessionConversationId && sessionId + ? await getAgentTurnSessionCheckpoint(sessionConversationId, sessionId) + : undefined; + const resumedFromCheckpoint = Boolean( + existingTurnCheckpoint && + existingTurnCheckpoint.state === "awaiting_resume" && + existingTurnCheckpoint.piMessages.length > 0, + ); + const currentSliceId = resumedFromCheckpoint + ? existingTurnCheckpoint!.sliceId + : 1; + timeoutResumeSliceId = currentSliceId; const capabilityRuntime = createSkillCapabilityRuntime({ invocationArgs: skillInvocation?.args, requesterId: context.requester?.userId, @@ -1021,10 +1077,17 @@ export async function generateAssistantReply( sandboxExecutor.configureSkills(availableSkills); const sandbox = await sandboxExecutor.createSandbox(); + for (const skillName of existingTurnCheckpoint?.loadedSkillNames ?? []) { + const preloaded = await skillSandbox.loadSkill(skillName); + if (preloaded) { + upsertActiveSkill(activeSkills, preloaded); + } + } + if (invokedSkill) { const preloaded = await skillSandbox.loadSkill(invokedSkill.name); if (preloaded) { - activeSkills.push(preloaded); + upsertActiveSkill(activeSkills, preloaded); } } @@ -1058,6 +1121,110 @@ export async function generateAssistantReply( const replyFiles: FileUpload[] = []; const artifactStatePatch: Partial = {}; const toolCalls: string[] = []; + const mcpAuthSessionIdsByProvider = new Map(); + mcpToolManager = new McpToolManager(getPluginMcpProviders(), { + authProviderFactory: async (plugin) => { + if ( + !sessionConversationId || + !sessionId || + !context.requester?.userId + ) { + return undefined; + } + + const provider = await createMcpOAuthClientProvider({ + provider: plugin.manifest.name, + conversationId: sessionConversationId, + sessionId, + userId: context.requester.userId, + userMessage: userInput, + ...(context.correlation?.channelId + ? { channelId: context.correlation.channelId } + : {}), + ...(context.correlation?.threadTs + ? { threadTs: context.correlation.threadTs } + : {}), + ...(context.toolChannelId + ? { toolChannelId: context.toolChannelId } + : {}), + configuration: configurationValues, + artifactState: context.artifactState, + }); + mcpAuthSessionIdsByProvider.set( + plugin.manifest.name, + provider.authSessionId, + ); + return provider; + }, + onAuthorizationRequired: async (provider) => { + if (pendingMcpAuthorizationPause) { + return; + } + + const authSessionId = mcpAuthSessionIdsByProvider.get(provider); + if (!authSessionId || !context.requester?.userId) { + throw new Error( + `Missing MCP auth session context for plugin "${provider}"`, + ); + } + + const latestArtifactState = mergeArtifactsState( + context.artifactState ?? {}, + artifactStatePatch, + ); + await patchMcpAuthSession(authSessionId, { + configuration: { ...configurationValues }, + artifactState: latestArtifactState, + toolChannelId: + context.toolChannelId ?? + latestArtifactState.assistantContextChannelId ?? + context.correlation?.channelId, + }); + + const authSession = await getMcpAuthSession(authSessionId); + if (!authSession?.authorizationUrl) { + throw new Error( + `Missing MCP authorization URL for plugin "${provider}"`, + ); + } + + const delivery = await deliverPrivateMessage({ + channelId: authSession.channelId, + threadTs: authSession.threadTs, + userId: authSession.userId, + text: `<${authSession.authorizationUrl}|Click here to link your ${formatProviderLabel(provider)} MCP access>. Once you've authorized, this thread will continue automatically.`, + }); + if (!delivery) { + throw new Error( + `Unable to deliver MCP authorization link for plugin "${provider}"`, + ); + } + + pendingMcpAuthorizationPause = new McpAuthorizationPauseError(provider); + agent?.abort(); + }, + ...(sessionConversationId && sessionId + ? { sessionId: `${sessionConversationId}:${sessionId}` } + : {}), + }); + const turnMcpToolManager = mcpToolManager; + let agent: Agent | undefined; + let baseAgentTools: AgentTool[] = []; + const syncResumeState = () => { + loadedSkillNamesForResume = activeSkills.map((skill) => skill.name); + activeMcpProvidersForResume = mcpToolManager?.getActiveProviders() ?? []; + }; + + const refreshAgentTools = () => { + if (!agent) { + return; + } + agent.setTools([ + ...baseAgentTools, + ...turnMcpToolManager.getActiveTools(), + ]); + syncResumeState(); + }; setTags({ conversationId: spanContext.conversationId, @@ -1099,19 +1266,10 @@ export async function generateAssistantReply( onSkillLoaded: async (loadedSkill) => { const resolvedSkill = await skillSandbox.loadSkill(loadedSkill.name); const effective = resolvedSkill ?? loadedSkill; - const existing = activeSkills.find( - (skill) => skill.name === effective.name, - ); - if (existing) { - existing.body = effective.body; - existing.description = effective.description; - existing.skillPath = effective.skillPath; - existing.allowedTools = effective.allowedTools; - existing.requiresCapabilities = effective.requiresCapabilities; - existing.usesConfig = effective.usesConfig; - return; - } - activeSkills.push(effective); + upsertActiveSkill(activeSkills, effective); + await turnMcpToolManager.activateForSkill(effective); + syncResumeState(); + refreshAgentTools(); }, }, { @@ -1124,6 +1282,26 @@ export async function generateAssistantReply( sandbox, }, ); + + syncResumeState(); + try { + for (const skill of activeSkills) { + await turnMcpToolManager.activateForSkill(skill); + syncResumeState(); + } + for (const provider of existingTurnCheckpoint?.activeMcpProviders ?? []) { + await turnMcpToolManager.activateProvider(provider); + syncResumeState(); + } + } catch (error) { + if (pendingMcpAuthorizationPause) { + timeoutResumeMessages = existingTurnCheckpoint?.piMessages ?? []; + throw pendingMcpAuthorizationPause; + } + throw error; + } + syncResumeState(); + const baseInstructions = buildSystemPrompt({ availableSkills, activeSkills, @@ -1170,43 +1348,26 @@ export async function generateAssistantReply( }, ]); - const { conversationId: sessionConversationId, sessionId } = - getSessionIdentifiers(context); - const canUseTurnSession = Boolean(sessionConversationId && sessionId); - timeoutResumeConversationId = sessionConversationId; - timeoutResumeSessionId = sessionId; - const existingTurnCheckpoint = - canUseTurnSession && sessionConversationId && sessionId - ? await getAgentTurnSessionCheckpoint(sessionConversationId, sessionId) - : undefined; - const resumedFromCheckpoint = Boolean( - existingTurnCheckpoint && - existingTurnCheckpoint.state === "awaiting_resume" && - existingTurnCheckpoint.piMessages.length > 0, + baseAgentTools = createAgentTools( + tools as Record>, + skillSandbox, + spanContext, + context.onStatus, + sandboxExecutor, + capabilityRuntime, + { + onToolCall: (toolName) => { + toolCalls.push(toolName); + }, + }, ); - const currentSliceId = resumedFromCheckpoint - ? existingTurnCheckpoint!.sliceId - : 1; - timeoutResumeSliceId = currentSliceId; - const agent = new Agent({ + agent = new Agent({ getApiKey: () => getGatewayApiKey(), initialState: { systemPrompt: baseInstructions, model: resolveGatewayModel(botConfig.modelId), - tools: createAgentTools( - tools as Record>, - skillSandbox, - spanContext, - context.onStatus, - sandboxExecutor, - capabilityRuntime, - { - onToolCall: (toolName) => { - toolCalls.push(toolName); - }, - }, - ), + tools: [...baseAgentTools, ...turnMcpToolManager.getActiveTools()], }, }); let hasEmittedText = false; @@ -1311,6 +1472,10 @@ export async function generateAssistantReply( await promptPromise.catch(() => {}); timeoutResumeMessages = [...(agent.state.messages as unknown[])]; } + if (pendingMcpAuthorizationPause) { + timeoutResumeMessages = [...(agent.state.messages as unknown[])]; + throw pendingMcpAuthorizationPause; + } throw error; } finally { if (timeoutId) { @@ -1321,6 +1486,10 @@ export async function generateAssistantReply( newMessages = agent.state.messages.slice( beforeMessageCount, ) as unknown[]; + if (pendingMcpAuthorizationPause) { + timeoutResumeMessages = [...(agent.state.messages as unknown[])]; + throw pendingMcpAuthorizationPause; + } const outputMessages = newMessages.filter(isAssistantMessage); const outputMessagesAttribute = serializeGenAiAttribute(outputMessages); @@ -1349,6 +1518,10 @@ export async function generateAssistantReply( unsubscribe(); } + if (pendingMcpAuthorizationPause) { + throw pendingMcpAuthorizationPause; + } + if (canUseTurnSession && sessionConversationId && sessionId) { await upsertAgentTurnSessionCheckpoint({ conversationId: sessionConversationId, @@ -1356,6 +1529,8 @@ export async function generateAssistantReply( sliceId: currentSliceId, state: "completed", piMessages: agent.state.messages as unknown[], + loadedSkillNames: activeSkills.map((skill) => skill.name), + activeMcpProviders: turnMcpToolManager.getActiveProviders(), }); } @@ -1513,6 +1688,30 @@ export async function generateAssistantReply( }, }; } catch (error) { + if ( + error instanceof McpAuthorizationPauseError && + timeoutResumeConversationId && + timeoutResumeSessionId + ) { + const nextSliceId = timeoutResumeSliceId + 1; + await upsertAgentTurnSessionCheckpoint({ + conversationId: timeoutResumeConversationId, + sessionId: timeoutResumeSessionId, + sliceId: nextSliceId, + state: "awaiting_resume", + piMessages: timeoutResumeMessages, + loadedSkillNames: loadedSkillNamesForResume, + activeMcpProviders: activeMcpProvidersForResume, + resumeReason: "auth", + resumedFromSliceId: timeoutResumeSliceId, + errorMessage: error.message, + }); + throw new RetryableTurnError( + "mcp_auth_resume", + `conversation=${timeoutResumeConversationId} session=${timeoutResumeSessionId} slice=${nextSliceId}`, + ); + } + if ( error instanceof AgentTurnTimeoutError && timeoutResumeConversationId && @@ -1554,6 +1753,9 @@ export async function generateAssistantReply( sliceId: nextSliceId, state: "awaiting_resume", piMessages, + loadedSkillNames: loadedSkillNamesForResume, + activeMcpProviders: activeMcpProvidersForResume, + resumeReason: "timeout", resumedFromSliceId: timeoutResumeSliceId, errorMessage: error.message, }); @@ -1620,5 +1822,21 @@ export async function generateAssistantReply( providerError: error, }, }; + } finally { + try { + await mcpToolManager?.close(); + } catch (closeError) { + logWarn( + "mcp_tool_manager_close_failed", + {}, + { + "error.message": + closeError instanceof Error + ? closeError.message + : String(closeError), + }, + "Failed to close MCP tool manager", + ); + } } } diff --git a/packages/junior/src/chat/skills.ts b/packages/junior/src/chat/skills.ts index 495132e6..be08d946 100644 --- a/packages/junior/src/chat/skills.ts +++ b/packages/junior/src/chat/skills.ts @@ -6,7 +6,10 @@ import { } from "@/chat/capabilities/catalog"; import { skillRoots } from "@/chat/home"; import { logWarn } from "@/chat/observability"; -import { getPluginSkillRoots } from "@/chat/plugins/registry"; +import { + getPluginForSkillPath, + getPluginSkillRoots, +} from "@/chat/plugins/registry"; import { parseSkillFile } from "@/chat/skill-frontmatter"; const SKILL_CACHE_TTL_MS = 5000; @@ -15,6 +18,7 @@ export interface SkillMetadata { name: string; description: string; skillPath: string; + pluginProvider?: string; allowedTools?: string[]; requiresCapabilities?: string[]; usesConfig?: string[]; @@ -117,6 +121,7 @@ async function readSkillDirectory( requiresCapabilities, usesConfig, } = parsed.skill; + const plugin = getPluginForSkillPath(skillDir); const metadataError = validateSkillMetadata({ requiresCapabilities, usesConfig, @@ -138,6 +143,7 @@ async function readSkillDirectory( name, description, skillPath: skillDir, + ...(plugin ? { pluginProvider: plugin.manifest.name } : {}), allowedTools, requiresCapabilities, usesConfig, diff --git a/packages/junior/src/chat/state.ts b/packages/junior/src/chat/state.ts index 4e88c33f..e3766ac3 100644 --- a/packages/junior/src/chat/state.ts +++ b/packages/junior/src/chat/state.ts @@ -152,6 +152,7 @@ export type AgentTurnSessionStatus = | "awaiting_resume" | "completed" | "failed"; +export type AgentTurnResumeReason = "timeout" | "auth"; export interface QueueMessageProcessingState { status: QueueMessageProcessingStatus; @@ -165,7 +166,10 @@ export interface AgentTurnSessionCheckpoint { checkpointVersion: number; conversationId: string; errorMessage?: string; + activeMcpProviders?: string[]; + loadedSkillNames?: string[]; piMessages: unknown[]; + resumeReason?: AgentTurnResumeReason; resumedFromSliceId?: number; sessionId: string; sliceId: number; @@ -270,6 +274,23 @@ function parseAgentTurnSessionCheckpoint( state: status, updatedAtMs, piMessages: Array.isArray(parsed.piMessages) ? parsed.piMessages : [], + ...(Array.isArray(parsed.loadedSkillNames) + ? { + loadedSkillNames: parsed.loadedSkillNames.filter( + (value): value is string => typeof value === "string", + ), + } + : {}), + ...(Array.isArray(parsed.activeMcpProviders) + ? { + activeMcpProviders: parsed.activeMcpProviders.filter( + (value): value is string => typeof value === "string", + ), + } + : {}), + ...(parsed.resumeReason === "timeout" || parsed.resumeReason === "auth" + ? { resumeReason: parsed.resumeReason } + : {}), ...(typeof parsed.errorMessage === "string" ? { errorMessage: parsed.errorMessage } : {}), @@ -461,6 +482,9 @@ export async function upsertAgentTurnSessionCheckpoint(args: { sliceId: number; state: AgentTurnSessionStatus; piMessages: unknown[]; + loadedSkillNames?: string[]; + activeMcpProviders?: string[]; + resumeReason?: AgentTurnResumeReason; errorMessage?: string; resumedFromSliceId?: number; ttlMs?: number; @@ -479,6 +503,21 @@ export async function upsertAgentTurnSessionCheckpoint(args: { state: args.state, updatedAtMs: Date.now(), piMessages: Array.isArray(args.piMessages) ? args.piMessages : [], + ...(Array.isArray(args.loadedSkillNames) + ? { + loadedSkillNames: args.loadedSkillNames.filter( + (value): value is string => typeof value === "string", + ), + } + : {}), + ...(Array.isArray(args.activeMcpProviders) + ? { + activeMcpProviders: args.activeMcpProviders.filter( + (value): value is string => typeof value === "string", + ), + } + : {}), + ...(args.resumeReason ? { resumeReason: args.resumeReason } : {}), ...(args.errorMessage ? { errorMessage: args.errorMessage } : {}), ...(typeof args.resumedFromSliceId === "number" ? { resumedFromSliceId: args.resumedFromSliceId } diff --git a/packages/junior/src/chat/turn/errors.ts b/packages/junior/src/chat/turn/errors.ts index 38f67cf0..99e9f31e 100644 --- a/packages/junior/src/chat/turn/errors.ts +++ b/packages/junior/src/chat/turn/errors.ts @@ -1,4 +1,6 @@ -export type RetryableTurnReason = "agent_turn_timeout_resume"; +export type RetryableTurnReason = + | "agent_turn_timeout_resume" + | "mcp_auth_resume"; export class RetryableTurnError extends Error { readonly code = "retryable_turn"; @@ -11,7 +13,10 @@ export class RetryableTurnError extends Error { } } -export function isRetryableTurnError(error: unknown, reason?: RetryableTurnReason): error is RetryableTurnError { +export function isRetryableTurnError( + error: unknown, + reason?: RetryableTurnReason, +): error is RetryableTurnError { if (!(error instanceof RetryableTurnError)) { return false; } diff --git a/packages/junior/src/handlers/mcp-oauth-callback.ts b/packages/junior/src/handlers/mcp-oauth-callback.ts new file mode 100644 index 00000000..0fa35ad3 --- /dev/null +++ b/packages/junior/src/handlers/mcp-oauth-callback.ts @@ -0,0 +1,529 @@ +import { Buffer } from "node:buffer"; +import { after } from "next/server"; +import { ThreadImpl, type FileUpload } from "chat"; +import { botConfig } from "@/chat/config"; +import { coerceThreadConversationState } from "@/chat/conversation-state"; +import type { ChannelConfigurationService } from "@/chat/configuration/types"; +import { deleteMcpAuthSession } from "@/chat/mcp/auth-store"; +import { buildSlackOutputMessage } from "@/chat/output"; +import { finalizeMcpAuthorization } from "@/chat/mcp/oauth"; +import { logException } from "@/chat/observability"; +import { generateAssistantReply, type AssistantReply } from "@/chat/respond"; +import { + mergeArtifactsState, + persistThreadState, +} from "@/chat/runtime/thread-state"; +import { + generateConversationId, + markConversationMessage, + normalizeConversationText, + upsertConversationMessage, + updateConversationStats, +} from "@/chat/services/conversation-memory"; +import { + getSlackClient, + uploadFilesToThread, +} from "@/chat/slack-actions/client"; +import { coerceThreadArtifactsState } from "@/chat/slack-actions/types"; +import { truncateStatusText } from "@/chat/status-format"; +import { markTurnCompleted, markTurnFailed } from "@/chat/turn/persist"; +import { resolveReplyDelivery } from "@/chat/turn/execute"; +import { escapeXml } from "@/chat/xml"; + +function htmlResponse( + title: string, + message: string, + status: number, +): Response { + const safeTitle = escapeXml(title); + const safeMessage = escapeXml(message); + const html = ` + +${safeTitle} + +
+

${safeTitle}

+

${safeMessage}

+

You can close this tab and return to Slack.

+
+ +`; + return new Response(html, { + status, + headers: { "Content-Type": "text/html; charset=utf-8" }, + }); +} + +async function postSlackMessage( + channelId: string, + threadTs: string, + text: string, +): Promise { + try { + await getSlackClient().chat.postMessage({ + channel: channelId, + thread_ts: threadTs, + text, + }); + } catch { + // Best effort. + } +} + +function extractSlackText(text: string, files?: FileUpload[]): string { + const message = buildSlackOutputMessage(text, files); + if ( + typeof message === "object" && + message !== null && + "markdown" in message && + typeof message.markdown === "string" + ) { + return message.markdown; + } + if ( + typeof message === "object" && + message !== null && + "raw" in message && + typeof message.raw === "string" + ) { + return message.raw; + } + return text; +} + +async function normalizeFileUploads( + files: FileUpload[], +): Promise> { + const normalized: Array<{ data: Buffer; filename: string }> = []; + + for (const file of files) { + let data: Buffer; + if (Buffer.isBuffer(file.data)) { + data = file.data; + } else if (file.data instanceof ArrayBuffer) { + data = Buffer.from(file.data); + } else { + data = Buffer.from(await file.data.arrayBuffer()); + } + normalized.push({ + data, + filename: file.filename, + }); + } + + return normalized; +} + +async function deliverReplyToThread( + channelId: string, + threadTs: string, + reply: AssistantReply, +): Promise { + const replyFiles = + reply.files && reply.files.length > 0 ? reply.files : undefined; + const { shouldPostThreadReply, attachFiles } = resolveReplyDelivery({ + reply, + hasStreamedThreadReply: false, + }); + + if (shouldPostThreadReply) { + const text = extractSlackText( + reply.text, + attachFiles === "inline" ? replyFiles : undefined, + ); + if (text.trim().length > 0) { + await postSlackMessage(channelId, threadTs, text); + } + } + + if (!replyFiles || attachFiles === "none" || !shouldPostThreadReply) { + return; + } + + const files = await normalizeFileUploads(replyFiles); + if (files.length === 0) { + return; + } + + try { + await uploadFilesToThread({ + channelId, + threadTs, + files, + }); + } catch { + // Best effort. + } +} + +function createSlackThread(channelId: string, threadTs: string) { + return ThreadImpl.fromJSON({ + _type: "chat:Thread", + adapterName: "slack", + channelId, + id: `slack:${channelId}:${threadTs}`, + isDM: channelId.startsWith("D"), + }); +} + +function buildDeterministicTurnId(messageId: string): string { + const sanitized = messageId.replace(/[^a-zA-Z0-9_-]/g, "_"); + return `turn_${sanitized}`; +} + +function getUserMessageIdForTurn( + conversation: ReturnType, + sessionId: string, +): string | undefined { + for (let index = conversation.messages.length - 1; index >= 0; index -= 1) { + const message = conversation.messages[index]; + if (message?.role !== "user") { + continue; + } + if (buildDeterministicTurnId(message.id) === sessionId) { + return message.id; + } + } + + return undefined; +} + +async function persistCompletedReplyState( + channelId: string, + threadTs: string, + sessionId: string, + reply: AssistantReply, +): Promise { + const thread = createSlackThread(channelId, threadTs); + const currentState = await thread.state; + const conversation = coerceThreadConversationState(currentState); + const artifacts = coerceThreadArtifactsState(currentState); + const nextArtifacts = reply.artifactStatePatch + ? mergeArtifactsState(artifacts, reply.artifactStatePatch) + : undefined; + const userMessageId = getUserMessageIdForTurn(conversation, sessionId); + + markConversationMessage(conversation, userMessageId, { + replied: true, + skippedReason: undefined, + }); + upsertConversationMessage(conversation, { + id: generateConversationId("assistant"), + role: "assistant", + text: normalizeConversationText(reply.text) || "[empty response]", + createdAtMs: Date.now(), + author: { + userName: botConfig.userName, + isBot: true, + }, + meta: { + replied: true, + }, + }); + markTurnCompleted({ + conversation, + nowMs: Date.now(), + updateConversationStats, + }); + + await persistThreadState(thread, { + artifacts: nextArtifacts, + conversation, + sandboxId: reply.sandboxId, + sandboxDependencyProfileHash: reply.sandboxDependencyProfileHash, + }); +} + +async function persistFailedReplyState( + channelId: string, + threadTs: string, + sessionId: string, +): Promise { + const thread = createSlackThread(channelId, threadTs); + const currentState = await thread.state; + const conversation = coerceThreadConversationState(currentState); + + markTurnFailed({ + conversation, + nowMs: Date.now(), + userMessageId: getUserMessageIdForTurn(conversation, sessionId), + markConversationMessage, + updateConversationStats, + }); + + await persistThreadState(thread, { + conversation, + }); +} + +async function setAssistantStatus( + channelId: string, + threadTs: string, + status: string, +): Promise { + try { + await getSlackClient().assistant.threads.setStatus({ + channel_id: channelId, + thread_ts: threadTs, + status, + }); + } catch { + // Best effort. + } +} + +const STATUS_DEBOUNCE_MS = 1000; + +function createDebouncedStatusPoster(channelId: string, threadTs: string) { + let lastPostAt = 0; + let currentStatus = ""; + let pendingStatus: string | null = null; + let pendingTimer: ReturnType | null = null; + let stopped = false; + + const flush = async () => { + if (stopped || !pendingStatus) return; + const status = pendingStatus; + pendingStatus = null; + pendingTimer = null; + lastPostAt = Date.now(); + currentStatus = status; + await setAssistantStatus(channelId, threadTs, status); + }; + + const post = async (status: string) => { + if (stopped) return; + const truncated = truncateStatusText(status); + if (!truncated || truncated === currentStatus) return; + + const now = Date.now(); + const elapsed = now - lastPostAt; + if (elapsed >= STATUS_DEBOUNCE_MS) { + if (pendingTimer) { + clearTimeout(pendingTimer); + pendingTimer = null; + } + pendingStatus = null; + lastPostAt = now; + currentStatus = truncated; + await setAssistantStatus(channelId, threadTs, truncated); + return; + } + + pendingStatus = truncated; + if (!pendingTimer) { + pendingTimer = setTimeout( + () => { + void flush(); + }, + Math.max(1, STATUS_DEBOUNCE_MS - elapsed), + ); + } + }; + + post.stop = () => { + stopped = true; + if (pendingTimer) { + clearTimeout(pendingTimer); + pendingTimer = null; + } + pendingStatus = null; + }; + + return post; +} + +function createReadOnlyConfigService( + values: Record, +): ChannelConfigurationService { + const entries = Object.entries(values).map(([key, value]) => ({ + key, + value, + scope: "conversation" as const, + updatedAt: new Date().toISOString(), + })); + + return { + get: async (key) => entries.find((entry) => entry.key === key), + set: async () => { + throw new Error("Read-only configuration in resumed context"); + }, + unset: async () => false, + list: async ({ prefix } = {}) => + entries.filter((entry) => !prefix || entry.key.startsWith(prefix)), + resolve: async (key) => values[key], + resolveValues: async ({ keys, prefix } = {}) => { + const filtered: Record = {}; + for (const [key, value] of Object.entries(values)) { + if (prefix && !key.startsWith(prefix)) continue; + if (keys && !keys.includes(key)) continue; + filtered[key] = value; + } + return filtered; + }, + }; +} + +type Context = { + params: Promise<{ + provider: string; + }>; +}; + +export async function GET( + request: Request, + context: Context, +): Promise { + const { provider } = await context.params; + const url = new URL(request.url); + const state = url.searchParams.get("state")?.trim(); + const code = url.searchParams.get("code")?.trim(); + const error = url.searchParams.get("error")?.trim(); + + if (!state) { + return htmlResponse( + "Authorization failed", + "Missing state parameter.", + 400, + ); + } + if (error) { + return htmlResponse("Authorization failed", `OAuth error: ${error}`, 400); + } + if (!code) { + return htmlResponse("Authorization failed", "Missing code parameter.", 400); + } + + try { + const authSession = await finalizeMcpAuthorization(provider, state, code); + try { + await deleteMcpAuthSession(authSession.authSessionId); + } catch (cleanupError) { + logException( + cleanupError, + "mcp_oauth_callback_session_cleanup_failed", + {}, + { "app.credential.provider": provider }, + "Failed to delete completed MCP auth session", + ); + } + + after(async () => { + if (!authSession.channelId || !authSession.threadTs) { + return; + } + + const postStatus = createDebouncedStatusPoster( + authSession.channelId, + authSession.threadTs, + ); + await postSlackMessage( + authSession.channelId, + authSession.threadTs, + `Your ${provider} MCP access is now connected. Continuing the original request...`, + ); + await setAssistantStatus( + authSession.channelId, + authSession.threadTs, + "Thinking...", + ); + + try { + const reply = await generateAssistantReply(authSession.userMessage, { + assistant: { userName: botConfig.userName }, + requester: { userId: authSession.userId }, + correlation: { + conversationId: authSession.conversationId, + turnId: authSession.sessionId, + channelId: authSession.channelId, + threadTs: authSession.threadTs, + requesterId: authSession.userId, + }, + toolChannelId: + authSession.toolChannelId ?? + authSession.artifactState?.assistantContextChannelId ?? + authSession.channelId, + artifactState: authSession.artifactState, + configuration: authSession.configuration, + channelConfiguration: authSession.configuration + ? createReadOnlyConfigService(authSession.configuration) + : undefined, + onStatus: postStatus, + }); + + postStatus.stop(); + await deliverReplyToThread( + authSession.channelId, + authSession.threadTs, + reply, + ); + try { + await persistCompletedReplyState( + authSession.channelId, + authSession.threadTs, + authSession.sessionId, + reply, + ); + } catch (persistError) { + logException( + persistError, + "mcp_oauth_callback_resume_persist_failed", + {}, + { "app.credential.provider": provider }, + "Failed to persist resumed MCP turn state", + ); + } + } catch (resumeError) { + postStatus.stop(); + logException( + resumeError, + "mcp_oauth_callback_resume_failed", + {}, + { "app.credential.provider": provider }, + "Failed to resume MCP-authorized turn", + ); + try { + await persistFailedReplyState( + authSession.channelId, + authSession.threadTs, + authSession.sessionId, + ); + } catch (persistError) { + logException( + persistError, + "mcp_oauth_callback_resume_failure_persist_failed", + {}, + { "app.credential.provider": provider }, + "Failed to persist failed MCP resume state", + ); + } + await postSlackMessage( + authSession.channelId, + authSession.threadTs, + "MCP authorization completed, but resuming the request failed. Please retry the original command.", + ); + } + }); + + return htmlResponse( + "Authorization complete", + "Your MCP access is connected. Junior will continue the paused request in Slack.", + 200, + ); + } catch (callbackError) { + logException( + callbackError, + "mcp_oauth_callback_failed", + {}, + { "app.credential.provider": provider }, + "Failed to process MCP OAuth callback", + ); + return htmlResponse( + "Authorization failed", + callbackError instanceof Error + ? callbackError.message + : "Unexpected callback error.", + 500, + ); + } +} diff --git a/packages/junior/src/handlers/router.ts b/packages/junior/src/handlers/router.ts index 5085acd7..5929d5b7 100644 --- a/packages/junior/src/handlers/router.ts +++ b/packages/junior/src/handlers/router.ts @@ -1,3 +1,4 @@ +import { GET as mcpOauthCallbackGET } from "@/handlers/mcp-oauth-callback"; import { GET as healthGET } from "@/handlers/health"; import { GET as oauthCallbackGET } from "@/handlers/oauth-callback"; import { POST as queueCallbackPOST } from "@/handlers/queue-callback"; @@ -23,7 +24,10 @@ function getRoutePathParts(params: unknown): string[] { } const candidate = (params as { path?: unknown }).path; - if (!Array.isArray(candidate) || candidate.some((segment) => typeof segment !== "string")) { + if ( + !Array.isArray(candidate) || + candidate.some((segment) => typeof segment !== "string") + ) { return []; } @@ -35,20 +39,32 @@ function getRoutePathParts(params: unknown): string[] { * * Supported routes: * - `api/health` + * - `api/oauth/callback/mcp/:provider` * - `api/oauth/callback/:provider` */ -export async function GET(request: Request, context: RouteContext): Promise { +export async function GET( + request: Request, + context: RouteContext, +): Promise { const route = normalizeRoutePath(getRoutePathParts(await context.params)); if (route === "health") { return healthGET(); } + const mcpOauthCallbackMatch = route.match(/^oauth\/callback\/mcp\/([^/]+)$/); + if (mcpOauthCallbackMatch) { + const provider = mcpOauthCallbackMatch[1]; + return mcpOauthCallbackGET(request, { + params: Promise.resolve({ provider }), + }); + } + const oauthCallbackMatch = route.match(/^oauth\/callback\/([^/]+)$/); if (oauthCallbackMatch) { const provider = oauthCallbackMatch[1]; return oauthCallbackGET(request, { - params: Promise.resolve({ provider }) + params: Promise.resolve({ provider }), }); } @@ -65,7 +81,10 @@ export async function GET(request: Request, context: RouteContext): Promise { +export async function POST( + request: Request, + context: RouteContext, +): Promise { const route = normalizeRoutePath(getRoutePathParts(await context.params)); if (route === "queue/callback") { @@ -76,7 +95,7 @@ export async function POST(request: Request, context: RouteContext): Promise ({ +const { + healthGetMock, + mcpOauthCallbackGetMock, + oauthCallbackGetMock, + queueCallbackPostMock, + webhooksPostMock, +} = vi.hoisted(() => ({ healthGetMock: vi.fn(async () => new Response("health", { status: 200 })), - oauthCallbackGetMock: vi.fn(async (_request: Request, context: { params: Promise<{ provider: string }> }) => { - const { provider } = await context.params; - return new Response(`oauth:${provider}`, { status: 200 }); - }), - queueCallbackPostMock: vi.fn(async () => new Response("queue:ok", { status: 200 })), - webhooksPostMock: vi.fn(async (_request: Request, context: { params: Promise<{ platform: string }> }) => { - const { platform } = await context.params; - return new Response(`webhook:${platform}`, { status: 202 }); - }) + mcpOauthCallbackGetMock: vi.fn( + async ( + _request: Request, + context: { params: Promise<{ provider: string }> }, + ) => { + const { provider } = await context.params; + return new Response(`mcp-oauth:${provider}`, { status: 200 }); + }, + ), + oauthCallbackGetMock: vi.fn( + async ( + _request: Request, + context: { params: Promise<{ provider: string }> }, + ) => { + const { provider } = await context.params; + return new Response(`oauth:${provider}`, { status: 200 }); + }, + ), + queueCallbackPostMock: vi.fn( + async () => new Response("queue:ok", { status: 200 }), + ), + webhooksPostMock: vi.fn( + async ( + _request: Request, + context: { params: Promise<{ platform: string }> }, + ) => { + const { platform } = await context.params; + return new Response(`webhook:${platform}`, { status: 202 }); + }, + ), })); vi.mock("@/handlers/health", () => ({ - GET: healthGetMock + GET: healthGetMock, +})); + +vi.mock("@/handlers/mcp-oauth-callback", () => ({ + GET: mcpOauthCallbackGetMock, })); vi.mock("@/handlers/oauth-callback", () => ({ - GET: oauthCallbackGetMock + GET: oauthCallbackGetMock, })); vi.mock("@/handlers/queue-callback", () => ({ - POST: queueCallbackPostMock + POST: queueCallbackPostMock, })); vi.mock("@/handlers/webhooks", () => ({ - POST: webhooksPostMock + POST: webhooksPostMock, })); import { GET, POST } from "@/handlers/router"; @@ -38,19 +69,26 @@ function routeContext(path: string[]): { params: Promise<{ path: string[] }> } { describe("handlers router", () => { beforeEach(() => { healthGetMock.mockClear(); + mcpOauthCallbackGetMock.mockClear(); oauthCallbackGetMock.mockClear(); queueCallbackPostMock.mockClear(); webhooksPostMock.mockClear(); }); it("routes catch-all health requests", async () => { - const response = await GET(new Request("http://localhost/api/health"), routeContext(["health"])); + const response = await GET( + new Request("http://localhost/api/health"), + routeContext(["health"]), + ); expect(response.status).toBe(200); expect(healthGetMock).toHaveBeenCalledTimes(1); }); it("accepts legacy api-prefixed health route form", async () => { - const response = await GET(new Request("http://localhost/api/health"), routeContext(["api", "health"])); + const response = await GET( + new Request("http://localhost/api/health"), + routeContext(["api", "health"]), + ); expect(response.status).toBe(200); expect(healthGetMock).toHaveBeenCalledTimes(1); }); @@ -58,18 +96,20 @@ describe("handlers router", () => { it("routes catch-all webhook requests", async () => { const response = await POST( new Request("http://localhost/api/webhooks/slack", { method: "POST" }), - routeContext(["webhooks", "slack"]) + routeContext(["webhooks", "slack"]), ); expect(response.status).toBe(202); expect(await response.text()).toBe("webhook:slack"); expect(webhooksPostMock).toHaveBeenCalledTimes(1); - expect(await webhooksPostMock.mock.calls[0][1].params).toEqual({ platform: "slack" }); + expect(await webhooksPostMock.mock.calls[0][1].params).toEqual({ + platform: "slack", + }); }); it("routes queue callback requests", async () => { const response = await POST( new Request("http://localhost/api/queue/callback", { method: "POST" }), - routeContext(["queue", "callback"]) + routeContext(["queue", "callback"]), ); expect(response.status).toBe(200); expect(await response.text()).toBe("queue:ok"); @@ -79,7 +119,7 @@ describe("handlers router", () => { it("accepts legacy api-prefixed queue callback route form", async () => { const response = await POST( new Request("http://localhost/api/queue/callback", { method: "POST" }), - routeContext(["api", "queue", "callback"]) + routeContext(["api", "queue", "callback"]), ); expect(response.status).toBe(200); expect(queueCallbackPostMock).toHaveBeenCalledTimes(1); @@ -88,28 +128,54 @@ describe("handlers router", () => { it("routes oauth callback requests", async () => { const response = await GET( new Request("http://localhost/api/oauth/callback/sentry"), - routeContext(["oauth", "callback", "sentry"]) + routeContext(["oauth", "callback", "sentry"]), ); expect(response.status).toBe(200); expect(await response.text()).toBe("oauth:sentry"); expect(oauthCallbackGetMock).toHaveBeenCalledTimes(1); - expect(await oauthCallbackGetMock.mock.calls[0][1].params).toEqual({ provider: "sentry" }); + expect(await oauthCallbackGetMock.mock.calls[0][1].params).toEqual({ + provider: "sentry", + }); + }); + + it("routes MCP oauth callback requests before generic oauth callbacks", async () => { + const response = await GET( + new Request("http://localhost/api/oauth/callback/mcp/sentry"), + routeContext(["oauth", "callback", "mcp", "sentry"]), + ); + expect(response.status).toBe(200); + expect(await response.text()).toBe("mcp-oauth:sentry"); + expect(mcpOauthCallbackGetMock).toHaveBeenCalledTimes(1); + expect(await mcpOauthCallbackGetMock.mock.calls[0][1].params).toEqual({ + provider: "sentry", + }); + expect(oauthCallbackGetMock).not.toHaveBeenCalled(); }); it("accepts legacy api-prefixed oauth callback route form", async () => { const response = await GET( new Request("http://localhost/api/oauth/callback/sentry"), - routeContext(["api", "oauth", "callback", "sentry"]) + routeContext(["api", "oauth", "callback", "sentry"]), ); expect(response.status).toBe(200); expect(await response.text()).toBe("oauth:sentry"); expect(oauthCallbackGetMock).toHaveBeenCalledTimes(1); }); + it("accepts legacy api-prefixed MCP oauth callback route form", async () => { + const response = await GET( + new Request("http://localhost/api/oauth/callback/mcp/sentry"), + routeContext(["api", "oauth", "callback", "mcp", "sentry"]), + ); + expect(response.status).toBe(200); + expect(await response.text()).toBe("mcp-oauth:sentry"); + expect(mcpOauthCallbackGetMock).toHaveBeenCalledTimes(1); + }); + it("accepts legacy api-prefixed webhook route form", async () => { const response = await POST( new Request("http://localhost/api/webhooks/slack", { method: "POST" }), - routeContext(["api", "webhooks", "slack"]) + routeContext(["api", "webhooks", "slack"]), ); expect(response.status).toBe(202); expect(await response.text()).toBe("webhook:slack"); @@ -118,15 +184,20 @@ describe("handlers router", () => { it("returns 404 for multi-segment webhook routes", async () => { const response = await POST( - new Request("http://localhost/api/webhooks/slack/unexpected", { method: "POST" }), - routeContext(["webhooks", "slack", "unexpected"]) + new Request("http://localhost/api/webhooks/slack/unexpected", { + method: "POST", + }), + routeContext(["webhooks", "slack", "unexpected"]), ); expect(response.status).toBe(404); expect(webhooksPostMock).not.toHaveBeenCalled(); }); it("returns 404 for unknown routes", async () => { - const response = await GET(new Request("http://localhost/api/unknown"), routeContext(["unknown"])); + const response = await GET( + new Request("http://localhost/api/unknown"), + routeContext(["unknown"]), + ); expect(response.status).toBe(404); expect(healthGetMock).not.toHaveBeenCalled(); expect(webhooksPostMock).not.toHaveBeenCalled(); diff --git a/packages/junior/tests/mcp-oauth-callback.test.ts b/packages/junior/tests/mcp-oauth-callback.test.ts new file mode 100644 index 00000000..aadef39f --- /dev/null +++ b/packages/junior/tests/mcp-oauth-callback.test.ts @@ -0,0 +1,397 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +const { + afterCallbacks, + coerceThreadArtifactsStateMock, + coerceThreadConversationStateMock, + deleteMcpAuthSessionMock, + finalizeMcpAuthorizationMock, + generateAssistantReplyMock, + markConversationMessageMock, + markTurnCompletedMock, + markTurnFailedMock, + mergeArtifactsStateMock, + persistThreadStateMock, + postMessageMock, + setStatusMock, + threadFromJsonMock, + updateConversationStatsMock, + uploadFilesToThreadMock, + upsertConversationMessageMock, +} = vi.hoisted(() => ({ + afterCallbacks: [] as Array<() => Promise | void>, + coerceThreadArtifactsStateMock: vi.fn(), + coerceThreadConversationStateMock: vi.fn(), + deleteMcpAuthSessionMock: vi.fn(), + finalizeMcpAuthorizationMock: vi.fn(), + generateAssistantReplyMock: vi.fn(), + markConversationMessageMock: vi.fn(), + markTurnCompletedMock: vi.fn(), + markTurnFailedMock: vi.fn(), + mergeArtifactsStateMock: vi.fn(), + persistThreadStateMock: vi.fn(), + postMessageMock: vi.fn(), + setStatusMock: vi.fn(), + threadFromJsonMock: vi.fn(), + updateConversationStatsMock: vi.fn(), + uploadFilesToThreadMock: vi.fn(), + upsertConversationMessageMock: vi.fn(), +})); + +vi.mock("chat", () => ({ + ThreadImpl: { + fromJSON: threadFromJsonMock, + }, +})); + +vi.mock("next/server", () => ({ + after: (callback: () => Promise | void) => { + afterCallbacks.push(callback); + }, +})); + +vi.mock("@/chat/mcp/oauth", () => ({ + finalizeMcpAuthorization: finalizeMcpAuthorizationMock, +})); + +vi.mock("@/chat/mcp/auth-store", () => ({ + deleteMcpAuthSession: deleteMcpAuthSessionMock, +})); + +vi.mock("@/chat/respond", () => ({ + generateAssistantReply: generateAssistantReplyMock, +})); + +vi.mock("@/chat/config", () => ({ + botConfig: { + userName: "junior", + }, +})); + +vi.mock("@/chat/slack-actions/client", () => ({ + getSlackClient: () => ({ + chat: { + postMessage: postMessageMock, + }, + assistant: { + threads: { + setStatus: setStatusMock, + }, + }, + }), + uploadFilesToThread: uploadFilesToThreadMock, +})); + +vi.mock("@/chat/observability", () => ({ + logException: vi.fn(), +})); + +vi.mock("@/chat/conversation-state", () => ({ + coerceThreadConversationState: coerceThreadConversationStateMock, +})); + +vi.mock("@/chat/runtime/thread-state", () => ({ + mergeArtifactsState: mergeArtifactsStateMock, + persistThreadState: persistThreadStateMock, +})); + +vi.mock("@/chat/services/conversation-memory", () => ({ + generateConversationId: () => "assistant-1", + markConversationMessage: markConversationMessageMock, + normalizeConversationText: (text: string) => text.trim(), + upsertConversationMessage: upsertConversationMessageMock, + updateConversationStats: updateConversationStatsMock, +})); + +vi.mock("@/chat/slack-actions/types", () => ({ + coerceThreadArtifactsState: coerceThreadArtifactsStateMock, +})); + +vi.mock("@/chat/turn/persist", () => ({ + markTurnCompleted: markTurnCompletedMock, + markTurnFailed: markTurnFailedMock, +})); + +import { GET } from "@/handlers/mcp-oauth-callback"; + +function makeRequest(url: string): Request { + return new Request(url, { method: "GET" }); +} + +function makeContext(provider: string) { + return { + params: Promise.resolve({ provider }), + }; +} + +describe("mcp oauth callback handler", () => { + beforeEach(() => { + afterCallbacks.length = 0; + coerceThreadArtifactsStateMock.mockReset(); + coerceThreadConversationStateMock.mockReset(); + deleteMcpAuthSessionMock.mockReset(); + finalizeMcpAuthorizationMock.mockReset(); + generateAssistantReplyMock.mockReset(); + markConversationMessageMock.mockReset(); + markTurnCompletedMock.mockReset(); + markTurnFailedMock.mockReset(); + mergeArtifactsStateMock.mockReset(); + persistThreadStateMock.mockReset(); + postMessageMock.mockReset(); + setStatusMock.mockReset(); + threadFromJsonMock.mockReset(); + updateConversationStatsMock.mockReset(); + uploadFilesToThreadMock.mockReset(); + upsertConversationMessageMock.mockReset(); + + finalizeMcpAuthorizationMock.mockResolvedValue({ + authSessionId: "state-123", + provider: "demo", + userId: "U123", + conversationId: "conversation-1", + sessionId: "turn_msg_1", + userMessage: "/demo incidents", + channelId: "C123", + threadTs: "1712345.0001", + toolChannelId: "C999", + configuration: { + "demo.org": "acme", + }, + artifactState: { + assistantContextChannelId: "C999", + lastCanvasId: "F123", + }, + createdAtMs: 1, + updatedAtMs: 1, + }); + generateAssistantReplyMock.mockResolvedValue({ + text: "resumed MCP reply", + artifactStatePatch: { + lastCanvasUrl: "https://example.com/canvas", + }, + sandboxId: "sandbox-1", + sandboxDependencyProfileHash: "hash-1", + diagnostics: { + outcome: "success", + toolCalls: [], + }, + }); + postMessageMock.mockResolvedValue(undefined); + setStatusMock.mockResolvedValue(undefined); + uploadFilesToThreadMock.mockResolvedValue(undefined); + threadFromJsonMock.mockReturnValue({ + state: Promise.resolve({ + conversation: {}, + artifacts: {}, + }), + }); + coerceThreadConversationStateMock.mockReturnValue({ + backfill: {}, + compactions: [], + messages: [ + { + id: "msg.1", + role: "user", + text: "/demo incidents", + createdAtMs: 1, + }, + ], + processing: { + activeTurnId: "turn_msg_1", + }, + schemaVersion: 1, + stats: { + compactedMessageCount: 0, + estimatedContextTokens: 0, + totalMessageCount: 1, + updatedAtMs: 1, + }, + vision: { + byFileId: {}, + }, + }); + coerceThreadArtifactsStateMock.mockReturnValue({ + assistantContextChannelId: "C999", + }); + mergeArtifactsStateMock.mockImplementation((current, patch) => ({ + ...current, + ...patch, + })); + deleteMcpAuthSessionMock.mockResolvedValue(undefined); + persistThreadStateMock.mockResolvedValue(undefined); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("returns HTML 400 when the state parameter is missing", async () => { + const response = await GET( + makeRequest("https://example.com/api/oauth/callback/mcp/demo?code=abc"), + makeContext("demo"), + ); + + expect(response.status).toBe(400); + expect(await response.text()).toContain("Missing state parameter"); + expect(finalizeMcpAuthorizationMock).not.toHaveBeenCalled(); + }); + + it("finalizes MCP auth and resumes the paused request in the stored Slack thread", async () => { + const response = await GET( + makeRequest( + "https://example.com/api/oauth/callback/mcp/demo?code=auth-code&state=state-123", + ), + makeContext("demo"), + ); + + expect(response.status).toBe(200); + expect(await response.text()).toContain("Authorization complete"); + expect(finalizeMcpAuthorizationMock).toHaveBeenCalledWith( + "demo", + "state-123", + "auth-code", + ); + expect(afterCallbacks).toHaveLength(1); + + await afterCallbacks[0]!(); + + expect(postMessageMock).toHaveBeenNthCalledWith(1, { + channel: "C123", + thread_ts: "1712345.0001", + text: "Your demo MCP access is now connected. Continuing the original request...", + }); + expect(setStatusMock).toHaveBeenCalledWith({ + channel_id: "C123", + thread_ts: "1712345.0001", + status: "Thinking...", + }); + expect(generateAssistantReplyMock).toHaveBeenCalledWith( + "/demo incidents", + expect.objectContaining({ + assistant: { userName: "junior" }, + requester: { userId: "U123" }, + correlation: { + conversationId: "conversation-1", + turnId: "turn_msg_1", + channelId: "C123", + threadTs: "1712345.0001", + requesterId: "U123", + }, + toolChannelId: "C999", + artifactState: { + assistantContextChannelId: "C999", + lastCanvasId: "F123", + }, + configuration: { + "demo.org": "acme", + }, + }), + ); + + const resumeContext = generateAssistantReplyMock.mock.calls[0]?.[1] as { + channelConfiguration?: { + resolve: (key: string) => Promise; + }; + }; + expect(await resumeContext.channelConfiguration?.resolve("demo.org")).toBe( + "acme", + ); + expect(postMessageMock).toHaveBeenNthCalledWith(2, { + channel: "C123", + thread_ts: "1712345.0001", + text: "resumed MCP reply", + }); + expect(uploadFilesToThreadMock).not.toHaveBeenCalled(); + expect(deleteMcpAuthSessionMock).toHaveBeenCalledWith("state-123"); + expect(markConversationMessageMock).toHaveBeenCalledWith( + expect.anything(), + "msg.1", + { replied: true, skippedReason: undefined }, + ); + expect(markTurnCompletedMock).toHaveBeenCalledTimes(1); + expect(persistThreadStateMock).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + artifacts: { + assistantContextChannelId: "C999", + lastCanvasUrl: "https://example.com/canvas", + }, + sandboxId: "sandbox-1", + sandboxDependencyProfileHash: "hash-1", + }), + ); + }); + + it("respects the resumed reply delivery plan and uploads files to the thread", async () => { + generateAssistantReplyMock.mockResolvedValueOnce({ + text: "", + files: [ + { + data: Buffer.from("hello"), + filename: "resume.txt", + }, + ], + deliveryPlan: { + mode: "thread", + ack: "none", + postThreadText: true, + attachFiles: "inline", + }, + diagnostics: { + outcome: "success", + toolCalls: [], + }, + }); + + const response = await GET( + makeRequest( + "https://example.com/api/oauth/callback/mcp/demo?code=auth-code&state=state-123", + ), + makeContext("demo"), + ); + + expect(response.status).toBe(200); + await afterCallbacks[0]!(); + + expect(postMessageMock).toHaveBeenCalledTimes(1); + expect(uploadFilesToThreadMock).toHaveBeenCalledWith({ + channelId: "C123", + threadTs: "1712345.0001", + files: [ + { + data: Buffer.from("hello"), + filename: "resume.txt", + }, + ], + }); + }); + + it("marks the resumed turn failed in thread state when continuation errors", async () => { + generateAssistantReplyMock.mockRejectedValueOnce( + new Error("resume failed"), + ); + + const response = await GET( + makeRequest( + "https://example.com/api/oauth/callback/mcp/demo?code=auth-code&state=state-123", + ), + makeContext("demo"), + ); + + expect(response.status).toBe(200); + await afterCallbacks[0]!(); + + expect(markTurnFailedMock).toHaveBeenCalledTimes(1); + expect(persistThreadStateMock).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + conversation: expect.anything(), + }), + ); + expect(postMessageMock).toHaveBeenNthCalledWith(2, { + channel: "C123", + thread_ts: "1712345.0001", + text: "MCP authorization completed, but resuming the request failed. Please retry the original command.", + }); + }); +}); diff --git a/packages/junior/tests/plugin-registry-packages.test.ts b/packages/junior/tests/plugin-registry-packages.test.ts index bde9d2da..2321fb08 100644 --- a/packages/junior/tests/plugin-registry-packages.test.ts +++ b/packages/junior/tests/plugin-registry-packages.test.ts @@ -306,6 +306,80 @@ async function writePackagedPluginWithForbiddenApiHeader( ); } +async function writePackagedPluginWithMcp(tempRoot: string): Promise { + const packageRoot = path.join( + tempRoot, + "node_modules", + "@acme", + "junior-plugin-mcp", + ); + const skillsDir = path.join(packageRoot, "skills", "demo"); + await fs.mkdir(skillsDir, { recursive: true }); + await fs.writeFile( + path.join(packageRoot, "plugin.yaml"), + [ + "name: demo", + "description: Demo MCP plugin", + "mcp:", + " transport: http", + " url: https://mcp.example.com", + " headers:", + ' X-Workspace: "acme"', + ].join("\n"), + "utf8", + ); +} + +async function writePackagedPluginWithForbiddenMcpHeader( + tempRoot: string, +): Promise { + const packageRoot = path.join( + tempRoot, + "node_modules", + "@acme", + "junior-plugin-mcp-forbidden-header", + ); + const skillsDir = path.join(packageRoot, "skills", "demo"); + await fs.mkdir(skillsDir, { recursive: true }); + await fs.writeFile( + path.join(packageRoot, "plugin.yaml"), + [ + "name: demo", + "description: Demo MCP plugin", + "mcp:", + " transport: http", + " url: https://mcp.example.com", + " headers:", + ' Authorization: "Bearer nope"', + ].join("\n"), + "utf8", + ); +} + +async function writePackagedPluginWithInvalidMcpTransport( + tempRoot: string, +): Promise { + const packageRoot = path.join( + tempRoot, + "node_modules", + "@acme", + "junior-plugin-mcp-invalid-transport", + ); + const skillsDir = path.join(packageRoot, "skills", "demo"); + await fs.mkdir(skillsDir, { recursive: true }); + await fs.writeFile( + path.join(packageRoot, "plugin.yaml"), + [ + "name: demo", + "description: Demo MCP plugin", + "mcp:", + " transport: stdio", + " url: https://mcp.example.com", + ].join("\n"), + "utf8", + ); +} + async function writeBundlingOnlyPlugin(tempRoot: string): Promise { const packageRoot = path.join( tempRoot, @@ -702,4 +776,97 @@ describe("plugin registry package discovery", () => { "Plugin demo credentials.api-headers.Authorization is not allowed", ); }); + + it("parses HTTP MCP configuration from packaged plugins", async () => { + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "junior-plugin-package-"), + ); + await writePackagedPluginWithMcp(tempRoot); + await fs.writeFile( + path.join(tempRoot, "package.json"), + JSON.stringify({ + name: "temp-junior-app", + private: true, + dependencies: { + "@acme/junior-plugin-mcp": "1.0.0", + }, + }), + "utf8", + ); + process.chdir(tempRoot); + + vi.resetModules(); + vi.doMock("@/chat/home", () => ({ + pluginRoots: () => [], + })); + + const registry = await import("@/chat/plugins/registry"); + const provider = registry.getPluginProviders()[0]; + expect(provider?.manifest.mcp).toEqual({ + transport: "http", + url: "https://mcp.example.com", + headers: { + "X-Workspace": "acme", + }, + }); + expect( + registry.getPluginMcpProviders().map((plugin) => plugin.manifest.name), + ).toEqual(["demo"]); + }); + + it("rejects Authorization in plugin MCP headers", async () => { + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "junior-plugin-package-"), + ); + await writePackagedPluginWithForbiddenMcpHeader(tempRoot); + await fs.writeFile( + path.join(tempRoot, "package.json"), + JSON.stringify({ + name: "temp-junior-app", + private: true, + dependencies: { + "@acme/junior-plugin-mcp-forbidden-header": "1.0.0", + }, + }), + "utf8", + ); + process.chdir(tempRoot); + + vi.resetModules(); + vi.doMock("@/chat/home", () => ({ + pluginRoots: () => [], + })); + + await expect(import("@/chat/plugins/registry")).rejects.toThrow( + "Plugin demo mcp.headers.Authorization is not allowed", + ); + }); + + it("rejects non-http MCP transports", async () => { + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "junior-plugin-package-"), + ); + await writePackagedPluginWithInvalidMcpTransport(tempRoot); + await fs.writeFile( + path.join(tempRoot, "package.json"), + JSON.stringify({ + name: "temp-junior-app", + private: true, + dependencies: { + "@acme/junior-plugin-mcp-invalid-transport": "1.0.0", + }, + }), + "utf8", + ); + process.chdir(tempRoot); + + vi.resetModules(); + vi.doMock("@/chat/home", () => ({ + pluginRoots: () => [], + })); + + await expect(import("@/chat/plugins/registry")).rejects.toThrow( + 'Plugin demo mcp.transport must be "http"', + ); + }); }); diff --git a/packages/junior/tests/unit/mcp/tool-manager.test.ts b/packages/junior/tests/unit/mcp/tool-manager.test.ts new file mode 100644 index 00000000..3fa3c19f --- /dev/null +++ b/packages/junior/tests/unit/mcp/tool-manager.test.ts @@ -0,0 +1,179 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import type { PluginDefinition } from "@/chat/plugins/types"; + +const { callToolMock, closeMock, listToolsMock, onAuthorizationRequiredMock } = + vi.hoisted(() => ({ + callToolMock: vi.fn(), + closeMock: vi.fn(), + listToolsMock: vi.fn(), + onAuthorizationRequiredMock: vi.fn(), + })); + +vi.mock("@/chat/mcp/client", () => { + class MockMcpAuthorizationRequiredError extends Error { + readonly provider: string; + + constructor(provider: string, message: string) { + super(message); + this.name = "McpAuthorizationRequiredError"; + this.provider = provider; + } + } + + class MockPluginMcpClient { + constructor(private readonly plugin: PluginDefinition) {} + + async listTools() { + return await listToolsMock(this.plugin); + } + + async callTool(name: string, args: Record) { + return await callToolMock(this.plugin, name, args); + } + + async close() { + await closeMock(this.plugin); + } + } + + return { + McpAuthorizationRequiredError: MockMcpAuthorizationRequiredError, + PluginMcpClient: MockPluginMcpClient, + }; +}); + +import { McpAuthorizationRequiredError } from "@/chat/mcp/client"; +import { McpToolManager } from "@/chat/mcp/tool-manager"; + +function buildPlugin(): PluginDefinition { + return { + dir: "/tmp/plugins/demo", + skillsDir: "/tmp/plugins/demo/skills", + manifest: { + name: "demo", + description: "Demo MCP plugin", + capabilities: [], + configKeys: [], + mcp: { + transport: "http", + url: "https://mcp.example.com", + }, + }, + }; +} + +describe("McpToolManager", () => { + beforeEach(() => { + listToolsMock.mockReset(); + callToolMock.mockReset(); + closeMock.mockReset(); + onAuthorizationRequiredMock.mockReset(); + + listToolsMock.mockResolvedValue([ + { + name: "ping", + title: "Ping", + description: "Ping the remote MCP server", + inputSchema: { + type: "object", + properties: { + query: { type: "string" }, + }, + }, + }, + ]); + callToolMock.mockResolvedValue({ + content: [{ type: "text", text: "pong" }], + isError: false, + }); + closeMock.mockResolvedValue(undefined); + onAuthorizationRequiredMock.mockResolvedValue(undefined); + }); + + it("activates plugin-scoped MCP tools once and prefixes their names", async () => { + const plugin = buildPlugin(); + const manager = new McpToolManager([plugin]); + + expect(await manager.activateForSkill({ pluginProvider: undefined })).toBe( + false, + ); + expect(await manager.activateForSkill({ pluginProvider: "demo" })).toBe( + true, + ); + expect(await manager.activateProvider("demo")).toBe(false); + expect(manager.getActiveProviders()).toEqual(["demo"]); + + const tools = manager.getActiveTools(); + expect(tools).toHaveLength(1); + expect(tools[0]?.name).toBe("mcp__demo__ping"); + expect(tools[0]?.description).toBe("[demo] Ping the remote MCP server"); + + const result = await tools[0]!.execute("call-1", { + query: "hello", + } as never); + + expect(callToolMock).toHaveBeenCalledWith(plugin, "ping", { + query: "hello", + }); + expect(result).toEqual({ + content: [{ type: "text", text: "pong" }], + details: { + provider: "demo", + tool: "ping", + rawResult: { + content: [{ type: "text", text: "pong" }], + isError: false, + }, + }, + }); + + await manager.close(); + expect(closeMock).toHaveBeenCalledTimes(1); + }); + + it("surfaces MCP authorization challenges through the callback hook", async () => { + const plugin = buildPlugin(); + const manager = new McpToolManager([plugin], { + onAuthorizationRequired: onAuthorizationRequiredMock, + }); + await manager.activateProvider("demo"); + callToolMock.mockRejectedValueOnce( + new McpAuthorizationRequiredError("demo", "Auth required"), + ); + + const tool = manager.getActiveTools()[0]; + await expect(tool!.execute("call-2", {} as never)).rejects.toBeInstanceOf( + McpAuthorizationRequiredError, + ); + expect(onAuthorizationRequiredMock).toHaveBeenCalledTimes(1); + expect(onAuthorizationRequiredMock).toHaveBeenCalledWith( + "demo", + expect.objectContaining({ + provider: "demo", + message: "Auth required", + }), + ); + }); + + it("surfaces MCP authorization challenges during tool discovery", async () => { + const plugin = buildPlugin(); + const manager = new McpToolManager([plugin], { + onAuthorizationRequired: onAuthorizationRequiredMock, + }); + listToolsMock.mockRejectedValueOnce( + new McpAuthorizationRequiredError("demo", "Discovery auth required"), + ); + + await expect(manager.activateProvider("demo")).rejects.toBeInstanceOf( + McpAuthorizationRequiredError, + ); + expect(onAuthorizationRequiredMock).toHaveBeenCalledTimes(1); + expect(onAuthorizationRequiredMock).toHaveBeenCalledWith( + "demo", + expect.objectContaining({ + provider: "demo", + message: "Discovery auth required", + }), + ); + }); +}); diff --git a/packages/junior/tests/unit/skills-plugin-provider.test.ts b/packages/junior/tests/unit/skills-plugin-provider.test.ts new file mode 100644 index 00000000..e008fe86 --- /dev/null +++ b/packages/junior/tests/unit/skills-plugin-provider.test.ts @@ -0,0 +1,93 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +const originalSkillDirs = process.env.SKILL_DIRS; + +async function writeSkill( + rootDir: string, + directoryName: string, + skillName: string, +): Promise { + const skillDir = path.join(rootDir, directoryName); + await fs.mkdir(skillDir, { recursive: true }); + await fs.writeFile( + path.join(skillDir, "SKILL.md"), + [ + "---", + `name: ${skillName}`, + `description: ${skillName} skill`, + "---", + "", + "# Body", + ].join("\n"), + "utf8", + ); +} + +afterEach(() => { + if (originalSkillDirs === undefined) { + delete process.env.SKILL_DIRS; + } else { + process.env.SKILL_DIRS = originalSkillDirs; + } + vi.resetModules(); + vi.doUnmock("@/chat/home"); + vi.doUnmock("@/chat/plugins/package-discovery"); +}); + +describe("discoverSkills plugin ownership", () => { + it("attaches pluginProvider only to plugin-owned skills", async () => { + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "junior-skill-plugin-provider-"), + ); + const pluginsRoot = path.join(tempRoot, "plugins"); + const pluginRoot = path.join(pluginsRoot, "demo"); + const localSkillsRoot = path.join(tempRoot, "skills"); + + await fs.mkdir(path.join(pluginRoot, "skills"), { recursive: true }); + await fs.writeFile( + path.join(pluginRoot, "plugin.yaml"), + ["name: demo", "description: Demo plugin"].join("\n"), + "utf8", + ); + await writeSkill(path.join(pluginRoot, "skills"), "triage", "triage"); + await writeSkill(localSkillsRoot, "notes", "notes"); + + process.env.SKILL_DIRS = localSkillsRoot; + + vi.doMock("@/chat/home", () => ({ + pluginRoots: () => [pluginsRoot], + skillRoots: () => [], + })); + vi.doMock("@/chat/plugins/package-discovery", () => ({ + discoverInstalledPluginPackageContent: () => ({ + packageNames: [], + manifestRoots: [], + skillRoots: [], + tracingIncludes: [], + }), + })); + + try { + const { discoverSkills, resetSkillDiscoveryCache } = + await import("@/chat/skills"); + resetSkillDiscoveryCache(); + + const skills = await discoverSkills(); + expect(skills.find((skill) => skill.name === "triage")).toMatchObject({ + name: "triage", + pluginProvider: "demo", + }); + expect(skills.find((skill) => skill.name === "notes")).toMatchObject({ + name: "notes", + }); + expect( + skills.find((skill) => skill.name === "notes")?.pluginProvider, + ).toBeUndefined(); + } finally { + await fs.rm(tempRoot, { recursive: true, force: true }); + } + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f7a2b3ff..fa590964 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,10 +1,11 @@ -lockfileVersion: "9.0" +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: + .: devDependencies: agent-browser: @@ -25,22 +26,22 @@ importers: apps/example: dependencies: - "@sentry/junior": + '@sentry/junior': specifier: workspace:* version: link:../../packages/junior - "@sentry/junior-agent-browser": + '@sentry/junior-agent-browser': specifier: workspace:* version: link:../../packages/junior-agent-browser - "@sentry/junior-github": + '@sentry/junior-github': specifier: workspace:* version: link:../../packages/junior-github - "@sentry/junior-notion": + '@sentry/junior-notion': specifier: workspace:* version: link:../../packages/junior-notion - "@sentry/junior-sentry": + '@sentry/junior-sentry': specifier: workspace:* version: link:../../packages/junior-sentry - "@sentry/nextjs": + '@sentry/nextjs': specifier: ^10.42.0 version: 10.42.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.1.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.2) next: @@ -53,13 +54,13 @@ importers: specifier: ^19.2.4 version: 19.2.4(react@19.2.4) devDependencies: - "@types/node": + '@types/node': specifier: ^25.3.5 version: 25.3.5 - "@types/react": + '@types/react': specifier: ^19.2.14 version: 19.2.14 - "@types/react-dom": + '@types/react-dom': specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.14) typescript: @@ -68,16 +69,16 @@ importers: packages/docs: dependencies: - "@astrojs/check": + '@astrojs/check': specifier: ^0.9.6 version: 0.9.6(prettier@3.8.1)(typescript@5.9.3) - "@astrojs/starlight": + '@astrojs/starlight': specifier: ^0.37.7 version: 0.37.7(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) - "@fontsource-variable/space-grotesk": + '@fontsource-variable/space-grotesk': specifier: ^5.2.10 version: 5.2.10 - "@fontsource/ibm-plex-mono": + '@fontsource/ibm-plex-mono': specifier: ^5.2.7 version: 5.2.7 astro: @@ -98,34 +99,37 @@ importers: packages/junior: dependencies: - "@ai-sdk/gateway": + '@ai-sdk/gateway': specifier: ^3.0.66 version: 3.0.66(zod@4.3.6) - "@chat-adapter/slack": + '@chat-adapter/slack': specifier: 4.20.2 version: 4.20.2 - "@chat-adapter/state-memory": + '@chat-adapter/state-memory': specifier: 4.20.2 version: 4.20.2 - "@chat-adapter/state-redis": + '@chat-adapter/state-redis': specifier: 4.20.2 version: 4.20.2 - "@mariozechner/pi-agent-core": + '@mariozechner/pi-agent-core': specifier: ^0.59.0 - version: 0.59.0(ws@8.19.0)(zod@4.3.6) - "@mariozechner/pi-ai": + version: 0.59.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.19.0)(zod@4.3.6) + '@mariozechner/pi-ai': specifier: ^0.59.0 - version: 0.59.0(ws@8.19.0)(zod@4.3.6) - "@sinclair/typebox": + version: 0.59.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.19.0)(zod@4.3.6) + '@modelcontextprotocol/sdk': + specifier: 1.27.1 + version: 1.27.1(zod@4.3.6) + '@sinclair/typebox': specifier: ^0.34.48 version: 0.34.48 - "@slack/web-api": + '@slack/web-api': specifier: ^7.15.0 version: 7.15.0 - "@vercel/queue": + '@vercel/queue': specifier: ^0.1.4 version: 0.1.4 - "@vercel/sandbox": + '@vercel/sandbox': specifier: ^1.8.1 version: 1.8.1 ai: @@ -150,16 +154,16 @@ importers: specifier: ^4.3.6 version: 4.3.6 devDependencies: - "@sentry/nextjs": + '@sentry/nextjs': specifier: ^10.44.0 version: 10.44.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.1.7(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3)) - "@types/node": + '@types/node': specifier: ^25.3.5 version: 25.3.5 - "@types/react": + '@types/react': specifier: ^19.2.14 version: 19.2.14 - "@types/react-dom": + '@types/react-dom': specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.14) msw: @@ -199,36 +203,25 @@ importers: packages/junior-sentry: {} packages: - "@ai-sdk/gateway@3.0.66": - resolution: - { - integrity: sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A==, - } - engines: { node: ">=18" } + + '@ai-sdk/gateway@3.0.66': + resolution: {integrity: sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A==} + engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - "@ai-sdk/provider-utils@4.0.19": - resolution: - { - integrity: sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg==, - } - engines: { node: ">=18" } + '@ai-sdk/provider-utils@4.0.19': + resolution: {integrity: sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg==} + engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - "@ai-sdk/provider@3.0.8": - resolution: - { - integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==, - } - engines: { node: ">=18" } - - "@anthropic-ai/sdk@0.73.0": - resolution: - { - integrity: sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw==, - } + '@ai-sdk/provider@3.0.8': + resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==} + engines: {node: '>=18'} + + '@anthropic-ai/sdk@0.73.0': + resolution: {integrity: sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw==} hasBin: true peerDependencies: zod: ^3.25.0 || ^4.0.0 @@ -236,4619 +229,2874 @@ packages: zod: optional: true - "@appium/logger@1.7.1": - resolution: - { - integrity: sha512-9C2o9X/lBEDBUnKfAi3mRo9oG7Z03nmISLwsGkWxIWjMAvBdJD0RRSJMekWVKzfXN3byrI1WlCXTITzN4LAoLw==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: ">=8" } - - "@astrojs/check@0.9.6": - resolution: - { - integrity: sha512-jlaEu5SxvSgmfGIFfNgcn5/f+29H61NJzEMfAZ82Xopr4XBchXB1GVlcJsE+elUlsYSbXlptZLX+JMG3b/wZEA==, - } + '@appium/logger@1.7.1': + resolution: {integrity: sha512-9C2o9X/lBEDBUnKfAi3mRo9oG7Z03nmISLwsGkWxIWjMAvBdJD0RRSJMekWVKzfXN3byrI1WlCXTITzN4LAoLw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=8'} + + '@astrojs/check@0.9.6': + resolution: {integrity: sha512-jlaEu5SxvSgmfGIFfNgcn5/f+29H61NJzEMfAZ82Xopr4XBchXB1GVlcJsE+elUlsYSbXlptZLX+JMG3b/wZEA==} hasBin: true peerDependencies: typescript: ^5.0.0 - "@astrojs/compiler@2.13.1": - resolution: - { - integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==, - } - - "@astrojs/internal-helpers@0.7.5": - resolution: - { - integrity: sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==, - } - - "@astrojs/language-server@2.16.3": - resolution: - { - integrity: sha512-yO5K7RYCMXUfeDlnU6UnmtnoXzpuQc0yhlaCNZ67k1C/MiwwwvMZz+LGa+H35c49w5QBfvtr4w4Zcf5PcH8uYA==, - } + '@astrojs/compiler@2.13.1': + resolution: {integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==} + + '@astrojs/internal-helpers@0.7.5': + resolution: {integrity: sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==} + + '@astrojs/language-server@2.16.3': + resolution: {integrity: sha512-yO5K7RYCMXUfeDlnU6UnmtnoXzpuQc0yhlaCNZ67k1C/MiwwwvMZz+LGa+H35c49w5QBfvtr4w4Zcf5PcH8uYA==} hasBin: true peerDependencies: prettier: ^3.0.0 - prettier-plugin-astro: ">=0.11.0" + prettier-plugin-astro: '>=0.11.0' peerDependenciesMeta: prettier: optional: true prettier-plugin-astro: optional: true - "@astrojs/markdown-remark@6.3.10": - resolution: - { - integrity: sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==, - } - - "@astrojs/mdx@4.3.13": - resolution: - { - integrity: sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==, - } - engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } + '@astrojs/markdown-remark@6.3.10': + resolution: {integrity: sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==} + + '@astrojs/mdx@4.3.13': + resolution: {integrity: sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} peerDependencies: astro: ^5.0.0 - "@astrojs/prism@3.3.0": - resolution: - { - integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==, - } - engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } - - "@astrojs/sitemap@3.7.0": - resolution: - { - integrity: sha512-+qxjUrz6Jcgh+D5VE1gKUJTA3pSthuPHe6Ao5JCxok794Lewx8hBFaWHtOnN0ntb2lfOf7gvOi9TefUswQ/ZVA==, - } - - "@astrojs/starlight@0.37.7": - resolution: - { - integrity: sha512-KyBnou8aKIlPJUSNx6a1SN7XyH22oj/VAvTGC+Edld4Bnei1A//pmCRTBvSrSeoGrdUjK0ErFUfaEhhO1bPfDg==, - } + '@astrojs/prism@3.3.0': + resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@astrojs/sitemap@3.7.0': + resolution: {integrity: sha512-+qxjUrz6Jcgh+D5VE1gKUJTA3pSthuPHe6Ao5JCxok794Lewx8hBFaWHtOnN0ntb2lfOf7gvOi9TefUswQ/ZVA==} + + '@astrojs/starlight@0.37.7': + resolution: {integrity: sha512-KyBnou8aKIlPJUSNx6a1SN7XyH22oj/VAvTGC+Edld4Bnei1A//pmCRTBvSrSeoGrdUjK0ErFUfaEhhO1bPfDg==} peerDependencies: astro: ^5.5.0 - "@astrojs/telemetry@3.3.0": - resolution: - { - integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==, - } - engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } - - "@astrojs/yaml2ts@0.2.2": - resolution: - { - integrity: sha512-GOfvSr5Nqy2z5XiwqTouBBpy5FyI6DEe+/g/Mk5am9SjILN1S5fOEvYK0GuWHg98yS/dobP4m8qyqw/URW35fQ==, - } - - "@aws-crypto/crc32@5.2.0": - resolution: - { - integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==, - } - engines: { node: ">=16.0.0" } - - "@aws-crypto/sha256-browser@5.2.0": - resolution: - { - integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==, - } - - "@aws-crypto/sha256-js@5.2.0": - resolution: - { - integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==, - } - engines: { node: ">=16.0.0" } - - "@aws-crypto/supports-web-crypto@5.2.0": - resolution: - { - integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==, - } - - "@aws-crypto/util@5.2.0": - resolution: - { - integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==, - } - - "@aws-sdk/client-bedrock-runtime@3.1003.0": - resolution: - { - integrity: sha512-b39kYrFC3dGFQ7S5UiHKD8aGCFr0/k+QXDzqnT8N2zi8JILEvdxBhMWNqCIpZAbCCK2Jp9S8jK5/Vh0TfLUIPQ==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/core@3.973.18": - resolution: - { - integrity: sha512-GUIlegfcK2LO1J2Y98sCJy63rQSiLiDOgVw7HiHPRqfI2vb3XozTVqemwO0VSGXp54ngCnAQz0Lf0YPCBINNxA==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/credential-provider-env@3.972.16": - resolution: - { - integrity: sha512-HrdtnadvTGAQUr18sPzGlE5El3ICphnH6SU7UQOMOWFgRKbTRNN8msTxM4emzguUso9CzaHU2xy5ctSrmK5YNA==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/credential-provider-http@3.972.18": - resolution: - { - integrity: sha512-NyB6smuZAixND5jZumkpkunQ0voc4Mwgkd+SZ6cvAzIB7gK8HV8Zd4rS8Kn5MmoGgusyNfVGG+RLoYc4yFiw+A==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/credential-provider-ini@3.972.16": - resolution: - { - integrity: sha512-hzAnzNXKV0A4knFRWGu2NCt72P4WWxpEGnOc6H3DptUjC4oX3hGw846oN76M1rTHAOwDdbhjU0GAOWR4OUfTZg==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/credential-provider-login@3.972.16": - resolution: - { - integrity: sha512-VI0kXTlr0o1FTay+Jvx6AKqx5ECBgp7X4VevGBEbuXdCXnNp7SPU0KvjsOLVhIz3OoPK4/lTXphk43t0IVk65w==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/credential-provider-node@3.972.17": - resolution: - { - integrity: sha512-98MAcQ2Dk7zkvgwZ5f6fLX2lTyptC3gTSDx4EpvTdJWET8qs9lBPYggoYx7GmKp/5uk0OwVl0hxIDZsDNS/Y9g==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/credential-provider-process@3.972.16": - resolution: - { - integrity: sha512-n89ibATwnLEg0ZdZmUds5bq8AfBAdoYEDpqP3uzPLaRuGelsKlIvCYSNNvfgGLi8NaHPNNhs1HjJZYbqkW9b+g==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/credential-provider-sso@3.972.16": - resolution: - { - integrity: sha512-b9of7tQgERxgcEcwAFWvRe84ivw+Kw6b3jVuz/6LQzonkomiY5UoWfprkbjc8FSCQ2VjDqKTvIRA9F0KSQ025w==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/credential-provider-web-identity@3.972.16": - resolution: - { - integrity: sha512-PaOH5jFoPQX4WkqpKzKh9cM7rieKtbgEGqrZ+ybGmotJhcvhI/xl69yCwMbHGnpQJJmHZIX9q2zaPB7HTBn/4w==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/eventstream-handler-node@3.972.10": - resolution: - { - integrity: sha512-g2Z9s6Y4iNh0wICaEqutgYgt/Pmhv5Ev9G3eKGFe2w9VuZDhc76vYdop6I5OocmpHV79d4TuLG+JWg5rQIVDVA==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/middleware-eventstream@3.972.7": - resolution: - { - integrity: sha512-VWndapHYCfwLgPpCb/xwlMKG4imhFzKJzZcKOEioGn7OHY+6gdr0K7oqy1HZgbLa3ACznZ9fku+DzmAi8fUC0g==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/middleware-host-header@3.972.7": - resolution: - { - integrity: sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/middleware-logger@3.972.7": - resolution: - { - integrity: sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/middleware-recursion-detection@3.972.7": - resolution: - { - integrity: sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/middleware-user-agent@3.972.18": - resolution: - { - integrity: sha512-KcqQDs/7WtoEnp52+879f8/i1XAJkgka5i4arOtOCPR10o4wWo3VRecDI9Gxoh6oghmLCnIiOSKyRcXI/50E+w==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/middleware-websocket@3.972.12": - resolution: - { - integrity: sha512-iyPP6FVDKe/5wy5ojC0akpDFG1vX3FeCUU47JuwN8xfvT66xlEI8qUJZPtN55TJVFzzWZJpWL78eqUE31md08Q==, - } - engines: { node: ">= 14.0.0" } - - "@aws-sdk/nested-clients@3.996.6": - resolution: - { - integrity: sha512-blNJ3ugn4gCQ9ZSZi/firzKCvVl5LvPFVxv24LprENeWI4R8UApG006UQkF4SkmLygKq2BQXRad2/anQ13Te4Q==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/region-config-resolver@3.972.7": - resolution: - { - integrity: sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/token-providers@3.1003.0": - resolution: - { - integrity: sha512-SOyyWNdT7njKRwtZ1JhwHlH1csv6Pkgf305X96/OIfnhq1pU/EjmT6W6por57rVrjrKuHBuEIXgpWv8OgoMHpg==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/types@3.973.5": - resolution: - { - integrity: sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/util-endpoints@3.996.4": - resolution: - { - integrity: sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/util-format-url@3.972.7": - resolution: - { - integrity: sha512-V+PbnWfUl93GuFwsOHsAq7hY/fnm9kElRqR8IexIJr5Rvif9e614X5sGSyz3mVSf1YAZ+VTy63W1/pGdA55zyA==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/util-locate-window@3.965.5": - resolution: - { - integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==, - } - engines: { node: ">=20.0.0" } - - "@aws-sdk/util-user-agent-browser@3.972.7": - resolution: - { - integrity: sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw==, - } - - "@aws-sdk/util-user-agent-node@3.973.3": - resolution: - { - integrity: sha512-8s2cQmTUOwcBlIJyI9PAZNnnnF+cGtdhHc1yzMMsSD/GR/Hxj7m0IGUE92CslXXb8/p5Q76iqOCjN1GFwyf+1A==, - } - engines: { node: ">=20.0.0" } + '@astrojs/telemetry@3.3.0': + resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@astrojs/yaml2ts@0.2.2': + resolution: {integrity: sha512-GOfvSr5Nqy2z5XiwqTouBBpy5FyI6DEe+/g/Mk5am9SjILN1S5fOEvYK0GuWHg98yS/dobP4m8qyqw/URW35fQ==} + + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.1003.0': + resolution: {integrity: sha512-b39kYrFC3dGFQ7S5UiHKD8aGCFr0/k+QXDzqnT8N2zi8JILEvdxBhMWNqCIpZAbCCK2Jp9S8jK5/Vh0TfLUIPQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.973.18': + resolution: {integrity: sha512-GUIlegfcK2LO1J2Y98sCJy63rQSiLiDOgVw7HiHPRqfI2vb3XozTVqemwO0VSGXp54ngCnAQz0Lf0YPCBINNxA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.16': + resolution: {integrity: sha512-HrdtnadvTGAQUr18sPzGlE5El3ICphnH6SU7UQOMOWFgRKbTRNN8msTxM4emzguUso9CzaHU2xy5ctSrmK5YNA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.18': + resolution: {integrity: sha512-NyB6smuZAixND5jZumkpkunQ0voc4Mwgkd+SZ6cvAzIB7gK8HV8Zd4rS8Kn5MmoGgusyNfVGG+RLoYc4yFiw+A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.16': + resolution: {integrity: sha512-hzAnzNXKV0A4knFRWGu2NCt72P4WWxpEGnOc6H3DptUjC4oX3hGw846oN76M1rTHAOwDdbhjU0GAOWR4OUfTZg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.16': + resolution: {integrity: sha512-VI0kXTlr0o1FTay+Jvx6AKqx5ECBgp7X4VevGBEbuXdCXnNp7SPU0KvjsOLVhIz3OoPK4/lTXphk43t0IVk65w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.17': + resolution: {integrity: sha512-98MAcQ2Dk7zkvgwZ5f6fLX2lTyptC3gTSDx4EpvTdJWET8qs9lBPYggoYx7GmKp/5uk0OwVl0hxIDZsDNS/Y9g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.16': + resolution: {integrity: sha512-n89ibATwnLEg0ZdZmUds5bq8AfBAdoYEDpqP3uzPLaRuGelsKlIvCYSNNvfgGLi8NaHPNNhs1HjJZYbqkW9b+g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.16': + resolution: {integrity: sha512-b9of7tQgERxgcEcwAFWvRe84ivw+Kw6b3jVuz/6LQzonkomiY5UoWfprkbjc8FSCQ2VjDqKTvIRA9F0KSQ025w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.16': + resolution: {integrity: sha512-PaOH5jFoPQX4WkqpKzKh9cM7rieKtbgEGqrZ+ybGmotJhcvhI/xl69yCwMbHGnpQJJmHZIX9q2zaPB7HTBn/4w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.10': + resolution: {integrity: sha512-g2Z9s6Y4iNh0wICaEqutgYgt/Pmhv5Ev9G3eKGFe2w9VuZDhc76vYdop6I5OocmpHV79d4TuLG+JWg5rQIVDVA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.7': + resolution: {integrity: sha512-VWndapHYCfwLgPpCb/xwlMKG4imhFzKJzZcKOEioGn7OHY+6gdr0K7oqy1HZgbLa3ACznZ9fku+DzmAi8fUC0g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-host-header@3.972.7': + resolution: {integrity: sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-logger@3.972.7': + resolution: {integrity: sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.972.7': + resolution: {integrity: sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-user-agent@3.972.18': + resolution: {integrity: sha512-KcqQDs/7WtoEnp52+879f8/i1XAJkgka5i4arOtOCPR10o4wWo3VRecDI9Gxoh6oghmLCnIiOSKyRcXI/50E+w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.12': + resolution: {integrity: sha512-iyPP6FVDKe/5wy5ojC0akpDFG1vX3FeCUU47JuwN8xfvT66xlEI8qUJZPtN55TJVFzzWZJpWL78eqUE31md08Q==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.996.6': + resolution: {integrity: sha512-blNJ3ugn4gCQ9ZSZi/firzKCvVl5LvPFVxv24LprENeWI4R8UApG006UQkF4SkmLygKq2BQXRad2/anQ13Te4Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/region-config-resolver@3.972.7': + resolution: {integrity: sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1003.0': + resolution: {integrity: sha512-SOyyWNdT7njKRwtZ1JhwHlH1csv6Pkgf305X96/OIfnhq1pU/EjmT6W6por57rVrjrKuHBuEIXgpWv8OgoMHpg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.5': + resolution: {integrity: sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-endpoints@3.996.4': + resolution: {integrity: sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-format-url@3.972.7': + resolution: {integrity: sha512-V+PbnWfUl93GuFwsOHsAq7hY/fnm9kElRqR8IexIJr5Rvif9e614X5sGSyz3mVSf1YAZ+VTy63W1/pGdA55zyA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.5': + resolution: {integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-user-agent-browser@3.972.7': + resolution: {integrity: sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw==} + + '@aws-sdk/util-user-agent-node@3.973.3': + resolution: {integrity: sha512-8s2cQmTUOwcBlIJyI9PAZNnnnF+cGtdhHc1yzMMsSD/GR/Hxj7m0IGUE92CslXXb8/p5Q76iqOCjN1GFwyf+1A==} + engines: {node: '>=20.0.0'} peerDependencies: - aws-crt: ">=1.0.0" + aws-crt: '>=1.0.0' peerDependenciesMeta: aws-crt: optional: true - "@aws-sdk/xml-builder@3.972.10": - resolution: - { - integrity: sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA==, - } - engines: { node: ">=20.0.0" } - - "@aws/lambda-invoke-store@0.2.3": - resolution: - { - integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==, - } - engines: { node: ">=18.0.0" } - - "@babel/code-frame@7.29.0": - resolution: - { - integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==, - } - engines: { node: ">=6.9.0" } - - "@babel/compat-data@7.29.0": - resolution: - { - integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==, - } - engines: { node: ">=6.9.0" } - - "@babel/core@7.29.0": - resolution: - { - integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==, - } - engines: { node: ">=6.9.0" } - - "@babel/generator@7.29.1": - resolution: - { - integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-compilation-targets@7.28.6": - resolution: - { - integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-globals@7.28.0": - resolution: - { - integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-module-imports@7.28.6": - resolution: - { - integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-module-transforms@7.28.6": - resolution: - { - integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==, - } - engines: { node: ">=6.9.0" } + '@aws-sdk/xml-builder@3.972.10': + resolution: {integrity: sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.3': + resolution: {integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==} + engines: {node: '>=18.0.0'} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} peerDependencies: - "@babel/core": ^7.0.0 - - "@babel/helper-string-parser@7.27.1": - resolution: - { - integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-validator-identifier@7.28.5": - resolution: - { - integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==, - } - engines: { node: ">=6.9.0" } - - "@babel/helper-validator-option@7.27.1": - resolution: - { - integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==, - } - engines: { node: ">=6.9.0" } - - "@babel/helpers@7.28.6": - resolution: - { - integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==, - } - engines: { node: ">=6.9.0" } - - "@babel/parser@7.29.0": - resolution: - { - integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==, - } - engines: { node: ">=6.0.0" } + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} hasBin: true - "@babel/runtime@7.28.6": - resolution: - { - integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==, - } - engines: { node: ">=6.9.0" } - - "@babel/template@7.28.6": - resolution: - { - integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==, - } - engines: { node: ">=6.9.0" } - - "@babel/traverse@7.29.0": - resolution: - { - integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==, - } - engines: { node: ">=6.9.0" } - - "@babel/types@7.29.0": - resolution: - { - integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==, - } - engines: { node: ">=6.9.0" } - - "@borewit/text-codec@0.2.1": - resolution: - { - integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==, - } - - "@bytecodealliance/preview2-shim@0.17.6": - resolution: - { - integrity: sha512-n3cM88gTen5980UOBAD6xDcNNL3ocTK8keab21bpx1ONdA+ARj7uD1qoFxOWCyKlkpSi195FH+GeAut7Oc6zZw==, - } - - "@capsizecss/unpack@4.0.0": - resolution: - { - integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==, - } - engines: { node: ">=18" } - - "@chat-adapter/shared@4.20.2": - resolution: - { - integrity: sha512-cTtTVHgH/2l9/+ILSExCr/kZwzz2Y8tp7WKRweMRWFOBcXZ0U5ZtviZCCDWBqU/YOBilQUgON8vIP9eo1w0m5w==, - } - - "@chat-adapter/slack@4.20.2": - resolution: - { - integrity: sha512-DCGMdB5sLG7lJ8TTv6zHUC3GQXfW3zWXLv+w5sRc+Km0Rq4tG43vLMmcCAd3AEj2Bjhl0bnWjhkTwR7txlu7TQ==, - } - - "@chat-adapter/state-memory@4.20.2": - resolution: - { - integrity: sha512-4388hp9Wsp87jMgSpkPfN4abflgIgQn5M3MLSDYdU4f20PNKrUkzhb8elkyPmYliF4MInZUau+llc26b7hZsng==, - } - - "@chat-adapter/state-redis@4.20.2": - resolution: - { - integrity: sha512-YngO0be1ZYrSZqZMHqHeCBfMWLj9jb1Kwpf5GGC25tk/aMc/ake/5EjYjrJOFO/0TLgLC2y1SwRe+sGtA8DjqA==, - } - - "@ctrl/tinycolor@4.2.0": - resolution: - { - integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==, - } - engines: { node: ">=14" } - - "@edge-runtime/format@2.2.1": - resolution: - { - integrity: sha512-JQTRVuiusQLNNLe2W9tnzBlV/GvSVcozLl4XZHk5swnRZ/v6jp8TqR8P7sqmJsQqblDZ3EztcWmLDbhRje/+8g==, - } - engines: { node: ">=16" } - - "@edge-runtime/node-utils@2.3.0": - resolution: - { - integrity: sha512-uUtx8BFoO1hNxtHjp3eqVPC/mWImGb2exOfGjMLUoipuWgjej+f4o/VP4bUI8U40gu7Teogd5VTeZUkGvJSPOQ==, - } - engines: { node: ">=16" } - - "@edge-runtime/ponyfill@2.4.2": - resolution: - { - integrity: sha512-oN17GjFr69chu6sDLvXxdhg0Qe8EZviGSuqzR9qOiKh4MhFYGdBBcqRNzdmYeAdeRzOW2mM9yil4RftUQ7sUOA==, - } - engines: { node: ">=16" } - - "@edge-runtime/primitives@4.1.0": - resolution: - { - integrity: sha512-Vw0lbJ2lvRUqc7/soqygUX216Xb8T3WBZ987oywz6aJqRxcwSVWwr9e+Nqo2m9bxobA9mdbWNNoRY6S9eko1EQ==, - } - engines: { node: ">=16" } - - "@edge-runtime/vm@3.2.0": - resolution: - { - integrity: sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==, - } - engines: { node: ">=16" } - - "@emmetio/abbreviation@2.3.3": - resolution: - { - integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==, - } - - "@emmetio/css-abbreviation@2.1.8": - resolution: - { - integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==, - } - - "@emmetio/css-parser@0.4.1": - resolution: - { - integrity: sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==, - } - - "@emmetio/html-matcher@1.3.0": - resolution: - { - integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==, - } - - "@emmetio/scanner@1.0.4": - resolution: - { - integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==, - } - - "@emmetio/stream-reader-utils@0.1.0": - resolution: - { - integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==, - } - - "@emmetio/stream-reader@2.2.0": - resolution: - { - integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==, - } - - "@emnapi/core@1.8.1": - resolution: - { - integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==, - } - - "@emnapi/runtime@1.9.0": - resolution: - { - integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==, - } - - "@emnapi/wasi-threads@1.1.0": - resolution: - { - integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==, - } - - "@esbuild/aix-ppc64@0.25.12": - resolution: - { - integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==, - } - engines: { node: ">=18" } + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@borewit/text-codec@0.2.1': + resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + + '@bytecodealliance/preview2-shim@0.17.6': + resolution: {integrity: sha512-n3cM88gTen5980UOBAD6xDcNNL3ocTK8keab21bpx1ONdA+ARj7uD1qoFxOWCyKlkpSi195FH+GeAut7Oc6zZw==} + + '@capsizecss/unpack@4.0.0': + resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} + engines: {node: '>=18'} + + '@chat-adapter/shared@4.20.2': + resolution: {integrity: sha512-cTtTVHgH/2l9/+ILSExCr/kZwzz2Y8tp7WKRweMRWFOBcXZ0U5ZtviZCCDWBqU/YOBilQUgON8vIP9eo1w0m5w==} + + '@chat-adapter/slack@4.20.2': + resolution: {integrity: sha512-DCGMdB5sLG7lJ8TTv6zHUC3GQXfW3zWXLv+w5sRc+Km0Rq4tG43vLMmcCAd3AEj2Bjhl0bnWjhkTwR7txlu7TQ==} + + '@chat-adapter/state-memory@4.20.2': + resolution: {integrity: sha512-4388hp9Wsp87jMgSpkPfN4abflgIgQn5M3MLSDYdU4f20PNKrUkzhb8elkyPmYliF4MInZUau+llc26b7hZsng==} + + '@chat-adapter/state-redis@4.20.2': + resolution: {integrity: sha512-YngO0be1ZYrSZqZMHqHeCBfMWLj9jb1Kwpf5GGC25tk/aMc/ake/5EjYjrJOFO/0TLgLC2y1SwRe+sGtA8DjqA==} + + '@ctrl/tinycolor@4.2.0': + resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} + engines: {node: '>=14'} + + '@edge-runtime/format@2.2.1': + resolution: {integrity: sha512-JQTRVuiusQLNNLe2W9tnzBlV/GvSVcozLl4XZHk5swnRZ/v6jp8TqR8P7sqmJsQqblDZ3EztcWmLDbhRje/+8g==} + engines: {node: '>=16'} + + '@edge-runtime/node-utils@2.3.0': + resolution: {integrity: sha512-uUtx8BFoO1hNxtHjp3eqVPC/mWImGb2exOfGjMLUoipuWgjej+f4o/VP4bUI8U40gu7Teogd5VTeZUkGvJSPOQ==} + engines: {node: '>=16'} + + '@edge-runtime/ponyfill@2.4.2': + resolution: {integrity: sha512-oN17GjFr69chu6sDLvXxdhg0Qe8EZviGSuqzR9qOiKh4MhFYGdBBcqRNzdmYeAdeRzOW2mM9yil4RftUQ7sUOA==} + engines: {node: '>=16'} + + '@edge-runtime/primitives@4.1.0': + resolution: {integrity: sha512-Vw0lbJ2lvRUqc7/soqygUX216Xb8T3WBZ987oywz6aJqRxcwSVWwr9e+Nqo2m9bxobA9mdbWNNoRY6S9eko1EQ==} + engines: {node: '>=16'} + + '@edge-runtime/vm@3.2.0': + resolution: {integrity: sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==} + engines: {node: '>=16'} + + '@emmetio/abbreviation@2.3.3': + resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} + + '@emmetio/css-abbreviation@2.1.8': + resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} + + '@emmetio/css-parser@0.4.1': + resolution: {integrity: sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==} + + '@emmetio/html-matcher@1.3.0': + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + + '@emmetio/scanner@1.0.4': + resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} + + '@emmetio/stream-reader-utils@0.1.0': + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + + '@emmetio/stream-reader@2.2.0': + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + + '@emnapi/runtime@1.9.0': + resolution: {integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - "@esbuild/aix-ppc64@0.27.0": - resolution: - { - integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==, - } - engines: { node: ">=18" } + '@esbuild/aix-ppc64@0.27.0': + resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - "@esbuild/aix-ppc64@0.27.3": - resolution: - { - integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==, - } - engines: { node: ">=18" } + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - "@esbuild/android-arm64@0.25.12": - resolution: - { - integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==, - } - engines: { node: ">=18" } + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - "@esbuild/android-arm64@0.27.0": - resolution: - { - integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==, - } - engines: { node: ">=18" } + '@esbuild/android-arm64@0.27.0': + resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - "@esbuild/android-arm64@0.27.3": - resolution: - { - integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==, - } - engines: { node: ">=18" } + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - "@esbuild/android-arm@0.25.12": - resolution: - { - integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==, - } - engines: { node: ">=18" } + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} cpu: [arm] os: [android] - "@esbuild/android-arm@0.27.0": - resolution: - { - integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==, - } - engines: { node: ">=18" } + '@esbuild/android-arm@0.27.0': + resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==} + engines: {node: '>=18'} cpu: [arm] os: [android] - "@esbuild/android-arm@0.27.3": - resolution: - { - integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==, - } - engines: { node: ">=18" } + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} cpu: [arm] os: [android] - "@esbuild/android-x64@0.25.12": - resolution: - { - integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==, - } - engines: { node: ">=18" } + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} cpu: [x64] os: [android] - "@esbuild/android-x64@0.27.0": - resolution: - { - integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==, - } - engines: { node: ">=18" } + '@esbuild/android-x64@0.27.0': + resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==} + engines: {node: '>=18'} cpu: [x64] os: [android] - "@esbuild/android-x64@0.27.3": - resolution: - { - integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==, - } - engines: { node: ">=18" } + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} cpu: [x64] os: [android] - "@esbuild/darwin-arm64@0.25.12": - resolution: - { - integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==, - } - engines: { node: ">=18" } + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - "@esbuild/darwin-arm64@0.27.0": - resolution: - { - integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==, - } - engines: { node: ">=18" } + '@esbuild/darwin-arm64@0.27.0': + resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - "@esbuild/darwin-arm64@0.27.3": - resolution: - { - integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==, - } - engines: { node: ">=18" } + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - "@esbuild/darwin-x64@0.25.12": - resolution: - { - integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==, - } - engines: { node: ">=18" } + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - "@esbuild/darwin-x64@0.27.0": - resolution: - { - integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==, - } - engines: { node: ">=18" } + '@esbuild/darwin-x64@0.27.0': + resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - "@esbuild/darwin-x64@0.27.3": - resolution: - { - integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==, - } - engines: { node: ">=18" } + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - "@esbuild/freebsd-arm64@0.25.12": - resolution: - { - integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==, - } - engines: { node: ">=18" } + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - "@esbuild/freebsd-arm64@0.27.0": - resolution: - { - integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==, - } - engines: { node: ">=18" } + '@esbuild/freebsd-arm64@0.27.0': + resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - "@esbuild/freebsd-arm64@0.27.3": - resolution: - { - integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==, - } - engines: { node: ">=18" } + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - "@esbuild/freebsd-x64@0.25.12": - resolution: - { - integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==, - } - engines: { node: ">=18" } + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - "@esbuild/freebsd-x64@0.27.0": - resolution: - { - integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==, - } - engines: { node: ">=18" } + '@esbuild/freebsd-x64@0.27.0': + resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - "@esbuild/freebsd-x64@0.27.3": - resolution: - { - integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==, - } - engines: { node: ">=18" } + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - "@esbuild/linux-arm64@0.25.12": - resolution: - { - integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==, - } - engines: { node: ">=18" } + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - "@esbuild/linux-arm64@0.27.0": - resolution: - { - integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==, - } - engines: { node: ">=18" } + '@esbuild/linux-arm64@0.27.0': + resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - "@esbuild/linux-arm64@0.27.3": - resolution: - { - integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==, - } - engines: { node: ">=18" } + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - "@esbuild/linux-arm@0.25.12": - resolution: - { - integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==, - } - engines: { node: ">=18" } + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - "@esbuild/linux-arm@0.27.0": - resolution: - { - integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==, - } - engines: { node: ">=18" } + '@esbuild/linux-arm@0.27.0': + resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - "@esbuild/linux-arm@0.27.3": - resolution: - { - integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==, - } - engines: { node: ">=18" } + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - "@esbuild/linux-ia32@0.25.12": - resolution: - { - integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==, - } - engines: { node: ">=18" } + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - "@esbuild/linux-ia32@0.27.0": - resolution: - { - integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==, - } - engines: { node: ">=18" } + '@esbuild/linux-ia32@0.27.0': + resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - "@esbuild/linux-ia32@0.27.3": - resolution: - { - integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==, - } - engines: { node: ">=18" } + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - "@esbuild/linux-loong64@0.25.12": - resolution: - { - integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==, - } - engines: { node: ">=18" } + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - "@esbuild/linux-loong64@0.27.0": - resolution: - { - integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==, - } - engines: { node: ">=18" } + '@esbuild/linux-loong64@0.27.0': + resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - "@esbuild/linux-loong64@0.27.3": - resolution: - { - integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==, - } - engines: { node: ">=18" } + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - "@esbuild/linux-mips64el@0.25.12": - resolution: - { - integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==, - } - engines: { node: ">=18" } + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - "@esbuild/linux-mips64el@0.27.0": - resolution: - { - integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==, - } - engines: { node: ">=18" } + '@esbuild/linux-mips64el@0.27.0': + resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - "@esbuild/linux-mips64el@0.27.3": - resolution: - { - integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==, - } - engines: { node: ">=18" } + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - "@esbuild/linux-ppc64@0.25.12": - resolution: - { - integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==, - } - engines: { node: ">=18" } + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - "@esbuild/linux-ppc64@0.27.0": - resolution: - { - integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==, - } - engines: { node: ">=18" } + '@esbuild/linux-ppc64@0.27.0': + resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - "@esbuild/linux-ppc64@0.27.3": - resolution: - { - integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==, - } - engines: { node: ">=18" } + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - "@esbuild/linux-riscv64@0.25.12": - resolution: - { - integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==, - } - engines: { node: ">=18" } + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - "@esbuild/linux-riscv64@0.27.0": - resolution: - { - integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==, - } - engines: { node: ">=18" } + '@esbuild/linux-riscv64@0.27.0': + resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - "@esbuild/linux-riscv64@0.27.3": - resolution: - { - integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==, - } - engines: { node: ">=18" } + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - "@esbuild/linux-s390x@0.25.12": - resolution: - { - integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==, - } - engines: { node: ">=18" } + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - "@esbuild/linux-s390x@0.27.0": - resolution: - { - integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==, - } - engines: { node: ">=18" } + '@esbuild/linux-s390x@0.27.0': + resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - "@esbuild/linux-s390x@0.27.3": - resolution: - { - integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==, - } - engines: { node: ">=18" } + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - "@esbuild/linux-x64@0.25.12": - resolution: - { - integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==, - } - engines: { node: ">=18" } + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - "@esbuild/linux-x64@0.27.0": - resolution: - { - integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==, - } - engines: { node: ">=18" } + '@esbuild/linux-x64@0.27.0': + resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - "@esbuild/linux-x64@0.27.3": - resolution: - { - integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==, - } - engines: { node: ">=18" } + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - "@esbuild/netbsd-arm64@0.25.12": - resolution: - { - integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==, - } - engines: { node: ">=18" } + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - "@esbuild/netbsd-arm64@0.27.0": - resolution: - { - integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==, - } - engines: { node: ">=18" } + '@esbuild/netbsd-arm64@0.27.0': + resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==} + engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - "@esbuild/netbsd-arm64@0.27.3": - resolution: - { - integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==, - } - engines: { node: ">=18" } + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - "@esbuild/netbsd-x64@0.25.12": - resolution: - { - integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==, - } - engines: { node: ">=18" } + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - "@esbuild/netbsd-x64@0.27.0": - resolution: - { - integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==, - } - engines: { node: ">=18" } + '@esbuild/netbsd-x64@0.27.0': + resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - "@esbuild/netbsd-x64@0.27.3": - resolution: - { - integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==, - } - engines: { node: ">=18" } + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - "@esbuild/openbsd-arm64@0.25.12": - resolution: - { - integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==, - } - engines: { node: ">=18" } + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - "@esbuild/openbsd-arm64@0.27.0": - resolution: - { - integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==, - } - engines: { node: ">=18" } + '@esbuild/openbsd-arm64@0.27.0': + resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==} + engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - "@esbuild/openbsd-arm64@0.27.3": - resolution: - { - integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==, - } - engines: { node: ">=18" } + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - "@esbuild/openbsd-x64@0.25.12": - resolution: - { - integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==, - } - engines: { node: ">=18" } + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - "@esbuild/openbsd-x64@0.27.0": - resolution: - { - integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==, - } - engines: { node: ">=18" } + '@esbuild/openbsd-x64@0.27.0': + resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - "@esbuild/openbsd-x64@0.27.3": - resolution: - { - integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==, - } - engines: { node: ">=18" } + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - "@esbuild/openharmony-arm64@0.25.12": - resolution: - { - integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==, - } - engines: { node: ">=18" } + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - "@esbuild/openharmony-arm64@0.27.0": - resolution: - { - integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==, - } - engines: { node: ">=18" } + '@esbuild/openharmony-arm64@0.27.0': + resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==} + engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - "@esbuild/openharmony-arm64@0.27.3": - resolution: - { - integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==, - } - engines: { node: ">=18" } + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - "@esbuild/sunos-x64@0.25.12": - resolution: - { - integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==, - } - engines: { node: ">=18" } + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - "@esbuild/sunos-x64@0.27.0": - resolution: - { - integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==, - } - engines: { node: ">=18" } + '@esbuild/sunos-x64@0.27.0': + resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - "@esbuild/sunos-x64@0.27.3": - resolution: - { - integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==, - } - engines: { node: ">=18" } + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - "@esbuild/win32-arm64@0.25.12": - resolution: - { - integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==, - } - engines: { node: ">=18" } + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - "@esbuild/win32-arm64@0.27.0": - resolution: - { - integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==, - } - engines: { node: ">=18" } + '@esbuild/win32-arm64@0.27.0': + resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - "@esbuild/win32-arm64@0.27.3": - resolution: - { - integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==, - } - engines: { node: ">=18" } + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - "@esbuild/win32-ia32@0.25.12": - resolution: - { - integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==, - } - engines: { node: ">=18" } + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - "@esbuild/win32-ia32@0.27.0": - resolution: - { - integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==, - } - engines: { node: ">=18" } + '@esbuild/win32-ia32@0.27.0': + resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - "@esbuild/win32-ia32@0.27.3": - resolution: - { - integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==, - } - engines: { node: ">=18" } + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - "@esbuild/win32-x64@0.25.12": - resolution: - { - integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==, - } - engines: { node: ">=18" } + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} cpu: [x64] os: [win32] - "@esbuild/win32-x64@0.27.0": - resolution: - { - integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==, - } - engines: { node: ">=18" } + '@esbuild/win32-x64@0.27.0': + resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==} + engines: {node: '>=18'} cpu: [x64] os: [win32] - "@esbuild/win32-x64@0.27.3": - resolution: - { - integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==, - } - engines: { node: ">=18" } + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} cpu: [x64] os: [win32] - "@expressive-code/core@0.41.7": - resolution: - { - integrity: sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg==, - } - - "@expressive-code/plugin-frames@0.41.7": - resolution: - { - integrity: sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA==, - } - - "@expressive-code/plugin-shiki@0.41.7": - resolution: - { - integrity: sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ==, - } - - "@expressive-code/plugin-text-markers@0.41.7": - resolution: - { - integrity: sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==, - } - - "@fastify/busboy@2.1.1": - resolution: - { - integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==, - } - engines: { node: ">=14" } - - "@fastify/otel@0.16.0": - resolution: - { - integrity: sha512-2304BdM5Q/kUvQC9qJO1KZq3Zn1WWsw+WWkVmFEaj1UE2hEIiuFqrPeglQOwEtw/ftngisqfQ3v70TWMmwhhHA==, - } + '@expressive-code/core@0.41.7': + resolution: {integrity: sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg==} + + '@expressive-code/plugin-frames@0.41.7': + resolution: {integrity: sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA==} + + '@expressive-code/plugin-shiki@0.41.7': + resolution: {integrity: sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ==} + + '@expressive-code/plugin-text-markers@0.41.7': + resolution: {integrity: sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==} + + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + + '@fastify/otel@0.16.0': + resolution: {integrity: sha512-2304BdM5Q/kUvQC9qJO1KZq3Zn1WWsw+WWkVmFEaj1UE2hEIiuFqrPeglQOwEtw/ftngisqfQ3v70TWMmwhhHA==} peerDependencies: - "@opentelemetry/api": ^1.9.0 + '@opentelemetry/api': ^1.9.0 - "@fastify/otel@0.17.1": - resolution: - { - integrity: sha512-K4wyxfUZx2ux5o+b6BtTqouYFVILohLZmSbA2tKUueJstNcBnoGPVhllCaOvbQ3ZrXdUxUC/fyrSWSCqHhdOPg==, - } + '@fastify/otel@0.17.1': + resolution: {integrity: sha512-K4wyxfUZx2ux5o+b6BtTqouYFVILohLZmSbA2tKUueJstNcBnoGPVhllCaOvbQ3ZrXdUxUC/fyrSWSCqHhdOPg==} peerDependencies: - "@opentelemetry/api": ^1.9.0 - - "@fontsource-variable/space-grotesk@5.2.10": - resolution: - { - integrity: sha512-yJQO/o35/hAP3CFnpdFTwQku2yzJOae2HIpBmqkOVoxhhXJaQP3g+b6Jrz7u+eI7A5ZdCIf88uMWpBJdFiGr5w==, - } - - "@fontsource/ibm-plex-mono@5.2.7": - resolution: - { - integrity: sha512-MKAb8qV+CaiMQn2B0dIi1OV3565NYzp3WN5b4oT6LTkk+F0jR6j0ZN+5BKJiIhffDC3rtBULsYZE65+0018z9w==, - } - - "@gerrit0/mini-shiki@3.23.0": - resolution: - { - integrity: sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==, - } - - "@google/genai@1.44.0": - resolution: - { - integrity: sha512-kRt9ZtuXmz+tLlcNntN/VV4LRdpl6ZOu5B1KbfNgfR65db15O6sUQcwnwLka8sT/V6qysD93fWrgJHF2L7dA9A==, - } - engines: { node: ">=20.0.0" } + '@opentelemetry/api': ^1.9.0 + + '@fontsource-variable/space-grotesk@5.2.10': + resolution: {integrity: sha512-yJQO/o35/hAP3CFnpdFTwQku2yzJOae2HIpBmqkOVoxhhXJaQP3g+b6Jrz7u+eI7A5ZdCIf88uMWpBJdFiGr5w==} + + '@fontsource/ibm-plex-mono@5.2.7': + resolution: {integrity: sha512-MKAb8qV+CaiMQn2B0dIi1OV3565NYzp3WN5b4oT6LTkk+F0jR6j0ZN+5BKJiIhffDC3rtBULsYZE65+0018z9w==} + + '@gerrit0/mini-shiki@3.23.0': + resolution: {integrity: sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==} + + '@google/genai@1.44.0': + resolution: {integrity: sha512-kRt9ZtuXmz+tLlcNntN/VV4LRdpl6ZOu5B1KbfNgfR65db15O6sUQcwnwLka8sT/V6qysD93fWrgJHF2L7dA9A==} + engines: {node: '>=20.0.0'} peerDependencies: - "@modelcontextprotocol/sdk": ^1.25.2 + '@modelcontextprotocol/sdk': ^1.25.2 peerDependenciesMeta: - "@modelcontextprotocol/sdk": + '@modelcontextprotocol/sdk': optional: true - "@iarna/toml@2.2.5": - resolution: - { - integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==, - } - - "@img/colour@1.1.0": - resolution: - { - integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==, - } - engines: { node: ">=18" } - - "@img/sharp-darwin-arm64@0.34.5": - resolution: - { - integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@hono/node-server@1.19.11': + resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@iarna/toml@2.2.5': + resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - "@img/sharp-darwin-x64@0.34.5": - resolution: - { - integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - "@img/sharp-libvips-darwin-arm64@1.2.4": - resolution: - { - integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==, - } + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - "@img/sharp-libvips-darwin-x64@1.2.4": - resolution: - { - integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==, - } + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - "@img/sharp-libvips-linux-arm64@1.2.4": - resolution: - { - integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==, - } + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] libc: [glibc] - "@img/sharp-libvips-linux-arm@1.2.4": - resolution: - { - integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==, - } + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] libc: [glibc] - "@img/sharp-libvips-linux-ppc64@1.2.4": - resolution: - { - integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==, - } + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] libc: [glibc] - "@img/sharp-libvips-linux-riscv64@1.2.4": - resolution: - { - integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==, - } + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] libc: [glibc] - "@img/sharp-libvips-linux-s390x@1.2.4": - resolution: - { - integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==, - } + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] libc: [glibc] - "@img/sharp-libvips-linux-x64@1.2.4": - resolution: - { - integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==, - } + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] libc: [glibc] - "@img/sharp-libvips-linuxmusl-arm64@1.2.4": - resolution: - { - integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==, - } + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] libc: [musl] - "@img/sharp-libvips-linuxmusl-x64@1.2.4": - resolution: - { - integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==, - } + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] libc: [musl] - "@img/sharp-linux-arm64@0.34.5": - resolution: - { - integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] libc: [glibc] - "@img/sharp-linux-arm@0.34.5": - resolution: - { - integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] libc: [glibc] - "@img/sharp-linux-ppc64@0.34.5": - resolution: - { - integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] libc: [glibc] - "@img/sharp-linux-riscv64@0.34.5": - resolution: - { - integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] libc: [glibc] - "@img/sharp-linux-s390x@0.34.5": - resolution: - { - integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] libc: [glibc] - "@img/sharp-linux-x64@0.34.5": - resolution: - { - integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] libc: [glibc] - "@img/sharp-linuxmusl-arm64@0.34.5": - resolution: - { - integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] libc: [musl] - "@img/sharp-linuxmusl-x64@0.34.5": - resolution: - { - integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] libc: [musl] - "@img/sharp-wasm32@0.34.5": - resolution: - { - integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - "@img/sharp-win32-arm64@0.34.5": - resolution: - { - integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - "@img/sharp-win32-ia32@0.34.5": - resolution: - { - integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - "@img/sharp-win32-x64@0.34.5": - resolution: - { - integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] - "@inquirer/ansi@1.0.2": - resolution: - { - integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==, - } - engines: { node: ">=18" } - - "@inquirer/confirm@5.1.21": - resolution: - { - integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==, - } - engines: { node: ">=18" } + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} + engines: {node: '>=18'} peerDependencies: - "@types/node": ">=18" + '@types/node': '>=18' peerDependenciesMeta: - "@types/node": + '@types/node': optional: true - "@inquirer/core@10.3.2": - resolution: - { - integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==, - } - engines: { node: ">=18" } + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} peerDependencies: - "@types/node": ">=18" + '@types/node': '>=18' peerDependenciesMeta: - "@types/node": + '@types/node': optional: true - "@inquirer/figures@1.0.15": - resolution: - { - integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==, - } - engines: { node: ">=18" } - - "@inquirer/type@3.0.10": - resolution: - { - integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==, - } - engines: { node: ">=18" } + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} peerDependencies: - "@types/node": ">=18" + '@types/node': '>=18' peerDependenciesMeta: - "@types/node": + '@types/node': optional: true - "@isaacs/balanced-match@4.0.1": - resolution: - { - integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==, - } - engines: { node: 20 || >=22 } - - "@isaacs/brace-expansion@5.0.1": - resolution: - { - integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==, - } - engines: { node: 20 || >=22 } - - "@isaacs/cliui@8.0.2": - resolution: - { - integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, - } - engines: { node: ">=12" } - - "@isaacs/fs-minipass@4.0.1": - resolution: - { - integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==, - } - engines: { node: ">=18.0.0" } - - "@jitl/quickjs-ffi-types@0.32.0": - resolution: - { - integrity: sha512-v9T+GQpmk43VDJ7d72sf0Nexhk+ArvtUihW27dy7lqAl0zBObFKtSBBIm5RBjwIhE8VwsPPm9PNuvPvNqLWUEg==, - } - - "@jitl/quickjs-wasmfile-debug-asyncify@0.32.0": - resolution: - { - integrity: sha512-EX8zbXwGqCgAE764M+qvkHtyXDi/FUoMBea0JnES7vCM3P7a2+EOZOjGv85wtZ2sJhI1oJ+nekmqpOODFDY+hw==, - } - - "@jitl/quickjs-wasmfile-debug-sync@0.32.0": - resolution: - { - integrity: sha512-LeYWrPGC1uNCTBWvibo3ZLJj0CSVNYUXvJpXMCmuQ5Sap2cCACc3uvGvYV4homHHBAzfw5akoTqMMS4YFRtw+Q==, - } - - "@jitl/quickjs-wasmfile-release-asyncify@0.32.0": - resolution: - { - integrity: sha512-3oSwPfja12ICz4aIblB58cuY8JlEq5Txt8Cut4VLo+LH47QN+mzCnSgnbB03hWzg1LBcc+VyyI9UOag7a1NF+Q==, - } - - "@jitl/quickjs-wasmfile-release-sync@0.32.0": - resolution: - { - integrity: sha512-BKNDI/TPBfGlLNGYpLrhcDGXmIk4xHm4MRAisOBnOzpXVn9HZWsfmMAc9WMBrAHjvvds6HOikKeaOBKdPdpVrg==, - } - - "@jridgewell/gen-mapping@0.3.13": - resolution: - { - integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, - } - - "@jridgewell/remapping@2.3.5": - resolution: - { - integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==, - } - - "@jridgewell/resolve-uri@3.1.2": - resolution: - { - integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, - } - engines: { node: ">=6.0.0" } - - "@jridgewell/source-map@0.3.11": - resolution: - { - integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==, - } - - "@jridgewell/sourcemap-codec@1.5.5": - resolution: - { - integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==, - } - - "@jridgewell/trace-mapping@0.3.31": - resolution: - { - integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, - } - - "@mapbox/node-pre-gyp@2.0.3": - resolution: - { - integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==, - } - engines: { node: ">=18" } + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.1': + resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} + engines: {node: 20 || >=22} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jitl/quickjs-ffi-types@0.32.0': + resolution: {integrity: sha512-v9T+GQpmk43VDJ7d72sf0Nexhk+ArvtUihW27dy7lqAl0zBObFKtSBBIm5RBjwIhE8VwsPPm9PNuvPvNqLWUEg==} + + '@jitl/quickjs-wasmfile-debug-asyncify@0.32.0': + resolution: {integrity: sha512-EX8zbXwGqCgAE764M+qvkHtyXDi/FUoMBea0JnES7vCM3P7a2+EOZOjGv85wtZ2sJhI1oJ+nekmqpOODFDY+hw==} + + '@jitl/quickjs-wasmfile-debug-sync@0.32.0': + resolution: {integrity: sha512-LeYWrPGC1uNCTBWvibo3ZLJj0CSVNYUXvJpXMCmuQ5Sap2cCACc3uvGvYV4homHHBAzfw5akoTqMMS4YFRtw+Q==} + + '@jitl/quickjs-wasmfile-release-asyncify@0.32.0': + resolution: {integrity: sha512-3oSwPfja12ICz4aIblB58cuY8JlEq5Txt8Cut4VLo+LH47QN+mzCnSgnbB03hWzg1LBcc+VyyI9UOag7a1NF+Q==} + + '@jitl/quickjs-wasmfile-release-sync@0.32.0': + resolution: {integrity: sha512-BKNDI/TPBfGlLNGYpLrhcDGXmIk4xHm4MRAisOBnOzpXVn9HZWsfmMAc9WMBrAHjvvds6HOikKeaOBKdPdpVrg==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@mapbox/node-pre-gyp@2.0.3': + resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} + engines: {node: '>=18'} hasBin: true - "@mariozechner/pi-agent-core@0.59.0": - resolution: - { - integrity: sha512-dTYJuesfvPOyEKQ5TFxsF98EcI43oh8X8hMH3iU1egMZohDqjIYWLWyVJqV68501cgkvxqzf7li6IFTjzUsP9A==, - } - engines: { node: ">=20.0.0" } - - "@mariozechner/pi-ai@0.59.0": - resolution: - { - integrity: sha512-jlRyCYnYI2tJiFR/z2I1umf0jXmx9F9W0vyjnEICabifg/yZ00h2dvrW5SHj3T8Om9HwC9kpWfh3iEA6o9N1Cw==, - } - engines: { node: ">=20.0.0" } + '@mariozechner/pi-agent-core@0.59.0': + resolution: {integrity: sha512-dTYJuesfvPOyEKQ5TFxsF98EcI43oh8X8hMH3iU1egMZohDqjIYWLWyVJqV68501cgkvxqzf7li6IFTjzUsP9A==} + engines: {node: '>=20.0.0'} + + '@mariozechner/pi-ai@0.59.0': + resolution: {integrity: sha512-jlRyCYnYI2tJiFR/z2I1umf0jXmx9F9W0vyjnEICabifg/yZ00h2dvrW5SHj3T8Om9HwC9kpWfh3iEA6o9N1Cw==} + engines: {node: '>=20.0.0'} hasBin: true - "@mdx-js/mdx@3.1.1": - resolution: - { - integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==, - } - - "@mistralai/mistralai@1.14.1": - resolution: - { - integrity: sha512-IiLmmZFCCTReQgPAT33r7KQ1nYo5JPdvGkrkZqA8qQ2qB1GHgs5LoP5K2ICyrjnpw2n8oSxMM/VP+liiKcGNlQ==, - } - - "@mixmark-io/domino@2.2.0": - resolution: - { - integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==, - } - - "@mongodb-js/zstd@7.0.0": - resolution: - { - integrity: sha512-mQ2s0pYYiav+tzCDR05Zptem8Ey2v8s11lri5RKGhTtL4COVCvVCk5vtyRYNT+9L8qSfyOqqefF9UtnW8mC5jA==, - } - engines: { node: ">= 20.19.0" } - - "@mswjs/interceptors@0.41.3": - resolution: - { - integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==, - } - engines: { node: ">=18" } - - "@napi-rs/wasm-runtime@1.1.1": - resolution: - { - integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==, - } - - "@next/env@16.1.7": - resolution: - { - integrity: sha512-rJJbIdJB/RQr2F1nylZr/PJzamvNNhfr3brdKP6s/GW850jbtR70QlSfFselvIBbcPUOlQwBakexjFzqLzF6pg==, - } - - "@next/swc-darwin-arm64@16.1.7": - resolution: - { - integrity: sha512-b2wWIE8sABdyafc4IM8r5Y/dS6kD80JRtOGrUiKTsACFQfWWgUQ2NwoUX1yjFMXVsAwcQeNpnucF2ZrujsBBPg==, - } - engines: { node: ">= 10" } + '@mdx-js/mdx@3.1.1': + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + + '@mistralai/mistralai@1.14.1': + resolution: {integrity: sha512-IiLmmZFCCTReQgPAT33r7KQ1nYo5JPdvGkrkZqA8qQ2qB1GHgs5LoP5K2ICyrjnpw2n8oSxMM/VP+liiKcGNlQ==} + + '@mixmark-io/domino@2.2.0': + resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} + + '@modelcontextprotocol/sdk@1.27.1': + resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@mongodb-js/zstd@7.0.0': + resolution: {integrity: sha512-mQ2s0pYYiav+tzCDR05Zptem8Ey2v8s11lri5RKGhTtL4COVCvVCk5vtyRYNT+9L8qSfyOqqefF9UtnW8mC5jA==} + engines: {node: '>= 20.19.0'} + + '@mswjs/interceptors@0.41.3': + resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} + engines: {node: '>=18'} + + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + + '@next/env@16.1.7': + resolution: {integrity: sha512-rJJbIdJB/RQr2F1nylZr/PJzamvNNhfr3brdKP6s/GW850jbtR70QlSfFselvIBbcPUOlQwBakexjFzqLzF6pg==} + + '@next/swc-darwin-arm64@16.1.7': + resolution: {integrity: sha512-b2wWIE8sABdyafc4IM8r5Y/dS6kD80JRtOGrUiKTsACFQfWWgUQ2NwoUX1yjFMXVsAwcQeNpnucF2ZrujsBBPg==} + engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - "@next/swc-darwin-x64@16.1.7": - resolution: - { - integrity: sha512-zcnVaaZulS1WL0Ss38R5Q6D2gz7MtBu8GZLPfK+73D/hp4GFMrC2sudLky1QibfV7h6RJBJs/gOFvYP0X7UVlQ==, - } - engines: { node: ">= 10" } + '@next/swc-darwin-x64@16.1.7': + resolution: {integrity: sha512-zcnVaaZulS1WL0Ss38R5Q6D2gz7MtBu8GZLPfK+73D/hp4GFMrC2sudLky1QibfV7h6RJBJs/gOFvYP0X7UVlQ==} + engines: {node: '>= 10'} cpu: [x64] os: [darwin] - "@next/swc-linux-arm64-gnu@16.1.7": - resolution: - { - integrity: sha512-2ant89Lux/Q3VyC8vNVg7uBaFVP9SwoK2jJOOR0L8TQnX8CAYnh4uctAScy2Hwj2dgjVHqHLORQZJ2wH6VxhSQ==, - } - engines: { node: ">= 10" } + '@next/swc-linux-arm64-gnu@16.1.7': + resolution: {integrity: sha512-2ant89Lux/Q3VyC8vNVg7uBaFVP9SwoK2jJOOR0L8TQnX8CAYnh4uctAScy2Hwj2dgjVHqHLORQZJ2wH6VxhSQ==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - "@next/swc-linux-arm64-musl@16.1.7": - resolution: - { - integrity: sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==, - } - engines: { node: ">= 10" } + '@next/swc-linux-arm64-musl@16.1.7': + resolution: {integrity: sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - "@next/swc-linux-x64-gnu@16.1.7": - resolution: - { - integrity: sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==, - } - engines: { node: ">= 10" } + '@next/swc-linux-x64-gnu@16.1.7': + resolution: {integrity: sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - "@next/swc-linux-x64-musl@16.1.7": - resolution: - { - integrity: sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==, - } - engines: { node: ">= 10" } + '@next/swc-linux-x64-musl@16.1.7': + resolution: {integrity: sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - "@next/swc-win32-arm64-msvc@16.1.7": - resolution: - { - integrity: sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==, - } - engines: { node: ">= 10" } + '@next/swc-win32-arm64-msvc@16.1.7': + resolution: {integrity: sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==} + engines: {node: '>= 10'} cpu: [arm64] os: [win32] - "@next/swc-win32-x64-msvc@16.1.7": - resolution: - { - integrity: sha512-mwgtg8CNZGYm06LeEd+bNnOUfwOyNem/rOiP14Lsz+AnUY92Zq/LXwtebtUiaeVkhbroRCQ0c8GlR4UT1U+0yg==, - } - engines: { node: ">= 10" } + '@next/swc-win32-x64-msvc@16.1.7': + resolution: {integrity: sha512-mwgtg8CNZGYm06LeEd+bNnOUfwOyNem/rOiP14Lsz+AnUY92Zq/LXwtebtUiaeVkhbroRCQ0c8GlR4UT1U+0yg==} + engines: {node: '>= 10'} cpu: [x64] os: [win32] - "@nodelib/fs.scandir@2.1.5": - resolution: - { - integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, - } - engines: { node: ">= 8" } - - "@nodelib/fs.stat@2.0.5": - resolution: - { - integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, - } - engines: { node: ">= 8" } - - "@nodelib/fs.walk@1.2.8": - resolution: - { - integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, - } - engines: { node: ">= 8" } - - "@open-draft/deferred-promise@2.2.0": - resolution: - { - integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==, - } - - "@open-draft/logger@0.3.0": - resolution: - { - integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==, - } - - "@open-draft/until@2.1.0": - resolution: - { - integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==, - } - - "@opentelemetry/api-logs@0.207.0": - resolution: - { - integrity: sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==, - } - engines: { node: ">=8.0.0" } - - "@opentelemetry/api-logs@0.208.0": - resolution: - { - integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==, - } - engines: { node: ">=8.0.0" } - - "@opentelemetry/api-logs@0.211.0": - resolution: - { - integrity: sha512-swFdZq8MCdmdR22jTVGQDhwqDzcI4M10nhjXkLr1EsIzXgZBqm4ZlmmcWsg3TSNf+3mzgOiqveXmBLZuDi2Lgg==, - } - engines: { node: ">=8.0.0" } - - "@opentelemetry/api-logs@0.212.0": - resolution: - { - integrity: sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg==, - } - engines: { node: ">=8.0.0" } - - "@opentelemetry/api-logs@0.213.0": - resolution: - { - integrity: sha512-zRM5/Qj6G84Ej3F1yt33xBVY/3tnMxtL1fiDIxYbDWYaZ/eudVw3/PBiZ8G7JwUxXxjW8gU4g6LnOyfGKYHYgw==, - } - engines: { node: ">=8.0.0" } - - "@opentelemetry/api@1.9.0": - resolution: - { - integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==, - } - engines: { node: ">=8.0.0" } - - "@opentelemetry/context-async-hooks@2.6.0": - resolution: - { - integrity: sha512-L8UyDwqpTcbkIK5cgwDRDYDoEhQoj8wp8BwsO19w3LB1Z41yEQm2VJyNfAi9DrLP/YTqXqWpKHyZfR9/tFYo1Q==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + + '@opentelemetry/api-logs@0.207.0': + resolution: {integrity: sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api-logs@0.208.0': + resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api-logs@0.211.0': + resolution: {integrity: sha512-swFdZq8MCdmdR22jTVGQDhwqDzcI4M10nhjXkLr1EsIzXgZBqm4ZlmmcWsg3TSNf+3mzgOiqveXmBLZuDi2Lgg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api-logs@0.212.0': + resolution: {integrity: sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api-logs@0.213.0': + resolution: {integrity: sha512-zRM5/Qj6G84Ej3F1yt33xBVY/3tnMxtL1fiDIxYbDWYaZ/eudVw3/PBiZ8G7JwUxXxjW8gU4g6LnOyfGKYHYgw==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/context-async-hooks@2.6.0': + resolution: {integrity: sha512-L8UyDwqpTcbkIK5cgwDRDYDoEhQoj8wp8BwsO19w3LB1Z41yEQm2VJyNfAi9DrLP/YTqXqWpKHyZfR9/tFYo1Q==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - - "@opentelemetry/core@2.5.0": - resolution: - { - integrity: sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.5.0': + resolution: {integrity: sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - - "@opentelemetry/core@2.6.0": - resolution: - { - integrity: sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.6.0': + resolution: {integrity: sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - - "@opentelemetry/instrumentation-amqplib@0.58.0": - resolution: - { - integrity: sha512-fjpQtH18J6GxzUZ+cwNhWUpb71u+DzT7rFkg5pLssDGaEber91Y2WNGdpVpwGivfEluMlNMZumzjEqfg8DeKXQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/instrumentation-amqplib@0.58.0': + resolution: {integrity: sha512-fjpQtH18J6GxzUZ+cwNhWUpb71u+DzT7rFkg5pLssDGaEber91Y2WNGdpVpwGivfEluMlNMZumzjEqfg8DeKXQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-amqplib@0.60.0": - resolution: - { - integrity: sha512-q/B2IvoVXRm1M00MvhnzpMN6rKYOszPXVsALi6u0ss4AYHe+TidZEtLW9N1ZhrobI1dSriHnBqqtAOZVAv07sg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-amqplib@0.60.0': + resolution: {integrity: sha512-q/B2IvoVXRm1M00MvhnzpMN6rKYOszPXVsALi6u0ss4AYHe+TidZEtLW9N1ZhrobI1dSriHnBqqtAOZVAv07sg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-connect@0.54.0": - resolution: - { - integrity: sha512-43RmbhUhqt3uuPnc16cX6NsxEASEtn8z/cYV8Zpt6EP4p2h9s4FNuJ4Q9BbEQ2C0YlCCB/2crO1ruVz/hWt8fA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-connect@0.54.0': + resolution: {integrity: sha512-43RmbhUhqt3uuPnc16cX6NsxEASEtn8z/cYV8Zpt6EP4p2h9s4FNuJ4Q9BbEQ2C0YlCCB/2crO1ruVz/hWt8fA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-connect@0.56.0": - resolution: - { - integrity: sha512-PKp+sSZ7AfzMvGgO3VCyo1inwNu+q7A1k9X88WK4PQ+S6Hp7eFk8pie+sWHDTaARovmqq5V2osav3lQej2B0nw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-connect@0.56.0': + resolution: {integrity: sha512-PKp+sSZ7AfzMvGgO3VCyo1inwNu+q7A1k9X88WK4PQ+S6Hp7eFk8pie+sWHDTaARovmqq5V2osav3lQej2B0nw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-dataloader@0.28.0": - resolution: - { - integrity: sha512-ExXGBp0sUj8yhm6Znhf9jmuOaGDsYfDES3gswZnKr4MCqoBWQdEFn6EoDdt5u+RdbxQER+t43FoUihEfTSqsjA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-dataloader@0.28.0': + resolution: {integrity: sha512-ExXGBp0sUj8yhm6Znhf9jmuOaGDsYfDES3gswZnKr4MCqoBWQdEFn6EoDdt5u+RdbxQER+t43FoUihEfTSqsjA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-dataloader@0.30.0": - resolution: - { - integrity: sha512-MXHP2Q38cd2OhzEBKAIXUi9uBlPEYzF6BNJbyjUXBQ6kLaf93kRC41vNMIz0Nl5mnuwK7fDvKT+/lpx7BXRwdg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-dataloader@0.30.0': + resolution: {integrity: sha512-MXHP2Q38cd2OhzEBKAIXUi9uBlPEYzF6BNJbyjUXBQ6kLaf93kRC41vNMIz0Nl5mnuwK7fDvKT+/lpx7BXRwdg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-express@0.59.0": - resolution: - { - integrity: sha512-pMKV/qnHiW/Q6pmbKkxt0eIhuNEtvJ7sUAyee192HErlr+a1Jx+FZ3WjfmzhQL1geewyGEiPGkmjjAgNY8TgDA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-express@0.59.0': + resolution: {integrity: sha512-pMKV/qnHiW/Q6pmbKkxt0eIhuNEtvJ7sUAyee192HErlr+a1Jx+FZ3WjfmzhQL1geewyGEiPGkmjjAgNY8TgDA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-express@0.61.0": - resolution: - { - integrity: sha512-Xdmqo9RZuZlL29Flg8QdwrrX7eW1CZ7wFQPKHyXljNymgKhN1MCsYuqQ/7uxavhSKwAl7WxkTzKhnqpUApLMvQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-express@0.61.0': + resolution: {integrity: sha512-Xdmqo9RZuZlL29Flg8QdwrrX7eW1CZ7wFQPKHyXljNymgKhN1MCsYuqQ/7uxavhSKwAl7WxkTzKhnqpUApLMvQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-fs@0.30.0": - resolution: - { - integrity: sha512-n3Cf8YhG7reaj5dncGlRIU7iT40bxPOjsBEA5Bc1a1g6e9Qvb+JFJ7SEiMlPbUw4PBmxE3h40ltE8LZ3zVt6OA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-fs@0.30.0': + resolution: {integrity: sha512-n3Cf8YhG7reaj5dncGlRIU7iT40bxPOjsBEA5Bc1a1g6e9Qvb+JFJ7SEiMlPbUw4PBmxE3h40ltE8LZ3zVt6OA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-fs@0.32.0": - resolution: - { - integrity: sha512-koR6apx0g0wX6RRiPpjA4AFQUQUbXrK16kq4/SZjVp7u5cffJhNkY4TnITxcGA4acGSPYAfx3NHRIv4Khn1axQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-fs@0.32.0': + resolution: {integrity: sha512-koR6apx0g0wX6RRiPpjA4AFQUQUbXrK16kq4/SZjVp7u5cffJhNkY4TnITxcGA4acGSPYAfx3NHRIv4Khn1axQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-generic-pool@0.54.0": - resolution: - { - integrity: sha512-8dXMBzzmEdXfH/wjuRvcJnUFeWzZHUnExkmFJ2uPfa31wmpyBCMxO59yr8f/OXXgSogNgi/uPo9KW9H7LMIZ+g==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-generic-pool@0.54.0': + resolution: {integrity: sha512-8dXMBzzmEdXfH/wjuRvcJnUFeWzZHUnExkmFJ2uPfa31wmpyBCMxO59yr8f/OXXgSogNgi/uPo9KW9H7LMIZ+g==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-generic-pool@0.56.0": - resolution: - { - integrity: sha512-fg+Jffs6fqrf0uQS0hom7qBFKsbtpBiBl8+Vkc63Gx8xh6pVh+FhagmiO6oM0m3vyb683t1lP7yGYq22SiDnqg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-generic-pool@0.56.0': + resolution: {integrity: sha512-fg+Jffs6fqrf0uQS0hom7qBFKsbtpBiBl8+Vkc63Gx8xh6pVh+FhagmiO6oM0m3vyb683t1lP7yGYq22SiDnqg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-graphql@0.58.0": - resolution: - { - integrity: sha512-+yWVVY7fxOs3j2RixCbvue8vUuJ1inHxN2q1sduqDB0Wnkr4vOzVKRYl/Zy7B31/dcPS72D9lo/kltdOTBM3bQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-graphql@0.58.0': + resolution: {integrity: sha512-+yWVVY7fxOs3j2RixCbvue8vUuJ1inHxN2q1sduqDB0Wnkr4vOzVKRYl/Zy7B31/dcPS72D9lo/kltdOTBM3bQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-graphql@0.61.0": - resolution: - { - integrity: sha512-pUiVASv6nh2XrerTvlbVHh7vKFzscpgwiQ/xvnZuAIzQ5lRjWVdRPUuXbvZJ/Yq79QsE81TZdJ7z9YsXiss1ew==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-graphql@0.61.0': + resolution: {integrity: sha512-pUiVASv6nh2XrerTvlbVHh7vKFzscpgwiQ/xvnZuAIzQ5lRjWVdRPUuXbvZJ/Yq79QsE81TZdJ7z9YsXiss1ew==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-hapi@0.57.0": - resolution: - { - integrity: sha512-Os4THbvls8cTQTVA8ApLfZZztuuqGEeqog0XUnyRW7QVF0d/vOVBEcBCk1pazPFmllXGEdNbbat8e2fYIWdFbw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-hapi@0.57.0': + resolution: {integrity: sha512-Os4THbvls8cTQTVA8ApLfZZztuuqGEeqog0XUnyRW7QVF0d/vOVBEcBCk1pazPFmllXGEdNbbat8e2fYIWdFbw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-hapi@0.59.0": - resolution: - { - integrity: sha512-33wa4mEr+9+ztwdgLor1SeBu4Opz4IsmpcLETXAd3VmBrOjez8uQtrsOhPCa5Vhbm5gzDlMYTgFRLQzf8/YHFA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-hapi@0.59.0': + resolution: {integrity: sha512-33wa4mEr+9+ztwdgLor1SeBu4Opz4IsmpcLETXAd3VmBrOjez8uQtrsOhPCa5Vhbm5gzDlMYTgFRLQzf8/YHFA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-http@0.211.0": - resolution: - { - integrity: sha512-n0IaQ6oVll9PP84SjbOCwDjaJasWRHi6BLsbMLiT6tNj7QbVOkuA5sk/EfZczwI0j5uTKl1awQPivO/ldVtsqA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-http@0.211.0': + resolution: {integrity: sha512-n0IaQ6oVll9PP84SjbOCwDjaJasWRHi6BLsbMLiT6tNj7QbVOkuA5sk/EfZczwI0j5uTKl1awQPivO/ldVtsqA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-http@0.213.0": - resolution: - { - integrity: sha512-B978Xsm5XEPGhm1P07grDoaOFLHapJPkOG9h016cJsyWWxmiLnPu2M/4Nrm7UCkHSiLnkXgC+zVGUAIahy8EEA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-http@0.213.0': + resolution: {integrity: sha512-B978Xsm5XEPGhm1P07grDoaOFLHapJPkOG9h016cJsyWWxmiLnPu2M/4Nrm7UCkHSiLnkXgC+zVGUAIahy8EEA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-ioredis@0.59.0": - resolution: - { - integrity: sha512-875UxzBHWkW+P4Y45SoFM2AR8f8TzBMD8eO7QXGCyFSCUMP5s9vtt/BS8b/r2kqLyaRPK6mLbdnZznK3XzQWvw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-ioredis@0.59.0': + resolution: {integrity: sha512-875UxzBHWkW+P4Y45SoFM2AR8f8TzBMD8eO7QXGCyFSCUMP5s9vtt/BS8b/r2kqLyaRPK6mLbdnZznK3XzQWvw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-ioredis@0.61.0": - resolution: - { - integrity: sha512-hsHDadUtAFbws1YSDc1XW0svGFKiUbqv2td1Cby+UAiwvojm1NyBo/taifH0t8CuFZ0x/2SDm0iuTwrM5pnVOg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-ioredis@0.61.0': + resolution: {integrity: sha512-hsHDadUtAFbws1YSDc1XW0svGFKiUbqv2td1Cby+UAiwvojm1NyBo/taifH0t8CuFZ0x/2SDm0iuTwrM5pnVOg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-kafkajs@0.20.0": - resolution: - { - integrity: sha512-yJXOuWZROzj7WmYCUiyT27tIfqBrVtl1/TwVbQyWPz7rL0r1Lu7kWjD0PiVeTCIL6CrIZ7M2s8eBxsTAOxbNvw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-kafkajs@0.20.0': + resolution: {integrity: sha512-yJXOuWZROzj7WmYCUiyT27tIfqBrVtl1/TwVbQyWPz7rL0r1Lu7kWjD0PiVeTCIL6CrIZ7M2s8eBxsTAOxbNvw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-kafkajs@0.22.0": - resolution: - { - integrity: sha512-wJU4IBQMUikdJAcTChLFqK5lo+flo7pahqd8DSLv7uMxsdOdAHj6RzKYAm8pPfUS6ItKYutYyuicwKaFwQKsoA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-kafkajs@0.22.0': + resolution: {integrity: sha512-wJU4IBQMUikdJAcTChLFqK5lo+flo7pahqd8DSLv7uMxsdOdAHj6RzKYAm8pPfUS6ItKYutYyuicwKaFwQKsoA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-knex@0.55.0": - resolution: - { - integrity: sha512-FtTL5DUx5Ka/8VK6P1VwnlUXPa3nrb7REvm5ddLUIeXXq4tb9pKd+/ThB1xM/IjefkRSN3z8a5t7epYw1JLBJQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-knex@0.55.0': + resolution: {integrity: sha512-FtTL5DUx5Ka/8VK6P1VwnlUXPa3nrb7REvm5ddLUIeXXq4tb9pKd+/ThB1xM/IjefkRSN3z8a5t7epYw1JLBJQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-knex@0.57.0": - resolution: - { - integrity: sha512-vMCSh8kolEm5rRsc+FZeTZymWmIJwc40hjIKnXH4O0Dv/gAkJJIRXCsPX5cPbe0c0j/34+PsENd0HqKruwhVYw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-knex@0.57.0': + resolution: {integrity: sha512-vMCSh8kolEm5rRsc+FZeTZymWmIJwc40hjIKnXH4O0Dv/gAkJJIRXCsPX5cPbe0c0j/34+PsENd0HqKruwhVYw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-koa@0.59.0": - resolution: - { - integrity: sha512-K9o2skADV20Skdu5tG2bogPKiSpXh4KxfLjz6FuqIVvDJNibwSdu5UvyyBzRVp1rQMV6UmoIk6d3PyPtJbaGSg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-koa@0.59.0': + resolution: {integrity: sha512-K9o2skADV20Skdu5tG2bogPKiSpXh4KxfLjz6FuqIVvDJNibwSdu5UvyyBzRVp1rQMV6UmoIk6d3PyPtJbaGSg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.9.0 - - "@opentelemetry/instrumentation-koa@0.61.0": - resolution: - { - integrity: sha512-lvrfWe9ShK/D2X4brmx8ZqqeWPfRl8xekU0FCn7C1dHm5k6+rTOOi36+4fnaHAP8lig9Ux6XQ1D4RNIpPCt1WQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.9.0 + + '@opentelemetry/instrumentation-koa@0.61.0': + resolution: {integrity: sha512-lvrfWe9ShK/D2X4brmx8ZqqeWPfRl8xekU0FCn7C1dHm5k6+rTOOi36+4fnaHAP8lig9Ux6XQ1D4RNIpPCt1WQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.9.0 - - "@opentelemetry/instrumentation-lru-memoizer@0.55.0": - resolution: - { - integrity: sha512-FDBfT7yDGcspN0Cxbu/k8A0Pp1Jhv/m7BMTzXGpcb8ENl3tDj/51U65R5lWzUH15GaZA15HQ5A5wtafklxYj7g==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.9.0 + + '@opentelemetry/instrumentation-lru-memoizer@0.55.0': + resolution: {integrity: sha512-FDBfT7yDGcspN0Cxbu/k8A0Pp1Jhv/m7BMTzXGpcb8ENl3tDj/51U65R5lWzUH15GaZA15HQ5A5wtafklxYj7g==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-lru-memoizer@0.57.0": - resolution: - { - integrity: sha512-cEqpUocSKJfwDtLYTTJehRLWzkZ2eoePCxfVIgGkGkb83fMB71O+y4MvRHJPbeV2bdoWdOVrl8uO0+EynWhTEA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-lru-memoizer@0.57.0': + resolution: {integrity: sha512-cEqpUocSKJfwDtLYTTJehRLWzkZ2eoePCxfVIgGkGkb83fMB71O+y4MvRHJPbeV2bdoWdOVrl8uO0+EynWhTEA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-mongodb@0.64.0": - resolution: - { - integrity: sha512-pFlCJjweTqVp7B220mCvCld1c1eYKZfQt1p3bxSbcReypKLJTwat+wbL2YZoX9jPi5X2O8tTKFEOahO5ehQGsA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mongodb@0.64.0': + resolution: {integrity: sha512-pFlCJjweTqVp7B220mCvCld1c1eYKZfQt1p3bxSbcReypKLJTwat+wbL2YZoX9jPi5X2O8tTKFEOahO5ehQGsA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-mongodb@0.66.0": - resolution: - { - integrity: sha512-d7m9QnAY+4TCWI4q1QRkfrc6fo/92VwssaB1DzQfXNRvu51b78P+HJlWP7Qg6N6nkwdb9faMZNBCZJfftmszkw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mongodb@0.66.0': + resolution: {integrity: sha512-d7m9QnAY+4TCWI4q1QRkfrc6fo/92VwssaB1DzQfXNRvu51b78P+HJlWP7Qg6N6nkwdb9faMZNBCZJfftmszkw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-mongoose@0.57.0": - resolution: - { - integrity: sha512-MthiekrU/BAJc5JZoZeJmo0OTX6ycJMiP6sMOSRTkvz5BrPMYDqaJos0OgsLPL/HpcgHP7eo5pduETuLguOqcg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mongoose@0.57.0': + resolution: {integrity: sha512-MthiekrU/BAJc5JZoZeJmo0OTX6ycJMiP6sMOSRTkvz5BrPMYDqaJos0OgsLPL/HpcgHP7eo5pduETuLguOqcg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-mongoose@0.59.0": - resolution: - { - integrity: sha512-6/jWU+c1NgznkVLDU/2y0bXV2nJo3o9FWZ9mZ9nN6T/JBNRoMnVXZl2FdBmgH+a5MwaWLs5kmRJTP5oUVGIkPw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mongoose@0.59.0': + resolution: {integrity: sha512-6/jWU+c1NgznkVLDU/2y0bXV2nJo3o9FWZ9mZ9nN6T/JBNRoMnVXZl2FdBmgH+a5MwaWLs5kmRJTP5oUVGIkPw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-mysql2@0.57.0": - resolution: - { - integrity: sha512-nHSrYAwF7+aV1E1V9yOOP9TchOodb6fjn4gFvdrdQXiRE7cMuffyLLbCZlZd4wsspBzVwOXX8mpURdRserAhNA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mysql2@0.57.0': + resolution: {integrity: sha512-nHSrYAwF7+aV1E1V9yOOP9TchOodb6fjn4gFvdrdQXiRE7cMuffyLLbCZlZd4wsspBzVwOXX8mpURdRserAhNA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-mysql2@0.59.0": - resolution: - { - integrity: sha512-n9/xrVCRBfG9egVbffnlU1uhr+HX0vF4GgtAB/Bvm48wpFgRidqD8msBMiym1kRYzmpWvJqTxNT47u1MkgBEdw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mysql2@0.59.0': + resolution: {integrity: sha512-n9/xrVCRBfG9egVbffnlU1uhr+HX0vF4GgtAB/Bvm48wpFgRidqD8msBMiym1kRYzmpWvJqTxNT47u1MkgBEdw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-mysql@0.57.0": - resolution: - { - integrity: sha512-HFS/+FcZ6Q7piM7Il7CzQ4VHhJvGMJWjx7EgCkP5AnTntSN5rb5Xi3TkYJHBKeR27A0QqPlGaCITi93fUDs++Q==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mysql@0.57.0': + resolution: {integrity: sha512-HFS/+FcZ6Q7piM7Il7CzQ4VHhJvGMJWjx7EgCkP5AnTntSN5rb5Xi3TkYJHBKeR27A0QqPlGaCITi93fUDs++Q==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-mysql@0.59.0": - resolution: - { - integrity: sha512-r+V/Fh0sm7Ga8/zk/TI5H5FQRAjwr0RrpfPf8kNIehlsKf12XnvIaZi8ViZkpX0gyPEpLXqzqWD6QHlgObgzZw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mysql@0.59.0': + resolution: {integrity: sha512-r+V/Fh0sm7Ga8/zk/TI5H5FQRAjwr0RrpfPf8kNIehlsKf12XnvIaZi8ViZkpX0gyPEpLXqzqWD6QHlgObgzZw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-pg@0.63.0": - resolution: - { - integrity: sha512-dKm/ODNN3GgIQVlbD6ZPxwRc3kleLf95hrRWXM+l8wYo+vSeXtEpQPT53afEf6VFWDVzJK55VGn8KMLtSve/cg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-pg@0.63.0': + resolution: {integrity: sha512-dKm/ODNN3GgIQVlbD6ZPxwRc3kleLf95hrRWXM+l8wYo+vSeXtEpQPT53afEf6VFWDVzJK55VGn8KMLtSve/cg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-pg@0.65.0": - resolution: - { - integrity: sha512-W0zpHEIEuyZ8zvb3njaX9AAbHgPYOsSWVOoWmv1sjVRSF6ZpBqtlxBWbU+6hhq1TFWBeWJOXZ8nZS/PUFpLJYQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-pg@0.65.0': + resolution: {integrity: sha512-W0zpHEIEuyZ8zvb3njaX9AAbHgPYOsSWVOoWmv1sjVRSF6ZpBqtlxBWbU+6hhq1TFWBeWJOXZ8nZS/PUFpLJYQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-redis@0.59.0": - resolution: - { - integrity: sha512-JKv1KDDYA2chJ1PC3pLP+Q9ISMQk6h5ey+99mB57/ARk0vQPGZTTEb4h4/JlcEpy7AYT8HIGv7X6l+br03Neeg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-redis@0.59.0': + resolution: {integrity: sha512-JKv1KDDYA2chJ1PC3pLP+Q9ISMQk6h5ey+99mB57/ARk0vQPGZTTEb4h4/JlcEpy7AYT8HIGv7X6l+br03Neeg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-redis@0.61.0": - resolution: - { - integrity: sha512-JnPexA034/0UJRsvH96B0erQoNOqKJZjE2ZRSw9hiTSC23LzE0nJE/u6D+xqOhgUhRnhhcPHq4MdYtmUdYTF+Q==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-redis@0.61.0': + resolution: {integrity: sha512-JnPexA034/0UJRsvH96B0erQoNOqKJZjE2ZRSw9hiTSC23LzE0nJE/u6D+xqOhgUhRnhhcPHq4MdYtmUdYTF+Q==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-tedious@0.30.0": - resolution: - { - integrity: sha512-bZy9Q8jFdycKQ2pAsyuHYUHNmCxCOGdG6eg1Mn75RvQDccq832sU5OWOBnc12EFUELI6icJkhR7+EQKMBam2GA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-tedious@0.30.0': + resolution: {integrity: sha512-bZy9Q8jFdycKQ2pAsyuHYUHNmCxCOGdG6eg1Mn75RvQDccq832sU5OWOBnc12EFUELI6icJkhR7+EQKMBam2GA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-tedious@0.32.0": - resolution: - { - integrity: sha512-BQS6gG8RJ1foEqfEZ+wxoqlwfCAzb1ZVG0ad8Gfe4x8T658HJCLGLd4E4NaoQd8EvPfLqOXgzGaE/2U4ytDSWA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-tedious@0.32.0': + resolution: {integrity: sha512-BQS6gG8RJ1foEqfEZ+wxoqlwfCAzb1ZVG0ad8Gfe4x8T658HJCLGLd4E4NaoQd8EvPfLqOXgzGaE/2U4ytDSWA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation-undici@0.21.0": - resolution: - { - integrity: sha512-gok0LPUOTz2FQ1YJMZzaHcOzDFyT64XJ8M9rNkugk923/p6lDGms/cRW1cqgqp6N6qcd6K6YdVHwPEhnx9BWbw==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-undici@0.21.0': + resolution: {integrity: sha512-gok0LPUOTz2FQ1YJMZzaHcOzDFyT64XJ8M9rNkugk923/p6lDGms/cRW1cqgqp6N6qcd6K6YdVHwPEhnx9BWbw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.7.0 - - "@opentelemetry/instrumentation-undici@0.23.0": - resolution: - { - integrity: sha512-LL0VySzKVR2cJSFVZaTYpZl1XTpBGnfzoQPe2W7McS2267ldsaEIqtQY6VXs2KCXN0poFjze5110PIpxHDaDGg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.7.0 + + '@opentelemetry/instrumentation-undici@0.23.0': + resolution: {integrity: sha512-LL0VySzKVR2cJSFVZaTYpZl1XTpBGnfzoQPe2W7McS2267ldsaEIqtQY6VXs2KCXN0poFjze5110PIpxHDaDGg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.7.0 - - "@opentelemetry/instrumentation@0.207.0": - resolution: - { - integrity: sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.7.0 + + '@opentelemetry/instrumentation@0.207.0': + resolution: {integrity: sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation@0.208.0": - resolution: - { - integrity: sha512-Eju0L4qWcQS+oXxi6pgh7zvE2byogAkcsVv0OjHF/97iOz1N/aKE6etSGowYkie+YA1uo6DNwdSxaaNnLvcRlA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.208.0': + resolution: {integrity: sha512-Eju0L4qWcQS+oXxi6pgh7zvE2byogAkcsVv0OjHF/97iOz1N/aKE6etSGowYkie+YA1uo6DNwdSxaaNnLvcRlA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation@0.211.0": - resolution: - { - integrity: sha512-h0nrZEC/zvI994nhg7EgQ8URIHt0uDTwN90r3qQUdZORS455bbx+YebnGeEuFghUT0HlJSrLF4iHw67f+odY+Q==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.211.0': + resolution: {integrity: sha512-h0nrZEC/zvI994nhg7EgQ8URIHt0uDTwN90r3qQUdZORS455bbx+YebnGeEuFghUT0HlJSrLF4iHw67f+odY+Q==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation@0.212.0": - resolution: - { - integrity: sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.212.0': + resolution: {integrity: sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/instrumentation@0.213.0": - resolution: - { - integrity: sha512-3i9NdkET/KvQomeh7UaR/F4r9P25Rx6ooALlWXPIjypcEOUxksCmVu0zA70NBJWlrMW1rPr/LRidFAflLI+s/w==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.213.0': + resolution: {integrity: sha512-3i9NdkET/KvQomeh7UaR/F4r9P25Rx6ooALlWXPIjypcEOUxksCmVu0zA70NBJWlrMW1rPr/LRidFAflLI+s/w==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.3.0 - - "@opentelemetry/redis-common@0.38.2": - resolution: - { - integrity: sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==, - } - engines: { node: ^18.19.0 || >=20.6.0 } - - "@opentelemetry/resources@2.6.0": - resolution: - { - integrity: sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/redis-common@0.38.2': + resolution: {integrity: sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==} + engines: {node: ^18.19.0 || >=20.6.0} + + '@opentelemetry/resources@2.6.0': + resolution: {integrity: sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ">=1.3.0 <1.10.0" - - "@opentelemetry/sdk-trace-base@2.6.0": - resolution: - { - integrity: sha512-g/OZVkqlxllgFM7qMKqbPV9c1DUPhQ7d4n3pgZFcrnrNft9eJXZM2TNHTPYREJBrtNdRytYyvwjgL5geDKl3EQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.6.0': + resolution: {integrity: sha512-g/OZVkqlxllgFM7qMKqbPV9c1DUPhQ7d4n3pgZFcrnrNft9eJXZM2TNHTPYREJBrtNdRytYyvwjgL5geDKl3EQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ">=1.3.0 <1.10.0" - - "@opentelemetry/semantic-conventions@1.40.0": - resolution: - { - integrity: sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==, - } - engines: { node: ">=14" } - - "@opentelemetry/sql-common@0.41.2": - resolution: - { - integrity: sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==, - } - engines: { node: ^18.19.0 || >=20.6.0 } + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.40.0': + resolution: {integrity: sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==} + engines: {node: '>=14'} + + '@opentelemetry/sql-common@0.41.2': + resolution: {integrity: sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - "@opentelemetry/api": ^1.1.0 - - "@oslojs/encoding@1.1.0": - resolution: - { - integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==, - } - - "@oxc-project/types@0.110.0": - resolution: - { - integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==, - } - - "@oxc-transform/binding-android-arm-eabi@0.111.0": - resolution: - { - integrity: sha512-NdFLicvorfHYu0g2ftjVJaH7+Dz27AQUNJOq8t/ofRUoWmczOodgUCHx8C1M1htCN4ZmhS/FzfSy6yd/UngJGg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@opentelemetry/api': ^1.1.0 + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@oxc-project/types@0.110.0': + resolution: {integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==} + + '@oxc-transform/binding-android-arm-eabi@0.111.0': + resolution: {integrity: sha512-NdFLicvorfHYu0g2ftjVJaH7+Dz27AQUNJOq8t/ofRUoWmczOodgUCHx8C1M1htCN4ZmhS/FzfSy6yd/UngJGg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - "@oxc-transform/binding-android-arm64@0.111.0": - resolution: - { - integrity: sha512-J2v9ajarD2FYlhHtjbgZUFsS2Kvi27pPxDWLGCy7i8tO60xBoozX9/ktSgbiE/QsxKaUhfv4zVKppKWUo71PmQ==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-android-arm64@0.111.0': + resolution: {integrity: sha512-J2v9ajarD2FYlhHtjbgZUFsS2Kvi27pPxDWLGCy7i8tO60xBoozX9/ktSgbiE/QsxKaUhfv4zVKppKWUo71PmQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - "@oxc-transform/binding-darwin-arm64@0.111.0": - resolution: - { - integrity: sha512-2UYmExxpXzmiHTldhNlosWqG9Nc4US51K0GB9RLcGlTE23WO33vVo1NVAKwxPE+KYuhffwDnRYTovTMUjzwvZA==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-darwin-arm64@0.111.0': + resolution: {integrity: sha512-2UYmExxpXzmiHTldhNlosWqG9Nc4US51K0GB9RLcGlTE23WO33vVo1NVAKwxPE+KYuhffwDnRYTovTMUjzwvZA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - "@oxc-transform/binding-darwin-x64@0.111.0": - resolution: - { - integrity: sha512-c4YRwfLV8Pj/ToiTCbndZaHxM2BD4W3bltr/fjXZcGypEK+U2RZFDL7tIZYT/tyneAC9hCORZKDaKhLLNuzPtA==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-darwin-x64@0.111.0': + resolution: {integrity: sha512-c4YRwfLV8Pj/ToiTCbndZaHxM2BD4W3bltr/fjXZcGypEK+U2RZFDL7tIZYT/tyneAC9hCORZKDaKhLLNuzPtA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - "@oxc-transform/binding-freebsd-x64@0.111.0": - resolution: - { - integrity: sha512-prvf32IcEuLnLZbNVomFosBu0CaZpyj3YsZ6epbOgJy8iJjfLsXBb+PrkO/NBKzjuJoJa2+u7jFKRE0KT7gSOw==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-freebsd-x64@0.111.0': + resolution: {integrity: sha512-prvf32IcEuLnLZbNVomFosBu0CaZpyj3YsZ6epbOgJy8iJjfLsXBb+PrkO/NBKzjuJoJa2+u7jFKRE0KT7gSOw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - "@oxc-transform/binding-linux-arm-gnueabihf@0.111.0": - resolution: - { - integrity: sha512-+se3579Wp7VOk8TnTZCpT+obTAyzOw2b/UuoM0+51LtbzCSfjKxd4A+o7zRl7GyPrPZvx57KdbMOC9rWB1xNrw==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-arm-gnueabihf@0.111.0': + resolution: {integrity: sha512-+se3579Wp7VOk8TnTZCpT+obTAyzOw2b/UuoM0+51LtbzCSfjKxd4A+o7zRl7GyPrPZvx57KdbMOC9rWB1xNrw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - "@oxc-transform/binding-linux-arm-musleabihf@0.111.0": - resolution: - { - integrity: sha512-8faC99pStqaSDPK/vBgaagAHUeL0LcIzfeSjSiDTtvPGc3AwZIeqC1tx3CP15a6tWXjdgS/IUw4IjfD5HweBlg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-arm-musleabihf@0.111.0': + resolution: {integrity: sha512-8faC99pStqaSDPK/vBgaagAHUeL0LcIzfeSjSiDTtvPGc3AwZIeqC1tx3CP15a6tWXjdgS/IUw4IjfD5HweBlg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - "@oxc-transform/binding-linux-arm64-gnu@0.111.0": - resolution: - { - integrity: sha512-HtfQv8j796gzI5WR/RaP6IMwFpiL0vYeDrUA1hYhlPzTHKYan/B+NlhJkKOI1v24yAl/yEnFmb0pxIxLNqBqBA==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-arm64-gnu@0.111.0': + resolution: {integrity: sha512-HtfQv8j796gzI5WR/RaP6IMwFpiL0vYeDrUA1hYhlPzTHKYan/B+NlhJkKOI1v24yAl/yEnFmb0pxIxLNqBqBA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - "@oxc-transform/binding-linux-arm64-musl@0.111.0": - resolution: - { - integrity: sha512-ARyfcMCIxVLDgLf6FQ8Oo1/TFySpnquV+vuSb4SFQZfYDqgMklzwv0NYXxWD0aB6enElyMDs6pQJBzusEKCkOg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-arm64-musl@0.111.0': + resolution: {integrity: sha512-ARyfcMCIxVLDgLf6FQ8Oo1/TFySpnquV+vuSb4SFQZfYDqgMklzwv0NYXxWD0aB6enElyMDs6pQJBzusEKCkOg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - "@oxc-transform/binding-linux-ppc64-gnu@0.111.0": - resolution: - { - integrity: sha512-PKpVRrSvBNK3tv9vwxn7Fay+QWZmprPGlEqJcseBJllQc5mFMD4Q/w44chu5iR9ZLsDeSHzmNWrgMLo4J0sP2A==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-ppc64-gnu@0.111.0': + resolution: {integrity: sha512-PKpVRrSvBNK3tv9vwxn7Fay+QWZmprPGlEqJcseBJllQc5mFMD4Q/w44chu5iR9ZLsDeSHzmNWrgMLo4J0sP2A==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - "@oxc-transform/binding-linux-riscv64-gnu@0.111.0": - resolution: - { - integrity: sha512-9bUml6rMgk+8GF5rvNMweFspkzSiCjqpV6HduwiUyexqfGKrmjq9IZOxxvnzkE2RGdQzP507NNDoVNYIoGQYuA==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-riscv64-gnu@0.111.0': + resolution: {integrity: sha512-9bUml6rMgk+8GF5rvNMweFspkzSiCjqpV6HduwiUyexqfGKrmjq9IZOxxvnzkE2RGdQzP507NNDoVNYIoGQYuA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - "@oxc-transform/binding-linux-riscv64-musl@0.111.0": - resolution: - { - integrity: sha512-tzGCohGxaeH6KRJjfYZd4mHCoGjCai6N+zZi1Oj+tSDMAAdyvs1dRzYb8PNUGnybCg3Te4M0jLPzWZaSmnKraQ==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-riscv64-musl@0.111.0': + resolution: {integrity: sha512-tzGCohGxaeH6KRJjfYZd4mHCoGjCai6N+zZi1Oj+tSDMAAdyvs1dRzYb8PNUGnybCg3Te4M0jLPzWZaSmnKraQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - "@oxc-transform/binding-linux-s390x-gnu@0.111.0": - resolution: - { - integrity: sha512-sRG1KIfZ0ML9ToEygm5aM/5GJeBA05uHlgW3M0Rx/DNWMJhuahLmqWuB02aWSmijndLfEKXLLXIWhvWupRG8lg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-s390x-gnu@0.111.0': + resolution: {integrity: sha512-sRG1KIfZ0ML9ToEygm5aM/5GJeBA05uHlgW3M0Rx/DNWMJhuahLmqWuB02aWSmijndLfEKXLLXIWhvWupRG8lg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - "@oxc-transform/binding-linux-x64-gnu@0.111.0": - resolution: - { - integrity: sha512-T0Kmvk+OdlUdABdXlDIf3MQReMzFfC75NEI9x8jxy5pKooACEFg0k0V8gyR3gq4DzbDCfucqFQDWNvSgIopAbQ==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-x64-gnu@0.111.0': + resolution: {integrity: sha512-T0Kmvk+OdlUdABdXlDIf3MQReMzFfC75NEI9x8jxy5pKooACEFg0k0V8gyR3gq4DzbDCfucqFQDWNvSgIopAbQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - "@oxc-transform/binding-linux-x64-musl@0.111.0": - resolution: - { - integrity: sha512-EgoutsP3YfqzN8a9vpc9+XLr0bmBl0dA3uOMiP77+exATCPxJBkJErGmQkqk6RtTp5XqX6q6mB45qWQyKk6+pA==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-linux-x64-musl@0.111.0': + resolution: {integrity: sha512-EgoutsP3YfqzN8a9vpc9+XLr0bmBl0dA3uOMiP77+exATCPxJBkJErGmQkqk6RtTp5XqX6q6mB45qWQyKk6+pA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - "@oxc-transform/binding-openharmony-arm64@0.111.0": - resolution: - { - integrity: sha512-d8J+ejc0j5WODbVwR/QxFaI65YMwvG0W53vcVCHwa6ja1QI5lpe7sislrefG2EFYgnY47voMRzlXab5d4gEcDw==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-openharmony-arm64@0.111.0': + resolution: {integrity: sha512-d8J+ejc0j5WODbVwR/QxFaI65YMwvG0W53vcVCHwa6ja1QI5lpe7sislrefG2EFYgnY47voMRzlXab5d4gEcDw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - "@oxc-transform/binding-wasm32-wasi@0.111.0": - resolution: - { - integrity: sha512-HtyIZO8IwuZgXkyb56rysLz1OLbfLhEu8A3BeuyJXzUseAj96yuxgGt3cu3QYX9AXb9pfRfA3c/fvlhsDugyTQ==, - } - engines: { node: ">=14.0.0" } + '@oxc-transform/binding-wasm32-wasi@0.111.0': + resolution: {integrity: sha512-HtyIZO8IwuZgXkyb56rysLz1OLbfLhEu8A3BeuyJXzUseAj96yuxgGt3cu3QYX9AXb9pfRfA3c/fvlhsDugyTQ==} + engines: {node: '>=14.0.0'} cpu: [wasm32] - "@oxc-transform/binding-win32-arm64-msvc@0.111.0": - resolution: - { - integrity: sha512-YeP80Riptc0MkVVBnzbmoFuHVLUq278+MbwNo9sTLALmzTIJxJqN029xRZbG+Bun7aLsoZhmRnm3J5JZ1NcP5w==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-win32-arm64-msvc@0.111.0': + resolution: {integrity: sha512-YeP80Riptc0MkVVBnzbmoFuHVLUq278+MbwNo9sTLALmzTIJxJqN029xRZbG+Bun7aLsoZhmRnm3J5JZ1NcP5w==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - "@oxc-transform/binding-win32-ia32-msvc@0.111.0": - resolution: - { - integrity: sha512-A6ztCXpoSHt6PbvGAFqB0MLOcGG7ZJrrPXY1iB0zfOB1atLgI8oNePGxPl03XSbwpiTsFJ1oo8rj9DXcBzgT9g==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-win32-ia32-msvc@0.111.0': + resolution: {integrity: sha512-A6ztCXpoSHt6PbvGAFqB0MLOcGG7ZJrrPXY1iB0zfOB1atLgI8oNePGxPl03XSbwpiTsFJ1oo8rj9DXcBzgT9g==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - "@oxc-transform/binding-win32-x64-msvc@0.111.0": - resolution: - { - integrity: sha512-QddKW4kBH0Wof6Y65eYCNHM4iOGmCTWLLcNYY1FGswhzmTYOUVXajNROR+iCXAOFnOF0ldtsR79SyqgyHH1Bgg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@oxc-transform/binding-win32-x64-msvc@0.111.0': + resolution: {integrity: sha512-QddKW4kBH0Wof6Y65eYCNHM4iOGmCTWLLcNYY1FGswhzmTYOUVXajNROR+iCXAOFnOF0ldtsR79SyqgyHH1Bgg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - "@pagefind/darwin-arm64@1.4.0": - resolution: - { - integrity: sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==, - } + '@pagefind/darwin-arm64@1.4.0': + resolution: {integrity: sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==} cpu: [arm64] os: [darwin] - "@pagefind/darwin-x64@1.4.0": - resolution: - { - integrity: sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A==, - } + '@pagefind/darwin-x64@1.4.0': + resolution: {integrity: sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A==} cpu: [x64] os: [darwin] - "@pagefind/default-ui@1.4.0": - resolution: - { - integrity: sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ==, - } - - "@pagefind/freebsd-x64@1.4.0": - resolution: - { - integrity: sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q==, - } + '@pagefind/default-ui@1.4.0': + resolution: {integrity: sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ==} + + '@pagefind/freebsd-x64@1.4.0': + resolution: {integrity: sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q==} cpu: [x64] os: [freebsd] - "@pagefind/linux-arm64@1.4.0": - resolution: - { - integrity: sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw==, - } + '@pagefind/linux-arm64@1.4.0': + resolution: {integrity: sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw==} cpu: [arm64] os: [linux] - "@pagefind/linux-x64@1.4.0": - resolution: - { - integrity: sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg==, - } + '@pagefind/linux-x64@1.4.0': + resolution: {integrity: sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg==} cpu: [x64] os: [linux] - "@pagefind/windows-x64@1.4.0": - resolution: - { - integrity: sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g==, - } + '@pagefind/windows-x64@1.4.0': + resolution: {integrity: sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g==} cpu: [x64] os: [win32] - "@pkgjs/parseargs@0.11.0": - resolution: - { - integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, - } - engines: { node: ">=14" } - - "@prisma/instrumentation@7.2.0": - resolution: - { - integrity: sha512-Rh9Z4x5kEj1OdARd7U18AtVrnL6rmLSI0qYShaB4W7Wx5BKbgzndWF+QnuzMb7GLfVdlT5aYCXoPQVYuYtVu0g==, - } + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@prisma/instrumentation@7.2.0': + resolution: {integrity: sha512-Rh9Z4x5kEj1OdARd7U18AtVrnL6rmLSI0qYShaB4W7Wx5BKbgzndWF+QnuzMb7GLfVdlT5aYCXoPQVYuYtVu0g==} peerDependencies: - "@opentelemetry/api": ^1.8 + '@opentelemetry/api': ^1.8 - "@prisma/instrumentation@7.4.2": - resolution: - { - integrity: sha512-r9JfchJF1Ae6yAxcaLu/V1TGqBhAuSDe3mRNOssBfx1rMzfZ4fdNvrgUBwyb/TNTGXFxlH9AZix5P257x07nrg==, - } + '@prisma/instrumentation@7.4.2': + resolution: {integrity: sha512-r9JfchJF1Ae6yAxcaLu/V1TGqBhAuSDe3mRNOssBfx1rMzfZ4fdNvrgUBwyb/TNTGXFxlH9AZix5P257x07nrg==} peerDependencies: - "@opentelemetry/api": ^1.8 - - "@promptbook/utils@0.69.5": - resolution: - { - integrity: sha512-xm5Ti/Hp3o4xHrsK9Yy3MS6KbDxYbq485hDsFvxqaNA7equHLPdo8H8faTitTeb14QCDfLW4iwCxdVYu5sn6YQ==, - } - - "@protobufjs/aspromise@1.1.2": - resolution: - { - integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==, - } - - "@protobufjs/base64@1.1.2": - resolution: - { - integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==, - } - - "@protobufjs/codegen@2.0.4": - resolution: - { - integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==, - } - - "@protobufjs/eventemitter@1.1.0": - resolution: - { - integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==, - } - - "@protobufjs/fetch@1.1.0": - resolution: - { - integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==, - } - - "@protobufjs/float@1.0.2": - resolution: - { - integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==, - } - - "@protobufjs/inquire@1.1.0": - resolution: - { - integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==, - } - - "@protobufjs/path@1.1.2": - resolution: - { - integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==, - } - - "@protobufjs/pool@1.1.0": - resolution: - { - integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==, - } - - "@protobufjs/utf8@1.1.0": - resolution: - { - integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==, - } - - "@puppeteer/browsers@2.13.0": - resolution: - { - integrity: sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==, - } - engines: { node: ">=18" } + '@opentelemetry/api': ^1.8 + + '@promptbook/utils@0.69.5': + resolution: {integrity: sha512-xm5Ti/Hp3o4xHrsK9Yy3MS6KbDxYbq485hDsFvxqaNA7equHLPdo8H8faTitTeb14QCDfLW4iwCxdVYu5sn6YQ==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@puppeteer/browsers@2.13.0': + resolution: {integrity: sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==} + engines: {node: '>=18'} hasBin: true - "@redis/bloom@5.11.0": - resolution: - { - integrity: sha512-KYiVilAhAFN3057afUb/tfYJpsEyTkQB+tQcn5gVVA7DgcNOAj8lLxe4j8ov8BF6I9C1Fe/kwlbuAICcTMX8Lw==, - } - engines: { node: ">= 18" } + '@redis/bloom@5.11.0': + resolution: {integrity: sha512-KYiVilAhAFN3057afUb/tfYJpsEyTkQB+tQcn5gVVA7DgcNOAj8lLxe4j8ov8BF6I9C1Fe/kwlbuAICcTMX8Lw==} + engines: {node: '>= 18'} peerDependencies: - "@redis/client": ^5.11.0 - - "@redis/client@5.11.0": - resolution: - { - integrity: sha512-GHoprlNQD51Xq2Ztd94HHV94MdFZQ3CVrpA04Fz8MVoHM0B7SlbmPEVIjwTbcv58z8QyjnrOuikS0rWF03k5dQ==, - } - engines: { node: ">= 18" } + '@redis/client': ^5.11.0 + + '@redis/client@5.11.0': + resolution: {integrity: sha512-GHoprlNQD51Xq2Ztd94HHV94MdFZQ3CVrpA04Fz8MVoHM0B7SlbmPEVIjwTbcv58z8QyjnrOuikS0rWF03k5dQ==} + engines: {node: '>= 18'} peerDependencies: - "@node-rs/xxhash": ^1.1.0 + '@node-rs/xxhash': ^1.1.0 peerDependenciesMeta: - "@node-rs/xxhash": + '@node-rs/xxhash': optional: true - "@redis/json@5.11.0": - resolution: - { - integrity: sha512-1iAy9kAtcD0quB21RbPTbUqqy+T2Uu2JxucwE+B4A+VaDbIRvpZR6DMqV8Iqaws2YxJYB3GC5JVNzPYio2ErUg==, - } - engines: { node: ">= 18" } + '@redis/json@5.11.0': + resolution: {integrity: sha512-1iAy9kAtcD0quB21RbPTbUqqy+T2Uu2JxucwE+B4A+VaDbIRvpZR6DMqV8Iqaws2YxJYB3GC5JVNzPYio2ErUg==} + engines: {node: '>= 18'} peerDependencies: - "@redis/client": ^5.11.0 - - "@redis/search@5.11.0": - resolution: - { - integrity: sha512-g1l7f3Rnyk/xI99oGHIgWHSKFl45Re5YTIcO8j/JE8olz389yUFyz2+A6nqVy/Zi031VgPDWscbbgOk8hlhZ3g==, - } - engines: { node: ">= 18" } + '@redis/client': ^5.11.0 + + '@redis/search@5.11.0': + resolution: {integrity: sha512-g1l7f3Rnyk/xI99oGHIgWHSKFl45Re5YTIcO8j/JE8olz389yUFyz2+A6nqVy/Zi031VgPDWscbbgOk8hlhZ3g==} + engines: {node: '>= 18'} peerDependencies: - "@redis/client": ^5.11.0 - - "@redis/time-series@5.11.0": - resolution: - { - integrity: sha512-TWFeOcU4xkj0DkndnOyhtxvX1KWD+78UHT3XX3x3XRBUGWeQrKo3jqzDsZwxbggUgf9yLJr/akFHXru66X5UQA==, - } - engines: { node: ">= 18" } + '@redis/client': ^5.11.0 + + '@redis/time-series@5.11.0': + resolution: {integrity: sha512-TWFeOcU4xkj0DkndnOyhtxvX1KWD+78UHT3XX3x3XRBUGWeQrKo3jqzDsZwxbggUgf9yLJr/akFHXru66X5UQA==} + engines: {node: '>= 18'} peerDependencies: - "@redis/client": ^5.11.0 - - "@renovatebot/pep440@4.2.1": - resolution: - { - integrity: sha512-2FK1hF93Fuf1laSdfiEmJvSJPVIDHEUTz68D3Fi9s0IZrrpaEcj6pTFBTbYvsgC5du4ogrtf5re7yMMvrKNgkw==, - } - engines: { node: ^20.9.0 || ^22.11.0 || ^24, pnpm: ^10.0.0 } - - "@rolldown/binding-android-arm64@1.0.0-rc.1": - resolution: - { - integrity: sha512-He6ZoCfv5D7dlRbrhNBkuMVIHd0GDnjJwbICE1OWpG7G3S2gmJ+eXkcNLJjzjNDpeI2aRy56ou39AJM9AD8YFA==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@redis/client': ^5.11.0 + + '@renovatebot/pep440@4.2.1': + resolution: {integrity: sha512-2FK1hF93Fuf1laSdfiEmJvSJPVIDHEUTz68D3Fi9s0IZrrpaEcj6pTFBTbYvsgC5du4ogrtf5re7yMMvrKNgkw==} + engines: {node: ^20.9.0 || ^22.11.0 || ^24, pnpm: ^10.0.0} + + '@rolldown/binding-android-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-He6ZoCfv5D7dlRbrhNBkuMVIHd0GDnjJwbICE1OWpG7G3S2gmJ+eXkcNLJjzjNDpeI2aRy56ou39AJM9AD8YFA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - "@rolldown/binding-darwin-arm64@1.0.0-rc.1": - resolution: - { - integrity: sha512-YzJdn08kSOXnj85ghHauH2iHpOJ6eSmstdRTLyaziDcUxe9SyQJgGyx/5jDIhDvtOcNvMm2Ju7m19+S/Rm1jFg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-darwin-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-YzJdn08kSOXnj85ghHauH2iHpOJ6eSmstdRTLyaziDcUxe9SyQJgGyx/5jDIhDvtOcNvMm2Ju7m19+S/Rm1jFg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - "@rolldown/binding-darwin-x64@1.0.0-rc.1": - resolution: - { - integrity: sha512-cIvAbqM+ZVV6lBSKSBtlNqH5iCiW933t1q8j0H66B3sjbe8AxIRetVqfGgcHcJtMzBIkIALlL9fcDrElWLJQcQ==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-darwin-x64@1.0.0-rc.1': + resolution: {integrity: sha512-cIvAbqM+ZVV6lBSKSBtlNqH5iCiW933t1q8j0H66B3sjbe8AxIRetVqfGgcHcJtMzBIkIALlL9fcDrElWLJQcQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - "@rolldown/binding-freebsd-x64@1.0.0-rc.1": - resolution: - { - integrity: sha512-rVt+B1B/qmKwCl1XD02wKfgh3vQPXRXdB/TicV2w6g7RVAM1+cZcpigwhLarqiVCxDObFZ7UgXCxPC7tpDoRog==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-freebsd-x64@1.0.0-rc.1': + resolution: {integrity: sha512-rVt+B1B/qmKwCl1XD02wKfgh3vQPXRXdB/TicV2w6g7RVAM1+cZcpigwhLarqiVCxDObFZ7UgXCxPC7tpDoRog==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - "@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1": - resolution: - { - integrity: sha512-69YKwJJBOFprQa1GktPgbuBOfnn+EGxu8sBJ1TjPER+zhSpYeaU4N07uqmyBiksOLGXsMegymuecLobfz03h8Q==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': + resolution: {integrity: sha512-69YKwJJBOFprQa1GktPgbuBOfnn+EGxu8sBJ1TjPER+zhSpYeaU4N07uqmyBiksOLGXsMegymuecLobfz03h8Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - "@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1": - resolution: - { - integrity: sha512-9JDhHUf3WcLfnViFWm+TyorqUtnSAHaCzlSNmMOq824prVuuzDOK91K0Hl8DUcEb9M5x2O+d2/jmBMsetRIn3g==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': + resolution: {integrity: sha512-9JDhHUf3WcLfnViFWm+TyorqUtnSAHaCzlSNmMOq824prVuuzDOK91K0Hl8DUcEb9M5x2O+d2/jmBMsetRIn3g==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - "@rolldown/binding-linux-arm64-musl@1.0.0-rc.1": - resolution: - { - integrity: sha512-UvApLEGholmxw/HIwmUnLq3CwdydbhaHHllvWiCTNbyGom7wTwOtz5OAQbAKZYyiEOeIXZNPkM7nA4Dtng7CLw==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': + resolution: {integrity: sha512-UvApLEGholmxw/HIwmUnLq3CwdydbhaHHllvWiCTNbyGom7wTwOtz5OAQbAKZYyiEOeIXZNPkM7nA4Dtng7CLw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - "@rolldown/binding-linux-x64-gnu@1.0.0-rc.1": - resolution: - { - integrity: sha512-uVctNgZHiGnJx5Fij7wHLhgw4uyZBVi6mykeWKOqE7bVy9Hcxn0fM/IuqdMwk6hXlaf9fFShDTFz2+YejP+x0A==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': + resolution: {integrity: sha512-uVctNgZHiGnJx5Fij7wHLhgw4uyZBVi6mykeWKOqE7bVy9Hcxn0fM/IuqdMwk6hXlaf9fFShDTFz2+YejP+x0A==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - "@rolldown/binding-linux-x64-musl@1.0.0-rc.1": - resolution: - { - integrity: sha512-T6Eg0xWwcxd/MzBcuv4Z37YVbUbJxy5cMNnbIt/Yr99wFwli30O4BPlY8hKeGyn6lWNtU0QioBS46lVzDN38bg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': + resolution: {integrity: sha512-T6Eg0xWwcxd/MzBcuv4Z37YVbUbJxy5cMNnbIt/Yr99wFwli30O4BPlY8hKeGyn6lWNtU0QioBS46lVzDN38bg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - "@rolldown/binding-openharmony-arm64@1.0.0-rc.1": - resolution: - { - integrity: sha512-PuGZVS2xNJyLADeh2F04b+Cz4NwvpglbtWACgrDOa5YDTEHKwmiTDjoD5eZ9/ptXtcpeFrMqD2H4Zn33KAh1Eg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-PuGZVS2xNJyLADeh2F04b+Cz4NwvpglbtWACgrDOa5YDTEHKwmiTDjoD5eZ9/ptXtcpeFrMqD2H4Zn33KAh1Eg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - "@rolldown/binding-wasm32-wasi@1.0.0-rc.1": - resolution: - { - integrity: sha512-2mOxY562ihHlz9lEXuaGEIDCZ1vI+zyFdtsoa3M62xsEunDXQE+DVPO4S4x5MPK9tKulG/aFcA/IH5eVN257Cw==, - } - engines: { node: ">=14.0.0" } + '@rolldown/binding-wasm32-wasi@1.0.0-rc.1': + resolution: {integrity: sha512-2mOxY562ihHlz9lEXuaGEIDCZ1vI+zyFdtsoa3M62xsEunDXQE+DVPO4S4x5MPK9tKulG/aFcA/IH5eVN257Cw==} + engines: {node: '>=14.0.0'} cpu: [wasm32] - "@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1": - resolution: - { - integrity: sha512-oQVOP5cfAWZwRD0Q3nGn/cA9FW3KhMMuQ0NIndALAe6obqjLhqYVYDiGGRGrxvnjJsVbpLwR14gIUYnpIcHR1g==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': + resolution: {integrity: sha512-oQVOP5cfAWZwRD0Q3nGn/cA9FW3KhMMuQ0NIndALAe6obqjLhqYVYDiGGRGrxvnjJsVbpLwR14gIUYnpIcHR1g==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - "@rolldown/binding-win32-x64-msvc@1.0.0-rc.1": - resolution: - { - integrity: sha512-Ydsxxx++FNOuov3wCBPaYjZrEvKOOGq3k+BF4BPridhg2pENfitSRD2TEuQ8i33bp5VptuNdC9IzxRKU031z5A==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': + resolution: {integrity: sha512-Ydsxxx++FNOuov3wCBPaYjZrEvKOOGq3k+BF4BPridhg2pENfitSRD2TEuQ8i33bp5VptuNdC9IzxRKU031z5A==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - "@rolldown/pluginutils@1.0.0-rc.1": - resolution: - { - integrity: sha512-UTBjtTxVOhodhzFVp/ayITaTETRHPUPYZPXQe0WU0wOgxghMojXxYjOiPOauKIYNWJAWS2fd7gJgGQK8GU8vDA==, - } - - "@rollup/plugin-commonjs@28.0.1": - resolution: - { - integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==, - } - engines: { node: ">=16.0.0 || 14 >= 14.17" } + '@rolldown/pluginutils@1.0.0-rc.1': + resolution: {integrity: sha512-UTBjtTxVOhodhzFVp/ayITaTETRHPUPYZPXQe0WU0wOgxghMojXxYjOiPOauKIYNWJAWS2fd7gJgGQK8GU8vDA==} + + '@rollup/plugin-commonjs@28.0.1': + resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - "@rollup/pluginutils@5.3.0": - resolution: - { - integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==, - } - engines: { node: ">=14.0.0" } + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - "@rollup/rollup-android-arm-eabi@4.59.0": - resolution: - { - integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==, - } + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] os: [android] - "@rollup/rollup-android-arm64@4.59.0": - resolution: - { - integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==, - } + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} cpu: [arm64] os: [android] - "@rollup/rollup-darwin-arm64@4.59.0": - resolution: - { - integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==, - } + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} cpu: [arm64] os: [darwin] - "@rollup/rollup-darwin-x64@4.59.0": - resolution: - { - integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==, - } + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} cpu: [x64] os: [darwin] - "@rollup/rollup-freebsd-arm64@4.59.0": - resolution: - { - integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==, - } + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} cpu: [arm64] os: [freebsd] - "@rollup/rollup-freebsd-x64@4.59.0": - resolution: - { - integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==, - } + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} cpu: [x64] os: [freebsd] - "@rollup/rollup-linux-arm-gnueabihf@4.59.0": - resolution: - { - integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==, - } + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] libc: [glibc] - "@rollup/rollup-linux-arm-musleabihf@4.59.0": - resolution: - { - integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==, - } + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] libc: [musl] - "@rollup/rollup-linux-arm64-gnu@4.59.0": - resolution: - { - integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==, - } + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] libc: [glibc] - "@rollup/rollup-linux-arm64-musl@4.59.0": - resolution: - { - integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==, - } + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] libc: [musl] - "@rollup/rollup-linux-loong64-gnu@4.59.0": - resolution: - { - integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==, - } + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} cpu: [loong64] os: [linux] libc: [glibc] - "@rollup/rollup-linux-loong64-musl@4.59.0": - resolution: - { - integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==, - } + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} cpu: [loong64] os: [linux] libc: [musl] - "@rollup/rollup-linux-ppc64-gnu@4.59.0": - resolution: - { - integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==, - } + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} cpu: [ppc64] os: [linux] libc: [glibc] - "@rollup/rollup-linux-ppc64-musl@4.59.0": - resolution: - { - integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==, - } + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} cpu: [ppc64] os: [linux] libc: [musl] - "@rollup/rollup-linux-riscv64-gnu@4.59.0": - resolution: - { - integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==, - } + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} cpu: [riscv64] os: [linux] libc: [glibc] - "@rollup/rollup-linux-riscv64-musl@4.59.0": - resolution: - { - integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==, - } + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} cpu: [riscv64] os: [linux] libc: [musl] - "@rollup/rollup-linux-s390x-gnu@4.59.0": - resolution: - { - integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==, - } + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} cpu: [s390x] os: [linux] libc: [glibc] - "@rollup/rollup-linux-x64-gnu@4.59.0": - resolution: - { - integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==, - } + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} cpu: [x64] os: [linux] libc: [glibc] - "@rollup/rollup-linux-x64-musl@4.59.0": - resolution: - { - integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==, - } + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} cpu: [x64] os: [linux] libc: [musl] - "@rollup/rollup-openbsd-x64@4.59.0": - resolution: - { - integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==, - } + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} cpu: [x64] os: [openbsd] - "@rollup/rollup-openharmony-arm64@4.59.0": - resolution: - { - integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==, - } + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} cpu: [arm64] os: [openharmony] - "@rollup/rollup-win32-arm64-msvc@4.59.0": - resolution: - { - integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==, - } + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} cpu: [arm64] os: [win32] - "@rollup/rollup-win32-ia32-msvc@4.59.0": - resolution: - { - integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==, - } + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} cpu: [ia32] os: [win32] - "@rollup/rollup-win32-x64-gnu@4.59.0": - resolution: - { - integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==, - } + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} cpu: [x64] os: [win32] - "@rollup/rollup-win32-x64-msvc@4.59.0": - resolution: - { - integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==, - } + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} cpu: [x64] os: [win32] - "@sentry-internal/browser-utils@10.42.0": - resolution: - { - integrity: sha512-HCEICKvepxN4/6NYfnMMMlppcSwIEwtS66X6d1/mwaHdi2ivw0uGl52p7Nfhda/lIJArbrkWprxl0WcjZajhQA==, - } - engines: { node: ">=18" } - - "@sentry-internal/browser-utils@10.44.0": - resolution: - { - integrity: sha512-z9xz3T/v+MnfHY6kdUCmOZI8CiAl3LlKYtGH2p3rAsrxhwX+BTnUp01VhMVnEZIDgUXNt3AhJac+4kcDIPu1Hg==, - } - engines: { node: ">=18" } - - "@sentry-internal/feedback@10.42.0": - resolution: - { - integrity: sha512-lpPcHsog10MVYFTWE0Pf8vQRqQWwZHJpkVl2FEb9/HDdHFyTBUhCVoWo1KyKaG7GJl9AVKMAg7bp9SSNArhFNQ==, - } - engines: { node: ">=18" } - - "@sentry-internal/feedback@10.44.0": - resolution: - { - integrity: sha512-yNS2EGK1bNm8YUI+Orzpa7yr05Da+b1VEe/9x7dl7gTjw/+tfutoXlG6Y+iFZBB3gQ9QU+nxZAhU+KcxiPEURw==, - } - engines: { node: ">=18" } - - "@sentry-internal/replay-canvas@10.42.0": - resolution: - { - integrity: sha512-am3m1Fj8ihoPfoYo41Qq4KeCAAICn4bySso8Oepu9dMNe9Lcnsf+reMRS2qxTPg3pZDc4JEMOcLyNCcgnAfrHw==, - } - engines: { node: ">=18" } - - "@sentry-internal/replay-canvas@10.44.0": - resolution: - { - integrity: sha512-RA7XgYZWHY7M+vaHvuMxDFT51wCs4puS2smElM5oh+j3YqbFXY7P16fOCwIAGoyI4gVsj8aTeBgVqUmrmzhAXQ==, - } - engines: { node: ">=18" } - - "@sentry-internal/replay@10.42.0": - resolution: - { - integrity: sha512-Zh3EoaH39x2lqVY1YyVB2vJEyCIrT+YLUQxYl1yvP0MJgLxaR6akVjkgxbSUJahan4cX5DxpZiEHfzdlWnYPyQ==, - } - engines: { node: ">=18" } - - "@sentry-internal/replay@10.44.0": - resolution: - { - integrity: sha512-KDmoqBsRmkaoc+eKLR2CbScd2eBmLcw+1+D441lLttAO3WWhvYyCaYdu/HIGGUoybuSgt+IcpCJdi7hFuCvYqw==, - } - engines: { node: ">=18" } - - "@sentry/babel-plugin-component-annotate@5.1.1": - resolution: - { - integrity: sha512-x2wEpBHwsTyTF2rWsLKJlzrRF1TTIGOfX+ngdE+Yd5DBkoS58HwQv824QOviPGQRla4/ypISqAXzjdDPL/zalg==, - } - engines: { node: ">= 18" } - - "@sentry/browser@10.42.0": - resolution: - { - integrity: sha512-iXxYjXNEBwY1MH4lDSDZZUNjzPJDK7/YLwVIJq/3iBYpIQVIhaJsoJnf3clx9+NfJ8QFKyKfcvgae61zm+hgTA==, - } - engines: { node: ">=18" } - - "@sentry/browser@10.44.0": - resolution: - { - integrity: sha512-UpMx5forbVKieNULma3gT2SsLYqsYT4nLXa6s1io/Y8BFej9sH2dD5ExA8TrkQThQwAWFI3qKsQzYnF+EX/Bfg==, - } - engines: { node: ">=18" } - - "@sentry/bundler-plugin-core@5.1.1": - resolution: - { - integrity: sha512-F+itpwR9DyQR7gEkrXd2tigREPTvtF5lC8qu6e4anxXYRTui1+dVR0fXNwjpyAZMhIesLfXRN7WY7ggdj7hi0Q==, - } - engines: { node: ">= 18" } - - "@sentry/cli-darwin@2.58.5": - resolution: - { - integrity: sha512-lYrNzenZFJftfwSya7gwrHGxtE+Kob/e1sr9lmHMFOd4utDlmq0XFDllmdZAMf21fxcPRI1GL28ejZ3bId01fQ==, - } - engines: { node: ">=10" } + '@sentry-internal/browser-utils@10.42.0': + resolution: {integrity: sha512-HCEICKvepxN4/6NYfnMMMlppcSwIEwtS66X6d1/mwaHdi2ivw0uGl52p7Nfhda/lIJArbrkWprxl0WcjZajhQA==} + engines: {node: '>=18'} + + '@sentry-internal/browser-utils@10.44.0': + resolution: {integrity: sha512-z9xz3T/v+MnfHY6kdUCmOZI8CiAl3LlKYtGH2p3rAsrxhwX+BTnUp01VhMVnEZIDgUXNt3AhJac+4kcDIPu1Hg==} + engines: {node: '>=18'} + + '@sentry-internal/feedback@10.42.0': + resolution: {integrity: sha512-lpPcHsog10MVYFTWE0Pf8vQRqQWwZHJpkVl2FEb9/HDdHFyTBUhCVoWo1KyKaG7GJl9AVKMAg7bp9SSNArhFNQ==} + engines: {node: '>=18'} + + '@sentry-internal/feedback@10.44.0': + resolution: {integrity: sha512-yNS2EGK1bNm8YUI+Orzpa7yr05Da+b1VEe/9x7dl7gTjw/+tfutoXlG6Y+iFZBB3gQ9QU+nxZAhU+KcxiPEURw==} + engines: {node: '>=18'} + + '@sentry-internal/replay-canvas@10.42.0': + resolution: {integrity: sha512-am3m1Fj8ihoPfoYo41Qq4KeCAAICn4bySso8Oepu9dMNe9Lcnsf+reMRS2qxTPg3pZDc4JEMOcLyNCcgnAfrHw==} + engines: {node: '>=18'} + + '@sentry-internal/replay-canvas@10.44.0': + resolution: {integrity: sha512-RA7XgYZWHY7M+vaHvuMxDFT51wCs4puS2smElM5oh+j3YqbFXY7P16fOCwIAGoyI4gVsj8aTeBgVqUmrmzhAXQ==} + engines: {node: '>=18'} + + '@sentry-internal/replay@10.42.0': + resolution: {integrity: sha512-Zh3EoaH39x2lqVY1YyVB2vJEyCIrT+YLUQxYl1yvP0MJgLxaR6akVjkgxbSUJahan4cX5DxpZiEHfzdlWnYPyQ==} + engines: {node: '>=18'} + + '@sentry-internal/replay@10.44.0': + resolution: {integrity: sha512-KDmoqBsRmkaoc+eKLR2CbScd2eBmLcw+1+D441lLttAO3WWhvYyCaYdu/HIGGUoybuSgt+IcpCJdi7hFuCvYqw==} + engines: {node: '>=18'} + + '@sentry/babel-plugin-component-annotate@5.1.1': + resolution: {integrity: sha512-x2wEpBHwsTyTF2rWsLKJlzrRF1TTIGOfX+ngdE+Yd5DBkoS58HwQv824QOviPGQRla4/ypISqAXzjdDPL/zalg==} + engines: {node: '>= 18'} + + '@sentry/browser@10.42.0': + resolution: {integrity: sha512-iXxYjXNEBwY1MH4lDSDZZUNjzPJDK7/YLwVIJq/3iBYpIQVIhaJsoJnf3clx9+NfJ8QFKyKfcvgae61zm+hgTA==} + engines: {node: '>=18'} + + '@sentry/browser@10.44.0': + resolution: {integrity: sha512-UpMx5forbVKieNULma3gT2SsLYqsYT4nLXa6s1io/Y8BFej9sH2dD5ExA8TrkQThQwAWFI3qKsQzYnF+EX/Bfg==} + engines: {node: '>=18'} + + '@sentry/bundler-plugin-core@5.1.1': + resolution: {integrity: sha512-F+itpwR9DyQR7gEkrXd2tigREPTvtF5lC8qu6e4anxXYRTui1+dVR0fXNwjpyAZMhIesLfXRN7WY7ggdj7hi0Q==} + engines: {node: '>= 18'} + + '@sentry/cli-darwin@2.58.5': + resolution: {integrity: sha512-lYrNzenZFJftfwSya7gwrHGxtE+Kob/e1sr9lmHMFOd4utDlmq0XFDllmdZAMf21fxcPRI1GL28ejZ3bId01fQ==} + engines: {node: '>=10'} os: [darwin] - "@sentry/cli-linux-arm64@2.58.5": - resolution: - { - integrity: sha512-/4gywFeBqRB6tR/iGMRAJ3HRqY6Z7Yp4l8ZCbl0TDLAfHNxu7schEw4tSnm2/Hh9eNMiOVy4z58uzAWlZXAYBQ==, - } - engines: { node: ">=10" } + '@sentry/cli-linux-arm64@2.58.5': + resolution: {integrity: sha512-/4gywFeBqRB6tR/iGMRAJ3HRqY6Z7Yp4l8ZCbl0TDLAfHNxu7schEw4tSnm2/Hh9eNMiOVy4z58uzAWlZXAYBQ==} + engines: {node: '>=10'} cpu: [arm64] os: [linux, freebsd, android] - "@sentry/cli-linux-arm@2.58.5": - resolution: - { - integrity: sha512-KtHweSIomYL4WVDrBrYSYJricKAAzxUgX86kc6OnlikbyOhoK6Fy8Vs6vwd52P6dvWPjgrMpUYjW2M5pYXQDUw==, - } - engines: { node: ">=10" } + '@sentry/cli-linux-arm@2.58.5': + resolution: {integrity: sha512-KtHweSIomYL4WVDrBrYSYJricKAAzxUgX86kc6OnlikbyOhoK6Fy8Vs6vwd52P6dvWPjgrMpUYjW2M5pYXQDUw==} + engines: {node: '>=10'} cpu: [arm] os: [linux, freebsd, android] - "@sentry/cli-linux-i686@2.58.5": - resolution: - { - integrity: sha512-G7261dkmyxqlMdyvyP06b+RTIVzp1gZNgglj5UksxSouSUqRd/46W/2pQeOMPhloDYo9yLtCN2YFb3Mw4aUsWw==, - } - engines: { node: ">=10" } + '@sentry/cli-linux-i686@2.58.5': + resolution: {integrity: sha512-G7261dkmyxqlMdyvyP06b+RTIVzp1gZNgglj5UksxSouSUqRd/46W/2pQeOMPhloDYo9yLtCN2YFb3Mw4aUsWw==} + engines: {node: '>=10'} cpu: [x86, ia32] os: [linux, freebsd, android] - "@sentry/cli-linux-x64@2.58.5": - resolution: - { - integrity: sha512-rP04494RSmt86xChkQ+ecBNRYSPbyXc4u0IA7R7N1pSLCyO74e5w5Al+LnAq35cMfVbZgz5Sm0iGLjyiUu4I1g==, - } - engines: { node: ">=10" } + '@sentry/cli-linux-x64@2.58.5': + resolution: {integrity: sha512-rP04494RSmt86xChkQ+ecBNRYSPbyXc4u0IA7R7N1pSLCyO74e5w5Al+LnAq35cMfVbZgz5Sm0iGLjyiUu4I1g==} + engines: {node: '>=10'} cpu: [x64] os: [linux, freebsd, android] - "@sentry/cli-win32-arm64@2.58.5": - resolution: - { - integrity: sha512-AOJ2nCXlQL1KBaCzv38m3i2VmSHNurUpm7xVKd6yAHX+ZoVBI8VT0EgvwmtJR2TY2N2hNCC7UrgRmdUsQ152bA==, - } - engines: { node: ">=10" } + '@sentry/cli-win32-arm64@2.58.5': + resolution: {integrity: sha512-AOJ2nCXlQL1KBaCzv38m3i2VmSHNurUpm7xVKd6yAHX+ZoVBI8VT0EgvwmtJR2TY2N2hNCC7UrgRmdUsQ152bA==} + engines: {node: '>=10'} cpu: [arm64] os: [win32] - "@sentry/cli-win32-i686@2.58.5": - resolution: - { - integrity: sha512-EsuboLSOnlrN7MMPJ1eFvfMDm+BnzOaSWl8eYhNo8W/BIrmNgpRUdBwnWn9Q2UOjJj5ZopukmsiMYtU/D7ml9g==, - } - engines: { node: ">=10" } + '@sentry/cli-win32-i686@2.58.5': + resolution: {integrity: sha512-EsuboLSOnlrN7MMPJ1eFvfMDm+BnzOaSWl8eYhNo8W/BIrmNgpRUdBwnWn9Q2UOjJj5ZopukmsiMYtU/D7ml9g==} + engines: {node: '>=10'} cpu: [x86, ia32] os: [win32] - "@sentry/cli-win32-x64@2.58.5": - resolution: - { - integrity: sha512-IZf+XIMiQwj+5NzqbOQfywlOitmCV424Vtf9c+ep61AaVScUFD1TSrQbOcJJv5xGxhlxNOMNgMeZhdexdzrKZg==, - } - engines: { node: ">=10" } + '@sentry/cli-win32-x64@2.58.5': + resolution: {integrity: sha512-IZf+XIMiQwj+5NzqbOQfywlOitmCV424Vtf9c+ep61AaVScUFD1TSrQbOcJJv5xGxhlxNOMNgMeZhdexdzrKZg==} + engines: {node: '>=10'} cpu: [x64] os: [win32] - "@sentry/cli@2.58.5": - resolution: - { - integrity: sha512-tavJ7yGUZV+z3Ct2/ZB6mg339i08sAk6HDkgqmSRuQEu2iLS5sl9HIvuXfM6xjv8fwlgFOSy++WNABNAcGHUbg==, - } - engines: { node: ">= 10" } + '@sentry/cli@2.58.5': + resolution: {integrity: sha512-tavJ7yGUZV+z3Ct2/ZB6mg339i08sAk6HDkgqmSRuQEu2iLS5sl9HIvuXfM6xjv8fwlgFOSy++WNABNAcGHUbg==} + engines: {node: '>= 10'} hasBin: true - "@sentry/core@10.42.0": - resolution: - { - integrity: sha512-L4rMrXMqUKBanpjpMT+TuAVk6xAijz6AWM6RiEYpohAr7SGcCEc1/T0+Ep1eLV8+pwWacfU27OvELIyNeOnGzA==, - } - engines: { node: ">=18" } - - "@sentry/core@10.44.0": - resolution: - { - integrity: sha512-aa7CiDaNFZvHpqd97LJhuskolfJ/4IH5xyuVVLnv7l6B0v9KTwskPUxb0tH1ej3FxuzfH+i8iTiTFuqpfHS3QA==, - } - engines: { node: ">=18" } - - "@sentry/nextjs@10.42.0": - resolution: - { - integrity: sha512-4YcVwicZLQWCNXMRSmtg0q68cqhttwhUqcvTe0aYg4YkQIDQKzVOYVU7/js9kSK1PFe9gFdaUxgboBYBp2evDg==, - } - engines: { node: ">=18" } + '@sentry/core@10.42.0': + resolution: {integrity: sha512-L4rMrXMqUKBanpjpMT+TuAVk6xAijz6AWM6RiEYpohAr7SGcCEc1/T0+Ep1eLV8+pwWacfU27OvELIyNeOnGzA==} + engines: {node: '>=18'} + + '@sentry/core@10.44.0': + resolution: {integrity: sha512-aa7CiDaNFZvHpqd97LJhuskolfJ/4IH5xyuVVLnv7l6B0v9KTwskPUxb0tH1ej3FxuzfH+i8iTiTFuqpfHS3QA==} + engines: {node: '>=18'} + + '@sentry/nextjs@10.42.0': + resolution: {integrity: sha512-4YcVwicZLQWCNXMRSmtg0q68cqhttwhUqcvTe0aYg4YkQIDQKzVOYVU7/js9kSK1PFe9gFdaUxgboBYBp2evDg==} + engines: {node: '>=18'} peerDependencies: next: ^13.2.0 || ^14.0 || ^15.0.0-rc.0 || ^16.0.0-0 - "@sentry/nextjs@10.44.0": - resolution: - { - integrity: sha512-bZzeADQjQvtz6FOADJqOgC0nGYIaBjD+KrqpBuxoYVqDXLY9BjJ5VddxWwItu0gV9cYPtu6YrQNESrCCiPyWqA==, - } - engines: { node: ">=18" } + '@sentry/nextjs@10.44.0': + resolution: {integrity: sha512-bZzeADQjQvtz6FOADJqOgC0nGYIaBjD+KrqpBuxoYVqDXLY9BjJ5VddxWwItu0gV9cYPtu6YrQNESrCCiPyWqA==} + engines: {node: '>=18'} peerDependencies: next: ^13.2.0 || ^14.0 || ^15.0.0-rc.0 || ^16.0.0-0 - "@sentry/node-core@10.42.0": - resolution: - { - integrity: sha512-9tf3fPV6M071aps72D+PEtdQPTuj+SuqO2+PpTfdPP5ZL4TTKYo3VK0li76SL+5wGdTFGV5qmsokHq9IRBA0iA==, - } - engines: { node: ">=18" } - peerDependencies: - "@opentelemetry/api": ^1.9.0 - "@opentelemetry/context-async-hooks": ^1.30.1 || ^2.1.0 - "@opentelemetry/core": ^1.30.1 || ^2.1.0 - "@opentelemetry/instrumentation": ">=0.57.1 <1" - "@opentelemetry/resources": ^1.30.1 || ^2.1.0 - "@opentelemetry/sdk-trace-base": ^1.30.1 || ^2.1.0 - "@opentelemetry/semantic-conventions": ^1.39.0 + '@sentry/node-core@10.42.0': + resolution: {integrity: sha512-9tf3fPV6M071aps72D+PEtdQPTuj+SuqO2+PpTfdPP5ZL4TTKYo3VK0li76SL+5wGdTFGV5qmsokHq9IRBA0iA==} + engines: {node: '>=18'} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 + '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/instrumentation': '>=0.57.1 <1' + '@opentelemetry/resources': ^1.30.1 || ^2.1.0 + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + '@opentelemetry/semantic-conventions': ^1.39.0 peerDependenciesMeta: - "@opentelemetry/api": + '@opentelemetry/api': optional: true - "@opentelemetry/context-async-hooks": + '@opentelemetry/context-async-hooks': optional: true - "@opentelemetry/core": + '@opentelemetry/core': optional: true - "@opentelemetry/instrumentation": + '@opentelemetry/instrumentation': optional: true - "@opentelemetry/resources": + '@opentelemetry/resources': optional: true - "@opentelemetry/sdk-trace-base": + '@opentelemetry/sdk-trace-base': optional: true - "@opentelemetry/semantic-conventions": + '@opentelemetry/semantic-conventions': optional: true - "@sentry/node-core@10.44.0": - resolution: - { - integrity: sha512-jUGsadMrvZ08UMbqJBfjFFMk1k3VbyxfUypf0iDGGgyLmuHotYQPo/5aND+o2KxMDXR60LwcQrMoZFpanK6jXQ==, - } - engines: { node: ">=18" } + '@sentry/node-core@10.44.0': + resolution: {integrity: sha512-jUGsadMrvZ08UMbqJBfjFFMk1k3VbyxfUypf0iDGGgyLmuHotYQPo/5aND+o2KxMDXR60LwcQrMoZFpanK6jXQ==} + engines: {node: '>=18'} peerDependencies: - "@opentelemetry/api": ^1.9.0 - "@opentelemetry/context-async-hooks": ^1.30.1 || ^2.1.0 - "@opentelemetry/core": ^1.30.1 || ^2.1.0 - "@opentelemetry/instrumentation": ">=0.57.1 <1" - "@opentelemetry/resources": ^1.30.1 || ^2.1.0 - "@opentelemetry/sdk-trace-base": ^1.30.1 || ^2.1.0 - "@opentelemetry/semantic-conventions": ^1.39.0 + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 + '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/instrumentation': '>=0.57.1 <1' + '@opentelemetry/resources': ^1.30.1 || ^2.1.0 + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + '@opentelemetry/semantic-conventions': ^1.39.0 peerDependenciesMeta: - "@opentelemetry/api": + '@opentelemetry/api': optional: true - "@opentelemetry/context-async-hooks": + '@opentelemetry/context-async-hooks': optional: true - "@opentelemetry/core": + '@opentelemetry/core': optional: true - "@opentelemetry/instrumentation": + '@opentelemetry/instrumentation': optional: true - "@opentelemetry/resources": + '@opentelemetry/resources': optional: true - "@opentelemetry/sdk-trace-base": + '@opentelemetry/sdk-trace-base': optional: true - "@opentelemetry/semantic-conventions": + '@opentelemetry/semantic-conventions': optional: true - "@sentry/node@10.42.0": - resolution: - { - integrity: sha512-ZZfU3Fnni7Aj0lTX4e3QpY3UxK4FGuzfM20316UAJycBGnripm+sDHwcekPMGfLnk/FrN9wa1atspVlHvOI0WQ==, - } - engines: { node: ">=18" } - - "@sentry/node@10.44.0": - resolution: - { - integrity: sha512-q+/WR9ZeF9Af8uyehOj2tQQOa7LH07mJfOuDus5X6G6cLuugdRUGUBB5Qhw+J/ULSxbzGADBZv6AYOyoGaNx7w==, - } - engines: { node: ">=18" } - - "@sentry/opentelemetry@10.42.0": - resolution: - { - integrity: sha512-5vsYz683iihzlIj3sT1+tEixf0awwXK86a+aYsnMHrTXJDrkBDq4U0ZT+yxdPfJlkaxRtYycFR08SXr2pSm7Eg==, - } - engines: { node: ">=18" } + '@sentry/node@10.42.0': + resolution: {integrity: sha512-ZZfU3Fnni7Aj0lTX4e3QpY3UxK4FGuzfM20316UAJycBGnripm+sDHwcekPMGfLnk/FrN9wa1atspVlHvOI0WQ==} + engines: {node: '>=18'} + + '@sentry/node@10.44.0': + resolution: {integrity: sha512-q+/WR9ZeF9Af8uyehOj2tQQOa7LH07mJfOuDus5X6G6cLuugdRUGUBB5Qhw+J/ULSxbzGADBZv6AYOyoGaNx7w==} + engines: {node: '>=18'} + + '@sentry/opentelemetry@10.42.0': + resolution: {integrity: sha512-5vsYz683iihzlIj3sT1+tEixf0awwXK86a+aYsnMHrTXJDrkBDq4U0ZT+yxdPfJlkaxRtYycFR08SXr2pSm7Eg==} + engines: {node: '>=18'} peerDependencies: - "@opentelemetry/api": ^1.9.0 - "@opentelemetry/context-async-hooks": ^1.30.1 || ^2.1.0 - "@opentelemetry/core": ^1.30.1 || ^2.1.0 - "@opentelemetry/sdk-trace-base": ^1.30.1 || ^2.1.0 - "@opentelemetry/semantic-conventions": ^1.39.0 - - "@sentry/opentelemetry@10.44.0": - resolution: - { - integrity: sha512-zP4vP8tBxjlmxQ4VcWOwZ0b3lPUxlYPg9FqJwANm9SRJN+7V5psm8TIaAtu9uqtIcJMRHdXkOM4cAggNiLk0KA==, - } - engines: { node: ">=18" } + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 + '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + '@opentelemetry/semantic-conventions': ^1.39.0 + + '@sentry/opentelemetry@10.44.0': + resolution: {integrity: sha512-zP4vP8tBxjlmxQ4VcWOwZ0b3lPUxlYPg9FqJwANm9SRJN+7V5psm8TIaAtu9uqtIcJMRHdXkOM4cAggNiLk0KA==} + engines: {node: '>=18'} peerDependencies: - "@opentelemetry/api": ^1.9.0 - "@opentelemetry/context-async-hooks": ^1.30.1 || ^2.1.0 - "@opentelemetry/core": ^1.30.1 || ^2.1.0 - "@opentelemetry/sdk-trace-base": ^1.30.1 || ^2.1.0 - "@opentelemetry/semantic-conventions": ^1.39.0 - - "@sentry/react@10.42.0": - resolution: - { - integrity: sha512-uigyz6E3yPjjqIZpkGzRChww6gzMmqdCpK30M5aBYoaen29DDmSECHYA16sfgXeSwzQhnXyX7GxgOB+eKIr9dw==, - } - engines: { node: ">=18" } + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 + '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + '@opentelemetry/semantic-conventions': ^1.39.0 + + '@sentry/react@10.42.0': + resolution: {integrity: sha512-uigyz6E3yPjjqIZpkGzRChww6gzMmqdCpK30M5aBYoaen29DDmSECHYA16sfgXeSwzQhnXyX7GxgOB+eKIr9dw==} + engines: {node: '>=18'} peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - "@sentry/react@10.44.0": - resolution: - { - integrity: sha512-blaYoLk/UgFZXj9ieKZeY1JIiqzeL2VegQt22S9IQk8gHpunDZux5XC4CdcPdavcVusddaB/SmHAmhy2RCBdPQ==, - } - engines: { node: ">=18" } - peerDependencies: - react: ^16.14.0 || 17.x || 18.x || 19.x + '@sentry/react@10.44.0': + resolution: {integrity: sha512-blaYoLk/UgFZXj9ieKZeY1JIiqzeL2VegQt22S9IQk8gHpunDZux5XC4CdcPdavcVusddaB/SmHAmhy2RCBdPQ==} + engines: {node: '>=18'} + peerDependencies: + react: ^16.14.0 || 17.x || 18.x || 19.x + + '@sentry/vercel-edge@10.42.0': + resolution: {integrity: sha512-BjK5P5qBBC1biAErKlDICiXaer7FnqAL7NcBCD0pHK7aLO5IAzyegfA0zcu4fIo8TIqipLJiCOGmkYaiSALq8g==} + engines: {node: '>=18'} + + '@sentry/vercel-edge@10.44.0': + resolution: {integrity: sha512-Xk+bP5HFkzR4OzL3r6NTBt7PVk3HOp7PIyCIgk9pKUFg7720TTSeXw7/O14X+sOrokEqrTq7RpjNCG6ipUOrlw==} + engines: {node: '>=18'} + + '@sentry/webpack-plugin@5.1.1': + resolution: {integrity: sha512-XgQg+t2aVrlQDfIiAEizqR/bsy6GtBygwgR+Kw11P/cYczj4W9PZ2IYqQEStBzHqnRTh5DbpyMcUNW2CujdA9A==} + engines: {node: '>= 18'} + peerDependencies: + webpack: '>=5.0.0' + + '@shikijs/core@3.23.0': + resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} + + '@shikijs/engine-javascript@3.23.0': + resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} + + '@shikijs/engine-oniguruma@3.23.0': + resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} + + '@shikijs/langs@3.23.0': + resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} + + '@shikijs/themes@3.23.0': + resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + + '@shikijs/types@3.23.0': + resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@sinclair/typebox@0.25.24': + resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} + + '@sinclair/typebox@0.34.48': + resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} + + '@slack/logger@4.0.1': + resolution: {integrity: sha512-6cmdPrV/RYfd2U0mDGiMK8S7OJqpCTm7enMLRR3edccsPX8j7zXTLnaEF4fhxxJJTAIOil6+qZrnUPTuaLvwrQ==} + engines: {node: '>= 18', npm: '>= 8.6.0'} + + '@slack/types@2.20.1': + resolution: {integrity: sha512-eWX2mdt1ktpn8+40iiMc404uGrih+2fxiky3zBcPjtXKj6HLRdYlmhrPkJi7JTJm8dpXR6BWVWEDBXtaWMKD6A==} + engines: {node: '>= 12.13.0', npm: '>= 6.12.0'} + + '@slack/web-api@7.15.0': + resolution: {integrity: sha512-va7zYIt3QHG1x9M/jqXXRPFMoOVlVSSRHC5YH+DzKYsrz5xUKOA3lR4THsu/Zxha9N1jOndbKFKLtr0WOPW1Vw==} + engines: {node: '>= 18', npm: '>= 8.6.0'} + + '@smithy/abort-controller@4.2.11': + resolution: {integrity: sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ==} + engines: {node: '>=18.0.0'} + + '@smithy/config-resolver@4.4.10': + resolution: {integrity: sha512-IRTkd6ps0ru+lTWnfnsbXzW80A8Od8p3pYiZnW98K2Hb20rqfsX7VTlfUwhrcOeSSy68Gn9WBofwPuw3e5CCsg==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.23.9': + resolution: {integrity: sha512-1Vcut4LEL9HZsdpI0vFiRYIsaoPwZLjAxnVQDUMQK8beMS+EYPLDQCXtbzfxmM5GzSgjfe2Q9M7WaXwIMQllyQ==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.2.11': + resolution: {integrity: sha512-lBXrS6ku0kTj3xLmsJW0WwqWbGQ6ueooYyp/1L9lkyT0M02C+DWwYwc5aTyXFbRaK38ojALxNixg+LxKSHZc0g==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-codec@4.2.11': + resolution: {integrity: sha512-Sf39Ml0iVX+ba/bgMPxaXWAAFmHqYLTmbjAPfLPLY8CrYkRDEqZdUsKC1OwVMCdJXfAt0v4j49GIJ8DoSYAe6w==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-browser@4.2.11': + resolution: {integrity: sha512-3rEpo3G6f/nRS7fQDsZmxw/ius6rnlIpz4UX6FlALEzz8JoSxFmdBt0SZnthis+km7sQo6q5/3e+UJcuQivoXA==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-config-resolver@4.3.11': + resolution: {integrity: sha512-XeNIA8tcP/GDWnnKkO7qEm/bg0B/bP9lvIXZBXcGZwZ+VYM8h8k9wuDvUODtdQ2Wcp2RcBkPTCSMmaniVHrMlA==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-node@4.2.11': + resolution: {integrity: sha512-fzbCh18rscBDTQSCrsp1fGcclLNF//nJyhjldsEl/5wCYmgpHblv5JSppQAyQI24lClsFT0wV06N1Porn0IsEw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-universal@4.2.11': + resolution: {integrity: sha512-MJ7HcI+jEkqoWT5vp+uoVaAjBrmxBtKhZTeynDRG/seEjJfqyg3SiqMMqyPnAMzmIfLaeJ/uiuSDP/l9AnMy/Q==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.3.13': + resolution: {integrity: sha512-U2Hcfl2s3XaYjikN9cT4mPu8ybDbImV3baXR0PkVlC0TTx808bRP3FaPGAzPtB8OByI+JqJ1kyS+7GEgae7+qQ==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.2.11': + resolution: {integrity: sha512-T+p1pNynRkydpdL015ruIoyPSRw9e/SQOWmSAMmmprfswMrd5Ow5igOWNVlvyVFZlxXqGmyH3NQwfwy8r5Jx0A==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.2.11': + resolution: {integrity: sha512-cGNMrgykRmddrNhYy1yBdrp5GwIgEkniS7k9O1VLB38yxQtlvrxpZtUVvo6T4cKpeZsriukBuuxfJcdZQc/f/g==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.2.2': + resolution: {integrity: sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.2.11': + resolution: {integrity: sha512-UvIfKYAKhCzr4p6jFevPlKhQwyQwlJ6IeKLDhmV1PlYfcW3RL4ROjNEDtSik4NYMi9kDkH7eSwyTP3vNJ/u/Dw==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.4.23': + resolution: {integrity: sha512-UEFIejZy54T1EJn2aWJ45voB7RP2T+IRzUqocIdM6GFFa5ClZncakYJfcYnoXt3UsQrZZ9ZRauGm77l9UCbBLw==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.4.40': + resolution: {integrity: sha512-YhEMakG1Ae57FajERdHNZ4ShOPIY7DsgV+ZoAxo/5BT0KIe+f6DDU2rtIymNNFIj22NJfeeI6LWIifrwM0f+rA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.2.12': + resolution: {integrity: sha512-W9g1bOLui7Xn5FABRVS0o3rXL0gfN37d/8I/W7i0N7oxjx9QecUmXEMSUMADTODwdtka9cN43t5BI2CodLJpng==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.2.11': + resolution: {integrity: sha512-s+eenEPW6RgliDk2IhjD2hWOxIx1NKrOHxEwNUaUXxYBxIyCcDfNULZ2Mu15E3kwcJWBedTET/kEASPV1A1Akg==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.3.11': + resolution: {integrity: sha512-xD17eE7kaLgBBGf5CZQ58hh2YmwK1Z0O8YhffwB/De2jsL0U3JklmhVYJ9Uf37OtUDLF2gsW40Xwwag9U869Gg==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.4.14': + resolution: {integrity: sha512-DamSqaU8nuk0xTJDrYnRzZndHwwRnyj/n/+RqGGCcBKB4qrQem0mSDiWdupaNWdwxzyMU91qxDmHOCazfhtO3A==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.2.11': + resolution: {integrity: sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.3.11': + resolution: {integrity: sha512-hI+barOVDJBkNt4y0L2mu3Ugc0w7+BpJ2CZuLwXtSltGAAwCb3IvnalGlbDV/UCS6a9ZuT3+exd1WxNdLb5IlQ==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.2.11': + resolution: {integrity: sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.2.11': + resolution: {integrity: sha512-nE3IRNjDltvGcoThD2abTozI1dkSy8aX+a2N1Rs55en5UsdyyIXgGEmevUL3okZFoJC77JgRGe99xYohhsjivQ==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.2.11': + resolution: {integrity: sha512-HkMFJZJUhzU3HvND1+Yw/kYWXp4RPDLBWLcK1n+Vqw8xn4y2YiBhdww8IxhkQjP/QlZun5bwm3vcHc8AqIU3zw==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.4.6': + resolution: {integrity: sha512-IB/M5I8G0EeXZTHsAxpx51tMQ5R719F3aq+fjEB6VtNcCHDc0ajFDIGDZw+FW9GxtEkgTduiPpjveJdA/CX7sw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.3.11': + resolution: {integrity: sha512-V1L6N9aKOBAN4wEHLyqjLBnAz13mtILU0SeDrjOaIZEeN6IFa6DxwRt1NNpOdmSpQUfkBj0qeD3m6P77uzMhgQ==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.12.3': + resolution: {integrity: sha512-7k4UxjSpHmPN2AxVhvIazRSzFQjWnud3sOsXcFStzagww17j1cFQYqTSiQ8xuYK3vKLR1Ni8FzuT3VlKr3xCNw==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.13.0': + resolution: {integrity: sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.2.11': + resolution: {integrity: sha512-oTAGGHo8ZYc5VZsBREzuf5lf2pAurJQsccMusVZ85wDkX66ojEc/XauiGjzCj50A61ObFTPe6d7Pyt6UBYaing==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.3.2': + resolution: {integrity: sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.2.2': + resolution: {integrity: sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.2.3': + resolution: {integrity: sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.2.2': + resolution: {integrity: sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.2.2': + resolution: {integrity: sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.3.39': + resolution: {integrity: sha512-ui7/Ho/+VHqS7Km2wBw4/Ab4RktoiSshgcgpJzC4keFPs6tLJS4IQwbeahxQS3E/w98uq6E1mirCH/id9xIXeQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.2.42': + resolution: {integrity: sha512-QDA84CWNe8Akpj15ofLO+1N3Rfg8qa2K5uX0y6HnOp4AnRYRgWrKx/xzbYNbVF9ZsyJUYOfcoaN3y93wA/QJ2A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.3.2': + resolution: {integrity: sha512-+4HFLpE5u29AbFlTdlKIT7jfOzZ8PDYZKTb3e+AgLz986OYwqTourQ5H+jg79/66DB69Un1+qKecLnkZdAsYcA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.2.2': + resolution: {integrity: sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.2.11': + resolution: {integrity: sha512-r3dtF9F+TpSZUxpOVVtPfk09Rlo4lT6ORBqEvX3IBT6SkQAdDSVKR5GcfmZbtl7WKhKnmb3wbDTQ6ibR2XHClw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.2.11': + resolution: {integrity: sha512-XSZULmL5x6aCTTii59wJqKsY1l3eMIAomRAccW7Tzh9r8s7T/7rdo03oektuH5jeYRlJMPcNP92EuRDvk9aXbw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.5.17': + resolution: {integrity: sha512-793BYZ4h2JAQkNHcEnyFxDTcZbm9bVybD0UV/LEWmZ5bkTms7JqjfrLMi2Qy0E5WFcCzLwCAPgcvcvxoeALbAQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.2.2': + resolution: {integrity: sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.2.2': + resolution: {integrity: sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==} + engines: {node: '>=18.0.0'} + + '@smithy/uuid@1.1.2': + resolution: {integrity: sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==} + engines: {node: '>=18.0.0'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/core-darwin-arm64@1.15.3': + resolution: {integrity: sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.15.3': + resolution: {integrity: sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.15.3': + resolution: {integrity: sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.15.3': + resolution: {integrity: sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-arm64-musl@1.15.3': + resolution: {integrity: sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@swc/core-linux-x64-gnu@1.15.3': + resolution: {integrity: sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-musl@1.15.3': + resolution: {integrity: sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@swc/core-win32-arm64-msvc@1.15.3': + resolution: {integrity: sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.15.3': + resolution: {integrity: sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.15.3': + resolution: {integrity: sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.15.3': + resolution: {integrity: sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@swc/types@0.1.25': + resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} + + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tootallnate/once@2.0.0': + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + + '@ts-morph/common@0.11.1': + resolution: {integrity: sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/js-yaml@4.0.9': + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdx@2.0.13': + resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/mysql@2.15.27': + resolution: {integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==} + + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + + '@types/node@17.0.45': + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + + '@types/node@20.11.0': + resolution: {integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==} + + '@types/node@20.19.37': + resolution: {integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==} + + '@types/node@25.3.5': + resolution: {integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==} + + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + + '@types/pg-pool@2.0.7': + resolution: {integrity: sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng==} + + '@types/pg@8.15.6': + resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + + '@types/sax@1.2.7': + resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + + '@types/sinonjs__fake-timers@8.1.5': + resolution: {integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==} + + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + + '@types/tedious@4.0.14': + resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/which@2.0.2': + resolution: {integrity: sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@vercel/backends@0.0.45': + resolution: {integrity: sha512-KIdt/z4LfH7NgFMqgSuKi0H9UIasly7ByzP+/ZXulgNrWyeJKT9KCas3SDT65o5tU6x1D/jBysZA9AnOt8Ivew==} + peerDependencies: + typescript: ^4.0.0 || ^5.0.0 + + '@vercel/blob@2.3.0': + resolution: {integrity: sha512-oYWiJbWRQ7gz9Mj0X/NHFJ3OcLMOBzq/2b3j6zeNrQmtFo6dHwU8FAwNpxVIYddVMd+g8eqEi7iRueYx8FtM0Q==} + engines: {node: '>=20.0.0'} + + '@vercel/build-utils@13.8.0': + resolution: {integrity: sha512-moQS4Qd0pvluPd6WRTHxLN3Hh0oSObVNdFv3V0spiEmCk/wm6571up3n1th2PQFqf1a3gheNfxzL7h4I9CWs2A==} + + '@vercel/cervel@0.0.32': + resolution: {integrity: sha512-g/LIa97d/m3yIZGyBjwl4FOQK1Lg5HU2+N3uHiGVajLoSgJM2aBiwETDZc8bVCr8IO3IqXZQsT2hGy1Jnyko1g==} + hasBin: true + peerDependencies: + typescript: ^4.0.0 || ^5.0.0 + + '@vercel/detect-agent@1.2.1': + resolution: {integrity: sha512-U/BJCltQSTFTHwaiCQQTQG3GonTbRoEewjV+OU2mMjcHLAoPOh6CP1SXA2XNmqiqI3c82nkRNJ7piZ14RqmTXw==} + engines: {node: '>=14'} + + '@vercel/elysia@0.1.48': + resolution: {integrity: sha512-QlmOHUSOx/uE67Y6u/o8VbNF7ebZ8SZFbrEoBo7iZAd0MC2Vn4xUmlrHFXNR/FEkHFXWkhFKda5Ade3XMqMY8A==} + + '@vercel/error-utils@2.0.3': + resolution: {integrity: sha512-CqC01WZxbLUxoiVdh9B/poPbNpY9U+tO1N9oWHwTl5YAZxcqXmmWJ8KNMFItJCUUWdY3J3xv8LvAuQv2KZ5YdQ==} + + '@vercel/express@0.1.57': + resolution: {integrity: sha512-/Ih1eiJrBGSW6JPzexB8y8AMX/8MzuDUf0xzmpYbKLCbehp3NNuxde5RxT+6cALglFivDETsJBCFwaFuIh3ZqQ==} + + '@vercel/fastify@0.1.51': + resolution: {integrity: sha512-c9CwFQqmoUm5eEGwAcqb98DcxsRmSZGngCAo1B+nlDhaACKcrJ7Ro0tYdTDhi8Lkt+OcPnRWr4+pepgWwH94GQ==} + + '@vercel/fun@1.3.0': + resolution: {integrity: sha512-8erw9uPe0dFg45THkNxmjtvMX143SkZebmjgSVbcM3XCkXu3RIiBaJMcMNG8aaS+rnTuw8+d4De9HVT0M/r3wg==} + engines: {node: '>= 18'} + + '@vercel/gatsby-plugin-vercel-analytics@1.0.11': + resolution: {integrity: sha512-iTEA0vY6RBPuEzkwUTVzSHDATo1aF6bdLLspI68mQ/BTbi5UQEGjpjyzdKOVcSYApDtFU6M6vypZ1t4vIEnHvw==} + + '@vercel/gatsby-plugin-vercel-builder@2.1.0': + resolution: {integrity: sha512-avJ5IFev2h2K6E/Pd7qd00cFLALj3OyEmQE3UoGs1dmoncINFqa1RoIZDJ9wIhWm1Euan4wrFMRsXkCwNhEGhw==} + + '@vercel/go@3.4.5': + resolution: {integrity: sha512-eTWsdXawkSsG5TP+1BJUo+wRnoG9uH51MRID0YlwMMvollG5q7CrYisg859koy8MzGjQAcu3ff5v/WwRbwXwgQ==} + + '@vercel/h3@0.1.57': + resolution: {integrity: sha512-I7Q1ity7xEdIVw4OQuKOAR8i6DrvfjpKy+y2uTwbqBD80Gg0KpsMS/KKA+UjvCuclFmP/EHYS3kpMLc/O1rVqg==} + + '@vercel/hono@0.2.51': + resolution: {integrity: sha512-iYEjjF4qR3gTZpVoB4sMQNm5OOdKw5/P2bL1CtolDTeGaea9KwqUrLyXmdK4N41HIRZr/wduID31mmHhSdC3sA==} + + '@vercel/hydrogen@1.3.6': + resolution: {integrity: sha512-Ec8dKEjGIM4BfThcRLtQs5zaJ4+iJbgLZwkytwi7Blk8VrK6W2F1dtLDmVQYZdVnQcnmHmTx8mxUuMkfP06Mnw==} + + '@vercel/koa@0.1.31': + resolution: {integrity: sha512-Gj4sjqNA80/gnHpC0tRPCTtVEct69tUK21fsjVmawCa+nDNQ4bqXu3dSewna7GtCcp9KnrWgzAIaeVAQUl53mQ==} + + '@vercel/nestjs@0.2.52': + resolution: {integrity: sha512-yfy4rpWJ1BRWZ1xBBPew0egVIblFe6G7laCKDzyESnbw19zY0F16g9HCu1H/0IfuKIQvOc95dtbmBsqLm9jyqw==} + + '@vercel/next@4.16.1': + resolution: {integrity: sha512-gwy3XQRZ/f6RdKuC7BZIRMAzUOQf/R5+k9LMf1LcOm1CVZOLpDhDkeZMTG5vb3Lk9LWwBrJJ2ohhZaYuYEOHaw==} + + '@vercel/nft@1.1.1': + resolution: {integrity: sha512-mKMGa7CEUcXU75474kOeqHbtvK1kAcu4wiahhmlUenB5JbTQB8wVlDI8CyHR3rpGo0qlzoRWqcDzI41FUoBJCA==} + engines: {node: '>=20'} + hasBin: true - "@sentry/vercel-edge@10.42.0": - resolution: - { - integrity: sha512-BjK5P5qBBC1biAErKlDICiXaer7FnqAL7NcBCD0pHK7aLO5IAzyegfA0zcu4fIo8TIqipLJiCOGmkYaiSALq8g==, - } - engines: { node: ">=18" } - - "@sentry/vercel-edge@10.44.0": - resolution: - { - integrity: sha512-Xk+bP5HFkzR4OzL3r6NTBt7PVk3HOp7PIyCIgk9pKUFg7720TTSeXw7/O14X+sOrokEqrTq7RpjNCG6ipUOrlw==, - } - engines: { node: ">=18" } - - "@sentry/webpack-plugin@5.1.1": - resolution: - { - integrity: sha512-XgQg+t2aVrlQDfIiAEizqR/bsy6GtBygwgR+Kw11P/cYczj4W9PZ2IYqQEStBzHqnRTh5DbpyMcUNW2CujdA9A==, - } - engines: { node: ">= 18" } - peerDependencies: - webpack: ">=5.0.0" - - "@shikijs/core@3.23.0": - resolution: - { - integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==, - } - - "@shikijs/engine-javascript@3.23.0": - resolution: - { - integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==, - } - - "@shikijs/engine-oniguruma@3.23.0": - resolution: - { - integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==, - } - - "@shikijs/langs@3.23.0": - resolution: - { - integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==, - } - - "@shikijs/themes@3.23.0": - resolution: - { - integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==, - } - - "@shikijs/types@3.23.0": - resolution: - { - integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==, - } - - "@shikijs/vscode-textmate@10.0.2": - resolution: - { - integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==, - } - - "@sinclair/typebox@0.25.24": - resolution: - { - integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==, - } - - "@sinclair/typebox@0.34.48": - resolution: - { - integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==, - } - - "@slack/logger@4.0.1": - resolution: - { - integrity: sha512-6cmdPrV/RYfd2U0mDGiMK8S7OJqpCTm7enMLRR3edccsPX8j7zXTLnaEF4fhxxJJTAIOil6+qZrnUPTuaLvwrQ==, - } - engines: { node: ">= 18", npm: ">= 8.6.0" } - - "@slack/types@2.20.1": - resolution: - { - integrity: sha512-eWX2mdt1ktpn8+40iiMc404uGrih+2fxiky3zBcPjtXKj6HLRdYlmhrPkJi7JTJm8dpXR6BWVWEDBXtaWMKD6A==, - } - engines: { node: ">= 12.13.0", npm: ">= 6.12.0" } - - "@slack/web-api@7.15.0": - resolution: - { - integrity: sha512-va7zYIt3QHG1x9M/jqXXRPFMoOVlVSSRHC5YH+DzKYsrz5xUKOA3lR4THsu/Zxha9N1jOndbKFKLtr0WOPW1Vw==, - } - engines: { node: ">= 18", npm: ">= 8.6.0" } - - "@smithy/abort-controller@4.2.11": - resolution: - { - integrity: sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/config-resolver@4.4.10": - resolution: - { - integrity: sha512-IRTkd6ps0ru+lTWnfnsbXzW80A8Od8p3pYiZnW98K2Hb20rqfsX7VTlfUwhrcOeSSy68Gn9WBofwPuw3e5CCsg==, - } - engines: { node: ">=18.0.0" } - - "@smithy/core@3.23.9": - resolution: - { - integrity: sha512-1Vcut4LEL9HZsdpI0vFiRYIsaoPwZLjAxnVQDUMQK8beMS+EYPLDQCXtbzfxmM5GzSgjfe2Q9M7WaXwIMQllyQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/credential-provider-imds@4.2.11": - resolution: - { - integrity: sha512-lBXrS6ku0kTj3xLmsJW0WwqWbGQ6ueooYyp/1L9lkyT0M02C+DWwYwc5aTyXFbRaK38ojALxNixg+LxKSHZc0g==, - } - engines: { node: ">=18.0.0" } - - "@smithy/eventstream-codec@4.2.11": - resolution: - { - integrity: sha512-Sf39Ml0iVX+ba/bgMPxaXWAAFmHqYLTmbjAPfLPLY8CrYkRDEqZdUsKC1OwVMCdJXfAt0v4j49GIJ8DoSYAe6w==, - } - engines: { node: ">=18.0.0" } - - "@smithy/eventstream-serde-browser@4.2.11": - resolution: - { - integrity: sha512-3rEpo3G6f/nRS7fQDsZmxw/ius6rnlIpz4UX6FlALEzz8JoSxFmdBt0SZnthis+km7sQo6q5/3e+UJcuQivoXA==, - } - engines: { node: ">=18.0.0" } - - "@smithy/eventstream-serde-config-resolver@4.3.11": - resolution: - { - integrity: sha512-XeNIA8tcP/GDWnnKkO7qEm/bg0B/bP9lvIXZBXcGZwZ+VYM8h8k9wuDvUODtdQ2Wcp2RcBkPTCSMmaniVHrMlA==, - } - engines: { node: ">=18.0.0" } - - "@smithy/eventstream-serde-node@4.2.11": - resolution: - { - integrity: sha512-fzbCh18rscBDTQSCrsp1fGcclLNF//nJyhjldsEl/5wCYmgpHblv5JSppQAyQI24lClsFT0wV06N1Porn0IsEw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/eventstream-serde-universal@4.2.11": - resolution: - { - integrity: sha512-MJ7HcI+jEkqoWT5vp+uoVaAjBrmxBtKhZTeynDRG/seEjJfqyg3SiqMMqyPnAMzmIfLaeJ/uiuSDP/l9AnMy/Q==, - } - engines: { node: ">=18.0.0" } - - "@smithy/fetch-http-handler@5.3.13": - resolution: - { - integrity: sha512-U2Hcfl2s3XaYjikN9cT4mPu8ybDbImV3baXR0PkVlC0TTx808bRP3FaPGAzPtB8OByI+JqJ1kyS+7GEgae7+qQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/hash-node@4.2.11": - resolution: - { - integrity: sha512-T+p1pNynRkydpdL015ruIoyPSRw9e/SQOWmSAMmmprfswMrd5Ow5igOWNVlvyVFZlxXqGmyH3NQwfwy8r5Jx0A==, - } - engines: { node: ">=18.0.0" } - - "@smithy/invalid-dependency@4.2.11": - resolution: - { - integrity: sha512-cGNMrgykRmddrNhYy1yBdrp5GwIgEkniS7k9O1VLB38yxQtlvrxpZtUVvo6T4cKpeZsriukBuuxfJcdZQc/f/g==, - } - engines: { node: ">=18.0.0" } - - "@smithy/is-array-buffer@2.2.0": - resolution: - { - integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==, - } - engines: { node: ">=14.0.0" } - - "@smithy/is-array-buffer@4.2.2": - resolution: - { - integrity: sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==, - } - engines: { node: ">=18.0.0" } - - "@smithy/middleware-content-length@4.2.11": - resolution: - { - integrity: sha512-UvIfKYAKhCzr4p6jFevPlKhQwyQwlJ6IeKLDhmV1PlYfcW3RL4ROjNEDtSik4NYMi9kDkH7eSwyTP3vNJ/u/Dw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/middleware-endpoint@4.4.23": - resolution: - { - integrity: sha512-UEFIejZy54T1EJn2aWJ45voB7RP2T+IRzUqocIdM6GFFa5ClZncakYJfcYnoXt3UsQrZZ9ZRauGm77l9UCbBLw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/middleware-retry@4.4.40": - resolution: - { - integrity: sha512-YhEMakG1Ae57FajERdHNZ4ShOPIY7DsgV+ZoAxo/5BT0KIe+f6DDU2rtIymNNFIj22NJfeeI6LWIifrwM0f+rA==, - } - engines: { node: ">=18.0.0" } - - "@smithy/middleware-serde@4.2.12": - resolution: - { - integrity: sha512-W9g1bOLui7Xn5FABRVS0o3rXL0gfN37d/8I/W7i0N7oxjx9QecUmXEMSUMADTODwdtka9cN43t5BI2CodLJpng==, - } - engines: { node: ">=18.0.0" } - - "@smithy/middleware-stack@4.2.11": - resolution: - { - integrity: sha512-s+eenEPW6RgliDk2IhjD2hWOxIx1NKrOHxEwNUaUXxYBxIyCcDfNULZ2Mu15E3kwcJWBedTET/kEASPV1A1Akg==, - } - engines: { node: ">=18.0.0" } - - "@smithy/node-config-provider@4.3.11": - resolution: - { - integrity: sha512-xD17eE7kaLgBBGf5CZQ58hh2YmwK1Z0O8YhffwB/De2jsL0U3JklmhVYJ9Uf37OtUDLF2gsW40Xwwag9U869Gg==, - } - engines: { node: ">=18.0.0" } - - "@smithy/node-http-handler@4.4.14": - resolution: - { - integrity: sha512-DamSqaU8nuk0xTJDrYnRzZndHwwRnyj/n/+RqGGCcBKB4qrQem0mSDiWdupaNWdwxzyMU91qxDmHOCazfhtO3A==, - } - engines: { node: ">=18.0.0" } - - "@smithy/property-provider@4.2.11": - resolution: - { - integrity: sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg==, - } - engines: { node: ">=18.0.0" } - - "@smithy/protocol-http@5.3.11": - resolution: - { - integrity: sha512-hI+barOVDJBkNt4y0L2mu3Ugc0w7+BpJ2CZuLwXtSltGAAwCb3IvnalGlbDV/UCS6a9ZuT3+exd1WxNdLb5IlQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/querystring-builder@4.2.11": - resolution: - { - integrity: sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA==, - } - engines: { node: ">=18.0.0" } - - "@smithy/querystring-parser@4.2.11": - resolution: - { - integrity: sha512-nE3IRNjDltvGcoThD2abTozI1dkSy8aX+a2N1Rs55en5UsdyyIXgGEmevUL3okZFoJC77JgRGe99xYohhsjivQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/service-error-classification@4.2.11": - resolution: - { - integrity: sha512-HkMFJZJUhzU3HvND1+Yw/kYWXp4RPDLBWLcK1n+Vqw8xn4y2YiBhdww8IxhkQjP/QlZun5bwm3vcHc8AqIU3zw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/shared-ini-file-loader@4.4.6": - resolution: - { - integrity: sha512-IB/M5I8G0EeXZTHsAxpx51tMQ5R719F3aq+fjEB6VtNcCHDc0ajFDIGDZw+FW9GxtEkgTduiPpjveJdA/CX7sw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/signature-v4@5.3.11": - resolution: - { - integrity: sha512-V1L6N9aKOBAN4wEHLyqjLBnAz13mtILU0SeDrjOaIZEeN6IFa6DxwRt1NNpOdmSpQUfkBj0qeD3m6P77uzMhgQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/smithy-client@4.12.3": - resolution: - { - integrity: sha512-7k4UxjSpHmPN2AxVhvIazRSzFQjWnud3sOsXcFStzagww17j1cFQYqTSiQ8xuYK3vKLR1Ni8FzuT3VlKr3xCNw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/types@4.13.0": - resolution: - { - integrity: sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/url-parser@4.2.11": - resolution: - { - integrity: sha512-oTAGGHo8ZYc5VZsBREzuf5lf2pAurJQsccMusVZ85wDkX66ojEc/XauiGjzCj50A61ObFTPe6d7Pyt6UBYaing==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-base64@4.3.2": - resolution: - { - integrity: sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-body-length-browser@4.2.2": - resolution: - { - integrity: sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-body-length-node@4.2.3": - resolution: - { - integrity: sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-buffer-from@2.2.0": - resolution: - { - integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==, - } - engines: { node: ">=14.0.0" } - - "@smithy/util-buffer-from@4.2.2": - resolution: - { - integrity: sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-config-provider@4.2.2": - resolution: - { - integrity: sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-defaults-mode-browser@4.3.39": - resolution: - { - integrity: sha512-ui7/Ho/+VHqS7Km2wBw4/Ab4RktoiSshgcgpJzC4keFPs6tLJS4IQwbeahxQS3E/w98uq6E1mirCH/id9xIXeQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-defaults-mode-node@4.2.42": - resolution: - { - integrity: sha512-QDA84CWNe8Akpj15ofLO+1N3Rfg8qa2K5uX0y6HnOp4AnRYRgWrKx/xzbYNbVF9ZsyJUYOfcoaN3y93wA/QJ2A==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-endpoints@3.3.2": - resolution: - { - integrity: sha512-+4HFLpE5u29AbFlTdlKIT7jfOzZ8PDYZKTb3e+AgLz986OYwqTourQ5H+jg79/66DB69Un1+qKecLnkZdAsYcA==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-hex-encoding@4.2.2": - resolution: - { - integrity: sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-middleware@4.2.11": - resolution: - { - integrity: sha512-r3dtF9F+TpSZUxpOVVtPfk09Rlo4lT6ORBqEvX3IBT6SkQAdDSVKR5GcfmZbtl7WKhKnmb3wbDTQ6ibR2XHClw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-retry@4.2.11": - resolution: - { - integrity: sha512-XSZULmL5x6aCTTii59wJqKsY1l3eMIAomRAccW7Tzh9r8s7T/7rdo03oektuH5jeYRlJMPcNP92EuRDvk9aXbw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-stream@4.5.17": - resolution: - { - integrity: sha512-793BYZ4h2JAQkNHcEnyFxDTcZbm9bVybD0UV/LEWmZ5bkTms7JqjfrLMi2Qy0E5WFcCzLwCAPgcvcvxoeALbAQ==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-uri-escape@4.2.2": - resolution: - { - integrity: sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/util-utf8@2.3.0": - resolution: - { - integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==, - } - engines: { node: ">=14.0.0" } - - "@smithy/util-utf8@4.2.2": - resolution: - { - integrity: sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==, - } - engines: { node: ">=18.0.0" } - - "@smithy/uuid@1.1.2": - resolution: - { - integrity: sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==, - } - engines: { node: ">=18.0.0" } - - "@standard-schema/spec@1.1.0": - resolution: - { - integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==, - } - - "@swc/core-darwin-arm64@1.15.3": - resolution: - { - integrity: sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ==, - } - engines: { node: ">=10" } - cpu: [arm64] - os: [darwin] + '@vercel/nft@1.3.0': + resolution: {integrity: sha512-i4EYGkCsIjzu4vorDUbqglZc5eFtQI2syHb++9ZUDm6TU4edVywGpVnYDein35x9sevONOn9/UabfQXuNXtuzQ==} + engines: {node: '>=20'} + hasBin: true - "@swc/core-darwin-x64@1.15.3": - resolution: - { - integrity: sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A==, - } - engines: { node: ">=10" } - cpu: [x64] - os: [darwin] + '@vercel/node@5.6.15': + resolution: {integrity: sha512-xc5fxmdk8jtuUY8y9/8W5UhTn8R1Ii1Fb3q+V8Zv+2moU9enrrBADA9ercHgE0/DtoiNDpb9Wmvnrb4bUcFOzA==} - "@swc/core-linux-arm-gnueabihf@1.15.3": - resolution: - { - integrity: sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg==, - } - engines: { node: ">=10" } - cpu: [arm] - os: [linux] + '@vercel/oidc@3.1.0': + resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} + engines: {node: '>= 20'} - "@swc/core-linux-arm64-gnu@1.15.3": - resolution: - { - integrity: sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw==, - } - engines: { node: ">=10" } - cpu: [arm64] - os: [linux] - libc: [glibc] + '@vercel/oidc@3.2.0': + resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} + engines: {node: '>= 20'} - "@swc/core-linux-arm64-musl@1.15.3": - resolution: - { - integrity: sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g==, - } - engines: { node: ">=10" } - cpu: [arm64] - os: [linux] - libc: [musl] + '@vercel/python-analysis@0.9.1': + resolution: {integrity: sha512-ZwEi/F2DPxFPYmfjHFy7qM3+JTWRxD1EMpbIotNNhUyd/pnIG0wNt7S73RJSx62n1Y7pmFOFowoImnhULQgKvA==} - "@swc/core-linux-x64-gnu@1.15.3": - resolution: - { - integrity: sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A==, - } - engines: { node: ">=10" } - cpu: [x64] - os: [linux] - libc: [glibc] + '@vercel/python@6.23.0': + resolution: {integrity: sha512-P4cwbfk1zaVfX6obR3h+tEiuRIMX1cHyqmOlsbi9CBrHsxEbw45rtvXQLe29MErzUKO90kzbnQ4NbVQ8d4jt0g==} - "@swc/core-linux-x64-musl@1.15.3": - resolution: - { - integrity: sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug==, - } - engines: { node: ">=10" } - cpu: [x64] - os: [linux] - libc: [musl] + '@vercel/queue@0.1.4': + resolution: {integrity: sha512-wo+jCycmCX078vQSbkX+RcLvySONDCK0f9aQp5UMKQD1+B+xKt3YVbIYbZukvoHQpbm5nnk6If+ADSeK/PmCgQ==} + engines: {node: '>=20.0.0'} - "@swc/core-win32-arm64-msvc@1.15.3": - resolution: - { - integrity: sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA==, - } - engines: { node: ">=10" } - cpu: [arm64] - os: [win32] + '@vercel/redwood@2.4.10': + resolution: {integrity: sha512-7C5lUn9g9kLm1KpX55b8iizVPOB6087+kVyQyKyXGk8bbkYySL26yb+LIwyL/7mXwHlq/JTC0AxVdC3nNmPZuw==} - "@swc/core-win32-ia32-msvc@1.15.3": - resolution: - { - integrity: sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw==, - } - engines: { node: ">=10" } - cpu: [ia32] - os: [win32] + '@vercel/remix-builder@5.7.0': + resolution: {integrity: sha512-R44EHl+PQjX5PrCmyGust+bk+65eT5omxOLhEIJkSI90Kx/vvuyKnFNic/Zwo//GCMjxt9httvQUr/6vIBbjHg==} - "@swc/core-win32-x64-msvc@1.15.3": - resolution: - { - integrity: sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog==, - } - engines: { node: ">=10" } - cpu: [x64] - os: [win32] + '@vercel/ruby@2.3.2': + resolution: {integrity: sha512-okIgMmPEePyDR9TZYaKM4oftcxVHM5Dbdl7V/tIdh3lq8MGLi7HR5vvQglmZUwZOeovE6MVtezxl960EOzeIiQ==} - "@swc/core@1.15.3": - resolution: - { - integrity: sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==, - } - engines: { node: ">=10" } - peerDependencies: - "@swc/helpers": ">=0.5.17" - peerDependenciesMeta: - "@swc/helpers": - optional: true + '@vercel/rust@1.0.5': + resolution: {integrity: sha512-Y03g59nv1uT6Da+PvB/50WqJSHlaFZ9MSkG00R82dUcTySslMbQdOeaXymZtabrmU8zQYhWDb1/CwBki8sWnaQ==} - "@swc/counter@0.1.3": - resolution: - { - integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==, - } - - "@swc/helpers@0.5.15": - resolution: - { - integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==, - } - - "@swc/types@0.1.25": - resolution: - { - integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==, - } - - "@tokenizer/inflate@0.4.1": - resolution: - { - integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==, - } - engines: { node: ">=18" } - - "@tokenizer/token@0.3.0": - resolution: - { - integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==, - } - - "@tootallnate/once@2.0.0": - resolution: - { - integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==, - } - engines: { node: ">= 10" } - - "@tootallnate/quickjs-emscripten@0.23.0": - resolution: - { - integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==, - } - - "@ts-morph/common@0.11.1": - resolution: - { - integrity: sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==, - } - - "@tybys/wasm-util@0.10.1": - resolution: - { - integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==, - } - - "@types/chai@5.2.3": - resolution: - { - integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==, - } - - "@types/connect@3.4.38": - resolution: - { - integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==, - } - - "@types/debug@4.1.12": - resolution: - { - integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==, - } - - "@types/deep-eql@4.0.2": - resolution: - { - integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==, - } - - "@types/eslint-scope@3.7.7": - resolution: - { - integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==, - } - - "@types/eslint@9.6.1": - resolution: - { - integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==, - } - - "@types/estree-jsx@1.0.5": - resolution: - { - integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==, - } - - "@types/estree@1.0.8": - resolution: - { - integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, - } - - "@types/hast@3.0.4": - resolution: - { - integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==, - } - - "@types/js-yaml@4.0.9": - resolution: - { - integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==, - } - - "@types/json-schema@7.0.15": - resolution: - { - integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, - } - - "@types/mdast@4.0.4": - resolution: - { - integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==, - } - - "@types/mdx@2.0.13": - resolution: - { - integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==, - } - - "@types/ms@2.1.0": - resolution: - { - integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==, - } - - "@types/mysql@2.15.27": - resolution: - { - integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==, - } - - "@types/nlcst@2.0.3": - resolution: - { - integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==, - } - - "@types/node@17.0.45": - resolution: - { - integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==, - } - - "@types/node@20.11.0": - resolution: - { - integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==, - } - - "@types/node@20.19.37": - resolution: - { - integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==, - } - - "@types/node@25.3.5": - resolution: - { - integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==, - } - - "@types/node@25.5.0": - resolution: - { - integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==, - } - - "@types/pg-pool@2.0.7": - resolution: - { - integrity: sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng==, - } - - "@types/pg@8.15.6": - resolution: - { - integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==, - } - - "@types/react-dom@19.2.3": - resolution: - { - integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==, - } - peerDependencies: - "@types/react": ^19.2.0 - - "@types/react@19.2.14": - resolution: - { - integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==, - } - - "@types/retry@0.12.0": - resolution: - { - integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==, - } - - "@types/sax@1.2.7": - resolution: - { - integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==, - } - - "@types/sinonjs__fake-timers@8.1.5": - resolution: - { - integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==, - } - - "@types/statuses@2.0.6": - resolution: - { - integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==, - } - - "@types/tedious@4.0.14": - resolution: - { - integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==, - } - - "@types/unist@2.0.11": - resolution: - { - integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==, - } - - "@types/unist@3.0.3": - resolution: - { - integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==, - } - - "@types/which@2.0.2": - resolution: - { - integrity: sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==, - } - - "@types/ws@8.18.1": - resolution: - { - integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==, - } - - "@types/yauzl@2.10.3": - resolution: - { - integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==, - } - - "@ungap/structured-clone@1.3.0": - resolution: - { - integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==, - } - - "@vercel/backends@0.0.45": - resolution: - { - integrity: sha512-KIdt/z4LfH7NgFMqgSuKi0H9UIasly7ByzP+/ZXulgNrWyeJKT9KCas3SDT65o5tU6x1D/jBysZA9AnOt8Ivew==, - } - peerDependencies: - typescript: ^4.0.0 || ^5.0.0 + '@vercel/sandbox@1.8.1': + resolution: {integrity: sha512-txohjI20aMxZiAzBL/KJi5EqTYsesBdOyIOtpTIyebPLTqYtDYfNhQ4OeYiUcPMUo0XBt8gSet/rIdLQEjj3/A==} - "@vercel/blob@2.3.0": - resolution: - { - integrity: sha512-oYWiJbWRQ7gz9Mj0X/NHFJ3OcLMOBzq/2b3j6zeNrQmtFo6dHwU8FAwNpxVIYddVMd+g8eqEi7iRueYx8FtM0Q==, - } - engines: { node: ">=20.0.0" } - - "@vercel/build-utils@13.8.0": - resolution: - { - integrity: sha512-moQS4Qd0pvluPd6WRTHxLN3Hh0oSObVNdFv3V0spiEmCk/wm6571up3n1th2PQFqf1a3gheNfxzL7h4I9CWs2A==, - } - - "@vercel/cervel@0.0.32": - resolution: - { - integrity: sha512-g/LIa97d/m3yIZGyBjwl4FOQK1Lg5HU2+N3uHiGVajLoSgJM2aBiwETDZc8bVCr8IO3IqXZQsT2hGy1Jnyko1g==, - } - hasBin: true - peerDependencies: - typescript: ^4.0.0 || ^5.0.0 + '@vercel/static-build@2.9.0': + resolution: {integrity: sha512-3SHWntz8swxL6ve750dY8kyl4NwVUplYtun/ei7y11q2UnI70WnWmm6L9fi02Wy1o3RGhbvOnlFLcHOUBm3DXQ==} - "@vercel/detect-agent@1.2.1": - resolution: - { - integrity: sha512-U/BJCltQSTFTHwaiCQQTQG3GonTbRoEewjV+OU2mMjcHLAoPOh6CP1SXA2XNmqiqI3c82nkRNJ7piZ14RqmTXw==, - } - engines: { node: ">=14" } - - "@vercel/elysia@0.1.48": - resolution: - { - integrity: sha512-QlmOHUSOx/uE67Y6u/o8VbNF7ebZ8SZFbrEoBo7iZAd0MC2Vn4xUmlrHFXNR/FEkHFXWkhFKda5Ade3XMqMY8A==, - } - - "@vercel/error-utils@2.0.3": - resolution: - { - integrity: sha512-CqC01WZxbLUxoiVdh9B/poPbNpY9U+tO1N9oWHwTl5YAZxcqXmmWJ8KNMFItJCUUWdY3J3xv8LvAuQv2KZ5YdQ==, - } - - "@vercel/express@0.1.57": - resolution: - { - integrity: sha512-/Ih1eiJrBGSW6JPzexB8y8AMX/8MzuDUf0xzmpYbKLCbehp3NNuxde5RxT+6cALglFivDETsJBCFwaFuIh3ZqQ==, - } - - "@vercel/fastify@0.1.51": - resolution: - { - integrity: sha512-c9CwFQqmoUm5eEGwAcqb98DcxsRmSZGngCAo1B+nlDhaACKcrJ7Ro0tYdTDhi8Lkt+OcPnRWr4+pepgWwH94GQ==, - } - - "@vercel/fun@1.3.0": - resolution: - { - integrity: sha512-8erw9uPe0dFg45THkNxmjtvMX143SkZebmjgSVbcM3XCkXu3RIiBaJMcMNG8aaS+rnTuw8+d4De9HVT0M/r3wg==, - } - engines: { node: ">= 18" } - - "@vercel/gatsby-plugin-vercel-analytics@1.0.11": - resolution: - { - integrity: sha512-iTEA0vY6RBPuEzkwUTVzSHDATo1aF6bdLLspI68mQ/BTbi5UQEGjpjyzdKOVcSYApDtFU6M6vypZ1t4vIEnHvw==, - } - - "@vercel/gatsby-plugin-vercel-builder@2.1.0": - resolution: - { - integrity: sha512-avJ5IFev2h2K6E/Pd7qd00cFLALj3OyEmQE3UoGs1dmoncINFqa1RoIZDJ9wIhWm1Euan4wrFMRsXkCwNhEGhw==, - } - - "@vercel/go@3.4.5": - resolution: - { - integrity: sha512-eTWsdXawkSsG5TP+1BJUo+wRnoG9uH51MRID0YlwMMvollG5q7CrYisg859koy8MzGjQAcu3ff5v/WwRbwXwgQ==, - } - - "@vercel/h3@0.1.57": - resolution: - { - integrity: sha512-I7Q1ity7xEdIVw4OQuKOAR8i6DrvfjpKy+y2uTwbqBD80Gg0KpsMS/KKA+UjvCuclFmP/EHYS3kpMLc/O1rVqg==, - } - - "@vercel/hono@0.2.51": - resolution: - { - integrity: sha512-iYEjjF4qR3gTZpVoB4sMQNm5OOdKw5/P2bL1CtolDTeGaea9KwqUrLyXmdK4N41HIRZr/wduID31mmHhSdC3sA==, - } - - "@vercel/hydrogen@1.3.6": - resolution: - { - integrity: sha512-Ec8dKEjGIM4BfThcRLtQs5zaJ4+iJbgLZwkytwi7Blk8VrK6W2F1dtLDmVQYZdVnQcnmHmTx8mxUuMkfP06Mnw==, - } - - "@vercel/koa@0.1.31": - resolution: - { - integrity: sha512-Gj4sjqNA80/gnHpC0tRPCTtVEct69tUK21fsjVmawCa+nDNQ4bqXu3dSewna7GtCcp9KnrWgzAIaeVAQUl53mQ==, - } - - "@vercel/nestjs@0.2.52": - resolution: - { - integrity: sha512-yfy4rpWJ1BRWZ1xBBPew0egVIblFe6G7laCKDzyESnbw19zY0F16g9HCu1H/0IfuKIQvOc95dtbmBsqLm9jyqw==, - } - - "@vercel/next@4.16.1": - resolution: - { - integrity: sha512-gwy3XQRZ/f6RdKuC7BZIRMAzUOQf/R5+k9LMf1LcOm1CVZOLpDhDkeZMTG5vb3Lk9LWwBrJJ2ohhZaYuYEOHaw==, - } - - "@vercel/nft@1.1.1": - resolution: - { - integrity: sha512-mKMGa7CEUcXU75474kOeqHbtvK1kAcu4wiahhmlUenB5JbTQB8wVlDI8CyHR3rpGo0qlzoRWqcDzI41FUoBJCA==, - } - engines: { node: ">=20" } - hasBin: true + '@vercel/static-config@3.2.0': + resolution: {integrity: sha512-UpOEIgWxWx0M+mDe1IMdHS6JuWM/L5nNIJ4ixX8v9JgBAejymo88OkgnmfLCNMem0Wd+b5vcQPWLdZybCndlsA==} - "@vercel/nft@1.3.0": - resolution: - { - integrity: sha512-i4EYGkCsIjzu4vorDUbqglZc5eFtQI2syHb++9ZUDm6TU4edVywGpVnYDein35x9sevONOn9/UabfQXuNXtuzQ==, - } - engines: { node: ">=20" } - hasBin: true + '@vitest/expect@4.1.0': + resolution: {integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==} - "@vercel/node@5.6.15": - resolution: - { - integrity: sha512-xc5fxmdk8jtuUY8y9/8W5UhTn8R1Ii1Fb3q+V8Zv+2moU9enrrBADA9ercHgE0/DtoiNDpb9Wmvnrb4bUcFOzA==, - } - - "@vercel/oidc@3.1.0": - resolution: - { - integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==, - } - engines: { node: ">= 20" } - - "@vercel/oidc@3.2.0": - resolution: - { - integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==, - } - engines: { node: ">= 20" } - - "@vercel/python-analysis@0.9.1": - resolution: - { - integrity: sha512-ZwEi/F2DPxFPYmfjHFy7qM3+JTWRxD1EMpbIotNNhUyd/pnIG0wNt7S73RJSx62n1Y7pmFOFowoImnhULQgKvA==, - } - - "@vercel/python@6.23.0": - resolution: - { - integrity: sha512-P4cwbfk1zaVfX6obR3h+tEiuRIMX1cHyqmOlsbi9CBrHsxEbw45rtvXQLe29MErzUKO90kzbnQ4NbVQ8d4jt0g==, - } - - "@vercel/queue@0.1.4": - resolution: - { - integrity: sha512-wo+jCycmCX078vQSbkX+RcLvySONDCK0f9aQp5UMKQD1+B+xKt3YVbIYbZukvoHQpbm5nnk6If+ADSeK/PmCgQ==, - } - engines: { node: ">=20.0.0" } - - "@vercel/redwood@2.4.10": - resolution: - { - integrity: sha512-7C5lUn9g9kLm1KpX55b8iizVPOB6087+kVyQyKyXGk8bbkYySL26yb+LIwyL/7mXwHlq/JTC0AxVdC3nNmPZuw==, - } - - "@vercel/remix-builder@5.7.0": - resolution: - { - integrity: sha512-R44EHl+PQjX5PrCmyGust+bk+65eT5omxOLhEIJkSI90Kx/vvuyKnFNic/Zwo//GCMjxt9httvQUr/6vIBbjHg==, - } - - "@vercel/ruby@2.3.2": - resolution: - { - integrity: sha512-okIgMmPEePyDR9TZYaKM4oftcxVHM5Dbdl7V/tIdh3lq8MGLi7HR5vvQglmZUwZOeovE6MVtezxl960EOzeIiQ==, - } - - "@vercel/rust@1.0.5": - resolution: - { - integrity: sha512-Y03g59nv1uT6Da+PvB/50WqJSHlaFZ9MSkG00R82dUcTySslMbQdOeaXymZtabrmU8zQYhWDb1/CwBki8sWnaQ==, - } - - "@vercel/sandbox@1.8.1": - resolution: - { - integrity: sha512-txohjI20aMxZiAzBL/KJi5EqTYsesBdOyIOtpTIyebPLTqYtDYfNhQ4OeYiUcPMUo0XBt8gSet/rIdLQEjj3/A==, - } - - "@vercel/static-build@2.9.0": - resolution: - { - integrity: sha512-3SHWntz8swxL6ve750dY8kyl4NwVUplYtun/ei7y11q2UnI70WnWmm6L9fi02Wy1o3RGhbvOnlFLcHOUBm3DXQ==, - } - - "@vercel/static-config@3.2.0": - resolution: - { - integrity: sha512-UpOEIgWxWx0M+mDe1IMdHS6JuWM/L5nNIJ4ixX8v9JgBAejymo88OkgnmfLCNMem0Wd+b5vcQPWLdZybCndlsA==, - } - - "@vitest/expect@4.1.0": - resolution: - { - integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==, - } - - "@vitest/mocker@4.1.0": - resolution: - { - integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==, - } + '@vitest/mocker@4.1.0': + resolution: {integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 @@ -4858,324 +3106,181 @@ packages: vite: optional: true - "@vitest/pretty-format@4.1.0": - resolution: - { - integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==, - } - - "@vitest/runner@4.1.0": - resolution: - { - integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==, - } - - "@vitest/snapshot@4.1.0": - resolution: - { - integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==, - } - - "@vitest/spy@4.1.0": - resolution: - { - integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==, - } - - "@vitest/utils@4.1.0": - resolution: - { - integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==, - } - - "@volar/kit@2.4.28": - resolution: - { - integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==, - } + '@vitest/pretty-format@4.1.0': + resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} + + '@vitest/runner@4.1.0': + resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==} + + '@vitest/snapshot@4.1.0': + resolution: {integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==} + + '@vitest/spy@4.1.0': + resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==} + + '@vitest/utils@4.1.0': + resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} + + '@volar/kit@2.4.28': + resolution: {integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==} peerDependencies: - typescript: "*" - - "@volar/language-core@2.4.28": - resolution: - { - integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==, - } - - "@volar/language-server@2.4.28": - resolution: - { - integrity: sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==, - } - - "@volar/language-service@2.4.28": - resolution: - { - integrity: sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==, - } - - "@volar/source-map@2.4.28": - resolution: - { - integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==, - } - - "@volar/typescript@2.4.28": - resolution: - { - integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==, - } - - "@vscode/emmet-helper@2.11.0": - resolution: - { - integrity: sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==, - } - - "@vscode/l10n@0.0.18": - resolution: - { - integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==, - } - - "@wdio/config@9.24.0": - resolution: - { - integrity: sha512-rcHu0eG16rSEmHL0sEKDcr/vYFmGhQ5GOlmlx54r+1sgh6sf136q+kth4169s16XqviWGW3LjZbUfpTK29pGtw==, - } - engines: { node: ">=18.20.0" } - - "@wdio/logger@9.18.0": - resolution: - { - integrity: sha512-HdzDrRs+ywAqbXGKqe1i/bLtCv47plz4TvsHFH3j729OooT5VH38ctFn5aLXgECmiAKDkmH/A6kOq2Zh5DIxww==, - } - engines: { node: ">=18.20.0" } - - "@wdio/protocols@9.24.0": - resolution: - { - integrity: sha512-ozQKYddBLT4TRvU9J+fGrhVUtx3iDAe+KNCJcTDMFMxNSdDMR2xFQdNp8HLHypspk58oXTYCvz6ZYjySthhqsw==, - } - - "@wdio/repl@9.16.2": - resolution: - { - integrity: sha512-FLTF0VL6+o5BSTCO7yLSXocm3kUnu31zYwzdsz4n9s5YWt83sCtzGZlZpt7TaTzb3jVUfxuHNQDTb8UMkCu0lQ==, - } - engines: { node: ">=18.20.0" } - - "@wdio/types@9.24.0": - resolution: - { - integrity: sha512-PYYunNl8Uq1r8YMJAK6ReRy/V/XIrCSyj5cpCtR5EqCL6heETOORFj7gt4uPnzidfgbtMBcCru0LgjjlMiH1UQ==, - } - engines: { node: ">=18.20.0" } - - "@wdio/utils@9.24.0": - resolution: - { - integrity: sha512-6WhtzC5SNCGRBTkaObX6A07Ofnnyyf+TQH/d/fuhZRqvBknrP4AMMZF+PFxGl1fwdySWdBn+gV2QLE+52Byowg==, - } - engines: { node: ">=18.20.0" } - - "@webassemblyjs/ast@1.14.1": - resolution: - { - integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==, - } - - "@webassemblyjs/floating-point-hex-parser@1.13.2": - resolution: - { - integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==, - } - - "@webassemblyjs/helper-api-error@1.13.2": - resolution: - { - integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==, - } - - "@webassemblyjs/helper-buffer@1.14.1": - resolution: - { - integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==, - } - - "@webassemblyjs/helper-numbers@1.13.2": - resolution: - { - integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==, - } - - "@webassemblyjs/helper-wasm-bytecode@1.13.2": - resolution: - { - integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==, - } - - "@webassemblyjs/helper-wasm-section@1.14.1": - resolution: - { - integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==, - } - - "@webassemblyjs/ieee754@1.13.2": - resolution: - { - integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==, - } - - "@webassemblyjs/leb128@1.13.2": - resolution: - { - integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==, - } - - "@webassemblyjs/utf8@1.13.2": - resolution: - { - integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==, - } - - "@webassemblyjs/wasm-edit@1.14.1": - resolution: - { - integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==, - } - - "@webassemblyjs/wasm-gen@1.14.1": - resolution: - { - integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==, - } - - "@webassemblyjs/wasm-opt@1.14.1": - resolution: - { - integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==, - } - - "@webassemblyjs/wasm-parser@1.14.1": - resolution: - { - integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==, - } - - "@webassemblyjs/wast-printer@1.14.1": - resolution: - { - integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==, - } - - "@workflow/serde@4.1.0-beta.2": - resolution: - { - integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==, - } - - "@xtuc/ieee754@1.2.0": - resolution: - { - integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==, - } - - "@xtuc/long@4.2.2": - resolution: - { - integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==, - } - - "@zip.js/zip.js@2.8.23": - resolution: - { - integrity: sha512-RB+RLnxPJFPrGvQ9rgO+4JOcsob6lD32OcF0QE0yg24oeW9q8KnTTNlugcDaIveEcCbclobJcZP+fLQ++sH0bw==, - } - engines: { bun: ">=0.7.0", deno: ">=1.0.0", node: ">=18.0.0" } + typescript: '*' + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/language-server@2.4.28': + resolution: {integrity: sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==} + + '@volar/language-service@2.4.28': + resolution: {integrity: sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vscode/emmet-helper@2.11.0': + resolution: {integrity: sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==} + + '@vscode/l10n@0.0.18': + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + + '@wdio/config@9.24.0': + resolution: {integrity: sha512-rcHu0eG16rSEmHL0sEKDcr/vYFmGhQ5GOlmlx54r+1sgh6sf136q+kth4169s16XqviWGW3LjZbUfpTK29pGtw==} + engines: {node: '>=18.20.0'} + + '@wdio/logger@9.18.0': + resolution: {integrity: sha512-HdzDrRs+ywAqbXGKqe1i/bLtCv47plz4TvsHFH3j729OooT5VH38ctFn5aLXgECmiAKDkmH/A6kOq2Zh5DIxww==} + engines: {node: '>=18.20.0'} + + '@wdio/protocols@9.24.0': + resolution: {integrity: sha512-ozQKYddBLT4TRvU9J+fGrhVUtx3iDAe+KNCJcTDMFMxNSdDMR2xFQdNp8HLHypspk58oXTYCvz6ZYjySthhqsw==} + + '@wdio/repl@9.16.2': + resolution: {integrity: sha512-FLTF0VL6+o5BSTCO7yLSXocm3kUnu31zYwzdsz4n9s5YWt83sCtzGZlZpt7TaTzb3jVUfxuHNQDTb8UMkCu0lQ==} + engines: {node: '>=18.20.0'} + + '@wdio/types@9.24.0': + resolution: {integrity: sha512-PYYunNl8Uq1r8YMJAK6ReRy/V/XIrCSyj5cpCtR5EqCL6heETOORFj7gt4uPnzidfgbtMBcCru0LgjjlMiH1UQ==} + engines: {node: '>=18.20.0'} + + '@wdio/utils@9.24.0': + resolution: {integrity: sha512-6WhtzC5SNCGRBTkaObX6A07Ofnnyyf+TQH/d/fuhZRqvBknrP4AMMZF+PFxGl1fwdySWdBn+gV2QLE+52Byowg==} + engines: {node: '>=18.20.0'} + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@workflow/serde@4.1.0-beta.2': + resolution: {integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + '@zip.js/zip.js@2.8.23': + resolution: {integrity: sha512-RB+RLnxPJFPrGvQ9rgO+4JOcsob6lD32OcF0QE0yg24oeW9q8KnTTNlugcDaIveEcCbclobJcZP+fLQ++sH0bw==} + engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=18.0.0'} abbrev@3.0.1: - resolution: - { - integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==, - } - engines: { node: ^18.17.0 || >=20.5.0 } + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} abort-controller@3.0.0: - resolution: - { - integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==, - } - engines: { node: ">=6.5" } + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} acorn-import-attributes@1.9.5: - resolution: - { - integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==, - } + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: acorn: ^8 acorn-import-phases@1.0.4: - resolution: - { - integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==, - } - engines: { node: ">=10.13.0" } + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} peerDependencies: acorn: ^8.14.0 acorn-jsx@5.3.2: - resolution: - { - integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, - } + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 acorn@8.16.0: - resolution: - { - integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==, - } - engines: { node: ">=0.4.0" } + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} hasBin: true agent-base@6.0.2: - resolution: - { - integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==, - } - engines: { node: ">= 6.0.0" } + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} agent-base@7.1.4: - resolution: - { - integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} agent-browser@0.16.3: - resolution: - { - integrity: sha512-dsg8PTJNBIQ7/LPp/La42KQwLTzsP8sudbCLpP1atsJXps4Fbuz1CeepUJAGrgxb8koc9y4yKobYVPAsds8hPQ==, - } + resolution: {integrity: sha512-dsg8PTJNBIQ7/LPp/La42KQwLTzsP8sudbCLpP1atsJXps4Fbuz1CeepUJAGrgxb8koc9y4yKobYVPAsds8hPQ==} hasBin: true ai@6.0.116: - resolution: - { - integrity: sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA==} + engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 ajv-draft-04@1.0.0: - resolution: - { - integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==, - } + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: ajv: ^8.5.0 peerDependenciesMeta: @@ -5183,10 +3288,7 @@ packages: optional: true ajv-formats@2.1.1: - resolution: - { - integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==, - } + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: ajv: ^8.0.0 peerDependenciesMeta: @@ -5194,10 +3296,7 @@ packages: optional: true ajv-formats@3.0.1: - resolution: - { - integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==, - } + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: ajv: ^8.0.0 peerDependenciesMeta: @@ -5205,313 +3304,180 @@ packages: optional: true ajv-keywords@5.1.0: - resolution: - { - integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==, - } + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} peerDependencies: ajv: ^8.8.2 ajv@8.18.0: - resolution: - { - integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==, - } + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} ajv@8.6.3: - resolution: - { - integrity: sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==, - } + resolution: {integrity: sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==} amdefine@1.0.1: - resolution: - { - integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==, - } - engines: { node: ">=0.4.2" } + resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} + engines: {node: '>=0.4.2'} ansi-align@3.0.1: - resolution: - { - integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==, - } + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} ansi-escapes@7.3.0: - resolution: - { - integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} ansi-regex@5.0.1: - resolution: - { - integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} ansi-regex@6.2.2: - resolution: - { - integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} ansi-styles@4.3.0: - resolution: - { - integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} ansi-styles@6.2.3: - resolution: - { - integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} any-promise@1.3.0: - resolution: - { - integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, - } + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} anymatch@3.1.3: - resolution: - { - integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, - } - engines: { node: ">= 8" } + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} archiver-utils@5.0.2: - resolution: - { - integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} archiver@7.0.1: - resolution: - { - integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} arg@4.1.0: - resolution: - { - integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==, - } + resolution: {integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==} arg@5.0.2: - resolution: - { - integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, - } + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} argparse@1.0.10: - resolution: - { - integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==, - } + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} argparse@2.0.1: - resolution: - { - integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, - } + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} aria-query@5.3.2: - resolution: - { - integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} array-iterate@2.0.1: - resolution: - { - integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==, - } + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} assertion-error@2.0.1: - resolution: - { - integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} ast-types@0.13.4: - resolution: - { - integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} astring@1.9.0: - resolution: - { - integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==, - } + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true astro-expressive-code@0.41.7: - resolution: - { - integrity: sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==, - } + resolution: {integrity: sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==} peerDependencies: astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta astro@5.18.0: - resolution: - { - integrity: sha512-CHiohwJIS4L0G6/IzE1Fx3dgWqXBCXus/od0eGUfxrZJD2um2pE7ehclMmgL/fXqbU7NfE1Ze2pq34h2QaA6iQ==, - } - engines: - { node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0" } + resolution: {integrity: sha512-CHiohwJIS4L0G6/IzE1Fx3dgWqXBCXus/od0eGUfxrZJD2um2pE7ehclMmgL/fXqbU7NfE1Ze2pq34h2QaA6iQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true async-listen@1.2.0: - resolution: - { - integrity: sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==, - } + resolution: {integrity: sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==} async-listen@3.0.0: - resolution: - { - integrity: sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==} + engines: {node: '>= 14'} async-listen@3.0.1: - resolution: - { - integrity: sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==} + engines: {node: '>= 14'} async-retry@1.3.3: - resolution: - { - integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==, - } + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} async-sema@3.1.1: - resolution: - { - integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==, - } + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} async@3.2.6: - resolution: - { - integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==, - } + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} asyncbox@3.0.0: - resolution: - { - integrity: sha512-X7U0nedUMKV3nn9c4R0Zgvdvv6cw97tbDlHSZicq1snGPi/oX9DgGmFSURWtxDdnBWd3V0YviKhqAYAVvoWQ/A==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-X7U0nedUMKV3nn9c4R0Zgvdvv6cw97tbDlHSZicq1snGPi/oX9DgGmFSURWtxDdnBWd3V0YviKhqAYAVvoWQ/A==} + engines: {node: '>=16'} asynckit@0.4.0: - resolution: - { - integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, - } + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} axios@1.13.6: - resolution: - { - integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==, - } + resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} axobject-query@4.1.0: - resolution: - { - integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} b4a@1.8.0: - resolution: - { - integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==, - } + resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==} peerDependencies: - react-native-b4a: "*" + react-native-b4a: '*' peerDependenciesMeta: react-native-b4a: optional: true bail@2.0.2: - resolution: - { - integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==, - } + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} balanced-match@1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, - } + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} balanced-match@4.0.4: - resolution: - { - integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==, - } - engines: { node: 18 || 20 || >=22 } + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} bare-events@2.8.2: - resolution: - { - integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==, - } + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} peerDependencies: - bare-abort-controller: "*" + bare-abort-controller: '*' peerDependenciesMeta: bare-abort-controller: optional: true bare-fs@4.5.5: - resolution: - { - integrity: sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==, - } - engines: { bare: ">=1.16.0" } + resolution: {integrity: sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==} + engines: {bare: '>=1.16.0'} peerDependencies: - bare-buffer: "*" + bare-buffer: '*' peerDependenciesMeta: bare-buffer: optional: true bare-os@3.7.1: - resolution: - { - integrity: sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA==, - } - engines: { bare: ">=1.14.0" } + resolution: {integrity: sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA==} + engines: {bare: '>=1.14.0'} bare-path@3.0.0: - resolution: - { - integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==, - } + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} bare-stream@2.8.0: - resolution: - { - integrity: sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==, - } + resolution: {integrity: sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==} peerDependencies: - bare-buffer: "*" - bare-events: "*" + bare-buffer: '*' + bare-events: '*' peerDependenciesMeta: bare-buffer: optional: true @@ -5519,1376 +3485,821 @@ packages: optional: true bare-url@2.3.2: - resolution: - { - integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==, - } + resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} base-64@1.0.0: - resolution: - { - integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==, - } + resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} base64-js@1.5.1: - resolution: - { - integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, - } + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} baseline-browser-mapping@2.10.8: - resolution: - { - integrity: sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==, - } - engines: { node: ">=6.0.0" } + resolution: {integrity: sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==} + engines: {node: '>=6.0.0'} hasBin: true bash-tool@1.3.15: - resolution: - { - integrity: sha512-rsUxbwTO1qU9LxLhsqu7d5MfoJAqWgw0+E1uDEHLxrZRcXXayZspgiqTSXwGM2yuCz6N42duMdbF95o5ZSw8lQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-rsUxbwTO1qU9LxLhsqu7d5MfoJAqWgw0+E1uDEHLxrZRcXXayZspgiqTSXwGM2yuCz6N42duMdbF95o5ZSw8lQ==} + engines: {node: '>=18'} peerDependencies: - "@vercel/sandbox": "*" + '@vercel/sandbox': '*' ai: ^6.0.0 just-bash: ^2.9.3 peerDependenciesMeta: - "@vercel/sandbox": + '@vercel/sandbox': optional: true just-bash: optional: true basic-ftp@5.2.0: - resolution: - { - integrity: sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==, - } - engines: { node: ">=10.0.0" } + resolution: {integrity: sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==} + engines: {node: '>=10.0.0'} bcp-47-match@2.0.3: - resolution: - { - integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==, - } + resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} bcp-47@2.1.0: - resolution: - { - integrity: sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==, - } + resolution: {integrity: sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==} bignumber.js@9.3.1: - resolution: - { - integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==, - } + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} bindings@1.5.0: - resolution: - { - integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==, - } + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} bl@4.1.0: - resolution: - { - integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, - } + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} bluebird@3.7.2: - resolution: - { - integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==, - } + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} boolbase@1.0.0: - resolution: - { - integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==, - } + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} bowser@2.14.1: - resolution: - { - integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==, - } + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} boxen@8.0.1: - resolution: - { - integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} + engines: {node: '>=18'} brace-expansion@1.1.12: - resolution: - { - integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==, - } + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} brace-expansion@2.0.2: - resolution: - { - integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==, - } + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} brace-expansion@5.0.4: - resolution: - { - integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==, - } - engines: { node: 18 || 20 || >=22 } + resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + engines: {node: 18 || 20 || >=22} braces@3.0.3: - resolution: - { - integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} browserslist@4.28.1: - resolution: - { - integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==, - } - engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true buffer-crc32@0.2.13: - resolution: - { - integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==, - } + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} buffer-crc32@1.0.0: - resolution: - { - integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==, - } - engines: { node: ">=8.0.0" } + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} buffer-equal-constant-time@1.0.1: - resolution: - { - integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==, - } + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} buffer-from@1.1.2: - resolution: - { - integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, - } + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} buffer@5.7.1: - resolution: - { - integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, - } + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} buffer@6.0.3: - resolution: - { - integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==, - } + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} bundle-require@5.1.0: - resolution: - { - integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==, - } - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: - esbuild: ">=0.18" + esbuild: '>=0.18' bytes@3.1.0: - resolution: - { - integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==, - } - engines: { node: ">= 0.8" } + resolution: {integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==} + engines: {node: '>= 0.8'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} cac@6.7.14: - resolution: - { - integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} call-bind-apply-helpers@1.0.2: - resolution: - { - integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} camelcase@8.0.0: - resolution: - { - integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} caniuse-lite@1.0.30001780: - resolution: - { - integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==, - } + resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} ccount@2.0.1: - resolution: - { - integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==, - } + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} chai@6.2.2: - resolution: - { - integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} chalk@4.1.2: - resolution: - { - integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} chalk@5.6.2: - resolution: - { - integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==, - } - engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 } + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} character-entities-html4@2.1.0: - resolution: - { - integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==, - } + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} character-entities-legacy@3.0.0: - resolution: - { - integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==, - } + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} character-entities@2.0.2: - resolution: - { - integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==, - } + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} character-reference-invalid@2.0.1: - resolution: - { - integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==, - } + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} chat@4.20.2: - resolution: - { - integrity: sha512-iTyMjE3ZRnubw1t4HgSyhU+sOG5coIBYxNS4DZbBmjQCJ9DnArmiejtG3cMigb11E2OlilZ97oKuRGigIOPh4g==, - } + resolution: {integrity: sha512-iTyMjE3ZRnubw1t4HgSyhU+sOG5coIBYxNS4DZbBmjQCJ9DnArmiejtG3cMigb11E2OlilZ97oKuRGigIOPh4g==} cheerio-select@2.1.0: - resolution: - { - integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==, - } + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} cheerio@1.2.0: - resolution: - { - integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==, - } - engines: { node: ">=20.18.1" } + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} + engines: {node: '>=20.18.1'} chokidar@4.0.0: - resolution: - { - integrity: sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==, - } - engines: { node: ">= 14.16.0" } + resolution: {integrity: sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==} + engines: {node: '>= 14.16.0'} chokidar@4.0.3: - resolution: - { - integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==, - } - engines: { node: ">= 14.16.0" } + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} chokidar@5.0.0: - resolution: - { - integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==, - } - engines: { node: ">= 20.19.0" } + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} chownr@1.1.4: - resolution: - { - integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==, - } + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} chownr@3.0.0: - resolution: - { - integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} chrome-trace-event@1.0.4: - resolution: - { - integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==, - } - engines: { node: ">=6.0" } + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} ci-info@4.4.0: - resolution: - { - integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} cjs-module-lexer@1.2.3: - resolution: - { - integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==, - } + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} cjs-module-lexer@2.2.0: - resolution: - { - integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==, - } + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} cli-boxes@3.0.0: - resolution: - { - integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} cli-cursor@5.0.0: - resolution: - { - integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} cli-truncate@5.2.0: - resolution: - { - integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} + engines: {node: '>=20'} cli-width@4.1.0: - resolution: - { - integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==, - } - engines: { node: ">= 12" } + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} client-only@0.0.1: - resolution: - { - integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==, - } + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} cliui@8.0.1: - resolution: - { - integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} clsx@2.1.1: - resolution: - { - integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} cluster-key-slot@1.1.2: - resolution: - { - integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} code-block-writer@10.1.1: - resolution: - { - integrity: sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==, - } + resolution: {integrity: sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==} collapse-white-space@2.1.0: - resolution: - { - integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==, - } + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} color-convert@2.0.1: - resolution: - { - integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, - } - engines: { node: ">=7.0.0" } + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} color-name@1.1.4: - resolution: - { - integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, - } + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} colorette@2.0.20: - resolution: - { - integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==, - } + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} combined-stream@1.0.8: - resolution: - { - integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, - } - engines: { node: ">= 0.8" } + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} comma-separated-tokens@2.0.3: - resolution: - { - integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==, - } + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} commander@11.1.0: - resolution: - { - integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} commander@14.0.3: - resolution: - { - integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} commander@2.20.3: - resolution: - { - integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, - } + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} commander@2.8.1: - resolution: - { - integrity: sha512-+pJLBFVk+9ZZdlAOB5WuIElVPPth47hILFkmGym57aq8kwxsowvByvB0DHs1vQAhyMZzdcpTtF0VDKGkSDR4ZQ==, - } - engines: { node: ">= 0.6.x" } + resolution: {integrity: sha512-+pJLBFVk+9ZZdlAOB5WuIElVPPth47hILFkmGym57aq8kwxsowvByvB0DHs1vQAhyMZzdcpTtF0VDKGkSDR4ZQ==} + engines: {node: '>= 0.6.x'} commander@4.1.1: - resolution: - { - integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} commander@9.5.0: - resolution: - { - integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==, - } - engines: { node: ^12.20.0 || >=14 } + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} common-ancestor-path@1.0.1: - resolution: - { - integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==, - } + resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} commondir@1.0.1: - resolution: - { - integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==, - } + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} compress-commons@6.0.2: - resolution: - { - integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} compressjs@1.0.3: - resolution: - { - integrity: sha512-jpKJjBTretQACTGLNuvnozP1JdP2ZLrjdGdBgk/tz1VfXlUcBhhSZW6vEsuThmeot/yjvSrPQKEgfF3X2Lpi8Q==, - } + resolution: {integrity: sha512-jpKJjBTretQACTGLNuvnozP1JdP2ZLrjdGdBgk/tz1VfXlUcBhhSZW6vEsuThmeot/yjvSrPQKEgfF3X2Lpi8Q==} hasBin: true concat-map@0.0.1: - resolution: - { - integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, - } + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} confbox@0.1.8: - resolution: - { - integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==, - } + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} consola@3.4.2: - resolution: - { - integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==, - } - engines: { node: ^14.18.0 || >=16.10.0 } + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} console-control-strings@1.1.0: - resolution: - { - integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==, - } + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} content-type@1.0.4: - resolution: - { - integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==, - } - engines: { node: ">= 0.6" } + resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} convert-hrtime@3.0.0: - resolution: - { - integrity: sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==} + engines: {node: '>=8'} convert-source-map@2.0.0: - resolution: - { - integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, - } + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} cookie-es@1.2.2: - resolution: - { - integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==, - } + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} cookie-es@2.0.0: - resolution: - { - integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==, - } + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} cookie@1.1.1: - resolution: - { - integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} core-util-is@1.0.3: - resolution: - { - integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, - } + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} crc-32@1.2.2: - resolution: - { - integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==, - } - engines: { node: ">=0.8" } + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} hasBin: true crc32-stream@6.0.0: - resolution: - { - integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} cross-spawn@7.0.6: - resolution: - { - integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, - } - engines: { node: ">= 8" } + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} crossws@0.3.5: - resolution: - { - integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==, - } + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} css-select@5.2.2: - resolution: - { - integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==, - } + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} css-selector-parser@3.3.0: - resolution: - { - integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==, - } + resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} css-shorthand-properties@1.1.2: - resolution: - { - integrity: sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==, - } + resolution: {integrity: sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==} css-tree@2.2.1: - resolution: - { - integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==, - } - engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: ">=7.0.0" } + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} css-tree@3.2.1: - resolution: - { - integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==, - } - engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0 } + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} css-value@0.0.1: - resolution: - { - integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==, - } + resolution: {integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==} css-what@6.2.2: - resolution: - { - integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} cssesc@3.0.0: - resolution: - { - integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} hasBin: true csso@5.0.5: - resolution: - { - integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==, - } - engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: ">=7.0.0" } + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} csstype@3.2.3: - resolution: - { - integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==, - } + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} data-uri-to-buffer@4.0.1: - resolution: - { - integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==, - } - engines: { node: ">= 12" } + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} data-uri-to-buffer@6.0.2: - resolution: - { - integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} debug@4.3.4: - resolution: - { - integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, - } - engines: { node: ">=6.0" } + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} peerDependencies: - supports-color: "*" + supports-color: '*' peerDependenciesMeta: supports-color: optional: true debug@4.4.3: - resolution: - { - integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, - } - engines: { node: ">=6.0" } + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} peerDependencies: - supports-color: "*" + supports-color: '*' peerDependenciesMeta: supports-color: optional: true decamelize@6.0.1: - resolution: - { - integrity: sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==, - } - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + resolution: {integrity: sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} decode-named-character-reference@1.3.0: - resolution: - { - integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==, - } + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} decompress-response@6.0.0: - resolution: - { - integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} deep-extend@0.6.0: - resolution: - { - integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==, - } - engines: { node: ">=4.0.0" } + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} deepmerge-ts@7.1.5: - resolution: - { - integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==, - } - engines: { node: ">=16.0.0" } + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} defu@6.1.4: - resolution: - { - integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==, - } + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} degenerator@5.0.1: - resolution: - { - integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} delayed-stream@1.0.0: - resolution: - { - integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, - } - engines: { node: ">=0.4.0" } + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} depd@1.1.2: - resolution: - { - integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==, - } - engines: { node: ">= 0.6" } + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} dequal@2.0.3: - resolution: - { - integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} destr@2.0.5: - resolution: - { - integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==, - } + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} detect-libc@2.1.2: - resolution: - { - integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} deterministic-object-hash@2.0.2: - resolution: - { - integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==} + engines: {node: '>=18'} devalue@5.6.3: - resolution: - { - integrity: sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==, - } + resolution: {integrity: sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==} devlop@1.1.0: - resolution: - { - integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==, - } + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} diff@8.0.3: - resolution: - { - integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==, - } - engines: { node: ">=0.3.1" } + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} + engines: {node: '>=0.3.1'} direction@2.0.1: - resolution: - { - integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==, - } + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} hasBin: true dlv@1.1.3: - resolution: - { - integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, - } + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} dom-serializer@2.0.0: - resolution: - { - integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, - } + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} domelementtype@2.3.0: - resolution: - { - integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, - } + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} domhandler@5.0.3: - resolution: - { - integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, - } - engines: { node: ">= 4" } + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} domutils@3.2.2: - resolution: - { - integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==, - } + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} dotenv@16.6.1: - resolution: - { - integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} dset@3.1.4: - resolution: - { - integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} dunder-proto@1.0.1: - resolution: - { - integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} eastasianwidth@0.2.0: - resolution: - { - integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, - } + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} ecdsa-sig-formatter@1.0.11: - resolution: - { - integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==, - } + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} edge-paths@3.0.5: - resolution: - { - integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==, - } - engines: { node: ">=14.0.0" } + resolution: {integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==} + engines: {node: '>=14.0.0'} edge-runtime@2.5.9: - resolution: - { - integrity: sha512-pk+k0oK0PVXdlT4oRp4lwh+unuKB7Ng4iZ2HB+EZ7QCEQizX360Rp/F4aRpgpRgdP2ufB35N+1KppHmYjqIGSg==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-pk+k0oK0PVXdlT4oRp4lwh+unuKB7Ng4iZ2HB+EZ7QCEQizX360Rp/F4aRpgpRgdP2ufB35N+1KppHmYjqIGSg==} + engines: {node: '>=16'} hasBin: true edgedriver@6.3.0: - resolution: - { - integrity: sha512-ggEQL+oEyIcM4nP2QC3AtCQ04o4kDNefRM3hja0odvlPSnsaxiruMxEZ93v3gDCKWYW6BXUr51PPradb+3nffw==, - } - engines: { node: ">=20.0.0" } + resolution: {integrity: sha512-ggEQL+oEyIcM4nP2QC3AtCQ04o4kDNefRM3hja0odvlPSnsaxiruMxEZ93v3gDCKWYW6BXUr51PPradb+3nffw==} + engines: {node: '>=20.0.0'} hasBin: true + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.307: - resolution: - { - integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==, - } + resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} emmet@2.4.11: - resolution: - { - integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==, - } + resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} emoji-regex@10.6.0: - resolution: - { - integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==, - } + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} emoji-regex@8.0.0: - resolution: - { - integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, - } + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} emoji-regex@9.2.2: - resolution: - { - integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, - } + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} encoding-sniffer@0.2.1: - resolution: - { - integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==, - } + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} end-of-stream@1.1.0: - resolution: - { - integrity: sha512-EoulkdKF/1xa92q25PbjuDcgJ9RDHYU2Rs3SCIvs2/dSQ3BpmxneNHmA/M7fe60M3PrV7nNGTTNbkK62l6vXiQ==, - } + resolution: {integrity: sha512-EoulkdKF/1xa92q25PbjuDcgJ9RDHYU2Rs3SCIvs2/dSQ3BpmxneNHmA/M7fe60M3PrV7nNGTTNbkK62l6vXiQ==} end-of-stream@1.4.5: - resolution: - { - integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==, - } + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} enhanced-resolve@5.20.1: - resolution: - { - integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==, - } - engines: { node: ">=10.13.0" } + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + engines: {node: '>=10.13.0'} entities@4.5.0: - resolution: - { - integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, - } - engines: { node: ">=0.12" } + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} entities@6.0.1: - resolution: - { - integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==, - } - engines: { node: ">=0.12" } + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} entities@7.0.1: - resolution: - { - integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==, - } - engines: { node: ">=0.12" } + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} environment@1.1.0: - resolution: - { - integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} es-define-property@1.0.1: - resolution: - { - integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} es-errors@1.3.0: - resolution: - { - integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} es-module-lexer@1.4.1: - resolution: - { - integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==, - } + resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} es-module-lexer@1.7.0: - resolution: - { - integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==, - } + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} es-module-lexer@2.0.0: - resolution: - { - integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==, - } + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} es-object-atoms@1.1.1: - resolution: - { - integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} es-set-tostringtag@2.1.0: - resolution: - { - integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} esast-util-from-estree@2.0.0: - resolution: - { - integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==, - } + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} esast-util-from-js@2.0.1: - resolution: - { - integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==, - } + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} esbuild@0.25.12: - resolution: - { - integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} hasBin: true esbuild@0.27.0: - resolution: - { - integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==} + engines: {node: '>=18'} hasBin: true esbuild@0.27.3: - resolution: - { - integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} hasBin: true escalade@3.2.0: - resolution: - { - integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} escape-string-regexp@5.0.0: - resolution: - { - integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} escodegen@2.1.0: - resolution: - { - integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==, - } - engines: { node: ">=6.0" } + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} hasBin: true eslint-scope@5.1.1: - resolution: - { - integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==, - } - engines: { node: ">=8.0.0" } + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} esprima@4.0.1: - resolution: - { - integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} hasBin: true esrecurse@4.3.0: - resolution: - { - integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, - } - engines: { node: ">=4.0" } + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} estraverse@4.3.0: - resolution: - { - integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==, - } - engines: { node: ">=4.0" } + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} estraverse@5.3.0: - resolution: - { - integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, - } - engines: { node: ">=4.0" } + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} estree-util-attach-comments@3.0.0: - resolution: - { - integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==, - } + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} estree-util-build-jsx@3.0.1: - resolution: - { - integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==, - } + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} estree-util-is-identifier-name@3.0.0: - resolution: - { - integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==, - } + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} estree-util-scope@1.0.0: - resolution: - { - integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==, - } + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} estree-util-to-js@2.0.0: - resolution: - { - integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==, - } + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} estree-util-visit@2.0.0: - resolution: - { - integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==, - } + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} estree-walker@2.0.2: - resolution: - { - integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==, - } + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} estree-walker@3.0.3: - resolution: - { - integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==, - } + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} esutils@2.0.3: - resolution: - { - integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} etag@1.8.1: - resolution: - { - integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==, - } - engines: { node: ">= 0.6" } + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} event-target-shim@5.0.1: - resolution: - { - integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} eventemitter3@4.0.7: - resolution: - { - integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==, - } + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} eventemitter3@5.0.4: - resolution: - { - integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==, - } + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} events-intercept@2.0.0: - resolution: - { - integrity: sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==, - } + resolution: {integrity: sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==} events-universal@1.0.1: - resolution: - { - integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==, - } + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} events@3.3.0: - resolution: - { - integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, - } - engines: { node: ">=0.8.x" } + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} eventsource-parser@3.0.6: - resolution: - { - integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==, - } - engines: { node: ">=18.0.0" } + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} execa@3.2.0: - resolution: - { - integrity: sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==, - } - engines: { node: ^8.12.0 || >=9.7.0 } + resolution: {integrity: sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==} + engines: {node: ^8.12.0 || >=9.7.0} execa@5.1.1: - resolution: - { - integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} expand-template@2.0.3: - resolution: - { - integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} expect-type@1.3.0: - resolution: - { - integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==, - } - engines: { node: ">=12.0.0" } + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + express-rate-limit@8.3.1: + resolution: {integrity: sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} expressive-code@0.41.7: - resolution: - { - integrity: sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA==, - } + resolution: {integrity: sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA==} extend-shallow@2.0.1: - resolution: - { - integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} extend@3.0.2: - resolution: - { - integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==, - } + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} extract-zip@2.0.1: - resolution: - { - integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==, - } - engines: { node: ">= 10.17.0" } + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} hasBin: true fast-deep-equal@2.0.1: - resolution: - { - integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==, - } + resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} fast-deep-equal@3.1.3: - resolution: - { - integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, - } + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-fifo@1.3.2: - resolution: - { - integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==, - } + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} fast-glob@3.3.3: - resolution: - { - integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, - } - engines: { node: ">=8.6.0" } + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} fast-uri@3.1.0: - resolution: - { - integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==, - } + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} fast-xml-builder@1.0.0: - resolution: - { - integrity: sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==, - } + resolution: {integrity: sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==} fast-xml-parser@5.4.1: - resolution: - { - integrity: sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==, - } + resolution: {integrity: sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==} hasBin: true fast-xml-parser@5.4.2: - resolution: - { - integrity: sha512-pw/6pIl4k0CSpElPEJhDppLzaixDEuWui2CUQQBH/ECDf7+y6YwA4Gf7Tyb0Rfe4DIMuZipYj4AEL0nACKglvQ==, - } + resolution: {integrity: sha512-pw/6pIl4k0CSpElPEJhDppLzaixDEuWui2CUQQBH/ECDf7+y6YwA4Gf7Tyb0Rfe4DIMuZipYj4AEL0nACKglvQ==} hasBin: true fastq@1.20.1: - resolution: - { - integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==, - } + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fd-slicer@1.1.0: - resolution: - { - integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==, - } + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} fdir@6.5.0: - resolution: - { - integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, - } - engines: { node: ">=12.0.0" } + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -6896,1830 +4307,1050 @@ packages: optional: true fetch-blob@3.2.0: - resolution: - { - integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==, - } - engines: { node: ^12.20 || >= 14.13 } + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} file-type@21.3.0: - resolution: - { - integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} + engines: {node: '>=20'} file-uri-to-path@1.0.0: - resolution: - { - integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==, - } + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} fill-range@7.1.1: - resolution: - { - integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} find-up@5.0.0: - resolution: - { - integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} fix-dts-default-cjs-exports@1.0.1: - resolution: - { - integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==, - } + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} flattie@1.1.1: - resolution: - { - integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} follow-redirects@1.15.11: - resolution: - { - integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==, - } - engines: { node: ">=4.0" } + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} peerDependencies: - debug: "*" + debug: '*' peerDependenciesMeta: debug: optional: true fontace@0.4.1: - resolution: - { - integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==, - } + resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} fontkitten@1.0.3: - resolution: - { - integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} foreground-child@3.3.1: - resolution: - { - integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, - } - engines: { node: ">=14" } + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} form-data@4.0.5: - resolution: - { - integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} formdata-polyfill@4.0.10: - resolution: - { - integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==, - } - engines: { node: ">=12.20.0" } + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} forwarded-parse@2.1.2: - resolution: - { - integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==, - } + resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} fs-constants@1.0.0: - resolution: - { - integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==, - } + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} fs-extra@11.1.0: - resolution: - { - integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==, - } - engines: { node: ">=14.14" } + resolution: {integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==} + engines: {node: '>=14.14'} fs-extra@11.1.1: - resolution: - { - integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==, - } - engines: { node: ">=14.14" } + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} + engines: {node: '>=14.14'} fsevents@2.3.3: - resolution: - { - integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, - } - engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] function-bind@1.1.2: - resolution: - { - integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, - } + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} gaxios@7.1.3: - resolution: - { - integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} + engines: {node: '>=18'} gcp-metadata@8.1.2: - resolution: - { - integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} geckodriver@6.1.0: - resolution: - { - integrity: sha512-ZRXLa4ZaYTTgUO4Eefw+RsQCleugU2QLb1ME7qTYxxuRj51yAhfnXaItXNs5/vUzfIaDHuZ+YnSF005hfp07nQ==, - } - engines: { node: ">=20.0.0" } + resolution: {integrity: sha512-ZRXLa4ZaYTTgUO4Eefw+RsQCleugU2QLb1ME7qTYxxuRj51yAhfnXaItXNs5/vUzfIaDHuZ+YnSF005hfp07nQ==} + engines: {node: '>=20.0.0'} hasBin: true generic-pool@3.4.2: - resolution: - { - integrity: sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag==, - } - engines: { node: ">= 4" } + resolution: {integrity: sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag==} + engines: {node: '>= 4'} gensync@1.0.0-beta.2: - resolution: - { - integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, - } - engines: { node: ">=6.9.0" } + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} get-caller-file@2.0.5: - resolution: - { - integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, - } - engines: { node: 6.* || 8.* || >= 10.* } + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} get-east-asian-width@1.5.0: - resolution: - { - integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} get-intrinsic@1.3.0: - resolution: - { - integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} get-port@7.1.0: - resolution: - { - integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + engines: {node: '>=16'} get-proto@1.0.1: - resolution: - { - integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} get-stream@5.2.0: - resolution: - { - integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} get-stream@6.0.1: - resolution: - { - integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} get-tsconfig@4.13.6: - resolution: - { - integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==, - } + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} get-uri@6.0.5: - resolution: - { - integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} + engines: {node: '>= 14'} github-from-package@0.0.0: - resolution: - { - integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==, - } + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} github-slugger@2.0.0: - resolution: - { - integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==, - } + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} glob-parent@5.1.2: - resolution: - { - integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} glob-to-regexp@0.4.1: - resolution: - { - integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==, - } + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} glob@10.5.0: - resolution: - { - integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==, - } + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@13.0.6: - resolution: - { - integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==, - } - engines: { node: 18 || 20 || >=22 } + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} google-auth-library@10.6.1: - resolution: - { - integrity: sha512-5awwuLrzNol+pFDmKJd0dKtZ0fPLAtoA5p7YO4ODsDu6ONJUVqbYwvv8y2ZBO5MBNp9TJXigB19710kYpBPdtA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-5awwuLrzNol+pFDmKJd0dKtZ0fPLAtoA5p7YO4ODsDu6ONJUVqbYwvv8y2ZBO5MBNp9TJXigB19710kYpBPdtA==} + engines: {node: '>=18'} google-logging-utils@1.1.3: - resolution: - { - integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==, - } - engines: { node: ">=14" } + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} gopd@1.2.0: - resolution: - { - integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} graceful-fs@4.2.11: - resolution: - { - integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, - } + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} graceful-readlink@1.0.1: - resolution: - { - integrity: sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==, - } + resolution: {integrity: sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==} grapheme-splitter@1.0.4: - resolution: - { - integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==, - } + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} graphql@16.13.1: - resolution: - { - integrity: sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ==, - } - engines: { node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0 } + resolution: {integrity: sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} gray-matter@4.0.3: - resolution: - { - integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==, - } - engines: { node: ">=6.0" } + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} h3@1.15.5: - resolution: - { - integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==, - } + resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==} has-flag@4.0.0: - resolution: - { - integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} has-symbols@1.1.0: - resolution: - { - integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} has-tostringtag@1.0.2: - resolution: - { - integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} hasown@2.0.2: - resolution: - { - integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} hast-util-embedded@3.0.0: - resolution: - { - integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==, - } + resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} hast-util-format@1.1.0: - resolution: - { - integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==, - } + resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} hast-util-from-html@2.0.3: - resolution: - { - integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==, - } + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} hast-util-from-parse5@8.0.3: - resolution: - { - integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==, - } + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} hast-util-has-property@3.0.0: - resolution: - { - integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==, - } + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} hast-util-is-body-ok-link@3.0.1: - resolution: - { - integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==, - } + resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} hast-util-is-element@3.0.0: - resolution: - { - integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==, - } + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} hast-util-minify-whitespace@1.0.1: - resolution: - { - integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==, - } + resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} hast-util-parse-selector@4.0.0: - resolution: - { - integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==, - } + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} hast-util-phrasing@3.0.1: - resolution: - { - integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==, - } + resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} hast-util-raw@9.1.0: - resolution: - { - integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==, - } + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} hast-util-select@6.0.4: - resolution: - { - integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==, - } + resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} hast-util-to-estree@3.1.3: - resolution: - { - integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==, - } + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} hast-util-to-html@9.0.5: - resolution: - { - integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==, - } + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} hast-util-to-jsx-runtime@2.3.6: - resolution: - { - integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==, - } + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} hast-util-to-parse5@8.0.1: - resolution: - { - integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==, - } + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} hast-util-to-string@3.0.1: - resolution: - { - integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==, - } + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} hast-util-to-text@4.0.2: - resolution: - { - integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==, - } + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} hast-util-whitespace@3.0.0: - resolution: - { - integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==, - } + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} hastscript@9.0.1: - resolution: - { - integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==, - } + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} he@1.2.0: - resolution: - { - integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==, - } + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true headers-polyfill@4.0.3: - resolution: - { - integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==, - } + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + + hono@4.12.8: + resolution: {integrity: sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==} + engines: {node: '>=16.9.0'} html-escaper@3.0.3: - resolution: - { - integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==, - } + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} html-void-elements@3.0.0: - resolution: - { - integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==, - } + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} html-whitespace-sensitive-tag-names@3.0.1: - resolution: - { - integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==, - } + resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} htmlfy@0.8.1: - resolution: - { - integrity: sha512-xWROBw9+MEGwxpotll0h672KCaLrKKiCYzsyN8ZgL9cQbVumFnyvsk2JqiB9ELAV1GLj1GG/jxZUjV9OZZi/yQ==, - } + resolution: {integrity: sha512-xWROBw9+MEGwxpotll0h672KCaLrKKiCYzsyN8ZgL9cQbVumFnyvsk2JqiB9ELAV1GLj1GG/jxZUjV9OZZi/yQ==} htmlparser2@10.1.0: - resolution: - { - integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==, - } + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} http-cache-semantics@4.2.0: - resolution: - { - integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==, - } + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} http-errors@1.7.3: - resolution: - { - integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==, - } - engines: { node: ">= 0.6" } + resolution: {integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==} + engines: {node: '>= 0.6'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} http-proxy-agent@7.0.2: - resolution: - { - integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} https-proxy-agent@5.0.1: - resolution: - { - integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} https-proxy-agent@7.0.6: - resolution: - { - integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} human-signals@1.1.1: - resolution: - { - integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==, - } - engines: { node: ">=8.12.0" } + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} human-signals@2.1.0: - resolution: - { - integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==, - } - engines: { node: ">=10.17.0" } + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} i18next@23.16.8: - resolution: - { - integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==, - } + resolution: {integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==} iconv-lite@0.4.24: - resolution: - { - integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} iconv-lite@0.6.3: - resolution: - { - integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} ieee754@1.2.1: - resolution: - { - integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, - } + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} immediate@3.0.6: - resolution: - { - integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, - } + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} import-in-the-middle@2.0.6: - resolution: - { - integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==, - } + resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} import-in-the-middle@3.0.0: - resolution: - { - integrity: sha512-OnGy+eYT7wVejH2XWgLRgbmzujhhVIATQH0ztIeRilwHBjTeG3pD+XnH3PKX0r9gJ0BuJmJ68q/oh9qgXnNDQg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-OnGy+eYT7wVejH2XWgLRgbmzujhhVIATQH0ztIeRilwHBjTeG3pD+XnH3PKX0r9gJ0BuJmJ68q/oh9qgXnNDQg==} + engines: {node: '>=18'} import-meta-resolve@4.2.0: - resolution: - { - integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==, - } + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} inherits@2.0.4: - resolution: - { - integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, - } + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} ini@1.3.8: - resolution: - { - integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, - } + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} ini@6.0.0: - resolution: - { - integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==, - } - engines: { node: ^20.17.0 || >=22.9.0 } + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} inline-style-parser@0.2.7: - resolution: - { - integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==, - } + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} ip-address@10.1.0: - resolution: - { - integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==, - } - engines: { node: ">= 12" } + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} iron-webcrypto@1.2.1: - resolution: - { - integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==, - } + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} is-alphabetical@2.0.1: - resolution: - { - integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==, - } + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} is-alphanumerical@2.0.1: - resolution: - { - integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==, - } + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} is-buffer@2.0.5: - resolution: - { - integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} is-decimal@2.0.1: - resolution: - { - integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==, - } + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} is-docker@3.0.0: - resolution: - { - integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==, - } - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true is-electron@2.2.2: - resolution: - { - integrity: sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==, - } + resolution: {integrity: sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==} is-extendable@0.1.1: - resolution: - { - integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} is-extglob@2.1.1: - resolution: - { - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} is-fullwidth-code-point@3.0.0: - resolution: - { - integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} is-fullwidth-code-point@5.1.0: - resolution: - { - integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} is-glob@4.0.3: - resolution: - { - integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} is-hexadecimal@2.0.1: - resolution: - { - integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==, - } + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} is-inside-container@1.0.0: - resolution: - { - integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==, - } - engines: { node: ">=14.16" } + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} hasBin: true is-node-process@1.2.0: - resolution: - { - integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==, - } + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} is-number@7.0.0: - resolution: - { - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, - } - engines: { node: ">=0.12.0" } + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} is-plain-obj@4.1.0: - resolution: - { - integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} is-reference@1.2.1: - resolution: - { - integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==, - } + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} is-stream@2.0.1: - resolution: - { - integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} is-wsl@3.1.1: - resolution: - { - integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} isarray@1.0.0: - resolution: - { - integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, - } + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} isexe@2.0.0: - resolution: - { - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, - } + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} isexe@3.1.5: - resolution: - { - integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} isexe@4.0.0: - resolution: - { - integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} + engines: {node: '>=20'} jackspeak@3.4.3: - resolution: - { - integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==, - } + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} jest-worker@27.5.1: - resolution: - { - integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==, - } - engines: { node: ">= 10.13.0" } + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} jiti@2.6.1: - resolution: - { - integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==, - } + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true jose@5.9.6: - resolution: - { - integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==, - } + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + + jose@6.2.1: + resolution: {integrity: sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==} joycon@3.1.1: - resolution: - { - integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} js-tokens@4.0.0: - resolution: - { - integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, - } + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} js-yaml@3.14.2: - resolution: - { - integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==, - } + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true js-yaml@4.1.1: - resolution: - { - integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==, - } + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true jsesc@3.1.0: - resolution: - { - integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} hasBin: true json-bigint@1.0.0: - resolution: - { - integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==, - } + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} json-parse-even-better-errors@2.3.1: - resolution: - { - integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, - } + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} json-schema-to-ts@1.6.4: - resolution: - { - integrity: sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==, - } + resolution: {integrity: sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==} json-schema-to-ts@3.1.1: - resolution: - { - integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} json-schema-traverse@1.0.0: - resolution: - { - integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, - } + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} json-schema@0.4.0: - resolution: - { - integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==, - } + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} json5@2.2.3: - resolution: - { - integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} hasBin: true jsonc-parser@2.3.1: - resolution: - { - integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==, - } + resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} jsonc-parser@3.3.1: - resolution: - { - integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==, - } + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} jsonfile@6.2.0: - resolution: - { - integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==, - } + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} jsonlines@0.1.1: - resolution: - { - integrity: sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==, - } + resolution: {integrity: sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==} jszip@3.10.1: - resolution: - { - integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==, - } + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} just-bash@2.13.1: - resolution: - { - integrity: sha512-NxfMRnZhSXqfdLcMuBK/w0TIzlCSlP51mq/dqjbjgWL12P5ObCHDjgXi0Yqlg6+/2j29WQZs9Rt9qbNkccpM/g==, - } + resolution: {integrity: sha512-NxfMRnZhSXqfdLcMuBK/w0TIzlCSlP51mq/dqjbjgWL12P5ObCHDjgXi0Yqlg6+/2j29WQZs9Rt9qbNkccpM/g==} hasBin: true jwa@2.0.1: - resolution: - { - integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==, - } + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} jws@4.0.1: - resolution: - { - integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==, - } + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} kind-of@6.0.3: - resolution: - { - integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} kleur@3.0.3: - resolution: - { - integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} kleur@4.1.5: - resolution: - { - integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} klona@2.0.6: - resolution: - { - integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==, - } - engines: { node: ">= 8" } + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} lazystream@1.0.1: - resolution: - { - integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==, - } - engines: { node: ">= 0.6.3" } + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} lie@3.3.0: - resolution: - { - integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==, - } + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} lilconfig@3.1.3: - resolution: - { - integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==, - } - engines: { node: ">=14" } + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} lines-and-columns@1.2.4: - resolution: - { - integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, - } + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} linkify-it@5.0.0: - resolution: - { - integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==, - } + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} lint-staged@16.3.2: - resolution: - { - integrity: sha512-xKqhC2AeXLwiAHXguxBjuChoTTWFC6Pees0SHPwOpwlvI3BH7ZADFPddAdN3pgo3aiKgPUx/bxE78JfUnxQnlg==, - } - engines: { node: ">=20.17" } + resolution: {integrity: sha512-xKqhC2AeXLwiAHXguxBjuChoTTWFC6Pees0SHPwOpwlvI3BH7ZADFPddAdN3pgo3aiKgPUx/bxE78JfUnxQnlg==} + engines: {node: '>=20.17'} hasBin: true listr2@9.0.5: - resolution: - { - integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==, - } - engines: { node: ">=20.0.0" } + resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} + engines: {node: '>=20.0.0'} load-tsconfig@0.2.5: - resolution: - { - integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==, - } - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} loader-runner@4.3.1: - resolution: - { - integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==, - } - engines: { node: ">=6.11.5" } + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} + engines: {node: '>=6.11.5'} locate-app@2.5.0: - resolution: - { - integrity: sha512-xIqbzPMBYArJRmPGUZD9CzV9wOqmVtQnaAn3wrj3s6WYW0bQvPI7x+sPYUGmDTYMHefVK//zc6HEYZ1qnxIK+Q==, - } + resolution: {integrity: sha512-xIqbzPMBYArJRmPGUZD9CzV9wOqmVtQnaAn3wrj3s6WYW0bQvPI7x+sPYUGmDTYMHefVK//zc6HEYZ1qnxIK+Q==} locate-path@6.0.0: - resolution: - { - integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} lodash.clonedeep@4.5.0: - resolution: - { - integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==, - } + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} lodash.zip@4.2.0: - resolution: - { - integrity: sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==, - } + resolution: {integrity: sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==} lodash@4.17.21: - resolution: - { - integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, - } + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} log-update@6.1.0: - resolution: - { - integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} loglevel-plugin-prefix@0.8.4: - resolution: - { - integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==, - } + resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} loglevel@1.9.2: - resolution: - { - integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==, - } - engines: { node: ">= 0.6.0" } + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} long@5.3.2: - resolution: - { - integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==, - } + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} longest-streak@3.1.0: - resolution: - { - integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==, - } + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} lru-cache@10.4.3: - resolution: - { - integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, - } + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@11.2.6: - resolution: - { - integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + engines: {node: 20 || >=22} lru-cache@5.1.1: - resolution: - { - integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, - } + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} lru-cache@6.0.0: - resolution: - { - integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} lru-cache@7.18.3: - resolution: - { - integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} lunr@2.3.9: - resolution: - { - integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==, - } + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} luxon@3.7.2: - resolution: - { - integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} + engines: {node: '>=12'} magic-string@0.30.21: - resolution: - { - integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==, - } + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} magicast@0.5.2: - resolution: - { - integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==, - } + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} markdown-extensions@2.0.0: - resolution: - { - integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} markdown-it@14.1.1: - resolution: - { - integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==, - } + resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} hasBin: true markdown-table@3.0.4: - resolution: - { - integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==, - } + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} math-intrinsics@1.1.0: - resolution: - { - integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} mdast-util-definitions@6.0.0: - resolution: - { - integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==, - } + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} mdast-util-directive@3.1.0: - resolution: - { - integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==, - } + resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} mdast-util-find-and-replace@3.0.2: - resolution: - { - integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==, - } + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} mdast-util-from-markdown@2.0.3: - resolution: - { - integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==, - } + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} mdast-util-gfm-autolink-literal@2.0.1: - resolution: - { - integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==, - } + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} mdast-util-gfm-footnote@2.1.0: - resolution: - { - integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==, - } + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} mdast-util-gfm-strikethrough@2.0.0: - resolution: - { - integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==, - } + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} mdast-util-gfm-table@2.0.0: - resolution: - { - integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==, - } + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} mdast-util-gfm-task-list-item@2.0.0: - resolution: - { - integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==, - } + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} mdast-util-gfm@3.1.0: - resolution: - { - integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==, - } + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} mdast-util-mdx-expression@2.0.1: - resolution: - { - integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==, - } + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} mdast-util-mdx-jsx@3.2.0: - resolution: - { - integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==, - } + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} mdast-util-mdx@3.0.0: - resolution: - { - integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==, - } + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} mdast-util-mdxjs-esm@2.0.1: - resolution: - { - integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==, - } + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} mdast-util-phrasing@4.1.0: - resolution: - { - integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==, - } + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} mdast-util-to-hast@13.2.1: - resolution: - { - integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==, - } + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} mdast-util-to-markdown@2.1.2: - resolution: - { - integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==, - } + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} mdast-util-to-string@4.0.0: - resolution: - { - integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==, - } + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} mdn-data@2.0.28: - resolution: - { - integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==, - } + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} mdn-data@2.27.1: - resolution: - { - integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==, - } + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} mdurl@2.0.0: - resolution: - { - integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==, - } + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} merge-stream@2.0.0: - resolution: - { - integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, - } + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} merge2@1.4.1: - resolution: - { - integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, - } - engines: { node: ">= 8" } + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} micro@9.3.5-canary.3: - resolution: - { - integrity: sha512-viYIo9PefV+w9dvoIBh1gI44Mvx1BOk67B4BpC2QK77qdY0xZF0Q+vWLt/BII6cLkIc8rLmSIcJaB/OrXXKe1g==, - } - engines: { node: ">= 8.0.0" } + resolution: {integrity: sha512-viYIo9PefV+w9dvoIBh1gI44Mvx1BOk67B4BpC2QK77qdY0xZF0Q+vWLt/BII6cLkIc8rLmSIcJaB/OrXXKe1g==} + engines: {node: '>= 8.0.0'} hasBin: true micromark-core-commonmark@2.0.3: - resolution: - { - integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==, - } + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} micromark-extension-directive@3.0.2: - resolution: - { - integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==, - } + resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==} micromark-extension-gfm-autolink-literal@2.1.0: - resolution: - { - integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==, - } + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} micromark-extension-gfm-footnote@2.1.0: - resolution: - { - integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==, - } + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} micromark-extension-gfm-strikethrough@2.1.0: - resolution: - { - integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==, - } + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} micromark-extension-gfm-table@2.1.1: - resolution: - { - integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==, - } + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} micromark-extension-gfm-tagfilter@2.0.0: - resolution: - { - integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==, - } + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} micromark-extension-gfm-task-list-item@2.1.0: - resolution: - { - integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==, - } + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} micromark-extension-gfm@3.0.0: - resolution: - { - integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==, - } + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} micromark-extension-mdx-expression@3.0.1: - resolution: - { - integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==, - } + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} micromark-extension-mdx-jsx@3.0.2: - resolution: - { - integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==, - } + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} micromark-extension-mdx-md@2.0.0: - resolution: - { - integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==, - } + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} micromark-extension-mdxjs-esm@3.0.0: - resolution: - { - integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==, - } + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} micromark-extension-mdxjs@3.0.0: - resolution: - { - integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==, - } + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} micromark-factory-destination@2.0.1: - resolution: - { - integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==, - } + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} micromark-factory-label@2.0.1: - resolution: - { - integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==, - } + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} micromark-factory-mdx-expression@2.0.3: - resolution: - { - integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==, - } + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} micromark-factory-space@2.0.1: - resolution: - { - integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==, - } + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} micromark-factory-title@2.0.1: - resolution: - { - integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==, - } + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} micromark-factory-whitespace@2.0.1: - resolution: - { - integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==, - } + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} micromark-util-character@2.1.1: - resolution: - { - integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==, - } + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} micromark-util-chunked@2.0.1: - resolution: - { - integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==, - } + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} micromark-util-classify-character@2.0.1: - resolution: - { - integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==, - } + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} micromark-util-combine-extensions@2.0.1: - resolution: - { - integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==, - } + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} micromark-util-decode-numeric-character-reference@2.0.2: - resolution: - { - integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==, - } + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} micromark-util-decode-string@2.0.1: - resolution: - { - integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==, - } + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} micromark-util-encode@2.0.1: - resolution: - { - integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==, - } + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} micromark-util-events-to-acorn@2.0.3: - resolution: - { - integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==, - } + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} micromark-util-html-tag-name@2.0.1: - resolution: - { - integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==, - } + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} micromark-util-normalize-identifier@2.0.1: - resolution: - { - integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==, - } + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} micromark-util-resolve-all@2.0.1: - resolution: - { - integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==, - } + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} micromark-util-sanitize-uri@2.0.1: - resolution: - { - integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==, - } + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} micromark-util-subtokenize@2.1.0: - resolution: - { - integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==, - } + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} micromark-util-symbol@2.0.1: - resolution: - { - integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==, - } + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} micromark-util-types@2.0.2: - resolution: - { - integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==, - } + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} micromark@4.0.2: - resolution: - { - integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==, - } + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} micromatch@4.0.8: - resolution: - { - integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, - } - engines: { node: ">=8.6" } + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} mime-db@1.52.0: - resolution: - { - integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, - } - engines: { node: ">= 0.6" } + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} mime-types@2.1.35: - resolution: - { - integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, - } - engines: { node: ">= 0.6" } + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} mimic-fn@2.1.0: - resolution: - { - integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} mimic-function@5.0.1: - resolution: - { - integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} mimic-response@3.1.0: - resolution: - { - integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} minimatch@10.1.1: - resolution: - { - integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==, - } - engines: { node: 20 || >=22 } + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} minimatch@10.2.4: - resolution: - { - integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==, - } - engines: { node: 18 || 20 || >=22 } + resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + engines: {node: 18 || 20 || >=22} minimatch@3.1.5: - resolution: - { - integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==, - } + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} minimatch@5.1.9: - resolution: - { - integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} minimatch@9.0.9: - resolution: - { - integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==, - } - engines: { node: ">=16 || 14 >=14.17" } + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: - resolution: - { - integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, - } + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} minipass@7.1.3: - resolution: - { - integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==, - } - engines: { node: ">=16 || 14 >=14.17" } + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} minizlib@3.1.0: - resolution: - { - integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==, - } - engines: { node: ">= 18" } + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} mitt@3.0.1: - resolution: - { - integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==, - } + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} mixpart@0.0.5: - resolution: - { - integrity: sha512-TpWi9/2UIr7VWCVAM7NB4WR4yOglAetBkuKfxs3K0vFcUukqAaW1xsgX0v1gNGiDKzYhPHFcHgarC7jmnaOy4w==, - } - engines: { node: ">=20.0.0" } + resolution: {integrity: sha512-TpWi9/2UIr7VWCVAM7NB4WR4yOglAetBkuKfxs3K0vFcUukqAaW1xsgX0v1gNGiDKzYhPHFcHgarC7jmnaOy4w==} + engines: {node: '>=20.0.0'} mkdirp-classic@0.5.3: - resolution: - { - integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==, - } + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} mkdirp@1.0.4: - resolution: - { - integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} hasBin: true mlly@1.8.1: - resolution: - { - integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==, - } + resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} modern-tar@0.7.5: - resolution: - { - integrity: sha512-YTefgdpKKFgoTDbEUqXqgUJct2OG6/4hs4XWLsxcHkDLj/x/V8WmKIRppPnXP5feQ7d1vuYWSp3qKkxfwaFaxA==, - } - engines: { node: ">=18.0.0" } + resolution: {integrity: sha512-YTefgdpKKFgoTDbEUqXqgUJct2OG6/4hs4XWLsxcHkDLj/x/V8WmKIRppPnXP5feQ7d1vuYWSp3qKkxfwaFaxA==} + engines: {node: '>=18.0.0'} module-details-from-path@1.0.4: - resolution: - { - integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==, - } + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} mri@1.2.0: - resolution: - { - integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} mrmime@2.0.1: - resolution: - { - integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} ms@2.1.1: - resolution: - { - integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==, - } + resolution: {integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==} ms@2.1.2: - resolution: - { - integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, - } + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} ms@2.1.3: - resolution: - { - integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, - } + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} msw@2.12.13: - resolution: - { - integrity: sha512-9CV2mXT9+z0J26MQDfEZZkj/psJ5Er/w0w+t95FWdaGH/DTlhNZBx8vBO5jSYv8AZEnl3ouX+AaTT68KXdAIag==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-9CV2mXT9+z0J26MQDfEZZkj/psJ5Er/w0w+t95FWdaGH/DTlhNZBx8vBO5jSYv8AZEnl3ouX+AaTT68KXdAIag==} + engines: {node: '>=18'} hasBin: true peerDependencies: - typescript: ">= 4.8.x" + typescript: '>= 4.8.x' peerDependenciesMeta: typescript: optional: true muggle-string@0.4.1: - resolution: - { - integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==, - } + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} mute-stream@2.0.0: - resolution: - { - integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==, - } - engines: { node: ^18.17.0 || >=20.5.0 } + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} mz@2.7.0: - resolution: - { - integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, - } + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} nanoid@3.3.11: - resolution: - { - integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, - } - engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true napi-build-utils@2.0.0: - resolution: - { - integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==, - } + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} neo-async@2.6.2: - resolution: - { - integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, - } + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} neotraverse@0.6.18: - resolution: - { - integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} + engines: {node: '>= 10'} netmask@2.0.2: - resolution: - { - integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==, - } - engines: { node: ">= 0.4.0" } + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} next@16.1.7: - resolution: - { - integrity: sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg==, - } - engines: { node: ">=20.9.0" } + resolution: {integrity: sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg==} + engines: {node: '>=20.9.0'} hasBin: true peerDependencies: - "@opentelemetry/api": ^1.1.0 - "@playwright/test": ^1.51.1 - babel-plugin-react-compiler: "*" + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 sass: ^1.3.0 peerDependenciesMeta: - "@opentelemetry/api": + '@opentelemetry/api': optional: true - "@playwright/test": + '@playwright/test': optional: true babel-plugin-react-compiler: optional: true @@ -8727,45 +5358,27 @@ packages: optional: true nlcst-to-string@4.0.0: - resolution: - { - integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==, - } + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} node-abi@3.87.0: - resolution: - { - integrity: sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==} + engines: {node: '>=10'} node-addon-api@8.6.0: - resolution: - { - integrity: sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==, - } - engines: { node: ^18 || ^20 || >= 21 } + resolution: {integrity: sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==} + engines: {node: ^18 || ^20 || >= 21} node-domexception@1.0.0: - resolution: - { - integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==, - } - engines: { node: ">=10.5.0" } + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead node-fetch-native@1.6.7: - resolution: - { - integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==, - } + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} node-fetch@2.6.7: - resolution: - { - integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==, - } - engines: { node: 4.x || >=6.0.0 } + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + engines: {node: 4.x || >=6.0.0} peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -8773,11 +5386,8 @@ packages: optional: true node-fetch@2.6.9: - resolution: - { - integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==, - } - engines: { node: 4.x || >=6.0.0 } + resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} + engines: {node: 4.x || >=6.0.0} peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -8785,11 +5395,8 @@ packages: optional: true node-fetch@2.7.0: - resolution: - { - integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==, - } - engines: { node: 4.x || >=6.0.0 } + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -8797,162 +5404,98 @@ packages: optional: true node-fetch@3.3.2: - resolution: - { - integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==, - } - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} node-gyp-build@4.8.4: - resolution: - { - integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==, - } + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true node-html-markdown@2.0.0: - resolution: - { - integrity: sha512-DqUC3GGP7pwSYxS93SwHoP+qCw78xcMP6C6H2DuC8rPD2AweJRjBzQb5SdXpKtDlqAQ7hVotJcfhgU7hU5Gthw==, - } - engines: { node: ">=20.0.0" } + resolution: {integrity: sha512-DqUC3GGP7pwSYxS93SwHoP+qCw78xcMP6C6H2DuC8rPD2AweJRjBzQb5SdXpKtDlqAQ7hVotJcfhgU7hU5Gthw==} + engines: {node: '>=20.0.0'} node-html-parser@6.1.13: - resolution: - { - integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==, - } + resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} node-liblzma@2.2.0: - resolution: - { - integrity: sha512-s0KzNOWwOJJgPG6wxg6cKohnAl9Wk/oW1KrQaVzJBjQwVcUGPQCzpR46Ximygjqj/3KhOrtJXnYMp/xYAXp75g==, - } - engines: { node: ">=16.0.0" } + resolution: {integrity: sha512-s0KzNOWwOJJgPG6wxg6cKohnAl9Wk/oW1KrQaVzJBjQwVcUGPQCzpR46Ximygjqj/3KhOrtJXnYMp/xYAXp75g==} + engines: {node: '>=16.0.0'} hasBin: true node-mock-http@1.0.4: - resolution: - { - integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==, - } + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} node-releases@2.0.36: - resolution: - { - integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==, - } + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} node-simctl@7.7.5: - resolution: - { - integrity: sha512-lWflzDW9xLuOOvR6mTJ9efbDtO/iSCH6rEGjxFxTV0vGgz5XjoZlW2BkNCCZib0B6Y23tCOiYhYJaMQYB8FKIQ==, - } - engines: { node: ">=14", npm: ">=8" } + resolution: {integrity: sha512-lWflzDW9xLuOOvR6mTJ9efbDtO/iSCH6rEGjxFxTV0vGgz5XjoZlW2BkNCCZib0B6Y23tCOiYhYJaMQYB8FKIQ==} + engines: {node: '>=14', npm: '>=8'} nopt@8.1.0: - resolution: - { - integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==, - } - engines: { node: ^18.17.0 || >=20.5.0 } + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} hasBin: true normalize-path@3.0.0: - resolution: - { - integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} npm-run-path@4.0.1: - resolution: - { - integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} nth-check@2.1.1: - resolution: - { - integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==, - } + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} object-assign@4.1.1: - resolution: - { - integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} obug@2.1.1: - resolution: - { - integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==, - } + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} ofetch@1.5.1: - resolution: - { - integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==, - } + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} ohash@2.0.11: - resolution: - { - integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==, - } + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} ohm-js@17.5.0: - resolution: - { - integrity: sha512-l4Sa7026+6jsvYbt0PXKmL+f+ML32fD++IznLgxDhx2t9Cx6NC7zwRqblCujPHGGmkQerHoeBzRutdxaw/S72g==, - } - engines: { node: ">=0.12.1" } + resolution: {integrity: sha512-l4Sa7026+6jsvYbt0PXKmL+f+ML32fD++IznLgxDhx2t9Cx6NC7zwRqblCujPHGGmkQerHoeBzRutdxaw/S72g==} + engines: {node: '>=0.12.1'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} once@1.3.3: - resolution: - { - integrity: sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==, - } + resolution: {integrity: sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==} once@1.4.0: - resolution: - { - integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, - } + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} onetime@5.1.2: - resolution: - { - integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} onetime@7.0.0: - resolution: - { - integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} oniguruma-parser@0.12.1: - resolution: - { - integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==, - } + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} oniguruma-to-es@4.3.4: - resolution: - { - integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==, - } + resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} openai@6.26.0: - resolution: - { - integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==, - } + resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} hasBin: true peerDependencies: ws: ^8.18.0 @@ -8964,342 +5507,197 @@ packages: optional: true os-paths@4.4.0: - resolution: - { - integrity: sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==, - } - engines: { node: ">= 6.0" } + resolution: {integrity: sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==} + engines: {node: '>= 6.0'} outvariant@1.4.3: - resolution: - { - integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==, - } + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} oxc-transform@0.111.0: - resolution: - { - integrity: sha512-oa5KKSDNLHZGaiqIGAbCWXeN9IJUAz9MElWcQX90epDxdKc9Hrt/BsLj3K4gDqfAYa5dwdH+ZCFJG9hR74fiGg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + resolution: {integrity: sha512-oa5KKSDNLHZGaiqIGAbCWXeN9IJUAz9MElWcQX90epDxdKc9Hrt/BsLj3K4gDqfAYa5dwdH+ZCFJG9hR74fiGg==} + engines: {node: ^20.19.0 || >=22.12.0} p-finally@1.0.0: - resolution: - { - integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} p-finally@2.0.1: - resolution: - { - integrity: sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==} + engines: {node: '>=8'} p-limit@3.1.0: - resolution: - { - integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} p-limit@6.2.0: - resolution: - { - integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==} + engines: {node: '>=18'} p-locate@5.0.0: - resolution: - { - integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} p-queue@6.6.2: - resolution: - { - integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} p-queue@8.1.1: - resolution: - { - integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==} + engines: {node: '>=18'} p-retry@4.6.2: - resolution: - { - integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} p-timeout@3.2.0: - resolution: - { - integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} p-timeout@6.1.4: - resolution: - { - integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==, - } - engines: { node: ">=14.16" } + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} pac-proxy-agent@7.2.0: - resolution: - { - integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} + engines: {node: '>= 14'} pac-resolver@7.0.1: - resolution: - { - integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} package-json-from-dist@1.0.1: - resolution: - { - integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, - } + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} package-manager-detector@1.6.0: - resolution: - { - integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==, - } + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} pagefind@1.4.0: - resolution: - { - integrity: sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g==, - } + resolution: {integrity: sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g==} hasBin: true pako@1.0.11: - resolution: - { - integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==, - } + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} papaparse@5.5.3: - resolution: - { - integrity: sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==, - } + resolution: {integrity: sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==} parse-entities@4.0.2: - resolution: - { - integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==, - } + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} parse-latin@7.0.0: - resolution: - { - integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==, - } + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} parse-ms@2.1.0: - resolution: - { - integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} + engines: {node: '>=6'} parse5-htmlparser2-tree-adapter@7.1.0: - resolution: - { - integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==, - } + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} parse5-parser-stream@7.1.2: - resolution: - { - integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==, - } + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} parse5@7.3.0: - resolution: - { - integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==, - } + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} partial-json@0.1.7: - resolution: - { - integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==, - } + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} path-browserify@1.0.1: - resolution: - { - integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==, - } + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} path-exists@4.0.0: - resolution: - { - integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} path-key@3.1.1: - resolution: - { - integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} path-scurry@1.11.1: - resolution: - { - integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==, - } - engines: { node: ">=16 || 14 >=14.18" } + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} path-scurry@2.0.2: - resolution: - { - integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==, - } - engines: { node: 18 || 20 || >=22 } + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} path-to-regexp@6.1.0: - resolution: - { - integrity: sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==, - } + resolution: {integrity: sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==} path-to-regexp@6.3.0: - resolution: - { - integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==, - } + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} path-to-regexp@8.2.0: - resolution: - { - integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} path-to-regexp@8.3.0: - resolution: - { - integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==, - } + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} pathe@2.0.3: - resolution: - { - integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, - } + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} pend@1.2.0: - resolution: - { - integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==, - } + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} pg-int8@1.0.1: - resolution: - { - integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==, - } - engines: { node: ">=4.0.0" } + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} pg-protocol@1.13.0: - resolution: - { - integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==, - } + resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} pg-types@2.2.0: - resolution: - { - integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} piccolore@0.1.3: - resolution: - { - integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==, - } + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} picocolors@1.0.0: - resolution: - { - integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, - } + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} picocolors@1.1.1: - resolution: - { - integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, - } + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: - resolution: - { - integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, - } - engines: { node: ">=8.6" } + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} picomatch@4.0.3: - resolution: - { - integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} pip-requirements-js@1.0.3: - resolution: - { - integrity: sha512-1O9Bx0mPOZht3tW4LuxOA46qkD8A1AGymWXz3UwIMqGQgiTiOaFptsCf+9IE67qcbBrg8KHG6l8ePF7CoFRW/A==, - } + resolution: {integrity: sha512-1O9Bx0mPOZht3tW4LuxOA46qkD8A1AGymWXz3UwIMqGQgiTiOaFptsCf+9IE67qcbBrg8KHG6l8ePF7CoFRW/A==} pirates@4.0.7: - resolution: - { - integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} pkg-types@1.3.1: - resolution: - { - integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==, - } + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} playwright-core@1.58.2: - resolution: - { - integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} + engines: {node: '>=18'} hasBin: true postcss-load-config@6.0.1: - resolution: - { - integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==, - } - engines: { node: ">= 18" } + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} peerDependencies: - jiti: ">=1.21.0" - postcss: ">=8.0.9" + jiti: '>=1.21.0' + postcss: '>=8.0.9' tsx: ^4.8.1 yaml: ^2.4.2 peerDependenciesMeta: @@ -9313,1225 +5711,729 @@ packages: optional: true postcss-nested@6.2.0: - resolution: - { - integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==, - } - engines: { node: ">=12.0" } + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 postcss-selector-parser@6.1.2: - resolution: - { - integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} postcss@8.4.31: - resolution: - { - integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, - } - engines: { node: ^10 || ^12 || >=14 } + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} postcss@8.5.8: - resolution: - { - integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==, - } - engines: { node: ^10 || ^12 || >=14 } + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: - resolution: - { - integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} postgres-bytea@1.0.1: - resolution: - { - integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} postgres-date@1.0.7: - resolution: - { - integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} postgres-interval@1.2.0: - resolution: - { - integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} prebuild-install@7.1.3: - resolution: - { - integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. hasBin: true prettier@3.8.1: - resolution: - { - integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==, - } - engines: { node: ">=14" } + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} hasBin: true pretty-ms@7.0.1: - resolution: - { - integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} + engines: {node: '>=10'} prismjs@1.30.0: - resolution: - { - integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} process-nextick-args@2.0.1: - resolution: - { - integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, - } + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} process@0.11.10: - resolution: - { - integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==, - } - engines: { node: ">= 0.6.0" } + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} progress@2.0.3: - resolution: - { - integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==, - } - engines: { node: ">=0.4.0" } + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} promisepipe@3.0.0: - resolution: - { - integrity: sha512-V6TbZDJ/ZswevgkDNpGt/YqNCiZP9ASfgU+p83uJE6NrGtvSGoOcHLiDCqkMs2+yg7F5qHdLV8d0aS8O26G/KA==, - } + resolution: {integrity: sha512-V6TbZDJ/ZswevgkDNpGt/YqNCiZP9ASfgU+p83uJE6NrGtvSGoOcHLiDCqkMs2+yg7F5qHdLV8d0aS8O26G/KA==} prompts@2.4.2: - resolution: - { - integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} property-information@7.1.0: - resolution: - { - integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==, - } + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} protobufjs@7.5.4: - resolution: - { - integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==, - } - engines: { node: ">=12.0.0" } + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} proxy-agent@6.4.0: - resolution: - { - integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} + engines: {node: '>= 14'} proxy-agent@6.5.0: - resolution: - { - integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} + engines: {node: '>= 14'} proxy-from-env@1.1.0: - resolution: - { - integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, - } + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} pump@3.0.4: - resolution: - { - integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==, - } + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} punycode.js@2.3.1: - resolution: - { - integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} punycode@2.3.1: - resolution: - { - integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} query-selector-shadow-dom@1.0.1: - resolution: - { - integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==, - } + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} queue-microtask@1.2.3: - resolution: - { - integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, - } + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} quickjs-emscripten-core@0.32.0: - resolution: - { - integrity: sha512-QFnPfjFey8EqknSrSxe1hZrf1/8z7/6s1QzGOmKo6++02r7QRRX7ZoyNaZh7JuVjWsVW87KnQrbZqnHkOAzUyg==, - } + resolution: {integrity: sha512-QFnPfjFey8EqknSrSxe1hZrf1/8z7/6s1QzGOmKo6++02r7QRRX7ZoyNaZh7JuVjWsVW87KnQrbZqnHkOAzUyg==} quickjs-emscripten@0.32.0: - resolution: - { - integrity: sha512-So0Sqw869y/S2oE3Nuc0uT3Dhqgvsj8FSrwBdsuTosVsG8ME5/OcudU1GxsrIFdFABgy17GHnTVO9TYV/bLQcA==, - } - engines: { node: ">=16.0.0" } + resolution: {integrity: sha512-So0Sqw869y/S2oE3Nuc0uT3Dhqgvsj8FSrwBdsuTosVsG8ME5/OcudU1GxsrIFdFABgy17GHnTVO9TYV/bLQcA==} + engines: {node: '>=16.0.0'} radix3@1.1.2: - resolution: - { - integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==, - } + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} raw-body@2.4.1: - resolution: - { - integrity: sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==, - } - engines: { node: ">= 0.8" } + resolution: {integrity: sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==} + engines: {node: '>= 0.8'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} rc@1.2.8: - resolution: - { - integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==, - } + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true re2js@1.2.2: - resolution: - { - integrity: sha512-xvy4uuynAZWg9SuHbg0lgQncOuK6wssLmbHs8L8+YRbWLKY8Pe1avaHjNaFLOjErq8Oh0HvwQRWqIOCRL7uDDw==, - } + resolution: {integrity: sha512-xvy4uuynAZWg9SuHbg0lgQncOuK6wssLmbHs8L8+YRbWLKY8Pe1avaHjNaFLOjErq8Oh0HvwQRWqIOCRL7uDDw==} react-dom@19.2.4: - resolution: - { - integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==, - } + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: react: ^19.2.4 react@19.2.4: - resolution: - { - integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} readable-stream@2.3.8: - resolution: - { - integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, - } + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} readable-stream@3.6.2: - resolution: - { - integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} readable-stream@4.7.0: - resolution: - { - integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} readdir-glob@1.1.3: - resolution: - { - integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==, - } + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} readdirp@4.1.2: - resolution: - { - integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==, - } - engines: { node: ">= 14.18.0" } + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} readdirp@5.0.0: - resolution: - { - integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==, - } - engines: { node: ">= 20.19.0" } + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} recma-build-jsx@1.0.0: - resolution: - { - integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==, - } + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} recma-jsx@1.0.1: - resolution: - { - integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==, - } + resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 recma-parse@1.0.0: - resolution: - { - integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==, - } + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} recma-stringify@1.0.0: - resolution: - { - integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==, - } + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} redis@5.11.0: - resolution: - { - integrity: sha512-YwXjATVDT+AuxcyfOwZn046aml9jMlQPvU1VXIlLDVAExe0u93aTfPYSeRgG4p9Q/Jlkj+LXJ1XEoFV+j2JKcQ==, - } - engines: { node: ">= 18" } + resolution: {integrity: sha512-YwXjATVDT+AuxcyfOwZn046aml9jMlQPvU1VXIlLDVAExe0u93aTfPYSeRgG4p9Q/Jlkj+LXJ1XEoFV+j2JKcQ==} + engines: {node: '>= 18'} regex-recursion@6.0.2: - resolution: - { - integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==, - } + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} regex-utilities@2.3.0: - resolution: - { - integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==, - } + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} regex@6.1.0: - resolution: - { - integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==, - } + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} rehype-expressive-code@0.41.7: - resolution: - { - integrity: sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ==, - } + resolution: {integrity: sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ==} rehype-format@5.0.1: - resolution: - { - integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==, - } + resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} rehype-parse@9.0.1: - resolution: - { - integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==, - } + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} rehype-raw@7.0.0: - resolution: - { - integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==, - } + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} rehype-recma@1.0.0: - resolution: - { - integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==, - } + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} rehype-stringify@10.0.1: - resolution: - { - integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==, - } + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} rehype@13.0.2: - resolution: - { - integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==, - } + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} remark-directive@3.0.1: - resolution: - { - integrity: sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==, - } + resolution: {integrity: sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==} remark-gfm@4.0.1: - resolution: - { - integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==, - } + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} remark-mdx@3.1.1: - resolution: - { - integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==, - } + resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} remark-parse@11.0.0: - resolution: - { - integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==, - } + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} remark-rehype@11.1.2: - resolution: - { - integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==, - } + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} remark-smartypants@3.0.2: - resolution: - { - integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==, - } - engines: { node: ">=16.0.0" } + resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==} + engines: {node: '>=16.0.0'} remark-stringify@11.0.0: - resolution: - { - integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==, - } + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} remend@1.2.2: - resolution: - { - integrity: sha512-4ZJgIB9EG9fQE41mOJCRHMmnxDTKHWawQoJWZyUbZuj680wVyogu2ihnj8Edqm7vh2mo/TWHyEZpn2kqeDvS7w==, - } + resolution: {integrity: sha512-4ZJgIB9EG9fQE41mOJCRHMmnxDTKHWawQoJWZyUbZuj680wVyogu2ihnj8Edqm7vh2mo/TWHyEZpn2kqeDvS7w==} request-light@0.5.8: - resolution: - { - integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==, - } + resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} request-light@0.7.0: - resolution: - { - integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==, - } + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} require-directory@2.1.1: - resolution: - { - integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} require-from-string@2.0.2: - resolution: - { - integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} require-in-the-middle@8.0.1: - resolution: - { - integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==, - } - engines: { node: ">=9.3.0 || >=8.10.0 <9.0.0" } + resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} + engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} resolve-from@5.0.0: - resolution: - { - integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} resolve-pkg-maps@1.0.0: - resolution: - { - integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, - } + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} resolve.exports@2.0.3: - resolution: - { - integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} resq@1.11.0: - resolution: - { - integrity: sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==, - } + resolution: {integrity: sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==} restore-cursor@5.1.0: - resolution: - { - integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} ret@0.5.0: - resolution: - { - integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} + engines: {node: '>=10'} retext-latin@4.0.0: - resolution: - { - integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==, - } + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} retext-smartypants@6.2.0: - resolution: - { - integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==, - } + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} retext-stringify@4.0.0: - resolution: - { - integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==, - } + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} retext@9.0.0: - resolution: - { - integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==, - } + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} retry@0.13.1: - resolution: - { - integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==, - } - engines: { node: ">= 4" } + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} rettime@0.10.1: - resolution: - { - integrity: sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==, - } + resolution: {integrity: sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==} reusify@1.1.0: - resolution: - { - integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, - } - engines: { iojs: ">=1.0.0", node: ">=0.10.0" } + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} rfdc@1.4.1: - resolution: - { - integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==, - } + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} rgb2hex@0.2.5: - resolution: - { - integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==, - } + resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==} rimraf@5.0.10: - resolution: - { - integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==, - } + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true rolldown@1.0.0-rc.1: - resolution: - { - integrity: sha512-M3AeZjYE6UclblEf531Hch0WfVC/NOL43Cc+WdF3J50kk5/fvouHhDumSGTh0oRjbZ8C4faaVr5r6Nx1xMqDGg==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + resolution: {integrity: sha512-M3AeZjYE6UclblEf531Hch0WfVC/NOL43Cc+WdF3J50kk5/fvouHhDumSGTh0oRjbZ8C4faaVr5r6Nx1xMqDGg==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true rollup@4.59.0: - resolution: - { - integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==, - } - engines: { node: ">=18.0.0", npm: ">=8.0.0" } + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-parallel@1.2.0: - resolution: - { - integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, - } + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} safaridriver@1.0.1: - resolution: - { - integrity: sha512-jkg4434cYgtrIF2AeY/X0Wmd2W73cK5qIEFE3hDrrQenJH/2SDJIXGvPAigfvQTcE9+H31zkiNHbUqcihEiMRA==, - } - engines: { node: ">=18.0.0" } + resolution: {integrity: sha512-jkg4434cYgtrIF2AeY/X0Wmd2W73cK5qIEFE3hDrrQenJH/2SDJIXGvPAigfvQTcE9+H31zkiNHbUqcihEiMRA==} + engines: {node: '>=18.0.0'} safe-buffer@5.1.2: - resolution: - { - integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, - } + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} safe-buffer@5.2.1: - resolution: - { - integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, - } + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} safe-regex2@5.0.0: - resolution: - { - integrity: sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==, - } + resolution: {integrity: sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==} safer-buffer@2.1.2: - resolution: - { - integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, - } + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} sax@1.5.0: - resolution: - { - integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==, - } - engines: { node: ">=11.0.0" } + resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + engines: {node: '>=11.0.0'} scheduler@0.27.0: - resolution: - { - integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==, - } + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} schema-utils@4.3.3: - resolution: - { - integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==, - } - engines: { node: ">= 10.13.0" } + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} section-matter@1.0.0: - resolution: - { - integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} semver@6.3.1: - resolution: - { - integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, - } + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true semver@7.5.4: - resolution: - { - integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} hasBin: true semver@7.7.4: - resolution: - { - integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + serialize-error@12.0.0: - resolution: - { - integrity: sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==} + engines: {node: '>=18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} set-blocking@2.0.0: - resolution: - { - integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==, - } + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} setimmediate@1.0.5: - resolution: - { - integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==, - } + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} setprototypeof@1.1.1: - resolution: - { - integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==, - } + resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} sharp@0.34.5: - resolution: - { - integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==, - } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: - resolution: - { - integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} shebang-regex@3.0.0: - resolution: - { - integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} shell-quote@1.8.3: - resolution: - { - integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} shiki@3.23.0: - resolution: - { - integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==, - } + resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} siginfo@2.0.0: - resolution: - { - integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==, - } + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} signal-exit@3.0.7: - resolution: - { - integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, - } + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} signal-exit@4.0.2: - resolution: - { - integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==, - } - engines: { node: ">=14" } + resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} + engines: {node: '>=14'} signal-exit@4.1.0: - resolution: - { - integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, - } - engines: { node: ">=14" } + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} simple-concat@1.0.1: - resolution: - { - integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==, - } + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} simple-get@4.0.1: - resolution: - { - integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==, - } + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} simple-git-hooks@2.13.1: - resolution: - { - integrity: sha512-WszCLXwT4h2k1ufIXAgsbiTOazqqevFCIncOuUBZJ91DdvWcC5+OFkluWRQPrcuSYd8fjq+o2y1QfWqYMoAToQ==, - } + resolution: {integrity: sha512-WszCLXwT4h2k1ufIXAgsbiTOazqqevFCIncOuUBZJ91DdvWcC5+OFkluWRQPrcuSYd8fjq+o2y1QfWqYMoAToQ==} hasBin: true sisteransi@1.0.5: - resolution: - { - integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, - } + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} sitemap@8.0.3: - resolution: - { - integrity: sha512-9Ew1tR2WYw8RGE2XLy7GjkusvYXy8Rg6y8TYuBuQMfIEdGcWoJpY2Wr5DzsEiL/TKCw56+YKTCCUHglorEYK+A==, - } - engines: { node: ">=14.0.0", npm: ">=6.0.0" } + resolution: {integrity: sha512-9Ew1tR2WYw8RGE2XLy7GjkusvYXy8Rg6y8TYuBuQMfIEdGcWoJpY2Wr5DzsEiL/TKCw56+YKTCCUHglorEYK+A==} + engines: {node: '>=14.0.0', npm: '>=6.0.0'} hasBin: true slice-ansi@7.1.2: - resolution: - { - integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} slice-ansi@8.0.0: - resolution: - { - integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} + engines: {node: '>=20'} smart-buffer@4.2.0: - resolution: - { - integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==, - } - engines: { node: ">= 6.0.0", npm: ">= 3.0.0" } + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} smol-toml@1.5.2: - resolution: - { - integrity: sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==, - } - engines: { node: ">= 18" } + resolution: {integrity: sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==} + engines: {node: '>= 18'} smol-toml@1.6.0: - resolution: - { - integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==, - } - engines: { node: ">= 18" } + resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} + engines: {node: '>= 18'} socks-proxy-agent@8.0.5: - resolution: - { - integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} socks@2.8.7: - resolution: - { - integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==, - } - engines: { node: ">= 10.0.0", npm: ">= 3.0.0" } + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} source-map-js@1.2.1: - resolution: - { - integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} source-map-support@0.5.21: - resolution: - { - integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, - } + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} source-map@0.6.1: - resolution: - { - integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} source-map@0.7.6: - resolution: - { - integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==, - } - engines: { node: ">= 12" } + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} space-separated-tokens@2.0.2: - resolution: - { - integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==, - } + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} spacetrim@0.11.59: - resolution: - { - integrity: sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==, - } + resolution: {integrity: sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==} split2@4.2.0: - resolution: - { - integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==, - } - engines: { node: ">= 10.x" } + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} sprintf-js@1.0.3: - resolution: - { - integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, - } + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} sprintf-js@1.1.3: - resolution: - { - integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==, - } + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} sql.js@1.14.1: - resolution: - { - integrity: sha512-gcj8zBWU5cFsi9WUP+4bFNXAyF1iRpA3LLyS/DP5xlrNzGmPIizUeBggKa8DbDwdqaKwUcTEnChtd2grWo/x/A==, - } + resolution: {integrity: sha512-gcj8zBWU5cFsi9WUP+4bFNXAyF1iRpA3LLyS/DP5xlrNzGmPIizUeBggKa8DbDwdqaKwUcTEnChtd2grWo/x/A==} srvx@0.8.9: - resolution: - { - integrity: sha512-wYc3VLZHRzwYrWJhkEqkhLb31TI0SOkfYZDkUhXdp3NoCnNS0FqajiQszZZjfow/VYEuc6Q5sZh9nM6kPy2NBQ==, - } - engines: { node: ">=20.16.0" } + resolution: {integrity: sha512-wYc3VLZHRzwYrWJhkEqkhLb31TI0SOkfYZDkUhXdp3NoCnNS0FqajiQszZZjfow/VYEuc6Q5sZh9nM6kPy2NBQ==} + engines: {node: '>=20.16.0'} hasBin: true stackback@0.0.2: - resolution: - { - integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, - } + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} stacktrace-parser@0.1.11: - resolution: - { - integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} + engines: {node: '>=6'} starlight-typedoc@0.21.5: - resolution: - { - integrity: sha512-7JGaPHrP+HgX0sYGnafZcPuzMm+3OmHx7kqE0DWTrsuBfoQS02lJ6/PtJF9y0KCDcfsBynyo0G/1ttHcBq5Vww==, - } - engines: { node: ">=18.17.1" } + resolution: {integrity: sha512-7JGaPHrP+HgX0sYGnafZcPuzMm+3OmHx7kqE0DWTrsuBfoQS02lJ6/PtJF9y0KCDcfsBynyo0G/1ttHcBq5Vww==} + engines: {node: '>=18.17.1'} peerDependencies: - "@astrojs/starlight": ">=0.32.0" - typedoc: ">=0.28.0" - typedoc-plugin-markdown: ">=4.6.0" + '@astrojs/starlight': '>=0.32.0' + typedoc: '>=0.28.0' + typedoc-plugin-markdown: '>=4.6.0' stat-mode@0.3.0: - resolution: - { - integrity: sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng==, - } + resolution: {integrity: sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng==} statuses@1.5.0: - resolution: - { - integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==, - } - engines: { node: ">= 0.6" } + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} statuses@2.0.2: - resolution: - { - integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==, - } - engines: { node: ">= 0.8" } + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} std-env@4.0.0: - resolution: - { - integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==, - } + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} stream-replace-string@2.0.0: - resolution: - { - integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==, - } + resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==} stream-to-array@2.3.0: - resolution: - { - integrity: sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==, - } + resolution: {integrity: sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==} stream-to-promise@2.2.0: - resolution: - { - integrity: sha512-HAGUASw8NT0k8JvIVutB2Y/9iBk7gpgEyAudXwNJmZERdMITGdajOa4VJfD/kNiA3TppQpTP4J+CtcHwdzKBAw==, - } + resolution: {integrity: sha512-HAGUASw8NT0k8JvIVutB2Y/9iBk7gpgEyAudXwNJmZERdMITGdajOa4VJfD/kNiA3TppQpTP4J+CtcHwdzKBAw==} streamx@2.23.0: - resolution: - { - integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==, - } + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} strict-event-emitter@0.5.1: - resolution: - { - integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==, - } + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} string-argv@0.3.2: - resolution: - { - integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==, - } - engines: { node: ">=0.6.19" } + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} string-width@4.2.3: - resolution: - { - integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} string-width@5.1.2: - resolution: - { - integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} string-width@7.2.0: - resolution: - { - integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} string-width@8.2.0: - resolution: - { - integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + engines: {node: '>=20'} string_decoder@1.1.1: - resolution: - { - integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, - } + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} string_decoder@1.3.0: - resolution: - { - integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, - } + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} stringify-entities@4.0.4: - resolution: - { - integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==, - } + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} strip-ansi@6.0.1: - resolution: - { - integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} strip-ansi@7.2.0: - resolution: - { - integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} strip-bom-string@1.0.0: - resolution: - { - integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} strip-final-newline@2.0.0: - resolution: - { - integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} strip-json-comments@2.0.1: - resolution: - { - integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} strnum@2.2.0: - resolution: - { - integrity: sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==, - } + resolution: {integrity: sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==} strtok3@10.3.4: - resolution: - { - integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + engines: {node: '>=18'} style-to-js@1.1.21: - resolution: - { - integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==, - } + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} style-to-object@1.0.14: - resolution: - { - integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==, - } + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} styled-jsx@5.1.6: - resolution: - { - integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==, - } - engines: { node: ">= 12.0.0" } + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} peerDependencies: - "@babel/core": "*" - babel-plugin-macros: "*" - react: ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' peerDependenciesMeta: - "@babel/core": + '@babel/core': optional: true babel-plugin-macros: optional: true sucrase@3.35.1: - resolution: - { - integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==, - } - engines: { node: ">=16 || 14 >=14.17" } + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} hasBin: true supports-color@7.2.0: - resolution: - { - integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} supports-color@8.1.1: - resolution: - { - integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} svgo@4.0.1: - resolution: - { - integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} + engines: {node: '>=16'} hasBin: true tagged-tag@1.0.0: - resolution: - { - integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} tapable@2.3.0: - resolution: - { - integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} tar-fs@2.1.4: - resolution: - { - integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==, - } + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} tar-fs@3.1.2: - resolution: - { - integrity: sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==, - } + resolution: {integrity: sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==} tar-stream@2.2.0: - resolution: - { - integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} tar-stream@3.1.7: - resolution: - { - integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==, - } + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} tar@7.5.10: - resolution: - { - integrity: sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==} + engines: {node: '>=18'} tar@7.5.7: - resolution: - { - integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==} + engines: {node: '>=18'} deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me teen_process@2.3.3: - resolution: - { - integrity: sha512-NIdeetf/6gyEqLjnzvfgQe7PfipSceq2xDQM2Py2BkBnIIeWh3HRD3vNhulyO5WppfCv9z4mtsEHyq8kdiULTA==, - } - engines: { node: ^16.13.0 || >=18.0.0, npm: ">=8" } + resolution: {integrity: sha512-NIdeetf/6gyEqLjnzvfgQe7PfipSceq2xDQM2Py2BkBnIIeWh3HRD3vNhulyO5WppfCv9z4mtsEHyq8kdiULTA==} + engines: {node: ^16.13.0 || >=18.0.0, npm: '>=8'} teex@1.0.1: - resolution: - { - integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==, - } + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} terser-webpack-plugin@5.4.0: - resolution: - { - integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==, - } - engines: { node: ">= 10.13.0" } + resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==} + engines: {node: '>= 10.13.0'} peerDependencies: - "@swc/core": "*" - esbuild: "*" - uglify-js: "*" + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' webpack: ^5.1.0 peerDependenciesMeta: - "@swc/core": + '@swc/core': optional: true esbuild: optional: true @@ -10539,181 +6441,104 @@ packages: optional: true terser@5.46.1: - resolution: - { - integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} + engines: {node: '>=10'} hasBin: true text-decoder@1.2.7: - resolution: - { - integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==, - } + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} thenify-all@1.6.0: - resolution: - { - integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, - } - engines: { node: ">=0.8" } + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} thenify@3.3.1: - resolution: - { - integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, - } + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} throttleit@2.1.0: - resolution: - { - integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} + engines: {node: '>=18'} time-span@4.0.0: - resolution: - { - integrity: sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==} + engines: {node: '>=10'} tiny-inflate@1.0.3: - resolution: - { - integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==, - } + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} tinybench@2.9.0: - resolution: - { - integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==, - } + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} tinyexec@0.3.2: - resolution: - { - integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==, - } + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} tinyexec@1.0.2: - resolution: - { - integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} tinyglobby@0.2.15: - resolution: - { - integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==, - } - engines: { node: ">=12.0.0" } + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} tinyrainbow@3.0.3: - resolution: - { - integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==, - } - engines: { node: ">=14.0.0" } + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} tldts-core@7.0.25: - resolution: - { - integrity: sha512-ZjCZK0rppSBu7rjHYDYsEaMOIbbT+nWF57hKkv4IUmZWBNrBWBOjIElc0mKRgLM8bm7x/BBlof6t2gi/Oq/Asw==, - } + resolution: {integrity: sha512-ZjCZK0rppSBu7rjHYDYsEaMOIbbT+nWF57hKkv4IUmZWBNrBWBOjIElc0mKRgLM8bm7x/BBlof6t2gi/Oq/Asw==} tldts@7.0.25: - resolution: - { - integrity: sha512-keinCnPbwXEUG3ilrWQZU+CqcTTzHq9m2HhoUP2l7Xmi8l1LuijAXLpAJ5zRW+ifKTNscs4NdCkfkDCBYm352w==, - } + resolution: {integrity: sha512-keinCnPbwXEUG3ilrWQZU+CqcTTzHq9m2HhoUP2l7Xmi8l1LuijAXLpAJ5zRW+ifKTNscs4NdCkfkDCBYm352w==} hasBin: true to-regex-range@5.0.1: - resolution: - { - integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, - } - engines: { node: ">=8.0" } + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} toidentifier@1.0.0: - resolution: - { - integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==, - } - engines: { node: ">=0.6" } + resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==} + engines: {node: '>=0.6'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} token-types@6.1.2: - resolution: - { - integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==, - } - engines: { node: ">=14.16" } + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} tough-cookie@6.0.0: - resolution: - { - integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + engines: {node: '>=16'} tr46@0.0.3: - resolution: - { - integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, - } + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} tree-kill@1.2.2: - resolution: - { - integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==, - } + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true trim-lines@3.0.1: - resolution: - { - integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==, - } + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} trough@2.2.0: - resolution: - { - integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==, - } + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} ts-algebra@2.0.0: - resolution: - { - integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==, - } + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} ts-interface-checker@0.1.13: - resolution: - { - integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, - } + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} ts-morph@12.0.0: - resolution: - { - integrity: sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==, - } + resolution: {integrity: sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==} ts-toolbelt@6.15.5: - resolution: - { - integrity: sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==, - } + resolution: {integrity: sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==} tsconfck@3.1.6: - resolution: - { - integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==, - } - engines: { node: ^18 || >=20 } + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} hasBin: true peerDependencies: typescript: ^5.0.0 @@ -10722,27 +6547,21 @@ packages: optional: true tslib@2.8.1: - resolution: - { - integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, - } + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} tsup@8.5.1: - resolution: - { - integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} hasBin: true peerDependencies: - "@microsoft/api-extractor": ^7.36.0 - "@swc/core": ^1 + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 postcss: ^8.4.12 - typescript: ">=4.5.0" + typescript: '>=4.5.0' peerDependenciesMeta: - "@microsoft/api-extractor": + '@microsoft/api-extractor': optional: true - "@swc/core": + '@swc/core': optional: true postcss: optional: true @@ -10750,307 +6569,194 @@ packages: optional: true tsx@4.21.0: - resolution: - { - integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==, - } - engines: { node: ">=18.0.0" } + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} hasBin: true tunnel-agent@0.6.0: - resolution: - { - integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==, - } + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} turndown@7.2.2: - resolution: - { - integrity: sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==, - } + resolution: {integrity: sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==} type-fest@0.7.1: - resolution: - { - integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} type-fest@4.26.0: - resolution: - { - integrity: sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==} + engines: {node: '>=16'} type-fest@4.41.0: - resolution: - { - integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==, - } - engines: { node: ">=16" } + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} type-fest@5.4.4: - resolution: - { - integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==, - } - engines: { node: ">=20" } + resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} + engines: {node: '>=20'} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} typedoc-plugin-markdown@4.10.0: - resolution: - { - integrity: sha512-psrg8Rtnv4HPWCsoxId+MzEN8TVK5jeKCnTbnGAbTBqcDapR9hM41bJT/9eAyKn9C2MDG9Qjh3MkltAYuLDoXg==, - } - engines: { node: ">= 18" } + resolution: {integrity: sha512-psrg8Rtnv4HPWCsoxId+MzEN8TVK5jeKCnTbnGAbTBqcDapR9hM41bJT/9eAyKn9C2MDG9Qjh3MkltAYuLDoXg==} + engines: {node: '>= 18'} peerDependencies: typedoc: 0.28.x typedoc@0.28.17: - resolution: - { - integrity: sha512-ZkJ2G7mZrbxrKxinTQMjFqsCoYY6a5Luwv2GKbTnBCEgV2ihYm5CflA9JnJAwH0pZWavqfYxmDkFHPt4yx2oDQ==, - } - engines: { node: ">= 18", pnpm: ">= 10" } + resolution: {integrity: sha512-ZkJ2G7mZrbxrKxinTQMjFqsCoYY6a5Luwv2GKbTnBCEgV2ihYm5CflA9JnJAwH0pZWavqfYxmDkFHPt4yx2oDQ==} + engines: {node: '>= 18', pnpm: '>= 10'} hasBin: true peerDependencies: typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x typesafe-path@0.2.2: - resolution: - { - integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==, - } + resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==} typescript-auto-import-cache@0.3.6: - resolution: - { - integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==, - } + resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==} typescript@5.9.3: - resolution: - { - integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, - } - engines: { node: ">=14.17" } + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} hasBin: true uc.micro@2.1.0: - resolution: - { - integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==, - } + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} ufo@1.6.3: - resolution: - { - integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==, - } + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} uid-promise@1.0.0: - resolution: - { - integrity: sha512-R8375j0qwXyIu/7R0tjdF06/sElHqbmdmWC9M2qQHpEVbvE4I5+38KJI7LUUmQMp7NVq4tKHiBMkT0NFM453Ig==, - } + resolution: {integrity: sha512-R8375j0qwXyIu/7R0tjdF06/sElHqbmdmWC9M2qQHpEVbvE4I5+38KJI7LUUmQMp7NVq4tKHiBMkT0NFM453Ig==} uint8array-extras@1.5.0: - resolution: - { - integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} ultrahtml@1.6.0: - resolution: - { - integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==, - } + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} uncrypto@0.1.3: - resolution: - { - integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==, - } + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} undici-types@5.26.5: - resolution: - { - integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==, - } + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} undici-types@6.21.0: - resolution: - { - integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==, - } + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} undici-types@7.18.2: - resolution: - { - integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==, - } + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} undici@5.28.4: - resolution: - { - integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==, - } - engines: { node: ">=14.0" } + resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} + engines: {node: '>=14.0'} undici@6.23.0: - resolution: - { - integrity: sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==, - } - engines: { node: ">=18.17" } + resolution: {integrity: sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==} + engines: {node: '>=18.17'} undici@7.22.0: - resolution: - { - integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==, - } - engines: { node: ">=20.18.1" } + resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} + engines: {node: '>=20.18.1'} unified@11.0.5: - resolution: - { - integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==, - } + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} unifont@0.7.4: - resolution: - { - integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==, - } + resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==} unist-util-find-after@5.0.0: - resolution: - { - integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==, - } + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} unist-util-is@6.0.1: - resolution: - { - integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==, - } + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} unist-util-modify-children@4.0.0: - resolution: - { - integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==, - } + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} unist-util-position-from-estree@2.0.0: - resolution: - { - integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==, - } + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} unist-util-position@5.0.0: - resolution: - { - integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==, - } + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} unist-util-remove-position@5.0.0: - resolution: - { - integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==, - } + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} unist-util-stringify-position@4.0.0: - resolution: - { - integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==, - } + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} unist-util-visit-children@3.0.0: - resolution: - { - integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==, - } + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} unist-util-visit-parents@6.0.2: - resolution: - { - integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==, - } + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} unist-util-visit@5.1.0: - resolution: - { - integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==, - } + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} universalify@2.0.1: - resolution: - { - integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==, - } - engines: { node: ">= 10.0.0" } + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} unpipe@1.0.0: - resolution: - { - integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==, - } - engines: { node: ">= 0.8" } + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} unstorage@1.17.4: - resolution: - { - integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==, - } - peerDependencies: - "@azure/app-configuration": ^1.8.0 - "@azure/cosmos": ^4.2.0 - "@azure/data-tables": ^13.3.0 - "@azure/identity": ^4.6.0 - "@azure/keyvault-secrets": ^4.9.0 - "@azure/storage-blob": ^12.26.0 - "@capacitor/preferences": ^6 || ^7 || ^8 - "@deno/kv": ">=0.9.0" - "@netlify/blobs": ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 - "@planetscale/database": ^1.19.0 - "@upstash/redis": ^1.34.3 - "@vercel/blob": ">=0.27.1" - "@vercel/functions": ^2.2.12 || ^3.0.0 - "@vercel/kv": ^1 || ^2 || ^3 + resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 aws4fetch: ^1.0.20 - db0: ">=0.2.1" + db0: '>=0.2.1' idb-keyval: ^6.2.1 ioredis: ^5.4.2 uploadthing: ^7.4.4 peerDependenciesMeta: - "@azure/app-configuration": + '@azure/app-configuration': optional: true - "@azure/cosmos": + '@azure/cosmos': optional: true - "@azure/data-tables": + '@azure/data-tables': optional: true - "@azure/identity": + '@azure/identity': optional: true - "@azure/keyvault-secrets": + '@azure/keyvault-secrets': optional: true - "@azure/storage-blob": + '@azure/storage-blob': optional: true - "@capacitor/preferences": + '@capacitor/preferences': optional: true - "@deno/kv": + '@deno/kv': optional: true - "@netlify/blobs": + '@netlify/blobs': optional: true - "@planetscale/database": + '@planetscale/database': optional: true - "@upstash/redis": + '@upstash/redis': optional: true - "@vercel/blob": + '@vercel/blob': optional: true - "@vercel/functions": + '@vercel/functions': optional: true - "@vercel/kv": + '@vercel/kv': optional: true aws4fetch: optional: true @@ -11064,106 +6770,71 @@ packages: optional: true until-async@3.0.2: - resolution: - { - integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==, - } + resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} update-browserslist-db@1.2.3: - resolution: - { - integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==, - } + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: - browserslist: ">= 4.21.0" + browserslist: '>= 4.21.0' uri-js@4.4.1: - resolution: - { - integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, - } + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} urlpattern-polyfill@10.1.0: - resolution: - { - integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==, - } + resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==} userhome@1.0.1: - resolution: - { - integrity: sha512-5cnLm4gseXjAclKowC4IjByaGsjtAoV6PrOQOljplNB54ReUYJP8HdAFq2muHinSDAh09PPX/uXDPfdxRHvuSA==, - } - engines: { node: ">= 0.8.0" } + resolution: {integrity: sha512-5cnLm4gseXjAclKowC4IjByaGsjtAoV6PrOQOljplNB54ReUYJP8HdAFq2muHinSDAh09PPX/uXDPfdxRHvuSA==} + engines: {node: '>= 0.8.0'} util-deprecate@1.0.2: - resolution: - { - integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, - } + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} uuid@11.1.0: - resolution: - { - integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==, - } + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true uuid@9.0.1: - resolution: - { - integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==, - } + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + vercel@50.32.5: - resolution: - { - integrity: sha512-gwxkUgVLQGSUV3EgsJa3rbBXDgoKIjp73bxEgZm+BgSRDSG8sMJD1shozgu5NI+Od8HkzvsZBIX5c2XOsLH8+w==, - } - engines: { node: ">= 18" } + resolution: {integrity: sha512-gwxkUgVLQGSUV3EgsJa3rbBXDgoKIjp73bxEgZm+BgSRDSG8sMJD1shozgu5NI+Od8HkzvsZBIX5c2XOsLH8+w==} + engines: {node: '>= 18'} hasBin: true vfile-location@5.0.3: - resolution: - { - integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==, - } + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} vfile-message@4.0.3: - resolution: - { - integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==, - } + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} vfile@6.0.3: - resolution: - { - integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==, - } + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} vite@6.4.1: - resolution: - { - integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==, - } - engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } + resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: ">=1.21.0" - less: "*" + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' lightningcss: ^1.21.0 - sass: "*" - sass-embedded: "*" - stylus: "*" - sugarss: "*" + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 peerDependenciesMeta: - "@types/node": + '@types/node': optional: true jiti: optional: true @@ -11187,26 +6858,23 @@ packages: optional: true vite@7.3.1: - resolution: - { - integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==, - } - engines: { node: ^20.19.0 || >=22.12.0 } + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - "@types/node": ^20.19.0 || >=22.12.0 - jiti: ">=1.21.0" + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' less: ^4.0.0 lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 - stylus: ">=0.54.8" + stylus: '>=0.54.8' sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 peerDependenciesMeta: - "@types/node": + '@types/node': optional: true jiti: optional: true @@ -11230,10 +6898,7 @@ packages: optional: true vitefu@1.1.2: - resolution: - { - integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==, - } + resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==} peerDependencies: vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0 peerDependenciesMeta: @@ -11241,14 +6906,11 @@ packages: optional: true vitest-evals@0.6.0: - resolution: - { - integrity: sha512-6DjQRALjHjUPsHEkz28oSjO+q6uEp7HR4aU3qXr32D9vsHGOmyfxZn7fK6PDuHzE/5hDP8dtkkgZQZ6fAmV5vA==, - } + resolution: {integrity: sha512-6DjQRALjHjUPsHEkz28oSjO+q6uEp7HR4aU3qXr32D9vsHGOmyfxZn7fK6PDuHzE/5hDP8dtkkgZQZ6fAmV5vA==} peerDependencies: ai: ^4.0.0 - tinyrainbow: "*" - vitest: "*" + tinyrainbow: '*' + vitest: '*' zod: ^3.0.0 peerDependenciesMeta: ai: @@ -11257,37 +6919,34 @@ packages: optional: true vitest@4.1.0: - resolution: - { - integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==, - } - engines: { node: ^20.0.0 || ^22.0.0 || >=24.0.0 } + resolution: {integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: - "@edge-runtime/vm": "*" - "@opentelemetry/api": ^1.9.0 - "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 - "@vitest/browser-playwright": 4.1.0 - "@vitest/browser-preview": 4.1.0 - "@vitest/browser-webdriverio": 4.1.0 - "@vitest/ui": 4.1.0 - happy-dom: "*" - jsdom: "*" + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.0 + '@vitest/browser-preview': 4.1.0 + '@vitest/browser-webdriverio': 4.1.0 + '@vitest/ui': 4.1.0 + happy-dom: '*' + jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 peerDependenciesMeta: - "@edge-runtime/vm": + '@edge-runtime/vm': optional: true - "@opentelemetry/api": + '@opentelemetry/api': optional: true - "@types/node": + '@types/node': optional: true - "@vitest/browser-playwright": + '@vitest/browser-playwright': optional: true - "@vitest/browser-preview": + '@vitest/browser-preview': optional: true - "@vitest/browser-webdriverio": + '@vitest/browser-webdriverio': optional: true - "@vitest/ui": + '@vitest/ui': optional: true happy-dom: optional: true @@ -11295,337 +6954,211 @@ packages: optional: true volar-service-css@0.0.68: - resolution: - { - integrity: sha512-lJSMh6f3QzZ1tdLOZOzovLX0xzAadPhx8EKwraDLPxBndLCYfoTvnNuiFFV8FARrpAlW5C0WkH+TstPaCxr00Q==, - } + resolution: {integrity: sha512-lJSMh6f3QzZ1tdLOZOzovLX0xzAadPhx8EKwraDLPxBndLCYfoTvnNuiFFV8FARrpAlW5C0WkH+TstPaCxr00Q==} peerDependencies: - "@volar/language-service": ~2.4.0 + '@volar/language-service': ~2.4.0 peerDependenciesMeta: - "@volar/language-service": + '@volar/language-service': optional: true volar-service-emmet@0.0.68: - resolution: - { - integrity: sha512-nHvixrRQ83EzkQ4G/jFxu9Y4eSsXS/X2cltEPDM+K9qZmIv+Ey1w0tg1+6caSe8TU5Hgw4oSTwNMf/6cQb3LzQ==, - } + resolution: {integrity: sha512-nHvixrRQ83EzkQ4G/jFxu9Y4eSsXS/X2cltEPDM+K9qZmIv+Ey1w0tg1+6caSe8TU5Hgw4oSTwNMf/6cQb3LzQ==} peerDependencies: - "@volar/language-service": ~2.4.0 + '@volar/language-service': ~2.4.0 peerDependenciesMeta: - "@volar/language-service": + '@volar/language-service': optional: true volar-service-html@0.0.68: - resolution: - { - integrity: sha512-fru9gsLJxy33xAltXOh4TEdi312HP80hpuKhpYQD4O5hDnkNPEBdcQkpB+gcX0oK0VxRv1UOzcGQEUzWCVHLfA==, - } + resolution: {integrity: sha512-fru9gsLJxy33xAltXOh4TEdi312HP80hpuKhpYQD4O5hDnkNPEBdcQkpB+gcX0oK0VxRv1UOzcGQEUzWCVHLfA==} peerDependencies: - "@volar/language-service": ~2.4.0 + '@volar/language-service': ~2.4.0 peerDependenciesMeta: - "@volar/language-service": + '@volar/language-service': optional: true volar-service-prettier@0.0.68: - resolution: - { - integrity: sha512-grUmWHkHlebMOd6V8vXs2eNQUw/bJGJMjekh/EPf/p2ZNTK0Uyz7hoBRngcvGfJHMsSXZH8w/dZTForIW/4ihw==, - } + resolution: {integrity: sha512-grUmWHkHlebMOd6V8vXs2eNQUw/bJGJMjekh/EPf/p2ZNTK0Uyz7hoBRngcvGfJHMsSXZH8w/dZTForIW/4ihw==} peerDependencies: - "@volar/language-service": ~2.4.0 + '@volar/language-service': ~2.4.0 prettier: ^2.2 || ^3.0 peerDependenciesMeta: - "@volar/language-service": + '@volar/language-service': optional: true prettier: optional: true volar-service-typescript-twoslash-queries@0.0.68: - resolution: - { - integrity: sha512-NugzXcM0iwuZFLCJg47vI93su5YhTIweQuLmZxvz5ZPTaman16JCvmDZexx2rd5T/75SNuvvZmrTOTNYUsfe5w==, - } + resolution: {integrity: sha512-NugzXcM0iwuZFLCJg47vI93su5YhTIweQuLmZxvz5ZPTaman16JCvmDZexx2rd5T/75SNuvvZmrTOTNYUsfe5w==} peerDependencies: - "@volar/language-service": ~2.4.0 + '@volar/language-service': ~2.4.0 peerDependenciesMeta: - "@volar/language-service": + '@volar/language-service': optional: true volar-service-typescript@0.0.68: - resolution: - { - integrity: sha512-z7B/7CnJ0+TWWFp/gh2r5/QwMObHNDiQiv4C9pTBNI2Wxuwymd4bjEORzrJ/hJ5Yd5+OzeYK+nFCKevoGEEeKw==, - } + resolution: {integrity: sha512-z7B/7CnJ0+TWWFp/gh2r5/QwMObHNDiQiv4C9pTBNI2Wxuwymd4bjEORzrJ/hJ5Yd5+OzeYK+nFCKevoGEEeKw==} peerDependencies: - "@volar/language-service": ~2.4.0 + '@volar/language-service': ~2.4.0 peerDependenciesMeta: - "@volar/language-service": + '@volar/language-service': optional: true volar-service-yaml@0.0.68: - resolution: - { - integrity: sha512-84XgE02LV0OvTcwfqhcSwVg4of3MLNUWPMArO6Aj8YXqyEVnPu8xTEMY2btKSq37mVAPuaEVASI4e3ptObmqcA==, - } + resolution: {integrity: sha512-84XgE02LV0OvTcwfqhcSwVg4of3MLNUWPMArO6Aj8YXqyEVnPu8xTEMY2btKSq37mVAPuaEVASI4e3ptObmqcA==} peerDependencies: - "@volar/language-service": ~2.4.0 + '@volar/language-service': ~2.4.0 peerDependenciesMeta: - "@volar/language-service": + '@volar/language-service': optional: true vscode-css-languageservice@6.3.10: - resolution: - { - integrity: sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==, - } + resolution: {integrity: sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==} vscode-html-languageservice@5.6.2: - resolution: - { - integrity: sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==, - } + resolution: {integrity: sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==} vscode-json-languageservice@4.1.8: - resolution: - { - integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==, - } - engines: { npm: ">=7.0.0" } + resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==} + engines: {npm: '>=7.0.0'} vscode-jsonrpc@8.2.0: - resolution: - { - integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==, - } - engines: { node: ">=14.0.0" } + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} vscode-languageserver-protocol@3.17.5: - resolution: - { - integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==, - } + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} vscode-languageserver-textdocument@1.0.12: - resolution: - { - integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==, - } + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} vscode-languageserver-types@3.17.5: - resolution: - { - integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==, - } + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} vscode-languageserver@9.0.1: - resolution: - { - integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==, - } + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} hasBin: true vscode-nls@5.2.0: - resolution: - { - integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==, - } + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} vscode-uri@3.1.0: - resolution: - { - integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==, - } + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} wait-port@1.1.0: - resolution: - { - integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} + engines: {node: '>=10'} hasBin: true watchpack@2.5.1: - resolution: - { - integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==, - } - engines: { node: ">=10.13.0" } + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} + engines: {node: '>=10.13.0'} web-namespaces@2.0.1: - resolution: - { - integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==, - } + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} web-streams-polyfill@3.3.3: - resolution: - { - integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==, - } - engines: { node: ">= 8" } + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} web-vitals@0.2.4: - resolution: - { - integrity: sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg==, - } + resolution: {integrity: sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg==} webdriver@9.24.0: - resolution: - { - integrity: sha512-2R31Ey83NzMsafkl4hdFq6GlIBvOODQMkueLjeRqYAITu3QCYiq9oqBdnWA6CdePuV4dbKlYsKRX0mwMiPclDA==, - } - engines: { node: ">=18.20.0" } + resolution: {integrity: sha512-2R31Ey83NzMsafkl4hdFq6GlIBvOODQMkueLjeRqYAITu3QCYiq9oqBdnWA6CdePuV4dbKlYsKRX0mwMiPclDA==} + engines: {node: '>=18.20.0'} webdriverio@9.24.0: - resolution: - { - integrity: sha512-LTJt6Z/iDM0ne/4ytd3BykoPv9CuJ+CAILOzlwFeMGn4Mj02i4Bk2Rg9o/jeJ89f52hnv4OPmNjD0e8nzWAy5g==, - } - engines: { node: ">=18.20.0" } + resolution: {integrity: sha512-LTJt6Z/iDM0ne/4ytd3BykoPv9CuJ+CAILOzlwFeMGn4Mj02i4Bk2Rg9o/jeJ89f52hnv4OPmNjD0e8nzWAy5g==} + engines: {node: '>=18.20.0'} peerDependencies: - puppeteer-core: ">=22.x || <=24.x" + puppeteer-core: '>=22.x || <=24.x' peerDependenciesMeta: puppeteer-core: optional: true webidl-conversions@3.0.1: - resolution: - { - integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, - } + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} webpack-sources@3.3.4: - resolution: - { - integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==, - } - engines: { node: ">=10.13.0" } + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} + engines: {node: '>=10.13.0'} webpack@5.105.2: - resolution: - { - integrity: sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==, - } - engines: { node: ">=10.13.0" } + resolution: {integrity: sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==} + engines: {node: '>=10.13.0'} hasBin: true peerDependencies: - webpack-cli: "*" + webpack-cli: '*' peerDependenciesMeta: webpack-cli: optional: true whatwg-encoding@3.1.1: - resolution: - { - integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@4.0.0: - resolution: - { - integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} whatwg-url@5.0.0: - resolution: - { - integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, - } + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} which-pm-runs@1.1.0: - resolution: - { - integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} + engines: {node: '>=4'} which@2.0.2: - resolution: - { - integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, - } - engines: { node: ">= 8" } + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} hasBin: true which@5.0.0: - resolution: - { - integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==, - } - engines: { node: ^18.17.0 || >=20.5.0 } + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} hasBin: true which@6.0.1: - resolution: - { - integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==, - } - engines: { node: ^20.17.0 || >=22.9.0 } + resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} + engines: {node: ^20.17.0 || >=22.9.0} hasBin: true why-is-node-running@2.3.0: - resolution: - { - integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} hasBin: true widest-line@5.0.0: - resolution: - { - integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} + engines: {node: '>=18'} wrap-ansi@6.2.0: - resolution: - { - integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} wrap-ansi@7.0.0: - resolution: - { - integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} wrap-ansi@8.1.0: - resolution: - { - integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} wrap-ansi@9.0.2: - resolution: - { - integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} wrappy@1.0.2: - resolution: - { - integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, - } + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} ws@8.19.0: - resolution: - { - integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==, - } - engines: { node: ">=10.0.0" } + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" + utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true @@ -11633,239 +7166,153 @@ packages: optional: true xdg-app-paths@5.1.0: - resolution: - { - integrity: sha512-RAQ3WkPf4KTU1A8RtFx3gWywzVKe00tfOPFfl2NDGqbIFENQO4kqAJp7mhQjNj/33W5x5hiWWUdyfPq/5SU3QA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-RAQ3WkPf4KTU1A8RtFx3gWywzVKe00tfOPFfl2NDGqbIFENQO4kqAJp7mhQjNj/33W5x5hiWWUdyfPq/5SU3QA==} + engines: {node: '>=6'} xdg-portable@7.3.0: - resolution: - { - integrity: sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==, - } - engines: { node: ">= 6.0" } + resolution: {integrity: sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==} + engines: {node: '>= 6.0'} xtend@4.0.2: - resolution: - { - integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, - } - engines: { node: ">=0.4" } + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} xxhash-wasm@1.1.0: - resolution: - { - integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==, - } + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} y18n@5.0.8: - resolution: - { - integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} yallist@3.1.1: - resolution: - { - integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, - } + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} yallist@4.0.0: - resolution: - { - integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, - } + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} yallist@5.0.0: - resolution: - { - integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} yaml-language-server@1.19.2: - resolution: - { - integrity: sha512-9F3myNmJzUN/679jycdMxqtydPSDRAarSj3wPiF7pchEPnO9Dg07Oc+gIYLqXR4L+g+FSEVXXv2+mr54StLFOg==, - } + resolution: {integrity: sha512-9F3myNmJzUN/679jycdMxqtydPSDRAarSj3wPiF7pchEPnO9Dg07Oc+gIYLqXR4L+g+FSEVXXv2+mr54StLFOg==} hasBin: true yaml@2.7.1: - resolution: - { - integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} + engines: {node: '>= 14'} hasBin: true yaml@2.8.2: - resolution: - { - integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==, - } - engines: { node: ">= 14.6" } + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} hasBin: true yargs-parser@21.1.1: - resolution: - { - integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} yargs@17.7.2: - resolution: - { - integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} yauzl-clone@1.0.4: - resolution: - { - integrity: sha512-igM2RRCf3k8TvZoxR2oguuw4z1xasOnA31joCqHIyLkeWrvAc2Jgay5ISQ2ZplinkoGaJ6orCz56Ey456c5ESA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-igM2RRCf3k8TvZoxR2oguuw4z1xasOnA31joCqHIyLkeWrvAc2Jgay5ISQ2ZplinkoGaJ6orCz56Ey456c5ESA==} + engines: {node: '>=6'} yauzl-promise@2.1.3: - resolution: - { - integrity: sha512-A1pf6fzh6eYkK0L4Qp7g9jzJSDrM6nN0bOn5T0IbY4Yo3w+YkWlHFkJP7mzknMXjqusHFHlKsK2N+4OLsK2MRA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-A1pf6fzh6eYkK0L4Qp7g9jzJSDrM6nN0bOn5T0IbY4Yo3w+YkWlHFkJP7mzknMXjqusHFHlKsK2N+4OLsK2MRA==} + engines: {node: '>=6'} yauzl@2.10.0: - resolution: - { - integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==, - } + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} yocto-queue@0.1.0: - resolution: - { - integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} yocto-queue@1.2.2: - resolution: - { - integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==, - } - engines: { node: ">=12.20" } + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} yocto-spinner@0.2.3: - resolution: - { - integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==, - } - engines: { node: ">=18.19" } + resolution: {integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==} + engines: {node: '>=18.19'} yoctocolors-cjs@2.1.3: - resolution: - { - integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} yoctocolors@2.1.2: - resolution: - { - integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} zip-stream@6.0.1: - resolution: - { - integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==, - } - engines: { node: ">= 14" } + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} zod-to-json-schema@3.25.1: - resolution: - { - integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==, - } + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} peerDependencies: zod: ^3.25 || ^4 zod-to-ts@1.2.0: - resolution: - { - integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==, - } + resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==} peerDependencies: typescript: ^4.9.4 || ^5.0.2 zod: ^3 zod@3.22.4: - resolution: - { - integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==, - } + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} zod@3.24.4: - resolution: - { - integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==, - } + resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} zod@3.25.76: - resolution: - { - integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, - } + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} zod@4.3.6: - resolution: - { - integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==, - } + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} zwitch@2.0.4: - resolution: - { - integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==, - } + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} snapshots: - "@ai-sdk/gateway@3.0.66(zod@4.3.6)": + + '@ai-sdk/gateway@3.0.66(zod@4.3.6)': dependencies: - "@ai-sdk/provider": 3.0.8 - "@ai-sdk/provider-utils": 4.0.19(zod@4.3.6) - "@vercel/oidc": 3.1.0 + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6) + '@vercel/oidc': 3.1.0 zod: 4.3.6 - "@ai-sdk/provider-utils@4.0.19(zod@4.3.6)": + '@ai-sdk/provider-utils@4.0.19(zod@4.3.6)': dependencies: - "@ai-sdk/provider": 3.0.8 - "@standard-schema/spec": 1.1.0 + '@ai-sdk/provider': 3.0.8 + '@standard-schema/spec': 1.1.0 eventsource-parser: 3.0.6 zod: 4.3.6 - "@ai-sdk/provider@3.0.8": + '@ai-sdk/provider@3.0.8': dependencies: json-schema: 0.4.0 - "@anthropic-ai/sdk@0.73.0(zod@4.3.6)": + '@anthropic-ai/sdk@0.73.0(zod@4.3.6)': dependencies: json-schema-to-ts: 3.1.1 optionalDependencies: zod: 4.3.6 - "@appium/logger@1.7.1": + '@appium/logger@1.7.1': dependencies: console-control-strings: 1.1.0 lodash: 4.17.21 lru-cache: 10.4.3 set-blocking: 2.0.0 - "@astrojs/check@0.9.6(prettier@3.8.1)(typescript@5.9.3)": + '@astrojs/check@0.9.6(prettier@3.8.1)(typescript@5.9.3)': dependencies: - "@astrojs/language-server": 2.16.3(prettier@3.8.1)(typescript@5.9.3) + '@astrojs/language-server': 2.16.3(prettier@3.8.1)(typescript@5.9.3) chokidar: 4.0.3 kleur: 4.1.5 typescript: 5.9.3 @@ -11874,19 +7321,19 @@ snapshots: - prettier - prettier-plugin-astro - "@astrojs/compiler@2.13.1": {} + '@astrojs/compiler@2.13.1': {} - "@astrojs/internal-helpers@0.7.5": {} + '@astrojs/internal-helpers@0.7.5': {} - "@astrojs/language-server@2.16.3(prettier@3.8.1)(typescript@5.9.3)": + '@astrojs/language-server@2.16.3(prettier@3.8.1)(typescript@5.9.3)': dependencies: - "@astrojs/compiler": 2.13.1 - "@astrojs/yaml2ts": 0.2.2 - "@jridgewell/sourcemap-codec": 1.5.5 - "@volar/kit": 2.4.28(typescript@5.9.3) - "@volar/language-core": 2.4.28 - "@volar/language-server": 2.4.28 - "@volar/language-service": 2.4.28 + '@astrojs/compiler': 2.13.1 + '@astrojs/yaml2ts': 0.2.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@volar/kit': 2.4.28(typescript@5.9.3) + '@volar/language-core': 2.4.28 + '@volar/language-server': 2.4.28 + '@volar/language-service': 2.4.28 muggle-string: 0.4.1 tinyglobby: 0.2.15 volar-service-css: 0.0.68(@volar/language-service@2.4.28) @@ -11903,10 +7350,10 @@ snapshots: transitivePeerDependencies: - typescript - "@astrojs/markdown-remark@6.3.10": + '@astrojs/markdown-remark@6.3.10': dependencies: - "@astrojs/internal-helpers": 0.7.5 - "@astrojs/prism": 3.3.0 + '@astrojs/internal-helpers': 0.7.5 + '@astrojs/prism': 3.3.0 github-slugger: 2.0.0 hast-util-from-html: 2.0.3 hast-util-to-text: 4.0.2 @@ -11929,10 +7376,10 @@ snapshots: transitivePeerDependencies: - supports-color - "@astrojs/mdx@4.3.13(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))": + '@astrojs/mdx@4.3.13(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))': dependencies: - "@astrojs/markdown-remark": 6.3.10 - "@mdx-js/mdx": 3.1.1 + '@astrojs/markdown-remark': 6.3.10 + '@mdx-js/mdx': 3.1.1 acorn: 8.16.0 astro: 5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) es-module-lexer: 1.7.0 @@ -11948,25 +7395,25 @@ snapshots: transitivePeerDependencies: - supports-color - "@astrojs/prism@3.3.0": + '@astrojs/prism@3.3.0': dependencies: prismjs: 1.30.0 - "@astrojs/sitemap@3.7.0": + '@astrojs/sitemap@3.7.0': dependencies: sitemap: 8.0.3 stream-replace-string: 2.0.0 zod: 3.25.76 - "@astrojs/starlight@0.37.7(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))": + '@astrojs/starlight@0.37.7(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))': dependencies: - "@astrojs/markdown-remark": 6.3.10 - "@astrojs/mdx": 4.3.13(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) - "@astrojs/sitemap": 3.7.0 - "@pagefind/default-ui": 1.4.0 - "@types/hast": 3.0.4 - "@types/js-yaml": 4.0.9 - "@types/mdast": 4.0.4 + '@astrojs/markdown-remark': 6.3.10 + '@astrojs/mdx': 4.3.13(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) + '@astrojs/sitemap': 3.7.0 + '@pagefind/default-ui': 1.4.0 + '@types/hast': 3.0.4 + '@types/js-yaml': 4.0.9 + '@types/mdast': 4.0.4 astro: 5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) astro-expressive-code: 0.41.7(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) bcp-47: 2.1.0 @@ -11992,7 +7439,7 @@ snapshots: transitivePeerDependencies: - supports-color - "@astrojs/telemetry@3.3.0": + '@astrojs/telemetry@3.3.0': dependencies: ci-info: 4.4.0 debug: 4.4.3 @@ -12004,404 +7451,404 @@ snapshots: transitivePeerDependencies: - supports-color - "@astrojs/yaml2ts@0.2.2": + '@astrojs/yaml2ts@0.2.2': dependencies: yaml: 2.8.2 - "@aws-crypto/crc32@5.2.0": + '@aws-crypto/crc32@5.2.0': dependencies: - "@aws-crypto/util": 5.2.0 - "@aws-sdk/types": 3.973.5 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.5 tslib: 2.8.1 - "@aws-crypto/sha256-browser@5.2.0": + '@aws-crypto/sha256-browser@5.2.0': dependencies: - "@aws-crypto/sha256-js": 5.2.0 - "@aws-crypto/supports-web-crypto": 5.2.0 - "@aws-crypto/util": 5.2.0 - "@aws-sdk/types": 3.973.5 - "@aws-sdk/util-locate-window": 3.965.5 - "@smithy/util-utf8": 2.3.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.5 + '@aws-sdk/util-locate-window': 3.965.5 + '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - "@aws-crypto/sha256-js@5.2.0": + '@aws-crypto/sha256-js@5.2.0': dependencies: - "@aws-crypto/util": 5.2.0 - "@aws-sdk/types": 3.973.5 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.5 tslib: 2.8.1 - "@aws-crypto/supports-web-crypto@5.2.0": + '@aws-crypto/supports-web-crypto@5.2.0': dependencies: tslib: 2.8.1 - "@aws-crypto/util@5.2.0": + '@aws-crypto/util@5.2.0': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/util-utf8": 2.3.0 + '@aws-sdk/types': 3.973.5 + '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - "@aws-sdk/client-bedrock-runtime@3.1003.0": - dependencies: - "@aws-crypto/sha256-browser": 5.2.0 - "@aws-crypto/sha256-js": 5.2.0 - "@aws-sdk/core": 3.973.18 - "@aws-sdk/credential-provider-node": 3.972.17 - "@aws-sdk/eventstream-handler-node": 3.972.10 - "@aws-sdk/middleware-eventstream": 3.972.7 - "@aws-sdk/middleware-host-header": 3.972.7 - "@aws-sdk/middleware-logger": 3.972.7 - "@aws-sdk/middleware-recursion-detection": 3.972.7 - "@aws-sdk/middleware-user-agent": 3.972.18 - "@aws-sdk/middleware-websocket": 3.972.12 - "@aws-sdk/region-config-resolver": 3.972.7 - "@aws-sdk/token-providers": 3.1003.0 - "@aws-sdk/types": 3.973.5 - "@aws-sdk/util-endpoints": 3.996.4 - "@aws-sdk/util-user-agent-browser": 3.972.7 - "@aws-sdk/util-user-agent-node": 3.973.3 - "@smithy/config-resolver": 4.4.10 - "@smithy/core": 3.23.9 - "@smithy/eventstream-serde-browser": 4.2.11 - "@smithy/eventstream-serde-config-resolver": 4.3.11 - "@smithy/eventstream-serde-node": 4.2.11 - "@smithy/fetch-http-handler": 5.3.13 - "@smithy/hash-node": 4.2.11 - "@smithy/invalid-dependency": 4.2.11 - "@smithy/middleware-content-length": 4.2.11 - "@smithy/middleware-endpoint": 4.4.23 - "@smithy/middleware-retry": 4.4.40 - "@smithy/middleware-serde": 4.2.12 - "@smithy/middleware-stack": 4.2.11 - "@smithy/node-config-provider": 4.3.11 - "@smithy/node-http-handler": 4.4.14 - "@smithy/protocol-http": 5.3.11 - "@smithy/smithy-client": 4.12.3 - "@smithy/types": 4.13.0 - "@smithy/url-parser": 4.2.11 - "@smithy/util-base64": 4.3.2 - "@smithy/util-body-length-browser": 4.2.2 - "@smithy/util-body-length-node": 4.2.3 - "@smithy/util-defaults-mode-browser": 4.3.39 - "@smithy/util-defaults-mode-node": 4.2.42 - "@smithy/util-endpoints": 3.3.2 - "@smithy/util-middleware": 4.2.11 - "@smithy/util-retry": 4.2.11 - "@smithy/util-stream": 4.5.17 - "@smithy/util-utf8": 4.2.2 + '@aws-sdk/client-bedrock-runtime@3.1003.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/credential-provider-node': 3.972.17 + '@aws-sdk/eventstream-handler-node': 3.972.10 + '@aws-sdk/middleware-eventstream': 3.972.7 + '@aws-sdk/middleware-host-header': 3.972.7 + '@aws-sdk/middleware-logger': 3.972.7 + '@aws-sdk/middleware-recursion-detection': 3.972.7 + '@aws-sdk/middleware-user-agent': 3.972.18 + '@aws-sdk/middleware-websocket': 3.972.12 + '@aws-sdk/region-config-resolver': 3.972.7 + '@aws-sdk/token-providers': 3.1003.0 + '@aws-sdk/types': 3.973.5 + '@aws-sdk/util-endpoints': 3.996.4 + '@aws-sdk/util-user-agent-browser': 3.972.7 + '@aws-sdk/util-user-agent-node': 3.973.3 + '@smithy/config-resolver': 4.4.10 + '@smithy/core': 3.23.9 + '@smithy/eventstream-serde-browser': 4.2.11 + '@smithy/eventstream-serde-config-resolver': 4.3.11 + '@smithy/eventstream-serde-node': 4.2.11 + '@smithy/fetch-http-handler': 5.3.13 + '@smithy/hash-node': 4.2.11 + '@smithy/invalid-dependency': 4.2.11 + '@smithy/middleware-content-length': 4.2.11 + '@smithy/middleware-endpoint': 4.4.23 + '@smithy/middleware-retry': 4.4.40 + '@smithy/middleware-serde': 4.2.12 + '@smithy/middleware-stack': 4.2.11 + '@smithy/node-config-provider': 4.3.11 + '@smithy/node-http-handler': 4.4.14 + '@smithy/protocol-http': 5.3.11 + '@smithy/smithy-client': 4.12.3 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.11 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.39 + '@smithy/util-defaults-mode-node': 4.2.42 + '@smithy/util-endpoints': 3.3.2 + '@smithy/util-middleware': 4.2.11 + '@smithy/util-retry': 4.2.11 + '@smithy/util-stream': 4.5.17 + '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - "@aws-sdk/core@3.973.18": - dependencies: - "@aws-sdk/types": 3.973.5 - "@aws-sdk/xml-builder": 3.972.10 - "@smithy/core": 3.23.9 - "@smithy/node-config-provider": 4.3.11 - "@smithy/property-provider": 4.2.11 - "@smithy/protocol-http": 5.3.11 - "@smithy/signature-v4": 5.3.11 - "@smithy/smithy-client": 4.12.3 - "@smithy/types": 4.13.0 - "@smithy/util-base64": 4.3.2 - "@smithy/util-middleware": 4.2.11 - "@smithy/util-utf8": 4.2.2 + '@aws-sdk/core@3.973.18': + dependencies: + '@aws-sdk/types': 3.973.5 + '@aws-sdk/xml-builder': 3.972.10 + '@smithy/core': 3.23.9 + '@smithy/node-config-provider': 4.3.11 + '@smithy/property-provider': 4.2.11 + '@smithy/protocol-http': 5.3.11 + '@smithy/signature-v4': 5.3.11 + '@smithy/smithy-client': 4.12.3 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-middleware': 4.2.11 + '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - "@aws-sdk/credential-provider-env@3.972.16": + '@aws-sdk/credential-provider-env@3.972.16': dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/types": 3.973.5 - "@smithy/property-provider": 4.2.11 - "@smithy/types": 4.13.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/types': 3.973.5 + '@smithy/property-provider': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/credential-provider-http@3.972.18": - dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/types": 3.973.5 - "@smithy/fetch-http-handler": 5.3.13 - "@smithy/node-http-handler": 4.4.14 - "@smithy/property-provider": 4.2.11 - "@smithy/protocol-http": 5.3.11 - "@smithy/smithy-client": 4.12.3 - "@smithy/types": 4.13.0 - "@smithy/util-stream": 4.5.17 + '@aws-sdk/credential-provider-http@3.972.18': + dependencies: + '@aws-sdk/core': 3.973.18 + '@aws-sdk/types': 3.973.5 + '@smithy/fetch-http-handler': 5.3.13 + '@smithy/node-http-handler': 4.4.14 + '@smithy/property-provider': 4.2.11 + '@smithy/protocol-http': 5.3.11 + '@smithy/smithy-client': 4.12.3 + '@smithy/types': 4.13.0 + '@smithy/util-stream': 4.5.17 tslib: 2.8.1 - "@aws-sdk/credential-provider-ini@3.972.16": - dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/credential-provider-env": 3.972.16 - "@aws-sdk/credential-provider-http": 3.972.18 - "@aws-sdk/credential-provider-login": 3.972.16 - "@aws-sdk/credential-provider-process": 3.972.16 - "@aws-sdk/credential-provider-sso": 3.972.16 - "@aws-sdk/credential-provider-web-identity": 3.972.16 - "@aws-sdk/nested-clients": 3.996.6 - "@aws-sdk/types": 3.973.5 - "@smithy/credential-provider-imds": 4.2.11 - "@smithy/property-provider": 4.2.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 + '@aws-sdk/credential-provider-ini@3.972.16': + dependencies: + '@aws-sdk/core': 3.973.18 + '@aws-sdk/credential-provider-env': 3.972.16 + '@aws-sdk/credential-provider-http': 3.972.18 + '@aws-sdk/credential-provider-login': 3.972.16 + '@aws-sdk/credential-provider-process': 3.972.16 + '@aws-sdk/credential-provider-sso': 3.972.16 + '@aws-sdk/credential-provider-web-identity': 3.972.16 + '@aws-sdk/nested-clients': 3.996.6 + '@aws-sdk/types': 3.973.5 + '@smithy/credential-provider-imds': 4.2.11 + '@smithy/property-provider': 4.2.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - "@aws-sdk/credential-provider-login@3.972.16": + '@aws-sdk/credential-provider-login@3.972.16': dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/nested-clients": 3.996.6 - "@aws-sdk/types": 3.973.5 - "@smithy/property-provider": 4.2.11 - "@smithy/protocol-http": 5.3.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/nested-clients': 3.996.6 + '@aws-sdk/types': 3.973.5 + '@smithy/property-provider': 4.2.11 + '@smithy/protocol-http': 5.3.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - "@aws-sdk/credential-provider-node@3.972.17": - dependencies: - "@aws-sdk/credential-provider-env": 3.972.16 - "@aws-sdk/credential-provider-http": 3.972.18 - "@aws-sdk/credential-provider-ini": 3.972.16 - "@aws-sdk/credential-provider-process": 3.972.16 - "@aws-sdk/credential-provider-sso": 3.972.16 - "@aws-sdk/credential-provider-web-identity": 3.972.16 - "@aws-sdk/types": 3.973.5 - "@smithy/credential-provider-imds": 4.2.11 - "@smithy/property-provider": 4.2.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 + '@aws-sdk/credential-provider-node@3.972.17': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.16 + '@aws-sdk/credential-provider-http': 3.972.18 + '@aws-sdk/credential-provider-ini': 3.972.16 + '@aws-sdk/credential-provider-process': 3.972.16 + '@aws-sdk/credential-provider-sso': 3.972.16 + '@aws-sdk/credential-provider-web-identity': 3.972.16 + '@aws-sdk/types': 3.973.5 + '@smithy/credential-provider-imds': 4.2.11 + '@smithy/property-provider': 4.2.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - "@aws-sdk/credential-provider-process@3.972.16": + '@aws-sdk/credential-provider-process@3.972.16': dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/types": 3.973.5 - "@smithy/property-provider": 4.2.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/types': 3.973.5 + '@smithy/property-provider': 4.2.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/credential-provider-sso@3.972.16": + '@aws-sdk/credential-provider-sso@3.972.16': dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/nested-clients": 3.996.6 - "@aws-sdk/token-providers": 3.1003.0 - "@aws-sdk/types": 3.973.5 - "@smithy/property-provider": 4.2.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/nested-clients': 3.996.6 + '@aws-sdk/token-providers': 3.1003.0 + '@aws-sdk/types': 3.973.5 + '@smithy/property-provider': 4.2.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - "@aws-sdk/credential-provider-web-identity@3.972.16": + '@aws-sdk/credential-provider-web-identity@3.972.16': dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/nested-clients": 3.996.6 - "@aws-sdk/types": 3.973.5 - "@smithy/property-provider": 4.2.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/nested-clients': 3.996.6 + '@aws-sdk/types': 3.973.5 + '@smithy/property-provider': 4.2.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - "@aws-sdk/eventstream-handler-node@3.972.10": + '@aws-sdk/eventstream-handler-node@3.972.10': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/eventstream-codec": 4.2.11 - "@smithy/types": 4.13.0 + '@aws-sdk/types': 3.973.5 + '@smithy/eventstream-codec': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/middleware-eventstream@3.972.7": + '@aws-sdk/middleware-eventstream@3.972.7': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 + '@aws-sdk/types': 3.973.5 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/middleware-host-header@3.972.7": + '@aws-sdk/middleware-host-header@3.972.7': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 + '@aws-sdk/types': 3.973.5 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/middleware-logger@3.972.7": + '@aws-sdk/middleware-logger@3.972.7': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/types": 4.13.0 + '@aws-sdk/types': 3.973.5 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/middleware-recursion-detection@3.972.7": + '@aws-sdk/middleware-recursion-detection@3.972.7': dependencies: - "@aws-sdk/types": 3.973.5 - "@aws/lambda-invoke-store": 0.2.3 - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 + '@aws-sdk/types': 3.973.5 + '@aws/lambda-invoke-store': 0.2.3 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/middleware-user-agent@3.972.18": + '@aws-sdk/middleware-user-agent@3.972.18': dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/types": 3.973.5 - "@aws-sdk/util-endpoints": 3.996.4 - "@smithy/core": 3.23.9 - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/types': 3.973.5 + '@aws-sdk/util-endpoints': 3.996.4 + '@smithy/core': 3.23.9 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/middleware-websocket@3.972.12": - dependencies: - "@aws-sdk/types": 3.973.5 - "@aws-sdk/util-format-url": 3.972.7 - "@smithy/eventstream-codec": 4.2.11 - "@smithy/eventstream-serde-browser": 4.2.11 - "@smithy/fetch-http-handler": 5.3.13 - "@smithy/protocol-http": 5.3.11 - "@smithy/signature-v4": 5.3.11 - "@smithy/types": 4.13.0 - "@smithy/util-base64": 4.3.2 - "@smithy/util-hex-encoding": 4.2.2 - "@smithy/util-utf8": 4.2.2 + '@aws-sdk/middleware-websocket@3.972.12': + dependencies: + '@aws-sdk/types': 3.973.5 + '@aws-sdk/util-format-url': 3.972.7 + '@smithy/eventstream-codec': 4.2.11 + '@smithy/eventstream-serde-browser': 4.2.11 + '@smithy/fetch-http-handler': 5.3.13 + '@smithy/protocol-http': 5.3.11 + '@smithy/signature-v4': 5.3.11 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - "@aws-sdk/nested-clients@3.996.6": - dependencies: - "@aws-crypto/sha256-browser": 5.2.0 - "@aws-crypto/sha256-js": 5.2.0 - "@aws-sdk/core": 3.973.18 - "@aws-sdk/middleware-host-header": 3.972.7 - "@aws-sdk/middleware-logger": 3.972.7 - "@aws-sdk/middleware-recursion-detection": 3.972.7 - "@aws-sdk/middleware-user-agent": 3.972.18 - "@aws-sdk/region-config-resolver": 3.972.7 - "@aws-sdk/types": 3.973.5 - "@aws-sdk/util-endpoints": 3.996.4 - "@aws-sdk/util-user-agent-browser": 3.972.7 - "@aws-sdk/util-user-agent-node": 3.973.3 - "@smithy/config-resolver": 4.4.10 - "@smithy/core": 3.23.9 - "@smithy/fetch-http-handler": 5.3.13 - "@smithy/hash-node": 4.2.11 - "@smithy/invalid-dependency": 4.2.11 - "@smithy/middleware-content-length": 4.2.11 - "@smithy/middleware-endpoint": 4.4.23 - "@smithy/middleware-retry": 4.4.40 - "@smithy/middleware-serde": 4.2.12 - "@smithy/middleware-stack": 4.2.11 - "@smithy/node-config-provider": 4.3.11 - "@smithy/node-http-handler": 4.4.14 - "@smithy/protocol-http": 5.3.11 - "@smithy/smithy-client": 4.12.3 - "@smithy/types": 4.13.0 - "@smithy/url-parser": 4.2.11 - "@smithy/util-base64": 4.3.2 - "@smithy/util-body-length-browser": 4.2.2 - "@smithy/util-body-length-node": 4.2.3 - "@smithy/util-defaults-mode-browser": 4.3.39 - "@smithy/util-defaults-mode-node": 4.2.42 - "@smithy/util-endpoints": 3.3.2 - "@smithy/util-middleware": 4.2.11 - "@smithy/util-retry": 4.2.11 - "@smithy/util-utf8": 4.2.2 + '@aws-sdk/nested-clients@3.996.6': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/middleware-host-header': 3.972.7 + '@aws-sdk/middleware-logger': 3.972.7 + '@aws-sdk/middleware-recursion-detection': 3.972.7 + '@aws-sdk/middleware-user-agent': 3.972.18 + '@aws-sdk/region-config-resolver': 3.972.7 + '@aws-sdk/types': 3.973.5 + '@aws-sdk/util-endpoints': 3.996.4 + '@aws-sdk/util-user-agent-browser': 3.972.7 + '@aws-sdk/util-user-agent-node': 3.973.3 + '@smithy/config-resolver': 4.4.10 + '@smithy/core': 3.23.9 + '@smithy/fetch-http-handler': 5.3.13 + '@smithy/hash-node': 4.2.11 + '@smithy/invalid-dependency': 4.2.11 + '@smithy/middleware-content-length': 4.2.11 + '@smithy/middleware-endpoint': 4.4.23 + '@smithy/middleware-retry': 4.4.40 + '@smithy/middleware-serde': 4.2.12 + '@smithy/middleware-stack': 4.2.11 + '@smithy/node-config-provider': 4.3.11 + '@smithy/node-http-handler': 4.4.14 + '@smithy/protocol-http': 5.3.11 + '@smithy/smithy-client': 4.12.3 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.11 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.39 + '@smithy/util-defaults-mode-node': 4.2.42 + '@smithy/util-endpoints': 3.3.2 + '@smithy/util-middleware': 4.2.11 + '@smithy/util-retry': 4.2.11 + '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - "@aws-sdk/region-config-resolver@3.972.7": + '@aws-sdk/region-config-resolver@3.972.7': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/config-resolver": 4.4.10 - "@smithy/node-config-provider": 4.3.11 - "@smithy/types": 4.13.0 + '@aws-sdk/types': 3.973.5 + '@smithy/config-resolver': 4.4.10 + '@smithy/node-config-provider': 4.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/token-providers@3.1003.0": + '@aws-sdk/token-providers@3.1003.0': dependencies: - "@aws-sdk/core": 3.973.18 - "@aws-sdk/nested-clients": 3.996.6 - "@aws-sdk/types": 3.973.5 - "@smithy/property-provider": 4.2.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 + '@aws-sdk/core': 3.973.18 + '@aws-sdk/nested-clients': 3.996.6 + '@aws-sdk/types': 3.973.5 + '@smithy/property-provider': 4.2.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - "@aws-sdk/types@3.973.5": + '@aws-sdk/types@3.973.5': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/util-endpoints@3.996.4": + '@aws-sdk/util-endpoints@3.996.4': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/types": 4.13.0 - "@smithy/url-parser": 4.2.11 - "@smithy/util-endpoints": 3.3.2 + '@aws-sdk/types': 3.973.5 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.11 + '@smithy/util-endpoints': 3.3.2 tslib: 2.8.1 - "@aws-sdk/util-format-url@3.972.7": + '@aws-sdk/util-format-url@3.972.7': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/querystring-builder": 4.2.11 - "@smithy/types": 4.13.0 + '@aws-sdk/types': 3.973.5 + '@smithy/querystring-builder': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/util-locate-window@3.965.5": + '@aws-sdk/util-locate-window@3.965.5': dependencies: tslib: 2.8.1 - "@aws-sdk/util-user-agent-browser@3.972.7": + '@aws-sdk/util-user-agent-browser@3.972.7': dependencies: - "@aws-sdk/types": 3.973.5 - "@smithy/types": 4.13.0 + '@aws-sdk/types': 3.973.5 + '@smithy/types': 4.13.0 bowser: 2.14.1 tslib: 2.8.1 - "@aws-sdk/util-user-agent-node@3.973.3": + '@aws-sdk/util-user-agent-node@3.973.3': dependencies: - "@aws-sdk/middleware-user-agent": 3.972.18 - "@aws-sdk/types": 3.973.5 - "@smithy/node-config-provider": 4.3.11 - "@smithy/types": 4.13.0 + '@aws-sdk/middleware-user-agent': 3.972.18 + '@aws-sdk/types': 3.973.5 + '@smithy/node-config-provider': 4.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@aws-sdk/xml-builder@3.972.10": + '@aws-sdk/xml-builder@3.972.10': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 fast-xml-parser: 5.4.1 tslib: 2.8.1 - "@aws/lambda-invoke-store@0.2.3": {} + '@aws/lambda-invoke-store@0.2.3': {} - "@babel/code-frame@7.29.0": + '@babel/code-frame@7.29.0': dependencies: - "@babel/helper-validator-identifier": 7.28.5 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - "@babel/compat-data@7.29.0": {} + '@babel/compat-data@7.29.0': {} - "@babel/core@7.29.0": + '@babel/core@7.29.0': dependencies: - "@babel/code-frame": 7.29.0 - "@babel/generator": 7.29.1 - "@babel/helper-compilation-targets": 7.28.6 - "@babel/helper-module-transforms": 7.28.6(@babel/core@7.29.0) - "@babel/helpers": 7.28.6 - "@babel/parser": 7.29.0 - "@babel/template": 7.28.6 - "@babel/traverse": 7.29.0 - "@babel/types": 7.29.0 - "@jridgewell/remapping": 2.3.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 gensync: 1.0.0-beta.2 @@ -12410,407 +7857,407 @@ snapshots: transitivePeerDependencies: - supports-color - "@babel/generator@7.29.1": + '@babel/generator@7.29.1': dependencies: - "@babel/parser": 7.29.0 - "@babel/types": 7.29.0 - "@jridgewell/gen-mapping": 0.3.13 - "@jridgewell/trace-mapping": 0.3.31 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - "@babel/helper-compilation-targets@7.28.6": + '@babel/helper-compilation-targets@7.28.6': dependencies: - "@babel/compat-data": 7.29.0 - "@babel/helper-validator-option": 7.27.1 + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 - "@babel/helper-globals@7.28.0": {} + '@babel/helper-globals@7.28.0': {} - "@babel/helper-module-imports@7.28.6": + '@babel/helper-module-imports@7.28.6': dependencies: - "@babel/traverse": 7.29.0 - "@babel/types": 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - "@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)": + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - "@babel/core": 7.29.0 - "@babel/helper-module-imports": 7.28.6 - "@babel/helper-validator-identifier": 7.28.5 - "@babel/traverse": 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - "@babel/helper-string-parser@7.27.1": {} + '@babel/helper-string-parser@7.27.1': {} - "@babel/helper-validator-identifier@7.28.5": {} + '@babel/helper-validator-identifier@7.28.5': {} - "@babel/helper-validator-option@7.27.1": {} + '@babel/helper-validator-option@7.27.1': {} - "@babel/helpers@7.28.6": + '@babel/helpers@7.28.6': dependencies: - "@babel/template": 7.28.6 - "@babel/types": 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - "@babel/parser@7.29.0": + '@babel/parser@7.29.0': dependencies: - "@babel/types": 7.29.0 + '@babel/types': 7.29.0 - "@babel/runtime@7.28.6": {} + '@babel/runtime@7.28.6': {} - "@babel/template@7.28.6": + '@babel/template@7.28.6': dependencies: - "@babel/code-frame": 7.29.0 - "@babel/parser": 7.29.0 - "@babel/types": 7.29.0 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - "@babel/traverse@7.29.0": + '@babel/traverse@7.29.0': dependencies: - "@babel/code-frame": 7.29.0 - "@babel/generator": 7.29.1 - "@babel/helper-globals": 7.28.0 - "@babel/parser": 7.29.0 - "@babel/template": 7.28.6 - "@babel/types": 7.29.0 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 debug: 4.4.3 transitivePeerDependencies: - supports-color - "@babel/types@7.29.0": + '@babel/types@7.29.0': dependencies: - "@babel/helper-string-parser": 7.27.1 - "@babel/helper-validator-identifier": 7.28.5 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 - "@borewit/text-codec@0.2.1": {} + '@borewit/text-codec@0.2.1': {} - "@bytecodealliance/preview2-shim@0.17.6": {} + '@bytecodealliance/preview2-shim@0.17.6': {} - "@capsizecss/unpack@4.0.0": + '@capsizecss/unpack@4.0.0': dependencies: fontkitten: 1.0.3 - "@chat-adapter/shared@4.20.2": + '@chat-adapter/shared@4.20.2': dependencies: chat: 4.20.2 transitivePeerDependencies: - supports-color - "@chat-adapter/slack@4.20.2": + '@chat-adapter/slack@4.20.2': dependencies: - "@chat-adapter/shared": 4.20.2 - "@slack/web-api": 7.15.0 + '@chat-adapter/shared': 4.20.2 + '@slack/web-api': 7.15.0 chat: 4.20.2 transitivePeerDependencies: - debug - supports-color - "@chat-adapter/state-memory@4.20.2": + '@chat-adapter/state-memory@4.20.2': dependencies: chat: 4.20.2 transitivePeerDependencies: - supports-color - "@chat-adapter/state-redis@4.20.2": + '@chat-adapter/state-redis@4.20.2': dependencies: chat: 4.20.2 redis: 5.11.0 transitivePeerDependencies: - - "@node-rs/xxhash" + - '@node-rs/xxhash' - supports-color - "@ctrl/tinycolor@4.2.0": {} + '@ctrl/tinycolor@4.2.0': {} - "@edge-runtime/format@2.2.1": {} + '@edge-runtime/format@2.2.1': {} - "@edge-runtime/node-utils@2.3.0": {} + '@edge-runtime/node-utils@2.3.0': {} - "@edge-runtime/ponyfill@2.4.2": {} + '@edge-runtime/ponyfill@2.4.2': {} - "@edge-runtime/primitives@4.1.0": {} + '@edge-runtime/primitives@4.1.0': {} - "@edge-runtime/vm@3.2.0": + '@edge-runtime/vm@3.2.0': dependencies: - "@edge-runtime/primitives": 4.1.0 + '@edge-runtime/primitives': 4.1.0 - "@emmetio/abbreviation@2.3.3": + '@emmetio/abbreviation@2.3.3': dependencies: - "@emmetio/scanner": 1.0.4 + '@emmetio/scanner': 1.0.4 - "@emmetio/css-abbreviation@2.1.8": + '@emmetio/css-abbreviation@2.1.8': dependencies: - "@emmetio/scanner": 1.0.4 + '@emmetio/scanner': 1.0.4 - "@emmetio/css-parser@0.4.1": + '@emmetio/css-parser@0.4.1': dependencies: - "@emmetio/stream-reader": 2.2.0 - "@emmetio/stream-reader-utils": 0.1.0 + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 - "@emmetio/html-matcher@1.3.0": + '@emmetio/html-matcher@1.3.0': dependencies: - "@emmetio/scanner": 1.0.4 + '@emmetio/scanner': 1.0.4 - "@emmetio/scanner@1.0.4": {} + '@emmetio/scanner@1.0.4': {} - "@emmetio/stream-reader-utils@0.1.0": {} + '@emmetio/stream-reader-utils@0.1.0': {} - "@emmetio/stream-reader@2.2.0": {} + '@emmetio/stream-reader@2.2.0': {} - "@emnapi/core@1.8.1": + '@emnapi/core@1.8.1': dependencies: - "@emnapi/wasi-threads": 1.1.0 + '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - "@emnapi/runtime@1.9.0": + '@emnapi/runtime@1.9.0': dependencies: tslib: 2.8.1 optional: true - "@emnapi/wasi-threads@1.1.0": + '@emnapi/wasi-threads@1.1.0': dependencies: tslib: 2.8.1 optional: true - "@esbuild/aix-ppc64@0.25.12": + '@esbuild/aix-ppc64@0.25.12': optional: true - "@esbuild/aix-ppc64@0.27.0": + '@esbuild/aix-ppc64@0.27.0': optional: true - "@esbuild/aix-ppc64@0.27.3": + '@esbuild/aix-ppc64@0.27.3': optional: true - "@esbuild/android-arm64@0.25.12": + '@esbuild/android-arm64@0.25.12': optional: true - "@esbuild/android-arm64@0.27.0": + '@esbuild/android-arm64@0.27.0': optional: true - "@esbuild/android-arm64@0.27.3": + '@esbuild/android-arm64@0.27.3': optional: true - "@esbuild/android-arm@0.25.12": + '@esbuild/android-arm@0.25.12': optional: true - "@esbuild/android-arm@0.27.0": + '@esbuild/android-arm@0.27.0': optional: true - "@esbuild/android-arm@0.27.3": + '@esbuild/android-arm@0.27.3': optional: true - "@esbuild/android-x64@0.25.12": + '@esbuild/android-x64@0.25.12': optional: true - "@esbuild/android-x64@0.27.0": + '@esbuild/android-x64@0.27.0': optional: true - "@esbuild/android-x64@0.27.3": + '@esbuild/android-x64@0.27.3': optional: true - "@esbuild/darwin-arm64@0.25.12": + '@esbuild/darwin-arm64@0.25.12': optional: true - "@esbuild/darwin-arm64@0.27.0": + '@esbuild/darwin-arm64@0.27.0': optional: true - "@esbuild/darwin-arm64@0.27.3": + '@esbuild/darwin-arm64@0.27.3': optional: true - "@esbuild/darwin-x64@0.25.12": + '@esbuild/darwin-x64@0.25.12': optional: true - "@esbuild/darwin-x64@0.27.0": + '@esbuild/darwin-x64@0.27.0': optional: true - "@esbuild/darwin-x64@0.27.3": + '@esbuild/darwin-x64@0.27.3': optional: true - "@esbuild/freebsd-arm64@0.25.12": + '@esbuild/freebsd-arm64@0.25.12': optional: true - "@esbuild/freebsd-arm64@0.27.0": + '@esbuild/freebsd-arm64@0.27.0': optional: true - "@esbuild/freebsd-arm64@0.27.3": + '@esbuild/freebsd-arm64@0.27.3': optional: true - "@esbuild/freebsd-x64@0.25.12": + '@esbuild/freebsd-x64@0.25.12': optional: true - "@esbuild/freebsd-x64@0.27.0": + '@esbuild/freebsd-x64@0.27.0': optional: true - "@esbuild/freebsd-x64@0.27.3": + '@esbuild/freebsd-x64@0.27.3': optional: true - "@esbuild/linux-arm64@0.25.12": + '@esbuild/linux-arm64@0.25.12': optional: true - "@esbuild/linux-arm64@0.27.0": + '@esbuild/linux-arm64@0.27.0': optional: true - "@esbuild/linux-arm64@0.27.3": + '@esbuild/linux-arm64@0.27.3': optional: true - "@esbuild/linux-arm@0.25.12": + '@esbuild/linux-arm@0.25.12': optional: true - "@esbuild/linux-arm@0.27.0": + '@esbuild/linux-arm@0.27.0': optional: true - "@esbuild/linux-arm@0.27.3": + '@esbuild/linux-arm@0.27.3': optional: true - "@esbuild/linux-ia32@0.25.12": + '@esbuild/linux-ia32@0.25.12': optional: true - "@esbuild/linux-ia32@0.27.0": + '@esbuild/linux-ia32@0.27.0': optional: true - "@esbuild/linux-ia32@0.27.3": + '@esbuild/linux-ia32@0.27.3': optional: true - "@esbuild/linux-loong64@0.25.12": + '@esbuild/linux-loong64@0.25.12': optional: true - "@esbuild/linux-loong64@0.27.0": + '@esbuild/linux-loong64@0.27.0': optional: true - "@esbuild/linux-loong64@0.27.3": + '@esbuild/linux-loong64@0.27.3': optional: true - "@esbuild/linux-mips64el@0.25.12": + '@esbuild/linux-mips64el@0.25.12': optional: true - "@esbuild/linux-mips64el@0.27.0": + '@esbuild/linux-mips64el@0.27.0': optional: true - "@esbuild/linux-mips64el@0.27.3": + '@esbuild/linux-mips64el@0.27.3': optional: true - "@esbuild/linux-ppc64@0.25.12": + '@esbuild/linux-ppc64@0.25.12': optional: true - "@esbuild/linux-ppc64@0.27.0": + '@esbuild/linux-ppc64@0.27.0': optional: true - "@esbuild/linux-ppc64@0.27.3": + '@esbuild/linux-ppc64@0.27.3': optional: true - "@esbuild/linux-riscv64@0.25.12": + '@esbuild/linux-riscv64@0.25.12': optional: true - "@esbuild/linux-riscv64@0.27.0": + '@esbuild/linux-riscv64@0.27.0': optional: true - "@esbuild/linux-riscv64@0.27.3": + '@esbuild/linux-riscv64@0.27.3': optional: true - "@esbuild/linux-s390x@0.25.12": + '@esbuild/linux-s390x@0.25.12': optional: true - "@esbuild/linux-s390x@0.27.0": + '@esbuild/linux-s390x@0.27.0': optional: true - "@esbuild/linux-s390x@0.27.3": + '@esbuild/linux-s390x@0.27.3': optional: true - "@esbuild/linux-x64@0.25.12": + '@esbuild/linux-x64@0.25.12': optional: true - "@esbuild/linux-x64@0.27.0": + '@esbuild/linux-x64@0.27.0': optional: true - "@esbuild/linux-x64@0.27.3": + '@esbuild/linux-x64@0.27.3': optional: true - "@esbuild/netbsd-arm64@0.25.12": + '@esbuild/netbsd-arm64@0.25.12': optional: true - "@esbuild/netbsd-arm64@0.27.0": + '@esbuild/netbsd-arm64@0.27.0': optional: true - "@esbuild/netbsd-arm64@0.27.3": + '@esbuild/netbsd-arm64@0.27.3': optional: true - "@esbuild/netbsd-x64@0.25.12": + '@esbuild/netbsd-x64@0.25.12': optional: true - "@esbuild/netbsd-x64@0.27.0": + '@esbuild/netbsd-x64@0.27.0': optional: true - "@esbuild/netbsd-x64@0.27.3": + '@esbuild/netbsd-x64@0.27.3': optional: true - "@esbuild/openbsd-arm64@0.25.12": + '@esbuild/openbsd-arm64@0.25.12': optional: true - "@esbuild/openbsd-arm64@0.27.0": + '@esbuild/openbsd-arm64@0.27.0': optional: true - "@esbuild/openbsd-arm64@0.27.3": + '@esbuild/openbsd-arm64@0.27.3': optional: true - "@esbuild/openbsd-x64@0.25.12": + '@esbuild/openbsd-x64@0.25.12': optional: true - "@esbuild/openbsd-x64@0.27.0": + '@esbuild/openbsd-x64@0.27.0': optional: true - "@esbuild/openbsd-x64@0.27.3": + '@esbuild/openbsd-x64@0.27.3': optional: true - "@esbuild/openharmony-arm64@0.25.12": + '@esbuild/openharmony-arm64@0.25.12': optional: true - "@esbuild/openharmony-arm64@0.27.0": + '@esbuild/openharmony-arm64@0.27.0': optional: true - "@esbuild/openharmony-arm64@0.27.3": + '@esbuild/openharmony-arm64@0.27.3': optional: true - "@esbuild/sunos-x64@0.25.12": + '@esbuild/sunos-x64@0.25.12': optional: true - "@esbuild/sunos-x64@0.27.0": + '@esbuild/sunos-x64@0.27.0': optional: true - "@esbuild/sunos-x64@0.27.3": + '@esbuild/sunos-x64@0.27.3': optional: true - "@esbuild/win32-arm64@0.25.12": + '@esbuild/win32-arm64@0.25.12': optional: true - "@esbuild/win32-arm64@0.27.0": + '@esbuild/win32-arm64@0.27.0': optional: true - "@esbuild/win32-arm64@0.27.3": + '@esbuild/win32-arm64@0.27.3': optional: true - "@esbuild/win32-ia32@0.25.12": + '@esbuild/win32-ia32@0.25.12': optional: true - "@esbuild/win32-ia32@0.27.0": + '@esbuild/win32-ia32@0.27.0': optional: true - "@esbuild/win32-ia32@0.27.3": + '@esbuild/win32-ia32@0.27.3': optional: true - "@esbuild/win32-x64@0.25.12": + '@esbuild/win32-x64@0.25.12': optional: true - "@esbuild/win32-x64@0.27.0": + '@esbuild/win32-x64@0.27.0': optional: true - "@esbuild/win32-x64@0.27.3": + '@esbuild/win32-x64@0.27.3': optional: true - "@expressive-code/core@0.41.7": + '@expressive-code/core@0.41.7': dependencies: - "@ctrl/tinycolor": 4.2.0 + '@ctrl/tinycolor': 4.2.0 hast-util-select: 6.0.4 hast-util-to-html: 9.0.5 hast-util-to-text: 4.0.2 @@ -12820,198 +8267,204 @@ snapshots: unist-util-visit: 5.1.0 unist-util-visit-parents: 6.0.2 - "@expressive-code/plugin-frames@0.41.7": + '@expressive-code/plugin-frames@0.41.7': dependencies: - "@expressive-code/core": 0.41.7 + '@expressive-code/core': 0.41.7 - "@expressive-code/plugin-shiki@0.41.7": + '@expressive-code/plugin-shiki@0.41.7': dependencies: - "@expressive-code/core": 0.41.7 + '@expressive-code/core': 0.41.7 shiki: 3.23.0 - "@expressive-code/plugin-text-markers@0.41.7": + '@expressive-code/plugin-text-markers@0.41.7': dependencies: - "@expressive-code/core": 0.41.7 + '@expressive-code/core': 0.41.7 - "@fastify/busboy@2.1.1": {} + '@fastify/busboy@2.1.1': {} - "@fastify/otel@0.16.0(@opentelemetry/api@1.9.0)": + '@fastify/otel@0.16.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.208.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 minimatch: 10.2.4 transitivePeerDependencies: - supports-color - "@fastify/otel@0.17.1(@opentelemetry/api@1.9.0)": + '@fastify/otel@0.17.1(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.212.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.212.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 minimatch: 10.2.4 transitivePeerDependencies: - supports-color - "@fontsource-variable/space-grotesk@5.2.10": {} + '@fontsource-variable/space-grotesk@5.2.10': {} - "@fontsource/ibm-plex-mono@5.2.7": {} + '@fontsource/ibm-plex-mono@5.2.7': {} - "@gerrit0/mini-shiki@3.23.0": + '@gerrit0/mini-shiki@3.23.0': dependencies: - "@shikijs/engine-oniguruma": 3.23.0 - "@shikijs/langs": 3.23.0 - "@shikijs/themes": 3.23.0 - "@shikijs/types": 3.23.0 - "@shikijs/vscode-textmate": 10.0.2 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 - "@google/genai@1.44.0": + '@google/genai@1.44.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))': dependencies: google-auth-library: 10.6.1 p-retry: 4.6.2 protobufjs: 7.5.4 ws: 8.19.0 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.27.1(zod@4.3.6) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - "@iarna/toml@2.2.5": {} + '@hono/node-server@1.19.11(hono@4.12.8)': + dependencies: + hono: 4.12.8 + + '@iarna/toml@2.2.5': {} - "@img/colour@1.1.0": + '@img/colour@1.1.0': optional: true - "@img/sharp-darwin-arm64@0.34.5": + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - "@img/sharp-libvips-darwin-arm64": 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - "@img/sharp-darwin-x64@0.34.5": + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - "@img/sharp-libvips-darwin-x64": 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - "@img/sharp-libvips-darwin-arm64@1.2.4": + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - "@img/sharp-libvips-darwin-x64@1.2.4": + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - "@img/sharp-libvips-linux-arm64@1.2.4": + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - "@img/sharp-libvips-linux-arm@1.2.4": + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - "@img/sharp-libvips-linux-ppc64@1.2.4": + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - "@img/sharp-libvips-linux-riscv64@1.2.4": + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - "@img/sharp-libvips-linux-s390x@1.2.4": + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - "@img/sharp-libvips-linux-x64@1.2.4": + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - "@img/sharp-libvips-linuxmusl-arm64@1.2.4": + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - "@img/sharp-libvips-linuxmusl-x64@1.2.4": + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - "@img/sharp-linux-arm64@0.34.5": + '@img/sharp-linux-arm64@0.34.5': optionalDependencies: - "@img/sharp-libvips-linux-arm64": 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - "@img/sharp-linux-arm@0.34.5": + '@img/sharp-linux-arm@0.34.5': optionalDependencies: - "@img/sharp-libvips-linux-arm": 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - "@img/sharp-linux-ppc64@0.34.5": + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - "@img/sharp-libvips-linux-ppc64": 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - "@img/sharp-linux-riscv64@0.34.5": + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - "@img/sharp-libvips-linux-riscv64": 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - "@img/sharp-linux-s390x@0.34.5": + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - "@img/sharp-libvips-linux-s390x": 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - "@img/sharp-linux-x64@0.34.5": + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - "@img/sharp-libvips-linux-x64": 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - "@img/sharp-linuxmusl-arm64@0.34.5": + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - "@img/sharp-libvips-linuxmusl-arm64": 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - "@img/sharp-linuxmusl-x64@0.34.5": + '@img/sharp-linuxmusl-x64@0.34.5': optionalDependencies: - "@img/sharp-libvips-linuxmusl-x64": 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - "@img/sharp-wasm32@0.34.5": + '@img/sharp-wasm32@0.34.5': dependencies: - "@emnapi/runtime": 1.9.0 + '@emnapi/runtime': 1.9.0 optional: true - "@img/sharp-win32-arm64@0.34.5": + '@img/sharp-win32-arm64@0.34.5': optional: true - "@img/sharp-win32-ia32@0.34.5": + '@img/sharp-win32-ia32@0.34.5': optional: true - "@img/sharp-win32-x64@0.34.5": + '@img/sharp-win32-x64@0.34.5': optional: true - "@inquirer/ansi@1.0.2": {} + '@inquirer/ansi@1.0.2': {} - "@inquirer/confirm@5.1.21(@types/node@25.3.5)": + '@inquirer/confirm@5.1.21(@types/node@25.3.5)': dependencies: - "@inquirer/core": 10.3.2(@types/node@25.3.5) - "@inquirer/type": 3.0.10(@types/node@25.3.5) + '@inquirer/core': 10.3.2(@types/node@25.3.5) + '@inquirer/type': 3.0.10(@types/node@25.3.5) optionalDependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 - "@inquirer/core@10.3.2(@types/node@25.3.5)": + '@inquirer/core@10.3.2(@types/node@25.3.5)': dependencies: - "@inquirer/ansi": 1.0.2 - "@inquirer/figures": 1.0.15 - "@inquirer/type": 3.0.10(@types/node@25.3.5) + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@25.3.5) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 - "@inquirer/figures@1.0.15": {} + '@inquirer/figures@1.0.15': {} - "@inquirer/type@3.0.10(@types/node@25.3.5)": + '@inquirer/type@3.0.10(@types/node@25.3.5)': optionalDependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 - "@isaacs/balanced-match@4.0.1": {} + '@isaacs/balanced-match@4.0.1': {} - "@isaacs/brace-expansion@5.0.1": + '@isaacs/brace-expansion@5.0.1': dependencies: - "@isaacs/balanced-match": 4.0.1 + '@isaacs/balanced-match': 4.0.1 - "@isaacs/cliui@8.0.2": + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 @@ -13020,53 +8473,53 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - "@isaacs/fs-minipass@4.0.1": + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.3 - "@jitl/quickjs-ffi-types@0.32.0": {} + '@jitl/quickjs-ffi-types@0.32.0': {} - "@jitl/quickjs-wasmfile-debug-asyncify@0.32.0": + '@jitl/quickjs-wasmfile-debug-asyncify@0.32.0': dependencies: - "@jitl/quickjs-ffi-types": 0.32.0 + '@jitl/quickjs-ffi-types': 0.32.0 - "@jitl/quickjs-wasmfile-debug-sync@0.32.0": + '@jitl/quickjs-wasmfile-debug-sync@0.32.0': dependencies: - "@jitl/quickjs-ffi-types": 0.32.0 + '@jitl/quickjs-ffi-types': 0.32.0 - "@jitl/quickjs-wasmfile-release-asyncify@0.32.0": + '@jitl/quickjs-wasmfile-release-asyncify@0.32.0': dependencies: - "@jitl/quickjs-ffi-types": 0.32.0 + '@jitl/quickjs-ffi-types': 0.32.0 - "@jitl/quickjs-wasmfile-release-sync@0.32.0": + '@jitl/quickjs-wasmfile-release-sync@0.32.0': dependencies: - "@jitl/quickjs-ffi-types": 0.32.0 + '@jitl/quickjs-ffi-types': 0.32.0 - "@jridgewell/gen-mapping@0.3.13": + '@jridgewell/gen-mapping@0.3.13': dependencies: - "@jridgewell/sourcemap-codec": 1.5.5 - "@jridgewell/trace-mapping": 0.3.31 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 - "@jridgewell/remapping@2.3.5": + '@jridgewell/remapping@2.3.5': dependencies: - "@jridgewell/gen-mapping": 0.3.13 - "@jridgewell/trace-mapping": 0.3.31 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - "@jridgewell/resolve-uri@3.1.2": {} + '@jridgewell/resolve-uri@3.1.2': {} - "@jridgewell/source-map@0.3.11": + '@jridgewell/source-map@0.3.11': dependencies: - "@jridgewell/gen-mapping": 0.3.13 - "@jridgewell/trace-mapping": 0.3.31 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - "@jridgewell/sourcemap-codec@1.5.5": {} + '@jridgewell/sourcemap-codec@1.5.5': {} - "@jridgewell/trace-mapping@0.3.31": + '@jridgewell/trace-mapping@0.3.31': dependencies: - "@jridgewell/resolve-uri": 3.1.2 - "@jridgewell/sourcemap-codec": 1.5.5 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - "@mapbox/node-pre-gyp@2.0.3": + '@mapbox/node-pre-gyp@2.0.3': dependencies: consola: 3.4.2 detect-libc: 2.1.2 @@ -13079,11 +8532,11 @@ snapshots: - encoding - supports-color - "@mariozechner/pi-agent-core@0.59.0(ws@8.19.0)(zod@4.3.6)": + '@mariozechner/pi-agent-core@0.59.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.19.0)(zod@4.3.6)': dependencies: - "@mariozechner/pi-ai": 0.59.0(ws@8.19.0)(zod@4.3.6) + '@mariozechner/pi-ai': 0.59.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.19.0)(zod@4.3.6) transitivePeerDependencies: - - "@modelcontextprotocol/sdk" + - '@modelcontextprotocol/sdk' - aws-crt - bufferutil - supports-color @@ -13091,13 +8544,13 @@ snapshots: - ws - zod - "@mariozechner/pi-ai@0.59.0(ws@8.19.0)(zod@4.3.6)": + '@mariozechner/pi-ai@0.59.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.19.0)(zod@4.3.6)': dependencies: - "@anthropic-ai/sdk": 0.73.0(zod@4.3.6) - "@aws-sdk/client-bedrock-runtime": 3.1003.0 - "@google/genai": 1.44.0 - "@mistralai/mistralai": 1.14.1 - "@sinclair/typebox": 0.34.48 + '@anthropic-ai/sdk': 0.73.0(zod@4.3.6) + '@aws-sdk/client-bedrock-runtime': 3.1003.0 + '@google/genai': 1.44.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)) + '@mistralai/mistralai': 1.14.1 + '@sinclair/typebox': 0.34.48 ajv: 8.18.0 ajv-formats: 3.0.1(ajv@8.18.0) chalk: 5.6.2 @@ -13107,7 +8560,7 @@ snapshots: undici: 7.22.0 zod-to-json-schema: 3.25.1(zod@4.3.6) transitivePeerDependencies: - - "@modelcontextprotocol/sdk" + - '@modelcontextprotocol/sdk' - aws-crt - bufferutil - supports-color @@ -13115,12 +8568,12 @@ snapshots: - ws - zod - "@mdx-js/mdx@3.1.1": + '@mdx-js/mdx@3.1.1': dependencies: - "@types/estree": 1.0.8 - "@types/estree-jsx": 1.0.5 - "@types/hast": 3.0.4 - "@types/mdx": 2.0.13 + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdx': 2.0.13 acorn: 8.16.0 collapse-white-space: 2.1.0 devlop: 1.1.0 @@ -13145,7 +8598,7 @@ snapshots: transitivePeerDependencies: - supports-color - "@mistralai/mistralai@1.14.1": + '@mistralai/mistralai@1.14.1': dependencies: ws: 8.19.0 zod: 4.3.6 @@ -13154,693 +8607,715 @@ snapshots: - bufferutil - utf-8-validate - "@mixmark-io/domino@2.2.0": {} + '@mixmark-io/domino@2.2.0': {} + + '@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)': + dependencies: + '@hono/node-server': 1.19.11(hono@4.12.8) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.1(express@5.2.1) + hono: 4.12.8 + jose: 6.2.1 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.3.6 + zod-to-json-schema: 3.25.1(zod@4.3.6) + transitivePeerDependencies: + - supports-color - "@mongodb-js/zstd@7.0.0": + '@mongodb-js/zstd@7.0.0': dependencies: node-addon-api: 8.6.0 prebuild-install: 7.1.3 optional: true - "@mswjs/interceptors@0.41.3": + '@mswjs/interceptors@0.41.3': dependencies: - "@open-draft/deferred-promise": 2.2.0 - "@open-draft/logger": 0.3.0 - "@open-draft/until": 2.1.0 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 is-node-process: 1.2.0 outvariant: 1.4.3 strict-event-emitter: 0.5.1 - "@napi-rs/wasm-runtime@1.1.1": + '@napi-rs/wasm-runtime@1.1.1': dependencies: - "@emnapi/core": 1.8.1 - "@emnapi/runtime": 1.9.0 - "@tybys/wasm-util": 0.10.1 + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.9.0 + '@tybys/wasm-util': 0.10.1 optional: true - "@next/env@16.1.7": {} + '@next/env@16.1.7': {} - "@next/swc-darwin-arm64@16.1.7": + '@next/swc-darwin-arm64@16.1.7': optional: true - "@next/swc-darwin-x64@16.1.7": + '@next/swc-darwin-x64@16.1.7': optional: true - "@next/swc-linux-arm64-gnu@16.1.7": + '@next/swc-linux-arm64-gnu@16.1.7': optional: true - "@next/swc-linux-arm64-musl@16.1.7": + '@next/swc-linux-arm64-musl@16.1.7': optional: true - "@next/swc-linux-x64-gnu@16.1.7": + '@next/swc-linux-x64-gnu@16.1.7': optional: true - "@next/swc-linux-x64-musl@16.1.7": + '@next/swc-linux-x64-musl@16.1.7': optional: true - "@next/swc-win32-arm64-msvc@16.1.7": + '@next/swc-win32-arm64-msvc@16.1.7': optional: true - "@next/swc-win32-x64-msvc@16.1.7": + '@next/swc-win32-x64-msvc@16.1.7': optional: true - "@nodelib/fs.scandir@2.1.5": + '@nodelib/fs.scandir@2.1.5': dependencies: - "@nodelib/fs.stat": 2.0.5 + '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - "@nodelib/fs.stat@2.0.5": {} + '@nodelib/fs.stat@2.0.5': {} - "@nodelib/fs.walk@1.2.8": + '@nodelib/fs.walk@1.2.8': dependencies: - "@nodelib/fs.scandir": 2.1.5 + '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - "@open-draft/deferred-promise@2.2.0": {} + '@open-draft/deferred-promise@2.2.0': {} - "@open-draft/logger@0.3.0": + '@open-draft/logger@0.3.0': dependencies: is-node-process: 1.2.0 outvariant: 1.4.3 - "@open-draft/until@2.1.0": {} + '@open-draft/until@2.1.0': {} - "@opentelemetry/api-logs@0.207.0": + '@opentelemetry/api-logs@0.207.0': dependencies: - "@opentelemetry/api": 1.9.0 + '@opentelemetry/api': 1.9.0 - "@opentelemetry/api-logs@0.208.0": + '@opentelemetry/api-logs@0.208.0': dependencies: - "@opentelemetry/api": 1.9.0 + '@opentelemetry/api': 1.9.0 - "@opentelemetry/api-logs@0.211.0": + '@opentelemetry/api-logs@0.211.0': dependencies: - "@opentelemetry/api": 1.9.0 + '@opentelemetry/api': 1.9.0 - "@opentelemetry/api-logs@0.212.0": + '@opentelemetry/api-logs@0.212.0': dependencies: - "@opentelemetry/api": 1.9.0 + '@opentelemetry/api': 1.9.0 - "@opentelemetry/api-logs@0.213.0": + '@opentelemetry/api-logs@0.213.0': dependencies: - "@opentelemetry/api": 1.9.0 + '@opentelemetry/api': 1.9.0 - "@opentelemetry/api@1.9.0": {} + '@opentelemetry/api@1.9.0': {} - "@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 + '@opentelemetry/api': 1.9.0 - "@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.40.0 - "@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.40.0 - "@opentelemetry/instrumentation-amqplib@0.58.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-amqplib@0.58.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-amqplib@0.60.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-amqplib@0.60.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-connect@0.54.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-connect@0.54.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@types/connect": 3.4.38 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@types/connect': 3.4.38 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-connect@0.56.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-connect@0.56.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@types/connect": 3.4.38 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@types/connect': 3.4.38 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-dataloader@0.28.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-dataloader@0.28.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-dataloader@0.30.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-dataloader@0.30.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-express@0.59.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-express@0.59.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-express@0.61.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-express@0.61.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-fs@0.30.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-fs@0.30.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-fs@0.32.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-fs@0.32.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-generic-pool@0.54.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-generic-pool@0.54.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-generic-pool@0.56.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-generic-pool@0.56.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-graphql@0.58.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-graphql@0.58.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-graphql@0.61.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-graphql@0.61.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-hapi@0.57.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-hapi@0.57.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-hapi@0.59.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-hapi@0.59.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-http@0.211.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-http@0.211.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.5.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.5.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 forwarded-parse: 2.1.2 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-http@0.213.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-http@0.213.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 forwarded-parse: 2.1.2 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-ioredis@0.59.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-ioredis@0.59.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/redis-common": 0.38.2 - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/redis-common': 0.38.2 + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-ioredis@0.61.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-ioredis@0.61.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/redis-common": 0.38.2 - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/redis-common': 0.38.2 + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-kafkajs@0.20.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-kafkajs@0.20.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-kafkajs@0.22.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-kafkajs@0.22.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-knex@0.55.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-knex@0.55.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-knex@0.57.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-knex@0.57.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-koa@0.59.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-koa@0.59.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-koa@0.61.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-koa@0.61.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-lru-memoizer@0.55.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-lru-memoizer@0.55.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-lru-memoizer@0.57.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-lru-memoizer@0.57.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-mongodb@0.64.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-mongodb@0.64.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-mongodb@0.66.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-mongodb@0.66.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-mongoose@0.57.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-mongoose@0.57.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-mongoose@0.59.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-mongoose@0.59.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-mysql2@0.57.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-mysql2@0.57.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@opentelemetry/sql-common": 0.41.2(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-mysql2@0.59.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-mysql2@0.59.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@opentelemetry/sql-common": 0.41.2(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-mysql@0.57.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-mysql@0.57.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@types/mysql": 2.15.27 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@types/mysql': 2.15.27 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-mysql@0.59.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-mysql@0.59.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@types/mysql": 2.15.27 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@types/mysql': 2.15.27 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-pg@0.63.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-pg@0.63.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@opentelemetry/sql-common": 0.41.2(@opentelemetry/api@1.9.0) - "@types/pg": 8.15.6 - "@types/pg-pool": 2.0.7 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) + '@types/pg': 8.15.6 + '@types/pg-pool': 2.0.7 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-pg@0.65.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-pg@0.65.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@opentelemetry/sql-common": 0.41.2(@opentelemetry/api@1.9.0) - "@types/pg": 8.15.6 - "@types/pg-pool": 2.0.7 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) + '@types/pg': 8.15.6 + '@types/pg-pool': 2.0.7 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-redis@0.59.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-redis@0.59.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/redis-common": 0.38.2 - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/redis-common': 0.38.2 + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-redis@0.61.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-redis@0.61.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/redis-common": 0.38.2 - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/redis-common': 0.38.2 + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-tedious@0.30.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-tedious@0.30.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@types/tedious": 4.0.14 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@types/tedious': 4.0.14 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-tedious@0.32.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-tedious@0.32.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@types/tedious": 4.0.14 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@types/tedious': 4.0.14 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-undici@0.21.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-undici@0.21.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation-undici@0.23.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation-undici@0.23.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation@0.207.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation@0.207.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/api-logs": 0.207.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.207.0 import-in-the-middle: 2.0.6 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/api-logs": 0.208.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.208.0 import-in-the-middle: 2.0.6 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/api-logs": 0.211.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.211.0 import-in-the-middle: 2.0.6 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation@0.212.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation@0.212.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/api-logs": 0.212.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.212.0 import-in-the-middle: 2.0.6 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - "@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/api-logs": 0.213.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.213.0 import-in-the-middle: 3.0.0 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - "@opentelemetry/redis-common@0.38.2": {} + '@opentelemetry/redis-common@0.38.2': {} - "@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 - "@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0)": + '@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/resources": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 - "@opentelemetry/semantic-conventions@1.40.0": {} + '@opentelemetry/semantic-conventions@1.40.0': {} - "@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.0)": + '@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) - "@oslojs/encoding@1.1.0": {} + '@oslojs/encoding@1.1.0': {} - "@oxc-project/types@0.110.0": {} + '@oxc-project/types@0.110.0': {} - "@oxc-transform/binding-android-arm-eabi@0.111.0": + '@oxc-transform/binding-android-arm-eabi@0.111.0': optional: true - "@oxc-transform/binding-android-arm64@0.111.0": + '@oxc-transform/binding-android-arm64@0.111.0': optional: true - "@oxc-transform/binding-darwin-arm64@0.111.0": + '@oxc-transform/binding-darwin-arm64@0.111.0': optional: true - "@oxc-transform/binding-darwin-x64@0.111.0": + '@oxc-transform/binding-darwin-x64@0.111.0': optional: true - "@oxc-transform/binding-freebsd-x64@0.111.0": + '@oxc-transform/binding-freebsd-x64@0.111.0': optional: true - "@oxc-transform/binding-linux-arm-gnueabihf@0.111.0": + '@oxc-transform/binding-linux-arm-gnueabihf@0.111.0': optional: true - "@oxc-transform/binding-linux-arm-musleabihf@0.111.0": + '@oxc-transform/binding-linux-arm-musleabihf@0.111.0': optional: true - "@oxc-transform/binding-linux-arm64-gnu@0.111.0": + '@oxc-transform/binding-linux-arm64-gnu@0.111.0': optional: true - "@oxc-transform/binding-linux-arm64-musl@0.111.0": + '@oxc-transform/binding-linux-arm64-musl@0.111.0': optional: true - "@oxc-transform/binding-linux-ppc64-gnu@0.111.0": + '@oxc-transform/binding-linux-ppc64-gnu@0.111.0': optional: true - "@oxc-transform/binding-linux-riscv64-gnu@0.111.0": + '@oxc-transform/binding-linux-riscv64-gnu@0.111.0': optional: true - "@oxc-transform/binding-linux-riscv64-musl@0.111.0": + '@oxc-transform/binding-linux-riscv64-musl@0.111.0': optional: true - "@oxc-transform/binding-linux-s390x-gnu@0.111.0": + '@oxc-transform/binding-linux-s390x-gnu@0.111.0': optional: true - "@oxc-transform/binding-linux-x64-gnu@0.111.0": + '@oxc-transform/binding-linux-x64-gnu@0.111.0': optional: true - "@oxc-transform/binding-linux-x64-musl@0.111.0": + '@oxc-transform/binding-linux-x64-musl@0.111.0': optional: true - "@oxc-transform/binding-openharmony-arm64@0.111.0": + '@oxc-transform/binding-openharmony-arm64@0.111.0': optional: true - "@oxc-transform/binding-wasm32-wasi@0.111.0": + '@oxc-transform/binding-wasm32-wasi@0.111.0': dependencies: - "@napi-rs/wasm-runtime": 1.1.1 + '@napi-rs/wasm-runtime': 1.1.1 optional: true - "@oxc-transform/binding-win32-arm64-msvc@0.111.0": + '@oxc-transform/binding-win32-arm64-msvc@0.111.0': optional: true - "@oxc-transform/binding-win32-ia32-msvc@0.111.0": + '@oxc-transform/binding-win32-ia32-msvc@0.111.0': optional: true - "@oxc-transform/binding-win32-x64-msvc@0.111.0": + '@oxc-transform/binding-win32-x64-msvc@0.111.0': optional: true - "@pagefind/darwin-arm64@1.4.0": + '@pagefind/darwin-arm64@1.4.0': optional: true - "@pagefind/darwin-x64@1.4.0": + '@pagefind/darwin-x64@1.4.0': optional: true - "@pagefind/default-ui@1.4.0": {} + '@pagefind/default-ui@1.4.0': {} - "@pagefind/freebsd-x64@1.4.0": + '@pagefind/freebsd-x64@1.4.0': optional: true - "@pagefind/linux-arm64@1.4.0": + '@pagefind/linux-arm64@1.4.0': optional: true - "@pagefind/linux-x64@1.4.0": + '@pagefind/linux-x64@1.4.0': optional: true - "@pagefind/windows-x64@1.4.0": + '@pagefind/windows-x64@1.4.0': optional: true - "@pkgjs/parseargs@0.11.0": + '@pkgjs/parseargs@0.11.0': optional: true - "@prisma/instrumentation@7.2.0(@opentelemetry/api@1.9.0)": + '@prisma/instrumentation@7.2.0(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.207.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.207.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@prisma/instrumentation@7.4.2(@opentelemetry/api@1.9.0)": + '@prisma/instrumentation@7.4.2(@opentelemetry/api@1.9.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/instrumentation": 0.207.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.207.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - "@promptbook/utils@0.69.5": + '@promptbook/utils@0.69.5': dependencies: spacetrim: 0.11.59 - "@protobufjs/aspromise@1.1.2": {} + '@protobufjs/aspromise@1.1.2': {} - "@protobufjs/base64@1.1.2": {} + '@protobufjs/base64@1.1.2': {} - "@protobufjs/codegen@2.0.4": {} + '@protobufjs/codegen@2.0.4': {} - "@protobufjs/eventemitter@1.1.0": {} + '@protobufjs/eventemitter@1.1.0': {} - "@protobufjs/fetch@1.1.0": + '@protobufjs/fetch@1.1.0': dependencies: - "@protobufjs/aspromise": 1.1.2 - "@protobufjs/inquire": 1.1.0 + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 - "@protobufjs/float@1.0.2": {} + '@protobufjs/float@1.0.2': {} - "@protobufjs/inquire@1.1.0": {} + '@protobufjs/inquire@1.1.0': {} - "@protobufjs/path@1.1.2": {} + '@protobufjs/path@1.1.2': {} - "@protobufjs/pool@1.1.0": {} + '@protobufjs/pool@1.1.0': {} - "@protobufjs/utf8@1.1.0": {} + '@protobufjs/utf8@1.1.0': {} - "@puppeteer/browsers@2.13.0": + '@puppeteer/browsers@2.13.0': dependencies: debug: 4.4.3 extract-zip: 2.0.1 @@ -13855,74 +9330,74 @@ snapshots: - react-native-b4a - supports-color - "@redis/bloom@5.11.0(@redis/client@5.11.0)": + '@redis/bloom@5.11.0(@redis/client@5.11.0)': dependencies: - "@redis/client": 5.11.0 + '@redis/client': 5.11.0 - "@redis/client@5.11.0": + '@redis/client@5.11.0': dependencies: cluster-key-slot: 1.1.2 - "@redis/json@5.11.0(@redis/client@5.11.0)": + '@redis/json@5.11.0(@redis/client@5.11.0)': dependencies: - "@redis/client": 5.11.0 + '@redis/client': 5.11.0 - "@redis/search@5.11.0(@redis/client@5.11.0)": + '@redis/search@5.11.0(@redis/client@5.11.0)': dependencies: - "@redis/client": 5.11.0 + '@redis/client': 5.11.0 - "@redis/time-series@5.11.0(@redis/client@5.11.0)": + '@redis/time-series@5.11.0(@redis/client@5.11.0)': dependencies: - "@redis/client": 5.11.0 + '@redis/client': 5.11.0 - "@renovatebot/pep440@4.2.1": {} + '@renovatebot/pep440@4.2.1': {} - "@rolldown/binding-android-arm64@1.0.0-rc.1": + '@rolldown/binding-android-arm64@1.0.0-rc.1': optional: true - "@rolldown/binding-darwin-arm64@1.0.0-rc.1": + '@rolldown/binding-darwin-arm64@1.0.0-rc.1': optional: true - "@rolldown/binding-darwin-x64@1.0.0-rc.1": + '@rolldown/binding-darwin-x64@1.0.0-rc.1': optional: true - "@rolldown/binding-freebsd-x64@1.0.0-rc.1": + '@rolldown/binding-freebsd-x64@1.0.0-rc.1': optional: true - "@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1": + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': optional: true - "@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1": + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': optional: true - "@rolldown/binding-linux-arm64-musl@1.0.0-rc.1": + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': optional: true - "@rolldown/binding-linux-x64-gnu@1.0.0-rc.1": + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': optional: true - "@rolldown/binding-linux-x64-musl@1.0.0-rc.1": + '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': optional: true - "@rolldown/binding-openharmony-arm64@1.0.0-rc.1": + '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': optional: true - "@rolldown/binding-wasm32-wasi@1.0.0-rc.1": + '@rolldown/binding-wasm32-wasi@1.0.0-rc.1': dependencies: - "@napi-rs/wasm-runtime": 1.1.1 + '@napi-rs/wasm-runtime': 1.1.1 optional: true - "@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1": + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': optional: true - "@rolldown/binding-win32-x64-msvc@1.0.0-rc.1": + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': optional: true - "@rolldown/pluginutils@1.0.0-rc.1": {} + '@rolldown/pluginutils@1.0.0-rc.1': {} - "@rollup/plugin-commonjs@28.0.1(rollup@4.59.0)": + '@rollup/plugin-commonjs@28.0.1(rollup@4.59.0)': dependencies: - "@rollup/pluginutils": 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.3) @@ -13932,148 +9407,148 @@ snapshots: optionalDependencies: rollup: 4.59.0 - "@rollup/pluginutils@5.3.0(rollup@4.59.0)": + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: rollup: 4.59.0 - "@rollup/rollup-android-arm-eabi@4.59.0": + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true - "@rollup/rollup-android-arm64@4.59.0": + '@rollup/rollup-android-arm64@4.59.0': optional: true - "@rollup/rollup-darwin-arm64@4.59.0": + '@rollup/rollup-darwin-arm64@4.59.0': optional: true - "@rollup/rollup-darwin-x64@4.59.0": + '@rollup/rollup-darwin-x64@4.59.0': optional: true - "@rollup/rollup-freebsd-arm64@4.59.0": + '@rollup/rollup-freebsd-arm64@4.59.0': optional: true - "@rollup/rollup-freebsd-x64@4.59.0": + '@rollup/rollup-freebsd-x64@4.59.0': optional: true - "@rollup/rollup-linux-arm-gnueabihf@4.59.0": + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': optional: true - "@rollup/rollup-linux-arm-musleabihf@4.59.0": + '@rollup/rollup-linux-arm-musleabihf@4.59.0': optional: true - "@rollup/rollup-linux-arm64-gnu@4.59.0": + '@rollup/rollup-linux-arm64-gnu@4.59.0': optional: true - "@rollup/rollup-linux-arm64-musl@4.59.0": + '@rollup/rollup-linux-arm64-musl@4.59.0': optional: true - "@rollup/rollup-linux-loong64-gnu@4.59.0": + '@rollup/rollup-linux-loong64-gnu@4.59.0': optional: true - "@rollup/rollup-linux-loong64-musl@4.59.0": + '@rollup/rollup-linux-loong64-musl@4.59.0': optional: true - "@rollup/rollup-linux-ppc64-gnu@4.59.0": + '@rollup/rollup-linux-ppc64-gnu@4.59.0': optional: true - "@rollup/rollup-linux-ppc64-musl@4.59.0": + '@rollup/rollup-linux-ppc64-musl@4.59.0': optional: true - "@rollup/rollup-linux-riscv64-gnu@4.59.0": + '@rollup/rollup-linux-riscv64-gnu@4.59.0': optional: true - "@rollup/rollup-linux-riscv64-musl@4.59.0": + '@rollup/rollup-linux-riscv64-musl@4.59.0': optional: true - "@rollup/rollup-linux-s390x-gnu@4.59.0": + '@rollup/rollup-linux-s390x-gnu@4.59.0': optional: true - "@rollup/rollup-linux-x64-gnu@4.59.0": + '@rollup/rollup-linux-x64-gnu@4.59.0': optional: true - "@rollup/rollup-linux-x64-musl@4.59.0": + '@rollup/rollup-linux-x64-musl@4.59.0': optional: true - "@rollup/rollup-openbsd-x64@4.59.0": + '@rollup/rollup-openbsd-x64@4.59.0': optional: true - "@rollup/rollup-openharmony-arm64@4.59.0": + '@rollup/rollup-openharmony-arm64@4.59.0': optional: true - "@rollup/rollup-win32-arm64-msvc@4.59.0": + '@rollup/rollup-win32-arm64-msvc@4.59.0': optional: true - "@rollup/rollup-win32-ia32-msvc@4.59.0": + '@rollup/rollup-win32-ia32-msvc@4.59.0': optional: true - "@rollup/rollup-win32-x64-gnu@4.59.0": + '@rollup/rollup-win32-x64-gnu@4.59.0': optional: true - "@rollup/rollup-win32-x64-msvc@4.59.0": + '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true - "@sentry-internal/browser-utils@10.42.0": + '@sentry-internal/browser-utils@10.42.0': dependencies: - "@sentry/core": 10.42.0 + '@sentry/core': 10.42.0 - "@sentry-internal/browser-utils@10.44.0": + '@sentry-internal/browser-utils@10.44.0': dependencies: - "@sentry/core": 10.44.0 + '@sentry/core': 10.44.0 - "@sentry-internal/feedback@10.42.0": + '@sentry-internal/feedback@10.42.0': dependencies: - "@sentry/core": 10.42.0 + '@sentry/core': 10.42.0 - "@sentry-internal/feedback@10.44.0": + '@sentry-internal/feedback@10.44.0': dependencies: - "@sentry/core": 10.44.0 + '@sentry/core': 10.44.0 - "@sentry-internal/replay-canvas@10.42.0": + '@sentry-internal/replay-canvas@10.42.0': dependencies: - "@sentry-internal/replay": 10.42.0 - "@sentry/core": 10.42.0 + '@sentry-internal/replay': 10.42.0 + '@sentry/core': 10.42.0 - "@sentry-internal/replay-canvas@10.44.0": + '@sentry-internal/replay-canvas@10.44.0': dependencies: - "@sentry-internal/replay": 10.44.0 - "@sentry/core": 10.44.0 + '@sentry-internal/replay': 10.44.0 + '@sentry/core': 10.44.0 - "@sentry-internal/replay@10.42.0": + '@sentry-internal/replay@10.42.0': dependencies: - "@sentry-internal/browser-utils": 10.42.0 - "@sentry/core": 10.42.0 + '@sentry-internal/browser-utils': 10.42.0 + '@sentry/core': 10.42.0 - "@sentry-internal/replay@10.44.0": + '@sentry-internal/replay@10.44.0': dependencies: - "@sentry-internal/browser-utils": 10.44.0 - "@sentry/core": 10.44.0 + '@sentry-internal/browser-utils': 10.44.0 + '@sentry/core': 10.44.0 - "@sentry/babel-plugin-component-annotate@5.1.1": {} + '@sentry/babel-plugin-component-annotate@5.1.1': {} - "@sentry/browser@10.42.0": + '@sentry/browser@10.42.0': dependencies: - "@sentry-internal/browser-utils": 10.42.0 - "@sentry-internal/feedback": 10.42.0 - "@sentry-internal/replay": 10.42.0 - "@sentry-internal/replay-canvas": 10.42.0 - "@sentry/core": 10.42.0 + '@sentry-internal/browser-utils': 10.42.0 + '@sentry-internal/feedback': 10.42.0 + '@sentry-internal/replay': 10.42.0 + '@sentry-internal/replay-canvas': 10.42.0 + '@sentry/core': 10.42.0 - "@sentry/browser@10.44.0": + '@sentry/browser@10.44.0': dependencies: - "@sentry-internal/browser-utils": 10.44.0 - "@sentry-internal/feedback": 10.44.0 - "@sentry-internal/replay": 10.44.0 - "@sentry-internal/replay-canvas": 10.44.0 - "@sentry/core": 10.44.0 + '@sentry-internal/browser-utils': 10.44.0 + '@sentry-internal/feedback': 10.44.0 + '@sentry-internal/replay': 10.44.0 + '@sentry-internal/replay-canvas': 10.44.0 + '@sentry/core': 10.44.0 - "@sentry/bundler-plugin-core@5.1.1": + '@sentry/bundler-plugin-core@5.1.1': dependencies: - "@babel/core": 7.29.0 - "@sentry/babel-plugin-component-annotate": 5.1.1 - "@sentry/cli": 2.58.5 + '@babel/core': 7.29.0 + '@sentry/babel-plugin-component-annotate': 5.1.1 + '@sentry/cli': 2.58.5 dotenv: 16.6.1 find-up: 5.0.0 glob: 13.0.6 @@ -14082,31 +9557,31 @@ snapshots: - encoding - supports-color - "@sentry/cli-darwin@2.58.5": + '@sentry/cli-darwin@2.58.5': optional: true - "@sentry/cli-linux-arm64@2.58.5": + '@sentry/cli-linux-arm64@2.58.5': optional: true - "@sentry/cli-linux-arm@2.58.5": + '@sentry/cli-linux-arm@2.58.5': optional: true - "@sentry/cli-linux-i686@2.58.5": + '@sentry/cli-linux-i686@2.58.5': optional: true - "@sentry/cli-linux-x64@2.58.5": + '@sentry/cli-linux-x64@2.58.5': optional: true - "@sentry/cli-win32-arm64@2.58.5": + '@sentry/cli-win32-arm64@2.58.5': optional: true - "@sentry/cli-win32-i686@2.58.5": + '@sentry/cli-win32-i686@2.58.5': optional: true - "@sentry/cli-win32-x64@2.58.5": + '@sentry/cli-win32-x64@2.58.5': optional: true - "@sentry/cli@2.58.5": + '@sentry/cli@2.58.5': dependencies: https-proxy-agent: 5.0.1 node-fetch: 2.7.0 @@ -14114,289 +9589,289 @@ snapshots: proxy-from-env: 1.1.0 which: 2.0.2 optionalDependencies: - "@sentry/cli-darwin": 2.58.5 - "@sentry/cli-linux-arm": 2.58.5 - "@sentry/cli-linux-arm64": 2.58.5 - "@sentry/cli-linux-i686": 2.58.5 - "@sentry/cli-linux-x64": 2.58.5 - "@sentry/cli-win32-arm64": 2.58.5 - "@sentry/cli-win32-i686": 2.58.5 - "@sentry/cli-win32-x64": 2.58.5 + '@sentry/cli-darwin': 2.58.5 + '@sentry/cli-linux-arm': 2.58.5 + '@sentry/cli-linux-arm64': 2.58.5 + '@sentry/cli-linux-i686': 2.58.5 + '@sentry/cli-linux-x64': 2.58.5 + '@sentry/cli-win32-arm64': 2.58.5 + '@sentry/cli-win32-i686': 2.58.5 + '@sentry/cli-win32-x64': 2.58.5 transitivePeerDependencies: - encoding - supports-color - "@sentry/core@10.42.0": {} + '@sentry/core@10.42.0': {} - "@sentry/core@10.44.0": {} + '@sentry/core@10.44.0': {} - "@sentry/nextjs@10.42.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.1.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.2)": + '@sentry/nextjs@10.42.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.1.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.2)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/semantic-conventions": 1.40.0 - "@rollup/plugin-commonjs": 28.0.1(rollup@4.59.0) - "@sentry-internal/browser-utils": 10.42.0 - "@sentry/bundler-plugin-core": 5.1.1 - "@sentry/core": 10.42.0 - "@sentry/node": 10.42.0 - "@sentry/opentelemetry": 10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) - "@sentry/react": 10.42.0(react@19.2.4) - "@sentry/vercel-edge": 10.42.0 - "@sentry/webpack-plugin": 5.1.1(webpack@5.105.2) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.40.0 + '@rollup/plugin-commonjs': 28.0.1(rollup@4.59.0) + '@sentry-internal/browser-utils': 10.42.0 + '@sentry/bundler-plugin-core': 5.1.1 + '@sentry/core': 10.42.0 + '@sentry/node': 10.42.0 + '@sentry/opentelemetry': 10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/react': 10.42.0(react@19.2.4) + '@sentry/vercel-edge': 10.42.0 + '@sentry/webpack-plugin': 5.1.1(webpack@5.105.2) next: 16.1.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) rollup: 4.59.0 stacktrace-parser: 0.1.11 transitivePeerDependencies: - - "@opentelemetry/context-async-hooks" - - "@opentelemetry/core" - - "@opentelemetry/sdk-trace-base" + - '@opentelemetry/context-async-hooks' + - '@opentelemetry/core' + - '@opentelemetry/sdk-trace-base' - encoding - react - supports-color - webpack - "@sentry/nextjs@10.44.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.1.7(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3))": - dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/semantic-conventions": 1.40.0 - "@rollup/plugin-commonjs": 28.0.1(rollup@4.59.0) - "@sentry-internal/browser-utils": 10.44.0 - "@sentry/bundler-plugin-core": 5.1.1 - "@sentry/core": 10.44.0 - "@sentry/node": 10.44.0 - "@sentry/opentelemetry": 10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) - "@sentry/react": 10.44.0(react@19.2.4) - "@sentry/vercel-edge": 10.44.0 - "@sentry/webpack-plugin": 5.1.1(webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3)) + '@sentry/nextjs@10.44.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.1.7(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3))': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.40.0 + '@rollup/plugin-commonjs': 28.0.1(rollup@4.59.0) + '@sentry-internal/browser-utils': 10.44.0 + '@sentry/bundler-plugin-core': 5.1.1 + '@sentry/core': 10.44.0 + '@sentry/node': 10.44.0 + '@sentry/opentelemetry': 10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/react': 10.44.0(react@19.2.4) + '@sentry/vercel-edge': 10.44.0 + '@sentry/webpack-plugin': 5.1.1(webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3)) next: 16.1.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) rollup: 4.59.0 stacktrace-parser: 0.1.11 transitivePeerDependencies: - - "@opentelemetry/context-async-hooks" - - "@opentelemetry/core" - - "@opentelemetry/sdk-trace-base" + - '@opentelemetry/context-async-hooks' + - '@opentelemetry/core' + - '@opentelemetry/sdk-trace-base' - encoding - react - supports-color - webpack - "@sentry/node-core@10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)": + '@sentry/node-core@10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: - "@sentry/core": 10.42.0 - "@sentry/opentelemetry": 10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/core': 10.42.0 + '@sentry/opentelemetry': 10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) import-in-the-middle: 2.0.6 optionalDependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/context-async-hooks": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/resources": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/sdk-trace-base": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - - "@sentry/node-core@10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)": - dependencies: - "@sentry/core": 10.44.0 - "@sentry/opentelemetry": 10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + + '@sentry/node-core@10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': + dependencies: + '@sentry/core': 10.44.0 + '@sentry/opentelemetry': 10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) import-in-the-middle: 3.0.0 optionalDependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/context-async-hooks": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/resources": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/sdk-trace-base": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - - "@sentry/node@10.42.0": - dependencies: - "@fastify/otel": 0.16.0(@opentelemetry/api@1.9.0) - "@opentelemetry/api": 1.9.0 - "@opentelemetry/context-async-hooks": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-amqplib": 0.58.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-connect": 0.54.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-dataloader": 0.28.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-express": 0.59.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-fs": 0.30.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-generic-pool": 0.54.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-graphql": 0.58.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-hapi": 0.57.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-http": 0.211.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-ioredis": 0.59.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-kafkajs": 0.20.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-knex": 0.55.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-koa": 0.59.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-lru-memoizer": 0.55.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-mongodb": 0.64.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-mongoose": 0.57.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-mysql": 0.57.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-mysql2": 0.57.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-pg": 0.63.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-redis": 0.59.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-tedious": 0.30.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-undici": 0.21.0(@opentelemetry/api@1.9.0) - "@opentelemetry/resources": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/sdk-trace-base": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@prisma/instrumentation": 7.2.0(@opentelemetry/api@1.9.0) - "@sentry/core": 10.42.0 - "@sentry/node-core": 10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) - "@sentry/opentelemetry": 10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + + '@sentry/node@10.42.0': + dependencies: + '@fastify/otel': 0.16.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-amqplib': 0.58.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-connect': 0.54.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-dataloader': 0.28.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-express': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-fs': 0.30.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-generic-pool': 0.54.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-graphql': 0.58.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-hapi': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-http': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-ioredis': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-kafkajs': 0.20.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-knex': 0.55.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-koa': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-lru-memoizer': 0.55.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongodb': 0.64.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongoose': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql2': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-pg': 0.63.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-redis': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-tedious': 0.30.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-undici': 0.21.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@prisma/instrumentation': 7.2.0(@opentelemetry/api@1.9.0) + '@sentry/core': 10.42.0 + '@sentry/node-core': 10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/opentelemetry': 10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) import-in-the-middle: 2.0.6 transitivePeerDependencies: - supports-color - "@sentry/node@10.44.0": - dependencies: - "@fastify/otel": 0.17.1(@opentelemetry/api@1.9.0) - "@opentelemetry/api": 1.9.0 - "@opentelemetry/context-async-hooks": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-amqplib": 0.60.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-connect": 0.56.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-dataloader": 0.30.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-express": 0.61.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-fs": 0.32.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-generic-pool": 0.56.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-graphql": 0.61.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-hapi": 0.59.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-http": 0.213.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-ioredis": 0.61.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-kafkajs": 0.22.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-knex": 0.57.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-koa": 0.61.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-lru-memoizer": 0.57.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-mongodb": 0.66.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-mongoose": 0.59.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-mysql": 0.59.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-mysql2": 0.59.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-pg": 0.65.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-redis": 0.61.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-tedious": 0.32.0(@opentelemetry/api@1.9.0) - "@opentelemetry/instrumentation-undici": 0.23.0(@opentelemetry/api@1.9.0) - "@opentelemetry/resources": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/sdk-trace-base": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@prisma/instrumentation": 7.4.2(@opentelemetry/api@1.9.0) - "@sentry/core": 10.44.0 - "@sentry/node-core": 10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) - "@sentry/opentelemetry": 10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/node@10.44.0': + dependencies: + '@fastify/otel': 0.17.1(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-amqplib': 0.60.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-connect': 0.56.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-dataloader': 0.30.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-express': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-fs': 0.32.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-generic-pool': 0.56.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-graphql': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-hapi': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-http': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-ioredis': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-kafkajs': 0.22.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-knex': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-koa': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-lru-memoizer': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongodb': 0.66.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongoose': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql2': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-pg': 0.65.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-redis': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-tedious': 0.32.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-undici': 0.23.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@prisma/instrumentation': 7.4.2(@opentelemetry/api@1.9.0) + '@sentry/core': 10.44.0 + '@sentry/node-core': 10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/opentelemetry': 10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) import-in-the-middle: 3.0.0 transitivePeerDependencies: - supports-color - "@sentry/opentelemetry@10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)": + '@sentry/opentelemetry@10.42.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/context-async-hooks": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/sdk-trace-base": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@sentry/core": 10.42.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@sentry/core': 10.42.0 - "@sentry/opentelemetry@10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)": + '@sentry/opentelemetry@10.44.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/context-async-hooks": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/core": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/sdk-trace-base": 2.6.0(@opentelemetry/api@1.9.0) - "@opentelemetry/semantic-conventions": 1.40.0 - "@sentry/core": 10.44.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@sentry/core': 10.44.0 - "@sentry/react@10.42.0(react@19.2.4)": + '@sentry/react@10.42.0(react@19.2.4)': dependencies: - "@sentry/browser": 10.42.0 - "@sentry/core": 10.42.0 + '@sentry/browser': 10.42.0 + '@sentry/core': 10.42.0 react: 19.2.4 - "@sentry/react@10.44.0(react@19.2.4)": + '@sentry/react@10.44.0(react@19.2.4)': dependencies: - "@sentry/browser": 10.44.0 - "@sentry/core": 10.44.0 + '@sentry/browser': 10.44.0 + '@sentry/core': 10.44.0 react: 19.2.4 - "@sentry/vercel-edge@10.42.0": + '@sentry/vercel-edge@10.42.0': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/resources": 2.6.0(@opentelemetry/api@1.9.0) - "@sentry/core": 10.42.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@sentry/core': 10.42.0 - "@sentry/vercel-edge@10.44.0": + '@sentry/vercel-edge@10.44.0': dependencies: - "@opentelemetry/api": 1.9.0 - "@opentelemetry/resources": 2.6.0(@opentelemetry/api@1.9.0) - "@sentry/core": 10.44.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@sentry/core': 10.44.0 - "@sentry/webpack-plugin@5.1.1(webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3))": + '@sentry/webpack-plugin@5.1.1(webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3))': dependencies: - "@sentry/bundler-plugin-core": 5.1.1 + '@sentry/bundler-plugin-core': 5.1.1 uuid: 9.0.1 webpack: 5.105.2(@swc/core@1.15.3)(esbuild@0.27.3) transitivePeerDependencies: - encoding - supports-color - "@sentry/webpack-plugin@5.1.1(webpack@5.105.2)": + '@sentry/webpack-plugin@5.1.1(webpack@5.105.2)': dependencies: - "@sentry/bundler-plugin-core": 5.1.1 + '@sentry/bundler-plugin-core': 5.1.1 uuid: 9.0.1 webpack: 5.105.2 transitivePeerDependencies: - encoding - supports-color - "@shikijs/core@3.23.0": + '@shikijs/core@3.23.0': dependencies: - "@shikijs/types": 3.23.0 - "@shikijs/vscode-textmate": 10.0.2 - "@types/hast": 3.0.4 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 hast-util-to-html: 9.0.5 - "@shikijs/engine-javascript@3.23.0": + '@shikijs/engine-javascript@3.23.0': dependencies: - "@shikijs/types": 3.23.0 - "@shikijs/vscode-textmate": 10.0.2 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 oniguruma-to-es: 4.3.4 - "@shikijs/engine-oniguruma@3.23.0": + '@shikijs/engine-oniguruma@3.23.0': dependencies: - "@shikijs/types": 3.23.0 - "@shikijs/vscode-textmate": 10.0.2 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 - "@shikijs/langs@3.23.0": + '@shikijs/langs@3.23.0': dependencies: - "@shikijs/types": 3.23.0 + '@shikijs/types': 3.23.0 - "@shikijs/themes@3.23.0": + '@shikijs/themes@3.23.0': dependencies: - "@shikijs/types": 3.23.0 + '@shikijs/types': 3.23.0 - "@shikijs/types@3.23.0": + '@shikijs/types@3.23.0': dependencies: - "@shikijs/vscode-textmate": 10.0.2 - "@types/hast": 3.0.4 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 - "@shikijs/vscode-textmate@10.0.2": {} + '@shikijs/vscode-textmate@10.0.2': {} - "@sinclair/typebox@0.25.24": {} + '@sinclair/typebox@0.25.24': {} - "@sinclair/typebox@0.34.48": {} + '@sinclair/typebox@0.34.48': {} - "@slack/logger@4.0.1": + '@slack/logger@4.0.1': dependencies: - "@types/node": 25.5.0 + '@types/node': 25.5.0 - "@slack/types@2.20.1": {} + '@slack/types@2.20.1': {} - "@slack/web-api@7.15.0": + '@slack/web-api@7.15.0': dependencies: - "@slack/logger": 4.0.1 - "@slack/types": 2.20.1 - "@types/node": 25.5.0 - "@types/retry": 0.12.0 + '@slack/logger': 4.0.1 + '@slack/types': 2.20.1 + '@types/node': 25.5.0 + '@types/retry': 0.12.0 axios: 1.13.6 eventemitter3: 5.0.4 form-data: 4.0.5 @@ -14408,522 +9883,522 @@ snapshots: transitivePeerDependencies: - debug - "@smithy/abort-controller@4.2.11": + '@smithy/abort-controller@4.2.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/config-resolver@4.4.10": + '@smithy/config-resolver@4.4.10': dependencies: - "@smithy/node-config-provider": 4.3.11 - "@smithy/types": 4.13.0 - "@smithy/util-config-provider": 4.2.2 - "@smithy/util-endpoints": 3.3.2 - "@smithy/util-middleware": 4.2.11 + '@smithy/node-config-provider': 4.3.11 + '@smithy/types': 4.13.0 + '@smithy/util-config-provider': 4.2.2 + '@smithy/util-endpoints': 3.3.2 + '@smithy/util-middleware': 4.2.11 tslib: 2.8.1 - "@smithy/core@3.23.9": - dependencies: - "@smithy/middleware-serde": 4.2.12 - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 - "@smithy/util-base64": 4.3.2 - "@smithy/util-body-length-browser": 4.2.2 - "@smithy/util-middleware": 4.2.11 - "@smithy/util-stream": 4.5.17 - "@smithy/util-utf8": 4.2.2 - "@smithy/uuid": 1.1.2 + '@smithy/core@3.23.9': + dependencies: + '@smithy/middleware-serde': 4.2.12 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-middleware': 4.2.11 + '@smithy/util-stream': 4.5.17 + '@smithy/util-utf8': 4.2.2 + '@smithy/uuid': 1.1.2 tslib: 2.8.1 - "@smithy/credential-provider-imds@4.2.11": + '@smithy/credential-provider-imds@4.2.11': dependencies: - "@smithy/node-config-provider": 4.3.11 - "@smithy/property-provider": 4.2.11 - "@smithy/types": 4.13.0 - "@smithy/url-parser": 4.2.11 + '@smithy/node-config-provider': 4.3.11 + '@smithy/property-provider': 4.2.11 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.11 tslib: 2.8.1 - "@smithy/eventstream-codec@4.2.11": + '@smithy/eventstream-codec@4.2.11': dependencies: - "@aws-crypto/crc32": 5.2.0 - "@smithy/types": 4.13.0 - "@smithy/util-hex-encoding": 4.2.2 + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.13.0 + '@smithy/util-hex-encoding': 4.2.2 tslib: 2.8.1 - "@smithy/eventstream-serde-browser@4.2.11": + '@smithy/eventstream-serde-browser@4.2.11': dependencies: - "@smithy/eventstream-serde-universal": 4.2.11 - "@smithy/types": 4.13.0 + '@smithy/eventstream-serde-universal': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/eventstream-serde-config-resolver@4.3.11": + '@smithy/eventstream-serde-config-resolver@4.3.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/eventstream-serde-node@4.2.11": + '@smithy/eventstream-serde-node@4.2.11': dependencies: - "@smithy/eventstream-serde-universal": 4.2.11 - "@smithy/types": 4.13.0 + '@smithy/eventstream-serde-universal': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/eventstream-serde-universal@4.2.11": + '@smithy/eventstream-serde-universal@4.2.11': dependencies: - "@smithy/eventstream-codec": 4.2.11 - "@smithy/types": 4.13.0 + '@smithy/eventstream-codec': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/fetch-http-handler@5.3.13": + '@smithy/fetch-http-handler@5.3.13': dependencies: - "@smithy/protocol-http": 5.3.11 - "@smithy/querystring-builder": 4.2.11 - "@smithy/types": 4.13.0 - "@smithy/util-base64": 4.3.2 + '@smithy/protocol-http': 5.3.11 + '@smithy/querystring-builder': 4.2.11 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.2 tslib: 2.8.1 - "@smithy/hash-node@4.2.11": + '@smithy/hash-node@4.2.11': dependencies: - "@smithy/types": 4.13.0 - "@smithy/util-buffer-from": 4.2.2 - "@smithy/util-utf8": 4.2.2 + '@smithy/types': 4.13.0 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - "@smithy/invalid-dependency@4.2.11": + '@smithy/invalid-dependency@4.2.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/is-array-buffer@2.2.0": + '@smithy/is-array-buffer@2.2.0': dependencies: tslib: 2.8.1 - "@smithy/is-array-buffer@4.2.2": + '@smithy/is-array-buffer@4.2.2': dependencies: tslib: 2.8.1 - "@smithy/middleware-content-length@4.2.11": + '@smithy/middleware-content-length@4.2.11': dependencies: - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/middleware-endpoint@4.4.23": + '@smithy/middleware-endpoint@4.4.23': dependencies: - "@smithy/core": 3.23.9 - "@smithy/middleware-serde": 4.2.12 - "@smithy/node-config-provider": 4.3.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 - "@smithy/url-parser": 4.2.11 - "@smithy/util-middleware": 4.2.11 + '@smithy/core': 3.23.9 + '@smithy/middleware-serde': 4.2.12 + '@smithy/node-config-provider': 4.3.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.11 + '@smithy/util-middleware': 4.2.11 tslib: 2.8.1 - "@smithy/middleware-retry@4.4.40": + '@smithy/middleware-retry@4.4.40': dependencies: - "@smithy/node-config-provider": 4.3.11 - "@smithy/protocol-http": 5.3.11 - "@smithy/service-error-classification": 4.2.11 - "@smithy/smithy-client": 4.12.3 - "@smithy/types": 4.13.0 - "@smithy/util-middleware": 4.2.11 - "@smithy/util-retry": 4.2.11 - "@smithy/uuid": 1.1.2 + '@smithy/node-config-provider': 4.3.11 + '@smithy/protocol-http': 5.3.11 + '@smithy/service-error-classification': 4.2.11 + '@smithy/smithy-client': 4.12.3 + '@smithy/types': 4.13.0 + '@smithy/util-middleware': 4.2.11 + '@smithy/util-retry': 4.2.11 + '@smithy/uuid': 1.1.2 tslib: 2.8.1 - "@smithy/middleware-serde@4.2.12": + '@smithy/middleware-serde@4.2.12': dependencies: - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/middleware-stack@4.2.11": + '@smithy/middleware-stack@4.2.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/node-config-provider@4.3.11": + '@smithy/node-config-provider@4.3.11': dependencies: - "@smithy/property-provider": 4.2.11 - "@smithy/shared-ini-file-loader": 4.4.6 - "@smithy/types": 4.13.0 + '@smithy/property-provider': 4.2.11 + '@smithy/shared-ini-file-loader': 4.4.6 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/node-http-handler@4.4.14": + '@smithy/node-http-handler@4.4.14': dependencies: - "@smithy/abort-controller": 4.2.11 - "@smithy/protocol-http": 5.3.11 - "@smithy/querystring-builder": 4.2.11 - "@smithy/types": 4.13.0 + '@smithy/abort-controller': 4.2.11 + '@smithy/protocol-http': 5.3.11 + '@smithy/querystring-builder': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/property-provider@4.2.11": + '@smithy/property-provider@4.2.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/protocol-http@5.3.11": + '@smithy/protocol-http@5.3.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/querystring-builder@4.2.11": + '@smithy/querystring-builder@4.2.11': dependencies: - "@smithy/types": 4.13.0 - "@smithy/util-uri-escape": 4.2.2 + '@smithy/types': 4.13.0 + '@smithy/util-uri-escape': 4.2.2 tslib: 2.8.1 - "@smithy/querystring-parser@4.2.11": + '@smithy/querystring-parser@4.2.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/service-error-classification@4.2.11": + '@smithy/service-error-classification@4.2.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 - "@smithy/shared-ini-file-loader@4.4.6": + '@smithy/shared-ini-file-loader@4.4.6': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/signature-v4@5.3.11": + '@smithy/signature-v4@5.3.11': dependencies: - "@smithy/is-array-buffer": 4.2.2 - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 - "@smithy/util-hex-encoding": 4.2.2 - "@smithy/util-middleware": 4.2.11 - "@smithy/util-uri-escape": 4.2.2 - "@smithy/util-utf8": 4.2.2 + '@smithy/is-array-buffer': 4.2.2 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-middleware': 4.2.11 + '@smithy/util-uri-escape': 4.2.2 + '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - "@smithy/smithy-client@4.12.3": + '@smithy/smithy-client@4.12.3': dependencies: - "@smithy/core": 3.23.9 - "@smithy/middleware-endpoint": 4.4.23 - "@smithy/middleware-stack": 4.2.11 - "@smithy/protocol-http": 5.3.11 - "@smithy/types": 4.13.0 - "@smithy/util-stream": 4.5.17 + '@smithy/core': 3.23.9 + '@smithy/middleware-endpoint': 4.4.23 + '@smithy/middleware-stack': 4.2.11 + '@smithy/protocol-http': 5.3.11 + '@smithy/types': 4.13.0 + '@smithy/util-stream': 4.5.17 tslib: 2.8.1 - "@smithy/types@4.13.0": + '@smithy/types@4.13.0': dependencies: tslib: 2.8.1 - "@smithy/url-parser@4.2.11": + '@smithy/url-parser@4.2.11': dependencies: - "@smithy/querystring-parser": 4.2.11 - "@smithy/types": 4.13.0 + '@smithy/querystring-parser': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/util-base64@4.3.2": + '@smithy/util-base64@4.3.2': dependencies: - "@smithy/util-buffer-from": 4.2.2 - "@smithy/util-utf8": 4.2.2 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - "@smithy/util-body-length-browser@4.2.2": + '@smithy/util-body-length-browser@4.2.2': dependencies: tslib: 2.8.1 - "@smithy/util-body-length-node@4.2.3": + '@smithy/util-body-length-node@4.2.3': dependencies: tslib: 2.8.1 - "@smithy/util-buffer-from@2.2.0": + '@smithy/util-buffer-from@2.2.0': dependencies: - "@smithy/is-array-buffer": 2.2.0 + '@smithy/is-array-buffer': 2.2.0 tslib: 2.8.1 - "@smithy/util-buffer-from@4.2.2": + '@smithy/util-buffer-from@4.2.2': dependencies: - "@smithy/is-array-buffer": 4.2.2 + '@smithy/is-array-buffer': 4.2.2 tslib: 2.8.1 - "@smithy/util-config-provider@4.2.2": + '@smithy/util-config-provider@4.2.2': dependencies: tslib: 2.8.1 - "@smithy/util-defaults-mode-browser@4.3.39": + '@smithy/util-defaults-mode-browser@4.3.39': dependencies: - "@smithy/property-provider": 4.2.11 - "@smithy/smithy-client": 4.12.3 - "@smithy/types": 4.13.0 + '@smithy/property-provider': 4.2.11 + '@smithy/smithy-client': 4.12.3 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/util-defaults-mode-node@4.2.42": + '@smithy/util-defaults-mode-node@4.2.42': dependencies: - "@smithy/config-resolver": 4.4.10 - "@smithy/credential-provider-imds": 4.2.11 - "@smithy/node-config-provider": 4.3.11 - "@smithy/property-provider": 4.2.11 - "@smithy/smithy-client": 4.12.3 - "@smithy/types": 4.13.0 + '@smithy/config-resolver': 4.4.10 + '@smithy/credential-provider-imds': 4.2.11 + '@smithy/node-config-provider': 4.3.11 + '@smithy/property-provider': 4.2.11 + '@smithy/smithy-client': 4.12.3 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/util-endpoints@3.3.2": + '@smithy/util-endpoints@3.3.2': dependencies: - "@smithy/node-config-provider": 4.3.11 - "@smithy/types": 4.13.0 + '@smithy/node-config-provider': 4.3.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/util-hex-encoding@4.2.2": + '@smithy/util-hex-encoding@4.2.2': dependencies: tslib: 2.8.1 - "@smithy/util-middleware@4.2.11": + '@smithy/util-middleware@4.2.11': dependencies: - "@smithy/types": 4.13.0 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/util-retry@4.2.11": + '@smithy/util-retry@4.2.11': dependencies: - "@smithy/service-error-classification": 4.2.11 - "@smithy/types": 4.13.0 + '@smithy/service-error-classification': 4.2.11 + '@smithy/types': 4.13.0 tslib: 2.8.1 - "@smithy/util-stream@4.5.17": + '@smithy/util-stream@4.5.17': dependencies: - "@smithy/fetch-http-handler": 5.3.13 - "@smithy/node-http-handler": 4.4.14 - "@smithy/types": 4.13.0 - "@smithy/util-base64": 4.3.2 - "@smithy/util-buffer-from": 4.2.2 - "@smithy/util-hex-encoding": 4.2.2 - "@smithy/util-utf8": 4.2.2 + '@smithy/fetch-http-handler': 5.3.13 + '@smithy/node-http-handler': 4.4.14 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - "@smithy/util-uri-escape@4.2.2": + '@smithy/util-uri-escape@4.2.2': dependencies: tslib: 2.8.1 - "@smithy/util-utf8@2.3.0": + '@smithy/util-utf8@2.3.0': dependencies: - "@smithy/util-buffer-from": 2.2.0 + '@smithy/util-buffer-from': 2.2.0 tslib: 2.8.1 - "@smithy/util-utf8@4.2.2": + '@smithy/util-utf8@4.2.2': dependencies: - "@smithy/util-buffer-from": 4.2.2 + '@smithy/util-buffer-from': 4.2.2 tslib: 2.8.1 - "@smithy/uuid@1.1.2": + '@smithy/uuid@1.1.2': dependencies: tslib: 2.8.1 - "@standard-schema/spec@1.1.0": {} + '@standard-schema/spec@1.1.0': {} - "@swc/core-darwin-arm64@1.15.3": + '@swc/core-darwin-arm64@1.15.3': optional: true - "@swc/core-darwin-x64@1.15.3": + '@swc/core-darwin-x64@1.15.3': optional: true - "@swc/core-linux-arm-gnueabihf@1.15.3": + '@swc/core-linux-arm-gnueabihf@1.15.3': optional: true - "@swc/core-linux-arm64-gnu@1.15.3": + '@swc/core-linux-arm64-gnu@1.15.3': optional: true - "@swc/core-linux-arm64-musl@1.15.3": + '@swc/core-linux-arm64-musl@1.15.3': optional: true - "@swc/core-linux-x64-gnu@1.15.3": + '@swc/core-linux-x64-gnu@1.15.3': optional: true - "@swc/core-linux-x64-musl@1.15.3": + '@swc/core-linux-x64-musl@1.15.3': optional: true - "@swc/core-win32-arm64-msvc@1.15.3": + '@swc/core-win32-arm64-msvc@1.15.3': optional: true - "@swc/core-win32-ia32-msvc@1.15.3": + '@swc/core-win32-ia32-msvc@1.15.3': optional: true - "@swc/core-win32-x64-msvc@1.15.3": + '@swc/core-win32-x64-msvc@1.15.3': optional: true - "@swc/core@1.15.3": + '@swc/core@1.15.3': dependencies: - "@swc/counter": 0.1.3 - "@swc/types": 0.1.25 + '@swc/counter': 0.1.3 + '@swc/types': 0.1.25 optionalDependencies: - "@swc/core-darwin-arm64": 1.15.3 - "@swc/core-darwin-x64": 1.15.3 - "@swc/core-linux-arm-gnueabihf": 1.15.3 - "@swc/core-linux-arm64-gnu": 1.15.3 - "@swc/core-linux-arm64-musl": 1.15.3 - "@swc/core-linux-x64-gnu": 1.15.3 - "@swc/core-linux-x64-musl": 1.15.3 - "@swc/core-win32-arm64-msvc": 1.15.3 - "@swc/core-win32-ia32-msvc": 1.15.3 - "@swc/core-win32-x64-msvc": 1.15.3 + '@swc/core-darwin-arm64': 1.15.3 + '@swc/core-darwin-x64': 1.15.3 + '@swc/core-linux-arm-gnueabihf': 1.15.3 + '@swc/core-linux-arm64-gnu': 1.15.3 + '@swc/core-linux-arm64-musl': 1.15.3 + '@swc/core-linux-x64-gnu': 1.15.3 + '@swc/core-linux-x64-musl': 1.15.3 + '@swc/core-win32-arm64-msvc': 1.15.3 + '@swc/core-win32-ia32-msvc': 1.15.3 + '@swc/core-win32-x64-msvc': 1.15.3 optional: true - "@swc/counter@0.1.3": + '@swc/counter@0.1.3': optional: true - "@swc/helpers@0.5.15": + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 - "@swc/types@0.1.25": + '@swc/types@0.1.25': dependencies: - "@swc/counter": 0.1.3 + '@swc/counter': 0.1.3 optional: true - "@tokenizer/inflate@0.4.1": + '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3 token-types: 6.1.2 transitivePeerDependencies: - supports-color - "@tokenizer/token@0.3.0": {} + '@tokenizer/token@0.3.0': {} - "@tootallnate/once@2.0.0": {} + '@tootallnate/once@2.0.0': {} - "@tootallnate/quickjs-emscripten@0.23.0": {} + '@tootallnate/quickjs-emscripten@0.23.0': {} - "@ts-morph/common@0.11.1": + '@ts-morph/common@0.11.1': dependencies: fast-glob: 3.3.3 minimatch: 3.1.5 mkdirp: 1.0.4 path-browserify: 1.0.1 - "@tybys/wasm-util@0.10.1": + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 optional: true - "@types/chai@5.2.3": + '@types/chai@5.2.3': dependencies: - "@types/deep-eql": 4.0.2 + '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 - "@types/connect@3.4.38": + '@types/connect@3.4.38': dependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 - "@types/debug@4.1.12": + '@types/debug@4.1.12': dependencies: - "@types/ms": 2.1.0 + '@types/ms': 2.1.0 - "@types/deep-eql@4.0.2": {} + '@types/deep-eql@4.0.2': {} - "@types/eslint-scope@3.7.7": + '@types/eslint-scope@3.7.7': dependencies: - "@types/eslint": 9.6.1 - "@types/estree": 1.0.8 + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 - "@types/eslint@9.6.1": + '@types/eslint@9.6.1': dependencies: - "@types/estree": 1.0.8 - "@types/json-schema": 7.0.15 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 - "@types/estree-jsx@1.0.5": + '@types/estree-jsx@1.0.5': dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 - "@types/estree@1.0.8": {} + '@types/estree@1.0.8': {} - "@types/hast@3.0.4": + '@types/hast@3.0.4': dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 - "@types/js-yaml@4.0.9": {} + '@types/js-yaml@4.0.9': {} - "@types/json-schema@7.0.15": {} + '@types/json-schema@7.0.15': {} - "@types/mdast@4.0.4": + '@types/mdast@4.0.4': dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 - "@types/mdx@2.0.13": {} + '@types/mdx@2.0.13': {} - "@types/ms@2.1.0": {} + '@types/ms@2.1.0': {} - "@types/mysql@2.15.27": + '@types/mysql@2.15.27': dependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 - "@types/nlcst@2.0.3": + '@types/nlcst@2.0.3': dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 - "@types/node@17.0.45": {} + '@types/node@17.0.45': {} - "@types/node@20.11.0": + '@types/node@20.11.0': dependencies: undici-types: 5.26.5 - "@types/node@20.19.37": + '@types/node@20.19.37': dependencies: undici-types: 6.21.0 - "@types/node@25.3.5": + '@types/node@25.3.5': dependencies: undici-types: 7.18.2 - "@types/node@25.5.0": + '@types/node@25.5.0': dependencies: undici-types: 7.18.2 - "@types/pg-pool@2.0.7": + '@types/pg-pool@2.0.7': dependencies: - "@types/pg": 8.15.6 + '@types/pg': 8.15.6 - "@types/pg@8.15.6": + '@types/pg@8.15.6': dependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 pg-protocol: 1.13.0 pg-types: 2.2.0 - "@types/react-dom@19.2.3(@types/react@19.2.14)": + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: - "@types/react": 19.2.14 + '@types/react': 19.2.14 - "@types/react@19.2.14": + '@types/react@19.2.14': dependencies: csstype: 3.2.3 - "@types/retry@0.12.0": {} + '@types/retry@0.12.0': {} - "@types/sax@1.2.7": + '@types/sax@1.2.7': dependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 - "@types/sinonjs__fake-timers@8.1.5": {} + '@types/sinonjs__fake-timers@8.1.5': {} - "@types/statuses@2.0.6": {} + '@types/statuses@2.0.6': {} - "@types/tedious@4.0.14": + '@types/tedious@4.0.14': dependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 - "@types/unist@2.0.11": {} + '@types/unist@2.0.11': {} - "@types/unist@3.0.3": {} + '@types/unist@3.0.3': {} - "@types/which@2.0.2": {} + '@types/which@2.0.2': {} - "@types/ws@8.18.1": + '@types/ws@8.18.1': dependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 - "@types/yauzl@2.10.3": + '@types/yauzl@2.10.3': dependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 optional: true - "@ungap/structured-clone@1.3.0": {} + '@ungap/structured-clone@1.3.0': {} - "@vercel/backends@0.0.45(rollup@4.59.0)(typescript@5.9.3)": + '@vercel/backends@0.0.45(rollup@4.59.0)(typescript@5.9.3)': dependencies: - "@vercel/build-utils": 13.8.0 - "@vercel/nft": 1.3.0(rollup@4.59.0) + '@vercel/build-utils': 13.8.0 + '@vercel/nft': 1.3.0(rollup@4.59.0) execa: 3.2.0 fs-extra: 11.1.0 oxc-transform: 0.111.0 @@ -14939,7 +10414,7 @@ snapshots: - rollup - supports-color - "@vercel/blob@2.3.0": + '@vercel/blob@2.3.0': dependencies: async-retry: 1.3.3 is-buffer: 2.0.5 @@ -14947,38 +10422,38 @@ snapshots: throttleit: 2.1.0 undici: 6.23.0 - "@vercel/build-utils@13.8.0": + '@vercel/build-utils@13.8.0': dependencies: - "@vercel/python-analysis": 0.9.1 + '@vercel/python-analysis': 0.9.1 - "@vercel/cervel@0.0.32(rollup@4.59.0)(typescript@5.9.3)": + '@vercel/cervel@0.0.32(rollup@4.59.0)(typescript@5.9.3)': dependencies: - "@vercel/backends": 0.0.45(rollup@4.59.0)(typescript@5.9.3) + '@vercel/backends': 0.0.45(rollup@4.59.0)(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - encoding - rollup - supports-color - "@vercel/detect-agent@1.2.1": {} + '@vercel/detect-agent@1.2.1': {} - "@vercel/elysia@0.1.48(rollup@4.59.0)": + '@vercel/elysia@0.1.48(rollup@4.59.0)': dependencies: - "@vercel/node": 5.6.15(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/node': 5.6.15(rollup@4.59.0) + '@vercel/static-config': 3.2.0 transitivePeerDependencies: - encoding - rollup - supports-color - "@vercel/error-utils@2.0.3": {} + '@vercel/error-utils@2.0.3': {} - "@vercel/express@0.1.57(rollup@4.59.0)(typescript@5.9.3)": + '@vercel/express@0.1.57(rollup@4.59.0)(typescript@5.9.3)': dependencies: - "@vercel/cervel": 0.0.32(rollup@4.59.0)(typescript@5.9.3) - "@vercel/nft": 1.1.1(rollup@4.59.0) - "@vercel/node": 5.6.15(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/cervel': 0.0.32(rollup@4.59.0)(typescript@5.9.3) + '@vercel/nft': 1.1.1(rollup@4.59.0) + '@vercel/node': 5.6.15(rollup@4.59.0) + '@vercel/static-config': 3.2.0 fs-extra: 11.1.0 path-to-regexp: 8.3.0 ts-morph: 12.0.0 @@ -14989,18 +10464,18 @@ snapshots: - supports-color - typescript - "@vercel/fastify@0.1.51(rollup@4.59.0)": + '@vercel/fastify@0.1.51(rollup@4.59.0)': dependencies: - "@vercel/node": 5.6.15(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/node': 5.6.15(rollup@4.59.0) + '@vercel/static-config': 3.2.0 transitivePeerDependencies: - encoding - rollup - supports-color - "@vercel/fun@1.3.0": + '@vercel/fun@1.3.0': dependencies: - "@tootallnate/once": 2.0.0 + '@tootallnate/once': 2.0.0 async-listen: 1.2.0 debug: 4.3.4 generic-pool: 3.4.2 @@ -15022,34 +10497,34 @@ snapshots: - encoding - supports-color - "@vercel/gatsby-plugin-vercel-analytics@1.0.11": + '@vercel/gatsby-plugin-vercel-analytics@1.0.11': dependencies: web-vitals: 0.2.4 - "@vercel/gatsby-plugin-vercel-builder@2.1.0": + '@vercel/gatsby-plugin-vercel-builder@2.1.0': dependencies: - "@sinclair/typebox": 0.25.24 - "@vercel/build-utils": 13.8.0 + '@sinclair/typebox': 0.25.24 + '@vercel/build-utils': 13.8.0 esbuild: 0.27.0 etag: 1.8.1 fs-extra: 11.1.0 - "@vercel/go@3.4.5": {} + '@vercel/go@3.4.5': {} - "@vercel/h3@0.1.57(rollup@4.59.0)": + '@vercel/h3@0.1.57(rollup@4.59.0)': dependencies: - "@vercel/node": 5.6.15(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/node': 5.6.15(rollup@4.59.0) + '@vercel/static-config': 3.2.0 transitivePeerDependencies: - encoding - rollup - supports-color - "@vercel/hono@0.2.51(rollup@4.59.0)": + '@vercel/hono@0.2.51(rollup@4.59.0)': dependencies: - "@vercel/nft": 1.1.1(rollup@4.59.0) - "@vercel/node": 5.6.15(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/nft': 1.1.1(rollup@4.59.0) + '@vercel/node': 5.6.15(rollup@4.59.0) + '@vercel/static-config': 3.2.0 fs-extra: 11.1.0 path-to-regexp: 8.3.0 ts-morph: 12.0.0 @@ -15059,41 +10534,41 @@ snapshots: - rollup - supports-color - "@vercel/hydrogen@1.3.6": + '@vercel/hydrogen@1.3.6': dependencies: - "@vercel/static-config": 3.2.0 + '@vercel/static-config': 3.2.0 ts-morph: 12.0.0 - "@vercel/koa@0.1.31(rollup@4.59.0)": + '@vercel/koa@0.1.31(rollup@4.59.0)': dependencies: - "@vercel/node": 5.6.15(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/node': 5.6.15(rollup@4.59.0) + '@vercel/static-config': 3.2.0 transitivePeerDependencies: - encoding - rollup - supports-color - "@vercel/nestjs@0.2.52(rollup@4.59.0)": + '@vercel/nestjs@0.2.52(rollup@4.59.0)': dependencies: - "@vercel/node": 5.6.15(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/node': 5.6.15(rollup@4.59.0) + '@vercel/static-config': 3.2.0 transitivePeerDependencies: - encoding - rollup - supports-color - "@vercel/next@4.16.1(rollup@4.59.0)": + '@vercel/next@4.16.1(rollup@4.59.0)': dependencies: - "@vercel/nft": 1.1.1(rollup@4.59.0) + '@vercel/nft': 1.1.1(rollup@4.59.0) transitivePeerDependencies: - encoding - rollup - supports-color - "@vercel/nft@1.1.1(rollup@4.59.0)": + '@vercel/nft@1.1.1(rollup@4.59.0)': dependencies: - "@mapbox/node-pre-gyp": 2.0.3 - "@rollup/pluginutils": 5.3.0(rollup@4.59.0) + '@mapbox/node-pre-gyp': 2.0.3 + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) acorn: 8.16.0 acorn-import-attributes: 1.9.5(acorn@8.16.0) async-sema: 3.1.1 @@ -15109,10 +10584,10 @@ snapshots: - rollup - supports-color - "@vercel/nft@1.3.0(rollup@4.59.0)": + '@vercel/nft@1.3.0(rollup@4.59.0)': dependencies: - "@mapbox/node-pre-gyp": 2.0.3 - "@rollup/pluginutils": 5.3.0(rollup@4.59.0) + '@mapbox/node-pre-gyp': 2.0.3 + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) acorn: 8.16.0 acorn-import-attributes: 1.9.5(acorn@8.16.0) async-sema: 3.1.1 @@ -15128,16 +10603,16 @@ snapshots: - rollup - supports-color - "@vercel/node@5.6.15(rollup@4.59.0)": + '@vercel/node@5.6.15(rollup@4.59.0)': dependencies: - "@edge-runtime/node-utils": 2.3.0 - "@edge-runtime/primitives": 4.1.0 - "@edge-runtime/vm": 3.2.0 - "@types/node": 20.11.0 - "@vercel/build-utils": 13.8.0 - "@vercel/error-utils": 2.0.3 - "@vercel/nft": 1.1.1(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@edge-runtime/node-utils': 2.3.0 + '@edge-runtime/primitives': 4.1.0 + '@edge-runtime/vm': 3.2.0 + '@types/node': 20.11.0 + '@vercel/build-utils': 13.8.0 + '@vercel/error-utils': 2.0.3 + '@vercel/nft': 1.1.1(rollup@4.59.0) + '@vercel/static-config': 3.2.0 async-listen: 3.0.0 cjs-module-lexer: 1.2.3 edge-runtime: 2.5.9 @@ -15157,14 +10632,14 @@ snapshots: - rollup - supports-color - "@vercel/oidc@3.1.0": {} + '@vercel/oidc@3.1.0': {} - "@vercel/oidc@3.2.0": {} + '@vercel/oidc@3.2.0': {} - "@vercel/python-analysis@0.9.1": + '@vercel/python-analysis@0.9.1': dependencies: - "@bytecodealliance/preview2-shim": 0.17.6 - "@renovatebot/pep440": 4.2.1 + '@bytecodealliance/preview2-shim': 0.17.6 + '@renovatebot/pep440': 4.2.1 fs-extra: 11.1.1 js-yaml: 4.1.1 minimatch: 10.1.1 @@ -15172,21 +10647,21 @@ snapshots: smol-toml: 1.5.2 zod: 3.22.4 - "@vercel/python@6.23.0": + '@vercel/python@6.23.0': dependencies: - "@vercel/python-analysis": 0.9.1 + '@vercel/python-analysis': 0.9.1 - "@vercel/queue@0.1.4": + '@vercel/queue@0.1.4': dependencies: - "@vercel/oidc": 3.2.0 + '@vercel/oidc': 3.2.0 minimatch: 10.2.4 mixpart: 0.0.5 picocolors: 1.1.1 - "@vercel/redwood@2.4.10(rollup@4.59.0)": + '@vercel/redwood@2.4.10(rollup@4.59.0)': dependencies: - "@vercel/nft": 1.1.1(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/nft': 1.1.1(rollup@4.59.0) + '@vercel/static-config': 3.2.0 semver: 6.3.1 ts-morph: 12.0.0 transitivePeerDependencies: @@ -15194,11 +10669,11 @@ snapshots: - rollup - supports-color - "@vercel/remix-builder@5.7.0(rollup@4.59.0)": + '@vercel/remix-builder@5.7.0(rollup@4.59.0)': dependencies: - "@vercel/error-utils": 2.0.3 - "@vercel/nft": 1.1.1(rollup@4.59.0) - "@vercel/static-config": 3.2.0 + '@vercel/error-utils': 2.0.3 + '@vercel/nft': 1.1.1(rollup@4.59.0) + '@vercel/static-config': 3.2.0 path-to-regexp: 6.1.0 path-to-regexp-updated: path-to-regexp@6.3.0 ts-morph: 12.0.0 @@ -15207,16 +10682,16 @@ snapshots: - rollup - supports-color - "@vercel/ruby@2.3.2": {} + '@vercel/ruby@2.3.2': {} - "@vercel/rust@1.0.5": + '@vercel/rust@1.0.5': dependencies: - "@iarna/toml": 2.2.5 + '@iarna/toml': 2.2.5 execa: 5.1.1 - "@vercel/sandbox@1.8.1": + '@vercel/sandbox@1.8.1': dependencies: - "@vercel/oidc": 3.2.0 + '@vercel/oidc': 3.2.0 async-retry: 1.3.3 jsonlines: 0.1.1 ms: 2.1.3 @@ -15229,79 +10704,79 @@ snapshots: - bare-abort-controller - react-native-b4a - "@vercel/static-build@2.9.0": + '@vercel/static-build@2.9.0': dependencies: - "@vercel/gatsby-plugin-vercel-analytics": 1.0.11 - "@vercel/gatsby-plugin-vercel-builder": 2.1.0 - "@vercel/static-config": 3.2.0 + '@vercel/gatsby-plugin-vercel-analytics': 1.0.11 + '@vercel/gatsby-plugin-vercel-builder': 2.1.0 + '@vercel/static-config': 3.2.0 ts-morph: 12.0.0 - "@vercel/static-config@3.2.0": + '@vercel/static-config@3.2.0': dependencies: ajv: 8.6.3 json-schema-to-ts: 1.6.4 ts-morph: 12.0.0 - "@vitest/expect@4.1.0": + '@vitest/expect@4.1.0': dependencies: - "@standard-schema/spec": 1.1.0 - "@types/chai": 5.2.3 - "@vitest/spy": 4.1.0 - "@vitest/utils": 4.1.0 + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 chai: 6.2.2 tinyrainbow: 3.0.3 - "@vitest/mocker@4.1.0(msw@2.12.13(@types/node@25.3.5)(typescript@5.9.3))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))": + '@vitest/mocker@4.1.0(msw@2.12.13(@types/node@25.3.5)(typescript@5.9.3))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - "@vitest/spy": 4.1.0 + '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.12.13(@types/node@25.3.5)(typescript@5.9.3) vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) - "@vitest/pretty-format@4.1.0": + '@vitest/pretty-format@4.1.0': dependencies: tinyrainbow: 3.0.3 - "@vitest/runner@4.1.0": + '@vitest/runner@4.1.0': dependencies: - "@vitest/utils": 4.1.0 + '@vitest/utils': 4.1.0 pathe: 2.0.3 - "@vitest/snapshot@4.1.0": + '@vitest/snapshot@4.1.0': dependencies: - "@vitest/pretty-format": 4.1.0 - "@vitest/utils": 4.1.0 + '@vitest/pretty-format': 4.1.0 + '@vitest/utils': 4.1.0 magic-string: 0.30.21 pathe: 2.0.3 - "@vitest/spy@4.1.0": {} + '@vitest/spy@4.1.0': {} - "@vitest/utils@4.1.0": + '@vitest/utils@4.1.0': dependencies: - "@vitest/pretty-format": 4.1.0 + '@vitest/pretty-format': 4.1.0 convert-source-map: 2.0.0 tinyrainbow: 3.0.3 - "@volar/kit@2.4.28(typescript@5.9.3)": + '@volar/kit@2.4.28(typescript@5.9.3)': dependencies: - "@volar/language-service": 2.4.28 - "@volar/typescript": 2.4.28 + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 typesafe-path: 0.2.2 typescript: 5.9.3 vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.1.0 - "@volar/language-core@2.4.28": + '@volar/language-core@2.4.28': dependencies: - "@volar/source-map": 2.4.28 + '@volar/source-map': 2.4.28 - "@volar/language-server@2.4.28": + '@volar/language-server@2.4.28': dependencies: - "@volar/language-core": 2.4.28 - "@volar/language-service": 2.4.28 - "@volar/typescript": 2.4.28 + '@volar/language-core': 2.4.28 + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 path-browserify: 1.0.1 request-light: 0.7.0 vscode-languageserver: 9.0.1 @@ -15309,22 +10784,22 @@ snapshots: vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.1.0 - "@volar/language-service@2.4.28": + '@volar/language-service@2.4.28': dependencies: - "@volar/language-core": 2.4.28 + '@volar/language-core': 2.4.28 vscode-languageserver-protocol: 3.17.5 vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.1.0 - "@volar/source-map@2.4.28": {} + '@volar/source-map@2.4.28': {} - "@volar/typescript@2.4.28": + '@volar/typescript@2.4.28': dependencies: - "@volar/language-core": 2.4.28 + '@volar/language-core': 2.4.28 path-browserify: 1.0.1 vscode-uri: 3.1.0 - "@vscode/emmet-helper@2.11.0": + '@vscode/emmet-helper@2.11.0': dependencies: emmet: 2.4.11 jsonc-parser: 2.3.1 @@ -15332,13 +10807,13 @@ snapshots: vscode-languageserver-types: 3.17.5 vscode-uri: 3.1.0 - "@vscode/l10n@0.0.18": {} + '@vscode/l10n@0.0.18': {} - "@wdio/config@9.24.0": + '@wdio/config@9.24.0': dependencies: - "@wdio/logger": 9.18.0 - "@wdio/types": 9.24.0 - "@wdio/utils": 9.24.0 + '@wdio/logger': 9.18.0 + '@wdio/types': 9.24.0 + '@wdio/utils': 9.24.0 deepmerge-ts: 7.1.5 glob: 10.5.0 import-meta-resolve: 4.2.0 @@ -15349,7 +10824,7 @@ snapshots: - react-native-b4a - supports-color - "@wdio/logger@9.18.0": + '@wdio/logger@9.18.0': dependencies: chalk: 5.6.2 loglevel: 1.9.2 @@ -15357,21 +10832,21 @@ snapshots: safe-regex2: 5.0.0 strip-ansi: 7.2.0 - "@wdio/protocols@9.24.0": {} + '@wdio/protocols@9.24.0': {} - "@wdio/repl@9.16.2": + '@wdio/repl@9.16.2': dependencies: - "@types/node": 20.19.37 + '@types/node': 20.19.37 - "@wdio/types@9.24.0": + '@wdio/types@9.24.0': dependencies: - "@types/node": 20.19.37 + '@types/node': 20.19.37 - "@wdio/utils@9.24.0": + '@wdio/utils@9.24.0': dependencies: - "@puppeteer/browsers": 2.13.0 - "@wdio/logger": 9.18.0 - "@wdio/types": 9.24.0 + '@puppeteer/browsers': 2.13.0 + '@wdio/logger': 9.18.0 + '@wdio/types': 9.24.0 decamelize: 6.0.1 deepmerge-ts: 7.1.5 edgedriver: 6.3.0 @@ -15389,89 +10864,89 @@ snapshots: - react-native-b4a - supports-color - "@webassemblyjs/ast@1.14.1": + '@webassemblyjs/ast@1.14.1': dependencies: - "@webassemblyjs/helper-numbers": 1.13.2 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - "@webassemblyjs/floating-point-hex-parser@1.13.2": {} + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - "@webassemblyjs/helper-api-error@1.13.2": {} + '@webassemblyjs/helper-api-error@1.13.2': {} - "@webassemblyjs/helper-buffer@1.14.1": {} + '@webassemblyjs/helper-buffer@1.14.1': {} - "@webassemblyjs/helper-numbers@1.13.2": + '@webassemblyjs/helper-numbers@1.13.2': dependencies: - "@webassemblyjs/floating-point-hex-parser": 1.13.2 - "@webassemblyjs/helper-api-error": 1.13.2 - "@xtuc/long": 4.2.2 + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 - "@webassemblyjs/helper-wasm-bytecode@1.13.2": {} + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - "@webassemblyjs/helper-wasm-section@1.14.1": + '@webassemblyjs/helper-wasm-section@1.14.1': dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-buffer": 1.14.1 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 - "@webassemblyjs/wasm-gen": 1.14.1 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 - "@webassemblyjs/ieee754@1.13.2": + '@webassemblyjs/ieee754@1.13.2': dependencies: - "@xtuc/ieee754": 1.2.0 + '@xtuc/ieee754': 1.2.0 - "@webassemblyjs/leb128@1.13.2": + '@webassemblyjs/leb128@1.13.2': dependencies: - "@xtuc/long": 4.2.2 + '@xtuc/long': 4.2.2 - "@webassemblyjs/utf8@1.13.2": {} + '@webassemblyjs/utf8@1.13.2': {} - "@webassemblyjs/wasm-edit@1.14.1": + '@webassemblyjs/wasm-edit@1.14.1': dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-buffer": 1.14.1 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 - "@webassemblyjs/helper-wasm-section": 1.14.1 - "@webassemblyjs/wasm-gen": 1.14.1 - "@webassemblyjs/wasm-opt": 1.14.1 - "@webassemblyjs/wasm-parser": 1.14.1 - "@webassemblyjs/wast-printer": 1.14.1 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 - "@webassemblyjs/wasm-gen@1.14.1": + '@webassemblyjs/wasm-gen@1.14.1': dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 - "@webassemblyjs/ieee754": 1.13.2 - "@webassemblyjs/leb128": 1.13.2 - "@webassemblyjs/utf8": 1.13.2 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - "@webassemblyjs/wasm-opt@1.14.1": + '@webassemblyjs/wasm-opt@1.14.1': dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-buffer": 1.14.1 - "@webassemblyjs/wasm-gen": 1.14.1 - "@webassemblyjs/wasm-parser": 1.14.1 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 - "@webassemblyjs/wasm-parser@1.14.1": + '@webassemblyjs/wasm-parser@1.14.1': dependencies: - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/helper-api-error": 1.13.2 - "@webassemblyjs/helper-wasm-bytecode": 1.13.2 - "@webassemblyjs/ieee754": 1.13.2 - "@webassemblyjs/leb128": 1.13.2 - "@webassemblyjs/utf8": 1.13.2 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - "@webassemblyjs/wast-printer@1.14.1": + '@webassemblyjs/wast-printer@1.14.1': dependencies: - "@webassemblyjs/ast": 1.14.1 - "@xtuc/long": 4.2.2 + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 - "@workflow/serde@4.1.0-beta.2": {} + '@workflow/serde@4.1.0-beta.2': {} - "@xtuc/ieee754@1.2.0": {} + '@xtuc/ieee754@1.2.0': {} - "@xtuc/long@4.2.2": {} + '@xtuc/long@4.2.2': {} - "@zip.js/zip.js@2.8.23": {} + '@zip.js/zip.js@2.8.23': {} abbrev@3.0.1: {} @@ -15479,6 +10954,11 @@ snapshots: dependencies: event-target-shim: 5.0.1 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -15519,10 +10999,10 @@ snapshots: ai@6.0.116(zod@4.3.6): dependencies: - "@ai-sdk/gateway": 3.0.66(zod@4.3.6) - "@ai-sdk/provider": 3.0.8 - "@ai-sdk/provider-utils": 4.0.19(zod@4.3.6) - "@opentelemetry/api": 1.9.0 + '@ai-sdk/gateway': 3.0.66(zod@4.3.6) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6) + '@opentelemetry/api': 1.9.0 zod: 4.3.6 ajv-draft-04@1.0.0(ajv@8.18.0): @@ -15635,13 +11115,13 @@ snapshots: astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): dependencies: - "@astrojs/compiler": 2.13.1 - "@astrojs/internal-helpers": 0.7.5 - "@astrojs/markdown-remark": 6.3.10 - "@astrojs/telemetry": 3.3.0 - "@capsizecss/unpack": 4.0.0 - "@oslojs/encoding": 1.1.0 - "@rollup/pluginutils": 5.3.0(rollup@4.59.0) + '@astrojs/compiler': 2.13.1 + '@astrojs/internal-helpers': 0.7.5 + '@astrojs/markdown-remark': 6.3.10 + '@astrojs/telemetry': 3.3.0 + '@capsizecss/unpack': 4.0.0 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) acorn: 8.16.0 aria-query: 5.3.2 axobject-query: 4.1.0 @@ -15701,21 +11181,21 @@ snapshots: optionalDependencies: sharp: 0.34.5 transitivePeerDependencies: - - "@azure/app-configuration" - - "@azure/cosmos" - - "@azure/data-tables" - - "@azure/identity" - - "@azure/keyvault-secrets" - - "@azure/storage-blob" - - "@capacitor/preferences" - - "@deno/kv" - - "@netlify/blobs" - - "@planetscale/database" - - "@types/node" - - "@upstash/redis" - - "@vercel/blob" - - "@vercel/functions" - - "@vercel/kv" + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' - aws4fetch - db0 - idb-keyval @@ -15826,7 +11306,7 @@ snapshots: gray-matter: 4.0.3 zod: 3.25.76 optionalDependencies: - "@vercel/sandbox": 1.8.1 + '@vercel/sandbox': 1.8.1 just-bash: 2.13.1 basic-ftp@5.2.0: {} @@ -15854,6 +11334,20 @@ snapshots: bluebird@3.7.2: {} + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.0 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} bowser@2.14.1: {} @@ -15920,6 +11414,8 @@ snapshots: bytes@3.1.0: {} + bytes@3.1.2: {} + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -15927,6 +11423,11 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + camelcase@8.0.0: {} caniuse-lite@1.0.30001780: {} @@ -15952,7 +11453,7 @@ snapshots: chat@4.20.2: dependencies: - "@workflow/serde": 4.1.0-beta.2 + '@workflow/serde': 4.1.0-beta.2 mdast-util-to-string: 4.0.0 remark-gfm: 4.0.1 remark-parse: 11.0.0 @@ -16092,8 +11593,12 @@ snapshots: console-control-strings@1.1.0: {} + content-disposition@1.0.1: {} + content-type@1.0.4: {} + content-type@1.0.5: {} + convert-hrtime@3.0.0: {} convert-source-map@2.0.0: {} @@ -16102,10 +11607,19 @@ snapshots: cookie-es@2.0.0: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + cookie@1.1.1: {} core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + crc-32@1.2.2: {} crc32-stream@6.0.0: @@ -16197,6 +11711,8 @@ snapshots: depd@1.1.2: {} + depd@2.0.0: {} + dequal@2.0.3: {} destr@2.0.5: {} @@ -16255,14 +11771,14 @@ snapshots: edge-paths@3.0.5: dependencies: - "@types/which": 2.0.2 + '@types/which': 2.0.2 which: 2.0.2 edge-runtime@2.5.9: dependencies: - "@edge-runtime/format": 2.2.1 - "@edge-runtime/ponyfill": 2.4.2 - "@edge-runtime/vm": 3.2.0 + '@edge-runtime/format': 2.2.1 + '@edge-runtime/ponyfill': 2.4.2 + '@edge-runtime/vm': 3.2.0 async-listen: 3.0.1 mri: 1.2.0 picocolors: 1.0.0 @@ -16272,8 +11788,8 @@ snapshots: edgedriver@6.3.0: dependencies: - "@wdio/logger": 9.18.0 - "@zip.js/zip.js": 2.8.23 + '@wdio/logger': 9.18.0 + '@zip.js/zip.js': 2.8.23 decamelize: 6.0.1 edge-paths: 3.0.5 fast-xml-parser: 5.4.2 @@ -16283,12 +11799,14 @@ snapshots: transitivePeerDependencies: - supports-color + ee-first@1.1.1: {} + electron-to-chromium@1.5.307: {} emmet@2.4.11: dependencies: - "@emmetio/abbreviation": 2.3.3 - "@emmetio/css-abbreviation": 2.1.8 + '@emmetio/abbreviation': 2.3.3 + '@emmetio/css-abbreviation': 2.1.8 emoji-regex@10.6.0: {} @@ -16296,6 +11814,8 @@ snapshots: emoji-regex@9.2.2: {} + encodeurl@2.0.0: {} + encoding-sniffer@0.2.1: dependencies: iconv-lite: 0.6.3 @@ -16345,107 +11865,109 @@ snapshots: esast-util-from-estree@2.0.0: dependencies: - "@types/estree-jsx": 1.0.5 + '@types/estree-jsx': 1.0.5 devlop: 1.1.0 estree-util-visit: 2.0.0 unist-util-position-from-estree: 2.0.0 esast-util-from-js@2.0.1: dependencies: - "@types/estree-jsx": 1.0.5 + '@types/estree-jsx': 1.0.5 acorn: 8.16.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 esbuild@0.25.12: optionalDependencies: - "@esbuild/aix-ppc64": 0.25.12 - "@esbuild/android-arm": 0.25.12 - "@esbuild/android-arm64": 0.25.12 - "@esbuild/android-x64": 0.25.12 - "@esbuild/darwin-arm64": 0.25.12 - "@esbuild/darwin-x64": 0.25.12 - "@esbuild/freebsd-arm64": 0.25.12 - "@esbuild/freebsd-x64": 0.25.12 - "@esbuild/linux-arm": 0.25.12 - "@esbuild/linux-arm64": 0.25.12 - "@esbuild/linux-ia32": 0.25.12 - "@esbuild/linux-loong64": 0.25.12 - "@esbuild/linux-mips64el": 0.25.12 - "@esbuild/linux-ppc64": 0.25.12 - "@esbuild/linux-riscv64": 0.25.12 - "@esbuild/linux-s390x": 0.25.12 - "@esbuild/linux-x64": 0.25.12 - "@esbuild/netbsd-arm64": 0.25.12 - "@esbuild/netbsd-x64": 0.25.12 - "@esbuild/openbsd-arm64": 0.25.12 - "@esbuild/openbsd-x64": 0.25.12 - "@esbuild/openharmony-arm64": 0.25.12 - "@esbuild/sunos-x64": 0.25.12 - "@esbuild/win32-arm64": 0.25.12 - "@esbuild/win32-ia32": 0.25.12 - "@esbuild/win32-x64": 0.25.12 + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 esbuild@0.27.0: optionalDependencies: - "@esbuild/aix-ppc64": 0.27.0 - "@esbuild/android-arm": 0.27.0 - "@esbuild/android-arm64": 0.27.0 - "@esbuild/android-x64": 0.27.0 - "@esbuild/darwin-arm64": 0.27.0 - "@esbuild/darwin-x64": 0.27.0 - "@esbuild/freebsd-arm64": 0.27.0 - "@esbuild/freebsd-x64": 0.27.0 - "@esbuild/linux-arm": 0.27.0 - "@esbuild/linux-arm64": 0.27.0 - "@esbuild/linux-ia32": 0.27.0 - "@esbuild/linux-loong64": 0.27.0 - "@esbuild/linux-mips64el": 0.27.0 - "@esbuild/linux-ppc64": 0.27.0 - "@esbuild/linux-riscv64": 0.27.0 - "@esbuild/linux-s390x": 0.27.0 - "@esbuild/linux-x64": 0.27.0 - "@esbuild/netbsd-arm64": 0.27.0 - "@esbuild/netbsd-x64": 0.27.0 - "@esbuild/openbsd-arm64": 0.27.0 - "@esbuild/openbsd-x64": 0.27.0 - "@esbuild/openharmony-arm64": 0.27.0 - "@esbuild/sunos-x64": 0.27.0 - "@esbuild/win32-arm64": 0.27.0 - "@esbuild/win32-ia32": 0.27.0 - "@esbuild/win32-x64": 0.27.0 + '@esbuild/aix-ppc64': 0.27.0 + '@esbuild/android-arm': 0.27.0 + '@esbuild/android-arm64': 0.27.0 + '@esbuild/android-x64': 0.27.0 + '@esbuild/darwin-arm64': 0.27.0 + '@esbuild/darwin-x64': 0.27.0 + '@esbuild/freebsd-arm64': 0.27.0 + '@esbuild/freebsd-x64': 0.27.0 + '@esbuild/linux-arm': 0.27.0 + '@esbuild/linux-arm64': 0.27.0 + '@esbuild/linux-ia32': 0.27.0 + '@esbuild/linux-loong64': 0.27.0 + '@esbuild/linux-mips64el': 0.27.0 + '@esbuild/linux-ppc64': 0.27.0 + '@esbuild/linux-riscv64': 0.27.0 + '@esbuild/linux-s390x': 0.27.0 + '@esbuild/linux-x64': 0.27.0 + '@esbuild/netbsd-arm64': 0.27.0 + '@esbuild/netbsd-x64': 0.27.0 + '@esbuild/openbsd-arm64': 0.27.0 + '@esbuild/openbsd-x64': 0.27.0 + '@esbuild/openharmony-arm64': 0.27.0 + '@esbuild/sunos-x64': 0.27.0 + '@esbuild/win32-arm64': 0.27.0 + '@esbuild/win32-ia32': 0.27.0 + '@esbuild/win32-x64': 0.27.0 esbuild@0.27.3: optionalDependencies: - "@esbuild/aix-ppc64": 0.27.3 - "@esbuild/android-arm": 0.27.3 - "@esbuild/android-arm64": 0.27.3 - "@esbuild/android-x64": 0.27.3 - "@esbuild/darwin-arm64": 0.27.3 - "@esbuild/darwin-x64": 0.27.3 - "@esbuild/freebsd-arm64": 0.27.3 - "@esbuild/freebsd-x64": 0.27.3 - "@esbuild/linux-arm": 0.27.3 - "@esbuild/linux-arm64": 0.27.3 - "@esbuild/linux-ia32": 0.27.3 - "@esbuild/linux-loong64": 0.27.3 - "@esbuild/linux-mips64el": 0.27.3 - "@esbuild/linux-ppc64": 0.27.3 - "@esbuild/linux-riscv64": 0.27.3 - "@esbuild/linux-s390x": 0.27.3 - "@esbuild/linux-x64": 0.27.3 - "@esbuild/netbsd-arm64": 0.27.3 - "@esbuild/netbsd-x64": 0.27.3 - "@esbuild/openbsd-arm64": 0.27.3 - "@esbuild/openbsd-x64": 0.27.3 - "@esbuild/openharmony-arm64": 0.27.3 - "@esbuild/sunos-x64": 0.27.3 - "@esbuild/win32-arm64": 0.27.3 - "@esbuild/win32-ia32": 0.27.3 - "@esbuild/win32-x64": 0.27.3 + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@5.0.0: {} escodegen@2.1.0: @@ -16473,11 +11995,11 @@ snapshots: estree-util-attach-comments@3.0.0: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 estree-util-build-jsx@3.0.1: dependencies: - "@types/estree-jsx": 1.0.5 + '@types/estree-jsx': 1.0.5 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 estree-walker: 3.0.3 @@ -16486,25 +12008,25 @@ snapshots: estree-util-scope@1.0.0: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 devlop: 1.1.0 estree-util-to-js@2.0.0: dependencies: - "@types/estree-jsx": 1.0.5 + '@types/estree-jsx': 1.0.5 astring: 1.9.0 source-map: 0.7.6 estree-util-visit@2.0.0: dependencies: - "@types/estree-jsx": 1.0.5 - "@types/unist": 3.0.3 + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 estree-walker@2.0.2: {} estree-walker@3.0.3: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 esutils@2.0.3: {} @@ -16528,6 +12050,10 @@ snapshots: eventsource-parser@3.0.6: {} + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + execa@3.2.0: dependencies: cross-spawn: 7.0.6 @@ -16558,12 +12084,50 @@ snapshots: expect-type@1.3.0: {} + express-rate-limit@8.3.1(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + expressive-code@0.41.7: dependencies: - "@expressive-code/core": 0.41.7 - "@expressive-code/plugin-frames": 0.41.7 - "@expressive-code/plugin-shiki": 0.41.7 - "@expressive-code/plugin-text-markers": 0.41.7 + '@expressive-code/core': 0.41.7 + '@expressive-code/plugin-frames': 0.41.7 + '@expressive-code/plugin-shiki': 0.41.7 + '@expressive-code/plugin-text-markers': 0.41.7 extend-shallow@2.0.1: dependencies: @@ -16577,7 +12141,7 @@ snapshots: get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: - "@types/yauzl": 2.10.3 + '@types/yauzl': 2.10.3 transitivePeerDependencies: - supports-color @@ -16589,8 +12153,8 @@ snapshots: fast-glob@3.3.3: dependencies: - "@nodelib/fs.stat": 2.0.5 - "@nodelib/fs.walk": 1.2.8 + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.8 @@ -16628,7 +12192,7 @@ snapshots: file-type@21.3.0: dependencies: - "@tokenizer/inflate": 0.4.1 + '@tokenizer/inflate': 0.4.1 strtok3: 10.3.4 token-types: 6.1.2 uint8array-extras: 1.5.0 @@ -16641,6 +12205,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -16683,6 +12258,10 @@ snapshots: forwarded-parse@2.1.2: {} + forwarded@0.2.0: {} + + fresh@2.0.0: {} + fs-constants@1.0.0: optional: true @@ -16722,8 +12301,8 @@ snapshots: geckodriver@6.1.0: dependencies: - "@wdio/logger": 9.18.0 - "@zip.js/zip.js": 2.8.23 + '@wdio/logger': 9.18.0 + '@zip.js/zip.js': 2.8.23 decamelize: 6.0.1 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -16859,12 +12438,12 @@ snapshots: hast-util-embedded@3.0.0: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-is-element: 3.0.0 hast-util-format@1.1.0: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-embedded: 3.0.0 hast-util-minify-whitespace: 1.0.1 hast-util-phrasing: 3.0.1 @@ -16874,7 +12453,7 @@ snapshots: hast-util-from-html@2.0.3: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 devlop: 1.1.0 hast-util-from-parse5: 8.0.3 parse5: 7.3.0 @@ -16883,8 +12462,8 @@ snapshots: hast-util-from-parse5@8.0.3: dependencies: - "@types/hast": 3.0.4 - "@types/unist": 3.0.3 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 devlop: 1.1.0 hastscript: 9.0.1 property-information: 7.1.0 @@ -16894,19 +12473,19 @@ snapshots: hast-util-has-property@3.0.0: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-is-body-ok-link@3.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-is-element@3.0.0: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-minify-whitespace@1.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-embedded: 3.0.0 hast-util-is-element: 3.0.0 hast-util-whitespace: 3.0.0 @@ -16914,11 +12493,11 @@ snapshots: hast-util-parse-selector@4.0.0: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-phrasing@3.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-embedded: 3.0.0 hast-util-has-property: 3.0.0 hast-util-is-body-ok-link: 3.0.1 @@ -16926,9 +12505,9 @@ snapshots: hast-util-raw@9.1.0: dependencies: - "@types/hast": 3.0.4 - "@types/unist": 3.0.3 - "@ungap/structured-clone": 1.3.0 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 hast-util-from-parse5: 8.0.3 hast-util-to-parse5: 8.0.1 html-void-elements: 3.0.0 @@ -16942,8 +12521,8 @@ snapshots: hast-util-select@6.0.4: dependencies: - "@types/hast": 3.0.4 - "@types/unist": 3.0.3 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 bcp-47-match: 2.0.3 comma-separated-tokens: 2.0.3 css-selector-parser: 3.3.0 @@ -16960,9 +12539,9 @@ snapshots: hast-util-to-estree@3.1.3: dependencies: - "@types/estree": 1.0.8 - "@types/estree-jsx": 1.0.5 - "@types/hast": 3.0.4 + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 devlop: 1.1.0 estree-util-attach-comments: 3.0.0 @@ -16981,8 +12560,8 @@ snapshots: hast-util-to-html@9.0.5: dependencies: - "@types/hast": 3.0.4 - "@types/unist": 3.0.3 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 ccount: 2.0.1 comma-separated-tokens: 2.0.3 hast-util-whitespace: 3.0.0 @@ -16995,9 +12574,9 @@ snapshots: hast-util-to-jsx-runtime@2.3.6: dependencies: - "@types/estree": 1.0.8 - "@types/hast": 3.0.4 - "@types/unist": 3.0.3 + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 comma-separated-tokens: 2.0.3 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 @@ -17015,7 +12594,7 @@ snapshots: hast-util-to-parse5@8.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 devlop: 1.1.0 property-information: 7.1.0 @@ -17025,22 +12604,22 @@ snapshots: hast-util-to-string@3.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-to-text@4.0.2: dependencies: - "@types/hast": 3.0.4 - "@types/unist": 3.0.3 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 hast-util-is-element: 3.0.0 unist-util-find-after: 5.0.0 hast-util-whitespace@3.0.0: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hastscript@9.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 hast-util-parse-selector: 4.0.0 property-information: 7.1.0 @@ -17050,6 +12629,8 @@ snapshots: headers-polyfill@4.0.3: {} + hono@4.12.8: {} + html-escaper@3.0.3: {} html-void-elements@3.0.0: {} @@ -17075,6 +12656,14 @@ snapshots: statuses: 1.5.0 toidentifier: 1.0.0 + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -17102,7 +12691,7 @@ snapshots: i18next@23.16.8: dependencies: - "@babel/runtime": 7.28.6 + '@babel/runtime': 7.28.6 iconv-lite@0.4.24: dependencies: @@ -17112,6 +12701,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} immediate@3.0.6: {} @@ -17143,6 +12736,8 @@ snapshots: ip-address@10.1.0: {} + ipaddr.js@1.9.1: {} + iron-webcrypto@1.2.1: {} is-alphabetical@2.0.1: {} @@ -17186,9 +12781,11 @@ snapshots: is-plain-obj@4.1.0: {} + is-promise@4.0.0: {} + is-reference@1.2.1: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 is-stream@2.0.1: {} @@ -17206,13 +12803,13 @@ snapshots: jackspeak@3.4.3: dependencies: - "@isaacs/cliui": 8.0.2 + '@isaacs/cliui': 8.0.2 optionalDependencies: - "@pkgjs/parseargs": 0.11.0 + '@pkgjs/parseargs': 0.11.0 jest-worker@27.5.1: dependencies: - "@types/node": 25.5.0 + '@types/node': 25.5.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -17220,6 +12817,8 @@ snapshots: jose@5.9.6: {} + jose@6.2.1: {} + joycon@3.1.1: {} js-tokens@4.0.0: {} @@ -17243,16 +12842,18 @@ snapshots: json-schema-to-ts@1.6.4: dependencies: - "@types/json-schema": 7.0.15 + '@types/json-schema': 7.0.15 ts-toolbelt: 6.15.5 json-schema-to-ts@3.1.1: dependencies: - "@babel/runtime": 7.28.6 + '@babel/runtime': 7.28.6 ts-algebra: 2.0.0 json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json5@2.2.3: {} @@ -17294,7 +12895,7 @@ snapshots: turndown: 7.2.2 yaml: 2.8.2 optionalDependencies: - "@mongodb-js/zstd": 7.0.0 + '@mongodb-js/zstd': 7.0.0 node-liblzma: 2.2.0 transitivePeerDependencies: - supports-color @@ -17358,7 +12959,7 @@ snapshots: locate-app@2.5.0: dependencies: - "@promptbook/utils": 0.69.5 + '@promptbook/utils': 0.69.5 type-fest: 4.26.0 userhome: 1.0.1 @@ -17408,12 +13009,12 @@ snapshots: magic-string@0.30.21: dependencies: - "@jridgewell/sourcemap-codec": 1.5.5 + '@jridgewell/sourcemap-codec': 1.5.5 magicast@0.5.2: dependencies: - "@babel/parser": 7.29.0 - "@babel/types": 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 source-map-js: 1.2.1 markdown-extensions@2.0.0: {} @@ -17433,14 +13034,14 @@ snapshots: mdast-util-definitions@6.0.0: dependencies: - "@types/mdast": 4.0.4 - "@types/unist": 3.0.3 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 unist-util-visit: 5.1.0 mdast-util-directive@3.1.0: dependencies: - "@types/mdast": 4.0.4 - "@types/unist": 3.0.3 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 mdast-util-from-markdown: 2.0.3 @@ -17453,15 +13054,15 @@ snapshots: mdast-util-find-and-replace@3.0.2: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 escape-string-regexp: 5.0.0 unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 mdast-util-from-markdown@2.0.3: dependencies: - "@types/mdast": 4.0.4 - "@types/unist": 3.0.3 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 @@ -17477,7 +13078,7 @@ snapshots: mdast-util-gfm-autolink-literal@2.0.1: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 ccount: 2.0.1 devlop: 1.1.0 mdast-util-find-and-replace: 3.0.2 @@ -17485,7 +13086,7 @@ snapshots: mdast-util-gfm-footnote@2.1.0: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 devlop: 1.1.0 mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 @@ -17495,7 +13096,7 @@ snapshots: mdast-util-gfm-strikethrough@2.0.0: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: @@ -17503,7 +13104,7 @@ snapshots: mdast-util-gfm-table@2.0.0: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 mdast-util-from-markdown: 2.0.3 @@ -17513,7 +13114,7 @@ snapshots: mdast-util-gfm-task-list-item@2.0.0: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 devlop: 1.1.0 mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 @@ -17534,9 +13135,9 @@ snapshots: mdast-util-mdx-expression@2.0.1: dependencies: - "@types/estree-jsx": 1.0.5 - "@types/hast": 3.0.4 - "@types/mdast": 4.0.4 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 devlop: 1.1.0 mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 @@ -17545,10 +13146,10 @@ snapshots: mdast-util-mdx-jsx@3.2.0: dependencies: - "@types/estree-jsx": 1.0.5 - "@types/hast": 3.0.4 - "@types/mdast": 4.0.4 - "@types/unist": 3.0.3 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 mdast-util-from-markdown: 2.0.3 @@ -17572,9 +13173,9 @@ snapshots: mdast-util-mdxjs-esm@2.0.1: dependencies: - "@types/estree-jsx": 1.0.5 - "@types/hast": 3.0.4 - "@types/mdast": 4.0.4 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 devlop: 1.1.0 mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 @@ -17583,14 +13184,14 @@ snapshots: mdast-util-phrasing@4.1.0: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 unist-util-is: 6.0.1 mdast-util-to-hast@13.2.1: dependencies: - "@types/hast": 3.0.4 - "@types/mdast": 4.0.4 - "@ungap/structured-clone": 1.3.0 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 devlop: 1.1.0 micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 @@ -17600,8 +13201,8 @@ snapshots: mdast-util-to-markdown@2.1.2: dependencies: - "@types/mdast": 4.0.4 - "@types/unist": 3.0.3 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 longest-streak: 3.1.0 mdast-util-phrasing: 4.1.0 mdast-util-to-string: 4.0.0 @@ -17612,7 +13213,7 @@ snapshots: mdast-util-to-string@4.0.0: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 mdn-data@2.0.28: {} @@ -17620,6 +13221,10 @@ snapshots: mdurl@2.0.0: {} + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -17719,7 +13324,7 @@ snapshots: micromark-extension-mdx-expression@3.0.1: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 devlop: 1.1.0 micromark-factory-mdx-expression: 2.0.3 micromark-factory-space: 2.0.1 @@ -17730,7 +13335,7 @@ snapshots: micromark-extension-mdx-jsx@3.0.2: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 micromark-factory-mdx-expression: 2.0.3 @@ -17747,7 +13352,7 @@ snapshots: micromark-extension-mdxjs-esm@3.0.0: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-util-character: 2.1.1 @@ -17783,7 +13388,7 @@ snapshots: micromark-factory-mdx-expression@2.0.3: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 devlop: 1.1.0 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 @@ -17847,8 +13452,8 @@ snapshots: micromark-util-events-to-acorn@2.0.3: dependencies: - "@types/estree": 1.0.8 - "@types/unist": 3.0.3 + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 devlop: 1.1.0 estree-util-visit: 2.0.0 micromark-util-symbol: 2.0.1 @@ -17884,7 +13489,7 @@ snapshots: micromark@4.0.2: dependencies: - "@types/debug": 4.1.12 + '@types/debug': 4.1.12 debug: 4.4.3 decode-named-character-reference: 1.3.0 devlop: 1.1.0 @@ -17911,10 +13516,16 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mimic-fn@2.1.0: {} mimic-function@5.0.1: {} @@ -17924,7 +13535,7 @@ snapshots: minimatch@10.1.1: dependencies: - "@isaacs/brace-expansion": 5.0.1 + '@isaacs/brace-expansion': 5.0.1 minimatch@10.2.4: dependencies: @@ -17983,10 +13594,10 @@ snapshots: msw@2.12.13(@types/node@25.3.5)(typescript@5.9.3): dependencies: - "@inquirer/confirm": 5.1.21(@types/node@25.3.5) - "@mswjs/interceptors": 0.41.3 - "@open-draft/deferred-promise": 2.2.0 - "@types/statuses": 2.0.6 + '@inquirer/confirm': 5.1.21(@types/node@25.3.5) + '@mswjs/interceptors': 0.41.3 + '@open-draft/deferred-promise': 2.2.0 + '@types/statuses': 2.0.6 cookie: 1.1.1 graphql: 16.13.1 headers-polyfill: 4.0.3 @@ -18004,7 +13615,7 @@ snapshots: optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - - "@types/node" + - '@types/node' muggle-string@0.4.1: {} @@ -18021,6 +13632,8 @@ snapshots: napi-build-utils@2.0.0: optional: true + negotiator@1.0.0: {} + neo-async@2.6.2: {} neotraverse@0.6.18: {} @@ -18029,8 +13642,8 @@ snapshots: next@16.1.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - "@next/env": 16.1.7 - "@swc/helpers": 0.5.15 + '@next/env': 16.1.7 + '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.8 caniuse-lite: 1.0.30001780 postcss: 8.4.31 @@ -18038,23 +13651,23 @@ snapshots: react-dom: 19.2.4(react@19.2.4) styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) optionalDependencies: - "@next/swc-darwin-arm64": 16.1.7 - "@next/swc-darwin-x64": 16.1.7 - "@next/swc-linux-arm64-gnu": 16.1.7 - "@next/swc-linux-arm64-musl": 16.1.7 - "@next/swc-linux-x64-gnu": 16.1.7 - "@next/swc-linux-x64-musl": 16.1.7 - "@next/swc-win32-arm64-msvc": 16.1.7 - "@next/swc-win32-x64-msvc": 16.1.7 - "@opentelemetry/api": 1.9.0 + '@next/swc-darwin-arm64': 16.1.7 + '@next/swc-darwin-x64': 16.1.7 + '@next/swc-linux-arm64-gnu': 16.1.7 + '@next/swc-linux-arm64-musl': 16.1.7 + '@next/swc-linux-x64-gnu': 16.1.7 + '@next/swc-linux-x64-musl': 16.1.7 + '@next/swc-win32-arm64-msvc': 16.1.7 + '@next/swc-win32-x64-msvc': 16.1.7 + '@opentelemetry/api': 1.9.0 sharp: 0.34.5 transitivePeerDependencies: - - "@babel/core" + - '@babel/core' - babel-plugin-macros nlcst-to-string@4.0.0: dependencies: - "@types/nlcst": 2.0.3 + '@types/nlcst': 2.0.3 node-abi@3.87.0: dependencies: @@ -18109,7 +13722,7 @@ snapshots: node-simctl@7.7.5: dependencies: - "@appium/logger": 1.7.1 + '@appium/logger': 1.7.1 asyncbox: 3.0.0 bluebird: 3.7.2 lodash: 4.17.21 @@ -18136,6 +13749,8 @@ snapshots: object-assign@4.1.1: {} + object-inspect@1.13.4: {} + obug@2.1.1: {} ofetch@1.5.1: @@ -18148,6 +13763,10 @@ snapshots: ohm-js@17.5.0: {} + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.3.3: dependencies: wrappy: 1.0.2 @@ -18183,26 +13802,26 @@ snapshots: oxc-transform@0.111.0: optionalDependencies: - "@oxc-transform/binding-android-arm-eabi": 0.111.0 - "@oxc-transform/binding-android-arm64": 0.111.0 - "@oxc-transform/binding-darwin-arm64": 0.111.0 - "@oxc-transform/binding-darwin-x64": 0.111.0 - "@oxc-transform/binding-freebsd-x64": 0.111.0 - "@oxc-transform/binding-linux-arm-gnueabihf": 0.111.0 - "@oxc-transform/binding-linux-arm-musleabihf": 0.111.0 - "@oxc-transform/binding-linux-arm64-gnu": 0.111.0 - "@oxc-transform/binding-linux-arm64-musl": 0.111.0 - "@oxc-transform/binding-linux-ppc64-gnu": 0.111.0 - "@oxc-transform/binding-linux-riscv64-gnu": 0.111.0 - "@oxc-transform/binding-linux-riscv64-musl": 0.111.0 - "@oxc-transform/binding-linux-s390x-gnu": 0.111.0 - "@oxc-transform/binding-linux-x64-gnu": 0.111.0 - "@oxc-transform/binding-linux-x64-musl": 0.111.0 - "@oxc-transform/binding-openharmony-arm64": 0.111.0 - "@oxc-transform/binding-wasm32-wasi": 0.111.0 - "@oxc-transform/binding-win32-arm64-msvc": 0.111.0 - "@oxc-transform/binding-win32-ia32-msvc": 0.111.0 - "@oxc-transform/binding-win32-x64-msvc": 0.111.0 + '@oxc-transform/binding-android-arm-eabi': 0.111.0 + '@oxc-transform/binding-android-arm64': 0.111.0 + '@oxc-transform/binding-darwin-arm64': 0.111.0 + '@oxc-transform/binding-darwin-x64': 0.111.0 + '@oxc-transform/binding-freebsd-x64': 0.111.0 + '@oxc-transform/binding-linux-arm-gnueabihf': 0.111.0 + '@oxc-transform/binding-linux-arm-musleabihf': 0.111.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.111.0 + '@oxc-transform/binding-linux-arm64-musl': 0.111.0 + '@oxc-transform/binding-linux-ppc64-gnu': 0.111.0 + '@oxc-transform/binding-linux-riscv64-gnu': 0.111.0 + '@oxc-transform/binding-linux-riscv64-musl': 0.111.0 + '@oxc-transform/binding-linux-s390x-gnu': 0.111.0 + '@oxc-transform/binding-linux-x64-gnu': 0.111.0 + '@oxc-transform/binding-linux-x64-musl': 0.111.0 + '@oxc-transform/binding-openharmony-arm64': 0.111.0 + '@oxc-transform/binding-wasm32-wasi': 0.111.0 + '@oxc-transform/binding-win32-arm64-msvc': 0.111.0 + '@oxc-transform/binding-win32-ia32-msvc': 0.111.0 + '@oxc-transform/binding-win32-x64-msvc': 0.111.0 p-finally@1.0.0: {} @@ -18232,7 +13851,7 @@ snapshots: p-retry@4.6.2: dependencies: - "@types/retry": 0.12.0 + '@types/retry': 0.12.0 retry: 0.13.1 p-timeout@3.2.0: @@ -18243,7 +13862,7 @@ snapshots: pac-proxy-agent@7.2.0: dependencies: - "@tootallnate/quickjs-emscripten": 0.23.0 + '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.4 debug: 4.4.3 get-uri: 6.0.5 @@ -18265,12 +13884,12 @@ snapshots: pagefind@1.4.0: optionalDependencies: - "@pagefind/darwin-arm64": 1.4.0 - "@pagefind/darwin-x64": 1.4.0 - "@pagefind/freebsd-x64": 1.4.0 - "@pagefind/linux-arm64": 1.4.0 - "@pagefind/linux-x64": 1.4.0 - "@pagefind/windows-x64": 1.4.0 + '@pagefind/darwin-arm64': 1.4.0 + '@pagefind/darwin-x64': 1.4.0 + '@pagefind/freebsd-x64': 1.4.0 + '@pagefind/linux-arm64': 1.4.0 + '@pagefind/linux-x64': 1.4.0 + '@pagefind/windows-x64': 1.4.0 pako@1.0.11: {} @@ -18278,7 +13897,7 @@ snapshots: parse-entities@4.0.2: dependencies: - "@types/unist": 2.0.11 + '@types/unist': 2.0.11 character-entities-legacy: 3.0.0 character-reference-invalid: 2.0.1 decode-named-character-reference: 1.3.0 @@ -18288,8 +13907,8 @@ snapshots: parse-latin@7.0.0: dependencies: - "@types/nlcst": 2.0.3 - "@types/unist": 3.0.3 + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 nlcst-to-string: 4.0.0 unist-util-modify-children: 4.0.0 unist-util-visit-children: 3.0.0 @@ -18310,6 +13929,8 @@ snapshots: dependencies: entities: 6.0.1 + parseurl@1.3.3: {} + partial-json@0.1.7: {} path-browserify@1.0.1: {} @@ -18368,6 +13989,8 @@ snapshots: pirates@4.0.7: {} + pkce-challenge@5.0.1: {} + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -18458,19 +14081,24 @@ snapshots: protobufjs@7.5.4: dependencies: - "@protobufjs/aspromise": 1.1.2 - "@protobufjs/base64": 1.1.2 - "@protobufjs/codegen": 2.0.4 - "@protobufjs/eventemitter": 1.1.0 - "@protobufjs/fetch": 1.1.0 - "@protobufjs/float": 1.0.2 - "@protobufjs/inquire": 1.1.0 - "@protobufjs/path": 1.1.2 - "@protobufjs/pool": 1.1.0 - "@protobufjs/utf8": 1.1.0 - "@types/node": 25.5.0 + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 25.5.0 long: 5.3.2 + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + proxy-agent@6.4.0: dependencies: agent-base: 7.1.4 @@ -18508,24 +14136,30 @@ snapshots: punycode@2.3.1: {} + qs@6.15.0: + dependencies: + side-channel: 1.1.0 + query-selector-shadow-dom@1.0.1: {} queue-microtask@1.2.3: {} quickjs-emscripten-core@0.32.0: dependencies: - "@jitl/quickjs-ffi-types": 0.32.0 + '@jitl/quickjs-ffi-types': 0.32.0 quickjs-emscripten@0.32.0: dependencies: - "@jitl/quickjs-wasmfile-debug-asyncify": 0.32.0 - "@jitl/quickjs-wasmfile-debug-sync": 0.32.0 - "@jitl/quickjs-wasmfile-release-asyncify": 0.32.0 - "@jitl/quickjs-wasmfile-release-sync": 0.32.0 + '@jitl/quickjs-wasmfile-debug-asyncify': 0.32.0 + '@jitl/quickjs-wasmfile-debug-sync': 0.32.0 + '@jitl/quickjs-wasmfile-release-asyncify': 0.32.0 + '@jitl/quickjs-wasmfile-release-sync': 0.32.0 quickjs-emscripten-core: 0.32.0 radix3@1.1.2: {} + range-parser@1.2.1: {} + raw-body@2.4.1: dependencies: bytes: 3.1.0 @@ -18533,6 +14167,13 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -18585,7 +14226,7 @@ snapshots: recma-build-jsx@1.0.0: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 estree-util-build-jsx: 3.0.1 vfile: 6.0.3 @@ -18600,27 +14241,27 @@ snapshots: recma-parse@1.0.0: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 esast-util-from-js: 2.0.1 unified: 11.0.5 vfile: 6.0.3 recma-stringify@1.0.0: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 estree-util-to-js: 2.0.0 unified: 11.0.5 vfile: 6.0.3 redis@5.11.0: dependencies: - "@redis/bloom": 5.11.0(@redis/client@5.11.0) - "@redis/client": 5.11.0 - "@redis/json": 5.11.0(@redis/client@5.11.0) - "@redis/search": 5.11.0(@redis/client@5.11.0) - "@redis/time-series": 5.11.0(@redis/client@5.11.0) + '@redis/bloom': 5.11.0(@redis/client@5.11.0) + '@redis/client': 5.11.0 + '@redis/json': 5.11.0(@redis/client@5.11.0) + '@redis/search': 5.11.0(@redis/client@5.11.0) + '@redis/time-series': 5.11.0(@redis/client@5.11.0) transitivePeerDependencies: - - "@node-rs/xxhash" + - '@node-rs/xxhash' regex-recursion@6.0.2: dependencies: @@ -18638,45 +14279,45 @@ snapshots: rehype-format@5.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-format: 1.1.0 rehype-parse@9.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-from-html: 2.0.3 unified: 11.0.5 rehype-raw@7.0.0: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-raw: 9.1.0 vfile: 6.0.3 rehype-recma@1.0.0: dependencies: - "@types/estree": 1.0.8 - "@types/hast": 3.0.4 + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 hast-util-to-estree: 3.1.3 transitivePeerDependencies: - supports-color rehype-stringify@10.0.1: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 hast-util-to-html: 9.0.5 unified: 11.0.5 rehype@13.0.2: dependencies: - "@types/hast": 3.0.4 + '@types/hast': 3.0.4 rehype-parse: 9.0.1 rehype-stringify: 10.0.1 unified: 11.0.5 remark-directive@3.0.1: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 mdast-util-directive: 3.1.0 micromark-extension-directive: 3.0.2 unified: 11.0.5 @@ -18685,7 +14326,7 @@ snapshots: remark-gfm@4.0.1: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 mdast-util-gfm: 3.1.0 micromark-extension-gfm: 3.0.0 remark-parse: 11.0.0 @@ -18703,7 +14344,7 @@ snapshots: remark-parse@11.0.0: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 mdast-util-from-markdown: 2.0.3 micromark-util-types: 2.0.2 unified: 11.0.5 @@ -18712,8 +14353,8 @@ snapshots: remark-rehype@11.1.2: dependencies: - "@types/hast": 3.0.4 - "@types/mdast": 4.0.4 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 mdast-util-to-hast: 13.2.1 unified: 11.0.5 vfile: 6.0.3 @@ -18727,7 +14368,7 @@ snapshots: remark-stringify@11.0.0: dependencies: - "@types/mdast": 4.0.4 + '@types/mdast': 4.0.4 mdast-util-to-markdown: 2.1.2 unified: 11.0.5 @@ -18767,25 +14408,25 @@ snapshots: retext-latin@4.0.0: dependencies: - "@types/nlcst": 2.0.3 + '@types/nlcst': 2.0.3 parse-latin: 7.0.0 unified: 11.0.5 retext-smartypants@6.2.0: dependencies: - "@types/nlcst": 2.0.3 + '@types/nlcst': 2.0.3 nlcst-to-string: 4.0.0 unist-util-visit: 5.1.0 retext-stringify@4.0.0: dependencies: - "@types/nlcst": 2.0.3 + '@types/nlcst': 2.0.3 nlcst-to-string: 4.0.0 unified: 11.0.5 retext@9.0.0: dependencies: - "@types/nlcst": 2.0.3 + '@types/nlcst': 2.0.3 retext-latin: 4.0.0 retext-stringify: 4.0.0 unified: 11.0.5 @@ -18806,54 +14447,64 @@ snapshots: rolldown@1.0.0-rc.1: dependencies: - "@oxc-project/types": 0.110.0 - "@rolldown/pluginutils": 1.0.0-rc.1 + '@oxc-project/types': 0.110.0 + '@rolldown/pluginutils': 1.0.0-rc.1 optionalDependencies: - "@rolldown/binding-android-arm64": 1.0.0-rc.1 - "@rolldown/binding-darwin-arm64": 1.0.0-rc.1 - "@rolldown/binding-darwin-x64": 1.0.0-rc.1 - "@rolldown/binding-freebsd-x64": 1.0.0-rc.1 - "@rolldown/binding-linux-arm-gnueabihf": 1.0.0-rc.1 - "@rolldown/binding-linux-arm64-gnu": 1.0.0-rc.1 - "@rolldown/binding-linux-arm64-musl": 1.0.0-rc.1 - "@rolldown/binding-linux-x64-gnu": 1.0.0-rc.1 - "@rolldown/binding-linux-x64-musl": 1.0.0-rc.1 - "@rolldown/binding-openharmony-arm64": 1.0.0-rc.1 - "@rolldown/binding-wasm32-wasi": 1.0.0-rc.1 - "@rolldown/binding-win32-arm64-msvc": 1.0.0-rc.1 - "@rolldown/binding-win32-x64-msvc": 1.0.0-rc.1 + '@rolldown/binding-android-arm64': 1.0.0-rc.1 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.1 + '@rolldown/binding-darwin-x64': 1.0.0-rc.1 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.1 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.1 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.1 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.1 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.1 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.1 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.1 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.1 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.1 rollup@4.59.0: dependencies: - "@types/estree": 1.0.8 + '@types/estree': 1.0.8 optionalDependencies: - "@rollup/rollup-android-arm-eabi": 4.59.0 - "@rollup/rollup-android-arm64": 4.59.0 - "@rollup/rollup-darwin-arm64": 4.59.0 - "@rollup/rollup-darwin-x64": 4.59.0 - "@rollup/rollup-freebsd-arm64": 4.59.0 - "@rollup/rollup-freebsd-x64": 4.59.0 - "@rollup/rollup-linux-arm-gnueabihf": 4.59.0 - "@rollup/rollup-linux-arm-musleabihf": 4.59.0 - "@rollup/rollup-linux-arm64-gnu": 4.59.0 - "@rollup/rollup-linux-arm64-musl": 4.59.0 - "@rollup/rollup-linux-loong64-gnu": 4.59.0 - "@rollup/rollup-linux-loong64-musl": 4.59.0 - "@rollup/rollup-linux-ppc64-gnu": 4.59.0 - "@rollup/rollup-linux-ppc64-musl": 4.59.0 - "@rollup/rollup-linux-riscv64-gnu": 4.59.0 - "@rollup/rollup-linux-riscv64-musl": 4.59.0 - "@rollup/rollup-linux-s390x-gnu": 4.59.0 - "@rollup/rollup-linux-x64-gnu": 4.59.0 - "@rollup/rollup-linux-x64-musl": 4.59.0 - "@rollup/rollup-openbsd-x64": 4.59.0 - "@rollup/rollup-openharmony-arm64": 4.59.0 - "@rollup/rollup-win32-arm64-msvc": 4.59.0 - "@rollup/rollup-win32-ia32-msvc": 4.59.0 - "@rollup/rollup-win32-x64-gnu": 4.59.0 - "@rollup/rollup-win32-x64-msvc": 4.59.0 + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.3.0 + transitivePeerDependencies: + - supports-color + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -18876,7 +14527,7 @@ snapshots: schema-utils@4.3.3: dependencies: - "@types/json-schema": 7.0.15 + '@types/json-schema': 7.0.15 ajv: 8.18.0 ajv-formats: 2.1.1(ajv@8.18.0) ajv-keywords: 5.1.0(ajv@8.18.0) @@ -18894,46 +14545,73 @@ snapshots: semver@7.7.4: {} + send@1.2.1: + 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 + transitivePeerDependencies: + - supports-color + serialize-error@12.0.0: dependencies: type-fest: 4.41.0 + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + set-blocking@2.0.0: {} setimmediate@1.0.5: {} setprototypeof@1.1.1: {} + setprototypeof@1.2.0: {} + sharp@0.34.5: dependencies: - "@img/colour": 1.1.0 + '@img/colour': 1.1.0 detect-libc: 2.1.2 semver: 7.7.4 optionalDependencies: - "@img/sharp-darwin-arm64": 0.34.5 - "@img/sharp-darwin-x64": 0.34.5 - "@img/sharp-libvips-darwin-arm64": 1.2.4 - "@img/sharp-libvips-darwin-x64": 1.2.4 - "@img/sharp-libvips-linux-arm": 1.2.4 - "@img/sharp-libvips-linux-arm64": 1.2.4 - "@img/sharp-libvips-linux-ppc64": 1.2.4 - "@img/sharp-libvips-linux-riscv64": 1.2.4 - "@img/sharp-libvips-linux-s390x": 1.2.4 - "@img/sharp-libvips-linux-x64": 1.2.4 - "@img/sharp-libvips-linuxmusl-arm64": 1.2.4 - "@img/sharp-libvips-linuxmusl-x64": 1.2.4 - "@img/sharp-linux-arm": 0.34.5 - "@img/sharp-linux-arm64": 0.34.5 - "@img/sharp-linux-ppc64": 0.34.5 - "@img/sharp-linux-riscv64": 0.34.5 - "@img/sharp-linux-s390x": 0.34.5 - "@img/sharp-linux-x64": 0.34.5 - "@img/sharp-linuxmusl-arm64": 0.34.5 - "@img/sharp-linuxmusl-x64": 0.34.5 - "@img/sharp-wasm32": 0.34.5 - "@img/sharp-win32-arm64": 0.34.5 - "@img/sharp-win32-ia32": 0.34.5 - "@img/sharp-win32-x64": 0.34.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -18946,14 +14624,42 @@ snapshots: shiki@3.23.0: dependencies: - "@shikijs/core": 3.23.0 - "@shikijs/engine-javascript": 3.23.0 - "@shikijs/engine-oniguruma": 3.23.0 - "@shikijs/langs": 3.23.0 - "@shikijs/themes": 3.23.0 - "@shikijs/types": 3.23.0 - "@shikijs/vscode-textmate": 10.0.2 - "@types/hast": 3.0.4 + '@shikijs/core': 3.23.0 + '@shikijs/engine-javascript': 3.23.0 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 siginfo@2.0.0: {} @@ -18979,8 +14685,8 @@ snapshots: sitemap@8.0.3: dependencies: - "@types/node": 17.0.45 - "@types/sax": 1.2.7 + '@types/node': 17.0.45 + '@types/sax': 1.2.7 arg: 5.0.2 sax: 1.5.0 @@ -19048,7 +14754,7 @@ snapshots: starlight-typedoc@0.21.5(@astrojs/starlight@0.37.7(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)))(typedoc-plugin-markdown@4.10.0(typedoc@0.28.17(typescript@5.9.3)))(typedoc@0.28.17(typescript@5.9.3)): dependencies: - "@astrojs/starlight": 0.37.7(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) + '@astrojs/starlight': 0.37.7(astro@5.18.0(@types/node@25.5.0)(@vercel/blob@2.3.0)(jiti@2.6.1)(rollup@4.59.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) github-slugger: 2.0.0 typedoc: 0.28.17(typescript@5.9.3) typedoc-plugin-markdown: 4.10.0(typedoc@0.28.17(typescript@5.9.3)) @@ -19141,7 +14847,7 @@ snapshots: strtok3@10.3.4: dependencies: - "@tokenizer/token": 0.3.0 + '@tokenizer/token': 0.3.0 style-to-js@1.1.21: dependencies: @@ -19156,11 +14862,11 @@ snapshots: client-only: 0.0.1 react: 19.2.4 optionalDependencies: - "@babel/core": 7.29.0 + '@babel/core': 7.29.0 sucrase@3.35.1: dependencies: - "@jridgewell/gen-mapping": 0.3.13 + '@jridgewell/gen-mapping': 0.3.13 commander: 4.1.1 lines-and-columns: 1.2.4 mz: 2.7.0 @@ -19230,7 +14936,7 @@ snapshots: tar@7.5.10: dependencies: - "@isaacs/fs-minipass": 4.0.1 + '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 minipass: 7.1.3 minizlib: 3.1.0 @@ -19238,7 +14944,7 @@ snapshots: tar@7.5.7: dependencies: - "@isaacs/fs-minipass": 4.0.1 + '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 minipass: 7.1.3 minizlib: 3.1.0 @@ -19261,18 +14967,18 @@ snapshots: terser-webpack-plugin@5.4.0(@swc/core@1.15.3)(esbuild@0.27.3)(webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3)): dependencies: - "@jridgewell/trace-mapping": 0.3.31 + '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.46.1 webpack: 5.105.2(@swc/core@1.15.3)(esbuild@0.27.3) optionalDependencies: - "@swc/core": 1.15.3 + '@swc/core': 1.15.3 esbuild: 0.27.3 terser-webpack-plugin@5.4.0(webpack@5.105.2): dependencies: - "@jridgewell/trace-mapping": 0.3.31 + '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.46.1 @@ -19280,7 +14986,7 @@ snapshots: terser@5.46.1: dependencies: - "@jridgewell/source-map": 0.3.11 + '@jridgewell/source-map': 0.3.11 acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -19332,10 +15038,12 @@ snapshots: toidentifier@1.0.0: {} + toidentifier@1.0.1: {} + token-types@6.1.2: dependencies: - "@borewit/text-codec": 0.2.1 - "@tokenizer/token": 0.3.0 + '@borewit/text-codec': 0.2.1 + '@tokenizer/token': 0.3.0 ieee754: 1.2.1 tough-cookie@6.0.0: @@ -19356,7 +15064,7 @@ snapshots: ts-morph@12.0.0: dependencies: - "@ts-morph/common": 0.11.1 + '@ts-morph/common': 0.11.1 code-block-writer: 10.1.1 ts-toolbelt@6.15.5: {} @@ -19387,7 +15095,7 @@ snapshots: tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: - "@swc/core": 1.15.3 + '@swc/core': 1.15.3 postcss: 8.5.8 typescript: 5.9.3 transitivePeerDependencies: @@ -19410,7 +15118,7 @@ snapshots: turndown@7.2.2: dependencies: - "@mixmark-io/domino": 2.2.0 + '@mixmark-io/domino': 2.2.0 type-fest@0.7.1: {} @@ -19422,13 +15130,19 @@ snapshots: dependencies: tagged-tag: 1.0.0 + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + typedoc-plugin-markdown@4.10.0(typedoc@0.28.17(typescript@5.9.3)): dependencies: typedoc: 0.28.17(typescript@5.9.3) typedoc@0.28.17(typescript@5.9.3): dependencies: - "@gerrit0/mini-shiki": 3.23.0 + '@gerrit0/mini-shiki': 3.23.0 lunr: 2.3.9 markdown-it: 14.1.1 minimatch: 9.0.9 @@ -19463,7 +15177,7 @@ snapshots: undici@5.28.4: dependencies: - "@fastify/busboy": 2.1.1 + '@fastify/busboy': 2.1.1 undici@6.23.0: {} @@ -19471,7 +15185,7 @@ snapshots: unified@11.0.5: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 bail: 2.0.2 devlop: 1.1.0 extend: 3.0.2 @@ -19487,47 +15201,47 @@ snapshots: unist-util-find-after@5.0.0: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-is: 6.0.1 unist-util-is@6.0.1: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-modify-children@4.0.0: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 array-iterate: 2.0.1 unist-util-position-from-estree@2.0.0: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-position@5.0.0: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-remove-position@5.0.0: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-visit: 5.1.0 unist-util-stringify-position@4.0.0: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-visit-children@3.0.0: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-visit-parents@6.0.2: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-is: 6.0.1 unist-util-visit@5.1.0: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 @@ -19546,7 +15260,7 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.3 optionalDependencies: - "@vercel/blob": 2.3.0 + '@vercel/blob': 2.3.0 until-async@3.0.2: {} @@ -19570,30 +15284,32 @@ snapshots: uuid@9.0.1: {} + vary@1.1.2: {} + vercel@50.32.5(rollup@4.59.0)(typescript@5.9.3): dependencies: - "@vercel/backends": 0.0.45(rollup@4.59.0)(typescript@5.9.3) - "@vercel/blob": 2.3.0 - "@vercel/build-utils": 13.8.0 - "@vercel/detect-agent": 1.2.1 - "@vercel/elysia": 0.1.48(rollup@4.59.0) - "@vercel/express": 0.1.57(rollup@4.59.0)(typescript@5.9.3) - "@vercel/fastify": 0.1.51(rollup@4.59.0) - "@vercel/fun": 1.3.0 - "@vercel/go": 3.4.5 - "@vercel/h3": 0.1.57(rollup@4.59.0) - "@vercel/hono": 0.2.51(rollup@4.59.0) - "@vercel/hydrogen": 1.3.6 - "@vercel/koa": 0.1.31(rollup@4.59.0) - "@vercel/nestjs": 0.2.52(rollup@4.59.0) - "@vercel/next": 4.16.1(rollup@4.59.0) - "@vercel/node": 5.6.15(rollup@4.59.0) - "@vercel/python": 6.23.0 - "@vercel/redwood": 2.4.10(rollup@4.59.0) - "@vercel/remix-builder": 5.7.0(rollup@4.59.0) - "@vercel/ruby": 2.3.2 - "@vercel/rust": 1.0.5 - "@vercel/static-build": 2.9.0 + '@vercel/backends': 0.0.45(rollup@4.59.0)(typescript@5.9.3) + '@vercel/blob': 2.3.0 + '@vercel/build-utils': 13.8.0 + '@vercel/detect-agent': 1.2.1 + '@vercel/elysia': 0.1.48(rollup@4.59.0) + '@vercel/express': 0.1.57(rollup@4.59.0)(typescript@5.9.3) + '@vercel/fastify': 0.1.51(rollup@4.59.0) + '@vercel/fun': 1.3.0 + '@vercel/go': 3.4.5 + '@vercel/h3': 0.1.57(rollup@4.59.0) + '@vercel/hono': 0.2.51(rollup@4.59.0) + '@vercel/hydrogen': 1.3.6 + '@vercel/koa': 0.1.31(rollup@4.59.0) + '@vercel/nestjs': 0.2.52(rollup@4.59.0) + '@vercel/next': 4.16.1(rollup@4.59.0) + '@vercel/node': 5.6.15(rollup@4.59.0) + '@vercel/python': 6.23.0 + '@vercel/redwood': 2.4.10(rollup@4.59.0) + '@vercel/remix-builder': 5.7.0(rollup@4.59.0) + '@vercel/ruby': 2.3.2 + '@vercel/rust': 1.0.5 + '@vercel/static-build': 2.9.0 chokidar: 4.0.0 esbuild: 0.27.0 form-data: 4.0.5 @@ -19608,17 +15324,17 @@ snapshots: vfile-location@5.0.3: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 vfile: 6.0.3 vfile-message@4.0.3: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 unist-util-stringify-position: 4.0.0 vfile@6.0.3: dependencies: - "@types/unist": 3.0.3 + '@types/unist': 3.0.3 vfile-message: 4.0.3 vite@6.4.1(@types/node@25.5.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): @@ -19630,7 +15346,7 @@ snapshots: rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - "@types/node": 25.5.0 + '@types/node': 25.5.0 fsevents: 2.3.3 jiti: 2.6.1 terser: 5.46.1 @@ -19646,7 +15362,7 @@ snapshots: rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - "@types/node": 25.3.5 + '@types/node': 25.3.5 fsevents: 2.3.3 jiti: 2.6.1 terser: 5.46.1 @@ -19667,13 +15383,13 @@ snapshots: vitest@4.1.0(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.0)(@types/node@25.3.5)(msw@2.12.13(@types/node@25.3.5)(typescript@5.9.3))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: - "@vitest/expect": 4.1.0 - "@vitest/mocker": 4.1.0(msw@2.12.13(@types/node@25.3.5)(typescript@5.9.3))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) - "@vitest/pretty-format": 4.1.0 - "@vitest/runner": 4.1.0 - "@vitest/snapshot": 4.1.0 - "@vitest/spy": 4.1.0 - "@vitest/utils": 4.1.0 + '@vitest/expect': 4.1.0 + '@vitest/mocker': 4.1.0(msw@2.12.13(@types/node@25.3.5)(typescript@5.9.3))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/pretty-format': 4.1.0 + '@vitest/runner': 4.1.0 + '@vitest/snapshot': 4.1.0 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -19688,9 +15404,9 @@ snapshots: vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: - "@edge-runtime/vm": 3.2.0 - "@opentelemetry/api": 1.9.0 - "@types/node": 25.3.5 + '@edge-runtime/vm': 3.2.0 + '@opentelemetry/api': 1.9.0 + '@types/node': 25.3.5 transitivePeerDependencies: - msw @@ -19700,16 +15416,16 @@ snapshots: vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.1.0 optionalDependencies: - "@volar/language-service": 2.4.28 + '@volar/language-service': 2.4.28 volar-service-emmet@0.0.68(@volar/language-service@2.4.28): dependencies: - "@emmetio/css-parser": 0.4.1 - "@emmetio/html-matcher": 1.3.0 - "@vscode/emmet-helper": 2.11.0 + '@emmetio/css-parser': 0.4.1 + '@emmetio/html-matcher': 1.3.0 + '@vscode/emmet-helper': 2.11.0 vscode-uri: 3.1.0 optionalDependencies: - "@volar/language-service": 2.4.28 + '@volar/language-service': 2.4.28 volar-service-html@0.0.68(@volar/language-service@2.4.28): dependencies: @@ -19717,20 +15433,20 @@ snapshots: vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.1.0 optionalDependencies: - "@volar/language-service": 2.4.28 + '@volar/language-service': 2.4.28 volar-service-prettier@0.0.68(@volar/language-service@2.4.28)(prettier@3.8.1): dependencies: vscode-uri: 3.1.0 optionalDependencies: - "@volar/language-service": 2.4.28 + '@volar/language-service': 2.4.28 prettier: 3.8.1 volar-service-typescript-twoslash-queries@0.0.68(@volar/language-service@2.4.28): dependencies: vscode-uri: 3.1.0 optionalDependencies: - "@volar/language-service": 2.4.28 + '@volar/language-service': 2.4.28 volar-service-typescript@0.0.68(@volar/language-service@2.4.28): dependencies: @@ -19741,25 +15457,25 @@ snapshots: vscode-nls: 5.2.0 vscode-uri: 3.1.0 optionalDependencies: - "@volar/language-service": 2.4.28 + '@volar/language-service': 2.4.28 volar-service-yaml@0.0.68(@volar/language-service@2.4.28): dependencies: vscode-uri: 3.1.0 yaml-language-server: 1.19.2 optionalDependencies: - "@volar/language-service": 2.4.28 + '@volar/language-service': 2.4.28 vscode-css-languageservice@6.3.10: dependencies: - "@vscode/l10n": 0.0.18 + '@vscode/l10n': 0.0.18 vscode-languageserver-textdocument: 1.0.12 vscode-languageserver-types: 3.17.5 vscode-uri: 3.1.0 vscode-html-languageservice@5.6.2: dependencies: - "@vscode/l10n": 0.0.18 + '@vscode/l10n': 0.0.18 vscode-languageserver-textdocument: 1.0.12 vscode-languageserver-types: 3.17.5 vscode-uri: 3.1.0 @@ -19812,13 +15528,13 @@ snapshots: webdriver@9.24.0: dependencies: - "@types/node": 20.19.37 - "@types/ws": 8.18.1 - "@wdio/config": 9.24.0 - "@wdio/logger": 9.18.0 - "@wdio/protocols": 9.24.0 - "@wdio/types": 9.24.0 - "@wdio/utils": 9.24.0 + '@types/node': 20.19.37 + '@types/ws': 8.18.1 + '@wdio/config': 9.24.0 + '@wdio/logger': 9.18.0 + '@wdio/protocols': 9.24.0 + '@wdio/types': 9.24.0 + '@wdio/utils': 9.24.0 deepmerge-ts: 7.1.5 https-proxy-agent: 7.0.6 undici: 6.23.0 @@ -19833,14 +15549,14 @@ snapshots: webdriverio@9.24.0: dependencies: - "@types/node": 20.19.37 - "@types/sinonjs__fake-timers": 8.1.5 - "@wdio/config": 9.24.0 - "@wdio/logger": 9.18.0 - "@wdio/protocols": 9.24.0 - "@wdio/repl": 9.16.2 - "@wdio/types": 9.24.0 - "@wdio/utils": 9.24.0 + '@types/node': 20.19.37 + '@types/sinonjs__fake-timers': 8.1.5 + '@wdio/config': 9.24.0 + '@wdio/logger': 9.18.0 + '@wdio/protocols': 9.24.0 + '@wdio/repl': 9.16.2 + '@wdio/types': 9.24.0 + '@wdio/utils': 9.24.0 archiver: 7.0.1 aria-query: 5.3.2 cheerio: 1.2.0 @@ -19872,12 +15588,12 @@ snapshots: webpack@5.105.2: dependencies: - "@types/eslint-scope": 3.7.7 - "@types/estree": 1.0.8 - "@types/json-schema": 7.0.15 - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/wasm-edit": 1.14.1 - "@webassemblyjs/wasm-parser": 1.14.1 + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.16.0 acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 @@ -19898,18 +15614,18 @@ snapshots: watchpack: 2.5.1 webpack-sources: 3.3.4 transitivePeerDependencies: - - "@swc/core" + - '@swc/core' - esbuild - uglify-js webpack@5.105.2(@swc/core@1.15.3)(esbuild@0.27.3): dependencies: - "@types/eslint-scope": 3.7.7 - "@types/estree": 1.0.8 - "@types/json-schema": 7.0.15 - "@webassemblyjs/ast": 1.14.1 - "@webassemblyjs/wasm-edit": 1.14.1 - "@webassemblyjs/wasm-parser": 1.14.1 + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.16.0 acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 @@ -19930,7 +15646,7 @@ snapshots: watchpack: 2.5.1 webpack-sources: 3.3.4 transitivePeerDependencies: - - "@swc/core" + - '@swc/core' - esbuild - uglify-js @@ -20018,7 +15734,7 @@ snapshots: yaml-language-server@1.19.2: dependencies: - "@vscode/l10n": 0.0.18 + '@vscode/l10n': 0.0.18 ajv: 8.18.0 ajv-draft-04: 1.0.0(ajv@8.18.0) lodash: 4.17.21 diff --git a/specs/agent-session-resumability-spec.md b/specs/agent-session-resumability-spec.md index f7684f56..8e02a0d6 100644 --- a/specs/agent-session-resumability-spec.md +++ b/specs/agent-session-resumability-spec.md @@ -3,11 +3,12 @@ ## Metadata - Created: 2026-03-05 -- Last Edited: 2026-03-05 +- Last Edited: 2026-03-13 ## Changelog - 2026-03-05: Initial canonical contract for timeout-safe multi-slice assistant execution with Pi in serverless runtimes. +- 2026-03-13: Added auth-driven resume reason and checkpointed dynamic tool state for MCP-backed turns. ## Status @@ -84,7 +85,9 @@ Each checkpoint must include: - `tool_call_log`: Ordered committed tool calls and results. - `transcript_log`: Ordered committed user/assistant visible messages. - `state`: one of `running|awaiting_resume|completed|failed`. -- `resume_reason`: `timeout|preempted|retry|operator` (when `awaiting_resume`). +- `resume_reason`: `timeout|auth|preempted|retry|operator` (when `awaiting_resume`). +- `loaded_skill_names`: Active skills that must be restored before resume when tool availability depends on loaded skills. +- `active_mcp_providers`: Active plugin MCP providers that must be restored before resume when tools were progressively disclosed. - `deadline_at`: hard deadline for the current slice. - `updated_at` @@ -96,8 +99,9 @@ For slice `n+1`, runtime must: 1. Load latest committed checkpoint for `(conversation_id, session_id)`. 2. Instantiate Pi agent. -3. Call `replaceMessages(checkpoint.pi_messages)`. -4. Call `continue()` to resume generation/tool loop. +3. Restore any checkpointed dynamic tool state required by the wrapper runtime (for example loaded skills and active MCP providers). +4. Call `replaceMessages(checkpoint.pi_messages)`. +5. Call `continue()` to resume generation/tool loop. If the previous slice timed out after producing uncommitted partial assistant text, that text may be regenerated in the next slice. User-visible output must only include committed transcript content. @@ -181,7 +185,8 @@ Required attributes on slice/session events when available: 3. Integration: forced timeout at safe boundary resumes with `replaceMessages` + `continue` and reaches same terminal output. 4. Integration: duplicate continuation message does not produce duplicate tool side effects. 5. Integration: crash-after-commit-before-enqueue is recovered by sweeper. -6. Eval: long-running thread surpassing single serverless timeout completes across multiple slices without user-visible corruption. +6. Integration: auth-driven resume restores the same active skill/MCP tool universe before `continue()`. +7. Eval: long-running thread surpassing single serverless timeout completes across multiple slices without user-visible corruption. ## Related Specs diff --git a/specs/oauth-flows-spec.md b/specs/oauth-flows-spec.md index b130c664..39273e1a 100644 --- a/specs/oauth-flows-spec.md +++ b/specs/oauth-flows-spec.md @@ -3,12 +3,13 @@ ## Metadata - Created: 2026-03-03 -- Last Edited: 2026-03-03 +- Last Edited: 2026-03-13 ## Changelog - 2026-03-03: Standardized metadata headers and reconciled spec references/structure. - 2026-03-09: Added provider-configured token request auth/headers and optional token expiry semantics. +- 2026-03-13: Documented MCP challenge-driven OAuth, MCP callback routing, and auth-driven turn resume. ## Status @@ -27,12 +28,14 @@ Define how Junior handles OAuth-based user authentication for third-party provid ### Components -| Component | Role | -| -------------------------------- | -------------------------------------------------------------------------------------------------------- | -| `jr-rpc oauth-start ` | Generates state, stores in Redis, sends ephemeral link to user | -| `/api/oauth/callback/[provider]` | Exchanges code for tokens, stores server-side, auto-resumes pending request or posts thread confirmation | -| `StateAdapterTokenStore` | Redis-backed `UserTokenStore` for persistent token storage | -| `SentryCredentialBroker` | Issues short-lived credential leases from stored user tokens | +| Component | Role | +| ------------------------------------ | -------------------------------------------------------------------------------------------------------- | +| `jr-rpc oauth-start ` | Generates state, stores in Redis, sends ephemeral link to user | +| `/api/oauth/callback/[provider]` | Exchanges code for tokens, stores server-side, auto-resumes pending request or posts thread confirmation | +| `/api/oauth/callback/mcp/[provider]` | Completes MCP SDK authorization and resumes the paused MCP-backed turn session | +| `StateAdapterTokenStore` | Redis-backed `UserTokenStore` for persistent token storage | +| MCP auth session store | Stores MCP auth session context and SDK-managed OAuth state across the browser redirect | +| `SentryCredentialBroker` | Issues short-lived credential leases from stored user tokens | ### Why authorization code grant @@ -87,6 +90,32 @@ Provider: Redirects to /api/oauth/callback/?code=...&state=... User: Sees "account connected" in browser; if pending, sees resumed response in thread ``` +### MCP challenge-driven authorization + +``` +User: invokes a skill that exposes MCP-backed tools + │ + ▼ +Agent: calls an MCP tool from the same plugin + │ + ├─ MCP server responds with 401 / auth challenge + ├─ MCP OAuth provider persists auth session state + ├─ Runtime privately delivers the authorization link to the requesting user + ├─ Turn checkpoint is written as `awaiting_resume` with `resume_reason=auth` + └─ Current turn exits with retryable resume semantics + │ + ▼ +User: opens the private link, approves, provider redirects to /api/oauth/callback/mcp/?code=...&state=... + │ + ├─ Callback loads MCP auth session by `state` + ├─ SDK completes OAuth via `finishAuth(code)` and persists tokens + ├─ after() resumes the same `(conversation_id, session_id)` turn context + └─ Resumed turn rebuilds loaded skills + active MCP providers, then calls `continue()` + │ + ▼ +User: sees the original thread continue without reissuing the request +``` + ### Credential issuance (per-turn) After a user has connected their account, credential issuance works transparently: @@ -129,6 +158,15 @@ Agent: jr-rpc delete-token sentry - TTL: `expiresAt - now + 24h` buffer when expiry is known, otherwise 365 days - Storage: `StateAdapterTokenStore` wrapping `StateAdapter` (Redis) +### MCP auth sessions and credentials + +- Session key pattern: `junior:mcp_auth_session:` +- Session value: `{ provider, userId, conversationId, sessionId, userMessage, channelId?, threadTs?, toolChannelId?, configuration?, artifactState?, authorizationUrl?, codeVerifier? }` +- Session TTL: 24 hours +- Credentials key pattern: `junior:mcp_auth_credentials::` +- Credentials value: MCP SDK client information, discovery state, and OAuth tokens +- Credentials TTL: 30 days, refreshed on every write + ## Base URL resolution The OAuth `redirect_uri` requires the application's base URL. Resolved in order: @@ -166,6 +204,13 @@ Providers are configured via plugin manifests (`plugin.yaml`) and exposed throug - Scope: `event:read org:read project:read` - Callback: `/api/oauth/callback/sentry` +### MCP-backed plugins + +- Plugin manifests may also declare `mcp.transport: http` and `mcp.url`. +- MCP headers are optional but may not include `Authorization`. +- MCP callback path is `/api/oauth/callback/mcp/`. +- MCP OAuth is challenge-driven by the SDK rather than initiated through `jr-rpc oauth-start`. + ## Security properties - **Authorization links are private**: Authorization URLs contain user-specific CSRF state tokens and must **only** be visible to the requesting user. Delivered via `chat.postEphemeral` in channels or `chat.postMessage` in 1:1 DMs. If private delivery fails, falls back to a DM to the user. Authorization URLs are **never** posted as visible messages in channels or returned to the agent. @@ -175,6 +220,9 @@ Providers are configured via plugin manifests (`plugin.yaml`) and exposed throug - **Server-side secrets**: `client_secret` is read from host env, never exposed to sandbox or agent. - **Token refresh on host**: Broker refreshes expired tokens server-side, agent only receives header transforms. - **Scoped storage**: Tokens keyed by `userId:provider` — users cannot access each other's tokens. +- **MCP links remain private**: MCP authorization URLs are also delivered through the same private Slack delivery rules and are never emitted as visible thread messages. +- **Resumed tool universe is stable**: MCP auth resume restores the checkpointed loaded skills and active MCP providers before continuing the same turn session. +- **Resumed thread context is stable**: MCP auth resume also restores snapshotted configuration, artifact state, and tool-channel targeting before the resumed turn continues. ## Slack chat experience diff --git a/specs/plugin-spec.md b/specs/plugin-spec.md index 7dab4937..75db4724 100644 --- a/specs/plugin-spec.md +++ b/specs/plugin-spec.md @@ -3,7 +3,7 @@ ## Metadata - Created: 2026-03-01 -- Last Edited: 2026-03-06 +- Last Edited: 2026-03-13 ## Changelog @@ -12,6 +12,7 @@ - 2026-03-06: Added runtime dependency declarations and linked sandbox snapshot lifecycle contract. - 2026-03-06: Made plugin credentials/capabilities/config-keys optional to support bundle-only plugins. - 2026-03-09: Added OAuth request overrides, optional OAuth scope, and plugin-level API headers. +- 2026-03-13: Implemented HTTP MCP manifests, same-plugin progressive tool activation, and dedicated MCP OAuth callbacks. ## Status @@ -44,7 +45,8 @@ Define a plugin model where provider integrations are self-contained directories 3. The registry registers capabilities, config keys, OAuth config, and skill roots from each manifest. 4. Credential brokers are created on demand only for plugins that declare credentials (`oauth-bearer` or `github-app` type). 5. Skills in `plugins//skills/` are auto-discovered alongside existing skill roots. -6. Core infrastructure (agent loop, sandbox, jr-rpc, Slack tools, web tools) stays unchanged. +6. Plugin-declared MCP tools are host-managed and activated only after a skill from the same plugin is loaded for the turn. +7. Core infrastructure (agent loop, sandbox, jr-rpc, Slack tools, web tools) stays unchanged outside the MCP activation/resume wiring. ## Plugin directory structure @@ -118,10 +120,10 @@ runtime-postinstall: # optional — post-install commands executed before snapsh args: ["install"] mcp: # optional — MCP server config for tool sources - command: npx - args: ["-y", "@sentry/mcp-server"] - env: - SENTRY_AUTH_TOKEN: "${SENTRY_AUTH_TOKEN}" + transport: http + url: https://mcp.example.com/mcp + headers: + X-Workspace: acme ``` ## Plugin manifest contract @@ -170,7 +172,10 @@ mcp: # optional — MCP server config for tool sources | `runtime-postinstall[].cmd` | `string` | Non-empty command name. | | `runtime-postinstall[].args` | `string[]` | Optional command arguments. | | `runtime-postinstall[].sudo` | `boolean` | Optional sudo flag for commands requiring elevated privileges. | -| `mcp` | `object` | MCP server configuration for external tool sources. Reserved — not yet parsed by the registry. | +| `mcp` | `object` | Optional MCP server configuration for host-managed tool discovery. | +| `mcp.transport` | `string` | Must be `"http"` in v1. Stdio/command transports are not supported. | +| `mcp.url` | `string` | HTTPS endpoint for the MCP server. | +| `mcp.headers` | `Record` | Optional static non-Authorization headers sent with MCP HTTP requests. `Authorization` is reserved for runtime-managed auth. | Snapshot build/reuse and invalidation behavior for `runtime-dependencies` is defined in [Sandbox Snapshots Spec](./sandbox-snapshots-spec.md). @@ -245,6 +250,15 @@ isPluginConfigKey(key): boolean createPluginBroker(provider, deps: PluginBrokerDeps): CredentialBroker ``` +### MCP tool activation + +- MCP tools are not sandbox dependencies and are not registered globally at startup. +- The runtime activates a plugin's MCP tools only after a skill owned by that plugin is loaded in the current turn. +- Explicit `/skill` invocations preload the skill first, so same-plugin MCP tools are available before the first model step. +- Mid-turn `loadSkill` updates the active Pi tool list for subsequent agent steps. +- MCP tool names are exposed to Pi as `mcp____`. +- MCP authorization uses a dedicated callback path at `/api/oauth/callback/mcp/` and resumes the paused turn session after the user authorizes. + ## Capability and credential integration ### Catalog integration From 14dfb626976ad7a841243d830622b6851c74eae7 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Tue, 17 Mar 2026 15:41:04 -0700 Subject: [PATCH 02/28] fix(mcp): Preserve OAuth resume state Preserve the stored authorization URL when clearing only the code verifier so paused MCP authorization can resume without losing its redirect target. Render the MCP callback page through React's escaping path and add focused regressions for callback HTML escaping and auth-session invalidation behavior. Co-Authored-By: GPT-5 Codex --- .../junior/src/chat/mcp/oauth-provider.ts | 2 +- .../junior/src/handlers/mcp-oauth-callback.ts | 60 +++++++++--- .../junior/tests/mcp-oauth-callback.test.ts | 32 ++++++ .../tests/unit/mcp/oauth-provider.test.ts | 98 +++++++++++++++++++ 4 files changed, 176 insertions(+), 16 deletions(-) create mode 100644 packages/junior/tests/unit/mcp/oauth-provider.test.ts diff --git a/packages/junior/src/chat/mcp/oauth-provider.ts b/packages/junior/src/chat/mcp/oauth-provider.ts index 67f334ea..b00e63de 100644 --- a/packages/junior/src/chat/mcp/oauth-provider.ts +++ b/packages/junior/src/chat/mcp/oauth-provider.ts @@ -151,7 +151,7 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { if (scope === "verifier" || scope === "all") { await patchMcpAuthSession(this.authSessionId, { codeVerifier: undefined, - authorizationUrl: scope === "all" ? undefined : undefined, + ...(scope === "all" ? { authorizationUrl: undefined } : {}), }); } } diff --git a/packages/junior/src/handlers/mcp-oauth-callback.ts b/packages/junior/src/handlers/mcp-oauth-callback.ts index 0fa35ad3..47a0a701 100644 --- a/packages/junior/src/handlers/mcp-oauth-callback.ts +++ b/packages/junior/src/handlers/mcp-oauth-callback.ts @@ -1,6 +1,8 @@ import { Buffer } from "node:buffer"; import { after } from "next/server"; import { ThreadImpl, type FileUpload } from "chat"; +import { createElement } from "react"; +import { renderToStaticMarkup } from "react-dom/server"; import { botConfig } from "@/chat/config"; import { coerceThreadConversationState } from "@/chat/conversation-state"; import type { ChannelConfigurationService } from "@/chat/configuration/types"; @@ -28,27 +30,55 @@ import { coerceThreadArtifactsState } from "@/chat/slack-actions/types"; import { truncateStatusText } from "@/chat/status-format"; import { markTurnCompleted, markTurnFailed } from "@/chat/turn/persist"; import { resolveReplyDelivery } from "@/chat/turn/execute"; -import { escapeXml } from "@/chat/xml"; function htmlResponse( title: string, message: string, status: number, ): Response { - const safeTitle = escapeXml(title); - const safeMessage = escapeXml(message); - const html = ` - -${safeTitle} - -
-

${safeTitle}

-

${safeMessage}

-

You can close this tab and return to Slack.

-
- -`; - return new Response(html, { + const html = renderToStaticMarkup( + createElement( + "html", + null, + createElement("head", null, createElement("title", null, title)), + createElement( + "body", + { + style: { + fontFamily: "system-ui, sans-serif", + display: "flex", + justifyContent: "center", + alignItems: "center", + minHeight: "100vh", + margin: 0, + }, + }, + createElement( + "div", + { + style: { + textAlign: "center", + maxWidth: 480, + }, + }, + createElement("h1", null, title), + createElement("p", null, message), + createElement( + "p", + { + style: { + marginTop: "2rem", + color: "#666", + fontSize: "0.9em", + }, + }, + "You can close this tab and return to Slack.", + ), + ), + ), + ), + ); + return new Response(`${html}`, { status, headers: { "Content-Type": "text/html; charset=utf-8" }, }); diff --git a/packages/junior/tests/mcp-oauth-callback.test.ts b/packages/junior/tests/mcp-oauth-callback.test.ts index aadef39f..17964600 100644 --- a/packages/junior/tests/mcp-oauth-callback.test.ts +++ b/packages/junior/tests/mcp-oauth-callback.test.ts @@ -236,6 +236,38 @@ describe("mcp oauth callback handler", () => { expect(finalizeMcpAuthorizationMock).not.toHaveBeenCalled(); }); + it("escapes querystring error text in the HTML response", async () => { + const response = await GET( + makeRequest( + "https://example.com/api/oauth/callback/mcp/demo?state=state-123&error=%3Cscript%3Ealert(1)%3C%2Fscript%3E", + ), + makeContext("demo"), + ); + + expect(response.status).toBe(400); + const body = await response.text(); + expect(body).toContain("<script>alert(1)</script>"); + expect(body).not.toContain(""); + }); + + it("escapes callback exception text in the HTML response", async () => { + finalizeMcpAuthorizationMock.mockRejectedValueOnce( + new Error(""), + ); + + const response = await GET( + makeRequest( + "https://example.com/api/oauth/callback/mcp/demo?code=auth-code&state=state-123", + ), + makeContext("demo"), + ); + + expect(response.status).toBe(500); + const body = await response.text(); + expect(body).toContain("<img src=x onerror=alert(1)>"); + expect(body).not.toContain(""); + }); + it("finalizes MCP auth and resumes the paused request in the stored Slack thread", async () => { const response = await GET( makeRequest( diff --git a/packages/junior/tests/unit/mcp/oauth-provider.test.ts b/packages/junior/tests/unit/mcp/oauth-provider.test.ts new file mode 100644 index 00000000..6ed1bed7 --- /dev/null +++ b/packages/junior/tests/unit/mcp/oauth-provider.test.ts @@ -0,0 +1,98 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const { + getMcpAuthSessionMock, + getMcpStoredOAuthCredentialsMock, + patchMcpAuthSessionMock, + putMcpStoredOAuthCredentialsMock, +} = vi.hoisted(() => ({ + getMcpAuthSessionMock: vi.fn(), + getMcpStoredOAuthCredentialsMock: vi.fn(), + patchMcpAuthSessionMock: vi.fn(), + putMcpStoredOAuthCredentialsMock: vi.fn(), +})); + +vi.mock("@/chat/mcp/auth-store", () => ({ + getMcpAuthSession: getMcpAuthSessionMock, + getMcpStoredOAuthCredentials: getMcpStoredOAuthCredentialsMock, + patchMcpAuthSession: patchMcpAuthSessionMock, + putMcpStoredOAuthCredentials: putMcpStoredOAuthCredentialsMock, +})); + +import { StateBackedMcpOAuthClientProvider } from "@/chat/mcp/oauth-provider"; + +describe("StateBackedMcpOAuthClientProvider.invalidateCredentials", () => { + beforeEach(() => { + getMcpAuthSessionMock.mockReset(); + getMcpStoredOAuthCredentialsMock.mockReset(); + patchMcpAuthSessionMock.mockReset(); + putMcpStoredOAuthCredentialsMock.mockReset(); + + getMcpAuthSessionMock.mockResolvedValue({ + authSessionId: "auth-session-1", + provider: "demo", + userId: "U123", + conversationId: "conversation-1", + sessionId: "turn-1", + userMessage: "/demo", + authorizationUrl: "https://example.com/oauth/start", + codeVerifier: "code-verifier", + createdAtMs: 1, + updatedAtMs: 1, + }); + getMcpStoredOAuthCredentialsMock.mockResolvedValue({ + clientInformation: { client_id: "client-1" }, + discoveryState: { authorization_server: "https://example.com" }, + tokens: { + access_token: "access", + token_type: "Bearer", + }, + }); + putMcpStoredOAuthCredentialsMock.mockResolvedValue(undefined); + patchMcpAuthSessionMock.mockResolvedValue(undefined); + }); + + it("preserves the authorization URL when only clearing the verifier", async () => { + const provider = new StateBackedMcpOAuthClientProvider( + "auth-session-1", + "https://junior.example.com/callback", + ); + + await provider.invalidateCredentials("verifier"); + + expect(putMcpStoredOAuthCredentialsMock).toHaveBeenCalledWith( + "U123", + "demo", + { + clientInformation: { client_id: "client-1" }, + discoveryState: { authorization_server: "https://example.com" }, + tokens: { + access_token: "access", + token_type: "Bearer", + }, + }, + ); + expect(patchMcpAuthSessionMock).toHaveBeenCalledWith("auth-session-1", { + codeVerifier: undefined, + }); + }); + + it("clears the authorization URL when invalidating all credentials", async () => { + const provider = new StateBackedMcpOAuthClientProvider( + "auth-session-1", + "https://junior.example.com/callback", + ); + + await provider.invalidateCredentials("all"); + + expect(putMcpStoredOAuthCredentialsMock).toHaveBeenCalledWith( + "U123", + "demo", + {}, + ); + expect(patchMcpAuthSessionMock).toHaveBeenCalledWith("auth-session-1", { + codeVerifier: undefined, + authorizationUrl: undefined, + }); + }); +}); From 071d5187d5f8f1d687298117d1653414c6311168 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Tue, 17 Mar 2026 15:45:41 -0700 Subject: [PATCH 03/28] fix(security): Remove regex backtracking hotspots Replace the router slash-trimming regex with deterministic string trimming and redact PEM private key blocks without a broad backtracking pattern. Add focused regression coverage for both behaviors so the CodeQL findings stay fixed on future refactors. Co-Authored-By: GPT-5 Codex --- packages/junior/src/chat/logging.ts | 297 +++++++++++++----- packages/junior/src/handlers/router.ts | 16 +- packages/junior/tests/handlers-router.test.ts | 9 + .../junior/tests/unit/logging-context.test.ts | 80 ++++- 4 files changed, 305 insertions(+), 97 deletions(-) diff --git a/packages/junior/src/chat/logging.ts b/packages/junior/src/chat/logging.ts index d55faf8f..4eb13ecb 100644 --- a/packages/junior/src/chat/logging.ts +++ b/packages/junior/src/chat/logging.ts @@ -51,7 +51,6 @@ const SECRETS_RE = [ /\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g, /\bBearer\s+([A-Za-z0-9._\-+=]{20,})\b/gi, /\b[A-Z0-9_]+(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD)\s*[=:]\s*([^\s"']{8,})/gi, - /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g ]; const LEGACY_KEY_MAP: Record = { @@ -80,7 +79,7 @@ const LEGACY_KEY_MAP: Record = { responseMessages: "app.ai.response_messages", stepDiagnostics: "app.ai.step_diagnostics", inferredSkill: "app.skill.name", - inferredScore: "app.skill.score" + inferredScore: "app.skill.score", }; const contextStorage = new AsyncLocalStorage(); @@ -93,7 +92,7 @@ const ANSI = { green: "\u001b[32m", blue: "\u001b[34m", cyan: "\u001b[36m", - gray: "\u001b[90m" + gray: "\u001b[90m", } as const; const CONSOLE_PRIORITY_KEYS = [ "app.conversation.id", @@ -108,10 +107,10 @@ const CONSOLE_PRIORITY_KEYS = [ "app.run.id", "app.message.kind", "app.trace_id", - "app.span_id" + "app.span_id", ] as const; const CONSOLE_PRIORITY_INDEX: Map = new Map( - CONSOLE_PRIORITY_KEYS.map((key, index) => [key, index]) + CONSOLE_PRIORITY_KEYS.map((key, index) => [key, index]), ); function getSentryEnvironment(): string { @@ -138,14 +137,53 @@ function shouldEmitConsole(level: LogLevel): boolean { return getSentryEnvironment() !== "production"; } +function redactPrivateKeyBlocks(input: string): string { + const beginPrefix = "-----BEGIN "; + const footerMarker = "-----"; + let cursor = 0; + let output = ""; + + while (cursor < input.length) { + const begin = input.indexOf(beginPrefix, cursor); + if (begin === -1) { + output += input.slice(cursor); + break; + } + + const labelStart = begin + beginPrefix.length; + const labelEnd = input.indexOf(footerMarker, labelStart); + if (labelEnd === -1) { + output += input.slice(cursor); + break; + } + + const label = input.slice(labelStart, labelEnd); + if (!label.endsWith("PRIVATE KEY")) { + output += input.slice(cursor, labelEnd + footerMarker.length); + cursor = labelEnd + footerMarker.length; + continue; + } + + const header = input.slice(begin, labelEnd + footerMarker.length); + const footer = `-----END ${label}-----`; + const footerStart = input.indexOf(footer, labelEnd + footerMarker.length); + if (footerStart === -1) { + output += input.slice(cursor); + break; + } + + output += input.slice(cursor, begin); + output += `${header}\n...redacted...\n${footer}`; + cursor = footerStart + footer.length; + } + + return output; +} + function redactSecrets(input: string): string { - let out = input; + let out = redactPrivateKeyBlocks(input); for (const pattern of SECRETS_RE) { out = out.replace(pattern, (full, token: string) => { - if (full.includes("PRIVATE KEY")) { - const lines = full.trim().split("\n"); - return lines.length >= 2 ? `${lines[0]}\n...redacted...\n${lines[lines.length - 1]}` : "***PRIVATE KEY***"; - } if (typeof token !== "string") { return "***"; } @@ -196,7 +234,9 @@ function sanitizePrimitive(value: unknown): Primitive | undefined { const trimmed = value.trim(); if (!trimmed) return undefined; const redacted = redactSecrets(trimmed); - return redacted.length > MAX_STRING_VALUE ? `${redacted.slice(0, MAX_STRING_VALUE)}...` : redacted; + return redacted.length > MAX_STRING_VALUE + ? `${redacted.slice(0, MAX_STRING_VALUE)}...` + : redacted; } if (typeof value === "number") { return Number.isFinite(value) ? value : undefined; @@ -210,7 +250,9 @@ function sanitizePrimitive(value: unknown): Primitive | undefined { const json = JSON.stringify(value); if (!json) return undefined; const redacted = redactSecrets(json); - return redacted.length > MAX_STRING_VALUE ? `${redacted.slice(0, MAX_STRING_VALUE)}...` : redacted; + return redacted.length > MAX_STRING_VALUE + ? `${redacted.slice(0, MAX_STRING_VALUE)}...` + : redacted; } catch { return undefined; } @@ -234,7 +276,8 @@ function contextToAttributes(context: LogContext): LogAttributes { "app.agent.id": context.agentId, "app.platform": context.platform, "app.request.id": context.requestId, - "messaging.system": context.platform === "slack" ? "slack" : context.platform, + "messaging.system": + context.platform === "slack" ? "slack" : context.platform, "messaging.message.conversation_id": context.slackThreadId, "messaging.destination.name": context.slackChannelId, "enduser.id": context.slackUserId, @@ -246,7 +289,7 @@ function contextToAttributes(context: LogContext): LogAttributes { "http.request.method": context.httpMethod, "url.path": context.httpPath, "url.full": context.urlFull, - "user_agent.original": context.userAgent + "user_agent.original": context.userAgent, }; const normalized: LogAttributes = {}; @@ -259,7 +302,10 @@ function contextToAttributes(context: LogContext): LogAttributes { function getTraceCorrelationAttributes(): LogAttributes { const sentry = Sentry as unknown as SentryLike; - if (typeof sentry.getActiveSpan !== "function" || typeof sentry.spanToJSON !== "function") { + if ( + typeof sentry.getActiveSpan !== "function" || + typeof sentry.spanToJSON !== "function" + ) { return {}; } @@ -276,7 +322,9 @@ function getTraceCorrelationAttributes(): LogAttributes { } } -function mergeAttributes(...maps: Array | undefined>): LogAttributes { +function mergeAttributes( + ...maps: Array | undefined> +): LogAttributes { const merged: LogAttributes = {}; for (const map of maps) { if (!map) continue; @@ -291,7 +339,11 @@ function mergeAttributes(...maps: Array | undefined>): L return merged; } -function emitSentry(level: LogLevel, body: string, attributes: LogAttributes): void { +function emitSentry( + level: LogLevel, + body: string, + attributes: LogAttributes, +): void { if (shouldSuppressInfoLog(level)) { return; } @@ -303,13 +355,25 @@ function emitSentry(level: LogLevel, body: string, attributes: LogAttributes): v return; } - const sentryWithScope = (sentry as unknown as { withScope?: (callback: (scope: Sentry.Scope) => void) => void }).withScope; - const sentryCaptureMessage = (sentry as unknown as { - captureMessage?: (message: string, level?: "debug" | "info" | "warning" | "error") => void; - }).captureMessage; + const sentryWithScope = ( + sentry as unknown as { + withScope?: (callback: (scope: Sentry.Scope) => void) => void; + } + ).withScope; + const sentryCaptureMessage = ( + sentry as unknown as { + captureMessage?: ( + message: string, + level?: "debug" | "info" | "warning" | "error", + ) => void; + } + ).captureMessage; const sentryLevel = level === "warn" ? "warning" : level; - if (typeof sentryWithScope === "function" && typeof sentryCaptureMessage === "function") { + if ( + typeof sentryWithScope === "function" && + typeof sentryCaptureMessage === "function" + ) { sentryWithScope((scope) => { for (const [key, value] of Object.entries(attributes)) { scope.setExtra(key, value); @@ -358,25 +422,33 @@ function formatConsoleValue(value: AttributeValue): string { return quoteConsoleValue(value); } -function formatConsoleLine(level: LogLevel, body: string, attributes: LogAttributes): string { +function formatConsoleLine( + level: LogLevel, + body: string, + attributes: LogAttributes, +): string { const timestamp = new Date().toISOString(); - const useColor = process.env.NODE_ENV === "development" && Boolean(process.stdout?.isTTY); + const useColor = + process.env.NODE_ENV === "development" && Boolean(process.stdout?.isTTY); const levelColor = consoleLevelColor(level); - const colorize = (text: string, color: string) => (useColor ? `${color}${text}${ANSI.reset}` : text); + const colorize = (text: string, color: string) => + useColor ? `${color}${text}${ANSI.reset}` : text; const parts = [ - `${colorize(timestamp, ANSI.gray)} ${colorize(formatConsoleLevel(level), levelColor)} ${body}` + `${colorize(timestamp, ANSI.gray)} ${colorize(formatConsoleLevel(level), levelColor)} ${body}`, ]; - const sortedAttributes = Object.entries(attributes).sort(([left], [right]) => { - const leftRank = CONSOLE_PRIORITY_INDEX.get(left); - const rightRank = CONSOLE_PRIORITY_INDEX.get(right); - if (leftRank !== undefined || rightRank !== undefined) { - if (leftRank === undefined) return 1; - if (rightRank === undefined) return -1; - return leftRank - rightRank; - } - return left.localeCompare(right); - }); + const sortedAttributes = Object.entries(attributes).sort( + ([left], [right]) => { + const leftRank = CONSOLE_PRIORITY_INDEX.get(left); + const rightRank = CONSOLE_PRIORITY_INDEX.get(right); + if (leftRank !== undefined || rightRank !== undefined) { + if (leftRank === undefined) return 1; + if (rightRank === undefined) return -1; + return leftRank - rightRank; + } + return left.localeCompare(right); + }, + ); for (const [key, value] of sortedAttributes) { const rendered = `${colorize(key, ANSI.cyan)}=${colorize(formatConsoleValue(value), ANSI.faint)}`; parts.push(rendered); @@ -384,7 +456,12 @@ function formatConsoleLine(level: LogLevel, body: string, attributes: LogAttribu return parts.join(" "); } -function emitConsole(level: LogLevel, _eventName: string, body: string, attributes: LogAttributes): void { +function emitConsole( + level: LogLevel, + _eventName: string, + body: string, + attributes: LogAttributes, +): void { if (!shouldEmitConsole(level)) { return; } @@ -405,19 +482,20 @@ function emitConsole(level: LogLevel, _eventName: string, body: string, attribut console.debug(line); } -function emit(level: LogLevel, eventName: string, attrs: Record = {}, body?: string): void { +function emit( + level: LogLevel, + eventName: string, + attrs: Record = {}, + body?: string, +): void { const contextAttributes = contextStorage.getStore() ?? {}; const traceAttributes = getTraceCorrelationAttributes(); const normalizedEventName = toSnakeCase(eventName); const message = body ? redactSecrets(body) : normalizedEventName; - const attributes = mergeAttributes( - contextAttributes, - traceAttributes, - { - "event.name": normalizedEventName, - ...attrs - } - ); + const attributes = mergeAttributes(contextAttributes, traceAttributes, { + "event.name": normalizedEventName, + ...attrs, + }); for (const sink of logRecordSinks) { try { @@ -425,7 +503,7 @@ function emit(level: LogLevel, eventName: string, attrs: Record level, eventName: normalizedEventName, body: message, - attributes + attributes, }); } catch { // Test-only sink failures must not break runtime logging. @@ -437,40 +515,76 @@ function emit(level: LogLevel, eventName: string, attrs: Record } export const log = { - debug(eventName: string, attrs: Record = {}, body?: string): void { + debug( + eventName: string, + attrs: Record = {}, + body?: string, + ): void { emit("debug", eventName, attrs, body); }, - info(eventName: string, attrs: Record = {}, body?: string): void { + info( + eventName: string, + attrs: Record = {}, + body?: string, + ): void { emit("info", eventName, attrs, body); }, - warn(eventName: string, attrs: Record = {}, body?: string): void { + warn( + eventName: string, + attrs: Record = {}, + body?: string, + ): void { emit("warn", eventName, attrs, body); }, - error(eventName: string, attrs: Record = {}, body?: string): void { + error( + eventName: string, + attrs: Record = {}, + body?: string, + ): void { emit("error", eventName, attrs, body); }, - exception(eventName: string, error: unknown, attrs: Record = {}, body?: string): string | undefined { - const normalizedError = error instanceof Error ? error : new Error(String(error)); - emit("error", eventName, { - ...attrs, - "error.type": normalizedError.name, - "error.message": normalizedError.message, - "exception.type": normalizedError.name, - "exception.message": normalizedError.message, - "exception.stacktrace": normalizedError.stack - }, body ?? normalizedError.message); + exception( + eventName: string, + error: unknown, + attrs: Record = {}, + body?: string, + ): string | undefined { + const normalizedError = + error instanceof Error ? error : new Error(String(error)); + emit( + "error", + eventName, + { + ...attrs, + "error.type": normalizedError.name, + "error.message": normalizedError.message, + "exception.type": normalizedError.name, + "exception.message": normalizedError.message, + "exception.stacktrace": normalizedError.stack, + }, + body ?? normalizedError.message, + ); let eventId: string | undefined; - const sentryWithScope = (Sentry as unknown as { - withScope?: (callback: (scope: Sentry.Scope) => void) => void; - }).withScope; - const sentryCaptureException = (Sentry as unknown as { - captureException?: (error: unknown) => string | undefined; - }).captureException; + const sentryWithScope = ( + Sentry as unknown as { + withScope?: (callback: (scope: Sentry.Scope) => void) => void; + } + ).withScope; + const sentryCaptureException = ( + Sentry as unknown as { + captureException?: (error: unknown) => string | undefined; + } + ).captureException; - if (typeof sentryWithScope === "function" && typeof sentryCaptureException === "function") { + if ( + typeof sentryWithScope === "function" && + typeof sentryCaptureException === "function" + ) { sentryWithScope((scope) => { - for (const [key, value] of Object.entries(mergeAttributes(contextStorage.getStore(), attrs))) { + for (const [key, value] of Object.entries( + mergeAttributes(contextStorage.getStore(), attrs), + )) { scope.setExtra(key, value); } eventId = sentryCaptureException(normalizedError); @@ -482,16 +596,25 @@ export const log = { eventId = sentryCaptureException(normalizedError); } return eventId; - } + }, }; -export function withLogContext(context: LogContext, callback: () => Promise): Promise { - const next = mergeAttributes(contextStorage.getStore(), contextToAttributes(context)); +export function withLogContext( + context: LogContext, + callback: () => Promise, +): Promise { + const next = mergeAttributes( + contextStorage.getStore(), + contextToAttributes(context), + ); return contextStorage.run(next, callback); } export function setLogContext(context: LogContext): void { - const merged = mergeAttributes(contextStorage.getStore(), contextToAttributes(context)); + const merged = mergeAttributes( + contextStorage.getStore(), + contextToAttributes(context), + ); contextStorage.enterWith(merged); } @@ -499,29 +622,37 @@ export function getLogContextAttributes(): LogAttributes { return contextStorage.getStore() ?? {}; } -export function registerLogRecordSink(sink: (record: EmittedLogRecord) => void): () => void { +export function registerLogRecordSink( + sink: (record: EmittedLogRecord) => void, +): () => void { logRecordSinks.add(sink); return () => { logRecordSinks.delete(sink); }; } -export function createLogContextFromRequest(request: Request, context: Partial = {}): LogContext { +export function createLogContextFromRequest( + request: Request, + context: Partial = {}, +): LogContext { const url = new URL(request.url); return { ...context, - requestId: context.requestId ?? request.headers.get("x-request-id") ?? undefined, + requestId: + context.requestId ?? request.headers.get("x-request-id") ?? undefined, httpMethod: request.method, httpPath: url.pathname, urlFull: url.toString(), - userAgent: request.headers.get("user-agent") ?? undefined + userAgent: request.headers.get("user-agent") ?? undefined, }; } export function toSpanAttributes(context: LogContext): Record { const attrs = contextToAttributes(context); return Object.fromEntries( - Object.entries(attrs).filter(([, value]) => typeof value === "string" && value.length > 0) + Object.entries(attrs).filter( + ([, value]) => typeof value === "string" && value.length > 0, + ), ) as Record; } @@ -533,11 +664,17 @@ export function setSentryTagsFromContext(context: LogContext): void { } } if (context.slackUserId) { - Sentry.setUser({ id: context.slackUserId, username: context.slackUserName }); + Sentry.setUser({ + id: context.slackUserId, + username: context.slackUserName, + }); } } -export function setSentryScopeContext(scope: Sentry.Scope, context: LogContext): void { +export function setSentryScopeContext( + scope: Sentry.Scope, + context: LogContext, +): void { const attrs = contextToAttributes(context); for (const [key, value] of Object.entries(attrs)) { if (typeof value === "string" && value.length > 0) { diff --git a/packages/junior/src/handlers/router.ts b/packages/junior/src/handlers/router.ts index 5929d5b7..c13c4e27 100644 --- a/packages/junior/src/handlers/router.ts +++ b/packages/junior/src/handlers/router.ts @@ -13,8 +13,22 @@ type RouteContext = { * Keep this router thin and explicit so app code can export one handler module while * runtime internals continue to evolve behind it. */ +function trimEdgeSlashes(value: string): string { + let start = 0; + let end = value.length; + + while (start < end && value[start] === "/") { + start += 1; + } + while (end > start && value[end - 1] === "/") { + end -= 1; + } + + return value.slice(start, end); +} + function normalizeRoutePath(pathParts: string[]): string { - const route = pathParts.join("/").replace(/^\/+|\/+$/g, ""); + const route = trimEdgeSlashes(pathParts.join("/")); return route.startsWith("api/") ? route.slice("api/".length) : route; } diff --git a/packages/junior/tests/handlers-router.test.ts b/packages/junior/tests/handlers-router.test.ts index b421aab0..20a7a5b9 100644 --- a/packages/junior/tests/handlers-router.test.ts +++ b/packages/junior/tests/handlers-router.test.ts @@ -93,6 +93,15 @@ describe("handlers router", () => { expect(healthGetMock).toHaveBeenCalledTimes(1); }); + it("normalizes edge slashes before routing catch-all requests", async () => { + const response = await GET( + new Request("http://localhost/api/health"), + routeContext(["", "api", "health", ""]), + ); + expect(response.status).toBe(200); + expect(healthGetMock).toHaveBeenCalledTimes(1); + }); + it("routes catch-all webhook requests", async () => { const response = await POST( new Request("http://localhost/api/webhooks/slack", { method: "POST" }), diff --git a/packages/junior/tests/unit/logging-context.test.ts b/packages/junior/tests/unit/logging-context.test.ts index 9543c74f..ba81c6d1 100644 --- a/packages/junior/tests/unit/logging-context.test.ts +++ b/packages/junior/tests/unit/logging-context.test.ts @@ -5,14 +5,18 @@ vi.mock("@sentry/nextjs", () => ({ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), - error: vi.fn() + error: vi.fn(), }, - withScope: (callback: (scope: Record void>) => void) => { + withScope: ( + callback: ( + scope: Record void>, + ) => void, + ) => { callback({ setExtra: () => undefined, setTag: () => undefined, setUser: () => undefined, - setContext: () => undefined + setContext: () => undefined, }); }, captureMessage: vi.fn(), @@ -21,7 +25,9 @@ vi.mock("@sentry/nextjs", () => ({ spanToJSON: vi.fn(() => ({})), setTag: vi.fn(), setUser: vi.fn(), - startSpan: vi.fn(async (_args, callback: () => Promise) => await callback()) + startSpan: vi.fn( + async (_args, callback: () => Promise) => await callback(), + ), })); describe("logging context ids", () => { @@ -30,12 +36,16 @@ describe("logging context ids", () => { }); it("attaches conversation, turn, and agent ids to emitted records", async () => { - const { log, registerLogRecordSink, withLogContext } = await import("@/chat/logging"); - const records: Array<{ eventName: string; attributes: Record }> = []; + const { log, registerLogRecordSink, withLogContext } = + await import("@/chat/logging"); + const records: Array<{ + eventName: string; + attributes: Record; + }> = []; const unregister = registerLogRecordSink((record) => { records.push({ eventName: record.eventName, - attributes: record.attributes + attributes: record.attributes, }); }); @@ -44,11 +54,15 @@ describe("logging context ids", () => { { conversationId: "conversation-1", turnId: "turn-1", - agentId: "turn-1" + agentId: "turn-1", }, async () => { - log.info("agent_turn_started", { "app.message.kind": "user_inbound" }, "Agent turn started"); - } + log.info( + "agent_turn_started", + { "app.message.kind": "user_inbound" }, + "Agent turn started", + ); + }, ); } finally { unregister(); @@ -61,26 +75,32 @@ describe("logging context ids", () => { "app.conversation.id": "conversation-1", "app.turn.id": "turn-1", "app.agent.id": "turn-1", - "event.name": "agent_turn_started" - }) + "event.name": "agent_turn_started", + }), ); }); it("prioritizes correlation ids early in dev console output", async () => { vi.stubEnv("NODE_ENV", "development"); const { log, withLogContext } = await import("@/chat/logging"); - const infoSpy = vi.spyOn(console, "info").mockImplementation(() => undefined); + const infoSpy = vi + .spyOn(console, "info") + .mockImplementation(() => undefined); try { await withLogContext( { conversationId: "conversation-2", turnId: "turn-2", - agentId: "turn-2" + agentId: "turn-2", }, async () => { - log.info("agent_message_in", { "app.message.kind": "user_inbound" }, "Agent message received"); - } + log.info( + "agent_message_in", + { "app.message.kind": "user_inbound" }, + "Agent message received", + ); + }, ); } finally { vi.unstubAllEnvs(); @@ -97,4 +117,32 @@ describe("logging context ids", () => { expect(agentIndex).toBeGreaterThan(turnIndex); expect(eventNameIndex).toBeGreaterThan(agentIndex); }); + + it("redacts PEM private key bodies without regex backtracking", async () => { + const { log, registerLogRecordSink } = await import("@/chat/logging"); + const records: Array<{ body: string }> = []; + const unregister = registerLogRecordSink((record) => { + records.push({ body: record.body }); + }); + + try { + log.error( + "pem_key_logged", + {}, + [ + "-----BEGIN PRIVATE KEY-----", + "super-secret-material", + "-----END PRIVATE KEY-----", + ].join("\n"), + ); + } finally { + unregister(); + } + + expect(records).toHaveLength(1); + expect(records[0]?.body).toContain("-----BEGIN PRIVATE KEY-----"); + expect(records[0]?.body).toContain("...redacted..."); + expect(records[0]?.body).toContain("-----END PRIVATE KEY-----"); + expect(records[0]?.body).not.toContain("super-secret-material"); + }); }); From 6ead2049f2cb98b0dfde30190b03f2450dc5ec22 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Tue, 17 Mar 2026 17:08:52 -0700 Subject: [PATCH 04/28] fix(mcp): Preserve loaded skills during auth pause Sync the resumability checkpoint as soon as a plugin skill is loaded so an MCP auth pause cannot drop the newly activated skill. This keeps the resumed turn aligned with the tool state the user asked for before OAuth interrupted execution. Add a focused unit regression that exercises loadSkill, auth-required pause, checkpoint persistence, and resume-time MCP tool restoration. Co-Authored-By: GPT-5 Codex --- packages/junior/src/chat/respond.ts | 2 +- .../respond-mcp-progressive-loading.test.ts | 385 ++++++++++++++++++ 2 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index b85a8e7c..0dca666f 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -1267,8 +1267,8 @@ export async function generateAssistantReply( const resolvedSkill = await skillSandbox.loadSkill(loadedSkill.name); const effective = resolvedSkill ?? loadedSkill; upsertActiveSkill(activeSkills, effective); - await turnMcpToolManager.activateForSkill(effective); syncResumeState(); + await turnMcpToolManager.activateForSkill(effective); refreshAgentTools(); }, }, diff --git a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts new file mode 100644 index 00000000..ce49b0e1 --- /dev/null +++ b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts @@ -0,0 +1,385 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +const { + agentInitialToolNames, + deliverPrivateMessageMock, + listToolsMock, + loadSkillsByNameMock, + setToolsCallNames, +} = vi.hoisted(() => ({ + agentInitialToolNames: [] as string[][], + deliverPrivateMessageMock: vi.fn(), + listToolsMock: vi.fn(), + loadSkillsByNameMock: vi.fn(), + setToolsCallNames: [] as string[][], +})); + +vi.mock("@mariozechner/pi-agent-core", () => { + class MockAgent { + state: { + messages: unknown[]; + model: unknown; + systemPrompt: string; + tools: Array<{ + name: string; + execute: (toolCallId: unknown, params: unknown) => Promise; + }>; + }; + + constructor(input: { + initialState: { + model: unknown; + systemPrompt: string; + tools: Array<{ + name: string; + execute: (toolCallId: unknown, params: unknown) => Promise; + }>; + }; + }) { + this.state = { + messages: [], + model: input.initialState.model, + systemPrompt: input.initialState.systemPrompt, + tools: [...input.initialState.tools], + }; + agentInitialToolNames.push(this.state.tools.map((tool) => tool.name)); + } + + subscribe() { + return () => undefined; + } + + setTools( + tools: Array<{ + name: string; + execute: (toolCallId: unknown, params: unknown) => Promise; + }>, + ) { + this.state.tools = [...tools]; + setToolsCallNames.push(tools.map((tool) => tool.name)); + } + + abort() {} + + async replaceMessages(messages: unknown[]) { + this.state.messages = [...messages]; + } + + async prompt(message: unknown) { + this.state.messages.push(message); + const loadSkillTool = this.state.tools.find( + (tool) => tool.name === "loadSkill", + ); + if (!loadSkillTool) { + throw new Error("loadSkill tool missing"); + } + await loadSkillTool.execute("tool-call-1", { skill_name: "demo-skill" }); + return {}; + } + + async continue() { + this.state.messages.push({ + role: "assistant", + content: [{ type: "text", text: "resumed reply" }], + }); + return {}; + } + } + + return { Agent: MockAgent }; +}); + +vi.mock("@/chat/observability", () => ({ + logException: vi.fn(), + logInfo: vi.fn(), + logWarn: vi.fn(), + setSpanAttributes: vi.fn(), + setSpanStatus: vi.fn(), + setTags: vi.fn(), + withSpan: async ( + _name: string, + _op: string, + _context: unknown, + callback: () => Promise, + ) => await callback(), +})); + +vi.mock("@/chat/oauth-flow", () => ({ + deliverPrivateMessage: deliverPrivateMessageMock, + formatProviderLabel: (provider: string) => provider, + resolveBaseUrl: () => "https://junior.example.com", +})); + +vi.mock("@/chat/pi/client", () => ({ + GEN_AI_PROVIDER_NAME: "vercel-ai-gateway", + getGatewayApiKey: () => "test-gateway-key", + resolveGatewayModel: (modelId: string) => modelId, +})); + +vi.mock("@/chat/prompt", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + buildSystemPrompt: () => "System prompt", + }; +}); + +vi.mock("@/chat/runtime/dev-agent-trace", () => ({ + shouldEmitDevAgentTrace: () => false, +})); + +vi.mock("@/chat/runtime-metadata", () => ({ + getRuntimeMetadata: () => ({ version: "test" }), +})); + +vi.mock("@/chat/capabilities/factory", () => ({ + createSkillCapabilityRuntime: () => ({ + getTurnHeaderTransforms: () => undefined, + }), + getUserTokenStore: () => ({ + get: async () => undefined, + set: async () => undefined, + delete: async () => undefined, + }), +})); + +vi.mock("@/chat/capabilities/jr-rpc-command", () => ({ + maybeExecuteJrRpcCustomCommand: async () => ({ handled: false }), +})); + +vi.mock("@/chat/sandbox/sandbox", () => ({ + createSandboxExecutor: () => ({ + configureSkills: () => undefined, + createSandbox: async () => ({ + readFileToBuffer: async () => + Buffer.from( + [ + "---", + "name: demo-skill", + "description: Demo skill", + "---", + "", + "Skill instructions", + ].join("\n"), + "utf8", + ), + }), + canExecute: () => false, + execute: async () => { + throw new Error("sandbox executor should not handle mocked tools"); + }, + getSandboxId: () => "sandbox-test", + getDependencyProfileHash: () => "hash-test", + dispose: async () => undefined, + }), +})); + +vi.mock("@/chat/plugins/registry", async (importOriginal) => { + const actual = + await importOriginal(); + const plugin = { + dir: "/tmp/plugins/demo", + skillsDir: "/tmp/plugins/demo/skills", + manifest: { + name: "demo", + description: "Demo plugin", + capabilities: [], + configKeys: [], + mcp: { + transport: "http", + url: "https://mcp.example.com", + }, + }, + }; + + return { + ...actual, + getPluginDefinition: (provider: string) => + provider === "demo" ? plugin : undefined, + getPluginMcpProviders: () => [plugin], + getPluginProviders: () => [plugin], + }; +}); + +vi.mock("@/chat/skills", () => { + const metadata = { + name: "demo-skill", + description: "Demo skill", + skillPath: "/tmp/skills/demo-skill", + pluginProvider: "demo", + }; + + return { + discoverSkills: async () => [metadata], + findSkillByName: () => null, + loadSkillsByName: loadSkillsByNameMock, + parseSkillInvocation: () => null, + }; +}); + +vi.mock("@/chat/mcp/client", () => { + class MockMcpAuthorizationRequiredError extends Error { + readonly provider: string; + + constructor(provider: string, message: string) { + super(message); + this.name = "McpAuthorizationRequiredError"; + this.provider = provider; + } + } + + class MockPluginMcpClient { + constructor( + private readonly plugin: { manifest: { name: string } }, + private readonly options: { + authProvider?: { + redirectToAuthorization?: (authorizationUrl: URL) => Promise; + }; + }, + ) {} + + async listTools() { + return await listToolsMock(this.plugin, this.options); + } + + async callTool() { + return { + content: [{ type: "text", text: "pong" }], + isError: false, + }; + } + + async close() {} + } + + return { + McpAuthorizationRequiredError: MockMcpAuthorizationRequiredError, + PluginMcpClient: MockPluginMcpClient, + }; +}); + +import { generateAssistantReply } from "@/chat/respond"; +import { + disconnectStateAdapter, + getAgentTurnSessionCheckpoint, +} from "@/chat/state"; +import { isRetryableTurnError } from "@/chat/turn/errors"; + +describe("generateAssistantReply progressive MCP loading", () => { + beforeEach(async () => { + agentInitialToolNames.length = 0; + setToolsCallNames.length = 0; + deliverPrivateMessageMock.mockReset(); + listToolsMock.mockReset(); + loadSkillsByNameMock.mockReset(); + + process.env.JUNIOR_STATE_ADAPTER = "memory"; + process.env.JUNIOR_BASE_URL = "https://junior.example.com"; + + deliverPrivateMessageMock.mockResolvedValue({ + channel: "D123", + threadTs: "1712345.0001", + }); + loadSkillsByNameMock.mockResolvedValue([ + { + name: "demo-skill", + description: "Demo skill", + skillPath: "/tmp/skills/demo-skill", + pluginProvider: "demo", + body: "Skill instructions", + }, + ]); + listToolsMock + .mockImplementationOnce( + async ( + plugin: { manifest: { name: string } }, + options: { + authProvider?: { + redirectToAuthorization?: ( + authorizationUrl: URL, + ) => Promise; + }; + }, + ) => { + await options.authProvider?.redirectToAuthorization?.( + new URL(`https://auth.example.com/${plugin.manifest.name}`), + ); + const { McpAuthorizationRequiredError } = + await import("@/chat/mcp/client"); + throw new McpAuthorizationRequiredError( + plugin.manifest.name, + "Auth required", + ); + }, + ) + .mockResolvedValue([ + { + name: "ping", + title: "Ping", + description: "Ping the demo MCP server", + inputSchema: { + type: "object", + properties: {}, + }, + }, + ]); + + await disconnectStateAdapter(); + }); + + afterEach(async () => { + await disconnectStateAdapter(); + delete process.env.JUNIOR_STATE_ADAPTER; + delete process.env.JUNIOR_BASE_URL; + vi.restoreAllMocks(); + }); + + it("persists loaded plugin skills across auth pause and resume", async () => { + const context = { + assistant: { userName: "junior" }, + requester: { userId: "U123" }, + correlation: { + conversationId: "conversation-1", + turnId: "turn-1", + channelId: "C123", + threadTs: "1712345.0001", + }, + }; + + const firstError = await generateAssistantReply("help me", context).catch( + (error) => error, + ); + + expect(isRetryableTurnError(firstError, "mcp_auth_resume")).toBe(true); + expect(agentInitialToolNames[0]).toContain("loadSkill"); + expect(agentInitialToolNames[0]).not.toContain("mcp__demo__ping"); + + const pausedCheckpoint = await getAgentTurnSessionCheckpoint( + "conversation-1", + "turn-1", + ); + expect(pausedCheckpoint).toMatchObject({ + state: "awaiting_resume", + loadedSkillNames: ["demo-skill"], + activeMcpProviders: [], + resumeReason: "auth", + }); + expect(deliverPrivateMessageMock).toHaveBeenCalledTimes(1); + + const reply = await generateAssistantReply("help me", context); + + expect(reply.text).toBe("resumed reply"); + expect(agentInitialToolNames[1]).toContain("mcp__demo__ping"); + expect(setToolsCallNames).toEqual([]); + + const resumedCheckpoint = await getAgentTurnSessionCheckpoint( + "conversation-1", + "turn-1", + ); + expect(resumedCheckpoint).toMatchObject({ + state: "completed", + loadedSkillNames: ["demo-skill"], + activeMcpProviders: ["demo"], + }); + }); +}); From 8d476f5a2c417c080c8116ba0097adca4f29f9ae Mon Sep 17 00:00:00 2001 From: David Cramer Date: Tue, 17 Mar 2026 17:10:28 -0700 Subject: [PATCH 05/28] fix(mcp): Close all clients during teardown Keep MCP client shutdown best-effort so one failing client does not prevent the rest of the active providers from closing or leave the manager state populated. Preserve the first close error after cleanup so the caller can still log the teardown failure. Extend the existing tool-manager unit coverage to assert that all active clients are closed and the active provider state is cleared even when one close call throws. Co-Authored-By: GPT-5 Codex --- packages/junior/src/chat/mcp/tool-manager.ts | 13 +++++++- .../tests/unit/mcp/tool-manager.test.ts | 30 ++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/junior/src/chat/mcp/tool-manager.ts b/packages/junior/src/chat/mcp/tool-manager.ts index bcd8d1cf..57e2a4f6 100644 --- a/packages/junior/src/chat/mcp/tool-manager.ts +++ b/packages/junior/src/chat/mcp/tool-manager.ts @@ -214,12 +214,23 @@ export class McpToolManager { } async close(): Promise { + let firstError: unknown; + for (const client of this.clientsByProvider.values()) { - await client.close(); + try { + await client.close(); + } catch (error) { + firstError ??= error; + } } + this.clientsByProvider.clear(); this.toolsByProvider.clear(); this.activeProviders.clear(); + + if (firstError) { + throw firstError; + } } private async getClient(plugin: PluginDefinition): Promise { diff --git a/packages/junior/tests/unit/mcp/tool-manager.test.ts b/packages/junior/tests/unit/mcp/tool-manager.test.ts index 3fa3c19f..7f9d4513 100644 --- a/packages/junior/tests/unit/mcp/tool-manager.test.ts +++ b/packages/junior/tests/unit/mcp/tool-manager.test.ts @@ -45,12 +45,12 @@ vi.mock("@/chat/mcp/client", () => { import { McpAuthorizationRequiredError } from "@/chat/mcp/client"; import { McpToolManager } from "@/chat/mcp/tool-manager"; -function buildPlugin(): PluginDefinition { +function buildPlugin(name = "demo"): PluginDefinition { return { - dir: "/tmp/plugins/demo", - skillsDir: "/tmp/plugins/demo/skills", + dir: `/tmp/plugins/${name}`, + skillsDir: `/tmp/plugins/${name}/skills`, manifest: { - name: "demo", + name, description: "Demo MCP plugin", capabilities: [], configKeys: [], @@ -176,4 +176,26 @@ describe("McpToolManager", () => { }), ); }); + + it("closes every active client before surfacing the first close error", async () => { + const alphaPlugin = buildPlugin("alpha"); + const betaPlugin = buildPlugin("beta"); + const manager = new McpToolManager([alphaPlugin, betaPlugin]); + + await manager.activateProvider("alpha"); + await manager.activateProvider("beta"); + + closeMock.mockImplementation(async (plugin: PluginDefinition) => { + if (plugin.manifest.name === "alpha") { + throw new Error("alpha close failed"); + } + }); + + await expect(manager.close()).rejects.toThrow("alpha close failed"); + expect(closeMock).toHaveBeenCalledTimes(2); + expect(closeMock).toHaveBeenNthCalledWith(1, alphaPlugin); + expect(closeMock).toHaveBeenNthCalledWith(2, betaPlugin); + expect(manager.getActiveProviders()).toEqual([]); + expect(manager.getActiveTools()).toEqual([]); + }); }); From 4a492cb02b1fbdcc2e7a6fe27ffb06af4052975b Mon Sep 17 00:00:00 2001 From: David Cramer Date: Tue, 17 Mar 2026 17:14:02 -0700 Subject: [PATCH 06/28] fix(mcp): Preserve resumed file uploads Keep resumed OAuth callback delivery aligned with the normal reply executor by uploading files whenever the delivery plan requests them, even if thread text posting is intentionally suppressed. This avoids silently dropping artifacts in reaction-ack flows and other no-text reply modes. Add callback coverage for the resumed delivery path where files are attached but thread text is skipped. Co-Authored-By: GPT-5 Codex --- .../junior/src/handlers/mcp-oauth-callback.ts | 2 +- .../junior/tests/mcp-oauth-callback.test.ts | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/packages/junior/src/handlers/mcp-oauth-callback.ts b/packages/junior/src/handlers/mcp-oauth-callback.ts index 47a0a701..92bed56b 100644 --- a/packages/junior/src/handlers/mcp-oauth-callback.ts +++ b/packages/junior/src/handlers/mcp-oauth-callback.ts @@ -166,7 +166,7 @@ async function deliverReplyToThread( } } - if (!replyFiles || attachFiles === "none" || !shouldPostThreadReply) { + if (!replyFiles || attachFiles === "none") { return; } diff --git a/packages/junior/tests/mcp-oauth-callback.test.ts b/packages/junior/tests/mcp-oauth-callback.test.ts index 17964600..39d30952 100644 --- a/packages/junior/tests/mcp-oauth-callback.test.ts +++ b/packages/junior/tests/mcp-oauth-callback.test.ts @@ -398,6 +398,50 @@ describe("mcp oauth callback handler", () => { }); }); + it("uploads resumed reply files even when thread text delivery is suppressed", async () => { + generateAssistantReplyMock.mockResolvedValueOnce({ + text: "👍", + files: [ + { + data: Buffer.from("hello"), + filename: "resume.txt", + }, + ], + deliveryPlan: { + mode: "thread", + ack: "reaction", + postThreadText: false, + attachFiles: "inline", + }, + diagnostics: { + outcome: "success", + toolCalls: [], + }, + }); + + const response = await GET( + makeRequest( + "https://example.com/api/oauth/callback/mcp/demo?code=auth-code&state=state-123", + ), + makeContext("demo"), + ); + + expect(response.status).toBe(200); + await afterCallbacks[0]!(); + + expect(postMessageMock).toHaveBeenCalledTimes(1); + expect(uploadFilesToThreadMock).toHaveBeenCalledWith({ + channelId: "C123", + threadTs: "1712345.0001", + files: [ + { + data: Buffer.from("hello"), + filename: "resume.txt", + }, + ], + }); + }); + it("marks the resumed turn failed in thread state when continuation errors", async () => { generateAssistantReplyMock.mockRejectedValueOnce( new Error("resume failed"), From 3ade5068d1a8d16da7eb5f5f7a55715052ae0e6e Mon Sep 17 00:00:00 2001 From: David Cramer Date: Wed, 18 Mar 2026 16:09:36 -0700 Subject: [PATCH 07/28] feat(mcp): Dispatch plugin tools through stable host tools Replace per-provider Pi tool registration with host-managed searchTools and useTool dispatch so loadSkill can expose MCP tools without replaying the turn. Persist MCP auth and session state at the host boundary, migrate the Notion skill to the new dispatcher contract, and tighten the MCP resume path. Reduce dev noise by shrinking console logging, deduping startup/plugin file-load logs, and making MCP dispatcher status updates more specific in Slack. Co-Authored-By: GPT-5 Codex --- package.json | 2 - .../docs/src/content/docs/extend/index.md | 1 + .../src/content/docs/extend/notion-plugin.md | 68 +-- packages/junior-notion/README.md | 42 +- packages/junior-notion/plugin.yaml | 16 +- .../scripts/run-with-root-env.mjs | 45 -- packages/junior-notion/skills/notion/SKILL.md | 48 +- .../skills/notion/scripts/notion-cli.mjs | 557 ------------------ packages/junior/src/chat/app-home.ts | 100 ++-- packages/junior/src/chat/app-runtime.ts | 20 + .../src/chat/bootstrap/register-handlers.ts | 62 +- .../src/chat/capabilities/jr-rpc-command.ts | 22 +- packages/junior/src/chat/logging.ts | 165 +++++- packages/junior/src/chat/mcp/auth-store.ts | 159 ++++- packages/junior/src/chat/mcp/client.ts | 161 +++-- .../junior/src/chat/mcp/oauth-provider.ts | 82 ++- packages/junior/src/chat/mcp/oauth.ts | 42 +- packages/junior/src/chat/mcp/tool-manager.ts | 269 ++++++++- packages/junior/src/chat/plugins/manifest.ts | 39 ++ packages/junior/src/chat/plugins/registry.ts | 43 +- packages/junior/src/chat/plugins/types.ts | 1 + packages/junior/src/chat/prompt.ts | 66 ++- packages/junior/src/chat/respond.ts | 236 +++++--- packages/junior/src/chat/skill-frontmatter.ts | 9 + packages/junior/src/chat/skills.ts | 3 + packages/junior/src/chat/tools/index.ts | 15 + packages/junior/src/chat/tools/load-skill.ts | 19 +- .../junior/src/chat/tools/mcp-tool-summary.ts | 43 ++ .../junior/src/chat/tools/search-tools.ts | 58 ++ packages/junior/src/chat/tools/types.ts | 8 +- packages/junior/src/chat/tools/use-tool.ts | 62 ++ .../junior/src/handlers/mcp-oauth-callback.ts | 72 +-- packages/junior/tests/app-home.test.ts | 152 +++-- packages/junior/tests/bot-handlers.test.ts | 42 ++ packages/junior/tests/jr-rpc-command.test.ts | 67 ++- .../junior/tests/mcp-oauth-callback.test.ts | 30 + .../tests/plugin-registry-packages.test.ts | 57 ++ .../tests/respond-status-formatters.test.ts | 24 + .../junior/tests/skill-frontmatter.test.ts | 19 + .../junior/tests/unit/logging-context.test.ts | 166 +++++- .../junior/tests/unit/mcp/auth-store.test.ts | 113 ++++ packages/junior/tests/unit/mcp/client.test.ts | 221 +++++++ .../tests/unit/mcp/oauth-provider.test.ts | 104 ++++ .../tests/unit/mcp/tool-manager.test.ts | 199 ++++++- packages/junior/tests/unit/notion-cli.test.ts | 123 ---- .../respond-mcp-progressive-loading.test.ts | 206 ++++++- specs/agent-session-resumability-spec.md | 4 +- specs/logging/logging-spec.md | 52 +- specs/oauth-flows-spec.md | 16 +- specs/plugin-spec.md | 19 +- 50 files changed, 2903 insertions(+), 1246 deletions(-) delete mode 100644 packages/junior-notion/scripts/run-with-root-env.mjs delete mode 100644 packages/junior-notion/skills/notion/scripts/notion-cli.mjs create mode 100644 packages/junior/src/chat/tools/mcp-tool-summary.ts create mode 100644 packages/junior/src/chat/tools/search-tools.ts create mode 100644 packages/junior/src/chat/tools/use-tool.ts create mode 100644 packages/junior/tests/unit/mcp/auth-store.test.ts create mode 100644 packages/junior/tests/unit/mcp/client.test.ts delete mode 100644 packages/junior/tests/unit/notion-cli.test.ts diff --git a/package.json b/package.json index 503ecc41..80293e2f 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,6 @@ "scripts": { "dev": "node scripts/dev-with-root-env.mjs", "cli": "node scripts/cli-with-root-env.mjs", - "notion:search": "node packages/junior-notion/scripts/run-with-root-env.mjs ../skills/notion/scripts/notion-cli.mjs search", - "notion:fetch": "node packages/junior-notion/scripts/run-with-root-env.mjs ../skills/notion/scripts/notion-cli.mjs fetch", "prepare": "simple-git-hooks", "lint-staged": "lint-staged", "build": "pnpm --filter @sentry/junior build", diff --git a/packages/docs/src/content/docs/extend/index.md b/packages/docs/src/content/docs/extend/index.md index 78349c22..32a1a82a 100644 --- a/packages/docs/src/content/docs/extend/index.md +++ b/packages/docs/src/content/docs/extend/index.md @@ -147,6 +147,7 @@ runtime-postinstall: - `runtime-dependencies`: sandbox dependencies required by the plugin’s tools - `runtime-postinstall`: commands that run after dependency install and before snapshot capture - `mcp`: optional MCP server configuration for provider-scoped tool sources +- `mcp.allowed-tools`: optional raw MCP tool-name allowlist when a plugin should expose only part of a provider's tool surface ### Add skills to the plugin diff --git a/packages/docs/src/content/docs/extend/notion-plugin.md b/packages/docs/src/content/docs/extend/notion-plugin.md index a7ca7211..02fff403 100644 --- a/packages/docs/src/content/docs/extend/notion-plugin.md +++ b/packages/docs/src/content/docs/extend/notion-plugin.md @@ -1,8 +1,8 @@ --- title: Notion Plugin -description: Configure a shared internal Notion integration for read-only page and data source search workflows. +description: Configure the hosted Notion MCP server for read-only page and data source search workflows. type: tutorial -summary: Install the Notion plugin, register it with withJunior, configure a shared integration token, and verify Notion search workflows. +summary: Install the Notion plugin, register it with withJunior, connect user accounts through Notion MCP OAuth, and verify read-only search workflows. prerequisites: - /extend/ related: @@ -10,9 +10,11 @@ related: - /operate/security-hardening/ --- -The Notion plugin uses a shared internal integration so Slack users can search shared Notion pages and data sources through normal Notion requests. +The Notion plugin uses Notion's hosted MCP server so Slack users can search and fetch content from their own Notion account context. -Notion's public search API is more limited than the search experience in the Notion app. Junior uses the stable public API, so Notion requests work best when users search for the exact page or data source title they want to open. +Junior intentionally keeps this plugin read-only. It exposes only Notion's `notion-search` and `notion-fetch` MCP tools, even though the hosted server supports write-capable tools. + +Notion search is still title-biased. Requests work best when users search for the exact page or data source title they want to open. ## Install @@ -34,55 +36,35 @@ export default withJunior({ }); ``` -## Configure environment variables - -Set these values in the host environment: - -| Variable | Required | Purpose | -| -------------- | -------- | -------------------------------------------------------------------- | -| `NOTION_TOKEN` | Yes | Internal integration secret used for search and page fetch requests. | - -## Create the Notion integration - -Start with Notion's [Authorization guide](https://developers.notion.com/guides/get-started/authorization), then create an internal integration in the Notion integrations dashboard. - -After you create the integration: +## Auth model -1. Choose the workspace where the integration will live. -2. Open the `Capabilities` tab and enable `Read content`. -3. Open the `Configuration` tab and copy the integration secret. -4. Store that secret in your deployment environment as `NOTION_TOKEN`. +- No `NOTION_TOKEN` or shared integration secret is required. +- Each user completes OAuth the first time Junior calls a Notion MCP tool on their behalf. +- Junior sends the authorization link privately, then resumes the same thread automatically after the user authorizes. +- Notion MCP requires user-based OAuth and does not support bearer token authentication, so this plugin is not suitable for fully headless automation. -## Share pages and data sources with the integration +## What users can do -Notion internal integrations only see the pages and data sources that are explicitly shared with them: - -1. Open the page or data source in Notion. -2. Click the `•••` menu in the upper right. -3. Choose `Add connections`. -4. Select your integration. - -This is the most common reason a Notion request returns no matches or a permission-style error. +- Search for a page or data source by title-style query. +- Fetch the best matching result and summarize its content. +- Disconnect their account later from Junior App Home with `Unlink`. ## Verify -Confirm the token is set, the target content is shared with the integration, and a real search succeeds: - -- Ask Junior to search Notion for a real page or data source title and confirm the response includes the expected result. -- If needed, verify the same content through the local helper scripts: +Confirm a real user can connect and search successfully: -```bash -pnpm notion:search -- --query "company holidays" -pnpm notion:fetch -- --id "" --object page -``` +1. Ask Junior to search Notion for a real page or data source title. +2. Complete the private OAuth flow when Junior prompts for it. +3. Confirm the thread resumes automatically and includes the expected Notion result. +4. Open Junior App Home and confirm Notion appears under `Connected accounts`. ## Failure modes -- No search matches: the target page or data source is not shared with the integration yet, or Notion search is still indexing newly shared content. Share the content directly and retry after indexing catches up. -- `403` from Notion: the integration is missing `Read content`. Enable that capability in the integration settings. -- `401` from Notion: `NOTION_TOKEN` is missing or invalid. Update the deployment secret and redeploy. -- Retrieval errors after a match: the matching page or data source could not be fetched for summarization. Confirm the object is still shared and accessible to the integration. -- Search results differ from notion.so: Junior uses Notion's public `v1` API, which is title-biased and does not expose the richer `Best matches` behavior from the Notion UI. Search by the exact title when possible. +- No auth prompt or no resume: the user still needs to complete the OAuth flow. Retry the request and finish the private authorization flow when prompted. +- No search matches: the query is too broad, the content is outside the user's Notion permissions, or search has not indexed recent changes yet. +- Search results differ from notion.so: MCP search is still title-biased. Search by the exact title when possible. +- Connected-source results are missing: search across Slack, Google Drive, or Jira requires a Notion AI plan. Without it, search is limited to the user's Notion workspace. +- Retrieval errors after a match: the matching page or data source could not be fetched for summarization. Confirm the user can still access that object in Notion. ## Next step diff --git a/packages/junior-notion/README.md b/packages/junior-notion/README.md index 864a4592..beac9994 100644 --- a/packages/junior-notion/README.md +++ b/packages/junior-notion/README.md @@ -1,6 +1,6 @@ # @sentry/junior-notion -`@sentry/junior-notion` adds read-only Notion search workflows for pages and data sources to Junior via a shared internal Notion integration. +`@sentry/junior-notion` adds read-only Notion search workflows for pages and data sources to Junior through Notion's hosted MCP server. Install it alongside `@sentry/junior`: @@ -8,21 +8,6 @@ Install it alongside `@sentry/junior`: pnpm add @sentry/junior @sentry/junior-notion ``` -Create an internal Notion integration by following Notion's Authorization guide: - -- https://developers.notion.com/guides/get-started/authorization - -In the Notion integration settings: - -- choose the workspace where the integration will live -- enable the `Read content` capability -- copy the integration secret from the `Configuration` tab -- share any pages or data sources Junior should read via `•••` -> `Add connections` - -Set that value in your host environment: - -- `NOTION_TOKEN` - Then register the plugin package in `withJunior(...)`: ```js @@ -33,24 +18,23 @@ export default withJunior({ }); ``` -There is no `/notion auth` flow for this plugin. Once the token is configured and pages or data sources are shared with the integration, users can run `/notion ` directly. +This package does not use `NOTION_TOKEN` or a shared workspace integration. Each user connects their own Notion account the first time Junior calls a Notion MCP tool. Junior sends the OAuth link privately and resumes the thread automatically after the user authorizes. -## Search limitations +Junior intentionally keeps this package read-only by exposing only Notion's `notion-search` and `notion-fetch` MCP tools. The plugin does not expose create, update, move, or other write-capable Notion tools. -This plugin currently uses Notion's public `v1` API for search and content retrieval. +## Search limitations -- `v1/search` is title-biased and does not match the richer `Best matches` behavior users see in notion.so. -- Results can differ from the UI even when the user can see a page in the Notion app. -- The most common cause of missing results is that the target page or data source is not directly shared with the integration. -- Newly shared content can also lag behind search indexing. +This package uses Notion MCP search and fetch rather than the older REST helper flow. -We also tested Notion's private `api/v3/search` endpoint with the same integration token. It accepted the token at the HTTP layer, but it did not return useful results for the same sample queries, so this plugin does not depend on `api/v3`. +- Search is still title-biased, so prompts work best when users search for the actual page or data source title. +- Results can differ from the Notion UI even when the user can see a page in the app. +- Search across connected sources like Slack, Google Drive, and Jira requires a Notion AI plan. Without Notion AI, search is limited to the user's Notion workspace. +- Missing results are usually a permissions problem on the user's Notion account or a weak query phrase. -For local debugging, the package exposes one Notion helper script through two subcommands that load the workspace env first: +## Auth model -```bash -pnpm notion:search -- --query "company holidays" -pnpm notion:fetch -- --id "" --object page -``` +- Notion MCP requires user-based OAuth and does not support bearer token authentication. +- This package is not suitable for fully headless or unattended automation. +- Users can disconnect from Junior App Home with `Unlink`, or by asking Junior to disconnect Notion. Full setup guide: https://junior.sentry.dev/extend/notion-plugin/ diff --git a/packages/junior-notion/plugin.yaml b/packages/junior-notion/plugin.yaml index fd01371c..78cedfa4 100644 --- a/packages/junior-notion/plugin.yaml +++ b/packages/junior-notion/plugin.yaml @@ -1,13 +1,9 @@ name: notion description: Notion page search and summarization -capabilities: - - api - -credentials: - type: oauth-bearer - api-domains: - - api.notion.com - api-headers: - Notion-Version: "2025-09-03" - auth-token-env: NOTION_TOKEN +mcp: + transport: http + url: https://mcp.notion.com/mcp + allowed-tools: + - notion-search + - notion-fetch diff --git a/packages/junior-notion/scripts/run-with-root-env.mjs b/packages/junior-notion/scripts/run-with-root-env.mjs deleted file mode 100644 index 22ac81cb..00000000 --- a/packages/junior-notion/scripts/run-with-root-env.mjs +++ /dev/null @@ -1,45 +0,0 @@ -import fs from "node:fs"; -import { spawn } from "node:child_process"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const packageScriptsRoot = path.dirname(fileURLToPath(import.meta.url)); -const workspaceRoot = path.resolve(packageScriptsRoot, "../../.."); -const nodeEnv = process.env.NODE_ENV ?? "development"; -const rawArgs = process.argv.slice(2); - -if (rawArgs.length === 0) { - throw new Error("run-with-root-env requires a helper script path"); -} - -const [helperRelativePath, ...rawHelperArgs] = rawArgs; -const helperArgs = rawHelperArgs[0] === "--" ? rawHelperArgs.slice(1) : rawHelperArgs; -const envCandidates = [ - `.env.${nodeEnv}.local`, - nodeEnv === "test" ? null : ".env.local", - `.env.${nodeEnv}`, - ".env", -].filter(Boolean); - -for (const relativePath of envCandidates) { - const absolutePath = path.join(workspaceRoot, relativePath); - if (!fs.existsSync(absolutePath)) { - continue; - } - - process.loadEnvFile(absolutePath); -} - -const helperPath = path.resolve(packageScriptsRoot, helperRelativePath); -const child = spawn("node", [helperPath, ...helperArgs], { - stdio: "inherit", - env: process.env, -}); - -child.on("exit", (code, signal) => { - if (signal) { - process.kill(process.pid, signal); - return; - } - process.exit(code ?? 1); -}); diff --git a/packages/junior-notion/skills/notion/SKILL.md b/packages/junior-notion/skills/notion/SKILL.md index 7a1fcee9..45f950bb 100644 --- a/packages/junior-notion/skills/notion/SKILL.md +++ b/packages/junior-notion/skills/notion/SKILL.md @@ -1,8 +1,7 @@ --- name: notion description: Search Notion pages and data sources and summarize the best match. Use when users ask to look up docs, specs, notes, meeting notes, project context, roadmaps, trackers, or internal references stored in Notion. -requires-capabilities: notion.api -allowed-tools: bash +allowed-mcp-tools: notion-search notion-fetch --- # Notion Operations @@ -13,36 +12,45 @@ Use this skill for `/notion` workflows in the harness. 1. Classify the request: -- `auth`: explain that this plugin uses a shared internal Notion integration, so there is no per-user auth flow. Tell the user the workspace admin must configure `NOTION_TOKEN` and share the relevant pages or data sources with the integration. -- `disconnect`: explain that there is no per-user Notion connection to remove because the plugin uses a shared internal integration. +- `disconnect`: run `jr-rpc delete-token notion` in `bash`, then confirm that the user's Notion connection was removed. - otherwise treat the request as a read-only query. -2. Enable credentials: +2. Keep tool work mostly silent: -- Before any Notion API call, run `jr-rpc issue-credential notion.api`. -- If credential issuance fails, explain that Notion is not configured on the host and the admin must set `NOTION_TOKEN`. +- Send at most one short acknowledgment before Notion tool work. +- Keep intermediate search/fetch reasoning internal. +- Do not narrate each step with "let me...", "I found...", or partial findings while tools are still running. +- Reply with the real answer once you have enough evidence, or explain the actual blocker if you cannot finish. -3. Search with the checked-in helper: +3. Search with MCP: -- Do not improvise `curl` requests or inline `node` snippets for Notion. +- `loadSkill` returns `available_tools` for this skill, including the exact `tool_name` values and argument schemas for the Notion tools exposed in this turn. +- Use `useTool` with those exact `tool_name` values. +- Use `searchTools` only if you need to rediscover or filter the active Notion tools later in the turn. +- The first MCP call may trigger a private OAuth link. Do not try to start auth manually. The runtime will pause and resume automatically after the user completes the flow. - Decide the actual search phrases first. Notion search is title-biased, so search for the likely page or data source title, not the user's full sentence. - Use 1-3 short explicit search phrases. - Good: `deployment pipeline`, `launch tracker`, `incident review` - Bad: `how do we handle deployment pipelines for mobile releases` -- Run search with the loaded `skill_dir` path: - `node /scripts/notion-cli.mjs search --query "" --query ""` -- If the first phrase misses, rerun with 1-2 alternate title-style phrases. -- Search returns ranked page/data-source candidates only. Pick the best candidate, then fetch content with: - `node /scripts/notion-cli.mjs fetch --id "" --object "page"` - or - `node /scripts/notion-cli.mjs fetch --id "" --object "data_source"` -- Use the fetch output to summarize page markdown, or summarize the data source schema and returned rows. +- For list/report/calendar requests, search for the canonical container first: + - page title: `holidays`, `company holidays` + - data source title: `people calendar` +- Prefer one refinement round at most. If the first search already found a plausible canonical page or data source, fetch it before searching again. + +4. Fetch efficiently: + +- Search returns ranked page and data-source candidates only. Pick the best candidate, then fetch content with the disclosed Notion fetch tool via `useTool` using the returned URL or ID. +- If a fetched page clearly points at an inline data source or database, fetch that data source next and work from it. +- If the fetched data source already contains the rows and fields needed to answer, stop there and answer from that result. +- Do not serially fetch many individual row pages when the container page or data source already exposes the needed fields. +- Fetch individual rows only when a small number of important fields are still missing or ambiguous after fetching the canonical page or data source. +- Once you have enough evidence to answer, stop fetching and respond. ## Guardrails - Read-only only. -- Do not print credential values. -- The runtime injects `Authorization` and `Notion-Version`; the helper handles request-specific headers. +- Junior intentionally exposes only Notion search and fetch tools for this skill. Do not ask for writes, comments, or page moves. - Search results may be pages or data sources. Do not treat data sources as unsupported. -- If search returns no accessible matches, say that no accessible pages or data sources matched and note the content may not be shared with the integration yet. +- For scoped requests like "US holidays" or "2026 holidays", apply the user's scope when reading the fetched content and state any assumption you made if the source mixes multiple geos or years. +- If search returns no accessible matches, say that no accessible pages or data sources matched and note that the content may be outside the user's Notion permissions or poorly matched by title. - If content retrieval fails for the top result, return the best matching Notion URL and explain that the result could not be fetched for summarization. diff --git a/packages/junior-notion/skills/notion/scripts/notion-cli.mjs b/packages/junior-notion/skills/notion/scripts/notion-cli.mjs deleted file mode 100644 index 6bf3f4f5..00000000 --- a/packages/junior-notion/skills/notion/scripts/notion-cli.mjs +++ /dev/null @@ -1,557 +0,0 @@ -#!/usr/bin/env node - -import { pathToFileURL } from "node:url"; - -/** - * Unified Notion helper for LLM-facing search and fetch operations. - * - * `search` preserves the public v1 Search API's native ordering as closely as possible and - * returns broad candidate results for the raw query without forcing a winner. - * - * `fetch` loads normalized content for a specific page or data source chosen from search - * results so the model can summarize a stable payload. - */ - -const DEFAULT_API_BASE_URL = "https://api.notion.com/v1"; -// Keep this pinned in sync with packages/junior-notion/plugin.yaml. -const DEFAULT_NOTION_VERSION = "2025-09-03"; -const DEFAULT_PAGE_SIZE = 100; -const DEFAULT_ROW_LIMIT = 10; -const DEFAULT_TIMEOUT_MS = 15_000; -const DEFAULT_RETRY_LIMIT = 2; - -function parseArgs(argv) { - const parsed = {}; - for (let index = 0; index < argv.length; index += 1) { - const token = argv[index]; - if (!token.startsWith("--")) { - continue; - } - const [rawKey, inlineValue] = token.slice(2).split("=", 2); - if (inlineValue !== undefined) { - if (parsed[rawKey] === undefined) { - parsed[rawKey] = inlineValue; - } else if (Array.isArray(parsed[rawKey])) { - parsed[rawKey].push(inlineValue); - } else { - parsed[rawKey] = [parsed[rawKey], inlineValue]; - } - continue; - } - const next = argv[index + 1]; - if (!next || next.startsWith("--")) { - parsed[rawKey] = "true"; - continue; - } - if (parsed[rawKey] === undefined) { - parsed[rawKey] = next; - } else if (Array.isArray(parsed[rawKey])) { - parsed[rawKey].push(next); - } else { - parsed[rawKey] = [parsed[rawKey], next]; - } - index += 1; - } - return parsed; -} - -function normalizeWhitespace(value) { - return String(value ?? "") - .replace(/\s+/g, " ") - .trim(); -} - -function toStringArray(value) { - if (Array.isArray(value)) { - return value.map((item) => normalizeWhitespace(item)).filter(Boolean); - } - const normalized = normalizeWhitespace(value); - return normalized ? [normalized] : []; -} - -function buildSearchQueries(queries) { - const normalizedQueries = []; - const seenQueries = new Set(); - for (const value of toStringArray(queries)) { - if (seenQueries.has(value)) { - continue; - } - seenQueries.add(value); - normalizedQueries.push(value); - } - return normalizedQueries; -} - -function extractPlainText(value) { - if (typeof value === "string") { - return value; - } - if (!Array.isArray(value)) { - return ""; - } - return value - .map((item) => { - if (typeof item?.plain_text === "string") { - return item.plain_text; - } - if (typeof item?.text?.content === "string") { - return item.text.content; - } - return ""; - }) - .join("") - .trim(); -} - -function extractTitleFromProperties(properties) { - if (!properties || typeof properties !== "object") { - return ""; - } - for (const property of Object.values(properties)) { - if (property?.type === "title") { - return extractPlainText(property.title); - } - } - return ""; -} - -function extractResultTitle(result) { - if (!result || typeof result !== "object") { - return ""; - } - if (Array.isArray(result.title)) { - return extractPlainText(result.title); - } - if (typeof result.title === "string") { - return result.title.trim(); - } - if (result.properties) { - return extractTitleFromProperties(result.properties); - } - return ""; -} - -function simplifySearchResult(result) { - return { - id: String(result?.id ?? ""), - object: String(result?.object ?? ""), - title: extractResultTitle(result), - url: String(result?.url ?? ""), - last_edited_time: result?.last_edited_time ?? null, - }; -} - -function buildHeaders(extraHeaders) { - const headers = { - Accept: "application/json", - "Notion-Version": process.env.NOTION_VERSION || DEFAULT_NOTION_VERSION, - ...extraHeaders, - }; - const token = normalizeWhitespace(process.env.NOTION_TOKEN); - // In sandboxed runs the broker can set a placeholder value here and inject the - // real Authorization header later, so skip the placeholder rather than sending it. - if (token && token !== "host_managed_credential") { - headers.Authorization = `Bearer ${token}`; - } - return headers; -} - -function getApiBaseUrl() { - return normalizeWhitespace(process.env.NOTION_API_BASE_URL) || DEFAULT_API_BASE_URL; -} - -function isRetryableStatus(status) { - return status === 429 || status === 500 || status === 502 || status === 503 || status === 504; -} - -function parseRetryAfterMs(value) { - const seconds = Number.parseFloat(String(value ?? "")); - if (!Number.isFinite(seconds) || seconds < 0) { - return 0; - } - return Math.ceil(seconds * 1000); -} - -function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -async function notionRequest(pathname, init = {}, options = {}) { - const retryLimit = options.retryLimit ?? DEFAULT_RETRY_LIMIT; - const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS; - const method = init.method ?? "GET"; - const headers = buildHeaders(init.headers ?? {}); - const url = `${getApiBaseUrl()}${pathname}`; - - for (let attempt = 0; attempt <= retryLimit; attempt += 1) { - const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), timeoutMs); - try { - const response = await fetch(url, { - ...init, - method, - headers, - signal: controller.signal, - }); - if (!response.ok) { - const bodyText = await response.text(); - if (attempt < retryLimit && isRetryableStatus(response.status)) { - const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after")); - await sleep(retryAfterMs || 250 * (attempt + 1)); - continue; - } - throw new Error( - `Notion API ${method} ${pathname} failed with ${response.status}: ${bodyText || response.statusText}`, - ); - } - const contentType = response.headers.get("content-type") || ""; - if (contentType.includes("application/json")) { - return await response.json(); - } - return await response.text(); - } finally { - clearTimeout(timeout); - } - } - - throw new Error(`Notion API ${method} ${pathname} failed after retries`); -} - -async function searchOnce(query, pageSize, object) { - const body = { - query, - page_size: pageSize, - }; - if (object) { - body.filter = { - property: "object", - value: object, - }; - } - return await notionRequest("/search", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(body), - }); -} - -async function searchNotion({ queries = [], pageSize = DEFAULT_PAGE_SIZE, object = "" } = {}) { - const searchQueries = buildSearchQueries(queries); - const attempts = []; - const candidateMap = new Map(); - - for (const variant of searchQueries) { - const response = await searchOnce(variant, pageSize, object || undefined); - const results = Array.isArray(response?.results) ? response.results : []; - attempts.push({ - query: variant, - object: object || "page_or_data_source", - result_count: results.length, - has_more: Boolean(response?.has_more), - next_cursor: response?.next_cursor ?? null, - }); - - for (const result of results) { - if (!result?.id || candidateMap.has(result.id)) { - continue; - } - candidateMap.set(result.id, { - ...simplifySearchResult(result), - query: variant, - }); - } - } - - return { - ok: true, - query_variants: searchQueries, - attempts, - result_count: candidateMap.size, - results: [...candidateMap.values()].map((candidate) => ({ - id: candidate.id, - object: candidate.object, - title: candidate.title, - url: candidate.url, - last_edited_time: candidate.last_edited_time, - query: candidate.query, - })), - }; -} - -function simplifyFormulaValue(formula) { - if (!formula || typeof formula !== "object") { - return null; - } - - switch (formula.type) { - case "string": - return formula.string ?? null; - case "number": - return formula.number ?? null; - case "boolean": - return formula.boolean ?? null; - case "date": - return formula.date - ? { - start: formula.date.start ?? null, - end: formula.date.end ?? null, - } - : null; - case "page": - return formula.page?.id ?? null; - case "person": - return formula.person?.name || formula.person?.id || null; - case "list": - return Array.isArray(formula.list) - ? formula.list.map((item) => simplifyFormulaValue(item)).filter((item) => item !== null) - : []; - default: - return null; - } -} - -function simplifyPropertyValue(property) { - if (!property || typeof property !== "object") { - return null; - } - switch (property.type) { - case "title": - return extractPlainText(property.title); - case "rich_text": - return extractPlainText(property.rich_text); - case "status": - return property.status?.name ?? null; - case "select": - return property.select?.name ?? null; - case "multi_select": - return Array.isArray(property.multi_select) - ? property.multi_select.map((item) => item?.name).filter(Boolean) - : []; - case "number": - return property.number ?? null; - case "checkbox": - return property.checkbox ?? null; - case "url": - return property.url ?? null; - case "email": - return property.email ?? null; - case "phone_number": - return property.phone_number ?? null; - case "date": - return property.date - ? { - start: property.date.start ?? null, - end: property.date.end ?? null, - } - : null; - case "people": - return Array.isArray(property.people) - ? property.people.map((item) => item?.name || item?.id).filter(Boolean) - : []; - case "relation": - return Array.isArray(property.relation) - ? property.relation.map((item) => item?.id).filter(Boolean) - : []; - case "formula": - return simplifyFormulaValue(property.formula); - case "created_time": - return property.created_time ?? null; - case "last_edited_time": - return property.last_edited_time ?? null; - case "unique_id": - if (!property.unique_id) { - return null; - } - if (property.unique_id.prefix) { - return `${property.unique_id.prefix}-${property.unique_id.number ?? ""}`; - } - return property.unique_id.number ?? null; - default: - return null; - } -} - -function simplifyPageRecord(page) { - const properties = {}; - if (page?.properties && typeof page.properties === "object") { - for (const [key, value] of Object.entries(page.properties)) { - properties[key] = simplifyPropertyValue(value); - } - } - - return { - id: String(page?.id ?? ""), - object: String(page?.object ?? "page"), - title: extractResultTitle(page), - url: String(page?.url ?? ""), - last_edited_time: page?.last_edited_time ?? null, - properties, - }; -} - -function simplifyDataSourceSchema(dataSource) { - const properties = dataSource?.properties; - if (!properties || typeof properties !== "object") { - return []; - } - return Object.entries(properties).map(([name, value]) => ({ - name, - type: String(value?.type ?? "unknown"), - })); -} - -async function fetchPageMetadata(pageId) { - const page = await notionRequest(`/pages/${pageId}`); - return simplifySearchResult(page); -} - -async function fetchPageMarkdown(pageId) { - const response = await notionRequest(`/pages/${pageId}/markdown`); - if (typeof response === "string") { - return response; - } - if (typeof response?.markdown === "string") { - return response.markdown; - } - if (Array.isArray(response?.results)) { - return response.results - .map((item) => (typeof item === "string" ? item : item?.markdown ?? "")) - .filter(Boolean) - .join("\n"); - } - return JSON.stringify(response, null, 2); -} - -async function fetchDataSourceContent(dataSourceId, rowLimit) { - const dataSource = await notionRequest(`/data_sources/${dataSourceId}`); - const target = { - id: String(dataSource?.id ?? dataSourceId), - object: "data_source", - title: extractResultTitle(dataSource), - url: String(dataSource?.url ?? ""), - last_edited_time: dataSource?.last_edited_time ?? null, - }; - - try { - const rowsResponse = await notionRequest(`/data_sources/${dataSourceId}/query`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ page_size: rowLimit }), - }); - - return { - target, - content: { - type: "data_source", - schema: simplifyDataSourceSchema(dataSource), - rows: Array.isArray(rowsResponse?.results) - ? rowsResponse.results.map((row) => simplifyPageRecord(row)) - : [], - }, - }; - } catch (error) { - return { - target, - content: null, - content_error: error instanceof Error ? error.message : String(error), - }; - } -} - -export async function fetchContent({ id, object, rowLimit = DEFAULT_ROW_LIMIT } = {}) { - if (!id) { - throw new Error("notion fetch requires --id"); - } - if (object !== "page" && object !== "data_source") { - throw new Error("notion fetch requires --object page|data_source"); - } - - if (object === "page") { - let target = { - id, - object: "page", - title: "", - url: "", - last_edited_time: null, - }; - try { - target = await fetchPageMetadata(id); - const markdown = await fetchPageMarkdown(id); - return { - ok: true, - target, - content: { - type: "page", - markdown, - }, - }; - } catch (error) { - return { - ok: true, - target, - content: null, - content_error: error instanceof Error ? error.message : String(error), - }; - } - } - - try { - return { - ok: true, - ...(await fetchDataSourceContent(id, rowLimit)), - }; - } catch (error) { - return { - ok: true, - target: { - id, - object: "data_source", - title: "", - url: "", - last_edited_time: null, - }, - content: null, - content_error: error instanceof Error ? error.message : String(error), - }; - } -} - -async function main() { - const [command, ...rest] = process.argv.slice(2); - if (command !== "search" && command !== "fetch") { - throw new Error("notion-cli requires a subcommand: search | fetch"); - } - - const args = parseArgs(rest[0] === "--" ? rest.slice(1) : rest); - let result; - if (command === "search") { - const queries = toStringArray(args.query); - if (queries.length === 0) { - throw new Error("notion search requires at least one --query"); - } - result = await searchNotion({ - queries, - pageSize: args["page-size"] ? Number.parseInt(args["page-size"], 10) : DEFAULT_PAGE_SIZE, - object: normalizeWhitespace(args.object), - }); - } else { - result = await fetchContent({ - id: normalizeWhitespace(args.id), - object: normalizeWhitespace(args.object), - rowLimit: args["row-limit"] ? Number.parseInt(args["row-limit"], 10) : DEFAULT_ROW_LIMIT, - }); - } - - process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); -} - -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { - main().catch((error) => { - process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); - process.exitCode = 1; - }); -} diff --git a/packages/junior/src/chat/app-home.ts b/packages/junior/src/chat/app-home.ts index eac8aee8..b73be9a0 100644 --- a/packages/junior/src/chat/app-home.ts +++ b/packages/junior/src/chat/app-home.ts @@ -2,7 +2,9 @@ import fs from "node:fs"; import path from "node:path"; import type { WebClient, KnownBlock, SectionBlock } from "@slack/web-api"; import { homeDir } from "@/chat/home"; +import { getMcpStoredOAuthCredentials } from "@/chat/mcp/auth-store"; import { getPluginProviders } from "@/chat/plugins/registry"; +import type { PluginDefinition } from "@/chat/plugins/types"; import { discoverSkills } from "@/chat/skills"; import type { UserTokenStore } from "@/chat/credentials/user-token-store"; import { getRuntimeMetadata } from "@/chat/runtime-metadata"; @@ -12,7 +14,8 @@ interface HomeView { blocks: KnownBlock[]; } -const DEFAULT_ABOUT_TEXT = "I help your team investigate, summarize, and act on work in Slack."; +const DEFAULT_ABOUT_TEXT = + "I help your team investigate, summarize, and act on work in Slack."; const MAX_HOME_SKILLS = 6; const MAX_SECTION_TEXT_CHARS = 3000; const HIDDEN_HOME_SKILLS = new Set(["jr-rpc"]); @@ -38,22 +41,45 @@ function loadAboutText(): string { } async function buildSkillsSummaryText(): Promise { - const skills = (await discoverSkills()).filter((skill) => !HIDDEN_HOME_SKILLS.has(skill.name)); + const skills = (await discoverSkills()).filter( + (skill) => !HIDDEN_HOME_SKILLS.has(skill.name), + ); if (skills.length === 0) { return "No skills installed."; } const visible = skills.slice(0, MAX_HOME_SKILLS); - const lines = visible.map((skill) => `• *${skill.name}* — ${skill.description}`); + const lines = visible.map( + (skill) => `• *${skill.name}* — ${skill.description}`, + ); if (skills.length > visible.length) { lines.push(`• …and ${skills.length - visible.length} more`); } return lines.join("\n"); } +async function hasConnectedAccount( + userId: string, + plugin: PluginDefinition, + userTokenStore: UserTokenStore, +): Promise { + if (plugin.manifest.credentials?.type === "oauth-bearer") { + return Boolean(await userTokenStore.get(userId, plugin.manifest.name)); + } + + if (plugin.manifest.mcp) { + return Boolean( + (await getMcpStoredOAuthCredentials(userId, plugin.manifest.name)) + ?.tokens, + ); + } + + return false; +} + export async function buildHomeView( userId: string, - userTokenStore: UserTokenStore + userTokenStore: UserTokenStore, ): Promise { const runtimeMetadata = getRuntimeMetadata(); const aboutText = loadAboutText(); @@ -62,38 +88,36 @@ export async function buildHomeView( const connectedSections: SectionBlock[] = []; for (const plugin of providers) { - if (plugin.manifest.credentials?.type !== "oauth-bearer") continue; - - const tokens = await userTokenStore.get(userId, plugin.manifest.name); - if (!tokens) continue; + if (!(await hasConnectedAccount(userId, plugin, userTokenStore))) continue; connectedSections.push({ type: "section", text: { type: "mrkdwn", - text: `*${plugin.manifest.name}*\n${plugin.manifest.description}` + text: `*${plugin.manifest.name}*\n${plugin.manifest.description}`, }, accessory: { type: "button", text: { type: "plain_text", text: "Unlink" }, action_id: "app_home_disconnect", value: plugin.manifest.name, - style: "danger" - } + style: "danger", + }, }); } - const accountBlocks: KnownBlock[] = connectedSections.length > 0 - ? connectedSections - : [ - { - type: "section", - text: { - type: "mrkdwn", - text: "No connected accounts" - } - } - ]; + const accountBlocks: KnownBlock[] = + connectedSections.length > 0 + ? connectedSections + : [ + { + type: "section", + text: { + type: "mrkdwn", + text: "No connected accounts", + }, + }, + ]; return { type: "home", @@ -102,38 +126,38 @@ export async function buildHomeView( type: "header", text: { type: "plain_text", - text: "Junior" - } + text: "Junior", + }, }, { type: "section", text: { type: "mrkdwn", - text: aboutText - } + text: aboutText, + }, }, { type: "divider" }, { type: "header", text: { type: "plain_text", - text: "What I can help with" - } + text: "What I can help with", + }, }, { type: "section", text: { type: "mrkdwn", - text: skillsSummaryText - } + text: skillsSummaryText, + }, }, { type: "divider" }, { type: "header", text: { type: "plain_text", - text: "Connected accounts" - } + text: "Connected accounts", + }, }, ...accountBlocks, { @@ -141,18 +165,18 @@ export async function buildHomeView( elements: [ { type: "mrkdwn", - text: `*junior version:* \`${runtimeMetadata.version ?? "unknown"}\`` - } - ] - } - ] + text: `*junior version:* \`${runtimeMetadata.version ?? "unknown"}\``, + }, + ], + }, + ], }; } export async function publishAppHomeView( slackClient: WebClient, userId: string, - userTokenStore: UserTokenStore + userTokenStore: UserTokenStore, ): Promise { const view = await buildHomeView(userId, userTokenStore); await slackClient.views.publish({ user_id: userId, view }); diff --git a/packages/junior/src/chat/app-runtime.ts b/packages/junior/src/chat/app-runtime.ts index 36ca5898..e462b4f4 100644 --- a/packages/junior/src/chat/app-runtime.ts +++ b/packages/junior/src/chat/app-runtime.ts @@ -264,6 +264,16 @@ export function createAppSlackRuntime< channelId: deps.getChannelId(thread, message), runId: deps.getRunId(thread, message), }); + if (isRetryableTurnError(error, "mcp_auth_resume")) { + deps.logException( + error, + "mention_handler_auth_pause", + errorContext, + { "app.turn.retryable_reason": error.reason }, + "onNewMention parked turn for MCP auth resume", + ); + return; + } if (isRetryableTurnError(error)) { deps.logException( error, @@ -438,6 +448,16 @@ export function createAppSlackRuntime< channelId: deps.getChannelId(thread, message), runId: deps.getRunId(thread, message), }); + if (isRetryableTurnError(error, "mcp_auth_resume")) { + deps.logException( + error, + "subscribed_message_handler_auth_pause", + errorContext, + { "app.turn.retryable_reason": error.reason }, + "onSubscribedMessage parked turn for MCP auth resume", + ); + return; + } if (isRetryableTurnError(error)) { deps.logException( error, diff --git a/packages/junior/src/chat/bootstrap/register-handlers.ts b/packages/junior/src/chat/bootstrap/register-handlers.ts index d271c630..97703bba 100644 --- a/packages/junior/src/chat/bootstrap/register-handlers.ts +++ b/packages/junior/src/chat/bootstrap/register-handlers.ts @@ -1,7 +1,15 @@ import type { Chat } from "chat"; import type { SlackAdapter } from "@chat-adapter/slack"; -import type { AppRuntimeAssistantLifecycleEvent, AppSlackRuntime } from "@/chat/app-runtime"; +import type { + AppRuntimeAssistantLifecycleEvent, + AppSlackRuntime, +} from "@/chat/app-runtime"; import { getUserTokenStore } from "@/chat/capabilities/factory"; +import { + deleteMcpAuthSessionsForUserProvider, + deleteMcpServerSessionId, + deleteMcpStoredOAuthCredentials, +} from "@/chat/mcp/auth-store"; import { logException, withSpan } from "@/chat/observability"; import { publishAppHomeView } from "@/chat/app-home"; import { handleSlashCommand } from "@/chat/slash-command"; @@ -16,10 +24,10 @@ export function registerBotHandlers(args: { bot.onNewMention(appSlackRuntime.handleNewMention); bot.onSubscribedMessage(appSlackRuntime.handleSubscribedMessage); bot.onAssistantThreadStarted((event: AppRuntimeAssistantLifecycleEvent) => - appSlackRuntime.handleAssistantThreadStarted(event) + appSlackRuntime.handleAssistantThreadStarted(event), ); bot.onAssistantContextChanged((event: AppRuntimeAssistantLifecycleEvent) => - appSlackRuntime.handleAssistantContextChanged(event) + appSlackRuntime.handleAssistantContextChanged(event), ); bot.onSlashCommand("/jr", (event) => @@ -31,11 +39,13 @@ export function registerBotHandlers(args: { try { await handleSlashCommand(event); } catch (error) { - logException(error, "slash_command_failed", { slackUserId: event.user.userId }); + logException(error, "slash_command_failed", { + slackUserId: event.user.userId, + }); throw error; } - } - ) + }, + ), ); bot.onAppHomeOpened((event) => @@ -45,12 +55,18 @@ export function registerBotHandlers(args: { { slackUserId: event.userId }, async () => { try { - await publishAppHomeView(getSlackClient(), event.userId, getUserTokenStore()); + await publishAppHomeView( + getSlackClient(), + event.userId, + getUserTokenStore(), + ); } catch (error) { - logException(error, "app_home_opened_failed", { slackUserId: event.userId }); + logException(error, "app_home_opened_failed", { + slackUserId: event.userId, + }); } - } - ) + }, + ), ); bot.onAction("app_home_disconnect", async (event) => { @@ -63,14 +79,28 @@ export function registerBotHandlers(args: { { slackUserId: userId }, async () => { try { - await getUserTokenStore().delete(userId, provider); - await publishAppHomeView(getSlackClient(), userId, getUserTokenStore()); + await Promise.all([ + getUserTokenStore().delete(userId, provider), + deleteMcpStoredOAuthCredentials(userId, provider), + deleteMcpServerSessionId(userId, provider), + deleteMcpAuthSessionsForUserProvider(userId, provider), + ]); + await publishAppHomeView( + getSlackClient(), + userId, + getUserTokenStore(), + ); } catch (error) { - logException(error, "app_home_disconnect_failed", { slackUserId: userId }, { - "app.credential.provider": provider - }); + logException( + error, + "app_home_disconnect_failed", + { slackUserId: userId }, + { + "app.credential.provider": provider, + }, + ); } - } + }, ); }); } diff --git a/packages/junior/src/chat/capabilities/jr-rpc-command.ts b/packages/junior/src/chat/capabilities/jr-rpc-command.ts index 15d81f7b..768a5a95 100644 --- a/packages/junior/src/chat/capabilities/jr-rpc-command.ts +++ b/packages/junior/src/chat/capabilities/jr-rpc-command.ts @@ -7,7 +7,15 @@ import type { UserTokenStore } from "@/chat/credentials/user-token-store"; import { CredentialUnavailableError } from "@/chat/credentials/broker"; import { formatProviderLabel, startOAuthFlow } from "@/chat/oauth-flow"; import { logInfo } from "@/chat/observability"; -import { getPluginOAuthConfig } from "@/chat/plugins/registry"; +import { + deleteMcpAuthSessionsForUserProvider, + deleteMcpServerSessionId, + deleteMcpStoredOAuthCredentials, +} from "@/chat/mcp/auth-store"; +import { + getPluginOAuthConfig, + isPluginProvider, +} from "@/chat/plugins/registry"; import type { Skill } from "@/chat/skills"; type JrRpcDeps = { @@ -364,7 +372,10 @@ async function handleConfigCommand( } function isKnownProvider(provider: string): boolean { - return listCapabilityProviders().some((p) => p.provider === provider); + return ( + listCapabilityProviders().some((p) => p.provider === provider) || + isPluginProvider(provider) + ); } async function handleOAuthStartCommand( @@ -476,7 +487,12 @@ async function handleDeleteTokenCommand( }); } - await deps.userTokenStore.delete(deps.requesterId, provider); + await Promise.all([ + deps.userTokenStore.delete(deps.requesterId, provider), + deleteMcpStoredOAuthCredentials(deps.requesterId, provider), + deleteMcpServerSessionId(deps.requesterId, provider), + deleteMcpAuthSessionsForUserProvider(deps.requesterId, provider), + ]); logInfo( "jr_rpc_delete_token", diff --git a/packages/junior/src/chat/logging.ts b/packages/junior/src/chat/logging.ts index 4eb13ecb..174b8331 100644 --- a/packages/junior/src/chat/logging.ts +++ b/packages/junior/src/chat/logging.ts @@ -97,21 +97,43 @@ const ANSI = { const CONSOLE_PRIORITY_KEYS = [ "app.conversation.id", "app.turn.id", - "app.agent.id", "event.name", "error.message", "messaging.message.id", + "app.trace_id", + "app.span_id", + "app.agent.id", "messaging.message.conversation_id", "messaging.destination.name", "enduser.id", "app.run.id", "app.message.kind", - "app.trace_id", - "app.span_id", ] as const; const CONSOLE_PRIORITY_INDEX: Map = new Map( CONSOLE_PRIORITY_KEYS.map((key, index) => [key, index]), ); +const CONSOLE_ALWAYS_HIDDEN_KEYS = new Set([ + "app.assistant.username", + "app.platform", + "enduser.id", + "enduser.pseudo_id", + "http.request.method", + "messaging.system", + "url.full", + "url.path", + "user_agent.original", +]); +const CONSOLE_DROP_WHEN_COUNTED_KEYS = new Set([ + "app.capability.names", + "app.capability.providers", + "app.config.keys", +]); +const CONSOLE_PREVIEW_KEYS = new Set([ + "gen_ai.input.messages", + "gen_ai.output.messages", + "gen_ai.tool.call.arguments", + "gen_ai.tool.call.result", +]); function getSentryEnvironment(): string { return ( @@ -422,8 +444,134 @@ function formatConsoleValue(value: AttributeValue): string { return quoteConsoleValue(value); } +function shouldShowConsoleDestinationName(eventName: string): boolean { + return /^(app_home_|oauth_|queue_|slash_command_|slack_|webhook_)/.test( + eventName, + ); +} + +function shouldShowConsoleModel(level: LogLevel, eventName: string): boolean { + if (level === "warn" || level === "error") { + return true; + } + + return ( + eventName.startsWith("ai_") || + eventName.startsWith("assistant_") || + eventName === "agent_turn_started" || + eventName === "agent_turn_completed" || + eventName === "agent_turn_provider_error" + ); +} + +function shouldHideConsoleAttribute( + level: LogLevel, + eventName: string, + key: string, + attributes: LogAttributes, +): boolean { + if (CONSOLE_ALWAYS_HIDDEN_KEYS.has(key)) { + return true; + } + if (CONSOLE_DROP_WHEN_COUNTED_KEYS.has(key)) { + return true; + } + if (key === "app.agent.id" && attributes[key] === attributes["app.turn.id"]) { + return true; + } + if ( + key === "messaging.message.conversation_id" && + attributes[key] === attributes["app.conversation.id"] + ) { + return true; + } + if ( + key === "app.message.id" && + attributes[key] === attributes["messaging.message.id"] + ) { + return true; + } + if ( + key === "messaging.destination.name" && + !shouldShowConsoleDestinationName(eventName) + ) { + return true; + } + if ( + key === "gen_ai.request.model" && + !shouldShowConsoleModel(level, eventName) + ) { + return true; + } + if ( + key === "gen_ai.provider.name" && + eventName.startsWith("agent_tool_call_") && + level !== "warn" && + level !== "error" + ) { + return true; + } + if ( + key === "gen_ai.operation.name" && + eventName.startsWith("agent_tool_call_") + ) { + return true; + } + + return false; +} + +function summarizeConsoleString(value: string, maxChars: number): string { + const collapsed = value.replace(/\s+/g, " ").trim(); + if (collapsed.length <= maxChars) { + return collapsed; + } + return `${collapsed.slice(0, maxChars)}... [${collapsed.length} chars]`; +} + +function projectConsoleValue( + level: LogLevel, + key: string, + value: AttributeValue, +): AttributeValue | undefined { + if ( + (level === "debug" || level === "info") && + CONSOLE_PREVIEW_KEYS.has(key) && + typeof value === "string" + ) { + return summarizeConsoleString( + value, + key === "gen_ai.tool.call.result" ? 220 : 140, + ); + } + + return value; +} + +function projectConsoleAttributes( + level: LogLevel, + eventName: string, + attributes: LogAttributes, +): LogAttributes { + const projected: LogAttributes = {}; + + for (const [key, value] of Object.entries(attributes)) { + if (shouldHideConsoleAttribute(level, eventName, key, attributes)) { + continue; + } + + const nextValue = projectConsoleValue(level, key, value); + if (nextValue !== undefined) { + projected[key] = nextValue; + } + } + + return projected; +} + function formatConsoleLine( level: LogLevel, + eventName: string, body: string, attributes: LogAttributes, ): string { @@ -437,7 +585,12 @@ function formatConsoleLine( const parts = [ `${colorize(timestamp, ANSI.gray)} ${colorize(formatConsoleLevel(level), levelColor)} ${body}`, ]; - const sortedAttributes = Object.entries(attributes).sort( + const projectedAttributes = projectConsoleAttributes( + level, + eventName, + attributes, + ); + const sortedAttributes = Object.entries(projectedAttributes).sort( ([left], [right]) => { const leftRank = CONSOLE_PRIORITY_INDEX.get(left); const rightRank = CONSOLE_PRIORITY_INDEX.get(right); @@ -458,7 +611,7 @@ function formatConsoleLine( function emitConsole( level: LogLevel, - _eventName: string, + eventName: string, body: string, attributes: LogAttributes, ): void { @@ -466,7 +619,7 @@ function emitConsole( return; } - const line = formatConsoleLine(level, body, attributes); + const line = formatConsoleLine(level, eventName, body, attributes); if (level === "error") { console.error(line); return; diff --git a/packages/junior/src/chat/mcp/auth-store.ts b/packages/junior/src/chat/mcp/auth-store.ts index be1a3b70..8906ca13 100644 --- a/packages/junior/src/chat/mcp/auth-store.ts +++ b/packages/junior/src/chat/mcp/auth-store.ts @@ -8,8 +8,11 @@ import { getStateAdapter } from "@/chat/state"; const MCP_AUTH_SESSION_PREFIX = "junior:mcp_auth_session"; const MCP_AUTH_CREDENTIALS_PREFIX = "junior:mcp_auth_credentials"; +const MCP_AUTH_SESSION_INDEX_PREFIX = "junior:mcp_auth_session_index"; +const MCP_SERVER_SESSION_PREFIX = "junior:mcp_server_session"; const MCP_AUTH_SESSION_TTL_MS = 24 * 60 * 60 * 1000; const MCP_AUTH_CREDENTIALS_TTL_MS = 30 * 24 * 60 * 60 * 1000; +const MCP_SERVER_SESSION_TTL_MS = 24 * 60 * 60 * 1000; export interface McpAuthSessionState { authSessionId: string; @@ -35,6 +38,11 @@ export interface McpStoredOAuthCredentials { tokens?: OAuthTokens; } +export interface McpServerSessionState { + sessionId: string; + updatedAtMs: number; +} + function sessionKey(authSessionId: string): string { return `${MCP_AUTH_SESSION_PREFIX}:${authSessionId}`; } @@ -43,10 +51,36 @@ function credentialsKey(userId: string, provider: string): string { return `${MCP_AUTH_CREDENTIALS_PREFIX}:${userId}:${provider}`; } +function sessionIndexKey(userId: string, provider: string): string { + return `${MCP_AUTH_SESSION_INDEX_PREFIX}:${userId}:${provider}`; +} + +function serverSessionKey(userId: string, provider: string): string { + return `${MCP_SERVER_SESSION_PREFIX}:${userId}:${provider}`; +} + function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } +function parseSessionIndex(value: unknown): string[] { + if (typeof value !== "string") { + return []; + } + + try { + const parsed = JSON.parse(value) as unknown; + if (!Array.isArray(parsed)) { + return []; + } + return [ + ...new Set(parsed.filter((id): id is string => typeof id === "string")), + ]; + } catch { + return []; + } +} + function parseMcpAuthSession(value: unknown): McpAuthSessionState | undefined { if (typeof value !== "string") { return undefined; @@ -107,6 +141,30 @@ function parseMcpAuthSession(value: unknown): McpAuthSessionState | undefined { } } +function parseServerSession(value: unknown): McpServerSessionState | undefined { + if (typeof value !== "string") { + return undefined; + } + + try { + const parsed = JSON.parse(value) as Record; + if ( + !isRecord(parsed) || + typeof parsed.sessionId !== "string" || + typeof parsed.updatedAtMs !== "number" + ) { + return undefined; + } + + return { + sessionId: parsed.sessionId, + updatedAtMs: parsed.updatedAtMs, + }; + } catch { + return undefined; + } +} + function parseStoredCredentials( value: unknown, ): McpStoredOAuthCredentials | undefined { @@ -155,12 +213,24 @@ export async function putMcpAuthSession( session: McpAuthSessionState, ttlMs: number = MCP_AUTH_SESSION_TTL_MS, ): Promise { - await getStateAdapter().connect(); - await getStateAdapter().set( + const stateAdapter = getStateAdapter(); + await stateAdapter.connect(); + await stateAdapter.set( sessionKey(session.authSessionId), JSON.stringify(session), ttlMs, ); + const nextIndex = parseSessionIndex( + await stateAdapter.get(sessionIndexKey(session.userId, session.provider)), + ); + if (!nextIndex.includes(session.authSessionId)) { + nextIndex.push(session.authSessionId); + } + await stateAdapter.set( + sessionIndexKey(session.userId, session.provider), + JSON.stringify(nextIndex), + ttlMs, + ); } export async function patchMcpAuthSession( @@ -191,8 +261,46 @@ export async function patchMcpAuthSession( export async function deleteMcpAuthSession( authSessionId: string, ): Promise { - await getStateAdapter().connect(); - await getStateAdapter().delete(sessionKey(authSessionId)); + const stateAdapter = getStateAdapter(); + await stateAdapter.connect(); + const current = parseMcpAuthSession( + await stateAdapter.get(sessionKey(authSessionId)), + ); + await stateAdapter.delete(sessionKey(authSessionId)); + if (!current) { + return; + } + + const nextIndex = parseSessionIndex( + await stateAdapter.get(sessionIndexKey(current.userId, current.provider)), + ).filter((id) => id !== authSessionId); + + if (nextIndex.length > 0) { + await stateAdapter.set( + sessionIndexKey(current.userId, current.provider), + JSON.stringify(nextIndex), + MCP_AUTH_SESSION_TTL_MS, + ); + return; + } + + await stateAdapter.delete(sessionIndexKey(current.userId, current.provider)); +} + +export async function deleteMcpAuthSessionsForUserProvider( + userId: string, + provider: string, +): Promise { + const stateAdapter = getStateAdapter(); + await stateAdapter.connect(); + const indexKey = sessionIndexKey(userId, provider); + const authSessionIds = parseSessionIndex(await stateAdapter.get(indexKey)); + + for (const authSessionId of authSessionIds) { + await stateAdapter.delete(sessionKey(authSessionId)); + } + + await stateAdapter.delete(indexKey); } export async function getMcpStoredOAuthCredentials( @@ -218,3 +326,46 @@ export async function putMcpStoredOAuthCredentials( ttlMs, ); } + +export async function deleteMcpStoredOAuthCredentials( + userId: string, + provider: string, +): Promise { + await getStateAdapter().connect(); + await getStateAdapter().delete(credentialsKey(userId, provider)); +} + +export async function getMcpServerSessionId( + userId: string, + provider: string, +): Promise { + await getStateAdapter().connect(); + return parseServerSession( + await getStateAdapter().get(serverSessionKey(userId, provider)), + )?.sessionId; +} + +export async function putMcpServerSessionId( + userId: string, + provider: string, + sessionId: string, + ttlMs: number = MCP_SERVER_SESSION_TTL_MS, +): Promise { + await getStateAdapter().connect(); + await getStateAdapter().set( + serverSessionKey(userId, provider), + JSON.stringify({ + sessionId, + updatedAtMs: Date.now(), + } satisfies McpServerSessionState), + ttlMs, + ); +} + +export async function deleteMcpServerSessionId( + userId: string, + provider: string, +): Promise { + await getStateAdapter().connect(); + await getStateAdapter().delete(serverSessionKey(userId, provider)); +} diff --git a/packages/junior/src/chat/mcp/client.ts b/packages/junior/src/chat/mcp/client.ts index f512031c..ad1d6884 100644 --- a/packages/junior/src/chat/mcp/client.ts +++ b/packages/junior/src/chat/mcp/client.ts @@ -30,11 +30,16 @@ export class McpAuthorizationRequiredError extends Error { export interface PluginMcpClientOptions { authProvider?: OAuthClientProvider; fetch?: typeof fetch; - sessionId?: string; } +type HostManagedSessionProvider = OAuthClientProvider & { + getMcpServerSessionId?: () => Promise; + saveMcpServerSessionId?: (sessionId: string | undefined) => Promise; +}; + export class PluginMcpClient { private client?: Client; + private lastAttemptedTransportSessionId?: string; private transport?: StreamableHTTPClientTransport; private listedTools?: ListedTool[]; @@ -48,53 +53,70 @@ export class PluginMcpClient { return [...this.listedTools]; } - const client = await this.getClient(); - const discovered: ListedTool[] = []; - const seen = new Set(); - let cursor: string | undefined; + return await this.withSessionRecovery(async () => { + const client = await this.getClient(); + const discovered: ListedTool[] = []; + const seen = new Set(); + let cursor: string | undefined; - do { - const result = await this.wrapAuth( - client.listTools(cursor ? { cursor } : undefined), - ); - for (const tool of result.tools) { - if (seen.has(tool.name)) { - continue; + do { + const result = await this.wrapAuth( + client.listTools(cursor ? { cursor } : undefined), + ); + await this.syncTransportSessionId(); + for (const tool of result.tools) { + if (seen.has(tool.name)) { + continue; + } + seen.add(tool.name); + discovered.push(tool); } - seen.add(tool.name); - discovered.push(tool); - } - cursor = result.nextCursor; - } while (cursor); + cursor = result.nextCursor; + } while (cursor); - this.listedTools = discovered.sort((left, right) => - left.name.localeCompare(right.name), - ); - return [...this.listedTools]; + this.listedTools = discovered.sort((left, right) => + left.name.localeCompare(right.name), + ); + return [...this.listedTools]; + }); } async callTool( name: string, args: Record | undefined, ): Promise { - const client = await this.getClient(); - return await this.wrapAuth( - client.callTool({ - name, - ...(args && Object.keys(args).length > 0 ? { arguments: args } : {}), - }), - ); + return await this.withSessionRecovery(async () => { + const client = await this.getClient(); + const result = await this.wrapAuth( + client.callTool({ + name, + ...(args && Object.keys(args).length > 0 ? { arguments: args } : {}), + }), + ); + await this.syncTransportSessionId(); + return result; + }); } async close(): Promise { this.listedTools = undefined; + await this.disposeClient(); + } - const transport = this.transport; - this.transport = undefined; - this.client = undefined; + private async withSessionRecovery( + operation: () => Promise, + ): Promise { + try { + return await operation(); + } catch (error) { + await this.syncTransportSessionId(); + if (!(await this.shouldResetMissingSession(error))) { + throw error; + } - if (transport) { - await transport.close(); + await this.clearStoredTransportSessionId(); + await this.disposeClient(); + return await operation(); } } @@ -115,23 +137,32 @@ export class PluginMcpClient { requestInit.headers = new Headers(mcp.headers); } + const sessionId = await this.getStoredTransportSessionId(); + this.lastAttemptedTransportSessionId = sessionId; const transport = new StreamableHTTPClientTransport(new URL(mcp.url), { ...(Object.keys(requestInit).length > 0 ? { requestInit } : {}), ...(this.options.fetch ? { fetch: this.options.fetch } : {}), ...(this.options.authProvider ? { authProvider: this.options.authProvider } : {}), - ...(this.options.sessionId ? { sessionId: this.options.sessionId } : {}), + ...(sessionId ? { sessionId } : {}), }); const client = new Client(MCP_CLIENT_INFO, { capabilities: {}, }); - await this.wrapAuth(client.connect(transport)); - this.transport = transport; - this.client = client; - return client; + + try { + await this.wrapAuth(client.connect(transport)); + this.client = client; + await this.syncTransportSessionId(); + return client; + } catch (error) { + await this.syncTransportSessionId(); + await this.disposeClient(); + throw error; + } } private async wrapAuth(promise: Promise): Promise { @@ -156,6 +187,60 @@ export class PluginMcpClient { throw error; } } + + private async shouldResetMissingSession(error: unknown): Promise { + if ( + !( + error instanceof StreamableHTTPError && + (error.code === 404 || /Session not found/i.test(error.message)) + ) + ) { + return false; + } + + return Boolean( + this.transport?.sessionId ?? + this.lastAttemptedTransportSessionId ?? + (await this.getStoredTransportSessionId()), + ); + } + + private async disposeClient(): Promise { + const transport = this.transport; + this.transport = undefined; + this.client = undefined; + + if (transport) { + await transport.close(); + } + } + + private async getStoredTransportSessionId(): Promise { + const provider = this.options.authProvider as + | HostManagedSessionProvider + | undefined; + return await provider?.getMcpServerSessionId?.(); + } + + private async clearStoredTransportSessionId(): Promise { + const provider = this.options.authProvider as + | HostManagedSessionProvider + | undefined; + this.lastAttemptedTransportSessionId = undefined; + await provider?.saveMcpServerSessionId?.(undefined); + } + + private async syncTransportSessionId(): Promise { + const provider = this.options.authProvider as + | HostManagedSessionProvider + | undefined; + const sessionId = this.transport?.sessionId; + if (!provider?.saveMcpServerSessionId || !sessionId) { + return; + } + this.lastAttemptedTransportSessionId = sessionId; + await provider.saveMcpServerSessionId(sessionId); + } } export type { diff --git a/packages/junior/src/chat/mcp/oauth-provider.ts b/packages/junior/src/chat/mcp/oauth-provider.ts index b00e63de..2516f2b4 100644 --- a/packages/junior/src/chat/mcp/oauth-provider.ts +++ b/packages/junior/src/chat/mcp/oauth-provider.ts @@ -8,10 +8,15 @@ import type { OAuthDiscoveryState, } from "@modelcontextprotocol/sdk/client/auth.js"; import { + deleteMcpServerSessionId, getMcpAuthSession, + getMcpServerSessionId, getMcpStoredOAuthCredentials, patchMcpAuthSession, + putMcpServerSessionId, + putMcpAuthSession, putMcpStoredOAuthCredentials, + type McpAuthSessionState, } from "./auth-store"; function createClientMetadata(callbackUrl: string): OAuthClientMetadata { @@ -30,6 +35,14 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { constructor( readonly authSessionId: string, private readonly callbackUrl: string, + private readonly sessionContext?: Omit< + McpAuthSessionState, + | "authSessionId" + | "authorizationUrl" + | "codeVerifier" + | "createdAtMs" + | "updatedAtMs" + >, ) { this.clientMetadata = createClientMetadata(callbackUrl); } @@ -43,7 +56,7 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { } async clientInformation(): Promise { - const session = await this.requireSession(); + const session = await this.getCredentialContext(); const credentials = await getMcpStoredOAuthCredentials( session.userId, session.provider, @@ -54,7 +67,7 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { async saveClientInformation( clientInformation: OAuthClientInformationMixed, ): Promise { - const session = await this.requireSession(); + const session = await this.getCredentialContext(); const credentials = (await getMcpStoredOAuthCredentials(session.userId, session.provider)) ?? {}; @@ -65,7 +78,7 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { } async tokens(): Promise { - const session = await this.requireSession(); + const session = await this.getCredentialContext(); const credentials = await getMcpStoredOAuthCredentials( session.userId, session.provider, @@ -74,7 +87,7 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { } async saveTokens(tokens: OAuthTokens): Promise { - const session = await this.requireSession(); + const session = await this.getCredentialContext(); const credentials = (await getMcpStoredOAuthCredentials(session.userId, session.provider)) ?? {}; @@ -85,13 +98,13 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { } async redirectToAuthorization(authorizationUrl: URL): Promise { - await patchMcpAuthSession(this.authSessionId, { + await this.ensureSession({ authorizationUrl: authorizationUrl.toString(), }); } async saveCodeVerifier(codeVerifier: string): Promise { - await patchMcpAuthSession(this.authSessionId, { codeVerifier }); + await this.ensureSession({ codeVerifier }); } async codeVerifier(): Promise { @@ -103,7 +116,7 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { } async saveDiscoveryState(state: OAuthDiscoveryState): Promise { - const session = await this.requireSession(); + const session = await this.getCredentialContext(); const credentials = (await getMcpStoredOAuthCredentials(session.userId, session.provider)) ?? {}; @@ -114,7 +127,7 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { } async discoveryState(): Promise { - const session = await this.requireSession(); + const session = await this.getCredentialContext(); const credentials = await getMcpStoredOAuthCredentials( session.userId, session.provider, @@ -125,7 +138,7 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { async invalidateCredentials( scope: "all" | "client" | "tokens" | "verifier" | "discovery", ): Promise { - const session = await this.requireSession(); + const session = await this.getCredentialContext(); const credentials = (await getMcpStoredOAuthCredentials(session.userId, session.provider)) ?? {}; @@ -149,13 +162,56 @@ export class StateBackedMcpOAuthClientProvider implements OAuthClientProvider { }); if (scope === "verifier" || scope === "all") { - await patchMcpAuthSession(this.authSessionId, { - codeVerifier: undefined, - ...(scope === "all" ? { authorizationUrl: undefined } : {}), - }); + const authSession = await getMcpAuthSession(this.authSessionId); + if (authSession) { + await patchMcpAuthSession(this.authSessionId, { + codeVerifier: undefined, + ...(scope === "all" ? { authorizationUrl: undefined } : {}), + }); + } } } + async getMcpServerSessionId(): Promise { + const session = await this.getCredentialContext(); + return await getMcpServerSessionId(session.userId, session.provider); + } + + async saveMcpServerSessionId(sessionId: string | undefined): Promise { + const session = await this.getCredentialContext(); + if (!sessionId) { + await deleteMcpServerSessionId(session.userId, session.provider); + return; + } + + await putMcpServerSessionId(session.userId, session.provider, sessionId); + } + + private async getCredentialContext() { + return this.sessionContext ?? (await this.requireSession()); + } + + private async ensureSession(patch: Partial) { + const existing = await getMcpAuthSession(this.authSessionId); + if (existing) { + return await patchMcpAuthSession(this.authSessionId, patch); + } + if (!this.sessionContext) { + throw new Error(`Unknown MCP auth session: ${this.authSessionId}`); + } + + const now = Date.now(); + const nextSession: McpAuthSessionState = { + authSessionId: this.authSessionId, + ...this.sessionContext, + ...patch, + createdAtMs: now, + updatedAtMs: now, + }; + await putMcpAuthSession(nextSession); + return nextSession; + } + private async requireSession() { const session = await getMcpAuthSession(this.authSessionId); if (!session) { diff --git a/packages/junior/src/chat/mcp/oauth.ts b/packages/junior/src/chat/mcp/oauth.ts index 743ee867..05f6ba39 100644 --- a/packages/junior/src/chat/mcp/oauth.ts +++ b/packages/junior/src/chat/mcp/oauth.ts @@ -4,11 +4,7 @@ import { resolveBaseUrl } from "@/chat/oauth-flow"; import { getPluginDefinition } from "@/chat/plugins/registry"; import type { PluginDefinition } from "@/chat/plugins/types"; import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; -import { - getMcpAuthSession, - putMcpAuthSession, - type McpAuthSessionState, -} from "./auth-store"; +import { getMcpAuthSession, type McpAuthSessionState } from "./auth-store"; import { StateBackedMcpOAuthClientProvider } from "./oauth-provider"; export function getMcpOAuthCallbackPath(provider: string): string { @@ -44,26 +40,22 @@ export async function createMcpOAuthClientProvider(input: { ); } - const authSessionId = randomUUID(); - const callbackUrl = `${baseUrl}${getMcpOAuthCallbackPath(input.provider)}`; - const session: McpAuthSessionState = { - authSessionId, - provider: input.provider, - userId: input.userId, - conversationId: input.conversationId, - sessionId: input.sessionId, - userMessage: input.userMessage, - createdAtMs: Date.now(), - updatedAtMs: Date.now(), - ...(input.channelId ? { channelId: input.channelId } : {}), - ...(input.threadTs ? { threadTs: input.threadTs } : {}), - ...(input.toolChannelId ? { toolChannelId: input.toolChannelId } : {}), - ...(input.configuration ? { configuration: input.configuration } : {}), - ...(input.artifactState ? { artifactState: input.artifactState } : {}), - }; - await putMcpAuthSession(session); - - return new StateBackedMcpOAuthClientProvider(authSessionId, callbackUrl); + return new StateBackedMcpOAuthClientProvider( + randomUUID(), + `${baseUrl}${getMcpOAuthCallbackPath(input.provider)}`, + { + provider: input.provider, + userId: input.userId, + conversationId: input.conversationId, + sessionId: input.sessionId, + userMessage: input.userMessage, + ...(input.channelId ? { channelId: input.channelId } : {}), + ...(input.threadTs ? { threadTs: input.threadTs } : {}), + ...(input.toolChannelId ? { toolChannelId: input.toolChannelId } : {}), + ...(input.configuration ? { configuration: input.configuration } : {}), + ...(input.artifactState ? { artifactState: input.artifactState } : {}), + }, + ); } export async function finalizeMcpAuthorization( diff --git a/packages/junior/src/chat/mcp/tool-manager.ts b/packages/junior/src/chat/mcp/tool-manager.ts index 57e2a4f6..682a6bf6 100644 --- a/packages/junior/src/chat/mcp/tool-manager.ts +++ b/packages/junior/src/chat/mcp/tool-manager.ts @@ -1,6 +1,4 @@ -import type { AgentTool } from "@mariozechner/pi-agent-core"; import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; -import type { TSchema } from "@sinclair/typebox"; import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"; import type { SkillMetadata } from "@/chat/skills"; import type { PluginDefinition } from "@/chat/plugins/types"; @@ -140,14 +138,36 @@ export interface McpToolManagerOptions { provider: string, error: McpAuthorizationRequiredError, ) => Promise | void; - sessionId?: string; +} + +export interface ManagedMcpToolResult { + content: Array; + details: { + provider: string; + tool: string; + rawResult: PluginMcpToolCallResult; + }; +} + +export interface ManagedMcpToolDescriptor { + name: string; + label: string; + description: string; + parameters: Record; + provider: string; + rawName: string; + title?: string; +} + +interface ManagedMcpTool extends ManagedMcpToolDescriptor { + execute: (args: Record) => Promise; } export class McpToolManager { private readonly pluginsByProvider = new Map(); private readonly activeProviders = new Set(); private readonly clientsByProvider = new Map(); - private readonly toolsByProvider = new Map[]>(); + private readonly toolsByProvider = new Map(); constructor( plugins: PluginDefinition[], @@ -166,20 +186,16 @@ export class McpToolManager { ); } - getActiveTools(): AgentTool[] { - return this.getActiveProviders().flatMap( - (provider) => this.toolsByProvider.get(provider) ?? [], - ); - } - async activateForSkill( - skill: Pick, + skill: Pick, ): Promise { if (!skill.pluginProvider) { return false; } - return await this.activateProvider(skill.pluginProvider); + const activated = await this.activateProvider(skill.pluginProvider); + this.assertSkillToolExposure(skill); + return activated; } async activateProvider(provider: string): Promise { @@ -195,10 +211,10 @@ export class McpToolManager { const client = await this.getClient(plugin); try { - const tools = await client.listTools(); + const tools = this.filterListedTools(plugin, await client.listTools()); this.toolsByProvider.set( provider, - tools.map((tool) => this.toAgentTool(plugin, client, tool)), + tools.map((tool) => this.toManagedTool(plugin, client, tool)), ); this.activeProviders.add(provider); return true; @@ -233,6 +249,90 @@ export class McpToolManager { } } + getActiveToolCatalog( + skills: Array>, + options: { provider?: string } = {}, + ): ManagedMcpToolDescriptor[] { + return this.getResolvedActiveTools(skills, options).map((tool) => ({ + name: tool.name, + label: tool.label, + description: tool.description, + parameters: tool.parameters, + provider: tool.provider, + rawName: tool.rawName, + ...(tool.title ? { title: tool.title } : {}), + })); + } + + searchTools( + skills: Array>, + query: string, + options: { provider?: string; limit?: number } = {}, + ): ManagedMcpToolDescriptor[] { + const resolved = this.getActiveToolCatalog(skills, options); + const trimmedQuery = query.trim(); + if (!trimmedQuery || trimmedQuery === "*") { + return resolved.slice(0, Math.max(1, options.limit ?? 8)); + } + + const normalizedQuery = trimmedQuery.toLowerCase(); + const queryTokens = normalizedQuery + .split(/\s+/) + .map((token) => token.trim()) + .filter((token) => token.length > 0); + + return resolved + .map((tool) => ({ + tool, + score: this.scoreToolMatch(tool, normalizedQuery, queryTokens), + })) + .filter((entry) => entry.score > 0) + .sort((left, right) => { + if (right.score !== left.score) { + return right.score - left.score; + } + return left.tool.name.localeCompare(right.tool.name); + }) + .slice(0, Math.max(1, options.limit ?? 8)) + .map((entry) => entry.tool); + } + + async executeTool( + skills: Array>, + canonicalToolName: string, + args: Record, + ): Promise { + const tool = this.resolveActiveTool(skills, canonicalToolName); + if (!tool) { + throw new Error(`Unknown active MCP tool: ${canonicalToolName}`); + } + + return await tool.execute(args); + } + + private filterListedTools( + plugin: PluginDefinition, + tools: PluginMcpListedTool[], + ): PluginMcpListedTool[] { + const allowedTools = plugin.manifest.mcp?.allowedTools; + if (!allowedTools || allowedTools.length === 0) { + return tools; + } + + const availableToolNames = new Set(tools.map((tool) => tool.name)); + const missingTools = allowedTools.filter( + (toolName) => !availableToolNames.has(toolName), + ); + if (missingTools.length > 0) { + throw new Error( + `Plugin ${plugin.manifest.name} MCP discovery missing allowlisted tools: ${missingTools.join(", ")}`, + ); + } + + const allowedToolSet = new Set(allowedTools); + return tools.filter((tool) => allowedToolSet.has(tool.name)); + } + private async getClient(plugin: PluginDefinition): Promise { const existing = this.clientsByProvider.get(plugin.manifest.name); if (existing) { @@ -245,30 +345,30 @@ export class McpToolManager { const client = new PluginMcpClient(plugin, { ...(authProvider ? { authProvider } : {}), ...(this.options.fetch ? { fetch: this.options.fetch } : {}), - ...(this.options.sessionId ? { sessionId: this.options.sessionId } : {}), }); this.clientsByProvider.set(plugin.manifest.name, client); return client; } - private toAgentTool( + private toManagedTool( plugin: PluginDefinition, client: PluginMcpClient, tool: PluginMcpListedTool, - ): AgentTool { + ): ManagedMcpTool { return { name: normalizeMcpToolName(plugin.manifest.name, tool.name), label: tool.title?.trim() || tool.name, description: describeMcpTool(plugin.manifest.name, tool), - parameters: tool.inputSchema as unknown as TSchema, - execute: async (_toolCallId, params) => { - const args = - typeof params === "object" && params !== null - ? (params as Record) - : {}; + parameters: tool.inputSchema as Record, + provider: plugin.manifest.name, + rawName: tool.name, + ...(tool.title?.trim() ? { title: tool.title.trim() } : {}), + execute: async (args) => { + const resolvedArgs = + typeof args === "object" && args !== null ? args : {}; try { - const result = await client.callTool(tool.name, args); + const result = await client.callTool(tool.name, resolvedArgs); if ("isError" in result && result.isError) { throw new Error(extractMcpErrorMessage(result)); } @@ -296,4 +396,125 @@ export class McpToolManager { }, }; } + + private assertSkillToolExposure( + skill: Pick, + ): void { + const provider = skill.pluginProvider; + if ( + !provider || + !skill.allowedMcpTools || + skill.allowedMcpTools.length === 0 + ) { + return; + } + + const availableToolNames = new Set( + (this.toolsByProvider.get(provider) ?? []).map((tool) => tool.rawName), + ); + const missingTools = skill.allowedMcpTools.filter( + (toolName) => !availableToolNames.has(toolName), + ); + if (missingTools.length > 0) { + throw new Error( + `Skill ${skill.name} declares unavailable MCP tools for plugin ${provider}: ${missingTools.join(", ")}`, + ); + } + } + + private getResolvedActiveTools( + skills: Array>, + options: { provider?: string } = {}, + ): ManagedMcpTool[] { + const resolved: ManagedMcpTool[] = []; + + for (const provider of this.getActiveProviders()) { + if (options.provider && provider !== options.provider) { + continue; + } + + resolved.push(...this.resolveProviderTools(provider, skills)); + } + + return resolved; + } + + private resolveProviderTools( + provider: string, + skills: Array>, + ): ManagedMcpTool[] { + const providerTools = this.toolsByProvider.get(provider) ?? []; + if (providerTools.length === 0) { + return []; + } + + const relevantSkills = skills.filter( + (skill) => skill.pluginProvider === provider, + ); + if (relevantSkills.length === 0) { + return []; + } + + const exposeAllProviderTools = relevantSkills.some( + (skill) => !skill.allowedMcpTools || skill.allowedMcpTools.length === 0, + ); + if (exposeAllProviderTools) { + return providerTools; + } + + const allowedToolNames = new Set( + relevantSkills.flatMap((skill) => skill.allowedMcpTools ?? []), + ); + return providerTools.filter((tool) => allowedToolNames.has(tool.rawName)); + } + + private resolveActiveTool( + skills: Array>, + canonicalToolName: string, + ): ManagedMcpTool | undefined { + return this.getResolvedActiveTools(skills).find( + (tool) => tool.name === canonicalToolName, + ); + } + + private scoreToolMatch( + tool: ManagedMcpToolDescriptor, + normalizedQuery: string, + queryTokens: string[], + ): number { + const exactCandidates = [tool.name, tool.rawName, tool.label, tool.title] + .filter((value): value is string => Boolean(value)) + .map((value) => value.toLowerCase()); + + if (exactCandidates.includes(normalizedQuery)) { + return 100; + } + + let score = 0; + const searchableText = [ + tool.name, + tool.rawName, + tool.label, + tool.title, + tool.description, + tool.provider, + ] + .filter((value): value is string => Boolean(value)) + .join(" ") + .toLowerCase(); + + for (const candidate of exactCandidates) { + if (candidate.startsWith(normalizedQuery)) { + score = Math.max(score, 60); + } + } + + for (const token of queryTokens) { + if (searchableText.includes(token)) { + score += 10; + } + } + + return score; + } } diff --git a/packages/junior/src/chat/plugins/manifest.ts b/packages/junior/src/chat/plugins/manifest.ts index 43727312..d08d09c5 100644 --- a/packages/junior/src/chat/plugins/manifest.ts +++ b/packages/junior/src/chat/plugins/manifest.ts @@ -34,6 +34,41 @@ const trimmedString = z.string().transform((value) => value.trim()); const nonEmptyTrimmedString = trimmedString.pipe( z.string().min(1, { error: "must be a non-empty string" }), ); +const nonEmptyStringArraySchema = ( + fieldName: string, + options: { nonEmptyMessage?: string } = {}, +) => + z + .array(z.string(), { + error: "must be an array of strings when provided", + }) + .min(1, { + error: + options.nonEmptyMessage ?? + "must be a non-empty array of strings when provided", + }) + .transform((values, ctx) => { + const result: string[] = []; + const seen = new Set(); + + for (const rawValue of values) { + const value = rawValue.trim(); + if (!value) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `${fieldName} entries must be non-empty strings`, + }); + return z.NEVER; + } + if (seen.has(value)) { + continue; + } + seen.add(value); + result.push(value); + } + + return result; + }); const envVarString = nonEmptyTrimmedString.refine( (value) => AUTH_TOKEN_ENV_RE.test(value), { @@ -195,6 +230,7 @@ const mcpSourceSchema = z }), url: httpsUrlString, headers: stringMapSchema.optional(), + "allowed-tools": nonEmptyStringArraySchema("allowed-tools").optional(), }) .passthrough(); @@ -534,6 +570,9 @@ function normalizeMcp( ), } : {}), + ...(result.data["allowed-tools"] + ? { allowedTools: result.data["allowed-tools"] } + : {}), } satisfies PluginMcpConfig; } diff --git a/packages/junior/src/chat/plugins/registry.ts b/packages/junior/src/chat/plugins/registry.ts index f3f032ac..712ee686 100644 --- a/packages/junior/src/chat/plugins/registry.ts +++ b/packages/junior/src/chat/plugins/registry.ts @@ -29,6 +29,14 @@ const packageSkillRoots = new Set(); let pluginsLoaded = false; +function getLoggedPluginNames(): Set { + const globalState = globalThis as typeof globalThis & { + __juniorLoggedPluginNames?: Set; + }; + globalState.__juniorLoggedPluginNames ??= new Set(); + return globalState.__juniorLoggedPluginNames; +} + function registerPluginManifest(raw: string, pluginDir: string): void { const manifest = parsePluginManifest(raw, pluginDir); @@ -141,19 +149,28 @@ function loadPlugins(): void { packageSkillRoots.add(skillRoot); } - logInfo( - "plugins_loaded", - {}, - { - "file.directories": [...localRoots, ...packagedContent.manifestRoots], - "app.plugin.count": pluginDefinitions.length, - "app.plugin.names": pluginDefinitions - .map((plugin) => plugin.manifest.name) - .sort(), - "app.plugin.package_skill_roots": [...packageSkillRoots].sort(), - }, - "Loaded plugins", - ); + const loggedPluginNames = getLoggedPluginNames(); + for (const plugin of [...pluginDefinitions].sort((left, right) => + left.manifest.name.localeCompare(right.manifest.name), + )) { + if (loggedPluginNames.has(plugin.manifest.name)) { + continue; + } + loggedPluginNames.add(plugin.manifest.name); + logInfo( + "plugin_loaded", + {}, + { + "app.plugin.name": plugin.manifest.name, + "app.plugin.capability_count": plugin.manifest.capabilities.length, + "app.plugin.config_key_count": plugin.manifest.configKeys.length, + "app.plugin.has_mcp": Boolean(plugin.manifest.mcp), + "file.directory": plugin.dir, + "file.skill_directory": plugin.skillsDir, + }, + "Loaded plugin", + ); + } } function ensurePluginsLoaded(): void { diff --git a/packages/junior/src/chat/plugins/types.ts b/packages/junior/src/chat/plugins/types.ts index 167935a3..0e91d9d7 100644 --- a/packages/junior/src/chat/plugins/types.ts +++ b/packages/junior/src/chat/plugins/types.ts @@ -68,6 +68,7 @@ export interface PluginMcpHttpConfig { transport: "http"; url: string; headers?: Record; + allowedTools?: string[]; } export type PluginMcpConfig = PluginMcpHttpConfig; diff --git a/packages/junior/src/chat/prompt.ts b/packages/junior/src/chat/prompt.ts index 3150576d..9239bff9 100644 --- a/packages/junior/src/chat/prompt.ts +++ b/packages/junior/src/chat/prompt.ts @@ -8,28 +8,40 @@ import type { RuntimeMetadata } from "@/chat/runtime-metadata"; import { sandboxSkillDir } from "@/chat/sandbox/paths"; import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; import type { Skill, SkillMetadata, SkillInvocation } from "@/chat/skills"; +import type { ExposedToolSummary } from "@/chat/tools/mcp-tool-summary"; import { escapeXml } from "@/chat/xml"; const DEFAULT_SOUL = "You are Junior, a practical and concise assistant."; +function getLoggedMarkdownFiles(): Set { + const globalState = globalThis as typeof globalThis & { + __juniorLoggedMarkdownFiles?: Set; + }; + globalState.__juniorLoggedMarkdownFiles ??= new Set(); + return globalState.__juniorLoggedMarkdownFiles; +} + function loadOptionalMarkdownFile( candidates: string[], fileName: string, ): string | null { - const attempted: string[] = []; for (const resolved of candidates) { - attempted.push(resolved); try { const raw = fs.readFileSync(resolved, "utf8").trim(); if (raw.length > 0) { - logInfo( - `${fileName.toLowerCase()}_loaded`, - {}, - { - "file.path": resolved, - }, - `Loaded ${fileName}`, - ); + const loggedMarkdownFiles = getLoggedMarkdownFiles(); + const logKey = `${fileName}:${resolved}`; + if (!loggedMarkdownFiles.has(logKey)) { + loggedMarkdownFiles.add(logKey); + logInfo( + `${fileName.toLowerCase()}_loaded`, + {}, + { + "file.path": resolved, + }, + `Loaded ${fileName}`, + ); + } return raw; } } catch { @@ -178,6 +190,26 @@ function formatLoadedSkillsForPrompt(skills: Skill[]): string { return lines.join("\n"); } +function formatLoadedToolsForPrompt(tools: ExposedToolSummary[]): string { + if (tools.length === 0) { + return "\n"; + } + + const lines = [""]; + for (const tool of tools) { + lines.push( + ` `, + ); + lines.push(` ${escapeXml(tool.description)}`); + lines.push( + ` ${escapeXml(tool.input_schema_summary)}`, + ); + lines.push(" "); + } + lines.push(""); + return lines.join("\n"); +} + function formatProviderCatalogForPrompt(): string { const providers = listCapabilityProviders(); if (providers.length === 0) { @@ -221,6 +253,8 @@ function baseSystemPrompt(): string { "- Never claim you cannot access tools in this turn. If prior results are empty, run tools now.", "- If critical input is missing and cannot be discovered with tools, ask one direct clarifying question.", "- Always gather evidence from available sources (tools or skills) before answering factual questions.", + "- When a loaded skill exposes MCP capabilities, prefer the exact tool_name values disclosed by `loadSkill` or ``, then execute them with `useTool`.", + "- Use `searchTools` only when you need to rediscover or filter active MCP tools.", "- Never guess. If you cannot verify with available sources, say it is unverified.", "- Never claim a lookup succeeded unless a tool result supports it.", "- Do not give up when unsure how to do something; find a viable path, gather evidence, and provide the best actionable way forward.", @@ -231,6 +265,7 @@ function baseSystemPrompt(): string { export function buildSystemPrompt(params: { availableSkills: SkillMetadata[]; activeSkills: Skill[]; + activeTools?: ExposedToolSummary[]; invocation: SkillInvocation | null; assistant?: { userName?: string; @@ -249,6 +284,7 @@ export function buildSystemPrompt(params: { const { availableSkills, activeSkills, + activeTools, invocation, requester, assistant, @@ -287,6 +323,10 @@ export function buildSystemPrompt(params: { "Loaded skills for this turn:", formatLoadedSkillsForPrompt(activeSkills), ].join("\n"); + const activeToolsSection = [ + "Loaded host-managed tools for this turn. Use the exact tool_name values from here or from `loadSkill.available_tools`, and use `searchTools` only when you need to rediscover or filter them:", + formatLoadedToolsForPrompt(activeTools ?? []), + ].join("\n"); const configurationKeys = Object.keys(configuration ?? {}).sort((a, b) => a.localeCompare(b), @@ -441,6 +481,9 @@ export function buildSystemPrompt(params: { "- Do not use reaction-based progress signals; Assistants API status already covers in-progress UX.", "- Prefer `webSearch` before `webFetch` when the user gave no URL.", "- Never call side-effecting tools when the user only asked for analysis or options.", + "- `loadSkill` returns `available_tools` when the loaded skill exposes MCP tools. Use those exact tool_name values instead of guessing.", + "- `searchTools` searches active MCP tools exposed by currently loaded skills when you need to rediscover or filter them.", + "- `useTool` executes a canonical MCP tool name from `loadSkill.available_tools`, ``, or `searchTools`.", ].join("\n"), ), renderTag( @@ -454,6 +497,8 @@ export function buildSystemPrompt(params: { "- Never apply skill-specific behavior unless the skill is present in or `loadSkill` succeeded in this turn.", "- Load only the best matching skill first; do not load multiple skills upfront.", "- After `loadSkill`, use `skill_dir` as the root for any referenced files you read via `bash`.", + "- If a loaded skill exposes MCP tools, prefer the exact tool_name values returned by `loadSkill`, then use `useTool` to execute them.", + "- Use `searchTools` only when you need to rediscover or filter the currently exposed MCP tools.", "- If no skill is a clear fit, continue with normal tool usage.", ].join("\n"), ), @@ -473,6 +518,7 @@ export function buildSystemPrompt(params: { ), availableSkillsSection, activeSkillsSection, + activeToolsSection, renderTag( "invocation-context", invocation diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index 0dca666f..06660f0f 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -1,5 +1,10 @@ import { Agent, type AgentTool } from "@mariozechner/pi-agent-core"; -import type { AssistantMessage, ToolResultMessage } from "@mariozechner/pi-ai"; +import type { + AssistantMessage, + ImageContent, + TextContent, + ToolResultMessage, +} from "@mariozechner/pi-ai"; import { Value } from "@sinclair/typebox/value"; import type { FileUpload } from "chat"; import { botConfig } from "@/chat/config"; @@ -49,6 +54,7 @@ import { SlackActionError } from "@/chat/slack-actions/client"; import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; import { createTools } from "@/chat/tools"; import type { ToolDefinition } from "@/chat/tools/definition"; +import { toExposedToolSummary } from "@/chat/tools/mcp-tool-summary"; import type { ImageGenerateToolDeps } from "@/chat/tools/types"; import { GEN_AI_PROVIDER_NAME, @@ -296,6 +302,8 @@ function formatToolStatus(toolName: string): string { slackListAddItems: "Updating tracking list", slackListUpdateItem: "Updating tracking list", imageGenerate: "Generating image", + searchTools: "Searching active tools", + useTool: "Running active tool", }; if (known[toolName]) { @@ -306,6 +314,24 @@ function formatToolStatus(toolName: string): string { return readable.length > 0 ? `Running ${readable}` : "Running tool"; } +function formatCanonicalToolStatusName(value: unknown): string | undefined { + if (typeof value !== "string") { + return undefined; + } + + const trimmed = value.trim(); + if (!trimmed) { + return undefined; + } + + const mcpMatch = /^mcp__([^_]+)__(.+)$/.exec(trimmed); + if (mcpMatch) { + return compactStatusText(`${mcpMatch[1]}/${mcpMatch[2]}`, 40); + } + + return compactStatusText(trimmed, 40); +} + function formatToolStatusWithInput(toolName: string, input: unknown): string { const obj = input && typeof input === "object" @@ -319,6 +345,10 @@ function formatToolStatusWithInput(toolName: string, input: unknown): string { const skillName = obj ? compactStatusText(obj.skill_name ?? obj.skillName, 40) : undefined; + const provider = obj ? compactStatusText(obj.provider, 20) : undefined; + const activeToolName = obj + ? formatCanonicalToolStatusName(obj.tool_name ?? obj.toolName) + : undefined; if (command && toolName === "bash") { return `Running ${command}`; @@ -338,6 +368,15 @@ function formatToolStatusWithInput(toolName: string, input: unknown): string { if (query && toolName === "webSearch") { return `Searching web for "${query}"`; } + if (query && provider && toolName === "searchTools") { + return `Searching ${provider} tools for "${query}"`; + } + if (query && toolName === "searchTools") { + return `Searching tools for "${query}"`; + } + if (activeToolName && toolName === "useTool") { + return `Running ${activeToolName}`; + } if (domain && toolName === "webFetch") { return `Fetching page from ${domain}`; } @@ -362,6 +401,8 @@ function formatToolResultStatus(toolName: string): string { slackListAddItems: "Preparing list update", slackListUpdateItem: "Preparing list update", imageGenerate: "Preparing generated image", + searchTools: "Reviewing tool matches", + useTool: "Reviewing tool result", }; if (known[toolName]) { @@ -390,6 +431,10 @@ function formatToolResultStatusWithInput( const skillName = obj ? compactStatusText(obj.skill_name ?? obj.skillName, 40) : undefined; + const provider = obj ? compactStatusText(obj.provider, 20) : undefined; + const activeToolName = obj + ? formatCanonicalToolStatusName(obj.tool_name ?? obj.toolName) + : undefined; if (command && toolName === "bash") { return `Reviewed results from ${command}`; @@ -409,6 +454,15 @@ function formatToolResultStatusWithInput( if (query && toolName === "webSearch") { return `Reviewed web results for "${query}"`; } + if (query && provider && toolName === "searchTools") { + return `Reviewed ${provider} tool matches`; + } + if (query && toolName === "searchTools") { + return `Reviewed tool matches for "${query}"`; + } + if (activeToolName && toolName === "useTool") { + return `Reviewed ${activeToolName} result`; + } if (domain && toolName === "webFetch") { return `Reviewed page from ${domain}`; } @@ -506,6 +560,34 @@ function toToolContentText(value: unknown): string { } } +function isStructuredToolExecutionResult(value: unknown): value is { + content: Array; + details: unknown; +} { + const content = (value as { content?: unknown } | null)?.content; + return ( + typeof value === "object" && + value !== null && + Array.isArray(content) && + content.every((part) => { + if (!part || typeof part !== "object") { + return false; + } + const record = part as Record; + if (record.type === "text") { + return typeof record.text === "string"; + } + if (record.type === "image") { + return ( + typeof record.data === "string" && typeof record.mimeType === "string" + ); + } + return false; + }) && + "details" in value + ); +} + export const respondStatusFormatters = { formatToolStatus, formatToolStatusWithInput, @@ -546,6 +628,14 @@ function isAssistantMessage(value: unknown): value is AssistantMessage { ); } +function getPiMessageRole(value: unknown): string | undefined { + if (!value || typeof value !== "object") { + return undefined; + } + const role = (value as { role?: unknown }).role; + return typeof role === "string" ? role : undefined; +} + function extractAssistantText(message: AssistantMessage): string { const content = (message as { content?: Array<{ type?: unknown; text?: unknown }> }) @@ -566,6 +656,7 @@ function upsertActiveSkill(activeSkills: Skill[], next: Skill): void { existing.description = next.description; existing.skillPath = next.skillPath; existing.allowedTools = next.allowedTools; + existing.allowedMcpTools = next.allowedMcpTools; existing.requiresCapabilities = next.requiresCapabilities; existing.usesConfig = next.usesConfig; existing.pluginProvider = next.pluginProvider; @@ -640,24 +731,6 @@ function createAgentTools( turnId: spanContext.turnId, agentId: spanContext.agentId, }; - if (shouldTrace) { - logInfo( - "agent_tool_call_started", - traceToolContext, - { - "gen_ai.provider.name": GEN_AI_PROVIDER_NAME, - "gen_ai.operation.name": "execute_tool", - "gen_ai.tool.name": toolName, - ...(normalizedToolCallId - ? { "gen_ai.tool.call.id": normalizedToolCallId } - : {}), - ...(toolArgumentsAttribute - ? { "gen_ai.tool.call.arguments": toolArgumentsAttribute } - : {}), - }, - "Agent tool call started", - ); - } await onStatus?.(`${formatToolStatusWithInput(toolName, params)}...`); return withSpan( `execute_tool ${toolName}`, @@ -727,26 +800,6 @@ function createAgentTools( await onStatus?.( `${formatToolResultStatusWithInput(toolName, parsed)}...`, ); - if (shouldTrace) { - logInfo( - "agent_tool_call_completed", - traceToolContext, - { - "gen_ai.provider.name": GEN_AI_PROVIDER_NAME, - "gen_ai.operation.name": "execute_tool", - "gen_ai.tool.name": toolName, - ...(normalizedToolCallId - ? { "gen_ai.tool.call.id": normalizedToolCallId } - : {}), - "app.ai.tool_duration_ms": durationMs, - "app.ai.tool_outcome": "success", - ...(toolResultAttribute - ? { "gen_ai.tool.call.result": toolResultAttribute } - : {}), - }, - "Agent tool call completed", - ); - } return { content: [{ type: "text", text: "ok" }], details: resultDetails, @@ -833,7 +886,14 @@ function createAgentTools( } const durationMs = Date.now() - toolStartedAt; - const toolResultAttribute = serializeGenAiAttribute(resultDetails); + const structuredToolResult = isStructuredToolExecutionResult( + resultDetails, + ) + ? resultDetails + : undefined; + const toolResultAttribute = serializeGenAiAttribute( + structuredToolResult?.details ?? resultDetails, + ); setSpanAttributes({ "app.ai.tool_duration_ms": durationMs, "app.ai.tool_outcome": "success", @@ -845,25 +905,8 @@ function createAgentTools( await onStatus?.( `${formatToolResultStatusWithInput(toolName, parsed)}...`, ); - if (shouldTrace) { - logInfo( - "agent_tool_call_completed", - traceToolContext, - { - "gen_ai.provider.name": GEN_AI_PROVIDER_NAME, - "gen_ai.operation.name": "execute_tool", - "gen_ai.tool.name": toolName, - ...(normalizedToolCallId - ? { "gen_ai.tool.call.id": normalizedToolCallId } - : {}), - "app.ai.tool_duration_ms": durationMs, - "app.ai.tool_outcome": "success", - ...(toolResultAttribute - ? { "gen_ai.tool.call.result": toolResultAttribute } - : {}), - }, - "Agent tool call completed", - ); + if (structuredToolResult) { + return structuredToolResult; } return { content: [ @@ -1028,12 +1071,39 @@ export async function generateAssistantReply( canUseTurnSession && sessionConversationId && sessionId ? await getAgentTurnSessionCheckpoint(sessionConversationId, sessionId) : undefined; - const resumedFromCheckpoint = Boolean( + const hasAwaitingResumeCheckpoint = Boolean( existingTurnCheckpoint && existingTurnCheckpoint.state === "awaiting_resume" && existingTurnCheckpoint.piMessages.length > 0, ); - const currentSliceId = resumedFromCheckpoint + const checkpointEndsWithAssistant = Boolean( + hasAwaitingResumeCheckpoint && + getPiMessageRole(existingTurnCheckpoint!.piMessages.at(-1)) === + "assistant", + ); + const resumedFromCheckpoint = Boolean( + hasAwaitingResumeCheckpoint && + !( + existingTurnCheckpoint?.resumeReason === "auth" && + checkpointEndsWithAssistant + ), + ); + if ( + hasAwaitingResumeCheckpoint && + existingTurnCheckpoint?.resumeReason === "auth" && + checkpointEndsWithAssistant + ) { + logWarn( + "agent_turn_resume_replayed_from_prompt", + spanContext, + { + "app.ai.resume_reason": existingTurnCheckpoint.resumeReason, + "app.ai.resume_slice_id": existingTurnCheckpoint.sliceId, + }, + "Replaying auth-paused turn from prompt because the saved Pi checkpoint ended on an assistant message", + ); + } + const currentSliceId = hasAwaitingResumeCheckpoint ? existingTurnCheckpoint!.sliceId : 1; timeoutResumeSliceId = currentSliceId; @@ -1117,11 +1187,15 @@ export async function generateAssistantReply( }; } + timeoutResumeMessages = []; + pendingMcpAuthorizationPause = undefined; const generatedFiles: FileUpload[] = []; const replyFiles: FileUpload[] = []; const artifactStatePatch: Partial = {}; const toolCalls: string[] = []; const mcpAuthSessionIdsByProvider = new Map(); + let agent: Agent | undefined; + mcpToolManager = new McpToolManager(getPluginMcpProviders(), { authProviderFactory: async (plugin) => { if ( @@ -1203,29 +1277,13 @@ export async function generateAssistantReply( pendingMcpAuthorizationPause = new McpAuthorizationPauseError(provider); agent?.abort(); }, - ...(sessionConversationId && sessionId - ? { sessionId: `${sessionConversationId}:${sessionId}` } - : {}), }); const turnMcpToolManager = mcpToolManager; - let agent: Agent | undefined; - let baseAgentTools: AgentTool[] = []; const syncResumeState = () => { loadedSkillNamesForResume = activeSkills.map((skill) => skill.name); activeMcpProvidersForResume = mcpToolManager?.getActiveProviders() ?? []; }; - const refreshAgentTools = () => { - if (!agent) { - return; - } - agent.setTools([ - ...baseAgentTools, - ...turnMcpToolManager.getActiveTools(), - ]); - syncResumeState(); - }; - setTags({ conversationId: spanContext.conversationId, turnId: spanContext.turnId, @@ -1269,7 +1327,19 @@ export async function generateAssistantReply( upsertActiveSkill(activeSkills, effective); syncResumeState(); await turnMcpToolManager.activateForSkill(effective); - refreshAgentTools(); + syncResumeState(); + if (!effective.pluginProvider) { + return undefined; + } + + return { + available_tools: turnMcpToolManager + .getActiveToolCatalog(activeSkills, { + provider: effective.pluginProvider, + }) + .map(toExposedToolSummary), + tool_search_available: true, + }; }, }, { @@ -1279,6 +1349,8 @@ export async function generateAssistantReply( userText: userInput, artifactState: context.artifactState, configuration: configurationValues, + getActiveSkills: () => activeSkills, + mcpToolManager: turnMcpToolManager, sandbox, }, ); @@ -1302,9 +1374,13 @@ export async function generateAssistantReply( } syncResumeState(); + const activeToolSummaries = turnMcpToolManager + .getActiveToolCatalog(activeSkills) + .map(toExposedToolSummary); const baseInstructions = buildSystemPrompt({ availableSkills, activeSkills, + activeTools: activeToolSummaries, invocation: skillInvocation, assistant: context.assistant, requester: context.requester, @@ -1348,7 +1424,7 @@ export async function generateAssistantReply( }, ]); - baseAgentTools = createAgentTools( + const baseAgentTools = createAgentTools( tools as Record>, skillSandbox, spanContext, @@ -1367,7 +1443,7 @@ export async function generateAssistantReply( initialState: { systemPrompt: baseInstructions, model: resolveGatewayModel(botConfig.modelId), - tools: [...baseAgentTools, ...turnMcpToolManager.getActiveTools()], + tools: baseAgentTools, }, }); let hasEmittedText = false; diff --git a/packages/junior/src/chat/skill-frontmatter.ts b/packages/junior/src/chat/skill-frontmatter.ts index 0b83d39c..ad48d7fb 100644 --- a/packages/junior/src/chat/skill-frontmatter.ts +++ b/packages/junior/src/chat/skill-frontmatter.ts @@ -16,6 +16,7 @@ export interface ParsedSkillFile { compatibility?: string; license?: string; allowedTools?: string[]; + allowedMcpTools?: string[]; requiresCapabilities?: string[]; usesConfig?: string[]; } @@ -142,6 +143,12 @@ const skillFrontmatterSchema = z 'Frontmatter field "allowed-tools" must be a string when present', }) .optional(), + "allowed-mcp-tools": z + .string({ + error: + 'Frontmatter field "allowed-mcp-tools" must be a string when present', + }) + .optional(), "requires-capabilities": createTokenFieldSchema( "requires-capabilities", "github.issues.write", @@ -196,6 +203,7 @@ export function parseSkillFile( } const allowedTools = parseTokenList(result.data["allowed-tools"]); + const allowedMcpTools = parseTokenList(result.data["allowed-mcp-tools"]); const requiresCapabilities = parseTokenList( result.data["requires-capabilities"], ); @@ -215,6 +223,7 @@ export function parseSkillFile( ? { license: result.data.license } : {}), ...(allowedTools ? { allowedTools } : {}), + ...(allowedMcpTools ? { allowedMcpTools } : {}), ...(requiresCapabilities ? { requiresCapabilities } : {}), ...(usesConfig ? { usesConfig } : {}), }, diff --git a/packages/junior/src/chat/skills.ts b/packages/junior/src/chat/skills.ts index be08d946..f7a71460 100644 --- a/packages/junior/src/chat/skills.ts +++ b/packages/junior/src/chat/skills.ts @@ -20,6 +20,7 @@ export interface SkillMetadata { skillPath: string; pluginProvider?: string; allowedTools?: string[]; + allowedMcpTools?: string[]; requiresCapabilities?: string[]; usesConfig?: string[]; } @@ -118,6 +119,7 @@ async function readSkillDirectory( name, description, allowedTools, + allowedMcpTools, requiresCapabilities, usesConfig, } = parsed.skill; @@ -145,6 +147,7 @@ async function readSkillDirectory( skillPath: skillDir, ...(plugin ? { pluginProvider: plugin.manifest.name } : {}), allowedTools, + allowedMcpTools, requiresCapabilities, usesConfig, }; diff --git a/packages/junior/src/chat/tools/index.ts b/packages/junior/src/chat/tools/index.ts index fc0a5de2..bfaf210b 100644 --- a/packages/junior/src/chat/tools/index.ts +++ b/packages/junior/src/chat/tools/index.ts @@ -4,6 +4,7 @@ import type { SkillMetadata } from "@/chat/skills"; import { createImageGenerateTool } from "@/chat/tools/image-generate"; import { createLoadSkillTool } from "@/chat/tools/load-skill"; import { createReadFileTool } from "@/chat/tools/read-file"; +import { createSearchToolsTool } from "@/chat/tools/search-tools"; import { createSlackChannelListMessagesTool } from "@/chat/tools/slack-channel-list-messages"; import { createSlackChannelPostMessageTool } from "@/chat/tools/slack-channel-post-message"; import { createSlackMessageAddReactionTool } from "@/chat/tools/slack-message-add-reaction"; @@ -14,6 +15,7 @@ import { createSlackListCreateTool } from "@/chat/tools/slack-list-create"; import { createSlackListGetItemsTool } from "@/chat/tools/slack-list-get-items"; import { createSlackListUpdateItemTool } from "@/chat/tools/slack-list-update-item"; import { createSystemTimeTool } from "@/chat/tools/system-time"; +import { createUseToolTool } from "@/chat/tools/use-tool"; import type { ToolHooks, ToolRuntimeContext, @@ -155,6 +157,19 @@ export function createTools( ), }; + if (context.mcpToolManager && context.getActiveSkills) { + tools.searchTools = wrapToolExecution( + "searchTools", + createSearchToolsTool(context.mcpToolManager, context.getActiveSkills), + hooks, + ); + tools.useTool = wrapToolExecution( + "useTool", + createUseToolTool(context.mcpToolManager, context.getActiveSkills), + hooks, + ); + } + if (isConversationScopedChannel(context.channelId)) { tools.slackCanvasCreate = wrapToolExecution( "slackCanvasCreate", diff --git a/packages/junior/src/chat/tools/load-skill.ts b/packages/junior/src/chat/tools/load-skill.ts index 758d4b2a..16977ecb 100644 --- a/packages/junior/src/chat/tools/load-skill.ts +++ b/packages/junior/src/chat/tools/load-skill.ts @@ -4,6 +4,7 @@ import type { Sandbox } from "@vercel/sandbox"; import { sandboxSkillDir } from "@/chat/sandbox/paths"; import { stripFrontmatter } from "@/chat/skill-frontmatter"; import type { Skill, SkillMetadata } from "@/chat/skills"; +import type { ExposedToolSummary } from "@/chat/tools/mcp-tool-summary"; export type LoadSkillResult = { ok?: boolean; @@ -14,8 +15,15 @@ export type LoadSkillResult = { skill_dir?: string; location?: string; instructions?: string; + available_tools?: ExposedToolSummary[]; + tool_search_available?: boolean; }; +export type LoadSkillMetadata = Pick< + LoadSkillResult, + "available_tools" | "tool_search_available" +>; + function toLoadedSkill(result: LoadSkillResult): Skill | null { if ( result.ok !== true || @@ -73,12 +81,14 @@ export function createLoadSkillTool( sandbox: Sandbox, availableSkills: SkillMetadata[], options?: { - onSkillLoaded?: (skill: Skill) => void | Promise; + onSkillLoaded?: ( + skill: Skill, + ) => void | LoadSkillMetadata | Promise; }, ) { return tool({ description: - "Load a skill by name so its instructions are available for this turn. Use when a request clearly matches a known skill. Do not use when no skill is relevant.", + "Load a skill by name so its instructions are available for this turn. When the skill exposes MCP tools, the result includes `available_tools` with exact tool_name values and argument schemas for this turn. Use when a request clearly matches a known skill. Do not use when no skill is relevant.", inputSchema: Type.Object({ skill_name: Type.String({ minLength: 1, @@ -93,7 +103,10 @@ export function createLoadSkillTool( ); const loadedSkill = toLoadedSkill(result); if (loadedSkill) { - await options?.onSkillLoaded?.(loadedSkill); + const metadata = await options?.onSkillLoaded?.(loadedSkill); + if (metadata) { + Object.assign(result, metadata); + } } return result; }, diff --git a/packages/junior/src/chat/tools/mcp-tool-summary.ts b/packages/junior/src/chat/tools/mcp-tool-summary.ts new file mode 100644 index 00000000..5300d0c2 --- /dev/null +++ b/packages/junior/src/chat/tools/mcp-tool-summary.ts @@ -0,0 +1,43 @@ +import type { ManagedMcpToolDescriptor } from "@/chat/mcp/tool-manager"; + +export interface ExposedToolSummary { + tool_name: string; + provider: string; + description: string; + input_schema: Record; + input_schema_summary: string; +} + +export function summarizeInputSchema(schema: Record): string { + const properties = + schema.properties && typeof schema.properties === "object" + ? (schema.properties as Record) + : {}; + const required = Array.isArray(schema.required) + ? new Set( + schema.required.filter( + (value): value is string => typeof value === "string", + ), + ) + : new Set(); + const propertyNames = Object.keys(properties); + if (propertyNames.length === 0) { + return "No arguments."; + } + + return propertyNames + .map((name) => `${name}${required.has(name) ? " (required)" : ""}`) + .join(", "); +} + +export function toExposedToolSummary( + toolDef: ManagedMcpToolDescriptor, +): ExposedToolSummary { + return { + tool_name: toolDef.name, + provider: toolDef.provider, + description: toolDef.description, + input_schema: toolDef.parameters, + input_schema_summary: summarizeInputSchema(toolDef.parameters), + }; +} diff --git a/packages/junior/src/chat/tools/search-tools.ts b/packages/junior/src/chat/tools/search-tools.ts new file mode 100644 index 00000000..106e729e --- /dev/null +++ b/packages/junior/src/chat/tools/search-tools.ts @@ -0,0 +1,58 @@ +import { Type } from "@sinclair/typebox"; +import type { Skill } from "@/chat/skills"; +import { tool } from "@/chat/tools/definition"; +import type { McpToolManager } from "@/chat/mcp/tool-manager"; +import { toExposedToolSummary } from "@/chat/tools/mcp-tool-summary"; + +const DEFAULT_LIMIT = 5; +const MAX_LIMIT = 20; + +export function createSearchToolsTool( + mcpToolManager: McpToolManager, + getActiveSkills: () => Skill[], +) { + return tool({ + description: + "Search active MCP tools exposed by the currently loaded skills. Use when you need to rediscover or filter tools beyond what `loadSkill` or `` already disclosed.", + inputSchema: Type.Object( + { + query: Type.String({ + minLength: 1, + description: + "Search query for matching MCP tool names or descriptions.", + }), + provider: Type.Optional( + Type.String({ + minLength: 1, + description: + "Optional MCP provider filter, for example notion or sentry.", + }), + ), + limit: Type.Optional( + Type.Integer({ + minimum: 1, + maximum: MAX_LIMIT, + description: "Maximum number of matching tools to return.", + }), + ), + }, + { additionalProperties: false }, + ), + execute: async ({ query, provider, limit }) => { + const results = mcpToolManager + .searchTools(getActiveSkills(), query, { + ...(provider ? { provider } : {}), + limit: limit ?? DEFAULT_LIMIT, + }) + .map(toExposedToolSummary); + + return { + ok: true, + query, + ...(provider ? { provider } : {}), + result_count: results.length, + results, + }; + }, + }); +} diff --git a/packages/junior/src/chat/tools/types.ts b/packages/junior/src/chat/tools/types.ts index 2ce52437..1fba5dfb 100644 --- a/packages/junior/src/chat/tools/types.ts +++ b/packages/junior/src/chat/tools/types.ts @@ -1,7 +1,9 @@ import type { FileUpload } from "chat"; import type { Sandbox } from "@vercel/sandbox"; +import type { McpToolManager } from "@/chat/mcp/tool-manager"; import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; import type { Skill } from "@/chat/skills"; +import type { LoadSkillMetadata } from "@/chat/tools/load-skill"; export interface ImageGenerateToolDeps { fetch?: typeof fetch; @@ -14,7 +16,9 @@ export interface ToolHooks { onArtifactStatePatch?: (patch: Partial) => void; onToolCallStart?: (toolName: string, input?: unknown) => void | Promise; onToolCallEnd?: (toolName: string, input?: unknown) => void | Promise; - onSkillLoaded?: (skill: Skill) => void | Promise; + onSkillLoaded?: ( + skill: Skill, + ) => void | LoadSkillMetadata | Promise; toolOverrides?: { imageGenerate?: ImageGenerateToolDeps; }; @@ -27,6 +31,8 @@ export interface ToolRuntimeContext { userText?: string; artifactState?: ThreadArtifactsState; configuration?: Record; + getActiveSkills?: () => Skill[]; + mcpToolManager?: McpToolManager; sandbox: Sandbox; } diff --git a/packages/junior/src/chat/tools/use-tool.ts b/packages/junior/src/chat/tools/use-tool.ts new file mode 100644 index 00000000..b60bc902 --- /dev/null +++ b/packages/junior/src/chat/tools/use-tool.ts @@ -0,0 +1,62 @@ +import { validateToolArguments } from "@mariozechner/pi-ai"; +import { Type } from "@sinclair/typebox"; +import type { Skill } from "@/chat/skills"; +import { tool } from "@/chat/tools/definition"; +import type { McpToolManager } from "@/chat/mcp/tool-manager"; + +function normalizeToolArguments( + value: Record | undefined, +): Record { + return value ?? {}; +} + +export function createUseToolTool( + mcpToolManager: McpToolManager, + getActiveSkills: () => Skill[], +) { + return tool({ + description: + "Execute an active MCP tool by canonical tool_name. Use tool_name values disclosed by `loadSkill`, ``, or `searchTools`.", + inputSchema: Type.Object( + { + tool_name: Type.String({ + minLength: 1, + description: + "Canonical MCP tool name in the form mcp____.", + }), + arguments: Type.Optional( + Type.Object( + {}, + { + additionalProperties: true, + description: "Arguments for the selected MCP tool.", + }, + ), + ), + }, + { additionalProperties: false }, + ), + execute: async ({ tool_name, arguments: rawArguments }) => { + const activeSkills = getActiveSkills(); + const toolCatalog = mcpToolManager.getActiveToolCatalog(activeSkills); + const toolDef = toolCatalog.find((entry) => entry.name === tool_name); + if (!toolDef) { + throw new Error(`Unknown active MCP tool: ${tool_name}`); + } + + const validatedArguments = validateToolArguments( + toolDef as never, + { + name: tool_name, + arguments: normalizeToolArguments(rawArguments), + } as never, + ) as Record; + + return await mcpToolManager.executeTool( + activeSkills, + tool_name, + validatedArguments, + ); + }, + }); +} diff --git a/packages/junior/src/handlers/mcp-oauth-callback.ts b/packages/junior/src/handlers/mcp-oauth-callback.ts index 92bed56b..0e3cab76 100644 --- a/packages/junior/src/handlers/mcp-oauth-callback.ts +++ b/packages/junior/src/handlers/mcp-oauth-callback.ts @@ -1,15 +1,13 @@ import { Buffer } from "node:buffer"; import { after } from "next/server"; import { ThreadImpl, type FileUpload } from "chat"; -import { createElement } from "react"; -import { renderToStaticMarkup } from "react-dom/server"; import { botConfig } from "@/chat/config"; import { coerceThreadConversationState } from "@/chat/conversation-state"; import type { ChannelConfigurationService } from "@/chat/configuration/types"; import { deleteMcpAuthSession } from "@/chat/mcp/auth-store"; import { buildSlackOutputMessage } from "@/chat/output"; import { finalizeMcpAuthorization } from "@/chat/mcp/oauth"; -import { logException } from "@/chat/observability"; +import { logException, logWarn } from "@/chat/observability"; import { generateAssistantReply, type AssistantReply } from "@/chat/respond"; import { mergeArtifactsState, @@ -30,55 +28,28 @@ import { coerceThreadArtifactsState } from "@/chat/slack-actions/types"; import { truncateStatusText } from "@/chat/status-format"; import { markTurnCompleted, markTurnFailed } from "@/chat/turn/persist"; import { resolveReplyDelivery } from "@/chat/turn/execute"; +import { isRetryableTurnError } from "@/chat/turn/errors"; +import { escapeXml } from "@/chat/xml"; function htmlResponse( title: string, message: string, status: number, ): Response { - const html = renderToStaticMarkup( - createElement( - "html", - null, - createElement("head", null, createElement("title", null, title)), - createElement( - "body", - { - style: { - fontFamily: "system-ui, sans-serif", - display: "flex", - justifyContent: "center", - alignItems: "center", - minHeight: "100vh", - margin: 0, - }, - }, - createElement( - "div", - { - style: { - textAlign: "center", - maxWidth: 480, - }, - }, - createElement("h1", null, title), - createElement("p", null, message), - createElement( - "p", - { - style: { - marginTop: "2rem", - color: "#666", - fontSize: "0.9em", - }, - }, - "You can close this tab and return to Slack.", - ), - ), - ), - ), - ); - return new Response(`${html}`, { + const safeTitle = escapeXml(title); + const safeMessage = escapeXml(message); + const html = ` + +${safeTitle} + +
+

${safeTitle}

+

${safeMessage}

+

You can close this tab and return to Slack.

+
+ +`; + return new Response(html, { status, headers: { "Content-Type": "text/html; charset=utf-8" }, }); @@ -505,6 +476,15 @@ export async function GET( } } catch (resumeError) { postStatus.stop(); + if (isRetryableTurnError(resumeError, "mcp_auth_resume")) { + logWarn( + "mcp_oauth_callback_resume_reparked_for_auth", + {}, + { "app.credential.provider": provider }, + "Resumed MCP turn requested another authorization flow", + ); + return; + } logException( resumeError, "mcp_oauth_callback_resume_failed", diff --git a/packages/junior/tests/app-home.test.ts b/packages/junior/tests/app-home.test.ts index 3c45d5a0..08b1d01f 100644 --- a/packages/junior/tests/app-home.test.ts +++ b/packages/junior/tests/app-home.test.ts @@ -2,8 +2,12 @@ import fs from "node:fs"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { KnownBlock, SectionBlock } from "@slack/web-api"; import { buildHomeView, publishAppHomeView } from "@/chat/app-home"; -import type { UserTokenStore, StoredTokens } from "@/chat/credentials/user-token-store"; +import type { + UserTokenStore, + StoredTokens, +} from "@/chat/credentials/user-token-store"; import { discoverSkills } from "@/chat/skills"; +import { getMcpStoredOAuthCredentials } from "@/chat/mcp/auth-store"; vi.mock("@/chat/plugins/registry", () => ({ getPluginProviders: () => [ @@ -12,64 +16,85 @@ vi.mock("@/chat/plugins/registry", () => ({ name: "sentry", description: "Sentry provider", credentials: { - type: "oauth-bearer" - } - } + type: "oauth-bearer", + }, + }, + }, + { + manifest: { + name: "notion", + description: "Notion provider", + mcp: { + transport: "http", + url: "https://mcp.notion.com/mcp", + }, + }, }, { manifest: { name: "github", description: "GitHub provider", credentials: { - type: "github-app" - } - } + type: "github-app", + }, + }, }, { manifest: { name: "example-bundle", - description: "Bundle-only plugin" - } - } - ] + description: "Bundle-only plugin", + }, + }, + ], })); vi.mock("@/chat/home", () => ({ - homeDir: () => "/mock/app" + homeDir: () => "/mock/app", +})); + +vi.mock("@/chat/mcp/auth-store", () => ({ + getMcpStoredOAuthCredentials: vi.fn(async () => undefined), })); vi.mock("@/chat/skills", () => ({ - discoverSkills: vi.fn(async () => []) + discoverSkills: vi.fn(async () => []), })); -function createMockTokenStore(tokens: Record): UserTokenStore { +function createMockTokenStore( + tokens: Record, +): UserTokenStore { return { get: vi.fn(async (_userId: string, provider: string) => tokens[provider]), set: vi.fn(async () => {}), - delete: vi.fn(async () => {}) + delete: vi.fn(async () => {}), }; } const validToken: StoredTokens = { accessToken: "xoxp-test", refreshToken: "xoxr-test", - expiresAt: Date.now() + 3600_000 + expiresAt: Date.now() + 3600_000, }; const expiredToken: StoredTokens = { accessToken: "xoxp-expired", refreshToken: "xoxr-expired", - expiresAt: Date.now() - 1000 + expiresAt: Date.now() - 1000, }; -function findSection(blocks: KnownBlock[], predicate: (section: SectionBlock) => boolean): SectionBlock | undefined { +function findSection( + blocks: KnownBlock[], + predicate: (section: SectionBlock) => boolean, +): SectionBlock | undefined { return blocks.find((block) => { const section = block as SectionBlock; return section.type === "section" && predicate(section); }) as SectionBlock | undefined; } -function getVersionText(view: Awaited>): string | undefined { +function getVersionText( + view: Awaited>, +): string | undefined { const versionBlock = view.blocks[view.blocks.length - 1] as { type: string; elements?: Array<{ text?: string }>; @@ -93,6 +118,8 @@ describe("buildHomeView", () => { beforeEach(() => { readFileSpy = vi.spyOn(fs, "readFileSync").mockReturnValue("About text"); + vi.mocked(getMcpStoredOAuthCredentials).mockReset(); + vi.mocked(getMcpStoredOAuthCredentials).mockResolvedValue(undefined); }); afterEach(() => { @@ -121,8 +148,9 @@ describe("buildHomeView", () => { const view = await buildHomeView("U123", store); expect(view.type).toBe("home"); - const section = findSection(view.blocks, (candidate) => - candidate.text?.text.includes("sentry") ?? false + const section = findSection( + view.blocks, + (candidate) => candidate.text?.text.includes("sentry") ?? false, ); expect(section).toBeDefined(); if (!section) { @@ -134,13 +162,39 @@ describe("buildHomeView", () => { expect(accessory.value).toBe("sentry"); }); + it("shows connected MCP provider with Unlink button", async () => { + vi.mocked(getMcpStoredOAuthCredentials).mockResolvedValue({ + tokens: { + access_token: "token", + token_type: "bearer", + }, + }); + + const store = createMockTokenStore({}); + const view = await buildHomeView("U123", store); + + const section = findSection( + view.blocks, + (candidate) => candidate.text?.text.includes("notion") ?? false, + ); + expect(section).toBeDefined(); + if (!section) { + throw new Error("Expected connected account section for notion"); + } + + const accessory = section.accessory as { action_id: string; value: string }; + expect(accessory.action_id).toBe("app_home_disconnect"); + expect(accessory.value).toBe("notion"); + }); + it("shows 'No connected accounts' when user has no tokens", async () => { const store = createMockTokenStore({}); const view = await buildHomeView("U123", store); expect(view.type).toBe("home"); - const noAccountsSection = findSection(view.blocks, (candidate) => - candidate.text?.text === "No connected accounts" + const noAccountsSection = findSection( + view.blocks, + (candidate) => candidate.text?.text === "No connected accounts", ); expect(noAccountsSection).toBeDefined(); }); @@ -149,25 +203,35 @@ describe("buildHomeView", () => { const store = createMockTokenStore({ sentry: expiredToken }); const view = await buildHomeView("U123", store); - const section = findSection(view.blocks, (candidate) => - candidate.text?.text.includes("sentry") ?? false + const section = findSection( + view.blocks, + (candidate) => candidate.text?.text.includes("sentry") ?? false, ); expect(section?.text?.text).toContain("sentry"); }); it("excludes github-app providers (no per-user auth)", async () => { - // github-app tokens would never be in the user token store, but even if - // the store returned something, buildHomeView skips non-oauth-bearer providers. + // github-app tokens would never be in the user token store, and + // buildHomeView skips providers without oauth-bearer or MCP-backed auth. const store = createMockTokenStore({ github: validToken }); const view = await buildHomeView("U123", store); - const noAccountsSection = findSection(view.blocks, (candidate) => - candidate.text?.text === "No connected accounts" + const noAccountsSection = findSection( + view.blocks, + (candidate) => candidate.text?.text === "No connected accounts", ); expect(noAccountsSection).toBeDefined(); // github provider is github-app type, so store.get should not be called for it expect(store.get).not.toHaveBeenCalledWith("U123", "github"); expect(store.get).not.toHaveBeenCalledWith("U123", "example-bundle"); + expect(getMcpStoredOAuthCredentials).not.toHaveBeenCalledWith( + "U123", + "github", + ); + expect(getMcpStoredOAuthCredentials).not.toHaveBeenCalledWith( + "U123", + "example-bundle", + ); }); it("loads ABOUT.md from app root for home intro text", async () => { @@ -187,15 +251,27 @@ describe("buildHomeView", () => { const view = await buildHomeView("U123", store); expect(getAllSectionText(view.blocks)).toContain( - "I help your team investigate, summarize, and act on work in Slack." + "I help your team investigate, summarize, and act on work in Slack.", ); }); it("shows available skills as read-only list", async () => { vi.mocked(discoverSkills).mockResolvedValue([ - { name: "incident-summary", description: "Summarize incidents", skillPath: "/skills/incident-summary" }, - { name: "release-check", description: "Check release health", skillPath: "/skills/release-check" }, - { name: "jr-rpc", description: "Internal credential ops", skillPath: "/skills/jr-rpc" } + { + name: "incident-summary", + description: "Summarize incidents", + skillPath: "/skills/incident-summary", + }, + { + name: "release-check", + description: "Check release health", + skillPath: "/skills/release-check", + }, + { + name: "jr-rpc", + description: "Internal credential ops", + skillPath: "/skills/jr-rpc", + }, ]); const store = createMockTokenStore({}); @@ -213,8 +289,8 @@ describe("publishAppHomeView", () => { const store = createMockTokenStore({ sentry: validToken }); const mockClient = { views: { - publish: vi.fn(async () => ({ ok: true })) - } + publish: vi.fn(async () => ({ ok: true })), + }, }; await publishAppHomeView(mockClient as never, "U123", store); @@ -225,9 +301,9 @@ describe("publishAppHomeView", () => { user_id: "U123", view: expect.objectContaining({ type: "home", - blocks: expect.arrayContaining([expect.anything()]) - }) - }) + blocks: expect.arrayContaining([expect.anything()]), + }), + }), ); }); }); diff --git a/packages/junior/tests/bot-handlers.test.ts b/packages/junior/tests/bot-handlers.test.ts index f0335be0..3169002f 100644 --- a/packages/junior/tests/bot-handlers.test.ts +++ b/packages/junior/tests/bot-handlers.test.ts @@ -491,6 +491,48 @@ describe("bot handlers (integration)", () => { expect(lastMessage?.meta?.skippedReason).toBeUndefined(); }); + it("parks MCP auth resume turns without rethrowing to the queue", async () => { + const { appSlackRuntime, setBotDepsForTests } = await import("@/chat/bot"); + const { RetryableTurnError } = await import("@/chat/turn/errors"); + setBotDepsForTests({ + generateAssistantReply: async () => { + throw new RetryableTurnError("mcp_auth_resume", "simulated auth pause"); + }, + listThreadReplies: async () => [], + }); + + const thread = createTestThread({ id: "slack:C_AUTH:1700000000.000" }); + await expect( + appSlackRuntime.handleNewMention( + thread, + createTestMessage({ + id: "msg-auth-pause", + threadId: "slack:C_AUTH:1700000000.000", + text: "please use notion", + isMention: true, + }), + ), + ).resolves.toBeUndefined(); + + expect(thread.posts).toHaveLength(0); + const state = thread.getState(); + const conversation = ( + state as { + conversation?: { + processing?: { activeTurnId?: string }; + messages?: Array<{ + meta?: { replied?: boolean; skippedReason?: string }; + }>; + }; + } + ).conversation; + expect(conversation?.processing?.activeTurnId).toBe("turn_msg-auth-pause"); + const lastMessage = + conversation?.messages?.[conversation.messages.length - 1]; + expect(lastMessage?.meta?.replied).toBeUndefined(); + expect(lastMessage?.meta?.skippedReason).toBeUndefined(); + }); + it("posts terminal failure text after streamed partial output", async () => { const { appSlackRuntime, setBotDepsForTests } = await import("@/chat/bot"); setBotDepsForTests({ diff --git a/packages/junior/tests/jr-rpc-command.test.ts b/packages/junior/tests/jr-rpc-command.test.ts index 5bedaddb..eb88bf46 100644 --- a/packages/junior/tests/jr-rpc-command.test.ts +++ b/packages/junior/tests/jr-rpc-command.test.ts @@ -1,4 +1,14 @@ -import { describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const { + deleteMcpAuthSessionsForUserProviderMock, + deleteMcpServerSessionIdMock, + deleteMcpStoredOAuthCredentialsMock, +} = vi.hoisted(() => ({ + deleteMcpAuthSessionsForUserProviderMock: vi.fn(), + deleteMcpServerSessionIdMock: vi.fn(), + deleteMcpStoredOAuthCredentialsMock: vi.fn(), +})); vi.mock("@/chat/capabilities/catalog", () => ({ getCapabilityProvider: (capability: string) => @@ -21,9 +31,19 @@ vi.mock("@/chat/capabilities/catalog", () => ({ capabilities: ["sentry.api"], configKeys: ["sentry.org", "sentry.project"], }, - { provider: "notion", capabilities: ["notion.api"], configKeys: [] }, ], })); +vi.mock("@/chat/mcp/auth-store", () => ({ + deleteMcpAuthSessionsForUserProvider: + deleteMcpAuthSessionsForUserProviderMock, + deleteMcpServerSessionId: deleteMcpServerSessionIdMock, + deleteMcpStoredOAuthCredentials: deleteMcpStoredOAuthCredentialsMock, +})); +vi.mock("@/chat/plugins/registry", () => ({ + getPluginOAuthConfig: () => undefined, + isPluginProvider: (provider: string) => + provider === "github" || provider === "sentry" || provider === "notion", +})); import { maybeExecuteJrRpcCustomCommand } from "@/chat/capabilities/jr-rpc-command"; import { SkillCapabilityRuntime } from "@/chat/capabilities/runtime"; import { createChannelConfigurationService } from "@/chat/configuration/service"; @@ -85,6 +105,49 @@ function makeRuntime( } describe("jr-rpc custom command", () => { + beforeEach(() => { + deleteMcpAuthSessionsForUserProviderMock.mockReset(); + deleteMcpAuthSessionsForUserProviderMock.mockResolvedValue(undefined); + deleteMcpServerSessionIdMock.mockReset(); + deleteMcpServerSessionIdMock.mockResolvedValue(undefined); + deleteMcpStoredOAuthCredentialsMock.mockReset(); + deleteMcpStoredOAuthCredentialsMock.mockResolvedValue(undefined); + }); + + it("deletes both legacy and MCP-backed provider credentials", async () => { + const userTokenStore = { + get: vi.fn(async () => undefined), + set: vi.fn(async () => undefined), + delete: vi.fn(async () => undefined), + }; + + const result = await maybeExecuteJrRpcCustomCommand( + "jr-rpc delete-token notion", + { + capabilityRuntime: makeRuntime(), + activeSkill, + requesterId: "U123", + userTokenStore, + }, + ); + + expect(result.handled).toBe(true); + if (result.handled) { + expect(result.result.exit_code).toBe(0); + expect(result.result.stdout).toContain("token_deleted provider=notion"); + } + expect(userTokenStore.delete).toHaveBeenCalledWith("U123", "notion"); + expect(deleteMcpStoredOAuthCredentialsMock).toHaveBeenCalledWith( + "U123", + "notion", + ); + expect(deleteMcpServerSessionIdMock).toHaveBeenCalledWith("U123", "notion"); + expect(deleteMcpAuthSessionsForUserProviderMock).toHaveBeenCalledWith( + "U123", + "notion", + ); + }); + it("does not handle non jr-rpc commands", async () => { const result = await maybeExecuteJrRpcCustomCommand("echo hi", { capabilityRuntime: makeRuntime(), diff --git a/packages/junior/tests/mcp-oauth-callback.test.ts b/packages/junior/tests/mcp-oauth-callback.test.ts index 39d30952..08816aa0 100644 --- a/packages/junior/tests/mcp-oauth-callback.test.ts +++ b/packages/junior/tests/mcp-oauth-callback.test.ts @@ -7,6 +7,7 @@ const { deleteMcpAuthSessionMock, finalizeMcpAuthorizationMock, generateAssistantReplyMock, + logWarnMock, markConversationMessageMock, markTurnCompletedMock, markTurnFailedMock, @@ -25,6 +26,7 @@ const { deleteMcpAuthSessionMock: vi.fn(), finalizeMcpAuthorizationMock: vi.fn(), generateAssistantReplyMock: vi.fn(), + logWarnMock: vi.fn(), markConversationMessageMock: vi.fn(), markTurnCompletedMock: vi.fn(), markTurnFailedMock: vi.fn(), @@ -84,6 +86,7 @@ vi.mock("@/chat/slack-actions/client", () => ({ vi.mock("@/chat/observability", () => ({ logException: vi.fn(), + logWarn: logWarnMock, })); vi.mock("@/chat/conversation-state", () => ({ @@ -132,6 +135,7 @@ describe("mcp oauth callback handler", () => { deleteMcpAuthSessionMock.mockReset(); finalizeMcpAuthorizationMock.mockReset(); generateAssistantReplyMock.mockReset(); + logWarnMock.mockReset(); markConversationMessageMock.mockReset(); markTurnCompletedMock.mockReset(); markTurnFailedMock.mockReset(); @@ -470,4 +474,30 @@ describe("mcp oauth callback handler", () => { text: "MCP authorization completed, but resuming the request failed. Please retry the original command.", }); }); + + it("re-parks the resumed turn when another MCP auth challenge is required", async () => { + const { RetryableTurnError } = await import("@/chat/turn/errors"); + generateAssistantReplyMock.mockRejectedValueOnce( + new RetryableTurnError("mcp_auth_resume", "auth required again"), + ); + + const response = await GET( + makeRequest( + "https://example.com/api/oauth/callback/mcp/demo?code=auth-code&state=state-123", + ), + makeContext("demo"), + ); + + expect(response.status).toBe(200); + await afterCallbacks[0]!(); + + expect(logWarnMock).toHaveBeenCalledWith( + "mcp_oauth_callback_resume_reparked_for_auth", + {}, + { "app.credential.provider": "demo" }, + "Resumed MCP turn requested another authorization flow", + ); + expect(markTurnFailedMock).not.toHaveBeenCalled(); + expect(postMessageMock).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/junior/tests/plugin-registry-packages.test.ts b/packages/junior/tests/plugin-registry-packages.test.ts index 2321fb08..354bc67a 100644 --- a/packages/junior/tests/plugin-registry-packages.test.ts +++ b/packages/junior/tests/plugin-registry-packages.test.ts @@ -325,6 +325,34 @@ async function writePackagedPluginWithMcp(tempRoot: string): Promise { " url: https://mcp.example.com", " headers:", ' X-Workspace: "acme"', + " allowed-tools:", + " - search", + " - fetch", + ].join("\n"), + "utf8", + ); +} + +async function writePackagedPluginWithInvalidMcpAllowedTools( + tempRoot: string, +): Promise { + const packageRoot = path.join( + tempRoot, + "node_modules", + "@acme", + "junior-plugin-mcp-invalid-allowed-tools", + ); + const skillsDir = path.join(packageRoot, "skills", "demo"); + await fs.mkdir(skillsDir, { recursive: true }); + await fs.writeFile( + path.join(packageRoot, "plugin.yaml"), + [ + "name: demo", + "description: Demo MCP plugin", + "mcp:", + " transport: http", + " url: https://mcp.example.com", + ' allowed-tools: "search"', ].join("\n"), "utf8", ); @@ -808,12 +836,41 @@ describe("plugin registry package discovery", () => { headers: { "X-Workspace": "acme", }, + allowedTools: ["search", "fetch"], }); expect( registry.getPluginMcpProviders().map((plugin) => plugin.manifest.name), ).toEqual(["demo"]); }); + it("rejects invalid MCP allowed-tools declarations", async () => { + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "junior-plugin-package-"), + ); + await writePackagedPluginWithInvalidMcpAllowedTools(tempRoot); + await fs.writeFile( + path.join(tempRoot, "package.json"), + JSON.stringify({ + name: "temp-junior-app", + private: true, + dependencies: { + "@acme/junior-plugin-mcp-invalid-allowed-tools": "1.0.0", + }, + }), + "utf8", + ); + process.chdir(tempRoot); + + vi.resetModules(); + vi.doMock("@/chat/home", () => ({ + pluginRoots: () => [], + })); + + await expect(import("@/chat/plugins/registry")).rejects.toThrow( + "Plugin demo mcp.allowed-tools must be an array of strings when provided", + ); + }); + it("rejects Authorization in plugin MCP headers", async () => { const tempRoot = await fs.mkdtemp( path.join(os.tmpdir(), "junior-plugin-package-"), diff --git a/packages/junior/tests/respond-status-formatters.test.ts b/packages/junior/tests/respond-status-formatters.test.ts index fbd98f55..892e8dc2 100644 --- a/packages/junior/tests/respond-status-formatters.test.ts +++ b/packages/junior/tests/respond-status-formatters.test.ts @@ -36,4 +36,28 @@ describe("respond status formatters", () => { }), ).toBe("Updated file app.ts"); }); + + it("keeps MCP dispatcher statuses functional", () => { + expect( + respondStatusFormatters.formatToolStatusWithInput("searchTools", { + query: "holiday schedule", + }), + ).toBe('Searching tools for "holiday schedule"'); + expect( + respondStatusFormatters.formatToolStatusWithInput("searchTools", { + query: "holiday schedule", + provider: "notion", + }), + ).toBe('Searching notion tools for "holiday schedule"'); + expect( + respondStatusFormatters.formatToolStatusWithInput("useTool", { + tool_name: "mcp__notion__notion-search", + }), + ).toBe("Running notion/notion-search"); + expect( + respondStatusFormatters.formatToolResultStatusWithInput("useTool", { + tool_name: "mcp__notion__notion-search", + }), + ).toBe("Reviewed notion/notion-search result"); + }); }); diff --git a/packages/junior/tests/skill-frontmatter.test.ts b/packages/junior/tests/skill-frontmatter.test.ts index dac76067..6411f01b 100644 --- a/packages/junior/tests/skill-frontmatter.test.ts +++ b/packages/junior/tests/skill-frontmatter.test.ts @@ -104,6 +104,25 @@ describe("skill frontmatter validation", () => { ]); }); + it("accepts valid allowed-mcp-tools tokens", () => { + const raw = [ + "---", + "name: brief", + "description: Create a candidate brief from public engineering signals.", + "allowed-mcp-tools: notion-search notion-fetch", + "---", + "", + "# Body", + ].join("\n"); + + const result = parseSkillFile(raw, "brief"); + expect(result.ok).toBe(true); + expect(result.ok ? result.skill.allowedMcpTools : null).toEqual([ + "notion-search", + "notion-fetch", + ]); + }); + it("rejects invalid uses-config tokens", () => { const raw = [ "---", diff --git a/packages/junior/tests/unit/logging-context.test.ts b/packages/junior/tests/unit/logging-context.test.ts index ba81c6d1..8edb026e 100644 --- a/packages/junior/tests/unit/logging-context.test.ts +++ b/packages/junior/tests/unit/logging-context.test.ts @@ -110,12 +110,172 @@ describe("logging context ids", () => { const line = String(infoSpy.mock.calls[0]?.[0] ?? ""); const conversationIndex = line.indexOf("app.conversation.id="); const turnIndex = line.indexOf("app.turn.id="); - const agentIndex = line.indexOf("app.agent.id="); const eventNameIndex = line.indexOf("event.name="); expect(conversationIndex).toBeGreaterThan(-1); expect(turnIndex).toBeGreaterThan(conversationIndex); - expect(agentIndex).toBeGreaterThan(turnIndex); - expect(eventNameIndex).toBeGreaterThan(agentIndex); + expect(eventNameIndex).toBeGreaterThan(turnIndex); + expect(line).not.toContain("app.agent.id="); + }); + + it("suppresses noisy ambient context in dev console output", async () => { + vi.stubEnv("NODE_ENV", "development"); + const { log, withLogContext } = await import("@/chat/logging"); + const infoSpy = vi + .spyOn(console, "info") + .mockImplementation(() => undefined); + + try { + await withLogContext( + { + conversationId: "slack:C123:1710000000.001", + turnId: "turn-3", + agentId: "turn-3", + platform: "slack", + slackThreadId: "slack:C123:1710000000.001", + slackChannelId: "C123", + slackUserId: "U123", + slackUserName: "dcramer", + assistantUserName: "junior", + modelId: "anthropic/claude-sonnet-4.6", + httpMethod: "POST", + httpPath: "/api/webhooks/slack", + urlFull: "https://junior.example.com/api/webhooks/slack", + userAgent: "Slackbot 1.0", + }, + async () => { + log.info( + "agent_message_in", + { + "app.message.id": "1710000000.002", + "app.message.kind": "user_inbound", + "messaging.message.id": "1710000000.002", + }, + "Agent message received", + ); + }, + ); + } finally { + vi.unstubAllEnvs(); + } + + expect(infoSpy).toHaveBeenCalledTimes(1); + const line = String(infoSpy.mock.calls[0]?.[0] ?? ""); + expect(line).toContain("app.conversation.id=slack:C123:1710000000.001"); + expect(line).toContain("app.turn.id=turn-3"); + expect(line).toContain("event.name=agent_message_in"); + expect(line).toContain("messaging.message.id=1710000000.002"); + expect(line).not.toContain("app.agent.id="); + expect(line).not.toContain("app.platform="); + expect(line).not.toContain("messaging.system="); + expect(line).not.toContain("messaging.destination.name="); + expect(line).not.toContain("messaging.message.conversation_id="); + expect(line).not.toContain("enduser.id="); + expect(line).not.toContain("enduser.pseudo_id="); + expect(line).not.toContain("app.assistant.username="); + expect(line).not.toContain("http.request.method="); + expect(line).not.toContain("url.path="); + expect(line).not.toContain("url.full="); + expect(line).not.toContain("user_agent.original="); + expect(line).not.toContain("app.message.id="); + }); + + it("keeps sink records rich while compacting info-level console payload previews", async () => { + vi.stubEnv("NODE_ENV", "development"); + const { log, registerLogRecordSink } = await import("@/chat/logging"); + const infoSpy = vi + .spyOn(console, "info") + .mockImplementation(() => undefined); + const records: Array> = []; + const unregister = registerLogRecordSink((record) => { + records.push(record.attributes); + }); + const repeated = "LONGPAYLOAD".repeat(60); + + try { + log.info( + "agent_tool_call_completed", + { + "gen_ai.tool.name": "loadSkill", + "gen_ai.tool.call.result": JSON.stringify({ + ok: true, + description: "Loaded notion skill", + instructions: repeated, + }), + }, + "Agent tool call completed", + ); + } finally { + unregister(); + vi.unstubAllEnvs(); + } + + expect(records).toHaveLength(1); + expect(records[0]?.["gen_ai.tool.call.result"]).toContain(repeated); + const line = String(infoSpy.mock.calls[0]?.[0] ?? ""); + expect(line).toContain("gen_ai.tool.call.result="); + expect(line).toContain("["); + expect(line.length).toBeLessThan(500); + }); + + it("keeps full payload details in warn-level console output", async () => { + vi.stubEnv("NODE_ENV", "development"); + const { log } = await import("@/chat/logging"); + const warnSpy = vi + .spyOn(console, "warn") + .mockImplementation(() => undefined); + const payload = `prefix-${"LONGPAYLOAD".repeat(20)}-suffix`; + + try { + log.warn( + "agent_tool_call_failed", + { + "gen_ai.tool.name": "loadSkill", + "gen_ai.tool.call.result": payload, + }, + "Agent tool call failed", + ); + } finally { + vi.unstubAllEnvs(); + } + + const line = String(warnSpy.mock.calls[0]?.[0] ?? ""); + expect(line).toContain(payload); + expect(line).not.toContain("[246 chars]"); + }); + + it("shows counts without dumping catalog arrays in console output", async () => { + vi.stubEnv("NODE_ENV", "development"); + const { log } = await import("@/chat/logging"); + const infoSpy = vi + .spyOn(console, "info") + .mockImplementation(() => undefined); + + try { + log.info( + "capability_catalog_loaded", + { + "app.capability.count": 5, + "app.capability.names": [ + "github.issues.comment", + "github.issues.read", + "sentry.api", + ], + "app.capability.providers": ["github", "notion", "sentry"], + "app.config.key_count": 3, + "app.config.keys": ["github.repo", "sentry.org", "sentry.project"], + }, + "Loaded capability provider catalog", + ); + } finally { + vi.unstubAllEnvs(); + } + + const line = String(infoSpy.mock.calls[0]?.[0] ?? ""); + expect(line).toContain("app.capability.count=5"); + expect(line).toContain("app.config.key_count=3"); + expect(line).not.toContain("app.capability.names="); + expect(line).not.toContain("app.capability.providers="); + expect(line).not.toContain("app.config.keys="); }); it("redacts PEM private key bodies without regex backtracking", async () => { diff --git a/packages/junior/tests/unit/mcp/auth-store.test.ts b/packages/junior/tests/unit/mcp/auth-store.test.ts new file mode 100644 index 00000000..5aa75178 --- /dev/null +++ b/packages/junior/tests/unit/mcp/auth-store.test.ts @@ -0,0 +1,113 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +const ORIGINAL_ENV = { ...process.env }; + +function buildSession( + authSessionId: string, + overrides: Partial<{ + provider: string; + userId: string; + conversationId: string; + sessionId: string; + userMessage: string; + }> = {}, +) { + return { + authSessionId, + provider: overrides.provider ?? "notion", + userId: overrides.userId ?? "U123", + conversationId: overrides.conversationId ?? "conversation-1", + sessionId: overrides.sessionId ?? `turn-${authSessionId}`, + userMessage: overrides.userMessage ?? "test notion skill", + createdAtMs: 1, + updatedAtMs: 1, + }; +} + +describe("MCP auth session store", () => { + beforeEach(async () => { + process.env = { + ...ORIGINAL_ENV, + JUNIOR_STATE_ADAPTER: "memory", + }; + vi.resetModules(); + const { disconnectStateAdapter } = await import("@/chat/state"); + await disconnectStateAdapter(); + }); + + afterEach(async () => { + const { disconnectStateAdapter } = await import("@/chat/state"); + await disconnectStateAdapter(); + vi.resetModules(); + process.env = { ...ORIGINAL_ENV }; + }); + + it("deletes every pending auth session for one user/provider pair", async () => { + const { + deleteMcpAuthSessionsForUserProvider, + getMcpAuthSession, + putMcpAuthSession, + } = await import("@/chat/mcp/auth-store"); + + await putMcpAuthSession(buildSession("auth-1")); + await putMcpAuthSession(buildSession("auth-2")); + await putMcpAuthSession(buildSession("auth-3", { provider: "github" })); + await putMcpAuthSession(buildSession("auth-4", { userId: "U999" })); + + await deleteMcpAuthSessionsForUserProvider("U123", "notion"); + + await expect(getMcpAuthSession("auth-1")).resolves.toBeUndefined(); + await expect(getMcpAuthSession("auth-2")).resolves.toBeUndefined(); + await expect(getMcpAuthSession("auth-3")).resolves.toEqual( + expect.objectContaining({ authSessionId: "auth-3" }), + ); + await expect(getMcpAuthSession("auth-4")).resolves.toEqual( + expect.objectContaining({ authSessionId: "auth-4" }), + ); + }); + + it("keeps bulk deletion working after one sibling session is removed directly", async () => { + const { + deleteMcpAuthSession, + deleteMcpAuthSessionsForUserProvider, + getMcpAuthSession, + putMcpAuthSession, + } = await import("@/chat/mcp/auth-store"); + + await putMcpAuthSession(buildSession("auth-1")); + await putMcpAuthSession(buildSession("auth-2")); + await putMcpAuthSession(buildSession("auth-3", { provider: "github" })); + + await deleteMcpAuthSession("auth-1"); + await deleteMcpAuthSessionsForUserProvider("U123", "notion"); + + await expect(getMcpAuthSession("auth-1")).resolves.toBeUndefined(); + await expect(getMcpAuthSession("auth-2")).resolves.toBeUndefined(); + await expect(getMcpAuthSession("auth-3")).resolves.toEqual( + expect.objectContaining({ authSessionId: "auth-3" }), + ); + }); + + it("stores and clears the opaque MCP server session per user/provider", async () => { + const { + deleteMcpServerSessionId, + getMcpServerSessionId, + putMcpServerSessionId, + } = await import("@/chat/mcp/auth-store"); + + await putMcpServerSessionId("U123", "notion", "mcp-session-1"); + + await expect(getMcpServerSessionId("U123", "notion")).resolves.toBe( + "mcp-session-1", + ); + await expect(getMcpServerSessionId("U123", "github")).resolves.toBe( + undefined, + ); + + await deleteMcpServerSessionId("U123", "notion"); + + await expect(getMcpServerSessionId("U123", "notion")).resolves.toBe( + undefined, + ); + }); +}); diff --git a/packages/junior/tests/unit/mcp/client.test.ts b/packages/junior/tests/unit/mcp/client.test.ts new file mode 100644 index 00000000..f88df4fa --- /dev/null +++ b/packages/junior/tests/unit/mcp/client.test.ts @@ -0,0 +1,221 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"; + +const { callToolMock, connectMock, listToolsMock, transportOptions } = + vi.hoisted(() => ({ + callToolMock: vi.fn(), + connectMock: vi.fn(), + listToolsMock: vi.fn(), + transportOptions: [] as Array>, + })); + +vi.mock("@modelcontextprotocol/sdk/client/auth.js", () => { + class UnauthorizedError extends Error { + constructor(message?: string) { + super(message ?? "Unauthorized"); + this.name = "UnauthorizedError"; + } + } + + return { + UnauthorizedError, + }; +}); + +vi.mock("@modelcontextprotocol/sdk/client/streamableHttp.js", () => { + class StreamableHTTPError extends Error { + readonly code: number | undefined; + + constructor(code: number | undefined, message: string | undefined) { + super(`Streamable HTTP error: ${message}`); + this.code = code; + this.name = "StreamableHTTPError"; + } + } + + class StreamableHTTPClientTransport { + sessionId?: string; + + constructor( + _url: URL, + options?: { + sessionId?: string; + }, + ) { + this.sessionId = options?.sessionId; + transportOptions.push({ ...(options ?? {}) }); + } + + async close() {} + } + + return { + StreamableHTTPClientTransport, + StreamableHTTPError, + }; +}); + +vi.mock("@modelcontextprotocol/sdk/client", () => ({ + Client: class Client { + private transport?: { sessionId?: string }; + + constructor() {} + + async connect(transport: { sessionId?: string }) { + this.transport = transport; + return await connectMock(transport); + } + + async listTools(args?: unknown) { + return await listToolsMock(this.transport, args); + } + + async callTool(args: unknown) { + return await callToolMock(this.transport, args); + } + }, +})); + +import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js"; +import { StreamableHTTPError } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; +import { + McpAuthorizationRequiredError, + PluginMcpClient, +} from "@/chat/mcp/client"; + +function buildPlugin() { + return { + dir: "/tmp/plugins/notion", + skillsDir: "/tmp/plugins/notion/skills", + manifest: { + name: "notion", + description: "Notion MCP", + capabilities: [], + configKeys: [], + mcp: { + transport: "http" as const, + url: "https://mcp.notion.com/mcp", + }, + }, + }; +} + +function buildAuthProvider() { + return { + getMcpServerSessionId: vi.fn<() => Promise>(), + saveMcpServerSessionId: + vi.fn<(sessionId: string | undefined) => Promise>(), + redirectUrl: "https://junior.example.com/api/oauth/callback/mcp/notion", + clientMetadata: { + client_name: "Junior MCP Client", + redirect_uris: [ + "https://junior.example.com/api/oauth/callback/mcp/notion", + ], + grant_types: ["authorization_code", "refresh_token"], + response_types: ["code"], + token_endpoint_auth_method: "none", + }, + state: vi.fn(async () => "auth-state"), + clientInformation: vi.fn(async () => undefined), + saveClientInformation: vi.fn(async () => undefined), + tokens: vi.fn(async () => undefined), + saveTokens: vi.fn(async () => undefined), + redirectToAuthorization: vi.fn(async () => undefined), + saveCodeVerifier: vi.fn(async () => undefined), + codeVerifier: vi.fn(async () => "code-verifier"), + } satisfies OAuthClientProvider & { + getMcpServerSessionId: () => Promise; + saveMcpServerSessionId: (sessionId: string | undefined) => Promise; + }; +} + +describe("PluginMcpClient", () => { + beforeEach(() => { + callToolMock.mockReset(); + connectMock.mockReset(); + listToolsMock.mockReset(); + transportOptions.length = 0; + }); + + it("reuses and refreshes host-managed MCP server session ids", async () => { + const authProvider = buildAuthProvider(); + authProvider.getMcpServerSessionId.mockResolvedValue("stored-session"); + authProvider.saveMcpServerSessionId.mockResolvedValue(undefined); + connectMock.mockImplementation( + async (transport: { sessionId?: string }) => { + transport.sessionId = "server-session"; + }, + ); + listToolsMock.mockResolvedValue({ + tools: [ + { + name: "notion-search", + title: "Search", + inputSchema: { type: "object", properties: {} }, + }, + ], + nextCursor: undefined, + }); + + const client = new PluginMcpClient(buildPlugin(), { authProvider }); + + await expect(client.listTools()).resolves.toHaveLength(1); + expect(transportOptions[0]).toMatchObject({ sessionId: "stored-session" }); + expect(authProvider.saveMcpServerSessionId).toHaveBeenCalledWith( + "server-session", + ); + }); + + it("persists the server-issued MCP session before surfacing an auth challenge", async () => { + const authProvider = buildAuthProvider(); + authProvider.getMcpServerSessionId.mockResolvedValue(undefined); + authProvider.saveMcpServerSessionId.mockResolvedValue(undefined); + connectMock.mockImplementation( + async (transport: { sessionId?: string }) => { + transport.sessionId = "auth-session"; + throw new UnauthorizedError("auth required"); + }, + ); + + const client = new PluginMcpClient(buildPlugin(), { authProvider }); + + await expect(client.listTools()).rejects.toBeInstanceOf( + McpAuthorizationRequiredError, + ); + expect(authProvider.saveMcpServerSessionId).toHaveBeenCalledWith( + "auth-session", + ); + }); + + it("clears a stale MCP server session and retries once with a fresh transport", async () => { + const authProvider = buildAuthProvider(); + authProvider.getMcpServerSessionId + .mockResolvedValueOnce("stale-session") + .mockResolvedValue(undefined); + authProvider.saveMcpServerSessionId.mockResolvedValue(undefined); + connectMock + .mockRejectedValueOnce(new StreamableHTTPError(404, "Session not found")) + .mockImplementationOnce(async (transport: { sessionId?: string }) => { + transport.sessionId = "fresh-session"; + }); + listToolsMock.mockResolvedValue({ + tools: [ + { + name: "notion-search", + title: "Search", + inputSchema: { type: "object", properties: {} }, + }, + ], + nextCursor: undefined, + }); + + const client = new PluginMcpClient(buildPlugin(), { authProvider }); + + await expect(client.listTools()).resolves.toHaveLength(1); + expect(authProvider.saveMcpServerSessionId).toHaveBeenCalledWith(undefined); + expect(transportOptions).toEqual([ + { authProvider, sessionId: "stale-session" }, + { authProvider }, + ]); + }); +}); diff --git a/packages/junior/tests/unit/mcp/oauth-provider.test.ts b/packages/junior/tests/unit/mcp/oauth-provider.test.ts index 6ed1bed7..2c63866c 100644 --- a/packages/junior/tests/unit/mcp/oauth-provider.test.ts +++ b/packages/junior/tests/unit/mcp/oauth-provider.test.ts @@ -1,21 +1,33 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const { + deleteMcpServerSessionIdMock, getMcpAuthSessionMock, + getMcpServerSessionIdMock, getMcpStoredOAuthCredentialsMock, patchMcpAuthSessionMock, + putMcpServerSessionIdMock, + putMcpAuthSessionMock, putMcpStoredOAuthCredentialsMock, } = vi.hoisted(() => ({ + deleteMcpServerSessionIdMock: vi.fn(), getMcpAuthSessionMock: vi.fn(), + getMcpServerSessionIdMock: vi.fn(), getMcpStoredOAuthCredentialsMock: vi.fn(), patchMcpAuthSessionMock: vi.fn(), + putMcpServerSessionIdMock: vi.fn(), + putMcpAuthSessionMock: vi.fn(), putMcpStoredOAuthCredentialsMock: vi.fn(), })); vi.mock("@/chat/mcp/auth-store", () => ({ + deleteMcpServerSessionId: deleteMcpServerSessionIdMock, getMcpAuthSession: getMcpAuthSessionMock, + getMcpServerSessionId: getMcpServerSessionIdMock, getMcpStoredOAuthCredentials: getMcpStoredOAuthCredentialsMock, patchMcpAuthSession: patchMcpAuthSessionMock, + putMcpServerSessionId: putMcpServerSessionIdMock, + putMcpAuthSession: putMcpAuthSessionMock, putMcpStoredOAuthCredentials: putMcpStoredOAuthCredentialsMock, })); @@ -23,9 +35,13 @@ import { StateBackedMcpOAuthClientProvider } from "@/chat/mcp/oauth-provider"; describe("StateBackedMcpOAuthClientProvider.invalidateCredentials", () => { beforeEach(() => { + deleteMcpServerSessionIdMock.mockReset(); getMcpAuthSessionMock.mockReset(); + getMcpServerSessionIdMock.mockReset(); getMcpStoredOAuthCredentialsMock.mockReset(); patchMcpAuthSessionMock.mockReset(); + putMcpServerSessionIdMock.mockReset(); + putMcpAuthSessionMock.mockReset(); putMcpStoredOAuthCredentialsMock.mockReset(); getMcpAuthSessionMock.mockResolvedValue({ @@ -48,7 +64,11 @@ describe("StateBackedMcpOAuthClientProvider.invalidateCredentials", () => { token_type: "Bearer", }, }); + deleteMcpServerSessionIdMock.mockResolvedValue(undefined); + getMcpServerSessionIdMock.mockResolvedValue(undefined); putMcpStoredOAuthCredentialsMock.mockResolvedValue(undefined); + putMcpServerSessionIdMock.mockResolvedValue(undefined); + putMcpAuthSessionMock.mockResolvedValue(undefined); patchMcpAuthSessionMock.mockResolvedValue(undefined); }); @@ -95,4 +115,88 @@ describe("StateBackedMcpOAuthClientProvider.invalidateCredentials", () => { authorizationUrl: undefined, }); }); + + it("reads stored credentials without requiring a persisted auth session", async () => { + getMcpAuthSessionMock.mockResolvedValue(undefined); + + const provider = new StateBackedMcpOAuthClientProvider( + "auth-session-1", + "https://junior.example.com/callback", + { + provider: "demo", + userId: "U123", + conversationId: "conversation-1", + sessionId: "turn-1", + userMessage: "/demo", + }, + ); + + await expect(provider.tokens()).resolves.toEqual({ + access_token: "access", + token_type: "Bearer", + }); + expect(getMcpStoredOAuthCredentialsMock).toHaveBeenCalledWith( + "U123", + "demo", + ); + }); + + it("creates the auth session lazily when redirecting to authorization", async () => { + getMcpAuthSessionMock.mockResolvedValue(undefined); + + const provider = new StateBackedMcpOAuthClientProvider( + "auth-session-1", + "https://junior.example.com/callback", + { + provider: "demo", + userId: "U123", + conversationId: "conversation-1", + sessionId: "turn-1", + userMessage: "/demo", + channelId: "C123", + }, + ); + + await provider.redirectToAuthorization( + new URL("https://example.com/oauth/start"), + ); + + expect(putMcpAuthSessionMock).toHaveBeenCalledWith( + expect.objectContaining({ + authSessionId: "auth-session-1", + provider: "demo", + userId: "U123", + conversationId: "conversation-1", + sessionId: "turn-1", + userMessage: "/demo", + channelId: "C123", + authorizationUrl: "https://example.com/oauth/start", + }), + ); + expect(patchMcpAuthSessionMock).not.toHaveBeenCalled(); + }); + + it("stores the opaque MCP server session outside agent-visible state", async () => { + const provider = new StateBackedMcpOAuthClientProvider( + "auth-session-1", + "https://junior.example.com/callback", + { + provider: "demo", + userId: "U123", + conversationId: "conversation-1", + sessionId: "turn-1", + userMessage: "/demo", + }, + ); + + await provider.saveMcpServerSessionId("mcp-session-123"); + + expect(putMcpServerSessionIdMock).toHaveBeenCalledWith( + "U123", + "demo", + "mcp-session-123", + ); + await expect(provider.getMcpServerSessionId()).resolves.toBeUndefined(); + expect(getMcpServerSessionIdMock).toHaveBeenCalledWith("U123", "demo"); + }); }); diff --git a/packages/junior/tests/unit/mcp/tool-manager.test.ts b/packages/junior/tests/unit/mcp/tool-manager.test.ts index 7f9d4513..670ade0b 100644 --- a/packages/junior/tests/unit/mcp/tool-manager.test.ts +++ b/packages/junior/tests/unit/mcp/tool-manager.test.ts @@ -1,13 +1,19 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { PluginDefinition } from "@/chat/plugins/types"; -const { callToolMock, closeMock, listToolsMock, onAuthorizationRequiredMock } = - vi.hoisted(() => ({ - callToolMock: vi.fn(), - closeMock: vi.fn(), - listToolsMock: vi.fn(), - onAuthorizationRequiredMock: vi.fn(), - })); +const { + callToolMock, + clientOptions, + closeMock, + listToolsMock, + onAuthorizationRequiredMock, +} = vi.hoisted(() => ({ + callToolMock: vi.fn(), + clientOptions: [] as unknown[], + closeMock: vi.fn(), + listToolsMock: vi.fn(), + onAuthorizationRequiredMock: vi.fn(), +})); vi.mock("@/chat/mcp/client", () => { class MockMcpAuthorizationRequiredError extends Error { @@ -21,7 +27,12 @@ vi.mock("@/chat/mcp/client", () => { } class MockPluginMcpClient { - constructor(private readonly plugin: PluginDefinition) {} + constructor( + private readonly plugin: PluginDefinition, + options?: unknown, + ) { + clientOptions.push(options); + } async listTools() { return await listToolsMock(this.plugin); @@ -45,7 +56,10 @@ vi.mock("@/chat/mcp/client", () => { import { McpAuthorizationRequiredError } from "@/chat/mcp/client"; import { McpToolManager } from "@/chat/mcp/tool-manager"; -function buildPlugin(name = "demo"): PluginDefinition { +function buildPlugin( + name = "demo", + options: { allowedTools?: string[] } = {}, +): PluginDefinition { return { dir: `/tmp/plugins/${name}`, skillsDir: `/tmp/plugins/${name}/skills`, @@ -57,6 +71,7 @@ function buildPlugin(name = "demo"): PluginDefinition { mcp: { transport: "http", url: "https://mcp.example.com", + ...(options.allowedTools ? { allowedTools: options.allowedTools } : {}), }, }, }; @@ -68,6 +83,7 @@ describe("McpToolManager", () => { callToolMock.mockReset(); closeMock.mockReset(); onAuthorizationRequiredMock.mockReset(); + clientOptions.length = 0; listToolsMock.mockResolvedValue([ { @@ -93,24 +109,26 @@ describe("McpToolManager", () => { it("activates plugin-scoped MCP tools once and prefixes their names", async () => { const plugin = buildPlugin(); const manager = new McpToolManager([plugin]); + const activeSkills = [{ name: "demo-skill", pluginProvider: "demo" }]; - expect(await manager.activateForSkill({ pluginProvider: undefined })).toBe( - false, - ); - expect(await manager.activateForSkill({ pluginProvider: "demo" })).toBe( - true, - ); + expect( + await manager.activateForSkill({ + name: "demo-skill", + pluginProvider: undefined, + }), + ).toBe(false); + expect(await manager.activateForSkill(activeSkills[0]!)).toBe(true); expect(await manager.activateProvider("demo")).toBe(false); expect(manager.getActiveProviders()).toEqual(["demo"]); - const tools = manager.getActiveTools(); + const tools = manager.getActiveToolCatalog(activeSkills); expect(tools).toHaveLength(1); expect(tools[0]?.name).toBe("mcp__demo__ping"); expect(tools[0]?.description).toBe("[demo] Ping the remote MCP server"); - const result = await tools[0]!.execute("call-1", { + const result = await manager.executeTool(activeSkills, "mcp__demo__ping", { query: "hello", - } as never); + }); expect(callToolMock).toHaveBeenCalledWith(plugin, "ping", { query: "hello", @@ -129,6 +147,10 @@ describe("McpToolManager", () => { await manager.close(); expect(closeMock).toHaveBeenCalledTimes(1); + expect(clientOptions).not.toContainEqual( + expect.objectContaining({ sessionId: expect.any(String) }), + ); + expect(manager.getActiveToolCatalog(activeSkills)).toEqual([]); }); it("surfaces MCP authorization challenges through the callback hook", async () => { @@ -136,15 +158,15 @@ describe("McpToolManager", () => { const manager = new McpToolManager([plugin], { onAuthorizationRequired: onAuthorizationRequiredMock, }); + const activeSkills = [{ name: "demo-skill", pluginProvider: "demo" }]; await manager.activateProvider("demo"); callToolMock.mockRejectedValueOnce( new McpAuthorizationRequiredError("demo", "Auth required"), ); - const tool = manager.getActiveTools()[0]; - await expect(tool!.execute("call-2", {} as never)).rejects.toBeInstanceOf( - McpAuthorizationRequiredError, - ); + await expect( + manager.executeTool(activeSkills, "mcp__demo__ping", {}), + ).rejects.toBeInstanceOf(McpAuthorizationRequiredError); expect(onAuthorizationRequiredMock).toHaveBeenCalledTimes(1); expect(onAuthorizationRequiredMock).toHaveBeenCalledWith( "demo", @@ -196,6 +218,137 @@ describe("McpToolManager", () => { expect(closeMock).toHaveBeenNthCalledWith(1, alphaPlugin); expect(closeMock).toHaveBeenNthCalledWith(2, betaPlugin); expect(manager.getActiveProviders()).toEqual([]); - expect(manager.getActiveTools()).toEqual([]); + expect( + manager.getActiveToolCatalog([ + { pluginProvider: "alpha" }, + { pluginProvider: "beta" }, + ]), + ).toEqual([]); + }); + + it("filters MCP tools to the provider allowlist", async () => { + const plugin = buildPlugin("notion", { + allowedTools: ["notion-search", "notion-fetch"], + }); + listToolsMock.mockResolvedValue([ + { + name: "notion-search", + title: "Search", + description: "Search Notion", + inputSchema: { type: "object", properties: {} }, + }, + { + name: "notion-fetch", + title: "Fetch", + description: "Fetch Notion content", + inputSchema: { type: "object", properties: {} }, + }, + { + name: "notion-create-pages", + title: "Create", + description: "Create Notion pages", + inputSchema: { type: "object", properties: {} }, + }, + ]); + + const manager = new McpToolManager([plugin]); + await manager.activateProvider("notion"); + + expect( + manager + .getActiveToolCatalog([{ pluginProvider: "notion" }]) + .map((tool) => tool.name), + ).toEqual(["mcp__notion__notion-search", "mcp__notion__notion-fetch"]); + }); + + it("narrows the active registry to the skill-level MCP allowlist", async () => { + const plugin = buildPlugin("notion"); + listToolsMock.mockResolvedValue([ + { + name: "notion-search", + title: "Search", + description: "Search Notion", + inputSchema: { type: "object", properties: {} }, + }, + { + name: "notion-fetch", + title: "Fetch", + description: "Fetch Notion content", + inputSchema: { type: "object", properties: {} }, + }, + { + name: "notion-create-pages", + title: "Create", + description: "Create Notion pages", + inputSchema: { type: "object", properties: {} }, + }, + ]); + + const manager = new McpToolManager([plugin]); + const activeSkills = [ + { + name: "notion", + pluginProvider: "notion", + allowedMcpTools: ["notion-search", "notion-fetch"], + }, + ]; + + await manager.activateForSkill(activeSkills[0]!); + + expect( + manager.getActiveToolCatalog(activeSkills).map((tool) => tool.name), + ).toEqual(["mcp__notion__notion-search", "mcp__notion__notion-fetch"]); + expect( + manager.searchTools(activeSkills, "fetch").map((tool) => tool.name), + ).toEqual(["mcp__notion__notion-fetch"]); + await expect( + manager.executeTool(activeSkills, "mcp__notion__notion-create-pages", {}), + ).rejects.toThrow( + "Unknown active MCP tool: mcp__notion__notion-create-pages", + ); + }); + + it("fails activation when an allowlisted MCP tool is missing", async () => { + const plugin = buildPlugin("notion", { + allowedTools: ["notion-search", "notion-fetch"], + }); + listToolsMock.mockResolvedValue([ + { + name: "notion-search", + title: "Search", + description: "Search Notion", + inputSchema: { type: "object", properties: {} }, + }, + ]); + + const manager = new McpToolManager([plugin]); + + await expect(manager.activateProvider("notion")).rejects.toThrow( + "Plugin notion MCP discovery missing allowlisted tools: notion-fetch", + ); + }); + + it("fails skill activation when the skill declares unavailable MCP tools", async () => { + const plugin = buildPlugin("notion"); + listToolsMock.mockResolvedValue([ + { + name: "notion-search", + title: "Search", + description: "Search Notion", + inputSchema: { type: "object", properties: {} }, + }, + ]); + + const manager = new McpToolManager([plugin]); + + await expect( + manager.activateForSkill({ + name: "notion", + pluginProvider: "notion", + allowedMcpTools: ["notion-search", "notion-fetch"], + }), + ).rejects.toThrow( + "Skill notion declares unavailable MCP tools for plugin notion: notion-fetch", + ); }); }); diff --git a/packages/junior/tests/unit/notion-cli.test.ts b/packages/junior/tests/unit/notion-cli.test.ts deleted file mode 100644 index fd2753ac..00000000 --- a/packages/junior/tests/unit/notion-cli.test.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; - -// @ts-expect-error test-only import from an untyped sibling package script -import { fetchContent } from "../../../junior-notion/skills/notion/scripts/notion-cli.mjs"; - -describe("notion cli fetchContent", () => { - afterEach(() => { - vi.unstubAllGlobals(); - }); - - it("preserves data source metadata when the rows query fails", async () => { - const fetchMock = vi.fn(async (input: string | URL, init?: RequestInit) => { - const url = String(input); - if ( - url.endsWith("/data_sources/ds_123") && - (init?.method === undefined || init.method === "GET") - ) { - return Response.json({ - id: "ds_123", - object: "data_source", - title: [{ plain_text: "Roadmap" }], - url: "https://notion.so/roadmap", - last_edited_time: "2026-03-12T00:00:00.000Z", - properties: {}, - }); - } - - if (url.endsWith("/data_sources/ds_123/query")) { - return new Response("query failed", { status: 500 }); - } - - throw new Error(`Unexpected fetch: ${url}`); - }); - - vi.stubGlobal("fetch", fetchMock); - - const result = await fetchContent({ - id: "ds_123", - object: "data_source", - rowLimit: 5, - }); - - expect(result).toMatchObject({ - ok: true, - target: { - id: "ds_123", - object: "data_source", - title: "Roadmap", - url: "https://notion.so/roadmap", - last_edited_time: "2026-03-12T00:00:00.000Z", - }, - content: null, - }); - expect(result.content_error).toContain( - "Notion API POST /data_sources/ds_123/query failed with 500", - ); - expect(fetchMock).toHaveBeenCalledTimes(4); - expect( - fetchMock.mock.calls.filter(([input]) => - String(input).endsWith("/data_sources/ds_123"), - ), - ).toHaveLength(1); - expect( - fetchMock.mock.calls.filter(([input]) => - String(input).endsWith("/data_sources/ds_123/query"), - ), - ).toHaveLength(3); - }); - - it("keeps page targets on the compact shared shape", async () => { - vi.stubGlobal( - "fetch", - vi.fn(async (input: string | URL) => { - const url = String(input); - if (url.endsWith("/pages/page_123")) { - return Response.json({ - id: "page_123", - object: "page", - url: "https://notion.so/page", - last_edited_time: "2026-03-12T00:00:00.000Z", - properties: { - Name: { - type: "title", - title: [{ plain_text: "Spec" }], - }, - }, - }); - } - - if (url.endsWith("/pages/page_123/markdown")) { - return new Response("# Spec", { - headers: { - "content-type": "text/plain", - }, - }); - } - - throw new Error(`Unexpected fetch: ${url}`); - }), - ); - - const result = await fetchContent({ - id: "page_123", - object: "page", - }); - - expect(result).toMatchObject({ - ok: true, - target: { - id: "page_123", - object: "page", - title: "Spec", - url: "https://notion.so/page", - last_edited_time: "2026-03-12T00:00:00.000Z", - }, - content: { - type: "page", - markdown: "# Spec", - }, - }); - expect(result.target).not.toHaveProperty("properties"); - }); -}); diff --git a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts index ce49b0e1..767e481a 100644 --- a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts +++ b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts @@ -2,16 +2,26 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; const { agentInitialToolNames, + callToolMock, + clientOptions, + continueCallCount, deliverPrivateMessageMock, listToolsMock, + loadSkillAvailableToolNames, + loadSkillToolSearchFlags, loadSkillsByNameMock, - setToolsCallNames, + promptCallCount, } = vi.hoisted(() => ({ agentInitialToolNames: [] as string[][], + callToolMock: vi.fn(), + clientOptions: [] as Array>, + continueCallCount: { value: 0 }, deliverPrivateMessageMock: vi.fn(), listToolsMock: vi.fn(), + loadSkillAvailableToolNames: [] as string[][], + loadSkillToolSearchFlags: [] as boolean[], loadSkillsByNameMock: vi.fn(), - setToolsCallNames: [] as string[][], + promptCallCount: { value: 0 }, })); vi.mock("@mariozechner/pi-agent-core", () => { @@ -49,16 +59,6 @@ vi.mock("@mariozechner/pi-agent-core", () => { return () => undefined; } - setTools( - tools: Array<{ - name: string; - execute: (toolCallId: unknown, params: unknown) => Promise; - }>, - ) { - this.state.tools = [...tools]; - setToolsCallNames.push(tools.map((tool) => tool.name)); - } - abort() {} async replaceMessages(messages: unknown[]) { @@ -66,18 +66,78 @@ vi.mock("@mariozechner/pi-agent-core", () => { } async prompt(message: unknown) { + promptCallCount.value += 1; this.state.messages.push(message); + const loadSkillTool = this.state.tools.find( (tool) => tool.name === "loadSkill", ); + const useToolTool = this.state.tools.find( + (tool) => tool.name === "useTool", + ); if (!loadSkillTool) { throw new Error("loadSkill tool missing"); } - await loadSkillTool.execute("tool-call-1", { skill_name: "demo-skill" }); + if (!useToolTool) { + throw new Error("useTool tool missing"); + } + + let loadSkillResult: { + details?: { + available_tools?: Array<{ tool_name: string }>; + tool_search_available?: boolean; + }; + }; + try { + loadSkillResult = (await loadSkillTool.execute("tool-call-1", { + skill_name: "demo-skill", + })) as { + details?: { + available_tools?: Array<{ tool_name: string }>; + tool_search_available?: boolean; + }; + }; + } catch (error) { + this.state.messages.push({ + role: "assistant", + content: [{ type: "text", text: "loading demo skill" }], + }); + throw error; + } + const availableTools = loadSkillResult.details?.available_tools ?? []; + loadSkillAvailableToolNames.push( + availableTools.map((tool) => tool.tool_name), + ); + loadSkillToolSearchFlags.push( + loadSkillResult.details?.tool_search_available === true, + ); + + const pingTool = availableTools.find( + (tool) => tool.tool_name === "mcp__demo__ping", + ); + if (!pingTool) { + throw new Error("loadSkill did not disclose demo ping tool"); + } + + await useToolTool.execute("tool-call-2", { + tool_name: pingTool.tool_name, + arguments: { query: "hello" }, + }); + this.state.messages.push({ + role: "assistant", + content: [{ type: "text", text: "resumed reply" }], + }); return {}; } async continue() { + continueCallCount.value += 1; + const lastMessage = this.state.messages[ + this.state.messages.length - 1 + ] as { role?: unknown } | undefined; + if (lastMessage?.role === "assistant") { + throw new Error("Cannot continue from message role: assistant"); + } this.state.messages.push({ role: "assistant", content: [{ type: "text", text: "resumed reply" }], @@ -188,6 +248,7 @@ vi.mock("@/chat/plugins/registry", async (importOriginal) => { mcp: { transport: "http", url: "https://mcp.example.com", + allowedTools: ["ping"], }, }, }; @@ -236,17 +297,16 @@ vi.mock("@/chat/mcp/client", () => { redirectToAuthorization?: (authorizationUrl: URL) => Promise; }; }, - ) {} + ) { + clientOptions.push({ ...options }); + } async listTools() { return await listToolsMock(this.plugin, this.options); } - async callTool() { - return { - content: [{ type: "text", text: "pong" }], - isError: false, - }; + async callTool(name: string, args: Record) { + return await callToolMock(this.plugin, name, args); } async close() {} @@ -268,10 +328,15 @@ import { isRetryableTurnError } from "@/chat/turn/errors"; describe("generateAssistantReply progressive MCP loading", () => { beforeEach(async () => { agentInitialToolNames.length = 0; - setToolsCallNames.length = 0; + callToolMock.mockReset(); + clientOptions.length = 0; + continueCallCount.value = 0; deliverPrivateMessageMock.mockReset(); listToolsMock.mockReset(); + loadSkillAvailableToolNames.length = 0; + loadSkillToolSearchFlags.length = 0; loadSkillsByNameMock.mockReset(); + promptCallCount.value = 0; process.env.JUNIOR_STATE_ADAPTER = "memory"; process.env.JUNIOR_BASE_URL = "https://junior.example.com"; @@ -280,12 +345,17 @@ describe("generateAssistantReply progressive MCP loading", () => { channel: "D123", threadTs: "1712345.0001", }); + callToolMock.mockResolvedValue({ + content: [{ type: "text", text: "pong" }], + isError: false, + }); loadSkillsByNameMock.mockResolvedValue([ { name: "demo-skill", description: "Demo skill", skillPath: "/tmp/skills/demo-skill", pluginProvider: "demo", + allowedMcpTools: ["ping"], body: "Skill instructions", }, ]); @@ -322,6 +392,15 @@ describe("generateAssistantReply progressive MCP loading", () => { properties: {}, }, }, + { + name: "mutate", + title: "Mutate", + description: "Write through the demo MCP server", + inputSchema: { + type: "object", + properties: {}, + }, + }, ]); await disconnectStateAdapter(); @@ -352,6 +431,8 @@ describe("generateAssistantReply progressive MCP loading", () => { expect(isRetryableTurnError(firstError, "mcp_auth_resume")).toBe(true); expect(agentInitialToolNames[0]).toContain("loadSkill"); + expect(agentInitialToolNames[0]).toContain("searchTools"); + expect(agentInitialToolNames[0]).toContain("useTool"); expect(agentInitialToolNames[0]).not.toContain("mcp__demo__ping"); const pausedCheckpoint = await getAgentTurnSessionCheckpoint( @@ -364,13 +445,32 @@ describe("generateAssistantReply progressive MCP loading", () => { activeMcpProviders: [], resumeReason: "auth", }); + expect(pausedCheckpoint?.piMessages.at(-1)).toMatchObject({ + role: "assistant", + }); expect(deliverPrivateMessageMock).toHaveBeenCalledTimes(1); const reply = await generateAssistantReply("help me", context); expect(reply.text).toBe("resumed reply"); - expect(agentInitialToolNames[1]).toContain("mcp__demo__ping"); - expect(setToolsCallNames).toEqual([]); + expect(promptCallCount.value).toBe(2); + expect(continueCallCount.value).toBe(0); + expect(clientOptions).not.toContainEqual( + expect.objectContaining({ sessionId: expect.any(String) }), + ); + expect(agentInitialToolNames[1]).toContain("loadSkill"); + expect(agentInitialToolNames[1]).toContain("searchTools"); + expect(agentInitialToolNames[1]).toContain("useTool"); + expect(agentInitialToolNames[1]).not.toContain("mcp__demo__ping"); + expect(loadSkillAvailableToolNames).toEqual([["mcp__demo__ping"]]); + expect(loadSkillToolSearchFlags).toEqual([true]); + expect(callToolMock).toHaveBeenCalledWith( + expect.objectContaining({ + manifest: expect.objectContaining({ name: "demo" }), + }), + "ping", + { query: "hello" }, + ); const resumedCheckpoint = await getAgentTurnSessionCheckpoint( "conversation-1", @@ -382,4 +482,66 @@ describe("generateAssistantReply progressive MCP loading", () => { activeMcpProviders: ["demo"], }); }); + + it("uses loadSkill-disclosed MCP tools in the same turn without replay", async () => { + listToolsMock.mockReset(); + listToolsMock.mockResolvedValue([ + { + name: "ping", + title: "Ping", + description: "Ping the demo MCP server", + inputSchema: { + type: "object", + properties: {}, + }, + }, + { + name: "mutate", + title: "Mutate", + description: "Write through the demo MCP server", + inputSchema: { + type: "object", + properties: {}, + }, + }, + ]); + + const reply = await generateAssistantReply("help me", { + assistant: { userName: "junior" }, + requester: { userId: "U123" }, + correlation: { + conversationId: "conversation-2", + turnId: "turn-2", + channelId: "C123", + threadTs: "1712345.0002", + }, + }); + + expect(reply.text).toBe("resumed reply"); + expect(promptCallCount.value).toBe(1); + expect(continueCallCount.value).toBe(0); + expect(agentInitialToolNames[0]).toContain("loadSkill"); + expect(agentInitialToolNames[0]).toContain("searchTools"); + expect(agentInitialToolNames[0]).toContain("useTool"); + expect(agentInitialToolNames[0]).not.toContain("mcp__demo__ping"); + expect(loadSkillAvailableToolNames).toEqual([["mcp__demo__ping"]]); + expect(loadSkillToolSearchFlags).toEqual([true]); + expect(callToolMock).toHaveBeenCalledWith( + expect.objectContaining({ + manifest: expect.objectContaining({ name: "demo" }), + }), + "ping", + { query: "hello" }, + ); + + const checkpoint = await getAgentTurnSessionCheckpoint( + "conversation-2", + "turn-2", + ); + expect(checkpoint).toMatchObject({ + state: "completed", + loadedSkillNames: ["demo-skill"], + activeMcpProviders: ["demo"], + }); + }); }); diff --git a/specs/agent-session-resumability-spec.md b/specs/agent-session-resumability-spec.md index 8e02a0d6..094b494e 100644 --- a/specs/agent-session-resumability-spec.md +++ b/specs/agent-session-resumability-spec.md @@ -101,7 +101,9 @@ For slice `n+1`, runtime must: 2. Instantiate Pi agent. 3. Restore any checkpointed dynamic tool state required by the wrapper runtime (for example loaded skills and active MCP providers). 4. Call `replaceMessages(checkpoint.pi_messages)`. -5. Call `continue()` to resume generation/tool loop. +5. Resume generation with one of these modes: + - Default: call `continue()` to resume generation/tool loop. + - Auth fallback: if `resume_reason=auth` and `checkpoint.pi_messages` ends on an assistant message with no queued steering/follow-up input, do not call `continue()`. Replay the original user prompt after restoring dynamic tool state instead. If the previous slice timed out after producing uncommitted partial assistant text, that text may be regenerated in the next slice. User-visible output must only include committed transcript content. diff --git a/specs/logging/logging-spec.md b/specs/logging/logging-spec.md index 92aee521..9a7a3438 100644 --- a/specs/logging/logging-spec.md +++ b/specs/logging/logging-spec.md @@ -9,7 +9,7 @@ - 2026-03-03: Standardized metadata headers and reconciled spec references/structure. - 2026-03-04: Updated code and test file references to repo-root paths under `packages/junior/`. - +- 2026-03-18: Added console rendering policy for compact dev logs and clarified that tool success lifecycle uses spans instead of duplicate start/complete info logs. ## Status @@ -32,6 +32,7 @@ Define the canonical structured logging contract for application events, context - [Tracing Spec](./tracing-spec.md) ## Goals + - Make logs consistent, structured, and queryable across the app. - Use OpenTelemetry semantic attribute names wherever a standard exists. - Keep one logging entrypoint (similar to `ash`'s centralized logging model). @@ -39,10 +40,12 @@ Define the canonical structured logging contract for application events, context - Remove repeated per-request/per-turn attributes from log callsites by defaulting to ambient context propagation. ## Non-goals + - Replacing Sentry tracing setup. - Shipping a separate log backend in this phase. ## Current State (Audit) + - Core logging helper exists: `packages/junior/src/chat/observability.ts`. - Callsites are concentrated in: - `packages/junior/src/chat/bot.ts` @@ -56,6 +59,7 @@ Define the canonical structured logging contract for application events, context - Context is repeated manually instead of ambient propagation. ## Design Principles + - Centralized API: no direct `console.*` for application logging. - Event-first logging: stable `event.name` for every log record. - Semantic-first attributes: use OTel keys first; app keys are namespaced as `app.*`. @@ -66,7 +70,9 @@ Define the canonical structured logging contract for application events, context ## Logging Contract ### Record Shape + Each emitted log record follows this logical shape (transport can vary): + - `timestamp` - `severity_text` (`DEBUG|INFO|WARN|ERROR`) - `body` (human-readable summary) @@ -76,6 +82,7 @@ Each emitted log record follows this logical shape (transport can vary): - `span_id` (if active span) ### Message Semantics + - Every log record must include both: - `event.name`: stable snake_case identifier for machines, dashboards, and alert rules. - `body`: natural-language message for humans. @@ -88,6 +95,7 @@ Each emitted log record follows this logical shape (transport can vary): - Do not use `event.name` as a prose sentence and do not omit `event.name` in favor of only text. ### API Surface (`packages/junior/src/chat/logging.ts`) + - `log.debug(eventName, attrs?, body?)` - `log.info(eventName, attrs?, body?)` - `log.warn(eventName, attrs?, body?)` @@ -97,6 +105,7 @@ Each emitted log record follows this logical shape (transport can vary): - `createLogContextFromRequest(...)` Compatibility shims in `packages/junior/src/chat/observability.ts` remain supported: + - `logInfo(eventName, context?, attributes?, body?)` - `logWarn(eventName, context?, attributes?, body?)` - `logError(eventName, context?, attributes?, body?)` @@ -106,7 +115,9 @@ Compatibility shims in `packages/junior/src/chat/observability.ts` remain suppor Context passed directly to compatibility shims is optional and merged with ambient context. ### Ambient Context Contract + Context is attached in layered order and merged into a single flat attribute map: + - `request_context` - Long-lived per incoming request context (for example request ID, HTTP route, platform). - `operation_context` @@ -115,21 +126,39 @@ Context is attached in layered order and merged into a single flat attribute map - Per-event attributes passed at log callsites. Merge precedence (highest wins): + 1. `log_call_attributes` 2. `operation_context` 3. `request_context` Rules: + - Explicit per-log context/attributes remain allowed, but should be used only for event-local data. - Baseline request/turn keys should be bound once via ambient context instead of repeated in every call. - When keys collide, higher precedence overwrites lower precedence; duplicate keys are not emitted. +### Console Rendering Policy + +- Structured records remain rich for sinks and Sentry; console rendering may project a smaller view for readability. +- Default dev console output should keep a small stable core (`event.name`, conversation/turn correlation, trace/span ids, and event-local outcome fields) and suppress low-value ambient fields that are repeated on nearly every line. +- Default console output should suppress duplicated correlation fields when a stronger equivalent is already present (for example `app.agent.id` when it matches `app.turn.id`). +- Large payload attributes should be compacted for `debug` and `info` console output using short previews plus length metadata. `warn` and `error` console output may retain fuller payload detail subject to normal redaction/truncation rules. +- Console projection is a presentation concern only; it must not remove the underlying structured attributes from emitted log records. + +### Tool Lifecycle Logging + +- Success-path tool execution is primarily traced via spans and span attributes. +- Do not emit both `agent_tool_call_started` and `agent_tool_call_completed` info logs for ordinary successful tool executions. +- Keep log events for failures, invalid input, auth interruptions, and other unusual tool states where a discrete log record adds value beyond the span. + ### Runtime Constraints (Next.js) + - Ambient context propagation relies on Node `AsyncLocalStorage`. - API routes that rely on ambient context must run in Node runtime. - If Edge runtime logging is introduced later, it needs a separate propagation strategy. ## Event Naming Convention + - `snake_case` identifiers. - Format: `_[_]`. - Examples: @@ -142,12 +171,14 @@ Rules: ## OpenTelemetry Semantic Attribute Policy ### Required (when available) + - `service.name` - `service.version` - `deployment.environment.name` - `event.name` ### HTTP / Request + - `http.request.method` - `url.path` - `url.full` (when safe) @@ -155,6 +186,7 @@ Rules: - `user_agent.original` (if available) ### Messaging / Slack + - `messaging.system` = `slack` - `messaging.destination.name` (channel identifier) - `messaging.message.id` (message ts/id when available) @@ -162,6 +194,7 @@ Rules: - `enduser.id` (requester user id) ### GenAI + - `gen_ai.request.model` - `gen_ai.provider.name` (provider/gateway) - `gen_ai.operation.name` (e.g. `chat`, `invoke_agent`, `execute_tool`) @@ -171,18 +204,22 @@ Rules: - `gen_ai.tool.call.arguments` / `gen_ai.tool.call.result` (for tool-call spans when captured) ### Error + - `error.type` - `error.message` - `exception.stacktrace` (only on error-level logs/events; truncated) ### Workflow / App-specific (namespaced) + Only when no semantic key exists: + - `app.workflow.run_id` - `app.skill.name` - `app.assistant.username` - `app.retry.attempt` ## Attribute Rules + - Flat map only; no nested objects. - Value types: string | number | boolean | array of strings. - `undefined`, `null`, empty string dropped. @@ -190,11 +227,13 @@ Only when no semantic key exists: - Large strings truncated with suffix `...`. ## Redaction Rules + - Redact known secret/token patterns before emission. - Never log raw auth headers, API keys, or attachment bytes. - For user content, log size/metadata by default; content only when explicitly needed and safe. ## Metrics Derivation Policy + - Default: derive metrics from log events and their attributes. - `event.name` is the primary metric grouping key. - Avoid direct metric emission when equivalent counters/histograms can be computed from existing logs. @@ -206,11 +245,13 @@ Only when no semantic key exists: ## Rollout Plan ### Phase 0: Spec Alignment (current) + - Define ambient context merge semantics and precedence. - Define compatibility API contract where explicit context remains optional. - Track concrete migration and hardening items in `Logging TODOs`. ### Phase 1: Foundation + - Add `packages/junior/src/chat/logging.ts` with: - typed event names (string union + fallback string) - semantic key helpers @@ -222,16 +263,19 @@ Only when no semantic key exists: - attribute sanitizer/redactor ### Phase 2: Context Wiring + - Wire request context in `packages/junior/app/api/webhooks/[platform]/route.ts`. - Ensure `trace_id`/`span_id` are attached when spans are active. - Remove manual repeated context blocks in `bot.ts` and `respond.ts` by using `withLogContext`. ### Phase 3: Callsite Migration + - Replace all `logWarn/logError/logException` calls with event-based structured logs. - Standardize key names at each callsite using the semantic map above. - Keep `observability.ts` as passthrough wrappers to avoid large one-shot breaks. ### Phase 4: Guardrails + - Add tests for: - redaction - attribute sanitization @@ -241,11 +285,13 @@ Only when no semantic key exists: - Update docs with examples and migration cheatsheet. ### Phase 5: Hardening + - Set severity guidance by domain (debug/info/warn/error). - Reduce noisy logs and promote high-value operational events. - Validate logs in Sentry queries and dashboards. ## Acceptance Criteria + - 100% of application logs go through `packages/junior/src/chat/logging.ts`. - 0 mixed key style for migrated callsites (no `media_type` / ad-hoc keys). - Every warning/error log has stable `event.name` and semantic attributes. @@ -254,6 +300,7 @@ Only when no semantic key exists: - Secret redaction tests pass. ## Migration Matrix (Initial) + - `packages/junior/app/api/webhooks/[platform]/route.ts` - unknown platform, handler failures, request lifecycle - `packages/junior/src/chat/bot.ts` @@ -267,6 +314,7 @@ Only when no semantic key exists: - output normalization fallback ## Logging TODOs + - [ ] Migrate duplicated per-turn context in `packages/junior/src/chat/bot.ts` to ambient `withContext`/`withLogContext`. - [ ] Migrate duplicated per-turn context in `packages/junior/src/chat/respond.ts` to ambient `withContext`/`withLogContext`. - [ ] Update `packages/junior/src/chat/app-runtime.ts` logging call patterns to rely on ambient context by default. @@ -279,6 +327,7 @@ Only when no semantic key exists: - [ ] Investigate and fix duplicate Sentry emission in logger transport path (`emitSentry` currently invokes logger twice). ## Decision Record + - Keep current logging stack (`packages/junior/src/chat/logging.ts` + `AsyncLocalStorage` + Sentry transport) for this migration. - Do not adopt LogTape in this phase. - Revisit LogTape (or another logger) only if one or more become true: @@ -287,5 +336,6 @@ Only when no semantic key exists: - Current transport limitations block required queryability, performance, or reliability. ## Open Questions + - Should we emit logs to local JSONL in addition to Sentry in dev (ash-style local inspectability)? - Do we want strict compile-time enums for event names from day 1, or a soft migration with runtime validation first? diff --git a/specs/oauth-flows-spec.md b/specs/oauth-flows-spec.md index 39273e1a..d4e1485a 100644 --- a/specs/oauth-flows-spec.md +++ b/specs/oauth-flows-spec.md @@ -3,13 +3,14 @@ ## Metadata - Created: 2026-03-03 -- Last Edited: 2026-03-13 +- Last Edited: 2026-03-18 ## Changelog - 2026-03-03: Standardized metadata headers and reconciled spec references/structure. - 2026-03-09: Added provider-configured token request auth/headers and optional token expiry semantics. - 2026-03-13: Documented MCP challenge-driven OAuth, MCP callback routing, and auth-driven turn resume. +- 2026-03-18: Clarified lazy MCP auth-session creation, host-managed MCP server-session storage, and disconnect cleanup for stored credentials plus pending auth sessions. ## Status @@ -134,7 +135,9 @@ User: /sentry disconnect ▼ Agent: jr-rpc delete-token sentry │ - ├─ Deletes Redis key `oauth-token::` + ├─ Deletes Redis key `oauth-token::` when present + ├─ Deletes Redis key `junior:mcp_auth_credentials::` for MCP-backed providers + ├─ Deletes pending MCP auth-session entries for that `:` pair └─ Returns confirmation ``` @@ -161,11 +164,18 @@ Agent: jr-rpc delete-token sentry ### MCP auth sessions and credentials - Session key pattern: `junior:mcp_auth_session:` +- Session index key pattern: `junior:mcp_auth_session_index::` - Session value: `{ provider, userId, conversationId, sessionId, userMessage, channelId?, threadTs?, toolChannelId?, configuration?, artifactState?, authorizationUrl?, codeVerifier? }` - Session TTL: 24 hours +- Session records are created lazily when the MCP SDK first needs to redirect the user for authorization, not on every MCP client activation. +- Disconnect must clear both stored MCP credentials and any pending indexed auth sessions for that `userId:provider` pair so stale private links cannot reconnect an unlinked account. - Credentials key pattern: `junior:mcp_auth_credentials::` - Credentials value: MCP SDK client information, discovery state, and OAuth tokens - Credentials TTL: 30 days, refreshed on every write +- Server session key pattern: `junior:mcp_server_session::` +- Server session value: `{ sessionId, updatedAtMs }` +- Server session TTL: 24 hours +- Server session ids are opaque server-issued transport state. They are stored only in host-managed state, never injected into the sandbox or surfaced to the agent, and are cleared on disconnect or when the MCP server reports the session is missing. ## Base URL resolution @@ -362,7 +372,7 @@ User: @Junior /sentry disconnect Junior: Your Sentry account has been disconnected. ``` -Under the hood: `jr-rpc delete-token sentry` deletes the Redis key. Future Sentry commands will prompt the user to reconnect. +Under the hood: `jr-rpc delete-token sentry` deletes the stored provider credentials, including MCP OAuth credentials for MCP-backed providers. Future commands will prompt the user to reconnect. ### Design notes diff --git a/specs/plugin-spec.md b/specs/plugin-spec.md index 75db4724..7c859d89 100644 --- a/specs/plugin-spec.md +++ b/specs/plugin-spec.md @@ -3,7 +3,7 @@ ## Metadata - Created: 2026-03-01 -- Last Edited: 2026-03-13 +- Last Edited: 2026-03-18 ## Changelog @@ -13,6 +13,8 @@ - 2026-03-06: Made plugin credentials/capabilities/config-keys optional to support bundle-only plugins. - 2026-03-09: Added OAuth request overrides, optional OAuth scope, and plugin-level API headers. - 2026-03-13: Implemented HTTP MCP manifests, same-plugin progressive tool activation, and dedicated MCP OAuth callbacks. +- 2026-03-18: Added provider-scoped MCP tool allowlists for read-only plugin surfaces. +- 2026-03-18: Replaced per-MCP-tool Pi registration with stable `searchTools`/`useTool` dispatch and skill-level `allowed-mcp-tools` exposure. ## Status @@ -46,7 +48,8 @@ Define a plugin model where provider integrations are self-contained directories 4. Credential brokers are created on demand only for plugins that declare credentials (`oauth-bearer` or `github-app` type). 5. Skills in `plugins//skills/` are auto-discovered alongside existing skill roots. 6. Plugin-declared MCP tools are host-managed and activated only after a skill from the same plugin is loaded for the turn. -7. Core infrastructure (agent loop, sandbox, jr-rpc, Slack tools, web tools) stays unchanged outside the MCP activation/resume wiring. +7. Pi sees a stable MCP tool surface (`searchTools` and `useTool`) instead of one native Pi tool per discovered MCP tool. +8. `loadSkill` returns the newly exposed MCP tool descriptors for that skill, and the turn prompt mirrors the active registry in ``. ## Plugin directory structure @@ -124,6 +127,9 @@ mcp: # optional — MCP server config for tool sources url: https://mcp.example.com/mcp headers: X-Workspace: acme + allowed-tools: + - search + - fetch ``` ## Plugin manifest contract @@ -176,6 +182,7 @@ mcp: # optional — MCP server config for tool sources | `mcp.transport` | `string` | Must be `"http"` in v1. Stdio/command transports are not supported. | | `mcp.url` | `string` | HTTPS endpoint for the MCP server. | | `mcp.headers` | `Record` | Optional static non-Authorization headers sent with MCP HTTP requests. `Authorization` is reserved for runtime-managed auth. | +| `mcp.allowed-tools` | `string[]` | Optional non-empty allowlist of raw MCP tool names to expose for this provider. Activation fails if any listed tool is missing from discovery. | Snapshot build/reuse and invalidation behavior for `runtime-dependencies` is defined in [Sandbox Snapshots Spec](./sandbox-snapshots-spec.md). @@ -255,8 +262,12 @@ createPluginBroker(provider, deps: PluginBrokerDeps): CredentialBroker - MCP tools are not sandbox dependencies and are not registered globally at startup. - The runtime activates a plugin's MCP tools only after a skill owned by that plugin is loaded in the current turn. - Explicit `/skill` invocations preload the skill first, so same-plugin MCP tools are available before the first model step. -- Mid-turn `loadSkill` updates the active Pi tool list for subsequent agent steps. -- MCP tool names are exposed to Pi as `mcp____`. +- Pi does not receive one native tool per MCP tool. Instead, MCP execution uses stable dispatcher tools: `searchTools` and `useTool`. +- Mid-turn `loadSkill` updates the host-managed MCP registry and returns `available_tools` for the newly exposed tools, including canonical `tool_name` values and full input schemas. +- The prompt includes a compact `` section with the active MCP tool registry for the turn. +- When `mcp.allowed-tools` is set, discovery is filtered before exposure and provider activation fails if any allowlisted tool is absent. +- Skills may further narrow MCP exposure with `allowed-mcp-tools` frontmatter using raw provider tool names. Skill load fails if any listed tool is unavailable after provider discovery and provider-level allowlist filtering. +- Canonical MCP tool names remain `mcp____`. - MCP authorization uses a dedicated callback path at `/api/oauth/callback/mcp/` and resumes the paused turn session after the user authorizes. ## Capability and credential integration From 4d725ed30107e8e19495acd96d7d0dcda389f263 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Wed, 18 Mar 2026 16:15:59 -0700 Subject: [PATCH 08/28] chore(example): Update next-env route types import Commit the generated Next route types reference so the example app matches the current dev output after the recent routing and handler changes. Co-Authored-By: GPT-5 Codex --- apps/example/next-env.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/example/next-env.d.ts b/apps/example/next-env.d.ts index 9edff1c7..c4b7818f 100644 --- a/apps/example/next-env.d.ts +++ b/apps/example/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. From 70394e1d248d70c8695895cc0c86d517ff761197 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Wed, 18 Mar 2026 16:24:32 -0700 Subject: [PATCH 09/28] ref(mcp): Trim manager and auth store interfaces Shrink the exported MCP tool descriptor to the fields consumers actually use and keep argument validation inside the manager that owns the live tool registry. This removes duplicated lookup work from useTool and keeps the dispatcher path focused on dispatch. Also collapse repeated state-adapter connection setup in the MCP auth store so the storage operations read directly instead of repeating the same boilerplate in every function. Co-Authored-By: GPT-5 Codex --- packages/junior/src/chat/mcp/auth-store.ts | 45 +++++----- packages/junior/src/chat/mcp/tool-manager.ts | 86 ++++++++++++-------- packages/junior/src/chat/tools/use-tool.ts | 17 +--- 3 files changed, 78 insertions(+), 70 deletions(-) diff --git a/packages/junior/src/chat/mcp/auth-store.ts b/packages/junior/src/chat/mcp/auth-store.ts index 8906ca13..d851eead 100644 --- a/packages/junior/src/chat/mcp/auth-store.ts +++ b/packages/junior/src/chat/mcp/auth-store.ts @@ -200,21 +200,24 @@ function parseStoredCredentials( } } +async function getConnectedStateAdapter() { + const stateAdapter = getStateAdapter(); + await stateAdapter.connect(); + return stateAdapter; +} + export async function getMcpAuthSession( authSessionId: string, ): Promise { - await getStateAdapter().connect(); - return parseMcpAuthSession( - await getStateAdapter().get(sessionKey(authSessionId)), - ); + const stateAdapter = await getConnectedStateAdapter(); + return parseMcpAuthSession(await stateAdapter.get(sessionKey(authSessionId))); } export async function putMcpAuthSession( session: McpAuthSessionState, ttlMs: number = MCP_AUTH_SESSION_TTL_MS, ): Promise { - const stateAdapter = getStateAdapter(); - await stateAdapter.connect(); + const stateAdapter = await getConnectedStateAdapter(); await stateAdapter.set( sessionKey(session.authSessionId), JSON.stringify(session), @@ -261,8 +264,7 @@ export async function patchMcpAuthSession( export async function deleteMcpAuthSession( authSessionId: string, ): Promise { - const stateAdapter = getStateAdapter(); - await stateAdapter.connect(); + const stateAdapter = await getConnectedStateAdapter(); const current = parseMcpAuthSession( await stateAdapter.get(sessionKey(authSessionId)), ); @@ -291,8 +293,7 @@ export async function deleteMcpAuthSessionsForUserProvider( userId: string, provider: string, ): Promise { - const stateAdapter = getStateAdapter(); - await stateAdapter.connect(); + const stateAdapter = await getConnectedStateAdapter(); const indexKey = sessionIndexKey(userId, provider); const authSessionIds = parseSessionIndex(await stateAdapter.get(indexKey)); @@ -307,9 +308,9 @@ export async function getMcpStoredOAuthCredentials( userId: string, provider: string, ): Promise { - await getStateAdapter().connect(); + const stateAdapter = await getConnectedStateAdapter(); return parseStoredCredentials( - await getStateAdapter().get(credentialsKey(userId, provider)), + await stateAdapter.get(credentialsKey(userId, provider)), ); } @@ -319,8 +320,8 @@ export async function putMcpStoredOAuthCredentials( value: McpStoredOAuthCredentials, ttlMs: number = MCP_AUTH_CREDENTIALS_TTL_MS, ): Promise { - await getStateAdapter().connect(); - await getStateAdapter().set( + const stateAdapter = await getConnectedStateAdapter(); + await stateAdapter.set( credentialsKey(userId, provider), JSON.stringify(value), ttlMs, @@ -331,17 +332,17 @@ export async function deleteMcpStoredOAuthCredentials( userId: string, provider: string, ): Promise { - await getStateAdapter().connect(); - await getStateAdapter().delete(credentialsKey(userId, provider)); + const stateAdapter = await getConnectedStateAdapter(); + await stateAdapter.delete(credentialsKey(userId, provider)); } export async function getMcpServerSessionId( userId: string, provider: string, ): Promise { - await getStateAdapter().connect(); + const stateAdapter = await getConnectedStateAdapter(); return parseServerSession( - await getStateAdapter().get(serverSessionKey(userId, provider)), + await stateAdapter.get(serverSessionKey(userId, provider)), )?.sessionId; } @@ -351,8 +352,8 @@ export async function putMcpServerSessionId( sessionId: string, ttlMs: number = MCP_SERVER_SESSION_TTL_MS, ): Promise { - await getStateAdapter().connect(); - await getStateAdapter().set( + const stateAdapter = await getConnectedStateAdapter(); + await stateAdapter.set( serverSessionKey(userId, provider), JSON.stringify({ sessionId, @@ -366,6 +367,6 @@ export async function deleteMcpServerSessionId( userId: string, provider: string, ): Promise { - await getStateAdapter().connect(); - await getStateAdapter().delete(serverSessionKey(userId, provider)); + const stateAdapter = await getConnectedStateAdapter(); + await stateAdapter.delete(serverSessionKey(userId, provider)); } diff --git a/packages/junior/src/chat/mcp/tool-manager.ts b/packages/junior/src/chat/mcp/tool-manager.ts index 682a6bf6..5d55407d 100644 --- a/packages/junior/src/chat/mcp/tool-manager.ts +++ b/packages/junior/src/chat/mcp/tool-manager.ts @@ -1,4 +1,5 @@ import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; +import { validateToolArguments } from "@mariozechner/pi-ai"; import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"; import type { SkillMetadata } from "@/chat/skills"; import type { PluginDefinition } from "@/chat/plugins/types"; @@ -151,15 +152,24 @@ export interface ManagedMcpToolResult { export interface ManagedMcpToolDescriptor { name: string; - label: string; description: string; parameters: Record; provider: string; - rawName: string; - title?: string; } +type ActiveMcpSkillScope = Pick< + SkillMetadata, + "pluginProvider" | "allowedMcpTools" +>; + +type ActiveMcpSkill = Pick< + SkillMetadata, + "name" | "pluginProvider" | "allowedMcpTools" +>; + interface ManagedMcpTool extends ManagedMcpToolDescriptor { + rawName: string; + title?: string; execute: (args: Record) => Promise; } @@ -186,9 +196,7 @@ export class McpToolManager { ); } - async activateForSkill( - skill: Pick, - ): Promise { + async activateForSkill(skill: ActiveMcpSkill): Promise { if (!skill.pluginProvider) { return false; } @@ -250,29 +258,25 @@ export class McpToolManager { } getActiveToolCatalog( - skills: Array>, + skills: ActiveMcpSkillScope[], options: { provider?: string } = {}, ): ManagedMcpToolDescriptor[] { - return this.getResolvedActiveTools(skills, options).map((tool) => ({ - name: tool.name, - label: tool.label, - description: tool.description, - parameters: tool.parameters, - provider: tool.provider, - rawName: tool.rawName, - ...(tool.title ? { title: tool.title } : {}), - })); + return this.getResolvedActiveTools(skills, options).map((tool) => + this.toToolDescriptor(tool), + ); } searchTools( - skills: Array>, + skills: ActiveMcpSkillScope[], query: string, options: { provider?: string; limit?: number } = {}, ): ManagedMcpToolDescriptor[] { - const resolved = this.getActiveToolCatalog(skills, options); + const resolved = this.getResolvedActiveTools(skills, options); const trimmedQuery = query.trim(); if (!trimmedQuery || trimmedQuery === "*") { - return resolved.slice(0, Math.max(1, options.limit ?? 8)); + return resolved + .slice(0, Math.max(1, options.limit ?? 8)) + .map((tool) => this.toToolDescriptor(tool)); } const normalizedQuery = trimmedQuery.toLowerCase(); @@ -294,11 +298,11 @@ export class McpToolManager { return left.tool.name.localeCompare(right.tool.name); }) .slice(0, Math.max(1, options.limit ?? 8)) - .map((entry) => entry.tool); + .map((entry) => this.toToolDescriptor(entry.tool)); } async executeTool( - skills: Array>, + skills: ActiveMcpSkillScope[], canonicalToolName: string, args: Record, ): Promise { @@ -307,7 +311,7 @@ export class McpToolManager { throw new Error(`Unknown active MCP tool: ${canonicalToolName}`); } - return await tool.execute(args); + return await tool.execute(this.validateExecutionArgs(tool, args)); } private filterListedTools( @@ -357,7 +361,6 @@ export class McpToolManager { ): ManagedMcpTool { return { name: normalizeMcpToolName(plugin.manifest.name, tool.name), - label: tool.title?.trim() || tool.name, description: describeMcpTool(plugin.manifest.name, tool), parameters: tool.inputSchema as Record, provider: plugin.manifest.name, @@ -397,9 +400,7 @@ export class McpToolManager { }; } - private assertSkillToolExposure( - skill: Pick, - ): void { + private assertSkillToolExposure(skill: ActiveMcpSkill): void { const provider = skill.pluginProvider; if ( !provider || @@ -423,7 +424,7 @@ export class McpToolManager { } private getResolvedActiveTools( - skills: Array>, + skills: ActiveMcpSkillScope[], options: { provider?: string } = {}, ): ManagedMcpTool[] { const resolved: ManagedMcpTool[] = []; @@ -441,7 +442,7 @@ export class McpToolManager { private resolveProviderTools( provider: string, - skills: Array>, + skills: ActiveMcpSkillScope[], ): ManagedMcpTool[] { const providerTools = this.toolsByProvider.get(provider) ?? []; if (providerTools.length === 0) { @@ -469,7 +470,7 @@ export class McpToolManager { } private resolveActiveTool( - skills: Array>, + skills: ActiveMcpSkillScope[], canonicalToolName: string, ): ManagedMcpTool | undefined { return this.getResolvedActiveTools(skills).find( @@ -477,12 +478,34 @@ export class McpToolManager { ); } + private toToolDescriptor(tool: ManagedMcpTool): ManagedMcpToolDescriptor { + return { + name: tool.name, + description: tool.description, + parameters: tool.parameters, + provider: tool.provider, + }; + } + + private validateExecutionArgs( + tool: ManagedMcpTool, + args: Record, + ): Record { + return validateToolArguments( + tool as never, + { + name: tool.name, + arguments: args, + } as never, + ) as Record; + } + private scoreToolMatch( - tool: ManagedMcpToolDescriptor, + tool: ManagedMcpTool, normalizedQuery: string, queryTokens: string[], ): number { - const exactCandidates = [tool.name, tool.rawName, tool.label, tool.title] + const exactCandidates = [tool.name, tool.rawName, tool.title] .filter((value): value is string => Boolean(value)) .map((value) => value.toLowerCase()); @@ -494,7 +517,6 @@ export class McpToolManager { const searchableText = [ tool.name, tool.rawName, - tool.label, tool.title, tool.description, tool.provider, diff --git a/packages/junior/src/chat/tools/use-tool.ts b/packages/junior/src/chat/tools/use-tool.ts index b60bc902..e9088154 100644 --- a/packages/junior/src/chat/tools/use-tool.ts +++ b/packages/junior/src/chat/tools/use-tool.ts @@ -1,4 +1,3 @@ -import { validateToolArguments } from "@mariozechner/pi-ai"; import { Type } from "@sinclair/typebox"; import type { Skill } from "@/chat/skills"; import { tool } from "@/chat/tools/definition"; @@ -38,24 +37,10 @@ export function createUseToolTool( ), execute: async ({ tool_name, arguments: rawArguments }) => { const activeSkills = getActiveSkills(); - const toolCatalog = mcpToolManager.getActiveToolCatalog(activeSkills); - const toolDef = toolCatalog.find((entry) => entry.name === tool_name); - if (!toolDef) { - throw new Error(`Unknown active MCP tool: ${tool_name}`); - } - - const validatedArguments = validateToolArguments( - toolDef as never, - { - name: tool_name, - arguments: normalizeToolArguments(rawArguments), - } as never, - ) as Record; - return await mcpToolManager.executeTool( activeSkills, tool_name, - validatedArguments, + normalizeToolArguments(rawArguments), ); }, }); From 079b67c013e9a6f1336dd75630648319c29ec87c Mon Sep 17 00:00:00 2001 From: David Cramer Date: Wed, 18 Mar 2026 16:28:11 -0700 Subject: [PATCH 10/28] fix(oauth): Stop echoing callback errors in HTML Return fixed browser copy for MCP OAuth callback success and failure pages instead of reflecting provider error text or exception messages into the HTML response. The Slack-side logging and resume flow still keep the actionable details. Update the callback unit coverage to assert the browser page stays generic for provider and exception failures. Co-Authored-By: GPT-5 Codex --- .../junior/src/handlers/mcp-oauth-callback.ts | 74 +++++++++++-------- .../junior/tests/mcp-oauth-callback.test.ts | 10 ++- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/packages/junior/src/handlers/mcp-oauth-callback.ts b/packages/junior/src/handlers/mcp-oauth-callback.ts index 0e3cab76..0dea8c8f 100644 --- a/packages/junior/src/handlers/mcp-oauth-callback.ts +++ b/packages/junior/src/handlers/mcp-oauth-callback.ts @@ -29,28 +29,52 @@ import { truncateStatusText } from "@/chat/status-format"; import { markTurnCompleted, markTurnFailed } from "@/chat/turn/persist"; import { resolveReplyDelivery } from "@/chat/turn/execute"; import { isRetryableTurnError } from "@/chat/turn/errors"; -import { escapeXml } from "@/chat/xml"; - -function htmlResponse( - title: string, - message: string, - status: number, -): Response { - const safeTitle = escapeXml(title); - const safeMessage = escapeXml(message); + +const CALLBACK_PAGES = { + missing_state: { + title: "Authorization failed", + message: "Missing state parameter.", + status: 400, + }, + provider_error: { + title: "Authorization failed", + message: "The provider returned an authorization error.", + status: 400, + }, + missing_code: { + title: "Authorization failed", + message: "Missing code parameter.", + status: 400, + }, + success: { + title: "Authorization complete", + message: + "Your MCP access is connected. Junior will continue the paused request in Slack.", + status: 200, + }, + failure: { + title: "Authorization failed", + message: + "Junior could not finish the authorization callback. Return to Slack and retry the original request.", + status: 500, + }, +} as const; + +function htmlResponse(kind: keyof typeof CALLBACK_PAGES): Response { + const page = CALLBACK_PAGES[kind]; const html = ` -${safeTitle} +${page.title}
-

${safeTitle}

-

${safeMessage}

+

${page.title}

+

${page.message}

You can close this tab and return to Slack.

`; return new Response(html, { - status, + status: page.status, headers: { "Content-Type": "text/html; charset=utf-8" }, }); } @@ -382,17 +406,13 @@ export async function GET( const error = url.searchParams.get("error")?.trim(); if (!state) { - return htmlResponse( - "Authorization failed", - "Missing state parameter.", - 400, - ); + return htmlResponse("missing_state"); } if (error) { - return htmlResponse("Authorization failed", `OAuth error: ${error}`, 400); + return htmlResponse("provider_error"); } if (!code) { - return htmlResponse("Authorization failed", "Missing code parameter.", 400); + return htmlResponse("missing_code"); } try { @@ -515,11 +535,7 @@ export async function GET( } }); - return htmlResponse( - "Authorization complete", - "Your MCP access is connected. Junior will continue the paused request in Slack.", - 200, - ); + return htmlResponse("success"); } catch (callbackError) { logException( callbackError, @@ -528,12 +544,6 @@ export async function GET( { "app.credential.provider": provider }, "Failed to process MCP OAuth callback", ); - return htmlResponse( - "Authorization failed", - callbackError instanceof Error - ? callbackError.message - : "Unexpected callback error.", - 500, - ); + return htmlResponse("failure"); } } diff --git a/packages/junior/tests/mcp-oauth-callback.test.ts b/packages/junior/tests/mcp-oauth-callback.test.ts index 08816aa0..38695872 100644 --- a/packages/junior/tests/mcp-oauth-callback.test.ts +++ b/packages/junior/tests/mcp-oauth-callback.test.ts @@ -240,7 +240,7 @@ describe("mcp oauth callback handler", () => { expect(finalizeMcpAuthorizationMock).not.toHaveBeenCalled(); }); - it("escapes querystring error text in the HTML response", async () => { + it("does not reflect provider error text in the HTML response", async () => { const response = await GET( makeRequest( "https://example.com/api/oauth/callback/mcp/demo?state=state-123&error=%3Cscript%3Ealert(1)%3C%2Fscript%3E", @@ -250,11 +250,11 @@ describe("mcp oauth callback handler", () => { expect(response.status).toBe(400); const body = await response.text(); - expect(body).toContain("<script>alert(1)</script>"); + expect(body).toContain("The provider returned an authorization error."); expect(body).not.toContain(""); }); - it("escapes callback exception text in the HTML response", async () => { + it("does not reflect callback exception text in the HTML response", async () => { finalizeMcpAuthorizationMock.mockRejectedValueOnce( new Error(""), ); @@ -268,7 +268,9 @@ describe("mcp oauth callback handler", () => { expect(response.status).toBe(500); const body = await response.text(); - expect(body).toContain("<img src=x onerror=alert(1)>"); + expect(body).toContain( + "Junior could not finish the authorization callback. Return to Slack and retry the original request.", + ); expect(body).not.toContain(""); }); From 105f28655146a1aca830293a3cb9e2ed2267797a Mon Sep 17 00:00:00 2001 From: David Cramer Date: Wed, 18 Mar 2026 16:46:56 -0700 Subject: [PATCH 11/28] fix(mcp): Park handled auth pauses cleanly When MCP auth is required during loadSkill or useTool, Pi turns thrown tool errors into error tool results. Treat handled auth challenges as a parked turn instead of rethrowing through the tool path so the model does not see a spurious tool failure. Also keep malformed PEM private key tails redacted so truncated blocks do not leak the remaining secret body. Co-Authored-By: GPT-5 Codex --- packages/junior/src/chat/logging.ts | 3 +- packages/junior/src/chat/mcp/tool-manager.ts | 46 +++++++++++++++---- packages/junior/src/chat/respond.ts | 29 +++++++----- .../junior/tests/unit/logging-context.test.ts | 30 ++++++++++++ .../tests/unit/mcp/tool-manager.test.ts | 44 ++++++++++++++++++ .../respond-mcp-progressive-loading.test.ts | 22 +++++++-- 6 files changed, 151 insertions(+), 23 deletions(-) diff --git a/packages/junior/src/chat/logging.ts b/packages/junior/src/chat/logging.ts index 174b8331..1fa07cd7 100644 --- a/packages/junior/src/chat/logging.ts +++ b/packages/junior/src/chat/logging.ts @@ -190,7 +190,8 @@ function redactPrivateKeyBlocks(input: string): string { const footer = `-----END ${label}-----`; const footerStart = input.indexOf(footer, labelEnd + footerMarker.length); if (footerStart === -1) { - output += input.slice(cursor); + output += input.slice(cursor, begin); + output += `${header}\n...redacted...`; break; } diff --git a/packages/junior/src/chat/mcp/tool-manager.ts b/packages/junior/src/chat/mcp/tool-manager.ts index 5d55407d..f90ece72 100644 --- a/packages/junior/src/chat/mcp/tool-manager.ts +++ b/packages/junior/src/chat/mcp/tool-manager.ts @@ -138,7 +138,7 @@ export interface McpToolManagerOptions { onAuthorizationRequired?: ( provider: string, error: McpAuthorizationRequiredError, - ) => Promise | void; + ) => Promise | boolean | void; } export interface ManagedMcpToolResult { @@ -202,7 +202,9 @@ export class McpToolManager { } const activated = await this.activateProvider(skill.pluginProvider); - this.assertSkillToolExposure(skill); + if (this.activeProviders.has(skill.pluginProvider)) { + this.assertSkillToolExposure(skill); + } return activated; } @@ -229,9 +231,9 @@ export class McpToolManager { } catch (error) { if ( error instanceof McpAuthorizationRequiredError && - this.options.onAuthorizationRequired + (await this.handleAuthorizationRequired(plugin.manifest.name, error)) ) { - await this.options.onAuthorizationRequired(plugin.manifest.name, error); + return false; } throw error; } @@ -387,12 +389,27 @@ export class McpToolManager { } catch (error) { if ( error instanceof McpAuthorizationRequiredError && - this.options.onAuthorizationRequired - ) { - await this.options.onAuthorizationRequired( + (await this.handleAuthorizationRequired( plugin.manifest.name, error, - ); + )) + ) { + return { + // Pi turns thrown tool errors into toolResult isError frames. + // Once auth pause has been requested, return a placeholder result + // and let the aborted turn park cleanly instead of surfacing a + // spurious tool failure to the model. + content: [{ type: "text", text: "Authorization pending." }], + details: { + provider: plugin.manifest.name, + tool: tool.name, + rawResult: { + toolResult: { + authorizationPending: true, + }, + }, + }, + }; } throw error; } @@ -400,6 +417,19 @@ export class McpToolManager { }; } + private async handleAuthorizationRequired( + provider: string, + error: McpAuthorizationRequiredError, + ): Promise { + if (!this.options.onAuthorizationRequired) { + return false; + } + + return ( + (await this.options.onAuthorizationRequired(provider, error)) === true + ); + } + private assertSkillToolExposure(skill: ActiveMcpSkill): void { const provider = skill.pluginProvider; if ( diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index 06660f0f..bf0db16a 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -1232,7 +1232,7 @@ export async function generateAssistantReply( }, onAuthorizationRequired: async (provider) => { if (pendingMcpAuthorizationPause) { - return; + return true; } const authSessionId = mcpAuthSessionIdsByProvider.get(provider); @@ -1276,6 +1276,7 @@ export async function generateAssistantReply( pendingMcpAuthorizationPause = new McpAuthorizationPauseError(provider); agent?.abort(); + return true; }, }); const turnMcpToolManager = mcpToolManager; @@ -1328,6 +1329,12 @@ export async function generateAssistantReply( syncResumeState(); await turnMcpToolManager.activateForSkill(effective); syncResumeState(); + if (pendingMcpAuthorizationPause) { + // Pi turns thrown tool errors into toolResult isError frames. Once + // auth pause has been requested, stop here and let the aborted turn + // park cleanly instead of surfacing a fake loadSkill failure. + return undefined; + } if (!effective.pluginProvider) { return undefined; } @@ -1356,21 +1363,21 @@ export async function generateAssistantReply( ); syncResumeState(); - try { - for (const skill of activeSkills) { - await turnMcpToolManager.activateForSkill(skill); - syncResumeState(); - } - for (const provider of existingTurnCheckpoint?.activeMcpProviders ?? []) { - await turnMcpToolManager.activateProvider(provider); - syncResumeState(); + for (const skill of activeSkills) { + await turnMcpToolManager.activateForSkill(skill); + syncResumeState(); + if (pendingMcpAuthorizationPause) { + timeoutResumeMessages = existingTurnCheckpoint?.piMessages ?? []; + throw pendingMcpAuthorizationPause; } - } catch (error) { + } + for (const provider of existingTurnCheckpoint?.activeMcpProviders ?? []) { + await turnMcpToolManager.activateProvider(provider); + syncResumeState(); if (pendingMcpAuthorizationPause) { timeoutResumeMessages = existingTurnCheckpoint?.piMessages ?? []; throw pendingMcpAuthorizationPause; } - throw error; } syncResumeState(); diff --git a/packages/junior/tests/unit/logging-context.test.ts b/packages/junior/tests/unit/logging-context.test.ts index 8edb026e..c854fb0f 100644 --- a/packages/junior/tests/unit/logging-context.test.ts +++ b/packages/junior/tests/unit/logging-context.test.ts @@ -305,4 +305,34 @@ describe("logging context ids", () => { expect(records[0]?.body).toContain("-----END PRIVATE KEY-----"); expect(records[0]?.body).not.toContain("super-secret-material"); }); + + it("redacts malformed PEM private key tails without leaking the remaining body", async () => { + const { log, registerLogRecordSink } = await import("@/chat/logging"); + const records: Array<{ body: string }> = []; + const unregister = registerLogRecordSink((record) => { + records.push({ body: record.body }); + }); + + try { + log.error( + "pem_key_logged", + {}, + [ + "prefix", + "-----BEGIN RSA PRIVATE KEY-----", + "super-secret-material", + "truncated-without-footer", + ].join("\n"), + ); + } finally { + unregister(); + } + + expect(records).toHaveLength(1); + expect(records[0]?.body).toContain("prefix"); + expect(records[0]?.body).toContain("-----BEGIN RSA PRIVATE KEY-----"); + expect(records[0]?.body).toContain("...redacted..."); + expect(records[0]?.body).not.toContain("super-secret-material"); + expect(records[0]?.body).not.toContain("truncated-without-footer"); + }); }); diff --git a/packages/junior/tests/unit/mcp/tool-manager.test.ts b/packages/junior/tests/unit/mcp/tool-manager.test.ts index 670ade0b..1294c92e 100644 --- a/packages/junior/tests/unit/mcp/tool-manager.test.ts +++ b/packages/junior/tests/unit/mcp/tool-manager.test.ts @@ -177,6 +177,35 @@ describe("McpToolManager", () => { ); }); + it("parks handled MCP authorization challenges without surfacing a tool error", async () => { + const plugin = buildPlugin(); + onAuthorizationRequiredMock.mockResolvedValueOnce(true); + const manager = new McpToolManager([plugin], { + onAuthorizationRequired: onAuthorizationRequiredMock, + }); + const activeSkills = [{ name: "demo-skill", pluginProvider: "demo" }]; + await manager.activateProvider("demo"); + callToolMock.mockRejectedValueOnce( + new McpAuthorizationRequiredError("demo", "Auth required"), + ); + + await expect( + manager.executeTool(activeSkills, "mcp__demo__ping", {}), + ).resolves.toEqual({ + content: [{ type: "text", text: "Authorization pending." }], + details: { + provider: "demo", + tool: "ping", + rawResult: { + toolResult: { + authorizationPending: true, + }, + }, + }, + }); + expect(onAuthorizationRequiredMock).toHaveBeenCalledTimes(1); + }); + it("surfaces MCP authorization challenges during tool discovery", async () => { const plugin = buildPlugin(); const manager = new McpToolManager([plugin], { @@ -199,6 +228,21 @@ describe("McpToolManager", () => { ); }); + it("parks handled MCP authorization challenges during discovery", async () => { + const plugin = buildPlugin(); + onAuthorizationRequiredMock.mockResolvedValueOnce(true); + const manager = new McpToolManager([plugin], { + onAuthorizationRequired: onAuthorizationRequiredMock, + }); + listToolsMock.mockRejectedValueOnce( + new McpAuthorizationRequiredError("demo", "Discovery auth required"), + ); + + await expect(manager.activateProvider("demo")).resolves.toBe(false); + expect(onAuthorizationRequiredMock).toHaveBeenCalledTimes(1); + expect(manager.getActiveProviders()).toEqual([]); + }); + it("closes every active client before surfacing the first close error", async () => { const alphaPlugin = buildPlugin("alpha"); const betaPlugin = buildPlugin("beta"); diff --git a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts index 767e481a..3b28ef42 100644 --- a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts +++ b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts @@ -8,6 +8,7 @@ const { deliverPrivateMessageMock, listToolsMock, loadSkillAvailableToolNames, + loadSkillExecutionErrorCount, loadSkillToolSearchFlags, loadSkillsByNameMock, promptCallCount, @@ -19,6 +20,7 @@ const { deliverPrivateMessageMock: vi.fn(), listToolsMock: vi.fn(), loadSkillAvailableToolNames: [] as string[][], + loadSkillExecutionErrorCount: { value: 0 }, loadSkillToolSearchFlags: [] as boolean[], loadSkillsByNameMock: vi.fn(), promptCallCount: { value: 0 }, @@ -35,6 +37,7 @@ vi.mock("@mariozechner/pi-agent-core", () => { execute: (toolCallId: unknown, params: unknown) => Promise; }>; }; + private aborted = false; constructor(input: { initialState: { @@ -59,7 +62,9 @@ vi.mock("@mariozechner/pi-agent-core", () => { return () => undefined; } - abort() {} + abort() { + this.aborted = true; + } async replaceMessages(messages: unknown[]) { this.state.messages = [...messages]; @@ -67,6 +72,7 @@ vi.mock("@mariozechner/pi-agent-core", () => { async prompt(message: unknown) { promptCallCount.value += 1; + this.aborted = false; this.state.messages.push(message); const loadSkillTool = this.state.tools.find( @@ -98,6 +104,7 @@ vi.mock("@mariozechner/pi-agent-core", () => { }; }; } catch (error) { + loadSkillExecutionErrorCount.value += 1; this.state.messages.push({ role: "assistant", content: [{ type: "text", text: "loading demo skill" }], @@ -111,6 +118,13 @@ vi.mock("@mariozechner/pi-agent-core", () => { loadSkillToolSearchFlags.push( loadSkillResult.details?.tool_search_available === true, ); + if (this.aborted) { + this.state.messages.push({ + role: "assistant", + content: [{ type: "text", text: "loading demo skill" }], + }); + return {}; + } const pingTool = availableTools.find( (tool) => tool.tool_name === "mcp__demo__ping", @@ -334,6 +348,7 @@ describe("generateAssistantReply progressive MCP loading", () => { deliverPrivateMessageMock.mockReset(); listToolsMock.mockReset(); loadSkillAvailableToolNames.length = 0; + loadSkillExecutionErrorCount.value = 0; loadSkillToolSearchFlags.length = 0; loadSkillsByNameMock.mockReset(); promptCallCount.value = 0; @@ -449,6 +464,7 @@ describe("generateAssistantReply progressive MCP loading", () => { role: "assistant", }); expect(deliverPrivateMessageMock).toHaveBeenCalledTimes(1); + expect(loadSkillExecutionErrorCount.value).toBe(0); const reply = await generateAssistantReply("help me", context); @@ -462,8 +478,8 @@ describe("generateAssistantReply progressive MCP loading", () => { expect(agentInitialToolNames[1]).toContain("searchTools"); expect(agentInitialToolNames[1]).toContain("useTool"); expect(agentInitialToolNames[1]).not.toContain("mcp__demo__ping"); - expect(loadSkillAvailableToolNames).toEqual([["mcp__demo__ping"]]); - expect(loadSkillToolSearchFlags).toEqual([true]); + expect(loadSkillAvailableToolNames).toEqual([[], ["mcp__demo__ping"]]); + expect(loadSkillToolSearchFlags).toEqual([false, true]); expect(callToolMock).toHaveBeenCalledWith( expect.objectContaining({ manifest: expect.objectContaining({ name: "demo" }), From fd4928536f4b37dedb7ca731f63e4c6679151a7b Mon Sep 17 00:00:00 2001 From: David Cramer Date: Wed, 18 Mar 2026 21:58:00 -0700 Subject: [PATCH 12/28] fix(mcp): Preserve loaded skill metadata Keep plugin-backed skill metadata intact when loadSkill reads a skill from the sandbox so later MCP activation and capability checks see the same contract as startup discovery. Also preserve later log content when a malformed PEM block is missing its footer by only redacting through the next blank-line boundary instead of discarding the rest of the record. Co-Authored-By: GPT-5 Codex --- packages/junior/src/chat/logging.ts | 30 +++++++++- packages/junior/src/chat/tools/load-skill.ts | 21 ++++++- packages/junior/tests/load-skill-tool.test.ts | 60 ++++++++++++------- .../junior/tests/unit/logging-context.test.ts | 5 +- 4 files changed, 90 insertions(+), 26 deletions(-) diff --git a/packages/junior/src/chat/logging.ts b/packages/junior/src/chat/logging.ts index 1fa07cd7..a60d68de 100644 --- a/packages/junior/src/chat/logging.ts +++ b/packages/junior/src/chat/logging.ts @@ -159,6 +159,25 @@ function shouldEmitConsole(level: LogLevel): boolean { return getSentryEnvironment() !== "production"; } +function findNextBlankLineBoundary( + input: string, + start: number, +): { start: number; end: number } | null { + const lfBoundary = input.indexOf("\n\n", start); + const crlfBoundary = input.indexOf("\r\n\r\n", start); + + if (lfBoundary === -1 && crlfBoundary === -1) { + return null; + } + if (lfBoundary === -1) { + return { start: crlfBoundary, end: crlfBoundary + 4 }; + } + if (crlfBoundary === -1 || lfBoundary < crlfBoundary) { + return { start: lfBoundary, end: lfBoundary + 2 }; + } + return { start: crlfBoundary, end: crlfBoundary + 4 }; +} + function redactPrivateKeyBlocks(input: string): string { const beginPrefix = "-----BEGIN "; const footerMarker = "-----"; @@ -190,9 +209,18 @@ function redactPrivateKeyBlocks(input: string): string { const footer = `-----END ${label}-----`; const footerStart = input.indexOf(footer, labelEnd + footerMarker.length); if (footerStart === -1) { + const resumeBoundary = findNextBlankLineBoundary( + input, + labelEnd + footerMarker.length, + ); output += input.slice(cursor, begin); output += `${header}\n...redacted...`; - break; + if (!resumeBoundary) { + break; + } + output += input.slice(resumeBoundary.start, resumeBoundary.end); + cursor = resumeBoundary.end; + continue; } output += input.slice(cursor, begin); diff --git a/packages/junior/src/chat/tools/load-skill.ts b/packages/junior/src/chat/tools/load-skill.ts index 16977ecb..931af0d7 100644 --- a/packages/junior/src/chat/tools/load-skill.ts +++ b/packages/junior/src/chat/tools/load-skill.ts @@ -24,7 +24,10 @@ export type LoadSkillMetadata = Pick< "available_tools" | "tool_search_available" >; -function toLoadedSkill(result: LoadSkillResult): Skill | null { +function toLoadedSkill( + result: LoadSkillResult, + availableSkills: SkillMetadata[], +): Skill | null { if ( result.ok !== true || typeof result.skill_name !== "string" || @@ -35,10 +38,24 @@ function toLoadedSkill(result: LoadSkillResult): Skill | null { return null; } + const metadata = + availableSkills.find((skill) => skill.name === result.skill_name) ?? null; + return { name: result.skill_name, description: result.description, skillPath: result.skill_dir, + ...(metadata?.pluginProvider + ? { pluginProvider: metadata.pluginProvider } + : {}), + ...(metadata?.allowedTools ? { allowedTools: metadata.allowedTools } : {}), + ...(metadata?.allowedMcpTools + ? { allowedMcpTools: metadata.allowedMcpTools } + : {}), + ...(metadata?.requiresCapabilities + ? { requiresCapabilities: metadata.requiresCapabilities } + : {}), + ...(metadata?.usesConfig ? { usesConfig: metadata.usesConfig } : {}), body: result.instructions, }; } @@ -101,7 +118,7 @@ export function createLoadSkillTool( availableSkills, skill_name, ); - const loadedSkill = toLoadedSkill(result); + const loadedSkill = toLoadedSkill(result, availableSkills); if (loadedSkill) { const metadata = await options?.onSkillLoaded?.(loadedSkill); if (metadata) { diff --git a/packages/junior/tests/load-skill-tool.test.ts b/packages/junior/tests/load-skill-tool.test.ts index f6af578b..8361528b 100644 --- a/packages/junior/tests/load-skill-tool.test.ts +++ b/packages/junior/tests/load-skill-tool.test.ts @@ -7,38 +7,42 @@ import type { Skill } from "@/chat/skills"; describe("load_skill tool", () => { it("loads a skill from sandbox and returns instructions", async () => { const availableSkills = await discoverSkills(); - const [firstSkill] = availableSkills; + const firstSkill = availableSkills.find( + (skill) => + skill.pluginProvider || + skill.allowedTools || + skill.allowedMcpTools || + skill.requiresCapabilities || + skill.usesConfig, + ); if (!firstSkill) { - throw new Error("expected at least one available skill"); + throw new Error("expected at least one skill with metadata"); } const sandbox = { readFileToBuffer: async ({ path }: { path: string }) => path === sandboxSkillFile(firstSkill.name) ? Buffer.from("---\nname: test\n---\nInstruction body", "utf8") - : null + : null, } as any; const loaded: Skill[] = []; const tool = createLoadSkillTool(sandbox, availableSkills, { onSkillLoaded: (skill) => { loaded.push(skill); - } + }, }); if (typeof tool.execute !== "function") { throw new Error("load_skill execute function missing"); } - const result = await tool.execute( - { skill_name: firstSkill.name }, - { - toolCallId: "tool-call-1", - messages: [] - } as any - ); + const result = await tool.execute({ skill_name: firstSkill.name }, { + toolCallId: "tool-call-1", + messages: [], + } as any); expect(result).toMatchObject({ ok: true, - skill_name: firstSkill.name + skill_name: firstSkill.name, }); expect((result as any).location).toBe(sandboxSkillFile(firstSkill.name)); expect((result as any).skill_dir).toBe(sandboxSkillDir(firstSkill.name)); @@ -47,31 +51,43 @@ describe("load_skill tool", () => { expect(loaded[0]).toMatchObject({ name: firstSkill.name, skillPath: sandboxSkillDir(firstSkill.name), - body: "Instruction body" + body: "Instruction body", + }); + expect(loaded[0]).toMatchObject({ + ...(firstSkill.pluginProvider + ? { pluginProvider: firstSkill.pluginProvider } + : {}), + ...(firstSkill.allowedTools + ? { allowedTools: firstSkill.allowedTools } + : {}), + ...(firstSkill.allowedMcpTools + ? { allowedMcpTools: firstSkill.allowedMcpTools } + : {}), + ...(firstSkill.requiresCapabilities + ? { requiresCapabilities: firstSkill.requiresCapabilities } + : {}), + ...(firstSkill.usesConfig ? { usesConfig: firstSkill.usesConfig } : {}), }); }); it("returns unknown-skill when the name does not exist", async () => { const availableSkills = await discoverSkills(); const sandbox = { - readFileToBuffer: async () => null + readFileToBuffer: async () => null, } as any; const tool = createLoadSkillTool(sandbox, availableSkills); if (typeof tool.execute !== "function") { throw new Error("load_skill execute function missing"); } - const result = await tool.execute( - { skill_name: "does-not-exist" }, - { - toolCallId: "tool-call-2", - messages: [] - } as any - ); + const result = await tool.execute({ skill_name: "does-not-exist" }, { + toolCallId: "tool-call-2", + messages: [], + } as any); expect(result).toMatchObject({ ok: false, - error: "Unknown skill: does-not-exist" + error: "Unknown skill: does-not-exist", }); }); }); diff --git a/packages/junior/tests/unit/logging-context.test.ts b/packages/junior/tests/unit/logging-context.test.ts index c854fb0f..008d2ac7 100644 --- a/packages/junior/tests/unit/logging-context.test.ts +++ b/packages/junior/tests/unit/logging-context.test.ts @@ -306,7 +306,7 @@ describe("logging context ids", () => { expect(records[0]?.body).not.toContain("super-secret-material"); }); - it("redacts malformed PEM private key tails without leaking the remaining body", async () => { + it("redacts malformed PEM private key tails without dropping later log content", async () => { const { log, registerLogRecordSink } = await import("@/chat/logging"); const records: Array<{ body: string }> = []; const unregister = registerLogRecordSink((record) => { @@ -322,6 +322,8 @@ describe("logging context ids", () => { "-----BEGIN RSA PRIVATE KEY-----", "super-secret-material", "truncated-without-footer", + "", + "suffix after malformed key", ].join("\n"), ); } finally { @@ -332,6 +334,7 @@ describe("logging context ids", () => { expect(records[0]?.body).toContain("prefix"); expect(records[0]?.body).toContain("-----BEGIN RSA PRIVATE KEY-----"); expect(records[0]?.body).toContain("...redacted..."); + expect(records[0]?.body).toContain("suffix after malformed key"); expect(records[0]?.body).not.toContain("super-secret-material"); expect(records[0]?.body).not.toContain("truncated-without-footer"); }); From 2968c09884b2d9deff9f2e6dd0ffccb2b469019f Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 13:11:52 -0700 Subject: [PATCH 13/28] ref(oauth): Simplify auth resume flow Collapse the callback resume path onto a shared helper so OAuth and MCP callbacks follow the same shape. Persist only loaded skills for MCP turn resume and always continue from the checkpointed turn state. Co-Authored-By: Codex --- packages/junior/src/chat/respond.ts | 52 +--- packages/junior/src/chat/state.ts | 16 - .../junior/src/handlers/mcp-oauth-callback.ts | 291 +++++------------- .../junior/src/handlers/oauth-callback.ts | 223 ++------------ packages/junior/src/handlers/oauth-resume.ts | 200 ++++++++++++ .../respond-mcp-progressive-loading.test.ts | 83 ++++- specs/agent-session-resumability-spec.md | 12 +- 7 files changed, 399 insertions(+), 478 deletions(-) create mode 100644 packages/junior/src/handlers/oauth-resume.ts diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index bf0db16a..6018ac8e 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -209,6 +209,14 @@ async function runAgentContinuation(agent: Agent): Promise { return await resumable.continue(); } +function trimTrailingAssistantMessages(messages: unknown[]): unknown[] { + let end = messages.length; + while (end > 0 && getPiMessageRole(messages[end - 1]) === "assistant") { + end -= 1; + } + return end === messages.length ? [...messages] : messages.slice(0, end); +} + function isExecutionDeferralResponse(text: string): boolean { return /\b(want me to proceed|do you want me to proceed|shall i proceed|can i proceed|should i proceed|let me do that now|give me a moment|tag me again|fresh invocation)\b/i.test( text, @@ -993,7 +1001,6 @@ export async function generateAssistantReply( let lastKnownSandboxDependencyProfileHash: string | undefined = context.sandbox?.sandboxDependencyProfileHash; let loadedSkillNamesForResume: string[] = []; - let activeMcpProvidersForResume: string[] = []; let mcpToolManager: McpToolManager | undefined; let pendingMcpAuthorizationPause: McpAuthorizationPauseError | undefined; @@ -1076,33 +1083,7 @@ export async function generateAssistantReply( existingTurnCheckpoint.state === "awaiting_resume" && existingTurnCheckpoint.piMessages.length > 0, ); - const checkpointEndsWithAssistant = Boolean( - hasAwaitingResumeCheckpoint && - getPiMessageRole(existingTurnCheckpoint!.piMessages.at(-1)) === - "assistant", - ); - const resumedFromCheckpoint = Boolean( - hasAwaitingResumeCheckpoint && - !( - existingTurnCheckpoint?.resumeReason === "auth" && - checkpointEndsWithAssistant - ), - ); - if ( - hasAwaitingResumeCheckpoint && - existingTurnCheckpoint?.resumeReason === "auth" && - checkpointEndsWithAssistant - ) { - logWarn( - "agent_turn_resume_replayed_from_prompt", - spanContext, - { - "app.ai.resume_reason": existingTurnCheckpoint.resumeReason, - "app.ai.resume_slice_id": existingTurnCheckpoint.sliceId, - }, - "Replaying auth-paused turn from prompt because the saved Pi checkpoint ended on an assistant message", - ); - } + const resumedFromCheckpoint = hasAwaitingResumeCheckpoint; const currentSliceId = hasAwaitingResumeCheckpoint ? existingTurnCheckpoint!.sliceId : 1; @@ -1282,7 +1263,6 @@ export async function generateAssistantReply( const turnMcpToolManager = mcpToolManager; const syncResumeState = () => { loadedSkillNamesForResume = activeSkills.map((skill) => skill.name); - activeMcpProvidersForResume = mcpToolManager?.getActiveProviders() ?? []; }; setTags({ @@ -1371,14 +1351,6 @@ export async function generateAssistantReply( throw pendingMcpAuthorizationPause; } } - for (const provider of existingTurnCheckpoint?.activeMcpProviders ?? []) { - await turnMcpToolManager.activateProvider(provider); - syncResumeState(); - if (pendingMcpAuthorizationPause) { - timeoutResumeMessages = existingTurnCheckpoint?.piMessages ?? []; - throw pendingMcpAuthorizationPause; - } - } syncResumeState(); const activeToolSummaries = turnMcpToolManager @@ -1613,7 +1585,6 @@ export async function generateAssistantReply( state: "completed", piMessages: agent.state.messages as unknown[], loadedSkillNames: activeSkills.map((skill) => skill.name), - activeMcpProviders: turnMcpToolManager.getActiveProviders(), }); } @@ -1777,14 +1748,14 @@ export async function generateAssistantReply( timeoutResumeSessionId ) { const nextSliceId = timeoutResumeSliceId + 1; + const piMessages = trimTrailingAssistantMessages(timeoutResumeMessages); await upsertAgentTurnSessionCheckpoint({ conversationId: timeoutResumeConversationId, sessionId: timeoutResumeSessionId, sliceId: nextSliceId, state: "awaiting_resume", - piMessages: timeoutResumeMessages, + piMessages, loadedSkillNames: loadedSkillNamesForResume, - activeMcpProviders: activeMcpProvidersForResume, resumeReason: "auth", resumedFromSliceId: timeoutResumeSliceId, errorMessage: error.message, @@ -1837,7 +1808,6 @@ export async function generateAssistantReply( state: "awaiting_resume", piMessages, loadedSkillNames: loadedSkillNamesForResume, - activeMcpProviders: activeMcpProvidersForResume, resumeReason: "timeout", resumedFromSliceId: timeoutResumeSliceId, errorMessage: error.message, diff --git a/packages/junior/src/chat/state.ts b/packages/junior/src/chat/state.ts index e3766ac3..11988f75 100644 --- a/packages/junior/src/chat/state.ts +++ b/packages/junior/src/chat/state.ts @@ -166,7 +166,6 @@ export interface AgentTurnSessionCheckpoint { checkpointVersion: number; conversationId: string; errorMessage?: string; - activeMcpProviders?: string[]; loadedSkillNames?: string[]; piMessages: unknown[]; resumeReason?: AgentTurnResumeReason; @@ -281,13 +280,6 @@ function parseAgentTurnSessionCheckpoint( ), } : {}), - ...(Array.isArray(parsed.activeMcpProviders) - ? { - activeMcpProviders: parsed.activeMcpProviders.filter( - (value): value is string => typeof value === "string", - ), - } - : {}), ...(parsed.resumeReason === "timeout" || parsed.resumeReason === "auth" ? { resumeReason: parsed.resumeReason } : {}), @@ -483,7 +475,6 @@ export async function upsertAgentTurnSessionCheckpoint(args: { state: AgentTurnSessionStatus; piMessages: unknown[]; loadedSkillNames?: string[]; - activeMcpProviders?: string[]; resumeReason?: AgentTurnResumeReason; errorMessage?: string; resumedFromSliceId?: number; @@ -510,13 +501,6 @@ export async function upsertAgentTurnSessionCheckpoint(args: { ), } : {}), - ...(Array.isArray(args.activeMcpProviders) - ? { - activeMcpProviders: args.activeMcpProviders.filter( - (value): value is string => typeof value === "string", - ), - } - : {}), ...(args.resumeReason ? { resumeReason: args.resumeReason } : {}), ...(args.errorMessage ? { errorMessage: args.errorMessage } : {}), ...(typeof args.resumedFromSliceId === "number" diff --git a/packages/junior/src/handlers/mcp-oauth-callback.ts b/packages/junior/src/handlers/mcp-oauth-callback.ts index 0dea8c8f..eb2104ea 100644 --- a/packages/junior/src/handlers/mcp-oauth-callback.ts +++ b/packages/junior/src/handlers/mcp-oauth-callback.ts @@ -3,12 +3,11 @@ import { after } from "next/server"; import { ThreadImpl, type FileUpload } from "chat"; import { botConfig } from "@/chat/config"; import { coerceThreadConversationState } from "@/chat/conversation-state"; -import type { ChannelConfigurationService } from "@/chat/configuration/types"; import { deleteMcpAuthSession } from "@/chat/mcp/auth-store"; import { buildSlackOutputMessage } from "@/chat/output"; import { finalizeMcpAuthorization } from "@/chat/mcp/oauth"; import { logException, logWarn } from "@/chat/observability"; -import { generateAssistantReply, type AssistantReply } from "@/chat/respond"; +import type { AssistantReply } from "@/chat/respond"; import { mergeArtifactsState, persistThreadState, @@ -20,15 +19,14 @@ import { upsertConversationMessage, updateConversationStats, } from "@/chat/services/conversation-memory"; -import { - getSlackClient, - uploadFilesToThread, -} from "@/chat/slack-actions/client"; +import { uploadFilesToThread } from "@/chat/slack-actions/client"; import { coerceThreadArtifactsState } from "@/chat/slack-actions/types"; -import { truncateStatusText } from "@/chat/status-format"; +import { + postSlackMessage, + resumeAuthorizedRequest, +} from "@/handlers/oauth-resume"; import { markTurnCompleted, markTurnFailed } from "@/chat/turn/persist"; import { resolveReplyDelivery } from "@/chat/turn/execute"; -import { isRetryableTurnError } from "@/chat/turn/errors"; const CALLBACK_PAGES = { missing_state: { @@ -79,22 +77,6 @@ function htmlResponse(kind: keyof typeof CALLBACK_PAGES): Response { }); } -async function postSlackMessage( - channelId: string, - threadTs: string, - text: string, -): Promise { - try { - await getSlackClient().chat.postMessage({ - channel: channelId, - thread_ts: threadTs, - text, - }); - } catch { - // Best effort. - } -} - function extractSlackText(text: string, files?: FileUpload[]): string { const message = buildSlackOutputMessage(text, files); if ( @@ -281,114 +263,6 @@ async function persistFailedReplyState( }); } -async function setAssistantStatus( - channelId: string, - threadTs: string, - status: string, -): Promise { - try { - await getSlackClient().assistant.threads.setStatus({ - channel_id: channelId, - thread_ts: threadTs, - status, - }); - } catch { - // Best effort. - } -} - -const STATUS_DEBOUNCE_MS = 1000; - -function createDebouncedStatusPoster(channelId: string, threadTs: string) { - let lastPostAt = 0; - let currentStatus = ""; - let pendingStatus: string | null = null; - let pendingTimer: ReturnType | null = null; - let stopped = false; - - const flush = async () => { - if (stopped || !pendingStatus) return; - const status = pendingStatus; - pendingStatus = null; - pendingTimer = null; - lastPostAt = Date.now(); - currentStatus = status; - await setAssistantStatus(channelId, threadTs, status); - }; - - const post = async (status: string) => { - if (stopped) return; - const truncated = truncateStatusText(status); - if (!truncated || truncated === currentStatus) return; - - const now = Date.now(); - const elapsed = now - lastPostAt; - if (elapsed >= STATUS_DEBOUNCE_MS) { - if (pendingTimer) { - clearTimeout(pendingTimer); - pendingTimer = null; - } - pendingStatus = null; - lastPostAt = now; - currentStatus = truncated; - await setAssistantStatus(channelId, threadTs, truncated); - return; - } - - pendingStatus = truncated; - if (!pendingTimer) { - pendingTimer = setTimeout( - () => { - void flush(); - }, - Math.max(1, STATUS_DEBOUNCE_MS - elapsed), - ); - } - }; - - post.stop = () => { - stopped = true; - if (pendingTimer) { - clearTimeout(pendingTimer); - pendingTimer = null; - } - pendingStatus = null; - }; - - return post; -} - -function createReadOnlyConfigService( - values: Record, -): ChannelConfigurationService { - const entries = Object.entries(values).map(([key, value]) => ({ - key, - value, - scope: "conversation" as const, - updatedAt: new Date().toISOString(), - })); - - return { - get: async (key) => entries.find((entry) => entry.key === key), - set: async () => { - throw new Error("Read-only configuration in resumed context"); - }, - unset: async () => false, - list: async ({ prefix } = {}) => - entries.filter((entry) => !prefix || entry.key.startsWith(prefix)), - resolve: async (key) => values[key], - resolveValues: async ({ keys, prefix } = {}) => { - const filtered: Record = {}; - for (const [key, value] of Object.entries(values)) { - if (prefix && !key.startsWith(prefix)) continue; - if (keys && !keys.includes(key)) continue; - filtered[key] = value; - } - return filtered; - }, - }; -} - type Context = { params: Promise<{ provider: string; @@ -434,105 +308,86 @@ export async function GET( return; } - const postStatus = createDebouncedStatusPoster( - authSession.channelId, - authSession.threadTs, - ); - await postSlackMessage( - authSession.channelId, - authSession.threadTs, - `Your ${provider} MCP access is now connected. Continuing the original request...`, - ); - await setAssistantStatus( - authSession.channelId, - authSession.threadTs, - "Thinking...", - ); - - try { - const reply = await generateAssistantReply(authSession.userMessage, { - assistant: { userName: botConfig.userName }, - requester: { userId: authSession.userId }, - correlation: { - conversationId: authSession.conversationId, - turnId: authSession.sessionId, - channelId: authSession.channelId, - threadTs: authSession.threadTs, - requesterId: authSession.userId, - }, - toolChannelId: - authSession.toolChannelId ?? - authSession.artifactState?.assistantContextChannelId ?? - authSession.channelId, - artifactState: authSession.artifactState, - configuration: authSession.configuration, - channelConfiguration: authSession.configuration - ? createReadOnlyConfigService(authSession.configuration) - : undefined, - onStatus: postStatus, - }); - - postStatus.stop(); - await deliverReplyToThread( + await resumeAuthorizedRequest({ + messageText: authSession.userMessage, + requesterUserId: authSession.userId, + provider, + channelId: authSession.channelId, + threadTs: authSession.threadTs, + connectedText: `Your ${provider} MCP access is now connected. Continuing the original request...`, + failureText: + "MCP authorization completed, but resuming the request failed. Please retry the original command.", + correlation: { + conversationId: authSession.conversationId, + turnId: authSession.sessionId, + channelId: authSession.channelId, + threadTs: authSession.threadTs, + requesterId: authSession.userId, + }, + toolChannelId: + authSession.toolChannelId ?? + authSession.artifactState?.assistantContextChannelId ?? authSession.channelId, - authSession.threadTs, - reply, - ); - try { - await persistCompletedReplyState( - authSession.channelId, - authSession.threadTs, - authSession.sessionId, + artifactState: authSession.artifactState, + configuration: authSession.configuration, + onReply: async (reply) => { + await deliverReplyToThread( + authSession.channelId!, + authSession.threadTs!, reply, ); - } catch (persistError) { + }, + onSuccess: async (reply) => { + try { + await persistCompletedReplyState( + authSession.channelId!, + authSession.threadTs!, + authSession.sessionId, + reply, + ); + } catch (persistError) { + logException( + persistError, + "mcp_oauth_callback_resume_persist_failed", + {}, + { "app.credential.provider": provider }, + "Failed to persist resumed MCP turn state", + ); + } + }, + onFailure: async (error) => { logException( - persistError, - "mcp_oauth_callback_resume_persist_failed", + error, + "mcp_oauth_callback_resume_failed", {}, { "app.credential.provider": provider }, - "Failed to persist resumed MCP turn state", + "Failed to resume MCP-authorized turn", ); - } - } catch (resumeError) { - postStatus.stop(); - if (isRetryableTurnError(resumeError, "mcp_auth_resume")) { + try { + await persistFailedReplyState( + authSession.channelId!, + authSession.threadTs!, + authSession.sessionId, + ); + } catch (persistError) { + logException( + persistError, + "mcp_oauth_callback_resume_failure_persist_failed", + {}, + { "app.credential.provider": provider }, + "Failed to persist failed MCP resume state", + ); + } + }, + onAuthPause: async () => { logWarn( "mcp_oauth_callback_resume_reparked_for_auth", {}, { "app.credential.provider": provider }, "Resumed MCP turn requested another authorization flow", ); - return; - } - logException( - resumeError, - "mcp_oauth_callback_resume_failed", - {}, - { "app.credential.provider": provider }, - "Failed to resume MCP-authorized turn", - ); - try { - await persistFailedReplyState( - authSession.channelId, - authSession.threadTs, - authSession.sessionId, - ); - } catch (persistError) { - logException( - persistError, - "mcp_oauth_callback_resume_failure_persist_failed", - {}, - { "app.credential.provider": provider }, - "Failed to persist failed MCP resume state", - ); - } - await postSlackMessage( - authSession.channelId, - authSession.threadTs, - "MCP authorization completed, but resuming the request failed. Please retry the original command.", - ); - } + }, + }); }); return htmlResponse("success"); diff --git a/packages/junior/src/handlers/oauth-callback.ts b/packages/junior/src/handlers/oauth-callback.ts index 60bdb4e3..b6fda9f3 100644 --- a/packages/junior/src/handlers/oauth-callback.ts +++ b/packages/junior/src/handlers/oauth-callback.ts @@ -5,19 +5,19 @@ import { type OAuthStatePayload, resolveBaseUrl, } from "@/chat/oauth-flow"; -import { botConfig } from "@/chat/config"; -import type { ChannelConfigurationService } from "@/chat/configuration/types"; +import { + resumeAuthorizedRequest, + postSlackMessage, +} from "@/handlers/oauth-resume"; import { logException, logInfo } from "@/chat/observability"; import { getPluginOAuthConfig } from "@/chat/plugins/registry"; import { buildOAuthTokenRequest, parseOAuthTokenResponse, } from "@/chat/plugins/oauth-request"; -import { generateAssistantReply } from "@/chat/respond"; import { publishAppHomeView } from "@/chat/app-home"; import { getSlackClient } from "@/chat/slack-actions/client"; import { getStateAdapter } from "@/chat/state"; -import { truncateStatusText } from "@/chat/status-format"; import { escapeXml } from "@/chat/xml"; /** @@ -51,196 +51,41 @@ function htmlErrorResponse( }); } -async function postSlackMessage( - channelId: string, - threadTs: string, - text: string, -): Promise { - try { - await getSlackClient().chat.postMessage({ - channel: channelId, - thread_ts: threadTs, - text, - }); - } catch { - // Best effort. - } -} - -async function setAssistantStatus( - channelId: string, - threadTs: string, - status: string, -): Promise { - try { - await getSlackClient().assistant.threads.setStatus({ - channel_id: channelId, - thread_ts: threadTs, - status, - }); - } catch { - // Best effort. - } -} - -const STATUS_DEBOUNCE_MS = 1000; - -function createDebouncedStatusPoster(channelId: string, threadTs: string) { - let lastPostAt = 0; - let currentStatus = ""; - let pendingStatus: string | null = null; - let pendingTimer: ReturnType | null = null; - let stopped = false; - - const flush = async () => { - if (stopped || !pendingStatus) return; - const status = pendingStatus; - pendingStatus = null; - pendingTimer = null; - lastPostAt = Date.now(); - currentStatus = status; - await setAssistantStatus(channelId, threadTs, status); - }; - - const post = async (status: string) => { - if (stopped) return; - const truncated = truncateStatusText(status); - if (!truncated || truncated === currentStatus) return; - - const now = Date.now(); - const elapsed = now - lastPostAt; - - if (elapsed >= STATUS_DEBOUNCE_MS) { - if (pendingTimer) { - clearTimeout(pendingTimer); - pendingTimer = null; - } - pendingStatus = null; - lastPostAt = now; - currentStatus = truncated; - await setAssistantStatus(channelId, threadTs, truncated); - return; - } +async function resumePendingMessage(stored: OAuthStatePayload): Promise { + if (!stored.pendingMessage || !stored.channelId || !stored.threadTs) return; - pendingStatus = truncated; - if (!pendingTimer) { - pendingTimer = setTimeout( - () => { - void flush(); + const providerLabel = formatProviderLabel(stored.provider); + await resumeAuthorizedRequest({ + messageText: stored.pendingMessage, + requesterUserId: stored.userId, + provider: stored.provider, + channelId: stored.channelId, + threadTs: stored.threadTs, + connectedText: `Your ${providerLabel} account is now connected. Processing your request...`, + failureText: `I connected your account but hit an error processing your request. Please try \`${stored.pendingMessage}\` again.`, + configuration: stored.configuration, + onSuccess: async (reply) => { + logInfo( + "oauth_callback_resume_complete", + {}, + { + "app.credential.provider": stored.provider, + "app.ai.outcome": reply.diagnostics.outcome, + "app.ai.tool_calls": reply.diagnostics.toolCalls.length, }, - Math.max(1, STATUS_DEBOUNCE_MS - elapsed), + "Auto-resumed pending message after OAuth callback", ); - } - }; - - post.stop = () => { - stopped = true; - if (pendingTimer) { - clearTimeout(pendingTimer); - pendingTimer = null; - } - pendingStatus = null; - }; - - return post; -} - -function createReadOnlyConfigService( - values: Record, -): ChannelConfigurationService { - const entries = Object.entries(values).map(([key, value]) => ({ - key, - value, - scope: "conversation" as const, - updatedAt: new Date().toISOString(), - })); - - return { - get: async (key) => entries.find((e) => e.key === key), - set: async () => { - throw new Error("Read-only configuration in resumed context"); }, - unset: async () => false, - list: async ({ prefix } = {}) => - entries.filter((e) => !prefix || e.key.startsWith(prefix)), - resolve: async (key) => values[key], - resolveValues: async ({ keys, prefix } = {}) => { - const filtered: Record = {}; - for (const [key, value] of Object.entries(values)) { - if (prefix && !key.startsWith(prefix)) continue; - if (keys && !keys.includes(key)) continue; - filtered[key] = value; - } - return filtered; + onFailure: async (error) => { + logException( + error, + "oauth_callback_resume_failed", + {}, + { "app.credential.provider": stored.provider }, + "Failed to auto-resume pending message after OAuth callback", + ); }, - }; -} - -async function resumePendingMessage(stored: OAuthStatePayload): Promise { - if (!stored.pendingMessage || !stored.channelId || !stored.threadTs) return; - - const providerLabel = formatProviderLabel(stored.provider); - await postSlackMessage( - stored.channelId, - stored.threadTs, - `Your ${providerLabel} account is now connected. Processing your request...`, - ); - - const postStatus = createDebouncedStatusPoster( - stored.channelId, - stored.threadTs, - ); - await setAssistantStatus(stored.channelId, stored.threadTs, "Thinking..."); - - try { - const reply = await generateAssistantReply(stored.pendingMessage, { - assistant: { userName: botConfig.userName }, - requester: { userId: stored.userId }, - correlation: { - channelId: stored.channelId, - threadTs: stored.threadTs, - requesterId: stored.userId, - }, - configuration: stored.configuration, - channelConfiguration: stored.configuration - ? createReadOnlyConfigService(stored.configuration) - : undefined, - onStatus: postStatus, - }); - - postStatus.stop(); - - if (reply.text) { - await postSlackMessage(stored.channelId, stored.threadTs, reply.text); - } - - logInfo( - "oauth_callback_resume_complete", - {}, - { - "app.credential.provider": stored.provider, - "app.ai.outcome": reply.diagnostics.outcome, - "app.ai.tool_calls": reply.diagnostics.toolCalls.length, - }, - "Auto-resumed pending message after OAuth callback", - ); - } catch (error) { - postStatus.stop(); - - logException( - error, - "oauth_callback_resume_failed", - {}, - { "app.credential.provider": stored.provider }, - "Failed to auto-resume pending message after OAuth callback", - ); - - await postSlackMessage( - stored.channelId, - stored.threadTs, - `I connected your account but hit an error processing your request. Please try \`${stored.pendingMessage}\` again.`, - ); - } + }); } export async function GET( diff --git a/packages/junior/src/handlers/oauth-resume.ts b/packages/junior/src/handlers/oauth-resume.ts new file mode 100644 index 00000000..a706023b --- /dev/null +++ b/packages/junior/src/handlers/oauth-resume.ts @@ -0,0 +1,200 @@ +import { botConfig } from "@/chat/config"; +import type { ChannelConfigurationService } from "@/chat/configuration/types"; +import { logException } from "@/chat/observability"; +import { generateAssistantReply, type AssistantReply } from "@/chat/respond"; +import { getSlackClient } from "@/chat/slack-actions/client"; +import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; +import { truncateStatusText } from "@/chat/status-format"; +import { isRetryableTurnError } from "@/chat/turn/errors"; + +export async function postSlackMessage( + channelId: string, + threadTs: string, + text: string, +): Promise { + try { + await getSlackClient().chat.postMessage({ + channel: channelId, + thread_ts: threadTs, + text, + }); + } catch { + // Best effort. + } +} + +async function setAssistantStatus( + channelId: string, + threadTs: string, + status: string, +): Promise { + try { + await getSlackClient().assistant.threads.setStatus({ + channel_id: channelId, + thread_ts: threadTs, + status, + }); + } catch { + // Best effort. + } +} + +const STATUS_DEBOUNCE_MS = 1000; + +function createDebouncedStatusPoster(channelId: string, threadTs: string) { + let lastPostAt = 0; + let currentStatus = ""; + let pendingStatus: string | null = null; + let pendingTimer: ReturnType | null = null; + let stopped = false; + + const flush = async () => { + if (stopped || !pendingStatus) return; + const status = pendingStatus; + pendingStatus = null; + pendingTimer = null; + lastPostAt = Date.now(); + currentStatus = status; + await setAssistantStatus(channelId, threadTs, status); + }; + + const post = async (status: string) => { + if (stopped) return; + const truncated = truncateStatusText(status); + if (!truncated || truncated === currentStatus) return; + + const now = Date.now(); + const elapsed = now - lastPostAt; + if (elapsed >= STATUS_DEBOUNCE_MS) { + if (pendingTimer) { + clearTimeout(pendingTimer); + pendingTimer = null; + } + pendingStatus = null; + lastPostAt = now; + currentStatus = truncated; + await setAssistantStatus(channelId, threadTs, truncated); + return; + } + + pendingStatus = truncated; + if (!pendingTimer) { + pendingTimer = setTimeout( + () => { + void flush(); + }, + Math.max(1, STATUS_DEBOUNCE_MS - elapsed), + ); + } + }; + + post.stop = () => { + stopped = true; + if (pendingTimer) { + clearTimeout(pendingTimer); + pendingTimer = null; + } + pendingStatus = null; + }; + + return post; +} + +export function createReadOnlyConfigService( + values: Record, +): ChannelConfigurationService { + const entries = Object.entries(values).map(([key, value]) => ({ + key, + value, + scope: "conversation" as const, + updatedAt: new Date().toISOString(), + })); + + return { + get: async (key) => entries.find((entry) => entry.key === key), + set: async () => { + throw new Error("Read-only configuration in resumed context"); + }, + unset: async () => false, + list: async ({ prefix } = {}) => + entries.filter((entry) => !prefix || entry.key.startsWith(prefix)), + resolve: async (key) => values[key], + resolveValues: async ({ keys, prefix } = {}) => { + const filtered: Record = {}; + for (const [key, value] of Object.entries(values)) { + if (prefix && !key.startsWith(prefix)) continue; + if (keys && !keys.includes(key)) continue; + filtered[key] = value; + } + return filtered; + }, + }; +} + +export async function resumeAuthorizedRequest(args: { + messageText: string; + requesterUserId: string; + provider: string; + channelId: string; + threadTs: string; + connectedText: string; + failureText: string; + correlation?: { + conversationId?: string; + turnId?: string; + channelId?: string; + threadTs?: string; + requesterId?: string; + }; + toolChannelId?: string; + artifactState?: ThreadArtifactsState; + configuration?: Record; + onReply?: (reply: AssistantReply) => Promise; + onSuccess?: (reply: AssistantReply) => Promise; + onFailure?: (error: unknown) => Promise; + onAuthPause?: (error: unknown) => Promise; +}) { + const postStatus = createDebouncedStatusPoster(args.channelId, args.threadTs); + await postSlackMessage(args.channelId, args.threadTs, args.connectedText); + await setAssistantStatus(args.channelId, args.threadTs, "Thinking..."); + + try { + const reply = await generateAssistantReply(args.messageText, { + assistant: { userName: botConfig.userName }, + requester: { userId: args.requesterUserId }, + correlation: { + conversationId: args.correlation?.conversationId, + turnId: args.correlation?.turnId, + channelId: args.correlation?.channelId ?? args.channelId, + threadTs: args.correlation?.threadTs ?? args.threadTs, + requesterId: args.correlation?.requesterId ?? args.requesterUserId, + }, + toolChannelId: args.toolChannelId, + artifactState: args.artifactState, + configuration: args.configuration, + channelConfiguration: args.configuration + ? createReadOnlyConfigService(args.configuration) + : undefined, + onStatus: postStatus, + }); + + postStatus.stop(); + if (args.onReply) { + await args.onReply(reply); + } else if (reply.text) { + await postSlackMessage(args.channelId, args.threadTs, reply.text); + } + await args.onSuccess?.(reply); + } catch (error) { + postStatus.stop(); + + if (isRetryableTurnError(error, "mcp_auth_resume") && args.onAuthPause) { + await args.onAuthPause(error); + return; + } + + await args.onFailure?.(error); + + await postSlackMessage(args.channelId, args.threadTs, args.failureText); + } +} diff --git a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts index 3b28ef42..140bd890 100644 --- a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts +++ b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts @@ -152,6 +152,16 @@ vi.mock("@mariozechner/pi-agent-core", () => { if (lastMessage?.role === "assistant") { throw new Error("Cannot continue from message role: assistant"); } + const useToolTool = this.state.tools.find( + (tool) => tool.name === "useTool", + ); + if (!useToolTool) { + throw new Error("useTool tool missing"); + } + await useToolTool.execute("tool-call-continue", { + tool_name: "mcp__demo__ping", + arguments: { query: "hello" }, + }); this.state.messages.push({ role: "assistant", content: [{ type: "text", text: "resumed reply" }], @@ -184,6 +194,66 @@ vi.mock("@/chat/oauth-flow", () => ({ resolveBaseUrl: () => "https://junior.example.com", })); +vi.mock("@/chat/mcp/oauth", () => ({ + createMcpOAuthClientProvider: async (input: { + provider: string; + conversationId: string; + sessionId: string; + userId: string; + userMessage: string; + channelId?: string; + threadTs?: string; + toolChannelId?: string; + configuration?: Record; + artifactState?: Record; + }) => { + const { patchMcpAuthSession, putMcpAuthSession } = + await import("@/chat/mcp/auth-store"); + const authSessionId = `${input.provider}-auth-session`; + await putMcpAuthSession({ + authSessionId, + provider: input.provider, + userId: input.userId, + conversationId: input.conversationId, + sessionId: input.sessionId, + userMessage: input.userMessage, + ...(input.channelId ? { channelId: input.channelId } : {}), + ...(input.threadTs ? { threadTs: input.threadTs } : {}), + ...(input.toolChannelId ? { toolChannelId: input.toolChannelId } : {}), + ...(input.configuration ? { configuration: input.configuration } : {}), + ...(input.artifactState ? { artifactState: input.artifactState } : {}), + createdAtMs: Date.now(), + updatedAtMs: Date.now(), + }); + + return { + authSessionId, + redirectUrl: `https://junior.example.com/api/oauth/callback/mcp/${input.provider}`, + clientMetadata: { + client_name: "Junior MCP Client", + redirect_uris: [ + `https://junior.example.com/api/oauth/callback/mcp/${input.provider}`, + ], + grant_types: ["authorization_code", "refresh_token"], + response_types: ["code"], + token_endpoint_auth_method: "none", + }, + state: async () => `${input.provider}-auth-state`, + clientInformation: async () => undefined, + saveClientInformation: async () => undefined, + tokens: async () => undefined, + saveTokens: async () => undefined, + redirectToAuthorization: async (authorizationUrl: URL) => { + await patchMcpAuthSession(authSessionId, { + authorizationUrl: authorizationUrl.toString(), + }); + }, + saveCodeVerifier: async () => undefined, + codeVerifier: async () => "code-verifier", + }; + }, +})); + vi.mock("@/chat/pi/client", () => ({ GEN_AI_PROVIDER_NAME: "vercel-ai-gateway", getGatewayApiKey: () => "test-gateway-key", @@ -457,11 +527,10 @@ describe("generateAssistantReply progressive MCP loading", () => { expect(pausedCheckpoint).toMatchObject({ state: "awaiting_resume", loadedSkillNames: ["demo-skill"], - activeMcpProviders: [], resumeReason: "auth", }); expect(pausedCheckpoint?.piMessages.at(-1)).toMatchObject({ - role: "assistant", + role: "user", }); expect(deliverPrivateMessageMock).toHaveBeenCalledTimes(1); expect(loadSkillExecutionErrorCount.value).toBe(0); @@ -469,8 +538,8 @@ describe("generateAssistantReply progressive MCP loading", () => { const reply = await generateAssistantReply("help me", context); expect(reply.text).toBe("resumed reply"); - expect(promptCallCount.value).toBe(2); - expect(continueCallCount.value).toBe(0); + expect(promptCallCount.value).toBe(1); + expect(continueCallCount.value).toBe(1); expect(clientOptions).not.toContainEqual( expect.objectContaining({ sessionId: expect.any(String) }), ); @@ -478,8 +547,8 @@ describe("generateAssistantReply progressive MCP loading", () => { expect(agentInitialToolNames[1]).toContain("searchTools"); expect(agentInitialToolNames[1]).toContain("useTool"); expect(agentInitialToolNames[1]).not.toContain("mcp__demo__ping"); - expect(loadSkillAvailableToolNames).toEqual([[], ["mcp__demo__ping"]]); - expect(loadSkillToolSearchFlags).toEqual([false, true]); + expect(loadSkillAvailableToolNames).toEqual([[]]); + expect(loadSkillToolSearchFlags).toEqual([false]); expect(callToolMock).toHaveBeenCalledWith( expect.objectContaining({ manifest: expect.objectContaining({ name: "demo" }), @@ -495,7 +564,6 @@ describe("generateAssistantReply progressive MCP loading", () => { expect(resumedCheckpoint).toMatchObject({ state: "completed", loadedSkillNames: ["demo-skill"], - activeMcpProviders: ["demo"], }); }); @@ -557,7 +625,6 @@ describe("generateAssistantReply progressive MCP loading", () => { expect(checkpoint).toMatchObject({ state: "completed", loadedSkillNames: ["demo-skill"], - activeMcpProviders: ["demo"], }); }); }); diff --git a/specs/agent-session-resumability-spec.md b/specs/agent-session-resumability-spec.md index 094b494e..5c07f7b2 100644 --- a/specs/agent-session-resumability-spec.md +++ b/specs/agent-session-resumability-spec.md @@ -3,12 +3,13 @@ ## Metadata - Created: 2026-03-05 -- Last Edited: 2026-03-13 +- Last Edited: 2026-03-19 ## Changelog - 2026-03-05: Initial canonical contract for timeout-safe multi-slice assistant execution with Pi in serverless runtimes. - 2026-03-13: Added auth-driven resume reason and checkpointed dynamic tool state for MCP-backed turns. +- 2026-03-19: Simplified auth resume contract so resumed slices always use `continue()` after trimming trailing uncommitted assistant messages at the auth pause boundary. ## Status @@ -87,7 +88,6 @@ Each checkpoint must include: - `state`: one of `running|awaiting_resume|completed|failed`. - `resume_reason`: `timeout|auth|preempted|retry|operator` (when `awaiting_resume`). - `loaded_skill_names`: Active skills that must be restored before resume when tool availability depends on loaded skills. -- `active_mcp_providers`: Active plugin MCP providers that must be restored before resume when tools were progressively disclosed. - `deadline_at`: hard deadline for the current slice. - `updated_at` @@ -99,11 +99,11 @@ For slice `n+1`, runtime must: 1. Load latest committed checkpoint for `(conversation_id, session_id)`. 2. Instantiate Pi agent. -3. Restore any checkpointed dynamic tool state required by the wrapper runtime (for example loaded skills and active MCP providers). +3. Restore any checkpointed dynamic tool state required by the wrapper runtime (for example loaded skills). 4. Call `replaceMessages(checkpoint.pi_messages)`. -5. Resume generation with one of these modes: - - Default: call `continue()` to resume generation/tool loop. - - Auth fallback: if `resume_reason=auth` and `checkpoint.pi_messages` ends on an assistant message with no queued steering/follow-up input, do not call `continue()`. Replay the original user prompt after restoring dynamic tool state instead. +5. Resume generation by calling `continue()` to resume generation/tool loop. + +For auth-driven pauses, the checkpoint written at the pause boundary must trim any trailing uncommitted assistant-only messages so the restored Pi history is resumable with `continue()`. If the previous slice timed out after producing uncommitted partial assistant text, that text may be regenerated in the next slice. User-visible output must only include committed transcript content. From 361a4701c2dfc4f7786e6387a1711fdd906e5c02 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 13:18:44 -0700 Subject: [PATCH 14/28] test(logging): Cover escaped PEM redaction Add a regression test proving PEM private keys are still redacted when they appear inside escaped JSON strings. This documents the current behavior and closes out review concerns without widening the logging implementation. Co-Authored-By: Codex --- .../junior/tests/unit/logging-context.test.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/junior/tests/unit/logging-context.test.ts b/packages/junior/tests/unit/logging-context.test.ts index 008d2ac7..e966dbb4 100644 --- a/packages/junior/tests/unit/logging-context.test.ts +++ b/packages/junior/tests/unit/logging-context.test.ts @@ -338,4 +338,31 @@ describe("logging context ids", () => { expect(records[0]?.body).not.toContain("super-secret-material"); expect(records[0]?.body).not.toContain("truncated-without-footer"); }); + + it("redacts PEM private keys embedded in escaped JSON strings", async () => { + const { log, registerLogRecordSink } = await import("@/chat/logging"); + const records: Array<{ body: string }> = []; + const unregister = registerLogRecordSink((record) => { + records.push({ body: record.body }); + }); + + try { + log.error( + "pem_key_logged", + {}, + JSON.stringify({ + key: "-----BEGIN PRIVATE KEY-----\\nsuper-secret-material\\n-----END PRIVATE KEY-----", + ok: true, + }), + ); + } finally { + unregister(); + } + + expect(records).toHaveLength(1); + expect(records[0]?.body).toContain("-----BEGIN PRIVATE KEY-----"); + expect(records[0]?.body).toContain("...redacted..."); + expect(records[0]?.body).toContain("-----END PRIVATE KEY-----"); + expect(records[0]?.body).not.toContain("super-secret-material"); + }); }); From c89a315d178ab174f131319d7a81a9385a1f8e7c Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 13:22:15 -0700 Subject: [PATCH 15/28] fix(mcp): Clear cached tools after session reset Clear the cached MCP tool catalog whenever the client is disposed so a recovered session always reloads tools from the rebuilt transport. Add a focused unit regression covering the stale-session retry path to lock the refreshed tool list behavior. Co-Authored-By: Codex --- packages/junior/src/chat/mcp/client.ts | 2 +- packages/junior/tests/unit/mcp/client.test.ts | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/junior/src/chat/mcp/client.ts b/packages/junior/src/chat/mcp/client.ts index ad1d6884..d980e830 100644 --- a/packages/junior/src/chat/mcp/client.ts +++ b/packages/junior/src/chat/mcp/client.ts @@ -99,7 +99,6 @@ export class PluginMcpClient { } async close(): Promise { - this.listedTools = undefined; await this.disposeClient(); } @@ -207,6 +206,7 @@ export class PluginMcpClient { private async disposeClient(): Promise { const transport = this.transport; + this.listedTools = undefined; this.transport = undefined; this.client = undefined; diff --git a/packages/junior/tests/unit/mcp/client.test.ts b/packages/junior/tests/unit/mcp/client.test.ts index f88df4fa..da642820 100644 --- a/packages/junior/tests/unit/mcp/client.test.ts +++ b/packages/junior/tests/unit/mcp/client.test.ts @@ -218,4 +218,49 @@ describe("PluginMcpClient", () => { { authProvider }, ]); }); + + it("drops cached listed tools when session recovery rebuilds the client", async () => { + const authProvider = buildAuthProvider(); + authProvider.getMcpServerSessionId + .mockResolvedValueOnce("stale-session") + .mockResolvedValue(undefined); + authProvider.saveMcpServerSessionId.mockResolvedValue(undefined); + connectMock.mockImplementation(async () => undefined); + listToolsMock + .mockResolvedValueOnce({ + tools: [ + { + name: "notion-search", + title: "Search", + inputSchema: { type: "object", properties: {} }, + }, + ], + nextCursor: undefined, + }) + .mockResolvedValueOnce({ + tools: [ + { + name: "notion-query", + title: "Query", + inputSchema: { type: "object", properties: {} }, + }, + ], + nextCursor: undefined, + }); + callToolMock + .mockRejectedValueOnce(new StreamableHTTPError(404, "Session not found")) + .mockResolvedValueOnce({ content: [{ type: "text", text: "ok" }] }); + + const client = new PluginMcpClient(buildPlugin(), { authProvider }); + + await expect(client.listTools()).resolves.toEqual([ + expect.objectContaining({ name: "notion-search" }), + ]); + await expect(client.callTool("notion-search", undefined)).resolves.toEqual({ + content: [{ type: "text", text: "ok" }], + }); + await expect(client.listTools()).resolves.toEqual([ + expect.objectContaining({ name: "notion-query" }), + ]); + }); }); From 281ee96a79c1c4465f2ab509d8fe5963c4f1c4e6 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 13:53:50 -0700 Subject: [PATCH 16/28] ref(mcp): Simplify provider tool ownership Remove skill-level MCP tool allowlists so provider tool exposure is owned by the plugin manifest only. Extract shared provider unlink cleanup so app-home disconnect and jr-rpc provider deletion follow the same path. Co-Authored-By: Codex --- packages/junior-notion/skills/notion/SKILL.md | 1 - .../src/chat/bootstrap/register-handlers.ts | 13 +---- .../src/chat/capabilities/jr-rpc-command.ts | 13 +---- .../src/chat/credentials/unlink-provider.ts | 19 +++++++ packages/junior/src/chat/mcp/tool-manager.ts | 52 ++----------------- packages/junior/src/chat/respond.ts | 1 - packages/junior/src/chat/skill-frontmatter.ts | 9 ---- packages/junior/src/chat/skills.ts | 3 -- packages/junior/src/chat/tools/load-skill.ts | 3 -- packages/junior/tests/jr-rpc-command.test.ts | 34 +++--------- packages/junior/tests/load-skill-tool.test.ts | 4 -- .../junior/tests/skill-frontmatter.test.ts | 19 ------- .../tests/unit/mcp/tool-manager.test.ts | 42 +++++---------- .../respond-mcp-progressive-loading.test.ts | 1 - specs/plugin-spec.md | 4 +- 15 files changed, 49 insertions(+), 169 deletions(-) create mode 100644 packages/junior/src/chat/credentials/unlink-provider.ts diff --git a/packages/junior-notion/skills/notion/SKILL.md b/packages/junior-notion/skills/notion/SKILL.md index 45f950bb..d92c0226 100644 --- a/packages/junior-notion/skills/notion/SKILL.md +++ b/packages/junior-notion/skills/notion/SKILL.md @@ -1,7 +1,6 @@ --- name: notion description: Search Notion pages and data sources and summarize the best match. Use when users ask to look up docs, specs, notes, meeting notes, project context, roadmaps, trackers, or internal references stored in Notion. -allowed-mcp-tools: notion-search notion-fetch --- # Notion Operations diff --git a/packages/junior/src/chat/bootstrap/register-handlers.ts b/packages/junior/src/chat/bootstrap/register-handlers.ts index 97703bba..677283ac 100644 --- a/packages/junior/src/chat/bootstrap/register-handlers.ts +++ b/packages/junior/src/chat/bootstrap/register-handlers.ts @@ -5,11 +5,7 @@ import type { AppSlackRuntime, } from "@/chat/app-runtime"; import { getUserTokenStore } from "@/chat/capabilities/factory"; -import { - deleteMcpAuthSessionsForUserProvider, - deleteMcpServerSessionId, - deleteMcpStoredOAuthCredentials, -} from "@/chat/mcp/auth-store"; +import { unlinkProvider } from "@/chat/credentials/unlink-provider"; import { logException, withSpan } from "@/chat/observability"; import { publishAppHomeView } from "@/chat/app-home"; import { handleSlashCommand } from "@/chat/slash-command"; @@ -79,12 +75,7 @@ export function registerBotHandlers(args: { { slackUserId: userId }, async () => { try { - await Promise.all([ - getUserTokenStore().delete(userId, provider), - deleteMcpStoredOAuthCredentials(userId, provider), - deleteMcpServerSessionId(userId, provider), - deleteMcpAuthSessionsForUserProvider(userId, provider), - ]); + await unlinkProvider(userId, provider, getUserTokenStore()); await publishAppHomeView( getSlackClient(), userId, diff --git a/packages/junior/src/chat/capabilities/jr-rpc-command.ts b/packages/junior/src/chat/capabilities/jr-rpc-command.ts index 768a5a95..8523769e 100644 --- a/packages/junior/src/chat/capabilities/jr-rpc-command.ts +++ b/packages/junior/src/chat/capabilities/jr-rpc-command.ts @@ -5,13 +5,9 @@ import { parseRepoTarget } from "@/chat/capabilities/target"; import type { ChannelConfigurationService } from "@/chat/configuration/types"; import type { UserTokenStore } from "@/chat/credentials/user-token-store"; import { CredentialUnavailableError } from "@/chat/credentials/broker"; +import { unlinkProvider } from "@/chat/credentials/unlink-provider"; import { formatProviderLabel, startOAuthFlow } from "@/chat/oauth-flow"; import { logInfo } from "@/chat/observability"; -import { - deleteMcpAuthSessionsForUserProvider, - deleteMcpServerSessionId, - deleteMcpStoredOAuthCredentials, -} from "@/chat/mcp/auth-store"; import { getPluginOAuthConfig, isPluginProvider, @@ -487,12 +483,7 @@ async function handleDeleteTokenCommand( }); } - await Promise.all([ - deps.userTokenStore.delete(deps.requesterId, provider), - deleteMcpStoredOAuthCredentials(deps.requesterId, provider), - deleteMcpServerSessionId(deps.requesterId, provider), - deleteMcpAuthSessionsForUserProvider(deps.requesterId, provider), - ]); + await unlinkProvider(deps.requesterId, provider, deps.userTokenStore); logInfo( "jr_rpc_delete_token", diff --git a/packages/junior/src/chat/credentials/unlink-provider.ts b/packages/junior/src/chat/credentials/unlink-provider.ts new file mode 100644 index 00000000..5234a9a5 --- /dev/null +++ b/packages/junior/src/chat/credentials/unlink-provider.ts @@ -0,0 +1,19 @@ +import type { UserTokenStore } from "@/chat/credentials/user-token-store"; +import { + deleteMcpAuthSessionsForUserProvider, + deleteMcpServerSessionId, + deleteMcpStoredOAuthCredentials, +} from "@/chat/mcp/auth-store"; + +export async function unlinkProvider( + userId: string, + provider: string, + userTokenStore: UserTokenStore, +): Promise { + await Promise.all([ + userTokenStore.delete(userId, provider), + deleteMcpStoredOAuthCredentials(userId, provider), + deleteMcpServerSessionId(userId, provider), + deleteMcpAuthSessionsForUserProvider(userId, provider), + ]); +} diff --git a/packages/junior/src/chat/mcp/tool-manager.ts b/packages/junior/src/chat/mcp/tool-manager.ts index f90ece72..d45810f3 100644 --- a/packages/junior/src/chat/mcp/tool-manager.ts +++ b/packages/junior/src/chat/mcp/tool-manager.ts @@ -157,15 +157,9 @@ export interface ManagedMcpToolDescriptor { provider: string; } -type ActiveMcpSkillScope = Pick< - SkillMetadata, - "pluginProvider" | "allowedMcpTools" ->; +type ActiveMcpSkillScope = Pick; -type ActiveMcpSkill = Pick< - SkillMetadata, - "name" | "pluginProvider" | "allowedMcpTools" ->; +type ActiveMcpSkill = Pick; interface ManagedMcpTool extends ManagedMcpToolDescriptor { rawName: string; @@ -201,11 +195,7 @@ export class McpToolManager { return false; } - const activated = await this.activateProvider(skill.pluginProvider); - if (this.activeProviders.has(skill.pluginProvider)) { - this.assertSkillToolExposure(skill); - } - return activated; + return await this.activateProvider(skill.pluginProvider); } async activateProvider(provider: string): Promise { @@ -430,29 +420,6 @@ export class McpToolManager { ); } - private assertSkillToolExposure(skill: ActiveMcpSkill): void { - const provider = skill.pluginProvider; - if ( - !provider || - !skill.allowedMcpTools || - skill.allowedMcpTools.length === 0 - ) { - return; - } - - const availableToolNames = new Set( - (this.toolsByProvider.get(provider) ?? []).map((tool) => tool.rawName), - ); - const missingTools = skill.allowedMcpTools.filter( - (toolName) => !availableToolNames.has(toolName), - ); - if (missingTools.length > 0) { - throw new Error( - `Skill ${skill.name} declares unavailable MCP tools for plugin ${provider}: ${missingTools.join(", ")}`, - ); - } - } - private getResolvedActiveTools( skills: ActiveMcpSkillScope[], options: { provider?: string } = {}, @@ -485,18 +452,7 @@ export class McpToolManager { if (relevantSkills.length === 0) { return []; } - - const exposeAllProviderTools = relevantSkills.some( - (skill) => !skill.allowedMcpTools || skill.allowedMcpTools.length === 0, - ); - if (exposeAllProviderTools) { - return providerTools; - } - - const allowedToolNames = new Set( - relevantSkills.flatMap((skill) => skill.allowedMcpTools ?? []), - ); - return providerTools.filter((tool) => allowedToolNames.has(tool.rawName)); + return providerTools; } private resolveActiveTool( diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index 6018ac8e..2f4a45b8 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -664,7 +664,6 @@ function upsertActiveSkill(activeSkills: Skill[], next: Skill): void { existing.description = next.description; existing.skillPath = next.skillPath; existing.allowedTools = next.allowedTools; - existing.allowedMcpTools = next.allowedMcpTools; existing.requiresCapabilities = next.requiresCapabilities; existing.usesConfig = next.usesConfig; existing.pluginProvider = next.pluginProvider; diff --git a/packages/junior/src/chat/skill-frontmatter.ts b/packages/junior/src/chat/skill-frontmatter.ts index ad48d7fb..0b83d39c 100644 --- a/packages/junior/src/chat/skill-frontmatter.ts +++ b/packages/junior/src/chat/skill-frontmatter.ts @@ -16,7 +16,6 @@ export interface ParsedSkillFile { compatibility?: string; license?: string; allowedTools?: string[]; - allowedMcpTools?: string[]; requiresCapabilities?: string[]; usesConfig?: string[]; } @@ -143,12 +142,6 @@ const skillFrontmatterSchema = z 'Frontmatter field "allowed-tools" must be a string when present', }) .optional(), - "allowed-mcp-tools": z - .string({ - error: - 'Frontmatter field "allowed-mcp-tools" must be a string when present', - }) - .optional(), "requires-capabilities": createTokenFieldSchema( "requires-capabilities", "github.issues.write", @@ -203,7 +196,6 @@ export function parseSkillFile( } const allowedTools = parseTokenList(result.data["allowed-tools"]); - const allowedMcpTools = parseTokenList(result.data["allowed-mcp-tools"]); const requiresCapabilities = parseTokenList( result.data["requires-capabilities"], ); @@ -223,7 +215,6 @@ export function parseSkillFile( ? { license: result.data.license } : {}), ...(allowedTools ? { allowedTools } : {}), - ...(allowedMcpTools ? { allowedMcpTools } : {}), ...(requiresCapabilities ? { requiresCapabilities } : {}), ...(usesConfig ? { usesConfig } : {}), }, diff --git a/packages/junior/src/chat/skills.ts b/packages/junior/src/chat/skills.ts index f7a71460..be08d946 100644 --- a/packages/junior/src/chat/skills.ts +++ b/packages/junior/src/chat/skills.ts @@ -20,7 +20,6 @@ export interface SkillMetadata { skillPath: string; pluginProvider?: string; allowedTools?: string[]; - allowedMcpTools?: string[]; requiresCapabilities?: string[]; usesConfig?: string[]; } @@ -119,7 +118,6 @@ async function readSkillDirectory( name, description, allowedTools, - allowedMcpTools, requiresCapabilities, usesConfig, } = parsed.skill; @@ -147,7 +145,6 @@ async function readSkillDirectory( skillPath: skillDir, ...(plugin ? { pluginProvider: plugin.manifest.name } : {}), allowedTools, - allowedMcpTools, requiresCapabilities, usesConfig, }; diff --git a/packages/junior/src/chat/tools/load-skill.ts b/packages/junior/src/chat/tools/load-skill.ts index 931af0d7..6e0676cb 100644 --- a/packages/junior/src/chat/tools/load-skill.ts +++ b/packages/junior/src/chat/tools/load-skill.ts @@ -49,9 +49,6 @@ function toLoadedSkill( ? { pluginProvider: metadata.pluginProvider } : {}), ...(metadata?.allowedTools ? { allowedTools: metadata.allowedTools } : {}), - ...(metadata?.allowedMcpTools - ? { allowedMcpTools: metadata.allowedMcpTools } - : {}), ...(metadata?.requiresCapabilities ? { requiresCapabilities: metadata.requiresCapabilities } : {}), diff --git a/packages/junior/tests/jr-rpc-command.test.ts b/packages/junior/tests/jr-rpc-command.test.ts index eb88bf46..9b066fcf 100644 --- a/packages/junior/tests/jr-rpc-command.test.ts +++ b/packages/junior/tests/jr-rpc-command.test.ts @@ -1,13 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -const { - deleteMcpAuthSessionsForUserProviderMock, - deleteMcpServerSessionIdMock, - deleteMcpStoredOAuthCredentialsMock, -} = vi.hoisted(() => ({ - deleteMcpAuthSessionsForUserProviderMock: vi.fn(), - deleteMcpServerSessionIdMock: vi.fn(), - deleteMcpStoredOAuthCredentialsMock: vi.fn(), +const { unlinkProviderMock } = vi.hoisted(() => ({ + unlinkProviderMock: vi.fn(), })); vi.mock("@/chat/capabilities/catalog", () => ({ @@ -33,11 +27,8 @@ vi.mock("@/chat/capabilities/catalog", () => ({ }, ], })); -vi.mock("@/chat/mcp/auth-store", () => ({ - deleteMcpAuthSessionsForUserProvider: - deleteMcpAuthSessionsForUserProviderMock, - deleteMcpServerSessionId: deleteMcpServerSessionIdMock, - deleteMcpStoredOAuthCredentials: deleteMcpStoredOAuthCredentialsMock, +vi.mock("@/chat/credentials/unlink-provider", () => ({ + unlinkProvider: unlinkProviderMock, })); vi.mock("@/chat/plugins/registry", () => ({ getPluginOAuthConfig: () => undefined, @@ -106,12 +97,8 @@ function makeRuntime( describe("jr-rpc custom command", () => { beforeEach(() => { - deleteMcpAuthSessionsForUserProviderMock.mockReset(); - deleteMcpAuthSessionsForUserProviderMock.mockResolvedValue(undefined); - deleteMcpServerSessionIdMock.mockReset(); - deleteMcpServerSessionIdMock.mockResolvedValue(undefined); - deleteMcpStoredOAuthCredentialsMock.mockReset(); - deleteMcpStoredOAuthCredentialsMock.mockResolvedValue(undefined); + unlinkProviderMock.mockReset(); + unlinkProviderMock.mockResolvedValue(undefined); }); it("deletes both legacy and MCP-backed provider credentials", async () => { @@ -136,15 +123,10 @@ describe("jr-rpc custom command", () => { expect(result.result.exit_code).toBe(0); expect(result.result.stdout).toContain("token_deleted provider=notion"); } - expect(userTokenStore.delete).toHaveBeenCalledWith("U123", "notion"); - expect(deleteMcpStoredOAuthCredentialsMock).toHaveBeenCalledWith( - "U123", - "notion", - ); - expect(deleteMcpServerSessionIdMock).toHaveBeenCalledWith("U123", "notion"); - expect(deleteMcpAuthSessionsForUserProviderMock).toHaveBeenCalledWith( + expect(unlinkProviderMock).toHaveBeenCalledWith( "U123", "notion", + userTokenStore, ); }); diff --git a/packages/junior/tests/load-skill-tool.test.ts b/packages/junior/tests/load-skill-tool.test.ts index 8361528b..0fda86ff 100644 --- a/packages/junior/tests/load-skill-tool.test.ts +++ b/packages/junior/tests/load-skill-tool.test.ts @@ -11,7 +11,6 @@ describe("load_skill tool", () => { (skill) => skill.pluginProvider || skill.allowedTools || - skill.allowedMcpTools || skill.requiresCapabilities || skill.usesConfig, ); @@ -60,9 +59,6 @@ describe("load_skill tool", () => { ...(firstSkill.allowedTools ? { allowedTools: firstSkill.allowedTools } : {}), - ...(firstSkill.allowedMcpTools - ? { allowedMcpTools: firstSkill.allowedMcpTools } - : {}), ...(firstSkill.requiresCapabilities ? { requiresCapabilities: firstSkill.requiresCapabilities } : {}), diff --git a/packages/junior/tests/skill-frontmatter.test.ts b/packages/junior/tests/skill-frontmatter.test.ts index 6411f01b..dac76067 100644 --- a/packages/junior/tests/skill-frontmatter.test.ts +++ b/packages/junior/tests/skill-frontmatter.test.ts @@ -104,25 +104,6 @@ describe("skill frontmatter validation", () => { ]); }); - it("accepts valid allowed-mcp-tools tokens", () => { - const raw = [ - "---", - "name: brief", - "description: Create a candidate brief from public engineering signals.", - "allowed-mcp-tools: notion-search notion-fetch", - "---", - "", - "# Body", - ].join("\n"); - - const result = parseSkillFile(raw, "brief"); - expect(result.ok).toBe(true); - expect(result.ok ? result.skill.allowedMcpTools : null).toEqual([ - "notion-search", - "notion-fetch", - ]); - }); - it("rejects invalid uses-config tokens", () => { const raw = [ "---", diff --git a/packages/junior/tests/unit/mcp/tool-manager.test.ts b/packages/junior/tests/unit/mcp/tool-manager.test.ts index 1294c92e..f4e71334 100644 --- a/packages/junior/tests/unit/mcp/tool-manager.test.ts +++ b/packages/junior/tests/unit/mcp/tool-manager.test.ts @@ -305,7 +305,7 @@ describe("McpToolManager", () => { ).toEqual(["mcp__notion__notion-search", "mcp__notion__notion-fetch"]); }); - it("narrows the active registry to the skill-level MCP allowlist", async () => { + it("exposes the provider tool catalog once a plugin skill is active", async () => { const plugin = buildPlugin("notion"); listToolsMock.mockResolvedValue([ { @@ -333,7 +333,6 @@ describe("McpToolManager", () => { { name: "notion", pluginProvider: "notion", - allowedMcpTools: ["notion-search", "notion-fetch"], }, ]; @@ -341,15 +340,22 @@ describe("McpToolManager", () => { expect( manager.getActiveToolCatalog(activeSkills).map((tool) => tool.name), - ).toEqual(["mcp__notion__notion-search", "mcp__notion__notion-fetch"]); + ).toEqual([ + "mcp__notion__notion-search", + "mcp__notion__notion-fetch", + "mcp__notion__notion-create-pages", + ]); expect( manager.searchTools(activeSkills, "fetch").map((tool) => tool.name), ).toEqual(["mcp__notion__notion-fetch"]); await expect( manager.executeTool(activeSkills, "mcp__notion__notion-create-pages", {}), - ).rejects.toThrow( - "Unknown active MCP tool: mcp__notion__notion-create-pages", - ); + ).resolves.toMatchObject({ + details: { + provider: "notion", + tool: "notion-create-pages", + }, + }); }); it("fails activation when an allowlisted MCP tool is missing", async () => { @@ -371,28 +377,4 @@ describe("McpToolManager", () => { "Plugin notion MCP discovery missing allowlisted tools: notion-fetch", ); }); - - it("fails skill activation when the skill declares unavailable MCP tools", async () => { - const plugin = buildPlugin("notion"); - listToolsMock.mockResolvedValue([ - { - name: "notion-search", - title: "Search", - description: "Search Notion", - inputSchema: { type: "object", properties: {} }, - }, - ]); - - const manager = new McpToolManager([plugin]); - - await expect( - manager.activateForSkill({ - name: "notion", - pluginProvider: "notion", - allowedMcpTools: ["notion-search", "notion-fetch"], - }), - ).rejects.toThrow( - "Skill notion declares unavailable MCP tools for plugin notion: notion-fetch", - ); - }); }); diff --git a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts index 140bd890..31f32580 100644 --- a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts +++ b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts @@ -440,7 +440,6 @@ describe("generateAssistantReply progressive MCP loading", () => { description: "Demo skill", skillPath: "/tmp/skills/demo-skill", pluginProvider: "demo", - allowedMcpTools: ["ping"], body: "Skill instructions", }, ]); diff --git a/specs/plugin-spec.md b/specs/plugin-spec.md index 7c859d89..facf826b 100644 --- a/specs/plugin-spec.md +++ b/specs/plugin-spec.md @@ -14,7 +14,7 @@ - 2026-03-09: Added OAuth request overrides, optional OAuth scope, and plugin-level API headers. - 2026-03-13: Implemented HTTP MCP manifests, same-plugin progressive tool activation, and dedicated MCP OAuth callbacks. - 2026-03-18: Added provider-scoped MCP tool allowlists for read-only plugin surfaces. -- 2026-03-18: Replaced per-MCP-tool Pi registration with stable `searchTools`/`useTool` dispatch and skill-level `allowed-mcp-tools` exposure. +- 2026-03-18: Replaced per-MCP-tool Pi registration with stable `searchTools`/`useTool` dispatch and plugin-level MCP allowlists. ## Status @@ -266,7 +266,7 @@ createPluginBroker(provider, deps: PluginBrokerDeps): CredentialBroker - Mid-turn `loadSkill` updates the host-managed MCP registry and returns `available_tools` for the newly exposed tools, including canonical `tool_name` values and full input schemas. - The prompt includes a compact `` section with the active MCP tool registry for the turn. - When `mcp.allowed-tools` is set, discovery is filtered before exposure and provider activation fails if any allowlisted tool is absent. -- Skills may further narrow MCP exposure with `allowed-mcp-tools` frontmatter using raw provider tool names. Skill load fails if any listed tool is unavailable after provider discovery and provider-level allowlist filtering. +- MCP exposure is owned by the plugin manifest via `mcp.allowed-tools`; skill files do not declare per-tool MCP allowlists. - Canonical MCP tool names remain `mcp____`. - MCP authorization uses a dedicated callback path at `/api/oauth/callback/mcp/` and resumes the paused turn session after the user authorizes. From 4309ec7a2342213d3ff07fc9143dcef7528541ff Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 15:08:57 -0700 Subject: [PATCH 17/28] ref(mcp): Clarify auth pause snapshot timing Document why only the timeout branch waits for prompt settlement before snapshotting agent messages, and why auth-pause snapshots are already final once promptPromise settles. Co-Authored-By: Codex --- packages/junior/src/chat/respond.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index 2f4a45b8..88a16ca6 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -1523,10 +1523,17 @@ export async function generateAssistantReply( }, "Agent turn timed out and was aborted", ); + // The timeout branch wins the race via timeoutPromise, so the + // agent loop may still be settling its final message state. Wait + // for promptPromise before snapshotting messages for resume. await promptPromise.catch(() => {}); timeoutResumeMessages = [...(agent.state.messages as unknown[])]; } if (pendingMcpAuthorizationPause) { + // For non-timeout failures, pi-agent-core only settles + // promptPromise after it has finished mutating agent.state. + // By the time we get here, the prompt already settled, so the + // current message snapshot is final for auth-pause checkpointing. timeoutResumeMessages = [...(agent.state.messages as unknown[])]; throw pendingMcpAuthorizationPause; } From 8adcc789b9214778436200db9758dccc7ef1d08a Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 15:23:49 -0700 Subject: [PATCH 18/28] fix(mcp): Handle auth challenges during connect Catch MCP authorization errors raised during initial client setup so provider activation uses the same auth-pause path as discovery-time failures. Add focused unit coverage for the connect-time auth-required case. Co-Authored-By: Codex --- packages/junior/src/chat/mcp/tool-manager.ts | 3 +-- .../tests/unit/mcp/tool-manager.test.ts | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/junior/src/chat/mcp/tool-manager.ts b/packages/junior/src/chat/mcp/tool-manager.ts index d45810f3..cba2831c 100644 --- a/packages/junior/src/chat/mcp/tool-manager.ts +++ b/packages/junior/src/chat/mcp/tool-manager.ts @@ -208,9 +208,8 @@ export class McpToolManager { return false; } - const client = await this.getClient(plugin); - try { + const client = await this.getClient(plugin); const tools = this.filterListedTools(plugin, await client.listTools()); this.toolsByProvider.set( provider, diff --git a/packages/junior/tests/unit/mcp/tool-manager.test.ts b/packages/junior/tests/unit/mcp/tool-manager.test.ts index f4e71334..5611f7bf 100644 --- a/packages/junior/tests/unit/mcp/tool-manager.test.ts +++ b/packages/junior/tests/unit/mcp/tool-manager.test.ts @@ -4,12 +4,14 @@ import type { PluginDefinition } from "@/chat/plugins/types"; const { callToolMock, clientOptions, + clientSetupError, closeMock, listToolsMock, onAuthorizationRequiredMock, } = vi.hoisted(() => ({ callToolMock: vi.fn(), clientOptions: [] as unknown[], + clientSetupError: { value: undefined as unknown }, closeMock: vi.fn(), listToolsMock: vi.fn(), onAuthorizationRequiredMock: vi.fn(), @@ -31,6 +33,9 @@ vi.mock("@/chat/mcp/client", () => { private readonly plugin: PluginDefinition, options?: unknown, ) { + if (clientSetupError.value) { + throw clientSetupError.value; + } clientOptions.push(options); } @@ -84,6 +89,7 @@ describe("McpToolManager", () => { closeMock.mockReset(); onAuthorizationRequiredMock.mockReset(); clientOptions.length = 0; + clientSetupError.value = undefined; listToolsMock.mockResolvedValue([ { @@ -243,6 +249,24 @@ describe("McpToolManager", () => { expect(manager.getActiveProviders()).toEqual([]); }); + it("parks handled MCP authorization challenges during initial client setup", async () => { + const plugin = buildPlugin(); + const authError = new McpAuthorizationRequiredError( + "demo", + "Connect auth required", + ); + clientSetupError.value = authError; + onAuthorizationRequiredMock.mockResolvedValueOnce(true); + const manager = new McpToolManager([plugin], { + onAuthorizationRequired: onAuthorizationRequiredMock, + }); + + await expect(manager.activateProvider("demo")).resolves.toBe(false); + expect(onAuthorizationRequiredMock).toHaveBeenCalledTimes(1); + expect(onAuthorizationRequiredMock).toHaveBeenCalledWith("demo", authError); + expect(manager.getActiveProviders()).toEqual([]); + }); + it("closes every active client before surfacing the first close error", async () => { const alphaPlugin = buildPlugin("alpha"); const betaPlugin = buildPlugin("beta"); From b31c536bde06aec3a0f83d93401270a45d3ec579 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 15:31:50 -0700 Subject: [PATCH 19/28] fix(mcp): Preserve auth resume on checkpoint failures Wrap auth-pause checkpoint persistence so transient state adapter failures do not replace the intended auth resume retry path. Add a regression test to keep this control flow aligned with timeout checkpoint handling. Co-Authored-By: Codex --- packages/junior/src/chat/respond.ts | 44 ++++++++++++++----- .../respond-mcp-progressive-loading.test.ts | 27 ++++++++++++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index 88a16ca6..47abd6cd 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -1755,17 +1755,39 @@ export async function generateAssistantReply( ) { const nextSliceId = timeoutResumeSliceId + 1; const piMessages = trimTrailingAssistantMessages(timeoutResumeMessages); - await upsertAgentTurnSessionCheckpoint({ - conversationId: timeoutResumeConversationId, - sessionId: timeoutResumeSessionId, - sliceId: nextSliceId, - state: "awaiting_resume", - piMessages, - loadedSkillNames: loadedSkillNamesForResume, - resumeReason: "auth", - resumedFromSliceId: timeoutResumeSliceId, - errorMessage: error.message, - }); + try { + await upsertAgentTurnSessionCheckpoint({ + conversationId: timeoutResumeConversationId, + sessionId: timeoutResumeSessionId, + sliceId: nextSliceId, + state: "awaiting_resume", + piMessages, + loadedSkillNames: loadedSkillNamesForResume, + resumeReason: "auth", + resumedFromSliceId: timeoutResumeSliceId, + errorMessage: error.message, + }); + } catch (checkpointError) { + logException( + checkpointError, + "agent_turn_auth_resume_checkpoint_failed", + { + slackThreadId: context.correlation?.threadId, + slackUserId: context.correlation?.requesterId, + slackChannelId: context.correlation?.channelId, + runId: context.correlation?.runId, + assistantUserName: context.assistant?.userName, + modelId: botConfig.modelId, + }, + { + "app.ai.resume_conversation_id": timeoutResumeConversationId, + "app.ai.resume_session_id": timeoutResumeSessionId, + "app.ai.resume_from_slice_id": timeoutResumeSliceId, + "app.ai.resume_next_slice_id": nextSliceId, + }, + "Failed to persist auth checkpoint before retry", + ); + } throw new RetryableTurnError( "mcp_auth_resume", `conversation=${timeoutResumeConversationId} session=${timeoutResumeSessionId} slice=${nextSliceId}`, diff --git a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts index 31f32580..a9a6f604 100644 --- a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts +++ b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts @@ -403,6 +403,7 @@ vi.mock("@/chat/mcp/client", () => { }); import { generateAssistantReply } from "@/chat/respond"; +import * as stateModule from "@/chat/state"; import { disconnectStateAdapter, getAgentTurnSessionCheckpoint, @@ -626,4 +627,30 @@ describe("generateAssistantReply progressive MCP loading", () => { loadedSkillNames: ["demo-skill"], }); }); + + it("still returns auth resume when auth checkpoint persistence fails", async () => { + const checkpointSpy = vi + .spyOn(stateModule, "upsertAgentTurnSessionCheckpoint") + .mockImplementationOnce(async () => { + throw new Error("state adapter unavailable"); + }); + + const context = { + assistant: { userName: "junior" }, + requester: { userId: "U123" }, + correlation: { + conversationId: "conversation-3", + turnId: "turn-3", + channelId: "C123", + threadTs: "1712345.0003", + }, + }; + + const firstError = await generateAssistantReply("help me", context).catch( + (error) => error, + ); + + expect(isRetryableTurnError(firstError, "mcp_auth_resume")).toBe(true); + expect(checkpointSpy).toHaveBeenCalled(); + }); }); From 5a7b11b04c6f2c5f24dcb4f74471e9b4f58a4c0a Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 15:57:29 -0700 Subject: [PATCH 20/28] fix(logging): Remove enduser.id from console priority keys Remove enduser.id from the console priority ordering. The key remains hidden in compact console output, so this only changes sorting behavior for console attributes. Co-Authored-By: Codex --- packages/junior/src/chat/logging.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/junior/src/chat/logging.ts b/packages/junior/src/chat/logging.ts index a60d68de..be60f68b 100644 --- a/packages/junior/src/chat/logging.ts +++ b/packages/junior/src/chat/logging.ts @@ -105,7 +105,6 @@ const CONSOLE_PRIORITY_KEYS = [ "app.agent.id", "messaging.message.conversation_id", "messaging.destination.name", - "enduser.id", "app.run.id", "app.message.kind", ] as const; From d0bbfe88fcdfdd8c7ab9e8e2e36b249e18f04a05 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Thu, 19 Mar 2026 18:09:59 -0700 Subject: [PATCH 21/28] fix(mcp): Keep completed turns after auth races Ignore MCP auth-pause requests once the turn has already produced a completed assistant stop reason, while still parking aborted turns for resume. Add focused unit coverage for the tool-call race so completed turns are not discarded when an auth request arrives too late to interrupt them. Co-Authored-By: Codex --- packages/junior/src/chat/respond.ts | 21 ++++++- .../respond-mcp-progressive-loading.test.ts | 62 +++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index 47abd6cd..f9052aac 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -657,6 +657,18 @@ function extractAssistantText(message: AssistantMessage): string { .join("\n"); } +function hasCompletedAssistantTurn(messages: unknown[]): boolean { + for (let index = messages.length - 1; index >= 0; index -= 1) { + const message = messages[index]; + if (!isAssistantMessage(message)) { + continue; + } + const stopReason = (message as { stopReason?: unknown }).stopReason; + return typeof stopReason === "string" && stopReason !== "error"; + } + return false; +} + function upsertActiveSkill(activeSkills: Skill[], next: Skill): void { const existing = activeSkills.find((skill) => skill.name === next.name); if (existing) { @@ -1469,6 +1481,7 @@ export async function generateAssistantReply( let beforeMessageCount = agent.state.messages.length; let newMessages: unknown[] = []; + let completedAssistantTurn = false; try { if (resumedFromCheckpoint) { @@ -1547,10 +1560,14 @@ export async function generateAssistantReply( newMessages = agent.state.messages.slice( beforeMessageCount, ) as unknown[]; - if (pendingMcpAuthorizationPause) { + completedAssistantTurn = hasCompletedAssistantTurn(newMessages); + if (pendingMcpAuthorizationPause && !completedAssistantTurn) { timeoutResumeMessages = [...(agent.state.messages as unknown[])]; throw pendingMcpAuthorizationPause; } + if (pendingMcpAuthorizationPause && completedAssistantTurn) { + pendingMcpAuthorizationPause = undefined; + } const outputMessages = newMessages.filter(isAssistantMessage); const outputMessagesAttribute = serializeGenAiAttribute(outputMessages); @@ -1579,7 +1596,7 @@ export async function generateAssistantReply( unsubscribe(); } - if (pendingMcpAuthorizationPause) { + if (pendingMcpAuthorizationPause && !completedAssistantTurn) { throw pendingMcpAuthorizationPause; } diff --git a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts index a9a6f604..0974a033 100644 --- a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts +++ b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts @@ -140,6 +140,7 @@ vi.mock("@mariozechner/pi-agent-core", () => { this.state.messages.push({ role: "assistant", content: [{ type: "text", text: "resumed reply" }], + stopReason: "stop", }); return {}; } @@ -165,6 +166,7 @@ vi.mock("@mariozechner/pi-agent-core", () => { this.state.messages.push({ role: "assistant", content: [{ type: "text", text: "resumed reply" }], + stopReason: "stop", }); return {}; } @@ -628,6 +630,66 @@ describe("generateAssistantReply progressive MCP loading", () => { }); }); + it("keeps a completed turn when MCP auth is requested during a tool call", async () => { + listToolsMock.mockReset(); + listToolsMock.mockImplementation( + async ( + plugin: { manifest: { name: string } }, + options: { + authProvider?: { + redirectToAuthorization?: (authorizationUrl: URL) => Promise; + }; + }, + ) => { + await options.authProvider?.redirectToAuthorization?.( + new URL(`https://auth.example.com/${plugin.manifest.name}`), + ); + return [ + { + name: "ping", + title: "Ping", + description: "Ping the demo MCP server", + inputSchema: { + type: "object", + properties: {}, + }, + }, + ]; + }, + ); + callToolMock.mockImplementationOnce(async (plugin) => { + const { McpAuthorizationRequiredError } = + await import("@/chat/mcp/client"); + throw new McpAuthorizationRequiredError( + plugin.manifest.name, + "Auth required", + ); + }); + + const reply = await generateAssistantReply("help me", { + assistant: { userName: "junior" }, + requester: { userId: "U123" }, + correlation: { + conversationId: "conversation-4", + turnId: "turn-4", + channelId: "C123", + threadTs: "1712345.0004", + }, + }); + + expect(reply.text).toBe("resumed reply"); + expect(deliverPrivateMessageMock).toHaveBeenCalledTimes(1); + + const checkpoint = await getAgentTurnSessionCheckpoint( + "conversation-4", + "turn-4", + ); + expect(checkpoint).toMatchObject({ + state: "completed", + loadedSkillNames: ["demo-skill"], + }); + }); + it("still returns auth resume when auth checkpoint persistence fails", async () => { const checkpointSpy = vi .spyOn(stateModule, "upsertAgentTurnSessionCheckpoint") From d85e877d192011dfabd11c0f8adc01455c90b239 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Fri, 20 Mar 2026 09:53:01 -0700 Subject: [PATCH 22/28] fix(mcp): Restore auth resume checkpoint state Fall back to the latest stored turn checkpoint when an auth pause captures no in-memory messages so resumed turns keep their prior context. Add a focused unit regression covering the empty-capture auth-resume path to keep it aligned with the existing timeout fallback behavior. Co-Authored-By: Codex --- packages/junior/src/chat/respond.ts | 10 ++- .../respond-mcp-progressive-loading.test.ts | 73 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index f9052aac..2142a16c 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -1771,8 +1771,16 @@ export async function generateAssistantReply( timeoutResumeSessionId ) { const nextSliceId = timeoutResumeSliceId + 1; - const piMessages = trimTrailingAssistantMessages(timeoutResumeMessages); try { + const latestCheckpoint = await getAgentTurnSessionCheckpoint( + timeoutResumeConversationId, + timeoutResumeSessionId, + ); + const piMessages = trimTrailingAssistantMessages( + timeoutResumeMessages.length > 0 + ? timeoutResumeMessages + : (latestCheckpoint?.piMessages ?? []), + ); await upsertAgentTurnSessionCheckpoint({ conversationId: timeoutResumeConversationId, sessionId: timeoutResumeSessionId, diff --git a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts index 0974a033..a2280e51 100644 --- a/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts +++ b/packages/junior/tests/unit/respond-mcp-progressive-loading.test.ts @@ -5,7 +5,9 @@ const { callToolMock, clientOptions, continueCallCount, + continueStopsOnAbort, deliverPrivateMessageMock, + ignoreReplaceMessages, listToolsMock, loadSkillAvailableToolNames, loadSkillExecutionErrorCount, @@ -17,7 +19,9 @@ const { callToolMock: vi.fn(), clientOptions: [] as Array>, continueCallCount: { value: 0 }, + continueStopsOnAbort: { value: false }, deliverPrivateMessageMock: vi.fn(), + ignoreReplaceMessages: { value: false }, listToolsMock: vi.fn(), loadSkillAvailableToolNames: [] as string[][], loadSkillExecutionErrorCount: { value: 0 }, @@ -67,6 +71,9 @@ vi.mock("@mariozechner/pi-agent-core", () => { } async replaceMessages(messages: unknown[]) { + if (ignoreReplaceMessages.value) { + return; + } this.state.messages = [...messages]; } @@ -163,6 +170,9 @@ vi.mock("@mariozechner/pi-agent-core", () => { tool_name: "mcp__demo__ping", arguments: { query: "hello" }, }); + if (this.aborted && continueStopsOnAbort.value) { + return {}; + } this.state.messages.push({ role: "assistant", content: [{ type: "text", text: "resumed reply" }], @@ -418,7 +428,9 @@ describe("generateAssistantReply progressive MCP loading", () => { callToolMock.mockReset(); clientOptions.length = 0; continueCallCount.value = 0; + continueStopsOnAbort.value = false; deliverPrivateMessageMock.mockReset(); + ignoreReplaceMessages.value = false; listToolsMock.mockReset(); loadSkillAvailableToolNames.length = 0; loadSkillExecutionErrorCount.value = 0; @@ -715,4 +727,65 @@ describe("generateAssistantReply progressive MCP loading", () => { expect(isRetryableTurnError(firstError, "mcp_auth_resume")).toBe(true); expect(checkpointSpy).toHaveBeenCalled(); }); + + it("falls back to the latest stored checkpoint when auth pause captures no messages", async () => { + ignoreReplaceMessages.value = true; + continueStopsOnAbort.value = true; + + const priorMessages = [ + { + role: "user", + content: [{ type: "text", text: "help me" }], + }, + { + role: "assistant", + content: [{ type: "text", text: "working on it" }], + }, + ]; + const expectedResumeMessages = [priorMessages[0]]; + await stateModule.upsertAgentTurnSessionCheckpoint({ + conversationId: "conversation-5", + sessionId: "turn-5", + sliceId: 1, + state: "awaiting_resume", + piMessages: priorMessages, + loadedSkillNames: ["demo-skill"], + resumeReason: "auth", + }); + + callToolMock.mockImplementationOnce(async (plugin) => { + const { McpAuthorizationRequiredError } = + await import("@/chat/mcp/client"); + throw new McpAuthorizationRequiredError( + plugin.manifest.name, + "Auth required", + ); + }); + + const firstError = await generateAssistantReply("help me", { + assistant: { userName: "junior" }, + requester: { userId: "U123" }, + correlation: { + conversationId: "conversation-5", + turnId: "turn-5", + channelId: "C123", + threadTs: "1712345.0005", + }, + }).catch((error) => error); + + expect(isRetryableTurnError(firstError, "mcp_auth_resume")).toBe(true); + + const resumedCheckpoint = await getAgentTurnSessionCheckpoint( + "conversation-5", + "turn-5", + ); + expect(resumedCheckpoint).toMatchObject({ + state: "awaiting_resume", + sliceId: 2, + resumedFromSliceId: 1, + piMessages: expectedResumeMessages, + loadedSkillNames: ["demo-skill"], + resumeReason: "auth", + }); + }); }); From c40e3e8738e5ae9d030cfc1eb9a83bbbbe99ef10 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Fri, 20 Mar 2026 16:58:18 -0700 Subject: [PATCH 23/28] fix(oauth): harden auth resume eval coverage Add eval-only OAuth provider fixtures and callback harnesses that drive the real callback routes while only mocking third-party services. This gives the MCP and generic auth-resume flows meaningful conversational coverage in evals without scripting internal commands into the user prompt. Tighten the runtime and test contracts around auth resume so resumed turns preserve prior thread context, successful oauth_started tool results are surfaced correctly, late plugin capability registration works, and callback tests fail if after() work is not actually scheduled. Co-Authored-By: GPT-5 Codex --- packages/junior/evals/README.md | 11 + packages/junior/evals/behavior-harness.ts | 366 +++++++++++++++++- .../lifecycle-and-resilience.eval.ts | 3 +- .../conversational/oauth-workflows.eval.ts | 58 +++ packages/junior/evals/helpers.ts | 20 +- .../evals/plugins/eval-auth/plugin.yaml | 8 + .../eval-auth/skills/eval-auth/SKILL.md | 21 + .../evals/plugins/eval-oauth/plugin.yaml | 18 + .../eval-oauth/skills/eval-oauth/SKILL.md | 22 ++ .../junior/src/chat/capabilities/catalog.ts | 86 ++-- .../src/chat/capabilities/jr-rpc-command.ts | 2 +- packages/junior/src/chat/mcp/auth-store.ts | 25 ++ packages/junior/src/chat/plugins/registry.ts | 41 +- packages/junior/src/chat/prompt.ts | 1 + packages/junior/src/chat/respond.ts | 107 ++++- packages/junior/src/chat/skill-frontmatter.ts | 4 +- .../junior/src/handlers/mcp-oauth-callback.ts | 201 ++++++---- .../junior/src/handlers/oauth-callback.ts | 38 +- packages/junior/src/handlers/oauth-resume.ts | 58 ++- .../fixtures/mcp-oauth-callback-harness.ts | 31 ++ .../fixtures/oauth-callback-after-harness.ts | 9 + .../tests/fixtures/oauth-callback-harness.ts | 31 ++ .../integration/oauth-callback-slack.test.ts | 58 +++ .../integration/oauth-resume-slack.test.ts | 50 +++ packages/junior/tests/jr-rpc-command.test.ts | 75 +++- .../junior/tests/mcp-oauth-callback.test.ts | 12 + .../tests/msw/handlers/eval-mcp-auth.ts | 206 ++++++++++ .../junior/tests/msw/handlers/eval-oauth.ts | 34 ++ .../junior/tests/msw/handlers/slack-api.ts | 7 + packages/junior/tests/msw/server.ts | 29 +- packages/junior/tests/msw/setup.ts | 8 +- packages/junior/tests/oauth-callback.test.ts | 55 ++- .../junior/tests/skill-frontmatter.test.ts | 22 ++ packages/junior/tests/skills.test.ts | 144 ++++++- .../tests/unit/handlers/oauth-resume.test.ts | 73 ++++ .../unit/harness/behavior-harness.test.ts | 76 ++++ .../mcp-oauth-callback-harness.test.ts | 31 ++ .../harness/oauth-callback-harness.test.ts | 31 ++ .../respond-explicit-skill-preload.test.ts | 155 ++++++++ .../tests/unit/respond-oauth-start.test.ts | 188 +++++++++ specs/testing/evals-spec.md | 8 +- 41 files changed, 2241 insertions(+), 182 deletions(-) create mode 100644 packages/junior/evals/conversational/oauth-workflows.eval.ts create mode 100644 packages/junior/evals/plugins/eval-auth/plugin.yaml create mode 100644 packages/junior/evals/plugins/eval-auth/skills/eval-auth/SKILL.md create mode 100644 packages/junior/evals/plugins/eval-oauth/plugin.yaml create mode 100644 packages/junior/evals/plugins/eval-oauth/skills/eval-oauth/SKILL.md create mode 100644 packages/junior/tests/fixtures/mcp-oauth-callback-harness.ts create mode 100644 packages/junior/tests/fixtures/oauth-callback-after-harness.ts create mode 100644 packages/junior/tests/fixtures/oauth-callback-harness.ts create mode 100644 packages/junior/tests/integration/oauth-callback-slack.test.ts create mode 100644 packages/junior/tests/integration/oauth-resume-slack.test.ts create mode 100644 packages/junior/tests/msw/handlers/eval-mcp-auth.ts create mode 100644 packages/junior/tests/msw/handlers/eval-oauth.ts create mode 100644 packages/junior/tests/unit/handlers/oauth-resume.test.ts create mode 100644 packages/junior/tests/unit/harness/behavior-harness.test.ts create mode 100644 packages/junior/tests/unit/harness/mcp-oauth-callback-harness.test.ts create mode 100644 packages/junior/tests/unit/harness/oauth-callback-harness.test.ts create mode 100644 packages/junior/tests/unit/respond-explicit-skill-preload.test.ts create mode 100644 packages/junior/tests/unit/respond-oauth-start.test.ts diff --git a/packages/junior/evals/README.md b/packages/junior/evals/README.md index dd0c0f55..88e69044 100644 --- a/packages/junior/evals/README.md +++ b/packages/junior/evals/README.md @@ -41,6 +41,7 @@ Not in scope: - `evals/conversational/routing-and-continuity.eval.ts` - `evals/conversational/lifecycle-and-resilience.eval.ts` - `evals/conversational/media-and-attachments.eval.ts` + - `evals/conversational/oauth-workflows.eval.ts` - `evals/conversational/skill-workflows.eval.ts` - Helpers and event builders: `evals/helpers.ts` - Harness/runtime adapter: `evals/behavior-harness.ts` @@ -55,11 +56,15 @@ For each case (`slackEval()` call): Harness behavior knobs (in `BehaviorCaseConfig`): +- `auto_complete_mcp_oauth`: after our app genuinely starts an MCP OAuth flow for the listed providers, the harness immediately completes the fake provider callback. +- `auto_complete_oauth`: after our app genuinely starts a generic OAuth flow for the listed providers, the harness immediately completes the fake provider callback. - `fail_reply_call`: force a non-retryable reply failure on a specific call. - `mock_image_generation`: stub the image-generation HTTP response with a valid image payload while still exercising the real attachment path. +- `plugin_dirs`: load plugin fixtures from eval-local directories without adding workspace packages. - `retryable_timeout_calls`: force retryable timeout-shaped failures on selected reply calls. - `retryable_max_attempts`: max retries for retryable timeout-shaped failures during one event. - `reply_texts`: override returned reply text per call. +- `subscribed_decisions`: controls the subscribed-message reply gate in the harness. If you use it, do not claim that reply-selection behavior is being validated by the eval itself. `retryable_timeout_calls` validates handler-level retry propagation only. It does not validate checkpoint save/restore semantics in the core resumability path. @@ -85,9 +90,13 @@ Evals require real Vercel Sandbox access. If sandbox bootstrap fails, the eval f - Add new conversational cases under `evals/conversational/*.eval.ts` using `slackEval()`. - Use event builders (`mention`, `threadMessage`, `threadStart`) from `evals/helpers.ts`. +- Use `auto_complete_mcp_oauth` or `auto_complete_oauth` when the harness should instantly complete the fake provider callback after our app has genuinely initiated auth. - For multi-turn, pass the same `thread` override so events land in one thread. - Keep each case focused on one primary behavior. - Encode all expectations in `criteria`; do not add deterministic inline assertions. +- Keep user prompts natural. They should read like plausible user requests, not scripted implementation instructions. +- Do not tell the assistant which exact internal command, tool, skill-loading step, or transport sequence to use unless that exact surface is what the user would naturally say and is the behavior under evaluation. +- If an eval only passes when the prompt prescribes internal mechanics, the eval is invalid and the product behavior is not adequately covered. Do not do these in eval files: @@ -103,6 +112,7 @@ Do not do these in eval files: - Examples: - `routing-and-continuity.eval.ts` - `lifecycle-and-resilience.eval.ts` + - `oauth-workflows.eval.ts` - `skill-workflows.eval.ts` - Test naming: `: ` - Examples: @@ -123,6 +133,7 @@ Good conversational evals should: Avoid: - Criteria tied to exact internal tool call names (`bash`, etc.) when user-visible behavior is what matters. +- User prompts that prescribe exact internal commands or tool choices just to force the desired path. - Cases that only validate mocks or internal state transitions without conversational context. ## Minimal Case diff --git a/packages/junior/evals/behavior-harness.ts b/packages/junior/evals/behavior-harness.ts index 7dbd3aee..c8e2c4d4 100644 --- a/packages/junior/evals/behavior-harness.ts +++ b/packages/junior/evals/behavior-harness.ts @@ -2,21 +2,43 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import type { Message } from "chat"; import type { AppRuntimeAssistantLifecycleEvent } from "@/chat/app-runtime"; +import { getUserTokenStore } from "@/chat/capabilities/factory"; import { appSlackRuntime, bot, resetBotDepsForTests, setBotDepsForTests, } from "@/chat/bot"; -import { resetPluginRegistryForTests } from "@/chat/plugins/registry"; +import { + deleteMcpAuthSessionsForUserProvider, + deleteMcpServerSessionId, + deleteMcpStoredOAuthCredentials, + getLatestMcpAuthSessionForUserProvider, +} from "@/chat/mcp/auth-store"; +import { + getPluginOAuthConfig, + setAdditionalPluginRootsForTests, +} from "@/chat/plugins/registry"; import { generateAssistantReply } from "@/chat/respond"; +import { getStateAdapter } from "@/chat/state"; import { resetSkillDiscoveryCache } from "@/chat/skills"; import { RetryableTurnError, isRetryableTurnError } from "@/chat/turn/errors"; +import { setPostSlackMessageObserverForTests } from "@/handlers/oauth-resume"; import { FakeSlackAdapter, createTestThread, type TestThread, } from "../tests/fixtures/slack-harness"; +import { + EVAL_OAUTH_CODE, + EVAL_OAUTH_PROVIDER, +} from "../tests/msw/handlers/eval-oauth"; +import { + EVAL_MCP_AUTH_CODE, + EVAL_MCP_AUTH_PROVIDER, +} from "../tests/msw/handlers/eval-mcp-auth"; +import { runMcpOauthCallbackRoute } from "../tests/fixtures/mcp-oauth-callback-harness"; +import { runOauthCallbackRoute } from "../tests/fixtures/oauth-callback-harness"; import { readCapturedSlackApiCalls, type CapturedSlackApiCall, @@ -79,9 +101,12 @@ interface SubscribedDecisionFixture { } export interface BehaviorCaseConfig { + auto_complete_mcp_oauth?: string[]; + auto_complete_oauth?: string[]; enable_test_credentials?: boolean; fail_reply_call?: number; mock_image_generation?: boolean; + plugin_dirs?: string[]; mock_slack_api?: boolean; plugin_packages?: string[]; reply_texts?: string[]; @@ -117,6 +142,7 @@ export interface BehaviorCaseResult { const EVAL_PACKAGE_ROOT = path.resolve( fileURLToPath(new URL("..", import.meta.url)), ); +type HarnessStateAdapter = ReturnType; function resolveEvalRelativePath(entry: string): string { return path.isAbsolute(entry) @@ -138,6 +164,60 @@ function toFirstString(value: unknown): string | undefined { return undefined; } +function buildRuntimeThreadId(fixture: BehaviorEventThreadFixture): string { + if (fixture.channel_id && fixture.thread_ts) { + return `slack:${fixture.channel_id}:${fixture.thread_ts}`; + } + return fixture.id; +} + +const THREAD_STATE_TTL_MS = 30 * 24 * 60 * 60 * 1000; + +async function cleanupHarnessThreadState( + stateAdapter: HarnessStateAdapter, + events: readonly BehaviorCaseEvent[], +): Promise { + const runtimeThreadIds = new Set( + events.map((event) => buildRuntimeThreadId(event.thread)), + ); + const channelIds = new Set( + events + .map((event) => event.thread.channel_id?.trim()) + .filter((value): value is string => Boolean(value)), + ); + + for (const threadId of runtimeThreadIds) { + await stateAdapter.delete(`thread-state:${threadId}`); + } + for (const channelId of channelIds) { + await stateAdapter.delete(`channel-state:${channelId}`); + } +} + +function createEvalThread(args: { + fixture: BehaviorEventThreadFixture; + channelStateRef?: { value: Record }; + stateAdapter: HarnessStateAdapter; +}): TestThread { + const thread = createTestThread({ + id: buildRuntimeThreadId(args.fixture), + channelId: args.fixture.channel_id, + runId: args.fixture.run_id, + threadTs: args.fixture.thread_ts, + channelStateRef: args.channelStateRef, + }); + const originalSetState = thread.setState.bind(thread); + thread.setState = async (next, options) => { + await originalSetState(next, options); + await args.stateAdapter.set( + `thread-state:${thread.id}`, + thread.getState(), + THREAD_STATE_TTL_MS, + ); + }; + return thread; +} + function createMockImageGenerateDeps(): ImageGenerateToolDeps { const generatedImageBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aH3cAAAAASUVORK5CYII="; @@ -242,6 +322,7 @@ function toPostedText(value: unknown): string { } function toIncomingMessage(event: MentionEvent | SubscribedMessageEvent) { + const runtimeThreadId = buildRuntimeThreadId(event.thread); // In Slack payloads, `ts` identifies the specific message while `thread_ts` // identifies the thread root. Eval fixtures provide unique `message.id` per // event, so prefer it for `raw.ts` to avoid collapsing all replies to the @@ -254,7 +335,7 @@ function toIncomingMessage(event: MentionEvent | SubscribedMessageEvent) { attachments: [], metadata: { dateSent: new Date(), edited: false }, channelId: event.thread.channel_id, - threadId: event.thread.id, + threadId: runtimeThreadId, threadTs: event.thread.thread_ts, runId: event.thread.run_id, raw: { @@ -272,10 +353,164 @@ function toIncomingMessage(event: MentionEvent | SubscribedMessageEvent) { }; } +async function cleanupMcpAuthState( + userIds: Iterable, + providers: Iterable, +): Promise { + for (const provider of providers) { + for (const userId of userIds) { + await deleteMcpAuthSessionsForUserProvider(userId, provider); + await deleteMcpStoredOAuthCredentials(userId, provider); + await deleteMcpServerSessionId(userId, provider); + } + } +} + +async function cleanupOAuthTokens( + userIds: Iterable, + providers: Iterable, +): Promise { + const userTokenStore = getUserTokenStore(); + for (const provider of providers) { + for (const userId of userIds) { + await userTokenStore.delete(userId, provider); + } + } +} + +function getDefaultMcpOauthCode(provider: string): string { + if (provider === EVAL_MCP_AUTH_PROVIDER) { + return EVAL_MCP_AUTH_CODE; + } + throw new Error( + `No default eval MCP OAuth code configured for provider "${provider}"`, + ); +} + +async function runMcpOauthCallback(args: { + provider: string; + requesterUserId: string; +}): Promise { + const provider = args.provider.trim() || EVAL_MCP_AUTH_PROVIDER; + const requesterUserId = args.requesterUserId || "U-test"; + const authSession = await getLatestMcpAuthSessionForUserProvider( + requesterUserId, + provider, + ); + + if (!authSession) { + return false; + } + + const response = await runMcpOauthCallbackRoute({ + provider, + state: authSession.authSessionId, + code: getDefaultMcpOauthCode(provider), + }); + + if (response.status !== 200) { + throw new Error( + `MCP OAuth callback returned ${response.status}: ${await response.text()}`, + ); + } + return true; +} + +function extractSlackLinkUrl(text: string): URL | undefined { + const match = text.match(/<([^|>]+)\|/); + if (!match?.[1]) { + return undefined; + } + try { + return new URL(match[1]); + } catch { + return undefined; + } +} + +function findLatestOAuthStateFromSlackCalls(args: { + authorizeEndpoint: string; + consumedStates: Set; +}): string | undefined { + const expectedUrl = new URL(args.authorizeEndpoint); + const calls = readCapturedSlackApiCalls(); + + for (let index = calls.length - 1; index >= 0; index -= 1) { + const call = calls[index]; + if ( + call.method !== "chat.postEphemeral" && + call.method !== "chat.postMessage" + ) { + continue; + } + const text = toFirstString(call.params.text); + if (!text) { + continue; + } + const authLink = extractSlackLinkUrl(text); + if (!authLink) { + continue; + } + if ( + authLink.origin !== expectedUrl.origin || + authLink.pathname !== expectedUrl.pathname + ) { + continue; + } + const state = authLink.searchParams.get("state")?.trim(); + if (state && !args.consumedStates.has(state)) { + return state; + } + } + return undefined; +} + +function getDefaultOAuthCode(provider: string): string { + if (provider === EVAL_OAUTH_PROVIDER) { + return EVAL_OAUTH_CODE; + } + throw new Error( + `No default eval OAuth code configured for provider "${provider}"`, + ); +} + +async function runOauthCallback(args: { + provider: string; + consumedStates: Set; +}): Promise { + const provider = args.provider.trim() || EVAL_OAUTH_PROVIDER; + const providerConfig = getPluginOAuthConfig(provider); + if (!providerConfig) { + throw new Error(`Unknown OAuth provider "${provider}" in eval harness`); + } + + const state = findLatestOAuthStateFromSlackCalls({ + authorizeEndpoint: providerConfig.authorizeEndpoint, + consumedStates: args.consumedStates, + }); + if (!state) { + return false; + } + const response = await runOauthCallbackRoute({ + provider, + state, + code: getDefaultOAuthCode(provider), + }); + + if (response.status !== 200) { + throw new Error( + `OAuth callback returned ${response.status}: ${await response.text()}`, + ); + } + args.consumedStates.add(state); + return true; +} + export async function runBehaviorEvalCase( testCase: BehaviorEvalCase, ): Promise { const slackAdapter = new FakeSlackAdapter(); + const resumedChannelPosts: BehaviorCaseResult["channelPosts"] = []; const threadsById = new Map(); const channelStateById = new Map< string, @@ -301,12 +536,42 @@ export async function runBehaviorEvalCase( const originalEnableTestCredentials = process.env.EVAL_ENABLE_TEST_CREDENTIALS; const originalTestCredentialToken = process.env.EVAL_TEST_CREDENTIAL_TOKEN; + const originalJuniorBaseUrl = process.env.JUNIOR_BASE_URL; const originalPluginPackages = process.env.JUNIOR_PLUGIN_PACKAGES; const originalSlackBotToken = process.env.SLACK_BOT_TOKEN; + const originalStateAdapter = process.env.JUNIOR_STATE_ADAPTER; const configuredSkillDirs = testCase.behavior?.skill_dirs?.map((entry) => resolveEvalRelativePath(entry), ) ?? []; + const configuredPluginDirs = + testCase.behavior?.plugin_dirs?.map((entry) => + resolveEvalRelativePath(entry), + ) ?? []; + const autoCompleteMcpOauthProviders = new Set( + testCase.behavior?.auto_complete_mcp_oauth?.map((provider) => + provider.trim(), + ) ?? [], + ); + const autoCompleteOauthProviders = new Set( + testCase.behavior?.auto_complete_oauth?.map((provider) => + provider.trim(), + ) ?? [], + ); + const authRequesterUsers = new Set( + testCase.events.flatMap((event) => + "message" in event + ? [event.message.author?.user_id?.trim() || "U-test"] + : event.user_id + ? [event.user_id] + : [], + ), + ); + if (authRequesterUsers.size === 0) { + authRequesterUsers.add("U-test"); + } + const consumedOauthStates = new Set(); + const consumedMcpAuthSessions = new Set(); if (testCase.behavior?.enable_test_credentials) { process.env.EVAL_ENABLE_TEST_CREDENTIALS = "1"; if (testCase.behavior?.test_credential_token) { @@ -317,11 +582,56 @@ export async function runBehaviorEvalCase( if (testCase.behavior?.mock_slack_api) { process.env.SLACK_BOT_TOKEN = "xoxb-eval-test-token"; } + process.env.JUNIOR_BASE_URL = "https://junior.example.com"; + process.env.JUNIOR_STATE_ADAPTER = "memory"; process.env.JUNIOR_PLUGIN_PACKAGES = JSON.stringify( testCase.behavior?.plugin_packages ?? [], ); - resetPluginRegistryForTests(); + const stateAdapter = getStateAdapter(); + await stateAdapter.connect(); + setAdditionalPluginRootsForTests(configuredPluginDirs); resetSkillDiscoveryCache(); + setPostSlackMessageObserverForTests(({ channelId, text, threadTs }) => { + resumedChannelPosts.push({ + channel: channelId, + text, + thread_ts: threadTs, + }); + }); + await cleanupHarnessThreadState(stateAdapter, testCase.events); + await cleanupMcpAuthState(authRequesterUsers, autoCompleteMcpOauthProviders); + await cleanupOAuthTokens(authRequesterUsers, autoCompleteOauthProviders); + + const maybeAutoCompleteAuth = async (): Promise => { + for (const provider of autoCompleteMcpOauthProviders) { + for (const requesterUserId of authRequesterUsers) { + const authSession = await getLatestMcpAuthSessionForUserProvider( + requesterUserId, + provider, + ); + if (!authSession) { + continue; + } + if (consumedMcpAuthSessions.has(authSession.authSessionId)) { + continue; + } + const completed = await runMcpOauthCallback({ + provider, + requesterUserId, + }); + if (completed) { + consumedMcpAuthSessions.add(authSession.authSessionId); + } + } + } + + for (const provider of autoCompleteOauthProviders) { + await runOauthCallback({ + provider, + consumedStates: consumedOauthStates, + }); + } + }; const getChannelStateRef = ( channelId: string | undefined, @@ -340,12 +650,10 @@ export async function runBehaviorEvalCase( if (existing) { return existing; } - const created = createTestThread({ - id: fixture.id, - channelId: fixture.channel_id, - runId: fixture.run_id, - threadTs: fixture.thread_ts, + const created = createEvalThread({ + fixture, channelStateRef: getChannelStateRef(fixture.channel_id), + stateAdapter, }); threadsById.set(fixture.id, created); return created; @@ -495,6 +803,7 @@ export async function runBehaviorEvalCase( toIncomingMessage(event) as any, ); }); + await maybeAutoCompleteAuth(); continue; } @@ -506,6 +815,7 @@ export async function runBehaviorEvalCase( toIncomingMessage(event) as any, ); }); + await maybeAutoCompleteAuth(); continue; } @@ -517,17 +827,31 @@ export async function runBehaviorEvalCase( }; if (event.type === "assistant_thread_started") { await appSlackRuntime.handleAssistantThreadStarted(lifecycleEvent); + await maybeAutoCompleteAuth(); continue; } await appSlackRuntime.handleAssistantContextChanged(lifecycleEvent); + await maybeAutoCompleteAuth(); } } finally { resetBotDepsForTests(); - resetPluginRegistryForTests(); + setAdditionalPluginRootsForTests([]); resetSkillDiscoveryCache(); + setPostSlackMessageObserverForTests(undefined); + await cleanupHarnessThreadState(stateAdapter, testCase.events); + await cleanupMcpAuthState( + authRequesterUsers, + autoCompleteMcpOauthProviders, + ); + await cleanupOAuthTokens(authRequesterUsers, autoCompleteOauthProviders); (bot as unknown as { getAdapter?: (name: string) => unknown }).getAdapter = originalGetAdapter; + if (originalJuniorBaseUrl === undefined) { + delete process.env.JUNIOR_BASE_URL; + } else { + process.env.JUNIOR_BASE_URL = originalJuniorBaseUrl; + } if (originalPluginPackages === undefined) { delete process.env.JUNIOR_PLUGIN_PACKAGES; } else { @@ -538,6 +862,11 @@ export async function runBehaviorEvalCase( } else { process.env.SLACK_BOT_TOKEN = originalSlackBotToken; } + if (originalStateAdapter === undefined) { + delete process.env.JUNIOR_STATE_ADAPTER; + } else { + process.env.JUNIOR_STATE_ADAPTER = originalStateAdapter; + } if (testCase.behavior?.enable_test_credentials) { if (originalEnableTestCredentials === undefined) { delete process.env.EVAL_ENABLE_TEST_CREDENTIALS; @@ -556,9 +885,22 @@ export async function runBehaviorEvalCase( const posts = [...threadsById.values()].flatMap((thread) => thread.posts.map(toPostedText), ); - const { channelPosts, reactions } = collectSlackArtifactsFromCapturedCalls( - readCapturedSlackApiCalls(), - ); + const { channelPosts: capturedChannelPosts, reactions } = + collectSlackArtifactsFromCapturedCalls(readCapturedSlackApiCalls()); + const channelPosts = [...capturedChannelPosts]; + for (const post of resumedChannelPosts) { + if ( + channelPosts.some( + (existing) => + existing.channel === post.channel && + existing.text === post.text && + existing.thread_ts === post.thread_ts, + ) + ) { + continue; + } + channelPosts.push(post); + } return { channelPosts, diff --git a/packages/junior/evals/conversational/lifecycle-and-resilience.eval.ts b/packages/junior/evals/conversational/lifecycle-and-resilience.eval.ts index bbb758ad..f86a76c0 100644 --- a/packages/junior/evals/conversational/lifecycle-and-resilience.eval.ts +++ b/packages/junior/evals/conversational/lifecycle-and-resilience.eval.ts @@ -4,7 +4,8 @@ import { mention, slackEval, threadStart } from "../helpers"; describe("Conversational Evals: Lifecycle and Resilience", () => { slackEval("lifecycle: assistant thread init metadata", { events: [threadStart()], - criteria: "No reply is posted. Thread title and suggested prompts are each set exactly once.", + criteria: + "No reply is posted. Thread title and suggested prompts are each set exactly once.", }); slackEval("resilience: handler error is user-visible", { diff --git a/packages/junior/evals/conversational/oauth-workflows.eval.ts b/packages/junior/evals/conversational/oauth-workflows.eval.ts new file mode 100644 index 00000000..c629ac8d --- /dev/null +++ b/packages/junior/evals/conversational/oauth-workflows.eval.ts @@ -0,0 +1,58 @@ +import { describe } from "vitest"; +import { slackEval, threadMessage } from "../helpers"; + +describe("Conversational Evals: OAuth Workflows", () => { + const mcpAuthResumeThread = { + id: "thread-auth-resume", + channel_id: "C-auth-resume", + thread_ts: "17000000.auth-resume", + }; + + slackEval("oauth: mcp skill auth resume keeps prior thread context", { + behavior: { + auto_complete_mcp_oauth: ["eval-auth"], + plugin_dirs: ["evals/plugins"], + }, + events: [ + threadMessage("Remember this for later: the budget deadline is Friday.", { + thread: mcpAuthResumeThread, + is_mention: false, + }), + threadMessage( + "<@U_APP> /eval-auth Use the demo MCP connection, then tell me what budget deadline I mentioned earlier.", + { thread: mcpAuthResumeThread, is_mention: true }, + ), + ], + taskTimeout: 120_000, + timeout: 300_000, + criteria: + "After the second turn starts the eval MCP skill workflow, it pauses for MCP authorization, then after the real callback/resume path it posts a connection or continuation notice and a resumed answer in the same thread. The resumed answer explicitly says the budget deadline mentioned earlier was Friday. It must not ask the user to repeat the deadline, behave as if prior thread context was lost, or post a generic failure message.", + }); + + const oauthResumeThread = { + id: "thread-oauth-resume", + channel_id: "C-oauth-resume", + thread_ts: "17000000.oauth-resume", + }; + + slackEval("oauth: generic skill auth resume keeps prior thread context", { + behavior: { + auto_complete_oauth: ["eval-oauth"], + plugin_dirs: ["evals/plugins"], + }, + events: [ + threadMessage("Remember this for later: the budget deadline is Friday.", { + thread: oauthResumeThread, + is_mention: false, + }), + threadMessage( + "<@U_APP> /eval-oauth Connect the demo account, then tell me what budget deadline I mentioned earlier.", + { thread: oauthResumeThread, is_mention: true }, + ), + ], + taskTimeout: 120_000, + timeout: 300_000, + criteria: + "After the second turn starts the eval generic OAuth skill workflow, it pauses for generic OAuth authorization, then after the real callback/resume path it posts a connection or continuation notice and a resumed answer in the same thread. The resumed answer explicitly says the budget deadline mentioned earlier was Friday. It must not ask the user to repeat the deadline, behave as if prior thread context was lost, or post a generic failure message.", + }); +}); diff --git a/packages/junior/evals/helpers.ts b/packages/junior/evals/helpers.ts index e06cfd53..6713a2a1 100644 --- a/packages/junior/evals/helpers.ts +++ b/packages/junior/evals/helpers.ts @@ -86,6 +86,7 @@ interface SlackEvalOptions { behavior?: BehaviorCaseConfig; events: BehaviorCaseEvent[]; criteria: string; + taskTimeout?: number; threshold?: number; timeout?: number; requireSandboxReady?: boolean; @@ -113,10 +114,27 @@ export function slackEval(name: string, opts: SlackEvalOptions) { timeout: opts.timeout ?? 120_000, threshold: opts.threshold ?? 0.75, task: async () => { - const result = await runBehaviorEvalCase({ + const taskPromise = runBehaviorEvalCase({ behavior: opts.behavior, events: opts.events, }); + const result = + typeof opts.taskTimeout === "number" && opts.taskTimeout > 0 + ? await Promise.race([ + taskPromise, + new Promise((_, reject) => + setTimeout( + () => + reject( + new Error( + `Behavior harness timed out after ${opts.taskTimeout}ms before judge evaluation`, + ), + ), + opts.taskTimeout, + ), + ), + ]) + : await taskPromise; if (opts.requireSandboxReady ?? true) { assertSandboxReady(name, result); } diff --git a/packages/junior/evals/plugins/eval-auth/plugin.yaml b/packages/junior/evals/plugins/eval-auth/plugin.yaml new file mode 100644 index 00000000..041053e7 --- /dev/null +++ b/packages/junior/evals/plugins/eval-auth/plugin.yaml @@ -0,0 +1,8 @@ +name: eval-auth +description: Eval-only MCP auth resume fixture + +mcp: + transport: http + url: https://eval-auth.example.test/mcp + allowed-tools: + - budget-echo diff --git a/packages/junior/evals/plugins/eval-auth/skills/eval-auth/SKILL.md b/packages/junior/evals/plugins/eval-auth/skills/eval-auth/SKILL.md new file mode 100644 index 00000000..7f7e7f08 --- /dev/null +++ b/packages/junior/evals/plugins/eval-auth/skills/eval-auth/SKILL.md @@ -0,0 +1,21 @@ +--- +name: eval-auth +description: Use for `/eval-auth` requests in MCP auth-resume evals. Always connect through the disclosed MCP tool before answering, then continue the user's actual request using prior thread context when needed. +--- + +# Eval Auth Flow + +1. Always load this skill, inspect the disclosed MCP tools, and call the exact disclosed tool once before answering. + +2. The first MCP call may pause for OAuth. + +- Do not ask the user to start authorization manually. +- Do not abandon the request. +- The runtime will resume automatically after authorization completes. + +3. After the tool succeeds, answer the user's real question directly. + +- If the user asks about earlier thread context, use that context plainly. +- Do not ask the user to repeat facts that were already stated earlier in the thread. + +4. Keep the final answer short. diff --git a/packages/junior/evals/plugins/eval-oauth/plugin.yaml b/packages/junior/evals/plugins/eval-oauth/plugin.yaml new file mode 100644 index 00000000..a5d03c29 --- /dev/null +++ b/packages/junior/evals/plugins/eval-oauth/plugin.yaml @@ -0,0 +1,18 @@ +name: eval-oauth +description: Eval-only generic OAuth auth-resume fixture + +capabilities: + - read + +credentials: + type: oauth-bearer + api-domains: + - eval-oauth.example.test + auth-token-env: EVAL_OAUTH_ACCESS_TOKEN + +oauth: + client-id-env: EVAL_OAUTH_CLIENT_ID + client-secret-env: EVAL_OAUTH_CLIENT_SECRET + authorize-endpoint: https://eval-oauth.example.test/oauth/authorize + token-endpoint: https://eval-oauth.example.test/oauth/token + scope: read diff --git a/packages/junior/evals/plugins/eval-oauth/skills/eval-oauth/SKILL.md b/packages/junior/evals/plugins/eval-oauth/skills/eval-oauth/SKILL.md new file mode 100644 index 00000000..f1d014cc --- /dev/null +++ b/packages/junior/evals/plugins/eval-oauth/skills/eval-oauth/SKILL.md @@ -0,0 +1,22 @@ +--- +name: eval-oauth +description: Use for `/eval-oauth` requests in generic OAuth auth-resume evals. You must start the OAuth credential flow before answering anything else. +allowed-tools: bash +requires-capabilities: eval-oauth.read +--- + +# Eval OAuth Flow + +Run this command before doing anything else: + +`jr-rpc issue-credential eval-oauth.read` + +Rules: + +- Do not answer the user's question until that command succeeds. +- If the first run starts OAuth, stop there. Do not summarize, apologize, or ask the user to repeat anything. +- The runtime will resume automatically after authorization completes. +- After resume, run the same command again if needed, then answer the user's real question directly. +- If the user asks about earlier thread context, use that context plainly. +- Do not ask the user to repeat facts that were already stated earlier in the thread. +- Keep the final answer short. diff --git a/packages/junior/src/chat/capabilities/catalog.ts b/packages/junior/src/chat/capabilities/catalog.ts index 840ff7e1..ce8ff455 100644 --- a/packages/junior/src/chat/capabilities/catalog.ts +++ b/packages/junior/src/chat/capabilities/catalog.ts @@ -13,65 +13,93 @@ export interface CapabilityProviderDefinition { target?: CapabilityProviderTargetDefinition; } -const CAPABILITY_PROVIDERS: CapabilityProviderDefinition[] = [ - ...getPluginCapabilityProviders() -]; +function getCapabilityCatalog(): { + providers: CapabilityProviderDefinition[]; + capabilityToProvider: Map; + configKeys: Set; +} { + const providers = getPluginCapabilityProviders(); + const capabilityToProvider = new Map(); + const configKeys = new Set(); -const capabilityToProvider = new Map(); -const configKeySet = new Set(); -let startupCatalogLogged = false; - -for (const provider of CAPABILITY_PROVIDERS) { - for (const capability of provider.capabilities) { - if (capabilityToProvider.has(capability)) { - throw new Error(`Duplicate capability registration for "${capability}"`); + for (const provider of providers) { + for (const capability of provider.capabilities) { + if (capabilityToProvider.has(capability)) { + throw new Error( + `Duplicate capability registration for "${capability}"`, + ); + } + capabilityToProvider.set(capability, provider); + } + for (const configKey of provider.configKeys) { + configKeys.add(configKey); } - capabilityToProvider.set(capability, provider); - } - for (const configKey of provider.configKeys) { - configKeySet.add(configKey); } + + return { + providers, + capabilityToProvider, + configKeys, + }; } -export function getCapabilityProvider(capability: string): CapabilityProviderDefinition | undefined { - return capabilityToProvider.get(capability); +export function getCapabilityProvider( + capability: string, +): CapabilityProviderDefinition | undefined { + return getCapabilityCatalog().capabilityToProvider.get(capability); } export function isKnownCapability(capability: string): boolean { - return capabilityToProvider.has(capability); + return getCapabilityCatalog().capabilityToProvider.has(capability); } export function isKnownConfigKey(key: string): boolean { - return configKeySet.has(key); + return getCapabilityCatalog().configKeys.has(key); } export function listCapabilityProviders(): CapabilityProviderDefinition[] { - return CAPABILITY_PROVIDERS.map((provider) => ({ + return getCapabilityCatalog().providers.map((provider) => ({ ...provider, capabilities: [...provider.capabilities], - configKeys: [...provider.configKeys] + configKeys: [...provider.configKeys], })); } +let startupCatalogSignature: string | null = null; + export function logCapabilityCatalogLoadedOnce(): void { - if (startupCatalogLogged) { + const providers = listCapabilityProviders(); + const signature = JSON.stringify( + providers.map((provider) => ({ + provider: provider.provider, + capabilities: provider.capabilities, + configKeys: provider.configKeys, + target: provider.target, + })), + ); + if (startupCatalogSignature === signature) { return; } - startupCatalogLogged = true; + startupCatalogSignature = signature; - const providers = listCapabilityProviders(); - const capabilityNames = providers.flatMap((provider) => provider.capabilities).sort(); - const configKeys = [...new Set(providers.flatMap((provider) => provider.configKeys))].sort(); + const capabilityNames = providers + .flatMap((provider) => provider.capabilities) + .sort(); + const configKeys = [ + ...new Set(providers.flatMap((provider) => provider.configKeys)), + ].sort(); logInfo( "capability_catalog_loaded", {}, { - "app.capability.providers": providers.map((provider) => provider.provider), + "app.capability.providers": providers.map( + (provider) => provider.provider, + ), "app.capability.count": capabilityNames.length, "app.capability.names": capabilityNames, "app.config.key_count": configKeys.length, - "app.config.keys": configKeys + "app.config.keys": configKeys, }, - "Loaded capability provider catalog" + "Loaded capability provider catalog", ); } diff --git a/packages/junior/src/chat/capabilities/jr-rpc-command.ts b/packages/junior/src/chat/capabilities/jr-rpc-command.ts index 8523769e..765d1795 100644 --- a/packages/junior/src/chat/capabilities/jr-rpc-command.ts +++ b/packages/junior/src/chat/capabilities/jr-rpc-command.ts @@ -155,7 +155,7 @@ async function handleIssueCredentialCommand( ? `I need to connect your ${providerLabel} account first. I've sent you a private authorization link.` : `I need to connect your ${providerLabel} account first, but I wasn't able to send you a private authorization link. Please send me a direct message and try your command again.`, }, - exitCode: 1, + exitCode: 0, }); } // OAuth start failed — surface the specific misconfiguration error diff --git a/packages/junior/src/chat/mcp/auth-store.ts b/packages/junior/src/chat/mcp/auth-store.ts index d851eead..ef0e96ab 100644 --- a/packages/junior/src/chat/mcp/auth-store.ts +++ b/packages/junior/src/chat/mcp/auth-store.ts @@ -304,6 +304,31 @@ export async function deleteMcpAuthSessionsForUserProvider( await stateAdapter.delete(indexKey); } +export async function getLatestMcpAuthSessionForUserProvider( + userId: string, + provider: string, +): Promise { + const stateAdapter = await getConnectedStateAdapter(); + const authSessionIds = parseSessionIndex( + await stateAdapter.get(sessionIndexKey(userId, provider)), + ); + + let latestSession: McpAuthSessionState | undefined; + for (const authSessionId of authSessionIds) { + const session = parseMcpAuthSession( + await stateAdapter.get(sessionKey(authSessionId)), + ); + if (!session) { + continue; + } + if (!latestSession || session.updatedAtMs > latestSession.updatedAtMs) { + latestSession = session; + } + } + + return latestSession; +} + export async function getMcpStoredOAuthCredentials( userId: string, provider: string, diff --git a/packages/junior/src/chat/plugins/registry.ts b/packages/junior/src/chat/plugins/registry.ts index 712ee686..11097463 100644 --- a/packages/junior/src/chat/plugins/registry.ts +++ b/packages/junior/src/chat/plugins/registry.ts @@ -26,6 +26,7 @@ const capabilityToPlugin = new Map(); const pluginConfigKeys = new Set(); const pluginsByName = new Map(); const packageSkillRoots = new Set(); +let additionalPluginRootsForTests: string[] = []; let pluginsLoaded = false; @@ -69,12 +70,37 @@ function registerPluginManifest(raw: string, pluginDir: string): void { } } +function resetLoadedPluginState(): void { + pluginDefinitions.length = 0; + capabilityToPlugin.clear(); + pluginConfigKeys.clear(); + pluginsByName.clear(); + packageSkillRoots.clear(); + pluginsLoaded = false; +} + +function normalizePluginRootsForTests(roots: string[]): string[] { + const resolved: string[] = []; + const seen = new Set(); + + for (const root of roots) { + const normalized = path.resolve(root); + if (seen.has(normalized)) { + continue; + } + seen.add(normalized); + resolved.push(normalized); + } + + return resolved; +} + function loadPlugins(): void { if (pluginsLoaded) return; pluginsLoaded = true; const packagedContent = discoverInstalledPluginPackageContent(); - const localRoots = pluginRoots(); + const localRoots = [...pluginRoots(), ...additionalPluginRootsForTests]; const roots = [...localRoots, ...packagedContent.manifestRoots]; for (const pluginsRoot of roots) { let entries: string[]; @@ -178,12 +204,13 @@ function ensurePluginsLoaded(): void { } export function resetPluginRegistryForTests(): void { - pluginDefinitions.length = 0; - capabilityToPlugin.clear(); - pluginConfigKeys.clear(); - pluginsByName.clear(); - packageSkillRoots.clear(); - pluginsLoaded = false; + additionalPluginRootsForTests = []; + resetLoadedPluginState(); +} + +export function setAdditionalPluginRootsForTests(roots: string[]): void { + additionalPluginRootsForTests = normalizePluginRootsForTests(roots); + resetLoadedPluginState(); } loadPlugins(); diff --git a/packages/junior/src/chat/prompt.ts b/packages/junior/src/chat/prompt.ts index 9239bff9..73798977 100644 --- a/packages/junior/src/chat/prompt.ts +++ b/packages/junior/src/chat/prompt.ts @@ -491,6 +491,7 @@ export function buildSystemPrompt(params: { [ "- Explicit skill triggers may appear as `/skillname`.", "- If explicitly invoked skill instructions are already present in , apply them immediately.", + "- If an explicitly invoked skill is present in , never say the skill is unavailable, missing, or unsupported in this environment.", "- Otherwise, for an explicitly invoked skill, call `loadSkill` for that exact skill before applying skill-specific behavior.", "- For requests without an explicit trigger where a skill clearly matches, call `loadSkill` before applying skill-specific behavior.", "- Do not claim to have used a skill unless it is present in or `loadSkill` succeeded in this turn.", diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index 2142a16c..8bac543b 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -559,6 +559,87 @@ function buildExecutionFailureMessage(toolErrorCount: number): string { return "I couldn’t complete this request in this turn due to an execution failure. I’ve logged the details for debugging."; } +function extractOAuthStartedPayload( + value: unknown, +): { message?: string } | undefined { + if (typeof value === "string") { + const parsed = parseJsonCandidate(value); + return parsed === undefined + ? undefined + : extractOAuthStartedPayload(parsed); + } + + if (Array.isArray(value)) { + for (const entry of value) { + const found = extractOAuthStartedPayload(entry); + if (found) { + return found; + } + } + return undefined; + } + + if (!value || typeof value !== "object") { + return undefined; + } + + const record = value as Record; + if (record.oauth_started === true) { + const message = + typeof record.message === "string" ? record.message.trim() : undefined; + return message ? { message } : {}; + } + + const content = record.content; + if (Array.isArray(content)) { + for (const part of content) { + const text = + part && + typeof part === "object" && + (part as { type?: unknown }).type === "text" && + typeof (part as { text?: unknown }).text === "string" + ? (part as { text: string }).text + : part; + const found = extractOAuthStartedPayload(text); + if (found) { + return found; + } + } + } + + for (const key of ["details", "output", "result", "stdout"]) { + if (!(key in record)) { + continue; + } + const found = extractOAuthStartedPayload(record[key]); + if (found) { + return found; + } + } + + return undefined; +} + +function extractOAuthStartedMessage( + toolResults: unknown[], +): string | undefined { + for (const result of toolResults) { + if ( + normalizeToolNameFromResult(result) !== "bash" || + isToolResultError(result) + ) { + continue; + } + + const found = extractOAuthStartedPayload(result); + if (found?.message) { + return found.message; + } + } + + return undefined; +} + function toToolContentText(value: unknown): string { if (typeof value === "string") return value; try { @@ -1619,6 +1700,7 @@ export async function generateAssistantReply( .map((message) => extractAssistantText(message)) .join("\n\n") .trim(); + const oauthStartedMessage = extractOAuthStartedMessage(toolResults); const toolErrorCount = toolResults.filter( (result) => result.isError, @@ -1646,7 +1728,7 @@ export async function generateAssistantReply( const deliveryMode: "thread" | "channel_only" = deliveryPlan.mode; const ackStrategy: "none" | "reaction" = deliveryPlan.ack; - if (!primaryText) { + if (!primaryText && !oauthStartedMessage) { logWarn( "ai_model_response_empty", { @@ -1678,22 +1760,25 @@ export async function generateAssistantReply( ? lastAssistant.errorMessage : undefined; const usedPrimaryText = Boolean(primaryText); - const outcome: AgentTurnDiagnostics["outcome"] = primaryText - ? stopReason === "error" - ? "provider_error" - : "success" - : "execution_failure"; - - const candidateText = - primaryText || buildExecutionFailureMessage(toolErrorCount); + const outcome: AgentTurnDiagnostics["outcome"] = + primaryText || oauthStartedMessage + ? stopReason === "error" + ? "provider_error" + : "success" + : "execution_failure"; + const fallbackText = + oauthStartedMessage ?? buildExecutionFailureMessage(toolErrorCount); + const candidateText = primaryText || fallbackText; const escapedOrRawPayload = isExecutionEscapeResponse(candidateText) || isRawToolPayloadResponse(candidateText); const resolvedText = escapedOrRawPayload - ? buildExecutionFailureMessage(toolErrorCount) + ? fallbackText : enforceAttachmentClaimTruth(candidateText, replyFiles.length > 0); const resolvedOutcome: AgentTurnDiagnostics["outcome"] = escapedOrRawPayload - ? "execution_failure" + ? oauthStartedMessage + ? outcome + : "execution_failure" : outcome; if (shouldTrace) { logInfo( diff --git a/packages/junior/src/chat/skill-frontmatter.ts b/packages/junior/src/chat/skill-frontmatter.ts index 0b83d39c..fc9eb7ef 100644 --- a/packages/junior/src/chat/skill-frontmatter.ts +++ b/packages/junior/src/chat/skill-frontmatter.ts @@ -3,7 +3,7 @@ import { parse as parseYaml } from "yaml"; const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/; const SKILL_NAME_RE = /^[a-z0-9-]+$/; -const CAPABILITY_TOKEN_RE = /^[a-z0-9]+(?:\.[a-z0-9-]+)+$/; +const DOTTED_TOKEN_RE = /^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/; const MAX_NAME_LENGTH = 64; const MAX_DESCRIPTION_LENGTH = 1024; const MAX_COMPATIBILITY_LENGTH = 500; @@ -51,7 +51,7 @@ function createTokenFieldSchema( .filter((token) => token.length > 0); for (const token of tokens) { - if (!CAPABILITY_TOKEN_RE.test(token)) { + if (!DOTTED_TOKEN_RE.test(token)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `${fieldName} token "${token}" is invalid; expected dotted lowercase tokens (for example "${example}")`, diff --git a/packages/junior/src/handlers/mcp-oauth-callback.ts b/packages/junior/src/handlers/mcp-oauth-callback.ts index eb2104ea..6f5ec85f 100644 --- a/packages/junior/src/handlers/mcp-oauth-callback.ts +++ b/packages/junior/src/handlers/mcp-oauth-callback.ts @@ -3,7 +3,10 @@ import { after } from "next/server"; import { ThreadImpl, type FileUpload } from "chat"; import { botConfig } from "@/chat/config"; import { coerceThreadConversationState } from "@/chat/conversation-state"; -import { deleteMcpAuthSession } from "@/chat/mcp/auth-store"; +import { + deleteMcpAuthSession, + type McpAuthSessionState, +} from "@/chat/mcp/auth-store"; import { buildSlackOutputMessage } from "@/chat/output"; import { finalizeMcpAuthorization } from "@/chat/mcp/oauth"; import { logException, logWarn } from "@/chat/observability"; @@ -13,6 +16,7 @@ import { persistThreadState, } from "@/chat/runtime/thread-state"; import { + buildConversationContext, generateConversationId, markConversationMessage, normalizeConversationText, @@ -195,6 +199,19 @@ function getUserMessageIdForTurn( return undefined; } +async function buildResumeConversationContext( + channelId: string, + threadTs: string, + sessionId: string, +): Promise { + const thread = createSlackThread(channelId, threadTs); + const conversation = coerceThreadConversationState(await thread.state); + const userMessageId = getUserMessageIdForTurn(conversation, sessionId); + return buildConversationContext(conversation, { + excludeMessageId: userMessageId, + }); +} + async function persistCompletedReplyState( channelId: string, threadTs: string, @@ -263,6 +280,104 @@ async function persistFailedReplyState( }); } +export async function resumeAuthorizedMcpTurn(args: { + authSession: McpAuthSessionState; + provider: string; +}): Promise { + const { authSession, provider } = args; + if (!authSession.channelId || !authSession.threadTs) { + return; + } + + const conversationContext = await buildResumeConversationContext( + authSession.channelId, + authSession.threadTs, + authSession.sessionId, + ); + + await resumeAuthorizedRequest({ + messageText: authSession.userMessage, + requesterUserId: authSession.userId, + provider, + channelId: authSession.channelId, + threadTs: authSession.threadTs, + connectedText: `Your ${provider} MCP access is now connected. Continuing the original request...`, + failureText: + "MCP authorization completed, but resuming the request failed. Please retry the original command.", + correlation: { + conversationId: authSession.conversationId, + turnId: authSession.sessionId, + channelId: authSession.channelId, + threadTs: authSession.threadTs, + requesterId: authSession.userId, + }, + toolChannelId: + authSession.toolChannelId ?? + authSession.artifactState?.assistantContextChannelId ?? + authSession.channelId, + conversationContext, + artifactState: authSession.artifactState, + configuration: authSession.configuration, + onReply: async (reply) => { + await deliverReplyToThread( + authSession.channelId!, + authSession.threadTs!, + reply, + ); + }, + onSuccess: async (reply) => { + try { + await persistCompletedReplyState( + authSession.channelId!, + authSession.threadTs!, + authSession.sessionId, + reply, + ); + } catch (persistError) { + logException( + persistError, + "mcp_oauth_callback_resume_persist_failed", + {}, + { "app.credential.provider": provider }, + "Failed to persist resumed MCP turn state", + ); + } + }, + onFailure: async (error) => { + logException( + error, + "mcp_oauth_callback_resume_failed", + {}, + { "app.credential.provider": provider }, + "Failed to resume MCP-authorized turn", + ); + try { + await persistFailedReplyState( + authSession.channelId!, + authSession.threadTs!, + authSession.sessionId, + ); + } catch (persistError) { + logException( + persistError, + "mcp_oauth_callback_resume_failure_persist_failed", + {}, + { "app.credential.provider": provider }, + "Failed to persist failed MCP resume state", + ); + } + }, + onAuthPause: async () => { + logWarn( + "mcp_oauth_callback_resume_reparked_for_auth", + {}, + { "app.credential.provider": provider }, + "Resumed MCP turn requested another authorization flow", + ); + }, + }); +} + type Context = { params: Promise<{ provider: string; @@ -304,89 +419,9 @@ export async function GET( } after(async () => { - if (!authSession.channelId || !authSession.threadTs) { - return; - } - - await resumeAuthorizedRequest({ - messageText: authSession.userMessage, - requesterUserId: authSession.userId, + await resumeAuthorizedMcpTurn({ + authSession, provider, - channelId: authSession.channelId, - threadTs: authSession.threadTs, - connectedText: `Your ${provider} MCP access is now connected. Continuing the original request...`, - failureText: - "MCP authorization completed, but resuming the request failed. Please retry the original command.", - correlation: { - conversationId: authSession.conversationId, - turnId: authSession.sessionId, - channelId: authSession.channelId, - threadTs: authSession.threadTs, - requesterId: authSession.userId, - }, - toolChannelId: - authSession.toolChannelId ?? - authSession.artifactState?.assistantContextChannelId ?? - authSession.channelId, - artifactState: authSession.artifactState, - configuration: authSession.configuration, - onReply: async (reply) => { - await deliverReplyToThread( - authSession.channelId!, - authSession.threadTs!, - reply, - ); - }, - onSuccess: async (reply) => { - try { - await persistCompletedReplyState( - authSession.channelId!, - authSession.threadTs!, - authSession.sessionId, - reply, - ); - } catch (persistError) { - logException( - persistError, - "mcp_oauth_callback_resume_persist_failed", - {}, - { "app.credential.provider": provider }, - "Failed to persist resumed MCP turn state", - ); - } - }, - onFailure: async (error) => { - logException( - error, - "mcp_oauth_callback_resume_failed", - {}, - { "app.credential.provider": provider }, - "Failed to resume MCP-authorized turn", - ); - try { - await persistFailedReplyState( - authSession.channelId!, - authSession.threadTs!, - authSession.sessionId, - ); - } catch (persistError) { - logException( - persistError, - "mcp_oauth_callback_resume_failure_persist_failed", - {}, - { "app.credential.provider": provider }, - "Failed to persist failed MCP resume state", - ); - } - }, - onAuthPause: async () => { - logWarn( - "mcp_oauth_callback_resume_reparked_for_auth", - {}, - { "app.credential.provider": provider }, - "Resumed MCP turn requested another authorization flow", - ); - }, }); }); diff --git a/packages/junior/src/handlers/oauth-callback.ts b/packages/junior/src/handlers/oauth-callback.ts index b6fda9f3..5c94396d 100644 --- a/packages/junior/src/handlers/oauth-callback.ts +++ b/packages/junior/src/handlers/oauth-callback.ts @@ -1,10 +1,13 @@ import { after } from "next/server"; +import { ThreadImpl } from "chat"; import { getUserTokenStore } from "@/chat/capabilities/factory"; +import { coerceThreadConversationState } from "@/chat/conversation-state"; import { formatProviderLabel, type OAuthStatePayload, resolveBaseUrl, } from "@/chat/oauth-flow"; +import { buildConversationContext } from "@/chat/services/conversation-memory"; import { resumeAuthorizedRequest, postSlackMessage, @@ -51,10 +54,40 @@ function htmlErrorResponse( }); } -async function resumePendingMessage(stored: OAuthStatePayload): Promise { +function createSlackThread(channelId: string, threadTs: string) { + return ThreadImpl.fromJSON({ + _type: "chat:Thread", + adapterName: "slack", + channelId, + id: `slack:${channelId}:${threadTs}`, + isDM: channelId.startsWith("D"), + }); +} + +async function buildResumeConversationContext( + channelId: string, + threadTs: string, +): Promise { + const thread = createSlackThread(channelId, threadTs); + const conversation = coerceThreadConversationState(await thread.state); + const latestUserMessageId = [...conversation.messages] + .reverse() + .find((message) => message.role === "user")?.id; + return buildConversationContext(conversation, { + excludeMessageId: latestUserMessageId, + }); +} + +export async function resumePendingOAuthMessage( + stored: OAuthStatePayload, +): Promise { if (!stored.pendingMessage || !stored.channelId || !stored.threadTs) return; const providerLabel = formatProviderLabel(stored.provider); + const conversationContext = await buildResumeConversationContext( + stored.channelId, + stored.threadTs, + ); await resumeAuthorizedRequest({ messageText: stored.pendingMessage, requesterUserId: stored.userId, @@ -63,6 +96,7 @@ async function resumePendingMessage(stored: OAuthStatePayload): Promise { threadTs: stored.threadTs, connectedText: `Your ${providerLabel} account is now connected. Processing your request...`, failureText: `I connected your account but hit an error processing your request. Please try \`${stored.pendingMessage}\` again.`, + conversationContext, configuration: stored.configuration, onSuccess: async (reply) => { logInfo( @@ -236,7 +270,7 @@ export async function GET( }); if (stored.pendingMessage && stored.channelId && stored.threadTs) { - after(() => resumePendingMessage(stored)); + after(() => resumePendingOAuthMessage(stored)); } else if (stored.channelId && stored.threadTs) { const { channelId, threadTs } = stored; after(async () => { diff --git a/packages/junior/src/handlers/oauth-resume.ts b/packages/junior/src/handlers/oauth-resume.ts index a706023b..17638d25 100644 --- a/packages/junior/src/handlers/oauth-resume.ts +++ b/packages/junior/src/handlers/oauth-resume.ts @@ -7,11 +7,44 @@ import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; import { truncateStatusText } from "@/chat/status-format"; import { isRetryableTurnError } from "@/chat/turn/errors"; +type PostSlackMessageObserver = (args: { + channelId: string; + text: string; + threadTs: string; +}) => void; + +let postSlackMessageObserverForTests: PostSlackMessageObserver | undefined; + +export function setPostSlackMessageObserverForTests( + observer: PostSlackMessageObserver | undefined, +): void { + postSlackMessageObserverForTests = observer; +} + +function resolveReplyTimeoutMs(explicitTimeoutMs?: number): number | undefined { + if (typeof explicitTimeoutMs === "number" && explicitTimeoutMs > 0) { + return explicitTimeoutMs; + } + + const raw = process.env.EVAL_AGENT_REPLY_TIMEOUT_MS?.trim(); + if (!raw) { + return undefined; + } + + const parsed = Number.parseInt(raw, 10); + return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined; +} + export async function postSlackMessage( channelId: string, threadTs: string, text: string, ): Promise { + postSlackMessageObserverForTests?.({ + channelId, + threadTs, + text, + }); try { await getSlackClient().chat.postMessage({ channel: channelId, @@ -148,18 +181,22 @@ export async function resumeAuthorizedRequest(args: { }; toolChannelId?: string; artifactState?: ThreadArtifactsState; + conversationContext?: string; configuration?: Record; + generateReply?: typeof generateAssistantReply; onReply?: (reply: AssistantReply) => Promise; onSuccess?: (reply: AssistantReply) => Promise; onFailure?: (error: unknown) => Promise; onAuthPause?: (error: unknown) => Promise; + replyTimeoutMs?: number; }) { const postStatus = createDebouncedStatusPoster(args.channelId, args.threadTs); await postSlackMessage(args.channelId, args.threadTs, args.connectedText); await setAssistantStatus(args.channelId, args.threadTs, "Thinking..."); try { - const reply = await generateAssistantReply(args.messageText, { + const generateReply = args.generateReply ?? generateAssistantReply; + const replyPromise = generateReply(args.messageText, { assistant: { userName: botConfig.userName }, requester: { userId: args.requesterUserId }, correlation: { @@ -170,6 +207,7 @@ export async function resumeAuthorizedRequest(args: { requesterId: args.correlation?.requesterId ?? args.requesterUserId, }, toolChannelId: args.toolChannelId, + conversationContext: args.conversationContext, artifactState: args.artifactState, configuration: args.configuration, channelConfiguration: args.configuration @@ -177,6 +215,24 @@ export async function resumeAuthorizedRequest(args: { : undefined, onStatus: postStatus, }); + const replyTimeoutMs = resolveReplyTimeoutMs(args.replyTimeoutMs); + const reply = + typeof replyTimeoutMs === "number" + ? await Promise.race([ + replyPromise, + new Promise((_, reject) => + setTimeout( + () => + reject( + new Error( + `generateAssistantReply timed out after ${replyTimeoutMs}ms`, + ), + ), + replyTimeoutMs, + ), + ), + ]) + : await replyPromise; postStatus.stop(); if (args.onReply) { diff --git a/packages/junior/tests/fixtures/mcp-oauth-callback-harness.ts b/packages/junior/tests/fixtures/mcp-oauth-callback-harness.ts new file mode 100644 index 00000000..cd1ebcfe --- /dev/null +++ b/packages/junior/tests/fixtures/mcp-oauth-callback-harness.ts @@ -0,0 +1,31 @@ +import { afterCallbacks } from "./oauth-callback-after-harness"; + +export async function runMcpOauthCallbackRoute(args: { + provider: string; + state: string; + code: string; +}) { + afterCallbacks.length = 0; + const { GET } = await import("@/handlers/router"); + const response = await GET( + new Request( + `https://junior.example.com/api/oauth/callback/mcp/${args.provider}?state=${encodeURIComponent(args.state)}&code=${encodeURIComponent(args.code)}`, + { method: "GET" }, + ), + { + params: Promise.resolve({ + path: ["oauth", "callback", "mcp", args.provider], + }), + }, + ); + const callbacks = afterCallbacks.splice(0, afterCallbacks.length); + for (const callback of callbacks) { + await callback(); + } + if (response.status === 200 && callbacks.length === 0) { + throw new Error( + `MCP OAuth callback route returned 200 without registering after() work for provider "${args.provider}"`, + ); + } + return response; +} diff --git a/packages/junior/tests/fixtures/oauth-callback-after-harness.ts b/packages/junior/tests/fixtures/oauth-callback-after-harness.ts new file mode 100644 index 00000000..d861c4de --- /dev/null +++ b/packages/junior/tests/fixtures/oauth-callback-after-harness.ts @@ -0,0 +1,9 @@ +import { vi } from "vitest"; + +export const afterCallbacks: Array<() => Promise | void> = []; + +vi.mock("next/server", () => ({ + after: (callback: () => Promise | void) => { + afterCallbacks.push(callback); + }, +})); diff --git a/packages/junior/tests/fixtures/oauth-callback-harness.ts b/packages/junior/tests/fixtures/oauth-callback-harness.ts new file mode 100644 index 00000000..af5d5bcd --- /dev/null +++ b/packages/junior/tests/fixtures/oauth-callback-harness.ts @@ -0,0 +1,31 @@ +import { afterCallbacks } from "./oauth-callback-after-harness"; + +export async function runOauthCallbackRoute(args: { + provider: string; + state: string; + code: string; +}) { + afterCallbacks.length = 0; + const { GET } = await import("@/handlers/router"); + const response = await GET( + new Request( + `https://junior.example.com/api/oauth/callback/${args.provider}?state=${encodeURIComponent(args.state)}&code=${encodeURIComponent(args.code)}`, + { method: "GET" }, + ), + { + params: Promise.resolve({ + path: ["oauth", "callback", args.provider], + }), + }, + ); + const callbacks = afterCallbacks.splice(0, afterCallbacks.length); + for (const callback of callbacks) { + await callback(); + } + if (response.status === 200 && callbacks.length === 0) { + throw new Error( + `OAuth callback route returned 200 without registering after() work for provider "${args.provider}"`, + ); + } + return response; +} diff --git a/packages/junior/tests/integration/oauth-callback-slack.test.ts b/packages/junior/tests/integration/oauth-callback-slack.test.ts new file mode 100644 index 00000000..5b280348 --- /dev/null +++ b/packages/junior/tests/integration/oauth-callback-slack.test.ts @@ -0,0 +1,58 @@ +import path from "node:path"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { + resetPluginRegistryForTests, + setAdditionalPluginRootsForTests, +} from "@/chat/plugins/registry"; +import { disconnectStateAdapter, getStateAdapter } from "@/chat/state"; +import { runOauthCallbackRoute } from "../fixtures/oauth-callback-harness"; +import { getCapturedSlackApiCalls } from "../msw/handlers/slack-api"; + +const ORIGINAL_ENV = { ...process.env }; + +describe("oauth callback slack integration", () => { + beforeEach(async () => { + process.env = { + ...ORIGINAL_ENV, + JUNIOR_STATE_ADAPTER: "memory", + JUNIOR_BASE_URL: "https://junior.example.com", + }; + resetPluginRegistryForTests(); + setAdditionalPluginRootsForTests([ + path.resolve(process.cwd(), "evals/plugins/eval-oauth"), + ]); + await disconnectStateAdapter(); + await getStateAdapter().connect(); + }); + + afterEach(async () => { + resetPluginRegistryForTests(); + await disconnectStateAdapter(); + process.env = { ...ORIGINAL_ENV }; + }); + + it("publishes app home through the Slack MSW harness after generic OAuth callback", async () => { + await getStateAdapter().set("oauth-state:eval-oauth-state", { + userId: "U123", + provider: "eval-oauth", + }); + + const response = await runOauthCallbackRoute({ + provider: "eval-oauth", + state: "eval-oauth-state", + code: "eval-oauth-code", + }); + + expect(response.status).toBe(200); + expect(getCapturedSlackApiCalls("views.publish")).toEqual([ + expect.objectContaining({ + params: expect.objectContaining({ + user_id: "U123", + view: expect.objectContaining({ + type: "home", + }), + }), + }), + ]); + }); +}); diff --git a/packages/junior/tests/integration/oauth-resume-slack.test.ts b/packages/junior/tests/integration/oauth-resume-slack.test.ts new file mode 100644 index 00000000..3fb7371e --- /dev/null +++ b/packages/junior/tests/integration/oauth-resume-slack.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from "vitest"; +import { resumeAuthorizedRequest } from "@/handlers/oauth-resume"; +import { getCapturedSlackApiCalls } from "../msw/handlers/slack-api"; + +describe("oauth resume slack integration", () => { + it("posts resumed status updates through the Slack MSW harness", async () => { + await resumeAuthorizedRequest({ + messageText: "What budget deadline did I mention earlier?", + requesterUserId: "U123", + provider: "eval-auth", + channelId: "C123", + threadTs: "1700000000.001", + connectedText: + "Your eval-auth MCP access is now connected. Continuing the original request...", + failureText: + "MCP authorization completed, but resuming the request failed. Please retry the original command.", + generateReply: async () => + ({ + text: "The budget deadline you mentioned earlier was Friday.", + }) as any, + }); + + expect(getCapturedSlackApiCalls("assistant.threads.setStatus")).toEqual([ + expect.objectContaining({ + params: expect.objectContaining({ + channel_id: "C123", + thread_ts: "1700000000.001", + status: "Thinking...", + }), + }), + ]); + + expect(getCapturedSlackApiCalls("chat.postMessage")).toEqual([ + expect.objectContaining({ + params: expect.objectContaining({ + channel: "C123", + thread_ts: "1700000000.001", + text: "Your eval-auth MCP access is now connected. Continuing the original request...", + }), + }), + expect.objectContaining({ + params: expect.objectContaining({ + channel: "C123", + thread_ts: "1700000000.001", + text: "The budget deadline you mentioned earlier was Friday.", + }), + }), + ]); + }); +}); diff --git a/packages/junior/tests/jr-rpc-command.test.ts b/packages/junior/tests/jr-rpc-command.test.ts index 9b066fcf..97ac4e8c 100644 --- a/packages/junior/tests/jr-rpc-command.test.ts +++ b/packages/junior/tests/jr-rpc-command.test.ts @@ -1,6 +1,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; +import { CredentialUnavailableError } from "@/chat/credentials/broker"; -const { unlinkProviderMock } = vi.hoisted(() => ({ +const { startOAuthFlowMock, unlinkProviderMock } = vi.hoisted(() => ({ + startOAuthFlowMock: vi.fn(), unlinkProviderMock: vi.fn(), })); @@ -31,10 +33,24 @@ vi.mock("@/chat/credentials/unlink-provider", () => ({ unlinkProvider: unlinkProviderMock, })); vi.mock("@/chat/plugins/registry", () => ({ - getPluginOAuthConfig: () => undefined, + getPluginOAuthConfig: (provider: string) => + provider === "github" + ? { + clientIdEnv: "GITHUB_CLIENT_ID", + clientSecretEnv: "GITHUB_CLIENT_SECRET", + authorizeEndpoint: "https://github.example.test/oauth/authorize", + tokenEndpoint: "https://github.example.test/oauth/token", + callbackPath: "/api/oauth/callback/github", + } + : undefined, isPluginProvider: (provider: string) => provider === "github" || provider === "sentry" || provider === "notion", })); +vi.mock("@/chat/oauth-flow", () => ({ + formatProviderLabel: (provider: string) => + provider.charAt(0).toUpperCase() + provider.slice(1), + startOAuthFlow: startOAuthFlowMock, +})); import { maybeExecuteJrRpcCustomCommand } from "@/chat/capabilities/jr-rpc-command"; import { SkillCapabilityRuntime } from "@/chat/capabilities/runtime"; import { createChannelConfigurationService } from "@/chat/configuration/service"; @@ -97,6 +113,11 @@ function makeRuntime( describe("jr-rpc custom command", () => { beforeEach(() => { + startOAuthFlowMock.mockReset(); + startOAuthFlowMock.mockImplementation(async (provider: string) => ({ + ok: false, + error: `Provider "${provider}" does not support OAuth authorization`, + })); unlinkProviderMock.mockReset(); unlinkProviderMock.mockResolvedValue(undefined); }); @@ -251,6 +272,56 @@ describe("jr-rpc custom command", () => { } }); + it("treats oauth initiation as a successful issue-credential outcome", async () => { + startOAuthFlowMock.mockResolvedValue({ + ok: true, + delivery: "in_context", + }); + + const runtime = new SkillCapabilityRuntime({ + broker: { + issue: async () => { + throw new CredentialUnavailableError( + "github", + "No github credentials available.", + ); + }, + }, + invocationArgs: "--repo getsentry/junior", + requesterId: "U123", + }); + + const result = await maybeExecuteJrRpcCustomCommand( + "jr-rpc issue-credential github.issues.write", + { + capabilityRuntime: runtime, + activeSkill, + requesterId: "U123", + userMessage: "Connect my github account", + }, + ); + + expect(result.handled).toBe(true); + if (result.handled) { + expect(result.result.exit_code).toBe(0); + const payload = JSON.parse(result.result.stdout) as { + oauth_started: boolean; + private_delivery_sent: boolean; + }; + expect(payload).toMatchObject({ + oauth_started: true, + private_delivery_sent: true, + }); + } + expect(startOAuthFlowMock).toHaveBeenCalledWith( + "github", + expect.objectContaining({ + requesterId: "U123", + userMessage: "Connect my github account", + }), + ); + }); + it("returns structured runtime errors when repo context is missing", async () => { const result = await maybeExecuteJrRpcCustomCommand( "jr-rpc issue-credential github.issues.write", diff --git a/packages/junior/tests/mcp-oauth-callback.test.ts b/packages/junior/tests/mcp-oauth-callback.test.ts index 38695872..c3e8313e 100644 --- a/packages/junior/tests/mcp-oauth-callback.test.ts +++ b/packages/junior/tests/mcp-oauth-callback.test.ts @@ -4,6 +4,7 @@ const { afterCallbacks, coerceThreadArtifactsStateMock, coerceThreadConversationStateMock, + buildConversationContextMock, deleteMcpAuthSessionMock, finalizeMcpAuthorizationMock, generateAssistantReplyMock, @@ -23,6 +24,7 @@ const { afterCallbacks: [] as Array<() => Promise | void>, coerceThreadArtifactsStateMock: vi.fn(), coerceThreadConversationStateMock: vi.fn(), + buildConversationContextMock: vi.fn(), deleteMcpAuthSessionMock: vi.fn(), finalizeMcpAuthorizationMock: vi.fn(), generateAssistantReplyMock: vi.fn(), @@ -99,6 +101,7 @@ vi.mock("@/chat/runtime/thread-state", () => ({ })); vi.mock("@/chat/services/conversation-memory", () => ({ + buildConversationContext: buildConversationContextMock, generateConversationId: () => "assistant-1", markConversationMessage: markConversationMessageMock, normalizeConversationText: (text: string) => text.trim(), @@ -132,6 +135,7 @@ describe("mcp oauth callback handler", () => { afterCallbacks.length = 0; coerceThreadArtifactsStateMock.mockReset(); coerceThreadConversationStateMock.mockReset(); + buildConversationContextMock.mockReset(); deleteMcpAuthSessionMock.mockReset(); finalizeMcpAuthorizationMock.mockReset(); generateAssistantReplyMock.mockReset(); @@ -217,6 +221,9 @@ describe("mcp oauth callback handler", () => { coerceThreadArtifactsStateMock.mockReturnValue({ assistantContextChannelId: "C999", }); + buildConversationContextMock.mockReturnValue( + "[user] Test User: budget deadline is Friday", + ); mergeArtifactsStateMock.mockImplementation((current, patch) => ({ ...current, ...patch, @@ -323,6 +330,7 @@ describe("mcp oauth callback handler", () => { configuration: { "demo.org": "acme", }, + conversationContext: "[user] Test User: budget deadline is Friday", }), ); @@ -334,6 +342,10 @@ describe("mcp oauth callback handler", () => { expect(await resumeContext.channelConfiguration?.resolve("demo.org")).toBe( "acme", ); + expect(buildConversationContextMock).toHaveBeenCalledWith( + expect.anything(), + { excludeMessageId: "msg.1" }, + ); expect(postMessageMock).toHaveBeenNthCalledWith(2, { channel: "C123", thread_ts: "1712345.0001", diff --git a/packages/junior/tests/msw/handlers/eval-mcp-auth.ts b/packages/junior/tests/msw/handlers/eval-mcp-auth.ts new file mode 100644 index 00000000..4ff7d032 --- /dev/null +++ b/packages/junior/tests/msw/handlers/eval-mcp-auth.ts @@ -0,0 +1,206 @@ +import { http, HttpResponse } from "msw"; + +export const EVAL_MCP_AUTH_PROVIDER = "eval-auth"; +export const EVAL_MCP_AUTH_CODE = "eval-auth-code"; +export const EVAL_MCP_AUTH_ORIGIN = "https://eval-auth.example.test"; +export const EVAL_MCP_SERVER_URL = `${EVAL_MCP_AUTH_ORIGIN}/mcp`; +const EVAL_MCP_RESOURCE_METADATA_URL = `${EVAL_MCP_AUTH_ORIGIN}/.well-known/oauth-protected-resource/mcp`; +const EVAL_MCP_AUTHORIZATION_ENDPOINT = `${EVAL_MCP_AUTH_ORIGIN}/oauth/authorize`; +const EVAL_MCP_TOKEN_ENDPOINT = `${EVAL_MCP_AUTH_ORIGIN}/oauth/token`; +const EVAL_MCP_REGISTRATION_ENDPOINT = `${EVAL_MCP_AUTH_ORIGIN}/oauth/register`; +const EVAL_MCP_ACCESS_TOKEN = "eval-auth-access-token"; +const EVAL_MCP_SESSION_ID = "eval-auth-session"; + +function unauthorizedResponse() { + return new HttpResponse(null, { + status: 401, + headers: { + "WWW-Authenticate": `Bearer resource_metadata="${EVAL_MCP_RESOURCE_METADATA_URL}", scope="mcp:read"`, + }, + }); +} + +function jsonRpcResult(id: unknown, result: unknown, headers?: HeadersInit) { + return HttpResponse.json( + { + jsonrpc: "2.0", + id, + result, + }, + { + headers, + }, + ); +} + +export function resetEvalMcpAuthMockState(): void {} + +export const evalMcpAuthHandlers = [ + http.get( + EVAL_MCP_SERVER_URL, + async () => new HttpResponse(null, { status: 405 }), + ), + http.post(EVAL_MCP_SERVER_URL, async ({ request }) => { + const authorization = request.headers.get("authorization"); + if (authorization !== `Bearer ${EVAL_MCP_ACCESS_TOKEN}`) { + return unauthorizedResponse(); + } + + const payload = (await request.json()) as + | { id?: unknown; method?: unknown; params?: Record } + | Array<{ + id?: unknown; + method?: unknown; + params?: Record; + }>; + const message = Array.isArray(payload) ? payload[0] : payload; + const method = + message && typeof message.method === "string" + ? message.method + : undefined; + + switch (method) { + case "initialize": + return jsonRpcResult( + message?.id ?? null, + { + protocolVersion: "2025-03-26", + capabilities: { + tools: {}, + }, + serverInfo: { + name: "eval-auth-mcp", + version: "1.0.0", + }, + }, + { + "mcp-session-id": EVAL_MCP_SESSION_ID, + }, + ); + case "tools/list": + return jsonRpcResult(message?.id ?? null, { + tools: [ + { + name: "budget-echo", + title: "Budget Echo", + description: + "Confirms the MCP connection for the auth-resume eval.", + inputSchema: { + type: "object", + properties: { + query: { type: "string" }, + }, + required: ["query"], + additionalProperties: false, + }, + }, + ], + }); + case "tools/call": { + const args = + message?.params && + typeof message.params === "object" && + message.params.arguments && + typeof message.params.arguments === "object" + ? (message.params.arguments as Record) + : undefined; + const query = typeof args?.query === "string" ? args.query : "unknown"; + return jsonRpcResult(message?.id ?? null, { + content: [ + { + type: "text", + text: `Eval MCP connection confirmed for: ${query}`, + }, + ], + isError: false, + }); + } + case "notifications/initialized": + return new HttpResponse(null, { + status: 202, + headers: { + "mcp-session-id": EVAL_MCP_SESSION_ID, + }, + }); + default: + return HttpResponse.json( + { + jsonrpc: "2.0", + id: message?.id ?? null, + error: { + code: -32601, + message: `Unsupported eval MCP method: ${String(method)}`, + }, + }, + { status: 400 }, + ); + } + }), + http.get(EVAL_MCP_RESOURCE_METADATA_URL, async () => + HttpResponse.json({ + resource: EVAL_MCP_SERVER_URL, + authorization_servers: [EVAL_MCP_AUTH_ORIGIN], + scopes_supported: ["mcp:read"], + }), + ), + http.get( + `${EVAL_MCP_AUTH_ORIGIN}/.well-known/oauth-authorization-server`, + async () => + HttpResponse.json({ + issuer: EVAL_MCP_AUTH_ORIGIN, + authorization_endpoint: EVAL_MCP_AUTHORIZATION_ENDPOINT, + token_endpoint: EVAL_MCP_TOKEN_ENDPOINT, + registration_endpoint: EVAL_MCP_REGISTRATION_ENDPOINT, + response_types_supported: ["code"], + grant_types_supported: ["authorization_code", "refresh_token"], + token_endpoint_auth_methods_supported: ["none"], + code_challenge_methods_supported: ["S256"], + }), + ), + http.post(EVAL_MCP_REGISTRATION_ENDPOINT, async ({ request }) => { + const body = (await request.json()) as Record; + return HttpResponse.json({ + client_id: "eval-auth-client-id", + client_id_issued_at: Math.floor(Date.now() / 1000), + ...(Array.isArray(body.redirect_uris) + ? { redirect_uris: body.redirect_uris } + : { + redirect_uris: [ + "https://junior.example.com/api/oauth/callback/mcp/eval-auth", + ], + }), + ...(Array.isArray(body.grant_types) + ? { grant_types: body.grant_types } + : { grant_types: ["authorization_code", "refresh_token"] }), + ...(Array.isArray(body.response_types) + ? { response_types: body.response_types } + : { response_types: ["code"] }), + ...(typeof body.client_name === "string" + ? { client_name: body.client_name } + : { client_name: "Junior MCP Client" }), + token_endpoint_auth_method: "none", + }); + }), + http.post(EVAL_MCP_TOKEN_ENDPOINT, async ({ request }) => { + const bodyText = await request.text(); + const params = new URLSearchParams(bodyText); + const code = params.get("code"); + if (code !== EVAL_MCP_AUTH_CODE) { + return HttpResponse.json( + { + error: "invalid_grant", + error_description: `Unexpected code: ${code ?? ""}`, + }, + { status: 400 }, + ); + } + + return HttpResponse.json({ + access_token: EVAL_MCP_ACCESS_TOKEN, + token_type: "Bearer", + expires_in: 3600, + refresh_token: "eval-auth-refresh-token", + scope: "mcp:read", + }); + }), +]; diff --git a/packages/junior/tests/msw/handlers/eval-oauth.ts b/packages/junior/tests/msw/handlers/eval-oauth.ts new file mode 100644 index 00000000..40863d0b --- /dev/null +++ b/packages/junior/tests/msw/handlers/eval-oauth.ts @@ -0,0 +1,34 @@ +import { http, HttpResponse } from "msw"; + +export const EVAL_OAUTH_PROVIDER = "eval-oauth"; +export const EVAL_OAUTH_CODE = "eval-oauth-code"; +export const EVAL_OAUTH_ORIGIN = "https://eval-oauth.example.test"; +const EVAL_OAUTH_TOKEN_ENDPOINT = `${EVAL_OAUTH_ORIGIN}/oauth/token`; +const EVAL_OAUTH_ACCESS_TOKEN = "eval-oauth-access-token"; + +export function resetEvalOAuthMockState(): void {} + +export const evalOAuthHandlers = [ + http.post(EVAL_OAUTH_TOKEN_ENDPOINT, async ({ request }) => { + const bodyText = await request.text(); + const params = new URLSearchParams(bodyText); + const code = params.get("code"); + if (code !== EVAL_OAUTH_CODE) { + return HttpResponse.json( + { + error: "invalid_grant", + error_description: `Unexpected code: ${code ?? ""}`, + }, + { status: 400 }, + ); + } + + return HttpResponse.json({ + access_token: EVAL_OAUTH_ACCESS_TOKEN, + token_type: "Bearer", + expires_in: 3600, + refresh_token: "eval-oauth-refresh-token", + scope: "read", + }); + }), +]; diff --git a/packages/junior/tests/msw/handlers/slack-api.ts b/packages/junior/tests/msw/handlers/slack-api.ts index f2d1f620..b116704f 100644 --- a/packages/junior/tests/msw/handlers/slack-api.ts +++ b/packages/junior/tests/msw/handlers/slack-api.ts @@ -1,5 +1,6 @@ import { http, HttpResponse } from "msw"; import { + slackOk, canvasesCreateOk, canvasesEditOk, canvasesSectionsLookupOk, @@ -24,9 +25,11 @@ import { const EXTERNAL_UPLOAD_KEY = "__files.upload.external__"; export const SUPPORTED_SLACK_API_METHODS = [ + "assistant.threads.setStatus", "chat.postMessage", "chat.postEphemeral", "chat.getPermalink", + "views.publish", "reactions.add", "reactions.remove", "conversations.history", @@ -168,12 +171,16 @@ function defaultSlackApiResponse( method: SlackApiMethod, ): SlackMockHttpResponse { switch (method) { + case "assistant.threads.setStatus": + return { body: slackOk() }; case "chat.postMessage": return { body: chatPostMessageOk() }; case "chat.postEphemeral": return { body: chatPostEphemeralOk() }; case "chat.getPermalink": return { body: chatGetPermalinkOk() }; + case "views.publish": + return { body: slackOk() }; case "reactions.add": return { body: reactionsAddOk() }; case "reactions.remove": diff --git a/packages/junior/tests/msw/server.ts b/packages/junior/tests/msw/server.ts index 8542b41f..b7a6ec79 100644 --- a/packages/junior/tests/msw/server.ts +++ b/packages/junior/tests/msw/server.ts @@ -1,18 +1,41 @@ +import { EVAL_OAUTH_ORIGIN, evalOAuthHandlers } from "./handlers/eval-oauth"; +import { + EVAL_MCP_AUTH_ORIGIN, + evalMcpAuthHandlers, +} from "./handlers/eval-mcp-auth"; import { setupServer } from "msw/node"; import { slackApiHandlers } from "./handlers/slack-api"; import { slackWebhookHandlers } from "./handlers/slack-webhooks"; +const EVAL_MCP_AUTH_HOSTNAME = new URL(EVAL_MCP_AUTH_ORIGIN).hostname; +const EVAL_OAUTH_HOSTNAME = new URL(EVAL_OAUTH_ORIGIN).hostname; + function isSlackHost(hostname: string): boolean { return hostname === "slack.com" || hostname === "files.slack.com"; } +function requiresMockedHandling(hostname: string): boolean { + return ( + isSlackHost(hostname) || + hostname === EVAL_MCP_AUTH_HOSTNAME || + hostname === EVAL_OAUTH_HOSTNAME + ); +} + export function enforceUnhandledSlackRequestFailure(request: Request): void { const url = new URL(request.url); - if (!isSlackHost(url.hostname)) { + if (!requiresMockedHandling(url.hostname)) { return; } - throw new Error(`[MSW] Unhandled Slack request: ${request.method} ${request.url}`); + throw new Error( + `[MSW] Unhandled mocked request: ${request.method} ${request.url}`, + ); } -export const mswServer = setupServer(...slackApiHandlers, ...slackWebhookHandlers); +export const mswServer = setupServer( + ...slackApiHandlers, + ...slackWebhookHandlers, + ...evalMcpAuthHandlers, + ...evalOAuthHandlers, +); diff --git a/packages/junior/tests/msw/setup.ts b/packages/junior/tests/msw/setup.ts index 9e9dc65c..7b13d344 100644 --- a/packages/junior/tests/msw/setup.ts +++ b/packages/junior/tests/msw/setup.ts @@ -1,3 +1,5 @@ +import { resetEvalOAuthMockState } from "./handlers/eval-oauth"; +import { resetEvalMcpAuthMockState } from "./handlers/eval-mcp-auth"; import { afterAll, afterEach, beforeAll } from "vitest"; import { resetSlackApiMockState } from "./handlers/slack-api"; import { enforceUnhandledSlackRequestFailure, mswServer } from "./server"; @@ -10,6 +12,8 @@ process.env.SLACK_SIGNING_SECRET = "test-signing-secret"; process.env.SLACK_CLIENT_ID = "test-client-id"; process.env.SLACK_CLIENT_SECRET = "test-client-secret"; process.env.SLACK_APP_TOKEN = "xapp-test-token"; +process.env.EVAL_OAUTH_CLIENT_ID = "eval-oauth-client-id"; +process.env.EVAL_OAUTH_CLIENT_SECRET = "eval-oauth-client-secret"; // MSW is enabled globally for both tests and evals. Keep Slack HTTP contract // assertions in tests/integration and keep evals focused on behavior outcomes. @@ -17,12 +21,14 @@ beforeAll(() => { mswServer.listen({ onUnhandledRequest(request) { enforceUnhandledSlackRequestFailure(request); - } + }, }); }); afterEach(() => { mswServer.resetHandlers(); + resetEvalOAuthMockState(); + resetEvalMcpAuthMockState(); resetSlackApiMockState(); }); diff --git a/packages/junior/tests/oauth-callback.test.ts b/packages/junior/tests/oauth-callback.test.ts index d390a549..9465796e 100644 --- a/packages/junior/tests/oauth-callback.test.ts +++ b/packages/junior/tests/oauth-callback.test.ts @@ -1,10 +1,17 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +const { afterCallbacks, generateAssistantReplyMock } = vi.hoisted(() => ({ + afterCallbacks: [] as Array<() => Promise | void>, + generateAssistantReplyMock: vi.fn(async () => ({ + text: "test reply", + diagnostics: { outcome: "success", toolCalls: [] }, + })), +})); + // Mock next/server before importing the route handler vi.mock("next/server", () => ({ - after: (fn: () => unknown) => { - // Capture the callback but don't execute — we test the HTTP response only - void fn; + after: (fn: () => Promise | void) => { + afterCallbacks.push(fn); }, })); @@ -79,10 +86,7 @@ vi.mock("@/chat/plugins/registry", () => ({ // Mock generateAssistantReply vi.mock("@/chat/respond", () => ({ - generateAssistantReply: vi.fn(async () => ({ - text: "test reply", - diagnostics: { outcome: "success", toolCalls: [] }, - })), + generateAssistantReply: generateAssistantReplyMock, })); // Mock botConfig @@ -104,6 +108,8 @@ const ORIGINAL_FETCH = globalThis.fetch; beforeEach(() => { mockStateStore.clear(); mockTokenStore.clear(); + afterCallbacks.length = 0; + generateAssistantReplyMock.mockClear(); }); afterEach(() => { @@ -460,4 +466,39 @@ describe("oauth callback handler", () => { const body = await response.text(); expect(body).toContain("being processed in Slack"); }); + + it("registers after() work to resume pending messages after token exchange", async () => { + const stateKey = "oauth-state:resume-test"; + mockStateStore.set(stateKey, { + userId: "U111", + provider: "sentry", + channelId: "C123", + threadTs: "123.789", + pendingMessage: "list my sentry issues", + }); + + process.env.SENTRY_CLIENT_ID = "client-id"; + process.env.SENTRY_CLIENT_SECRET = "client-secret"; + process.env.JUNIOR_BASE_URL = "https://example.com"; + + globalThis.fetch = vi.fn(async () => ({ + ok: true, + json: async () => ({ + access_token: "token", + refresh_token: "refresh", + expires_in: 3600, + }), + })) as unknown as typeof fetch; + + const response = await GET( + makeRequest( + "https://example.com/api/oauth/callback/sentry?code=code&state=resume-test", + ), + makeContext("sentry"), + ); + + expect(response.status).toBe(200); + expect(afterCallbacks).toHaveLength(2); + expect(generateAssistantReplyMock).not.toHaveBeenCalled(); + }); }); diff --git a/packages/junior/tests/skill-frontmatter.test.ts b/packages/junior/tests/skill-frontmatter.test.ts index dac76067..cb3c63d5 100644 --- a/packages/junior/tests/skill-frontmatter.test.ts +++ b/packages/junior/tests/skill-frontmatter.test.ts @@ -70,6 +70,28 @@ describe("skill frontmatter validation", () => { ]); }); + it("accepts hyphenated provider prefixes in dotted tokens", () => { + const raw = [ + "---", + "name: brief", + "description: Create a candidate brief from public engineering signals.", + "requires-capabilities: eval-oauth.read", + "uses-config: eval-oauth.repo", + "---", + "", + "# Body", + ].join("\n"); + + const result = parseSkillFile(raw, "brief"); + expect(result.ok).toBe(true); + expect(result.ok ? result.skill.requiresCapabilities : null).toEqual([ + "eval-oauth.read", + ]); + expect(result.ok ? result.skill.usesConfig : null).toEqual([ + "eval-oauth.repo", + ]); + }); + it("rejects invalid requires-capabilities tokens", () => { const raw = [ "---", diff --git a/packages/junior/tests/skills.test.ts b/packages/junior/tests/skills.test.ts index 53aa0dd9..28cdb4b3 100644 --- a/packages/junior/tests/skills.test.ts +++ b/packages/junior/tests/skills.test.ts @@ -2,15 +2,24 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; +import { getCapabilityProvider } from "@/chat/capabilities/catalog"; +import { + resetPluginRegistryForTests, + setAdditionalPluginRootsForTests, +} from "@/chat/plugins/registry"; import { discoverSkills, parseSkillInvocation, - resetSkillDiscoveryCache + resetSkillDiscoveryCache, } from "@/chat/skills"; import type { SkillMetadata } from "@/chat/skills"; import * as observability from "@/chat/observability"; -async function writeSkillFile(rootDir: string, name: string, lines: string[]): Promise { +async function writeSkillFile( + rootDir: string, + name: string, + lines: string[], +): Promise { const skillDir = path.join(rootDir, name); await fs.mkdir(skillDir, { recursive: true }); await fs.writeFile(path.join(skillDir, "SKILL.md"), lines.join("\n"), "utf8"); @@ -18,16 +27,19 @@ async function writeSkillFile(rootDir: string, name: string, lines: string[]): P const stubSkills: SkillMetadata[] = [ { name: "brief", description: "Candidate brief", skillPath: "/tmp/brief" }, - { name: "sum", description: "Summarize", skillPath: "/tmp/sum" } + { name: "sum", description: "Summarize", skillPath: "/tmp/sum" }, ]; describe("skills", () => { afterEach(() => { resetSkillDiscoveryCache(); + resetPluginRegistryForTests(); }); it("discovers valid skills from configured skill directories", async () => { - const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "junior-skills-default-")); + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "junior-skills-default-"), + ); const originalSkillDirs = process.env.SKILL_DIRS; await writeSkillFile(tempRoot, "brief", [ @@ -36,7 +48,7 @@ describe("skills", () => { "description: Candidate brief", "---", "", - "# Body" + "# Body", ]); await writeSkillFile(tempRoot, "sum", [ "---", @@ -44,7 +56,7 @@ describe("skills", () => { "description: Summarize", "---", "", - "# Body" + "# Body", ]); resetSkillDiscoveryCache(); @@ -68,20 +80,26 @@ describe("skills", () => { }); it("does not parse invocation without slash command", () => { - expect(parseSkillInvocation("please summarize this candidate", stubSkills)).toBeNull(); + expect( + parseSkillInvocation("please summarize this candidate", stubSkills), + ).toBeNull(); }); it("parses /skill tokens anywhere in the message", () => { - expect(parseSkillInvocation("hey /brief github: octocat", stubSkills)).toEqual({ + expect( + parseSkillInvocation("hey /brief github: octocat", stubSkills), + ).toEqual({ skillName: "brief", - args: "github: octocat" + args: "github: octocat", }); }); it("parses /skill invocation", () => { - expect(parseSkillInvocation("hey /brief github: octocat", stubSkills)).toEqual({ + expect( + parseSkillInvocation("hey /brief github: octocat", stubSkills), + ).toEqual({ skillName: "brief", - args: "github: octocat" + args: "github: octocat", }); }); @@ -96,7 +114,9 @@ describe("skills", () => { it("skips skills with unknown capability/config metadata and logs warnings", async () => { const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "junior-skills-")); const originalSkillDirs = process.env.SKILL_DIRS; - const warnSpy = vi.spyOn(observability, "logWarn").mockImplementation(() => undefined); + const warnSpy = vi + .spyOn(observability, "logWarn") + .mockImplementation(() => undefined); try { await writeSkillFile(tempRoot, "tmp-valid-metadata", [ @@ -105,7 +125,7 @@ describe("skills", () => { "description: Valid metadata skill.", "---", "", - "# Body" + "# Body", ]); await writeSkillFile(tempRoot, "tmp-invalid-capability", [ "---", @@ -114,7 +134,7 @@ describe("skills", () => { "requires-capabilities: github.unknown.read", "---", "", - "# Body" + "# Body", ]); await writeSkillFile(tempRoot, "tmp-invalid-config", [ "---", @@ -123,7 +143,7 @@ describe("skills", () => { "uses-config: github.organization", "---", "", - "# Body" + "# Body", ]); process.env.SKILL_DIRS = tempRoot; @@ -136,12 +156,22 @@ describe("skills", () => { expect(names).not.toContain("tmp-invalid-capability"); expect(names).not.toContain("tmp-invalid-config"); - const warningCalls = warnSpy.mock.calls.filter(([event]) => event === "skill_frontmatter_invalid"); + const warningCalls = warnSpy.mock.calls.filter( + ([event]) => event === "skill_frontmatter_invalid", + ); const warningMessages = warningCalls .map((call) => call[2]) .map((attributes) => String(attributes?.["error.message"] ?? "")); - expect(warningMessages.some((message) => message.includes("Unknown requires-capabilities values"))).toBe(true); - expect(warningMessages.some((message) => message.includes("Unknown uses-config values"))).toBe(true); + expect( + warningMessages.some((message) => + message.includes("Unknown requires-capabilities values"), + ), + ).toBe(true); + expect( + warningMessages.some((message) => + message.includes("Unknown uses-config values"), + ), + ).toBe(true); } finally { warnSpy.mockRestore(); resetSkillDiscoveryCache(); @@ -153,4 +183,82 @@ describe("skills", () => { await fs.rm(tempRoot, { recursive: true, force: true }); } }); + + it("discovers plugin skills and capabilities added after module load", async () => { + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "junior-plugin-skill-late-load-"), + ); + const pluginRoot = path.join(tempRoot, "demo"); + + try { + await fs.mkdir(path.join(pluginRoot, "skills", "demo-connect"), { + recursive: true, + }); + await fs.writeFile( + path.join(pluginRoot, "plugin.yaml"), + [ + "name: demo", + "description: Demo plugin", + "capabilities:", + " - read", + "credentials:", + " type: oauth-bearer", + " api-domains:", + " - demo.example.test", + " auth-token-env: DEMO_ACCESS_TOKEN", + ].join("\n"), + "utf8", + ); + await fs.writeFile( + path.join(pluginRoot, "skills", "demo-connect", "SKILL.md"), + [ + "---", + "name: demo-connect", + "description: Demo plugin skill", + "allowed-tools: bash", + "requires-capabilities: demo.read", + "---", + "", + "# Body", + ].join("\n"), + "utf8", + ); + + setAdditionalPluginRootsForTests([pluginRoot]); + resetSkillDiscoveryCache(); + + const skills = await discoverSkills(); + expect( + skills.find((skill) => skill.name === "demo-connect"), + ).toMatchObject({ + name: "demo-connect", + pluginProvider: "demo", + requiresCapabilities: ["demo.read"], + }); + expect(getCapabilityProvider("demo.read")).toMatchObject({ + provider: "demo", + capabilities: ["demo.read"], + }); + } finally { + await fs.rm(tempRoot, { recursive: true, force: true }); + } + }); + + it("discovers eval plugin skills from a shared plugin root", async () => { + const evalPluginsRoot = path.resolve(process.cwd(), "evals", "plugins"); + + setAdditionalPluginRootsForTests([evalPluginsRoot]); + resetSkillDiscoveryCache(); + + const skills = await discoverSkills(); + const skillNames = skills.map((skill) => skill.name); + + expect(skillNames).toContain("eval-auth"); + expect(skillNames).toContain("eval-oauth"); + expect(skills.find((skill) => skill.name === "eval-oauth")).toMatchObject({ + pluginProvider: "eval-oauth", + requiresCapabilities: ["eval-oauth.read"], + allowedTools: ["bash"], + }); + }); }); diff --git a/packages/junior/tests/unit/handlers/oauth-resume.test.ts b/packages/junior/tests/unit/handlers/oauth-resume.test.ts new file mode 100644 index 00000000..a186bf27 --- /dev/null +++ b/packages/junior/tests/unit/handlers/oauth-resume.test.ts @@ -0,0 +1,73 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +const { postMessageMock, setStatusMock } = vi.hoisted(() => ({ + postMessageMock: vi.fn(), + setStatusMock: vi.fn(), +})); + +vi.mock("@/chat/config", () => ({ + botConfig: { + userName: "junior", + }, +})); + +vi.mock("@/chat/slack-actions/client", () => ({ + getSlackClient: () => ({ + chat: { + postMessage: postMessageMock, + }, + assistant: { + threads: { + setStatus: setStatusMock, + }, + }, + }), +})); + +import { resumeAuthorizedRequest } from "@/handlers/oauth-resume"; + +describe("resumeAuthorizedRequest", () => { + beforeEach(() => { + vi.useFakeTimers(); + postMessageMock.mockReset(); + setStatusMock.mockReset(); + postMessageMock.mockResolvedValue(undefined); + setStatusMock.mockResolvedValue(undefined); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it("fails fast when resumed reply generation exceeds the configured timeout", async () => { + const onFailure = vi.fn(async () => undefined); + + const resumePromise = resumeAuthorizedRequest({ + messageText: "tell me the saved deadline", + requesterUserId: "U-test", + provider: "eval-auth", + channelId: "C-test", + threadTs: "1700000000.0001", + connectedText: "connected", + failureText: "resume failed", + generateReply: () => new Promise(() => {}), + replyTimeoutMs: 10, + onFailure, + }); + + await vi.advanceTimersByTimeAsync(10); + await resumePromise; + + expect(onFailure).toHaveBeenCalledTimes(1); + expect(postMessageMock).toHaveBeenNthCalledWith(1, { + channel: "C-test", + thread_ts: "1700000000.0001", + text: "connected", + }); + expect(postMessageMock).toHaveBeenNthCalledWith(2, { + channel: "C-test", + thread_ts: "1700000000.0001", + text: "resume failed", + }); + }); +}); diff --git a/packages/junior/tests/unit/harness/behavior-harness.test.ts b/packages/junior/tests/unit/harness/behavior-harness.test.ts new file mode 100644 index 00000000..8a0f8496 --- /dev/null +++ b/packages/junior/tests/unit/harness/behavior-harness.test.ts @@ -0,0 +1,76 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +const { observedRuntimeIds, handleNewMentionMock, noopAsync } = vi.hoisted( + () => ({ + observedRuntimeIds: { + messageThreadId: undefined as string | undefined, + threadId: undefined as string | undefined, + }, + handleNewMentionMock: vi.fn( + async ( + thread: { id: string; post: (value: string) => Promise }, + message: { threadId?: string }, + ) => { + observedRuntimeIds.threadId = thread.id; + observedRuntimeIds.messageThreadId = message.threadId; + await thread.post("observed"); + }, + ), + noopAsync: vi.fn(async () => {}), + }), +); + +vi.mock("@/chat/bot", () => ({ + appSlackRuntime: { + handleNewMention: handleNewMentionMock, + handleSubscribedMessage: noopAsync, + handleAssistantThreadStarted: noopAsync, + handleAssistantContextChanged: noopAsync, + }, + bot: { + getAdapter: () => undefined, + }, + resetBotDepsForTests: noopAsync, + setBotDepsForTests: noopAsync, +})); + +import { runBehaviorEvalCase } from "../../../evals/behavior-harness"; + +describe("behavior harness", () => { + afterEach(() => { + observedRuntimeIds.threadId = undefined; + observedRuntimeIds.messageThreadId = undefined; + handleNewMentionMock.mockClear(); + noopAsync.mockClear(); + }); + + it("normalizes eval thread fixtures to Slack-style runtime thread ids", async () => { + const result = await runBehaviorEvalCase({ + events: [ + { + type: "new_mention", + thread: { + id: "fixture-auth-thread", + channel_id: "C_AUTH", + thread_ts: "1700000000.0001", + }, + message: { + id: "m-auth-1", + text: "hello", + is_mention: true, + author: { + user_id: "U_AUTH", + }, + }, + }, + ], + }); + + expect(handleNewMentionMock).toHaveBeenCalledTimes(1); + expect(observedRuntimeIds.threadId).toBe("slack:C_AUTH:1700000000.0001"); + expect(observedRuntimeIds.messageThreadId).toBe( + "slack:C_AUTH:1700000000.0001", + ); + expect(result.posts).toEqual(["observed"]); + }); +}); diff --git a/packages/junior/tests/unit/harness/mcp-oauth-callback-harness.test.ts b/packages/junior/tests/unit/harness/mcp-oauth-callback-harness.test.ts new file mode 100644 index 00000000..a6fe9e5d --- /dev/null +++ b/packages/junior/tests/unit/harness/mcp-oauth-callback-harness.test.ts @@ -0,0 +1,31 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +const { routerGetMock } = vi.hoisted(() => ({ + routerGetMock: vi.fn(), +})); + +vi.mock("@/handlers/router", () => ({ + GET: routerGetMock, +})); + +import { runMcpOauthCallbackRoute } from "../../fixtures/mcp-oauth-callback-harness"; + +describe("mcp oauth callback harness", () => { + afterEach(() => { + routerGetMock.mockReset(); + }); + + it("fails when the callback route returns success without registering after() work", async () => { + routerGetMock.mockResolvedValue(new Response("ok", { status: 200 })); + + await expect( + runMcpOauthCallbackRoute({ + provider: "eval-auth", + state: "auth-session-1", + code: "eval-auth-code", + }), + ).rejects.toThrow( + 'MCP OAuth callback route returned 200 without registering after() work for provider "eval-auth"', + ); + }); +}); diff --git a/packages/junior/tests/unit/harness/oauth-callback-harness.test.ts b/packages/junior/tests/unit/harness/oauth-callback-harness.test.ts new file mode 100644 index 00000000..90c2fc81 --- /dev/null +++ b/packages/junior/tests/unit/harness/oauth-callback-harness.test.ts @@ -0,0 +1,31 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +const { routerGetMock } = vi.hoisted(() => ({ + routerGetMock: vi.fn(), +})); + +vi.mock("@/handlers/router", () => ({ + GET: routerGetMock, +})); + +import { runOauthCallbackRoute } from "../../fixtures/oauth-callback-harness"; + +describe("oauth callback harness", () => { + afterEach(() => { + routerGetMock.mockReset(); + }); + + it("fails when the callback route returns success without registering after() work", async () => { + routerGetMock.mockResolvedValue(new Response("ok", { status: 200 })); + + await expect( + runOauthCallbackRoute({ + provider: "eval-oauth", + state: "oauth-state-1", + code: "eval-oauth-code", + }), + ).rejects.toThrow( + 'OAuth callback route returned 200 without registering after() work for provider "eval-oauth"', + ); + }); +}); diff --git a/packages/junior/tests/unit/respond-explicit-skill-preload.test.ts b/packages/junior/tests/unit/respond-explicit-skill-preload.test.ts new file mode 100644 index 00000000..9fdae843 --- /dev/null +++ b/packages/junior/tests/unit/respond-explicit-skill-preload.test.ts @@ -0,0 +1,155 @@ +import path from "node:path"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { + resetPluginRegistryForTests, + setAdditionalPluginRootsForTests, +} from "@/chat/plugins/registry"; +import { resetSkillDiscoveryCache } from "@/chat/skills"; + +const { capturedActiveSkillNames } = vi.hoisted(() => ({ + capturedActiveSkillNames: [] as string[][], +})); + +vi.mock("@mariozechner/pi-agent-core", () => { + class MockAgent { + state: { + messages: unknown[]; + model: unknown; + systemPrompt: string; + tools: Array<{ + name: string; + execute: (toolCallId: unknown, params: unknown) => Promise; + }>; + }; + + constructor(input: { + initialState: { + model: unknown; + systemPrompt: string; + tools: Array<{ + name: string; + execute: (toolCallId: unknown, params: unknown) => Promise; + }>; + }; + }) { + this.state = { + messages: [], + model: input.initialState.model, + systemPrompt: input.initialState.systemPrompt, + tools: [...input.initialState.tools], + }; + } + + subscribe() { + return () => undefined; + } + + abort() {} + + async prompt(message: unknown) { + this.state.messages.push(message); + this.state.messages.push({ + role: "assistant", + content: [{ type: "text", text: "ok" }], + stopReason: "stop", + }); + return {}; + } + } + + return { Agent: MockAgent }; +}); + +vi.mock("@/chat/observability", () => ({ + logException: vi.fn(), + logInfo: vi.fn(), + logWarn: vi.fn(), + setSpanAttributes: vi.fn(), + setSpanStatus: vi.fn(), + setTags: vi.fn(), + withSpan: async ( + _name: string, + _op: string, + _context: unknown, + callback: () => Promise, + ) => await callback(), +})); + +vi.mock("@/chat/pi/client", () => ({ + GEN_AI_PROVIDER_NAME: "vercel-ai-gateway", + getGatewayApiKey: () => "test-gateway-key", + resolveGatewayModel: (modelId: string) => modelId, +})); + +vi.mock("@/chat/prompt", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + buildSystemPrompt: ( + params: Parameters[0], + ) => { + capturedActiveSkillNames.push( + params.activeSkills.map((skill) => skill.name), + ); + return "System prompt"; + }, + }; +}); + +vi.mock("@/chat/runtime/dev-agent-trace", () => ({ + shouldEmitDevAgentTrace: () => false, +})); + +vi.mock("@/chat/runtime-metadata", () => ({ + getRuntimeMetadata: () => ({ version: "test" }), +})); + +vi.mock("@/chat/sandbox/sandbox", () => ({ + createSandboxExecutor: () => ({ + configureSkills: () => undefined, + createSandbox: async () => ({}), + canExecute: () => false, + execute: async () => { + throw new Error("sandbox executor should not execute in preload test"); + }, + getSandboxId: () => "sandbox-test", + getDependencyProfileHash: () => "hash-test", + dispose: async () => undefined, + }), +})); + +import { generateAssistantReply } from "@/chat/respond"; + +describe("generateAssistantReply explicit skill preload", () => { + beforeEach(() => { + capturedActiveSkillNames.length = 0; + resetPluginRegistryForTests(); + setAdditionalPluginRootsForTests([ + path.resolve(process.cwd(), "evals/plugins"), + ]); + resetSkillDiscoveryCache(); + }); + + afterEach(() => { + resetPluginRegistryForTests(); + resetSkillDiscoveryCache(); + }); + + it("preloads explicitly invoked eval plugin skills into the system prompt", async () => { + await generateAssistantReply( + "/eval-oauth Connect the demo account, then tell me what budget deadline I mentioned earlier.", + { + requester: { userId: "U_TEST" }, + correlation: { + channelId: "C_TEST", + threadTs: "1700000000.0001", + requesterId: "U_TEST", + }, + }, + ); + + expect( + capturedActiveSkillNames.some((names) => names.includes("eval-oauth")), + ).toBe(true); + }); +}); diff --git a/packages/junior/tests/unit/respond-oauth-start.test.ts b/packages/junior/tests/unit/respond-oauth-start.test.ts new file mode 100644 index 00000000..225d52e3 --- /dev/null +++ b/packages/junior/tests/unit/respond-oauth-start.test.ts @@ -0,0 +1,188 @@ +import { describe, expect, it, vi } from "vitest"; + +vi.mock("@mariozechner/pi-agent-core", () => { + class MockAgent { + state: { + messages: unknown[]; + model: unknown; + systemPrompt: string; + tools: Array<{ + name: string; + execute: (toolCallId: unknown, params: unknown) => Promise; + }>; + }; + + constructor(input: { + initialState: { + model: unknown; + systemPrompt: string; + tools: Array<{ + name: string; + execute: (toolCallId: unknown, params: unknown) => Promise; + }>; + }; + }) { + this.state = { + messages: [], + model: input.initialState.model, + systemPrompt: input.initialState.systemPrompt, + tools: [...input.initialState.tools], + }; + } + + subscribe() { + return () => undefined; + } + + abort() {} + + async prompt(message: unknown) { + this.state.messages.push(message); + + const bashTool = this.state.tools.find((tool) => tool.name === "bash"); + if (!bashTool) { + throw new Error("bash tool missing"); + } + + const result = (await bashTool.execute("tool-call-1", { + command: "jr-rpc issue-credential eval-oauth.read", + })) as { content?: unknown; details?: unknown }; + + this.state.messages.push({ + role: "toolResult", + toolName: "bash", + isError: false, + content: Array.isArray(result.content) ? result.content : [], + details: result.details, + }); + + return {}; + } + } + + return { Agent: MockAgent }; +}); + +vi.mock("@/chat/observability", () => ({ + logException: vi.fn(), + logInfo: vi.fn(), + logWarn: vi.fn(), + setSpanAttributes: vi.fn(), + setSpanStatus: vi.fn(), + setTags: vi.fn(), + withSpan: async ( + _name: string, + _op: string, + _context: unknown, + callback: () => Promise, + ) => await callback(), +})); + +vi.mock("@/chat/pi/client", () => ({ + GEN_AI_PROVIDER_NAME: "vercel-ai-gateway", + getGatewayApiKey: () => "test-gateway-key", + resolveGatewayModel: (modelId: string) => modelId, +})); + +vi.mock("@/chat/prompt", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + buildSystemPrompt: () => "System prompt", + }; +}); + +vi.mock("@/chat/runtime/dev-agent-trace", () => ({ + shouldEmitDevAgentTrace: () => false, +})); + +vi.mock("@/chat/runtime-metadata", () => ({ + getRuntimeMetadata: () => ({ version: "test" }), +})); + +vi.mock("@/chat/capabilities/factory", () => ({ + createSkillCapabilityRuntime: () => ({ + getTurnHeaderTransforms: () => undefined, + getTurnEnv: () => undefined, + }), + getUserTokenStore: () => ({ + get: async () => undefined, + set: async () => undefined, + delete: async () => undefined, + }), +})); + +vi.mock("@/chat/capabilities/jr-rpc-command", () => ({ + maybeExecuteJrRpcCustomCommand: async () => ({ handled: false }), +})); + +vi.mock("@/chat/sandbox/sandbox", () => ({ + createSandboxExecutor: () => ({ + configureSkills: () => undefined, + createSandbox: async () => ({}), + canExecute: (toolName: string) => toolName === "bash", + execute: async () => ({ + result: { + ok: true, + exit_code: 0, + duration_ms: 1, + stdout: `${JSON.stringify( + { + credential_unavailable: true, + oauth_started: true, + provider: "eval-oauth", + private_delivery_sent: true, + message: + "I need to connect your Eval-oauth account first. I've sent you a private authorization link.", + }, + null, + 2, + )}\n`, + stderr: "", + stdout_truncated: false, + stderr_truncated: false, + }, + }), + getSandboxId: () => "sandbox-test", + getDependencyProfileHash: () => "hash-test", + dispose: async () => undefined, + }), +})); + +vi.mock("@/chat/plugins/registry", () => ({ + getPluginMcpProviders: () => [], + getPluginProviders: () => [], +})); + +vi.mock("@/chat/skills", () => ({ + discoverSkills: async () => [], + findSkillByName: () => null, + loadSkillsByName: async () => [], + parseSkillInvocation: () => null, +})); + +import { generateAssistantReply } from "@/chat/respond"; + +describe("generateAssistantReply generic OAuth start fallback", () => { + it("uses the oauth-started message when the model emits no assistant text", async () => { + const reply = await generateAssistantReply( + "Connect the demo account, then tell me what budget deadline I mentioned earlier.", + { + requester: { userId: "U_TEST" }, + correlation: { + channelId: "C_TEST", + threadTs: "1700000000.0001", + requesterId: "U_TEST", + }, + }, + ); + + expect(reply.text).toBe( + "I need to connect your Eval-oauth account first. I've sent you a private authorization link.", + ); + expect(reply.diagnostics.outcome).toBe("success"); + expect(reply.diagnostics.usedPrimaryText).toBe(false); + expect(reply.diagnostics.toolResultCount).toBe(1); + expect(reply.diagnostics.toolErrorCount).toBe(0); + }); +}); diff --git a/specs/testing/evals-spec.md b/specs/testing/evals-spec.md index 98d7ee95..82556a8a 100644 --- a/specs/testing/evals-spec.md +++ b/specs/testing/evals-spec.md @@ -9,7 +9,7 @@ - 2026-03-03: Standardized metadata headers and reconciled spec references/structure. - 2026-03-04: Normalized section shape by introducing explicit `Non-Goals`. - +- 2026-03-20: Added natural-prompt authoring rule and explicit ban on scripting internal commands/tools into eval prompts. ## Intent @@ -18,6 +18,7 @@ Evals validate end-to-end conversational behavior outcomes through the runtime h ## Scope In scope: + - Multi-turn conversational behavior. - User-visible response quality and continuity. - Lifecycle/resilience behavior as observed by users. @@ -33,13 +34,18 @@ In scope: 2. Keep each case focused on one primary behavior outcome. 3. Express expectations in natural-language criteria. 4. Avoid asserting tool-internal mechanics unless explicitly user-visible. +5. Keep user prompts natural and product-realistic. Do not script exact internal commands, tool names, or implementation steps into the prompt just to force a path. +6. If a case only works when the prompt prescribes internal mechanics, treat that as an eval-design failure or product-behavior gap, not a passing eval. +7. If a case uses harness-controlled decision fixtures such as subscribed-message reply gating, do not claim those gated behaviors are being validated by the eval outcome. ## Boundaries Do not in eval files: + - Import Slack action internals for direct contract assertions. - Use MSW queue/capture helpers intended for integration contract tests. - Rely on implementation-only identifiers (exact internal tool names, opaque IDs) unless the case intentionally evaluates that surface. +- Encode exact internal commands or tool choices in user prompts when the contract under test is higher-level conversational behavior. ## Relationship to Other Layers From 1b23e46cbdafb19531c6851bd30ee9b91ea1a14d Mon Sep 17 00:00:00 2001 From: David Cramer Date: Fri, 20 Mar 2026 17:43:39 -0700 Subject: [PATCH 24/28] test(oauth): trim mock-heavy auth coverage Replace the heavy mocked respond.ts OAuth-start regression with a small pure parser test and keep the higher-level auth workflow coverage in integration tests and evals. Also merge the duplicate callback-harness guardrail tests and remove the redundant shared eval-plugin discovery check so the suite stays smaller and more focused. Co-Authored-By: GPT-5 Codex --- packages/junior/src/chat/respond.ts | 85 +------- packages/junior/src/chat/tool-result-oauth.ts | 114 +++++++++++ packages/junior/tests/skills.test.ts | 18 -- .../mcp-oauth-callback-harness.test.ts | 31 --- .../harness/oauth-callback-harness.test.ts | 45 +++-- .../respond-explicit-skill-preload.test.ts | 155 --------------- .../tests/unit/respond-oauth-start.test.ts | 188 ------------------ .../tests/unit/tool-result-oauth.test.ts | 48 +++++ 8 files changed, 197 insertions(+), 487 deletions(-) create mode 100644 packages/junior/src/chat/tool-result-oauth.ts delete mode 100644 packages/junior/tests/unit/harness/mcp-oauth-callback-harness.test.ts delete mode 100644 packages/junior/tests/unit/respond-explicit-skill-preload.test.ts delete mode 100644 packages/junior/tests/unit/respond-oauth-start.test.ts create mode 100644 packages/junior/tests/unit/tool-result-oauth.test.ts diff --git a/packages/junior/src/chat/respond.ts b/packages/junior/src/chat/respond.ts index 8bac543b..92e74554 100644 --- a/packages/junior/src/chat/respond.ts +++ b/packages/junior/src/chat/respond.ts @@ -77,6 +77,7 @@ import { compactStatusText, extractStatusUrlDomain, } from "@/chat/status-format"; +import { extractOAuthStartedMessageFromToolResults } from "@/chat/tool-result-oauth"; import { RetryableTurnError, isRetryableTurnError } from "@/chat/turn/errors"; import { enforceAttachmentClaimTruth } from "@/chat/attachment-claims"; import { mergeArtifactsState } from "@/chat/runtime/thread-state"; @@ -559,87 +560,6 @@ function buildExecutionFailureMessage(toolErrorCount: number): string { return "I couldn’t complete this request in this turn due to an execution failure. I’ve logged the details for debugging."; } -function extractOAuthStartedPayload( - value: unknown, -): { message?: string } | undefined { - if (typeof value === "string") { - const parsed = parseJsonCandidate(value); - return parsed === undefined - ? undefined - : extractOAuthStartedPayload(parsed); - } - - if (Array.isArray(value)) { - for (const entry of value) { - const found = extractOAuthStartedPayload(entry); - if (found) { - return found; - } - } - return undefined; - } - - if (!value || typeof value !== "object") { - return undefined; - } - - const record = value as Record; - if (record.oauth_started === true) { - const message = - typeof record.message === "string" ? record.message.trim() : undefined; - return message ? { message } : {}; - } - - const content = record.content; - if (Array.isArray(content)) { - for (const part of content) { - const text = - part && - typeof part === "object" && - (part as { type?: unknown }).type === "text" && - typeof (part as { text?: unknown }).text === "string" - ? (part as { text: string }).text - : part; - const found = extractOAuthStartedPayload(text); - if (found) { - return found; - } - } - } - - for (const key of ["details", "output", "result", "stdout"]) { - if (!(key in record)) { - continue; - } - const found = extractOAuthStartedPayload(record[key]); - if (found) { - return found; - } - } - - return undefined; -} - -function extractOAuthStartedMessage( - toolResults: unknown[], -): string | undefined { - for (const result of toolResults) { - if ( - normalizeToolNameFromResult(result) !== "bash" || - isToolResultError(result) - ) { - continue; - } - - const found = extractOAuthStartedPayload(result); - if (found?.message) { - return found.message; - } - } - - return undefined; -} - function toToolContentText(value: unknown): string { if (typeof value === "string") return value; try { @@ -1700,7 +1620,8 @@ export async function generateAssistantReply( .map((message) => extractAssistantText(message)) .join("\n\n") .trim(); - const oauthStartedMessage = extractOAuthStartedMessage(toolResults); + const oauthStartedMessage = + extractOAuthStartedMessageFromToolResults(toolResults); const toolErrorCount = toolResults.filter( (result) => result.isError, diff --git a/packages/junior/src/chat/tool-result-oauth.ts b/packages/junior/src/chat/tool-result-oauth.ts new file mode 100644 index 00000000..2b4bf77f --- /dev/null +++ b/packages/junior/src/chat/tool-result-oauth.ts @@ -0,0 +1,114 @@ +function parseJsonCandidate(text: string): unknown { + const trimmed = text.trim(); + if (!trimmed) return undefined; + + try { + return JSON.parse(trimmed) as unknown; + } catch { + const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i); + if (!fenced) return undefined; + try { + return JSON.parse(fenced[1]) as unknown; + } catch { + return undefined; + } + } +} + +function normalizeToolNameFromResult(result: unknown): string | undefined { + if (!result || typeof result !== "object") return undefined; + const record = result as { toolName?: unknown; name?: unknown }; + if (typeof record.toolName === "string" && record.toolName.length > 0) { + return record.toolName; + } + if (typeof record.name === "string" && record.name.length > 0) { + return record.name; + } + return undefined; +} + +function isToolResultError(result: unknown): boolean { + if (!result || typeof result !== "object") return false; + return Boolean((result as { isError?: unknown }).isError); +} + +function extractOAuthStartedPayload( + value: unknown, +): { message?: string } | undefined { + if (typeof value === "string") { + const parsed = parseJsonCandidate(value); + return parsed === undefined + ? undefined + : extractOAuthStartedPayload(parsed); + } + + if (Array.isArray(value)) { + for (const entry of value) { + const found = extractOAuthStartedPayload(entry); + if (found) { + return found; + } + } + return undefined; + } + + if (!value || typeof value !== "object") { + return undefined; + } + + const record = value as Record; + if (record.oauth_started === true) { + const message = + typeof record.message === "string" ? record.message.trim() : undefined; + return message ? { message } : {}; + } + + const content = record.content; + if (Array.isArray(content)) { + for (const part of content) { + const text = + part && + typeof part === "object" && + (part as { type?: unknown }).type === "text" && + typeof (part as { text?: unknown }).text === "string" + ? (part as { text: string }).text + : part; + const found = extractOAuthStartedPayload(text); + if (found) { + return found; + } + } + } + + for (const key of ["details", "output", "result", "stdout"]) { + if (!(key in record)) { + continue; + } + const found = extractOAuthStartedPayload(record[key]); + if (found) { + return found; + } + } + + return undefined; +} + +export function extractOAuthStartedMessageFromToolResults( + toolResults: unknown[], +): string | undefined { + for (const result of toolResults) { + if ( + normalizeToolNameFromResult(result) !== "bash" || + isToolResultError(result) + ) { + continue; + } + + const found = extractOAuthStartedPayload(result); + if (found?.message) { + return found.message; + } + } + + return undefined; +} diff --git a/packages/junior/tests/skills.test.ts b/packages/junior/tests/skills.test.ts index 28cdb4b3..70a726bf 100644 --- a/packages/junior/tests/skills.test.ts +++ b/packages/junior/tests/skills.test.ts @@ -243,22 +243,4 @@ describe("skills", () => { await fs.rm(tempRoot, { recursive: true, force: true }); } }); - - it("discovers eval plugin skills from a shared plugin root", async () => { - const evalPluginsRoot = path.resolve(process.cwd(), "evals", "plugins"); - - setAdditionalPluginRootsForTests([evalPluginsRoot]); - resetSkillDiscoveryCache(); - - const skills = await discoverSkills(); - const skillNames = skills.map((skill) => skill.name); - - expect(skillNames).toContain("eval-auth"); - expect(skillNames).toContain("eval-oauth"); - expect(skills.find((skill) => skill.name === "eval-oauth")).toMatchObject({ - pluginProvider: "eval-oauth", - requiresCapabilities: ["eval-oauth.read"], - allowedTools: ["bash"], - }); - }); }); diff --git a/packages/junior/tests/unit/harness/mcp-oauth-callback-harness.test.ts b/packages/junior/tests/unit/harness/mcp-oauth-callback-harness.test.ts deleted file mode 100644 index a6fe9e5d..00000000 --- a/packages/junior/tests/unit/harness/mcp-oauth-callback-harness.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; - -const { routerGetMock } = vi.hoisted(() => ({ - routerGetMock: vi.fn(), -})); - -vi.mock("@/handlers/router", () => ({ - GET: routerGetMock, -})); - -import { runMcpOauthCallbackRoute } from "../../fixtures/mcp-oauth-callback-harness"; - -describe("mcp oauth callback harness", () => { - afterEach(() => { - routerGetMock.mockReset(); - }); - - it("fails when the callback route returns success without registering after() work", async () => { - routerGetMock.mockResolvedValue(new Response("ok", { status: 200 })); - - await expect( - runMcpOauthCallbackRoute({ - provider: "eval-auth", - state: "auth-session-1", - code: "eval-auth-code", - }), - ).rejects.toThrow( - 'MCP OAuth callback route returned 200 without registering after() work for provider "eval-auth"', - ); - }); -}); diff --git a/packages/junior/tests/unit/harness/oauth-callback-harness.test.ts b/packages/junior/tests/unit/harness/oauth-callback-harness.test.ts index 90c2fc81..33f70f61 100644 --- a/packages/junior/tests/unit/harness/oauth-callback-harness.test.ts +++ b/packages/junior/tests/unit/harness/oauth-callback-harness.test.ts @@ -9,23 +9,42 @@ vi.mock("@/handlers/router", () => ({ })); import { runOauthCallbackRoute } from "../../fixtures/oauth-callback-harness"; +import { runMcpOauthCallbackRoute } from "../../fixtures/mcp-oauth-callback-harness"; -describe("oauth callback harness", () => { +describe("oauth callback harnesses", () => { afterEach(() => { routerGetMock.mockReset(); }); - it("fails when the callback route returns success without registering after() work", async () => { - routerGetMock.mockResolvedValue(new Response("ok", { status: 200 })); + it.each([ + { + label: "generic OAuth", + run: () => + runOauthCallbackRoute({ + provider: "eval-oauth", + state: "oauth-state-1", + code: "eval-oauth-code", + }), + expectedError: + 'OAuth callback route returned 200 without registering after() work for provider "eval-oauth"', + }, + { + label: "MCP OAuth", + run: () => + runMcpOauthCallbackRoute({ + provider: "eval-auth", + state: "auth-session-1", + code: "eval-auth-code", + }), + expectedError: + 'MCP OAuth callback route returned 200 without registering after() work for provider "eval-auth"', + }, + ])( + "fails when the $label callback route returns success without registering after() work", + async ({ run, expectedError }) => { + routerGetMock.mockResolvedValue(new Response("ok", { status: 200 })); - await expect( - runOauthCallbackRoute({ - provider: "eval-oauth", - state: "oauth-state-1", - code: "eval-oauth-code", - }), - ).rejects.toThrow( - 'OAuth callback route returned 200 without registering after() work for provider "eval-oauth"', - ); - }); + await expect(run()).rejects.toThrow(expectedError); + }, + ); }); diff --git a/packages/junior/tests/unit/respond-explicit-skill-preload.test.ts b/packages/junior/tests/unit/respond-explicit-skill-preload.test.ts deleted file mode 100644 index 9fdae843..00000000 --- a/packages/junior/tests/unit/respond-explicit-skill-preload.test.ts +++ /dev/null @@ -1,155 +0,0 @@ -import path from "node:path"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { - resetPluginRegistryForTests, - setAdditionalPluginRootsForTests, -} from "@/chat/plugins/registry"; -import { resetSkillDiscoveryCache } from "@/chat/skills"; - -const { capturedActiveSkillNames } = vi.hoisted(() => ({ - capturedActiveSkillNames: [] as string[][], -})); - -vi.mock("@mariozechner/pi-agent-core", () => { - class MockAgent { - state: { - messages: unknown[]; - model: unknown; - systemPrompt: string; - tools: Array<{ - name: string; - execute: (toolCallId: unknown, params: unknown) => Promise; - }>; - }; - - constructor(input: { - initialState: { - model: unknown; - systemPrompt: string; - tools: Array<{ - name: string; - execute: (toolCallId: unknown, params: unknown) => Promise; - }>; - }; - }) { - this.state = { - messages: [], - model: input.initialState.model, - systemPrompt: input.initialState.systemPrompt, - tools: [...input.initialState.tools], - }; - } - - subscribe() { - return () => undefined; - } - - abort() {} - - async prompt(message: unknown) { - this.state.messages.push(message); - this.state.messages.push({ - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - }); - return {}; - } - } - - return { Agent: MockAgent }; -}); - -vi.mock("@/chat/observability", () => ({ - logException: vi.fn(), - logInfo: vi.fn(), - logWarn: vi.fn(), - setSpanAttributes: vi.fn(), - setSpanStatus: vi.fn(), - setTags: vi.fn(), - withSpan: async ( - _name: string, - _op: string, - _context: unknown, - callback: () => Promise, - ) => await callback(), -})); - -vi.mock("@/chat/pi/client", () => ({ - GEN_AI_PROVIDER_NAME: "vercel-ai-gateway", - getGatewayApiKey: () => "test-gateway-key", - resolveGatewayModel: (modelId: string) => modelId, -})); - -vi.mock("@/chat/prompt", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - buildSystemPrompt: ( - params: Parameters[0], - ) => { - capturedActiveSkillNames.push( - params.activeSkills.map((skill) => skill.name), - ); - return "System prompt"; - }, - }; -}); - -vi.mock("@/chat/runtime/dev-agent-trace", () => ({ - shouldEmitDevAgentTrace: () => false, -})); - -vi.mock("@/chat/runtime-metadata", () => ({ - getRuntimeMetadata: () => ({ version: "test" }), -})); - -vi.mock("@/chat/sandbox/sandbox", () => ({ - createSandboxExecutor: () => ({ - configureSkills: () => undefined, - createSandbox: async () => ({}), - canExecute: () => false, - execute: async () => { - throw new Error("sandbox executor should not execute in preload test"); - }, - getSandboxId: () => "sandbox-test", - getDependencyProfileHash: () => "hash-test", - dispose: async () => undefined, - }), -})); - -import { generateAssistantReply } from "@/chat/respond"; - -describe("generateAssistantReply explicit skill preload", () => { - beforeEach(() => { - capturedActiveSkillNames.length = 0; - resetPluginRegistryForTests(); - setAdditionalPluginRootsForTests([ - path.resolve(process.cwd(), "evals/plugins"), - ]); - resetSkillDiscoveryCache(); - }); - - afterEach(() => { - resetPluginRegistryForTests(); - resetSkillDiscoveryCache(); - }); - - it("preloads explicitly invoked eval plugin skills into the system prompt", async () => { - await generateAssistantReply( - "/eval-oauth Connect the demo account, then tell me what budget deadline I mentioned earlier.", - { - requester: { userId: "U_TEST" }, - correlation: { - channelId: "C_TEST", - threadTs: "1700000000.0001", - requesterId: "U_TEST", - }, - }, - ); - - expect( - capturedActiveSkillNames.some((names) => names.includes("eval-oauth")), - ).toBe(true); - }); -}); diff --git a/packages/junior/tests/unit/respond-oauth-start.test.ts b/packages/junior/tests/unit/respond-oauth-start.test.ts deleted file mode 100644 index 225d52e3..00000000 --- a/packages/junior/tests/unit/respond-oauth-start.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; - -vi.mock("@mariozechner/pi-agent-core", () => { - class MockAgent { - state: { - messages: unknown[]; - model: unknown; - systemPrompt: string; - tools: Array<{ - name: string; - execute: (toolCallId: unknown, params: unknown) => Promise; - }>; - }; - - constructor(input: { - initialState: { - model: unknown; - systemPrompt: string; - tools: Array<{ - name: string; - execute: (toolCallId: unknown, params: unknown) => Promise; - }>; - }; - }) { - this.state = { - messages: [], - model: input.initialState.model, - systemPrompt: input.initialState.systemPrompt, - tools: [...input.initialState.tools], - }; - } - - subscribe() { - return () => undefined; - } - - abort() {} - - async prompt(message: unknown) { - this.state.messages.push(message); - - const bashTool = this.state.tools.find((tool) => tool.name === "bash"); - if (!bashTool) { - throw new Error("bash tool missing"); - } - - const result = (await bashTool.execute("tool-call-1", { - command: "jr-rpc issue-credential eval-oauth.read", - })) as { content?: unknown; details?: unknown }; - - this.state.messages.push({ - role: "toolResult", - toolName: "bash", - isError: false, - content: Array.isArray(result.content) ? result.content : [], - details: result.details, - }); - - return {}; - } - } - - return { Agent: MockAgent }; -}); - -vi.mock("@/chat/observability", () => ({ - logException: vi.fn(), - logInfo: vi.fn(), - logWarn: vi.fn(), - setSpanAttributes: vi.fn(), - setSpanStatus: vi.fn(), - setTags: vi.fn(), - withSpan: async ( - _name: string, - _op: string, - _context: unknown, - callback: () => Promise, - ) => await callback(), -})); - -vi.mock("@/chat/pi/client", () => ({ - GEN_AI_PROVIDER_NAME: "vercel-ai-gateway", - getGatewayApiKey: () => "test-gateway-key", - resolveGatewayModel: (modelId: string) => modelId, -})); - -vi.mock("@/chat/prompt", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - buildSystemPrompt: () => "System prompt", - }; -}); - -vi.mock("@/chat/runtime/dev-agent-trace", () => ({ - shouldEmitDevAgentTrace: () => false, -})); - -vi.mock("@/chat/runtime-metadata", () => ({ - getRuntimeMetadata: () => ({ version: "test" }), -})); - -vi.mock("@/chat/capabilities/factory", () => ({ - createSkillCapabilityRuntime: () => ({ - getTurnHeaderTransforms: () => undefined, - getTurnEnv: () => undefined, - }), - getUserTokenStore: () => ({ - get: async () => undefined, - set: async () => undefined, - delete: async () => undefined, - }), -})); - -vi.mock("@/chat/capabilities/jr-rpc-command", () => ({ - maybeExecuteJrRpcCustomCommand: async () => ({ handled: false }), -})); - -vi.mock("@/chat/sandbox/sandbox", () => ({ - createSandboxExecutor: () => ({ - configureSkills: () => undefined, - createSandbox: async () => ({}), - canExecute: (toolName: string) => toolName === "bash", - execute: async () => ({ - result: { - ok: true, - exit_code: 0, - duration_ms: 1, - stdout: `${JSON.stringify( - { - credential_unavailable: true, - oauth_started: true, - provider: "eval-oauth", - private_delivery_sent: true, - message: - "I need to connect your Eval-oauth account first. I've sent you a private authorization link.", - }, - null, - 2, - )}\n`, - stderr: "", - stdout_truncated: false, - stderr_truncated: false, - }, - }), - getSandboxId: () => "sandbox-test", - getDependencyProfileHash: () => "hash-test", - dispose: async () => undefined, - }), -})); - -vi.mock("@/chat/plugins/registry", () => ({ - getPluginMcpProviders: () => [], - getPluginProviders: () => [], -})); - -vi.mock("@/chat/skills", () => ({ - discoverSkills: async () => [], - findSkillByName: () => null, - loadSkillsByName: async () => [], - parseSkillInvocation: () => null, -})); - -import { generateAssistantReply } from "@/chat/respond"; - -describe("generateAssistantReply generic OAuth start fallback", () => { - it("uses the oauth-started message when the model emits no assistant text", async () => { - const reply = await generateAssistantReply( - "Connect the demo account, then tell me what budget deadline I mentioned earlier.", - { - requester: { userId: "U_TEST" }, - correlation: { - channelId: "C_TEST", - threadTs: "1700000000.0001", - requesterId: "U_TEST", - }, - }, - ); - - expect(reply.text).toBe( - "I need to connect your Eval-oauth account first. I've sent you a private authorization link.", - ); - expect(reply.diagnostics.outcome).toBe("success"); - expect(reply.diagnostics.usedPrimaryText).toBe(false); - expect(reply.diagnostics.toolResultCount).toBe(1); - expect(reply.diagnostics.toolErrorCount).toBe(0); - }); -}); diff --git a/packages/junior/tests/unit/tool-result-oauth.test.ts b/packages/junior/tests/unit/tool-result-oauth.test.ts new file mode 100644 index 00000000..f053f438 --- /dev/null +++ b/packages/junior/tests/unit/tool-result-oauth.test.ts @@ -0,0 +1,48 @@ +import { describe, expect, it } from "vitest"; +import { extractOAuthStartedMessageFromToolResults } from "@/chat/tool-result-oauth"; + +describe("tool result oauth parsing", () => { + it("extracts oauth_started messages from bash tool results", () => { + const message = extractOAuthStartedMessageFromToolResults([ + { + role: "toolResult", + toolName: "bash", + isError: false, + stdout: JSON.stringify({ + credential_unavailable: true, + oauth_started: true, + provider: "eval-oauth", + message: + "I need to connect your Eval-oauth account first. I've sent you a private authorization link.", + }), + }, + ]); + + expect(message).toBe( + "I need to connect your Eval-oauth account first. I've sent you a private authorization link.", + ); + }); + + it("ignores non-bash and error tool results", () => { + const message = extractOAuthStartedMessageFromToolResults([ + { + toolName: "webSearch", + isError: false, + stdout: JSON.stringify({ + oauth_started: true, + message: "wrong tool", + }), + }, + { + toolName: "bash", + isError: true, + stdout: JSON.stringify({ + oauth_started: true, + message: "errored tool", + }), + }, + ]); + + expect(message).toBeUndefined(); + }); +}); From 1c7f31f19fd8d6a732ff0ccdfba14ad42f767a5d Mon Sep 17 00:00:00 2001 From: David Cramer Date: Fri, 20 Mar 2026 17:56:07 -0700 Subject: [PATCH 25/28] fix(oauth): Reuse pending MCP auth sessions Persist the base MCP auth session as soon as the client provider is created so raw authorization challenges can patch a real session instead of failing on unknown state. Reuse the same auth session ID when the same provider is retried for the same turn. This keeps pending OAuth links stable across retries instead of minting a fresh state token each time. Co-Authored-By: GPT-5 --- packages/junior/src/chat/mcp/oauth.ts | 44 ++++++- packages/junior/tests/unit/mcp/oauth.test.ts | 117 +++++++++++++++++++ 2 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 packages/junior/tests/unit/mcp/oauth.test.ts diff --git a/packages/junior/src/chat/mcp/oauth.ts b/packages/junior/src/chat/mcp/oauth.ts index 05f6ba39..fac78137 100644 --- a/packages/junior/src/chat/mcp/oauth.ts +++ b/packages/junior/src/chat/mcp/oauth.ts @@ -4,7 +4,12 @@ import { resolveBaseUrl } from "@/chat/oauth-flow"; import { getPluginDefinition } from "@/chat/plugins/registry"; import type { PluginDefinition } from "@/chat/plugins/types"; import type { ThreadArtifactsState } from "@/chat/slack-actions/types"; -import { getMcpAuthSession, type McpAuthSessionState } from "./auth-store"; +import { + getLatestMcpAuthSessionForUserProvider, + getMcpAuthSession, + putMcpAuthSession, + type McpAuthSessionState, +} from "./auth-store"; import { StateBackedMcpOAuthClientProvider } from "./oauth-provider"; export function getMcpOAuthCallbackPath(provider: string): string { @@ -40,8 +45,43 @@ export async function createMcpOAuthClientProvider(input: { ); } + const existingSession = await getLatestMcpAuthSessionForUserProvider( + input.userId, + input.provider, + ); + const reusableSession = + existingSession && + existingSession.conversationId === input.conversationId && + existingSession.sessionId === input.sessionId + ? existingSession + : undefined; + const now = Date.now(); + const authSessionId = reusableSession?.authSessionId ?? randomUUID(); + + await putMcpAuthSession({ + authSessionId, + provider: input.provider, + userId: input.userId, + conversationId: input.conversationId, + sessionId: input.sessionId, + userMessage: input.userMessage, + ...(input.channelId ? { channelId: input.channelId } : {}), + ...(input.threadTs ? { threadTs: input.threadTs } : {}), + ...(input.toolChannelId ? { toolChannelId: input.toolChannelId } : {}), + ...(input.configuration ? { configuration: input.configuration } : {}), + ...(input.artifactState ? { artifactState: input.artifactState } : {}), + ...(reusableSession?.authorizationUrl + ? { authorizationUrl: reusableSession.authorizationUrl } + : {}), + ...(reusableSession?.codeVerifier + ? { codeVerifier: reusableSession.codeVerifier } + : {}), + createdAtMs: reusableSession?.createdAtMs ?? now, + updatedAtMs: now, + }); + return new StateBackedMcpOAuthClientProvider( - randomUUID(), + authSessionId, `${baseUrl}${getMcpOAuthCallbackPath(input.provider)}`, { provider: input.provider, diff --git a/packages/junior/tests/unit/mcp/oauth.test.ts b/packages/junior/tests/unit/mcp/oauth.test.ts new file mode 100644 index 00000000..0b0a6056 --- /dev/null +++ b/packages/junior/tests/unit/mcp/oauth.test.ts @@ -0,0 +1,117 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +const ORIGINAL_ENV = { ...process.env }; + +function buildPlugin() { + return { + dir: "/tmp/plugins/demo", + skillsDir: "/tmp/plugins/demo/skills", + manifest: { + name: "demo", + description: "Demo plugin", + capabilities: [], + configKeys: [], + mcp: { + transport: "http" as const, + url: "https://mcp.example.com", + }, + }, + }; +} + +describe("createMcpOAuthClientProvider", () => { + beforeEach(async () => { + process.env = { + ...ORIGINAL_ENV, + JUNIOR_BASE_URL: "https://junior.example.com", + JUNIOR_STATE_ADAPTER: "memory", + }; + vi.resetModules(); + vi.doMock("@/chat/plugins/registry", () => ({ + getPluginDefinition: (provider: string) => + provider === "demo" ? buildPlugin() : undefined, + })); + + const { disconnectStateAdapter } = await import("@/chat/state"); + await disconnectStateAdapter(); + }); + + afterEach(async () => { + const { disconnectStateAdapter } = await import("@/chat/state"); + await disconnectStateAdapter(); + vi.unmock("@/chat/plugins/registry"); + vi.resetModules(); + process.env = { ...ORIGINAL_ENV }; + }); + + it("persists and reuses the pending auth session for the same turn", async () => { + const { getMcpAuthSession, patchMcpAuthSession } = + await import("@/chat/mcp/auth-store"); + const { createMcpOAuthClientProvider } = await import("@/chat/mcp/oauth"); + + const firstProvider = await createMcpOAuthClientProvider({ + provider: "demo", + conversationId: "conversation-1", + sessionId: "turn-1", + userId: "U123", + userMessage: "use /demo", + channelId: "C123", + threadTs: "1712345.0001", + configuration: { region: "us" }, + }); + + const initialSession = await getMcpAuthSession(firstProvider.authSessionId); + expect(initialSession).toMatchObject({ + authSessionId: firstProvider.authSessionId, + provider: "demo", + userId: "U123", + conversationId: "conversation-1", + sessionId: "turn-1", + userMessage: "use /demo", + channelId: "C123", + threadTs: "1712345.0001", + configuration: { region: "us" }, + }); + + await patchMcpAuthSession(firstProvider.authSessionId, { + authorizationUrl: "https://auth.example.com/start", + codeVerifier: "code-verifier", + }); + + const reusedProvider = await createMcpOAuthClientProvider({ + provider: "demo", + conversationId: "conversation-1", + sessionId: "turn-1", + userId: "U123", + userMessage: "use /demo", + channelId: "C123", + threadTs: "1712345.0001", + toolChannelId: "C999", + configuration: { region: "eu" }, + artifactState: { assistantContextChannelId: "C999" }, + }); + + expect(reusedProvider.authSessionId).toBe(firstProvider.authSessionId); + + const reusedSession = await getMcpAuthSession(reusedProvider.authSessionId); + expect(reusedSession).toMatchObject({ + authSessionId: firstProvider.authSessionId, + provider: "demo", + userId: "U123", + conversationId: "conversation-1", + sessionId: "turn-1", + userMessage: "use /demo", + channelId: "C123", + threadTs: "1712345.0001", + toolChannelId: "C999", + configuration: { region: "eu" }, + artifactState: { assistantContextChannelId: "C999" }, + authorizationUrl: "https://auth.example.com/start", + codeVerifier: "code-verifier", + }); + expect(reusedSession?.createdAtMs).toBe(initialSession?.createdAtMs); + expect(reusedSession?.updatedAtMs).toBeGreaterThanOrEqual( + initialSession?.updatedAtMs ?? 0, + ); + }); +}); From e91b6dcf8fbbfb064589d6a53d1b72271a8640a9 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Fri, 20 Mar 2026 18:01:46 -0700 Subject: [PATCH 26/28] fix(mcp): Avoid duplicate auth activation retries Mark providers as auth-pending after a handled MCP authorization challenge so the same turn does not reconnect or rediscover tools again. Drop the cached client wrapper at that point as well, since the provider is no longer usable until the resumed turn builds a fresh manager. Co-Authored-By: GPT-5 --- packages/junior/src/chat/mcp/tool-manager.ts | 19 ++++++++++++++++--- .../tests/unit/mcp/tool-manager.test.ts | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/junior/src/chat/mcp/tool-manager.ts b/packages/junior/src/chat/mcp/tool-manager.ts index cba2831c..15e49fad 100644 --- a/packages/junior/src/chat/mcp/tool-manager.ts +++ b/packages/junior/src/chat/mcp/tool-manager.ts @@ -170,6 +170,7 @@ interface ManagedMcpTool extends ManagedMcpToolDescriptor { export class McpToolManager { private readonly pluginsByProvider = new Map(); private readonly activeProviders = new Set(); + private readonly authorizationPendingProviders = new Set(); private readonly clientsByProvider = new Map(); private readonly toolsByProvider = new Map(); @@ -202,6 +203,9 @@ export class McpToolManager { if (this.activeProviders.has(provider)) { return false; } + if (this.authorizationPendingProviders.has(provider)) { + return false; + } const plugin = this.pluginsByProvider.get(provider); if (!plugin?.manifest.mcp) { @@ -242,6 +246,7 @@ export class McpToolManager { this.clientsByProvider.clear(); this.toolsByProvider.clear(); this.activeProviders.clear(); + this.authorizationPendingProviders.clear(); if (firstError) { throw firstError; @@ -414,9 +419,17 @@ export class McpToolManager { return false; } - return ( - (await this.options.onAuthorizationRequired(provider, error)) === true - ); + const handled = + (await this.options.onAuthorizationRequired(provider, error)) === true; + if (!handled) { + return false; + } + + this.authorizationPendingProviders.add(provider); + this.clientsByProvider.delete(provider); + this.toolsByProvider.delete(provider); + this.activeProviders.delete(provider); + return true; } private getResolvedActiveTools( diff --git a/packages/junior/tests/unit/mcp/tool-manager.test.ts b/packages/junior/tests/unit/mcp/tool-manager.test.ts index 5611f7bf..342260d6 100644 --- a/packages/junior/tests/unit/mcp/tool-manager.test.ts +++ b/packages/junior/tests/unit/mcp/tool-manager.test.ts @@ -249,6 +249,24 @@ describe("McpToolManager", () => { expect(manager.getActiveProviders()).toEqual([]); }); + it("does not retry activation for a provider already parked for auth", async () => { + const plugin = buildPlugin(); + onAuthorizationRequiredMock.mockResolvedValueOnce(true); + const manager = new McpToolManager([plugin], { + onAuthorizationRequired: onAuthorizationRequiredMock, + }); + listToolsMock.mockRejectedValueOnce( + new McpAuthorizationRequiredError("demo", "Discovery auth required"), + ); + + await expect(manager.activateProvider("demo")).resolves.toBe(false); + await expect(manager.activateProvider("demo")).resolves.toBe(false); + + expect(onAuthorizationRequiredMock).toHaveBeenCalledTimes(1); + expect(listToolsMock).toHaveBeenCalledTimes(1); + expect(clientOptions).toHaveLength(1); + }); + it("parks handled MCP authorization challenges during initial client setup", async () => { const plugin = buildPlugin(); const authError = new McpAuthorizationRequiredError( From 31013872b819e78826969d9f5a6d88fe62d18911 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Fri, 20 Mar 2026 18:14:41 -0700 Subject: [PATCH 27/28] test(msw): Match unhandled request contract Align the Slack MSW integration assertion with the shared unhandled-request message that now covers Slack and eval provider hosts alike. This keeps the test focused on the actual contract enforced by the server instead of a stale Slack-specific string. Co-Authored-By: GPT-5 --- packages/junior/tests/integration/slack-server.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/junior/tests/integration/slack-server.test.ts b/packages/junior/tests/integration/slack-server.test.ts index 982b6ce6..c56e238a 100644 --- a/packages/junior/tests/integration/slack-server.test.ts +++ b/packages/junior/tests/integration/slack-server.test.ts @@ -5,19 +5,21 @@ describe("Slack MSW server", () => { const response = await fetch("https://slack.com/does-not-exist"); expect(response.status).toBe(500); const payload = (await response.json()) as { message?: string }; - expect(payload.message).toContain("[MSW] Unhandled Slack request"); + expect(payload.message).toContain( + "[MSW] Unhandled mocked request: GET https://slack.com/does-not-exist", + ); }); it("returns default mock responses for supported Slack API methods", async () => { const response = await fetch("https://slack.com/api/chat.postMessage", { method: "POST", headers: { - "content-type": "application/x-www-form-urlencoded" + "content-type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ channel: "C_TEST", - text: "hello" - }).toString() + text: "hello", + }).toString(), }); expect(response.ok).toBe(true); From b06748f2e468dd848dac7368be2aa546f52df86d Mon Sep 17 00:00:00 2001 From: David Cramer Date: Fri, 20 Mar 2026 18:26:07 -0700 Subject: [PATCH 28/28] fix(mcp): Preserve raw transport 401 failures Treat only the SDK UnauthorizedError path as an MCP auth challenge. A bare StreamableHTTPError 401 means the transport still failed after the SDK already attempted auth, so reclassifying it as resumable OAuth could crash later when no authorization URL exists. Co-Authored-By: GPT-5 --- packages/junior/src/chat/mcp/client.ts | 6 ------ packages/junior/tests/unit/mcp/client.test.ts | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/junior/src/chat/mcp/client.ts b/packages/junior/src/chat/mcp/client.ts index d980e830..d73ab4df 100644 --- a/packages/junior/src/chat/mcp/client.ts +++ b/packages/junior/src/chat/mcp/client.ts @@ -177,12 +177,6 @@ export class PluginMcpClient { `MCP authorization required for plugin "${this.plugin.manifest.name}"`, ); } - if (error instanceof StreamableHTTPError && error.code === 401) { - throw new McpAuthorizationRequiredError( - this.plugin.manifest.name, - `MCP authorization required for plugin "${this.plugin.manifest.name}"`, - ); - } throw error; } } diff --git a/packages/junior/tests/unit/mcp/client.test.ts b/packages/junior/tests/unit/mcp/client.test.ts index da642820..14b0fa6c 100644 --- a/packages/junior/tests/unit/mcp/client.test.ts +++ b/packages/junior/tests/unit/mcp/client.test.ts @@ -187,6 +187,24 @@ describe("PluginMcpClient", () => { ); }); + it("does not relabel raw 401 transport failures as auth challenges", async () => { + const authProvider = buildAuthProvider(); + authProvider.getMcpServerSessionId.mockResolvedValue(undefined); + authProvider.saveMcpServerSessionId.mockResolvedValue(undefined); + connectMock.mockRejectedValueOnce( + new StreamableHTTPError( + 401, + "Server returned 401 after successful authentication", + ), + ); + + const client = new PluginMcpClient(buildPlugin(), { authProvider }); + + await expect(client.listTools()).rejects.toBeInstanceOf( + StreamableHTTPError, + ); + }); + it("clears a stale MCP server session and retries once with a fresh transport", async () => { const authProvider = buildAuthProvider(); authProvider.getMcpServerSessionId