feat: improve mcp edge things

pull/715/head
Travis Fischer 2025-06-12 03:29:26 +07:00
rodzic f720323b5e
commit 4a6275da6c
11 zmienionych plików z 263 dodań i 51 usunięć

Wyświetl plik

@ -1,3 +1,4 @@
import { pick } from '@agentic/platform-core'
import { Client as McpClient } from '@modelcontextprotocol/sdk/client/index.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
@ -36,10 +37,16 @@ for (const [i, fixtureSuite] of fixtureSuites.entries()) {
content: expectedContent,
structuredContent: expectedStructuredContent,
_meta: expectedMeta,
_agenticMeta: expectedAgenticMeta,
_agenticMetaHeaders: expectedAgenticMetaHeaders,
validate
} = fixture.response ?? {}
const snapshot =
fixture.response?.snapshot ?? fixtureSuite.snapshot ?? !isError
const expectedSnapshot =
fixture.response?.snapshot ?? fixtureSuite.snapshot ?? false
const expectedStableSnapshot =
fixture.response?.stableSnapshot ??
fixtureSuite.stableSnapshot ??
!isError
const debugFixture = !!(
fixture.debug ??
fixtureSuite.debug ??
@ -93,15 +100,50 @@ for (const [i, fixtureSuite] of fixtureSuites.entries()) {
if (expectedMeta) {
expect(result._meta).toBeDefined()
expect(typeof result._meta).toEqual('object')
expect(!Array.isArray(result._meta)).toBeTruthy()
for (const [key, value] of Object.entries(expectedMeta)) {
expect(result._meta![key]).toEqual(value)
}
}
if (expectedAgenticMeta) {
expect(result._meta).toBeDefined()
expect(result._meta?.agentic).toBeDefined()
expect(typeof result._meta?.agentic).toEqual('object')
expect(!Array.isArray(result._meta?.agentic)).toBeTruthy()
for (const [key, value] of Object.entries(expectedAgenticMeta)) {
expect((result._meta!.agentic as any)[key]).toEqual(value)
}
}
if (snapshot) {
if (expectedAgenticMetaHeaders) {
expect(result._meta).toBeDefined()
expect(result._meta?.agentic).toBeDefined()
expect(typeof result._meta?.agentic).toEqual('object')
expect(!Array.isArray(result._meta?.agentic)).toBeTruthy()
expect(typeof (result._meta?.agentic as any)?.headers).toEqual(
'object'
)
expect(
!Array.isArray((result._meta?.agentic as any)?.headers)
).toBeTruthy()
for (const [key, value] of Object.entries(
expectedAgenticMetaHeaders
)) {
expect((result._meta!.agentic as any).headers[key]).toEqual(value)
}
}
if (expectedSnapshot) {
expect(result).toMatchSnapshot()
}
if (expectedStableSnapshot) {
expect(
pick(result, 'content', 'structuredContent', 'isError')
).toMatchSnapshot()
}
if (validate) {
await Promise.resolve(validate(result))
}

Wyświetl plik

@ -19,9 +19,13 @@ export type MCPE2ETestFixture = {
content?: Array<Record<string, unknown>>
structuredContent?: any
_meta?: Record<string, unknown>
_agenticMeta?: Record<string, unknown>
_agenticMetaHeaders?: Record<string, unknown>
validate?: (result: any) => void | Promise<void>
/** @default true */
/** @default undefined */
snapshot?: boolean
/** @default true */
stableSnapshot?: boolean
}
}
@ -42,8 +46,17 @@ export type MCPE2ETestFixtureSuite = {
/** @default false */
debug?: boolean
/** @default undefined */
/**
* Not used by default because the result `_meta.agentic` contains some
* metadata which may not be stable across test runs such as `cacheStatus`
* and `headers`.
*
* @default false
*/
snapshot?: boolean
/** @default undefined */
stableSnapshot?: boolean
}
const now = Date.now()
@ -94,7 +107,7 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [
{
title: 'Basic MCP => MCP "echo" tool call success',
path: '@dev/test-basic-mcp/mcp',
snapshot: false,
stableSnapshot: false,
fixtures: [
{
request: {
@ -141,8 +154,6 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [
{
title: 'Basic MCP => MCP "echo" tool call errors',
path: '@dev/test-basic-openapi/mcp',
snapshot: false,
only: true,
fixtures: [
{
request: {
@ -154,7 +165,10 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [
}
},
response: {
isError: true
isError: true,
_agenticMeta: {
status: 400
}
}
}
]

Wyświetl plik

@ -45,6 +45,7 @@
"hono": "catalog:",
"ky": "catalog:",
"plur": "catalog:",
"sort-keys": "^5.1.0",
"stripe": "catalog:",
"type-fest": "catalog:"
},

Wyświetl plik

@ -1,5 +1,5 @@
import type { AdminDeployment, PricingPlan } from '@agentic/platform-types'
import { assert, getRateLimitHeaders, pruneEmpty } from '@agentic/platform-core'
import { assert, getRateLimitHeaders } from '@agentic/platform-core'
import { parseDeploymentIdentifier } from '@agentic/platform-validators'
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import {
@ -19,6 +19,7 @@ import { handleMcpToolCallError } from './handle-mcp-tool-call-error'
import { recordToolCallUsage } from './record-tool-call-usage'
import { resolveOriginToolCall } from './resolve-origin-tool-call'
import { transformHttpResponseToMcpToolCallResponse } from './transform-http-response-to-mcp-tool-call-response'
import { createAgenticMcpMetadata } from './utils'
export class DurableMcpServerBase extends McpAgent<
RawEnv,
@ -119,8 +120,8 @@ export class DurableMcpServerBase extends McpAgent<
return toolCallResponse
} catch (err: unknown) {
// Gracefully handle tool call exceptions, whether they're thrown by the
// origin or internally by the gateway.
// Gracefully handle tool call exceptions, whether they were thrown by
// the origin server or internally by the gateway.
toolCallResponse = handleMcpToolCallError(err, {
toolName,
env: this.env
@ -133,22 +134,18 @@ export class DurableMcpServerBase extends McpAgent<
// Augment the MCP tool call response with agentic metadata, which
// makes it easier to debug tool calls and adds some much-needed HTTP
// header-like functionality to tool call responses.
toolCallResponse._meta = {
...toolCallResponse._meta,
agentic: pruneEmpty({
...(toolCallResponse._meta?.agentic as any),
toolCallResponse._meta = createAgenticMcpMetadata(
{
deploymentId: deployment.id,
consumerId: consumer?.id,
cacheStatus: resolvedOriginToolCallResult?.cacheStatus,
toolName,
headers: {
...(toolCallResponse._meta?.agentic as any)?.headers,
...getRateLimitHeaders(
resolvedOriginToolCallResult?.rateLimitResult
)
}
})
}
cacheStatus: resolvedOriginToolCallResult?.cacheStatus,
headers: getRateLimitHeaders(
resolvedOriginToolCallResult?.rateLimitResult
)
},
toolCallResponse._meta
)
// Record tool call usage, whether the call was successful or not.
recordToolCallUsage({

Wyświetl plik

@ -28,6 +28,12 @@ export function handleMcpToolCallError(
let status: ContentfulStatusCode = 500
const res: McpToolCallResponse = {
_meta: {
agentic: {
toolName,
headers: {}
}
},
isError: true,
content: [
{
@ -45,7 +51,7 @@ export function handleMcpToolCallError(
// is a subclass of `HttpError`.
if (err.headers) {
for (const [key, value] of Object.entries(err.headers)) {
res._meta![key] = value
;(res._meta!.agentic as any).headers[key] = value
}
}
} else if (err instanceof HTTPException) {
@ -76,10 +82,10 @@ export function handleMcpToolCallError(
}
} else {
// eslint-disable-next-line no-console
console.warn(`mcp tool call "${toolName}" warning`, status, message, err)
console.warn(`mcp tool call "${toolName}" warning`, status, err)
}
res._meta!.status = status
;(res._meta!.agentic as any).status = status
res.content = [
{
type: 'text',

Wyświetl plik

@ -1,6 +1,7 @@
import { expect, test } from 'vitest'
import {
createAgenticMcpMetadata,
isCacheControlPubliclyCacheable,
isRequestPubliclyCacheable
} from './utils'
@ -77,3 +78,18 @@ test('isCacheControlPubliclyCacheable false', () => {
isCacheControlPubliclyCacheable('private, max-age=3600, must-revalidate')
).toBe(false)
})
test('createAgenticMcpMetadata', () => {
expect(
// Test the stringified version because we want to test the order of the
// keys.
JSON.stringify(
createAgenticMcpMetadata({
deploymentId: '123',
consumerId: '456',
toolName: 'test',
cacheStatus: 'HIT'
})
)
).toMatchSnapshot()
})

Wyświetl plik

@ -1,3 +1,6 @@
import { pruneEmpty } from '@agentic/platform-core'
import sortKeys from 'sort-keys'
export function isRequestPubliclyCacheable(request: Request): boolean {
const pragma = request.headers.get('pragma')
if (pragma === 'no-cache') {
@ -36,3 +39,56 @@ export function isCacheControlPubliclyCacheable(
return true
}
const agenticMcpMetadataFieldOrder: string[] = [
'deploymentId',
'consumerId',
'toolName',
'status',
'cacheStatus',
'headers'
]
const agenticMcpMetadataFieldsOrderMap = Object.fromEntries(
agenticMcpMetadataFieldOrder.map((f, i) => [f, i])
)
function agenticMcpMetadataFieldComparator(a: string, b: string): number {
const aIndex = agenticMcpMetadataFieldsOrderMap[a] ?? Infinity
const bIndex = agenticMcpMetadataFieldsOrderMap[b] ?? Infinity
return aIndex - bIndex
}
/**
* Sanitizes agentic MCP metadata by sorting the keys and pruning empty values.
*/
export function createAgenticMcpMetadata(
metadata: {
deploymentId: string
consumerId?: string
toolName?: string
status?: number
cacheStatus?: string
headers?: Record<string, any>
},
existingMetadata?: Record<string, any>
): Record<string, any> {
const rawAgenticMcpMetadata = pruneEmpty({
...existingMetadata?.agentic,
...metadata,
headers: {
...existingMetadata?.agentic?.headers,
...metadata.headers
}
})
const agentic = sortKeys(rawAgenticMcpMetadata, {
compare: agenticMcpMetadataFieldComparator
})
return {
...existingMetadata,
agentic
}
}

Wyświetl plik

@ -1693,6 +1693,15 @@ exports[`getToolsFromOpenAPISpec > remote spec https://agentic-platform-fixtures
"path": "/pure",
"tags": undefined,
},
"strict_additional_properties": {
"method": "post",
"operationId": "strictAdditionalProperties",
"parameterSources": {
"foo": "body",
},
"path": "/strict-additional-properties",
"tags": undefined,
},
"unpure_marked_pure": {
"method": "post",
"operationId": "unpure_marked_pure",
@ -1908,6 +1917,32 @@ exports[`getToolsFromOpenAPISpec > remote spec https://agentic-platform-fixtures
"type": "object",
},
},
{
"description": "Echoes the request body only allowing a single "foo" field.",
"inputSchema": {
"properties": {
"foo": {
"type": "string",
},
},
"required": [
"foo",
],
"type": "object",
},
"name": "strict_additional_properties",
"outputSchema": {
"properties": {
"foo": {
"type": "string",
},
},
"required": [
"foo",
],
"type": "object",
},
},
],
}
`;

Wyświetl plik

@ -22820,6 +22820,49 @@ exports[`validateOpenAPISpec > remote spec https://agentic-platform-fixtures-eve
},
},
},
"/strict-additional-properties": {
"post": {
"description": "Echoes the request body only allowing a single "foo" field.",
"operationId": "strictAdditionalProperties",
"requestBody": {
"content": {
"application/json": {
"schema": {
"properties": {
"foo": {
"type": "string",
},
},
"required": [
"foo",
],
"type": "object",
},
},
},
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"properties": {
"foo": {
"type": "string",
},
},
"required": [
"foo",
],
"type": "object",
},
},
},
"description": "Echoed request body",
},
},
},
},
"/unpure-marked-pure": {
"post": {
"description": "Unpure tool marked pure",

Wyświetl plik

@ -56,12 +56,14 @@ exports[`loadAgenticConfig > basic-openapi 1`] = `
],
"toolConfigs": [
{
"additionalProperties": true,
"enabled": true,
"name": "get_posts",
"pure": true,
"reportUsage": true,
},
{
"additionalProperties": true,
"enabled": true,
"name": "get_post",
"pure": true,
@ -135,7 +137,7 @@ exports[`loadAgenticConfig > everything-openapi 1`] = `
"name": "test-everything-openapi",
"originAdapter": {
"location": "external",
"spec": "{"openapi":"3.1.0","info":{"title":"OpenAPI server everything","description":"OpenAPI kitchen sink server meant for testing Agentic's origin OpenAPI adapter and ToolConfig features.","version":"0.1.0"},"components":{"schemas":{"User":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"}},"required":["id","name","email"]}},"parameters":{}},"paths":{"/health":{"get":{"description":"Check if the server is healthy","operationId":"healthCheck","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}}}}}}},"/users/{userId}":{"get":{"description":"Gets a user","tags":["users"],"operationId":"getUser","parameters":[{"schema":{"type":"string"},"required":true,"description":"User ID","name":"userId","in":"path"}],"responses":{"200":{"description":"A user object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}}}}},"/disabled-tool":{"get":{"description":"Disabled tool","operationId":"disabledTool","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}}}}}}},"/disabled-for-free-plan-tool":{"get":{"description":"Disabled for free plan tool","operationId":"disabledForFreePlanTool","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}}}}}}},"/echo":{"post":{"description":"Echoes the request body","operationId":"echo","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/pure":{"post":{"description":"Pure tool","operationId":"pure","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/unpure-marked-pure":{"post":{"description":"Unpure tool marked pure","operationId":"unpure_marked_pure","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body with current timestamp to not be pure","content":{"application/json":{"schema":{"type":"object","properties":{"now":{"type":"number"}},"required":["now"]}}}}}}},"/custom-cache-control-tool":{"post":{"description":"Custom cache control tool","operationId":"customCacheControlTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/no-store-cache-control-tool":{"post":{"description":"No store cache control tool","operationId":"noStoreCacheControlTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/no-cache-cache-control-tool":{"post":{"description":"No cache cache control tool","operationId":"noCacheCacheControlTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/custom-rate-limit-tool":{"post":{"description":"Custom rate limit tool","operationId":"customRateLimitTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/disabled-rate-limit-tool":{"post":{"description":"Disabled rate limit tool","operationId":"disabledRateLimitTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}}},"webhooks":{}}",
"spec": "{"openapi":"3.1.0","info":{"title":"OpenAPI server everything","description":"OpenAPI kitchen sink server meant for testing Agentic's origin OpenAPI adapter and ToolConfig features.","version":"0.1.0"},"components":{"schemas":{"User":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"}},"required":["id","name","email"]}},"parameters":{}},"paths":{"/health":{"get":{"description":"Check if the server is healthy","operationId":"healthCheck","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}}}}}}},"/users/{userId}":{"get":{"description":"Gets a user","tags":["users"],"operationId":"getUser","parameters":[{"schema":{"type":"string"},"required":true,"description":"User ID","name":"userId","in":"path"}],"responses":{"200":{"description":"A user object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}}}}},"/disabled-tool":{"get":{"description":"Disabled tool","operationId":"disabledTool","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}}}}}}},"/disabled-for-free-plan-tool":{"get":{"description":"Disabled for free plan tool","operationId":"disabledForFreePlanTool","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}}}}}}},"/echo":{"post":{"description":"Echoes the request body","operationId":"echo","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/pure":{"post":{"description":"Pure tool","operationId":"pure","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/unpure-marked-pure":{"post":{"description":"Unpure tool marked pure","operationId":"unpure_marked_pure","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body with current timestamp to not be pure","content":{"application/json":{"schema":{"type":"object","properties":{"now":{"type":"number"}},"required":["now"]}}}}}}},"/custom-cache-control-tool":{"post":{"description":"Custom cache control tool","operationId":"customCacheControlTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/no-store-cache-control-tool":{"post":{"description":"No store cache control tool","operationId":"noStoreCacheControlTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/no-cache-cache-control-tool":{"post":{"description":"No cache cache control tool","operationId":"noCacheCacheControlTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/custom-rate-limit-tool":{"post":{"description":"Custom rate limit tool","operationId":"customRateLimitTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/disabled-rate-limit-tool":{"post":{"description":"Disabled rate limit tool","operationId":"disabledRateLimitTool","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/strict-additional-properties":{"post":{"description":"Echoes the request body only allowing a single \\"foo\\" field.","operationId":"strictAdditionalProperties","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"foo":{"type":"string"}},"required":["foo"]}}}},"responses":{"200":{"description":"Echoed request body","content":{"application/json":{"schema":{"type":"object","properties":{"foo":{"type":"string"}},"required":["foo"]}}}}}}}},"webhooks":{}}",
"type": "openapi",
},
"originUrl": "https://agentic-platform-fixtures-everything.onrender.com",
@ -157,6 +159,7 @@ exports[`loadAgenticConfig > everything-openapi 1`] = `
],
"toolConfigs": [
{
"additionalProperties": true,
"enabled": true,
"name": "get_user",
"pricingPlanOverridesMap": {
@ -170,12 +173,14 @@ exports[`loadAgenticConfig > everything-openapi 1`] = `
"reportUsage": true,
},
{
"additionalProperties": true,
"enabled": false,
"name": "disabled_tool",
"pure": false,
"reportUsage": true,
},
{
"additionalProperties": true,
"enabled": true,
"name": "disabled_for_free_plan_tool",
"pricingPlanOverridesMap": {
@ -187,18 +192,21 @@ exports[`loadAgenticConfig > everything-openapi 1`] = `
"reportUsage": true,
},
{
"additionalProperties": true,
"enabled": true,
"name": "pure",
"pure": true,
"reportUsage": true,
},
{
"additionalProperties": true,
"enabled": true,
"name": "unpure_marked_pure",
"pure": true,
"reportUsage": true,
},
{
"additionalProperties": true,
"cacheControl": "public, max-age=7200, s-maxage=7200, stale-while-revalidate=3600",
"enabled": true,
"name": "custom_cache_control_tool",
@ -206,6 +214,7 @@ exports[`loadAgenticConfig > everything-openapi 1`] = `
"reportUsage": true,
},
{
"additionalProperties": true,
"cacheControl": "no-cache",
"enabled": true,
"name": "no_cache_cache_control_tool",
@ -213,6 +222,7 @@ exports[`loadAgenticConfig > everything-openapi 1`] = `
"reportUsage": true,
},
{
"additionalProperties": true,
"cacheControl": "no-store",
"enabled": true,
"name": "no_store_cache_control_tool",
@ -220,6 +230,7 @@ exports[`loadAgenticConfig > everything-openapi 1`] = `
"reportUsage": true,
},
{
"additionalProperties": true,
"enabled": true,
"name": "custom_rate_limit_tool",
"pure": false,
@ -231,12 +242,20 @@ exports[`loadAgenticConfig > everything-openapi 1`] = `
"reportUsage": true,
},
{
"additionalProperties": true,
"enabled": true,
"name": "disabled_rate_limit_tool",
"pure": false,
"rateLimit": null,
"reportUsage": true,
},
{
"additionalProperties": false,
"enabled": true,
"name": "strict_additional_properties",
"pure": false,
"reportUsage": true,
},
],
"version": undefined,
}

Wyświetl plik

@ -451,6 +451,9 @@ importers:
plur:
specifier: 'catalog:'
version: 5.1.0
sort-keys:
specifier: ^5.1.0
version: 5.1.0
stripe:
specifier: 'catalog:'
version: 18.2.1(@types/node@22.15.29)
@ -1260,12 +1263,6 @@ packages:
cpu: [x64]
os: [win32]
'@eslint-community/eslint-utils@4.6.1':
resolution: {integrity: sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
'@eslint-community/eslint-utils@4.7.0':
resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -5286,10 +5283,6 @@ packages:
tinyexec@0.3.2:
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
tinyglobby@0.2.13:
resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
engines: {node: '>=12.0.0'}
tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'}
@ -6124,11 +6117,6 @@ snapshots:
'@esbuild/win32-x64@0.25.4':
optional: true
'@eslint-community/eslint-utils@4.6.1(eslint@9.28.0(jiti@2.4.2))':
dependencies:
eslint: 9.28.0(jiti@2.4.2)
eslint-visitor-keys: 3.4.3
'@eslint-community/eslint-utils@4.7.0(eslint@9.28.0(jiti@2.4.2))':
dependencies:
eslint: 9.28.0(jiti@2.4.2)
@ -8452,7 +8440,7 @@ snapshots:
eslint@9.28.0(jiti@2.4.2):
dependencies:
'@eslint-community/eslint-utils': 4.6.1(eslint@9.28.0(jiti@2.4.2))
'@eslint-community/eslint-utils': 4.7.0(eslint@9.28.0(jiti@2.4.2))
'@eslint-community/regexpp': 4.12.1
'@eslint/config-array': 0.20.0
'@eslint/config-helpers': 0.2.1
@ -10373,11 +10361,6 @@ snapshots:
tinyexec@0.3.2: {}
tinyglobby@0.2.13:
dependencies:
fdir: 6.4.4(picomatch@4.0.2)
picomatch: 4.0.2
tinyglobby@0.2.14:
dependencies:
fdir: 6.4.4(picomatch@4.0.2)
@ -10452,7 +10435,7 @@ snapshots:
source-map: 0.8.0-beta.0
sucrase: 3.35.0
tinyexec: 0.3.2
tinyglobby: 0.2.13
tinyglobby: 0.2.14
tree-kill: 1.2.2
optionalDependencies:
postcss: 8.5.3