From 72b9c3924297fa92ab1dee84e4994919f36f253f Mon Sep 17 00:00:00 2001 From: Jeremy Gayed Date: Mon, 2 Mar 2026 09:54:16 -0500 Subject: [PATCH 1/2] Add MCP server package for Shopify Admin API New `@shopify/mcp` package that exposes the Shopify Admin API to AI coding agents via the Model Context Protocol (MCP). Uses cli-kit's existing auth and GraphQL infrastructure. Tools: - shopify_auth_login: device auth flow for non-interactive MCP context - shopify_graphql: execute Admin API queries/mutations Install: claude mcp add shopify -- npx -y -p @shopify/mcp Co-Authored-By: Claude Opus 4.6 (1M context) --- .changeset/config.json | 3 +- packages/cli-kit/src/public/node/mcp.ts | 110 +++ packages/mcp/bin/shopify-mcp.js | 2 + packages/mcp/package.json | 71 ++ packages/mcp/project.json | 46 ++ packages/mcp/src/index.ts | 15 + packages/mcp/src/server.ts | 23 + packages/mcp/src/session-manager.test.ts | 199 +++++ packages/mcp/src/session-manager.ts | 81 ++ packages/mcp/src/tools/auth.test.ts | 100 +++ packages/mcp/src/tools/auth.ts | 68 ++ packages/mcp/src/tools/graphql.test.ts | 170 ++++ packages/mcp/src/tools/graphql.ts | 70 ++ packages/mcp/tsconfig.build.json | 7 + packages/mcp/tsconfig.json | 13 + packages/mcp/vite.config.ts | 3 + pnpm-lock.yaml | 946 +++++++++++++++-------- 17 files changed, 1594 insertions(+), 333 deletions(-) create mode 100644 packages/cli-kit/src/public/node/mcp.ts create mode 100755 packages/mcp/bin/shopify-mcp.js create mode 100644 packages/mcp/package.json create mode 100644 packages/mcp/project.json create mode 100644 packages/mcp/src/index.ts create mode 100644 packages/mcp/src/server.ts create mode 100644 packages/mcp/src/session-manager.test.ts create mode 100644 packages/mcp/src/session-manager.ts create mode 100644 packages/mcp/src/tools/auth.test.ts create mode 100644 packages/mcp/src/tools/auth.ts create mode 100644 packages/mcp/src/tools/graphql.test.ts create mode 100644 packages/mcp/src/tools/graphql.ts create mode 100644 packages/mcp/tsconfig.build.json create mode 100644 packages/mcp/tsconfig.json create mode 100644 packages/mcp/vite.config.ts diff --git a/.changeset/config.json b/.changeset/config.json index b7767ea2657..de23273b2ab 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -11,7 +11,8 @@ "@shopify/theme", "@shopify/ui-extensions-dev-console-app", "@shopify/plugin-cloudflare", - "@shopify/plugin-did-you-mean" + "@shopify/plugin-did-you-mean", + "@shopify/mcp" ]], "access": "public", "baseBranch": "main", diff --git a/packages/cli-kit/src/public/node/mcp.ts b/packages/cli-kit/src/public/node/mcp.ts new file mode 100644 index 00000000000..8d62ad39e27 --- /dev/null +++ b/packages/cli-kit/src/public/node/mcp.ts @@ -0,0 +1,110 @@ +import {identityFqdn} from './context/fqdn.js' +import {BugError} from './error.js' +import {shopifyFetch} from './http.js' +import {clientId, applicationId} from '../../private/node/session/identity.js' +import {pollForDeviceAuthorization} from '../../private/node/session/device-authorization.js' +import {exchangeAccessForApplicationTokens, ExchangeScopes} from '../../private/node/session/exchange.js' +import {allDefaultScopes, apiScopes} from '../../private/node/session/scopes.js' +import * as sessionStore from '../../private/node/session/store.js' +import {setCurrentSessionId} from '../../private/node/conf-store.js' + +import type {AdminSession} from './session.js' + +export interface DeviceCodeResponse { + deviceCode: string + userCode: string + verificationUri: string + verificationUriComplete: string + expiresIn: number + interval: number +} + +/** + * Requests a device authorization code for MCP non-interactive auth. + * + * @returns The device code response with verification URL. + */ +export async function requestDeviceCode(): Promise { + const fqdn = await identityFqdn() + const identityClientId = clientId() + const scopes = allDefaultScopes() + const params = `client_id=${identityClientId}&scope=${scopes.join(' ')}` + const url = `https://${fqdn}/oauth/device_authorization` + + const response = await shopifyFetch(url, { + method: 'POST', + headers: {'Content-type': 'application/x-www-form-urlencoded'}, + body: params, + }) + + const responseText = await response.text() + let result: Record + try { + result = JSON.parse(responseText) as Record + } catch { + throw new BugError(`Invalid response from authorization service (HTTP ${response.status})`) + } + + if (!result.device_code || !result.verification_uri_complete) { + throw new BugError('Failed to start device authorization') + } + + return { + deviceCode: result.device_code as string, + userCode: result.user_code as string, + verificationUri: result.verification_uri as string, + verificationUriComplete: result.verification_uri_complete as string, + expiresIn: result.expires_in as number, + interval: (result.interval as number) ?? 5, + } +} + +/** + * Completes device authorization by polling for approval and exchanging tokens. + * + * @param deviceCode - The device code from requestDeviceCode. + * @param interval - Polling interval in seconds. + * @param storeFqdn - The normalized store FQDN. + * @returns An admin session with token and store FQDN. + */ +export async function completeDeviceAuth( + deviceCode: string, + interval: number, + storeFqdn: string, +): Promise { + const identityToken = await pollForDeviceAuthorization(deviceCode, interval) + + const exchangeScopes: ExchangeScopes = { + admin: apiScopes('admin'), + partners: apiScopes('partners'), + storefront: apiScopes('storefront-renderer'), + businessPlatform: apiScopes('business-platform'), + appManagement: apiScopes('app-management'), + } + + const appTokens = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, storeFqdn) + + const fqdn = await identityFqdn() + const sessions = (await sessionStore.fetch()) ?? {} + const newSession = { + identity: identityToken, + applications: appTokens, + } + + const updatedSessions = { + ...sessions, + [fqdn]: {...sessions[fqdn], [identityToken.userId]: newSession}, + } + await sessionStore.store(updatedSessions) + setCurrentSessionId(identityToken.userId) + + const adminAppId = applicationId('admin') + const adminKey = `${storeFqdn}-${adminAppId}` + const adminToken = appTokens[adminKey] + + if (!adminToken) { + throw new BugError(`No admin token received for store ${storeFqdn}`) + } + + return {token: adminToken.accessToken, storeFqdn} +} diff --git a/packages/mcp/bin/shopify-mcp.js b/packages/mcp/bin/shopify-mcp.js new file mode 100755 index 00000000000..33a61be8e60 --- /dev/null +++ b/packages/mcp/bin/shopify-mcp.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +import '../dist/index.js' diff --git a/packages/mcp/package.json b/packages/mcp/package.json new file mode 100644 index 00000000000..e3ba4606949 --- /dev/null +++ b/packages/mcp/package.json @@ -0,0 +1,71 @@ +{ + "name": "@shopify/mcp", + "version": "3.91.0", + "description": "MCP server for the Shopify Admin API", + "packageManager": "pnpm@10.11.1", + "private": false, + "keywords": [ + "shopify", + "mcp", + "model-context-protocol" + ], + "homepage": "https://github.com/shopify/cli#readme", + "bugs": { + "url": "https://community.shopify.dev/c/shopify-cli-libraries/14" + }, + "repository": { + "type": "git", + "url": "https://github.com/Shopify/cli.git", + "directory": "packages/mcp" + }, + "license": "MIT", + "type": "module", + "bin": { + "shopify-mcp": "./bin/shopify-mcp.js" + }, + "files": [ + "/bin", + "/dist" + ], + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "nx build", + "clean": "nx clean", + "lint": "nx lint", + "lint:fix": "nx lint:fix", + "prepack": "NODE_ENV=production pnpm nx build && cp ../../README.md README.md", + "vitest": "vitest", + "type-check": "nx type-check" + }, + "eslintConfig": { + "extends": [ + "../../.eslintrc.cjs" + ] + }, + "dependencies": { + "@modelcontextprotocol/sdk": "1.27.1", + "@shopify/cli-kit": "3.91.0", + "zod": "3.25.76" + }, + "devDependencies": { + "@vitest/coverage-istanbul": "^3.1.4" + }, + "engines": { + "node": ">=20.10.0" + }, + "os": [ + "darwin", + "linux", + "win32" + ], + "publishConfig": { + "@shopify:registry": "https://registry.npmjs.org", + "access": "public" + }, + "engine-strict": true +} diff --git a/packages/mcp/project.json b/packages/mcp/project.json new file mode 100644 index 00000000000..1445f460e03 --- /dev/null +++ b/packages/mcp/project.json @@ -0,0 +1,46 @@ +{ + "name": "mcp", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/mcp/src", + "projectType": "library", + "tags": ["scope:feature"], + "targets": { + "clean": { + "executor": "nx:run-commands", + "options": { + "command": "pnpm rimraf dist/", + "cwd": "packages/mcp" + } + }, + "build": { + "executor": "nx:run-commands", + "outputs": ["{workspaceRoot}/dist"], + "inputs": ["{projectRoot}/src/**/*", "{projectRoot}/package.json"], + "options": { + "command": "pnpm tsc -b ./tsconfig.build.json", + "cwd": "packages/mcp" + } + }, + "lint": { + "executor": "nx:run-commands", + "options": { + "command": "pnpm eslint \"src/**/*.ts\"", + "cwd": "packages/mcp" + } + }, + "lint:fix": { + "executor": "nx:run-commands", + "options": { + "command": "pnpm eslint 'src/**/*.ts' --fix", + "cwd": "packages/mcp" + } + }, + "type-check": { + "executor": "nx:run-commands", + "options": { + "command": "pnpm tsc --noEmit", + "cwd": "packages/mcp" + } + } + } +} diff --git a/packages/mcp/src/index.ts b/packages/mcp/src/index.ts new file mode 100644 index 00000000000..8fb32f37e44 --- /dev/null +++ b/packages/mcp/src/index.ts @@ -0,0 +1,15 @@ +import {createServer} from './server.js' +import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js' + +const server = createServer() +const transport = new StdioServerTransport() +await server.connect(transport) + +const shutdown = () => { + const _closing = server + .close() + .then(() => process.exit(0)) + .catch(() => process.exit(1)) +} +process.on('SIGINT', shutdown) +process.on('SIGTERM', shutdown) diff --git a/packages/mcp/src/server.ts b/packages/mcp/src/server.ts new file mode 100644 index 00000000000..9d342e734c7 --- /dev/null +++ b/packages/mcp/src/server.ts @@ -0,0 +1,23 @@ +import {SessionManager} from './session-manager.js' +import {registerAuthTool} from './tools/auth.js' +import {registerGraphqlTool} from './tools/graphql.js' +import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js' + +import {createRequire} from 'module' + +const require = createRequire(import.meta.url) +const {version} = require('../package.json') as {version: string} + +export function createServer(): McpServer { + const server = new McpServer({ + name: 'shopify', + version, + }) + + const sessionManager = new SessionManager() + + registerAuthTool(server, sessionManager) + registerGraphqlTool(server, sessionManager) + + return server +} diff --git a/packages/mcp/src/session-manager.test.ts b/packages/mcp/src/session-manager.test.ts new file mode 100644 index 00000000000..56017c9d92f --- /dev/null +++ b/packages/mcp/src/session-manager.test.ts @@ -0,0 +1,199 @@ +import {SessionManager} from './session-manager.js' +import {AbortError} from '@shopify/cli-kit/node/error' +import {describe, test, expect, vi} from 'vitest' + +const mockEnsureAuthenticatedAdmin = vi.fn() +const mockRequestDeviceCode = vi.fn() +const mockCompleteDeviceAuth = vi.fn() +const mockNormalizeStoreFqdn = vi.fn((store: string) => `${store}.myshopify.com`) + +vi.mock('@shopify/cli-kit/node/session', () => ({ + ensureAuthenticatedAdmin: (...args: unknown[]) => mockEnsureAuthenticatedAdmin(...args), +})) + +vi.mock('@shopify/cli-kit/node/error', () => { + class MockAbortError extends Error { + constructor(message: string) { + super(message) + this.name = 'AbortError' + } + } + return {AbortError: MockAbortError} +}) + +vi.mock('@shopify/cli-kit/node/mcp', () => ({ + requestDeviceCode: (...args: unknown[]) => mockRequestDeviceCode(...args), + completeDeviceAuth: (...args: unknown[]) => mockCompleteDeviceAuth(...args), +})) + +vi.mock('@shopify/cli-kit/node/context/fqdn', () => ({ + normalizeStoreFqdn: (store: string) => mockNormalizeStoreFqdn(store), +})) + +describe('SessionManager', () => { + describe('getSession', () => { + test('returns existing session from ensureAuthenticatedAdmin', async () => { + const sessionManager = new SessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + mockEnsureAuthenticatedAdmin.mockResolvedValue(session) + + const result = await sessionManager.getSession('test') + expect(result).toEqual(session) + expect(mockEnsureAuthenticatedAdmin).toHaveBeenCalledWith('test.myshopify.com', [], {noPrompt: true}) + }) + + test('returns undefined when ensureAuthenticatedAdmin throws AbortError', async () => { + const sessionManager = new SessionManager() + mockEnsureAuthenticatedAdmin.mockRejectedValue(new AbortError('Unable to prompt')) + + const result = await sessionManager.getSession('test') + expect(result).toBeUndefined() + }) + + test('rethrows non-AbortError errors', async () => { + const sessionManager = new SessionManager() + mockEnsureAuthenticatedAdmin.mockRejectedValue(new TypeError('Unexpected null')) + + await expect(sessionManager.getSession('test')).rejects.toThrow('Unexpected null') + }) + + test('caches session after first successful fetch', async () => { + const sessionManager = new SessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + mockEnsureAuthenticatedAdmin.mockResolvedValueOnce(session) + + await sessionManager.getSession('test') + const result = await sessionManager.getSession('test') + expect(result).toEqual(session) + expect(mockEnsureAuthenticatedAdmin).toHaveBeenCalledTimes(1) + }) + }) + + describe('startAuth', () => { + test('returns device code response and starts background polling', async () => { + const sessionManager = new SessionManager() + const deviceCode = { + deviceCode: 'dev-123', + userCode: 'USR-123', + verificationUri: 'https://accounts.shopify.com/activate', + verificationUriComplete: 'https://accounts.shopify.com/activate?user_code=USR-123', + expiresIn: 600, + interval: 5, + } + mockRequestDeviceCode.mockResolvedValue(deviceCode) + + const session = {token: 'new-token', storeFqdn: 'test.myshopify.com'} + mockCompleteDeviceAuth.mockResolvedValue(session) + + const result = await sessionManager.startAuth('test') + expect(result).toEqual(deviceCode) + expect(mockRequestDeviceCode).toHaveBeenCalled() + expect(mockCompleteDeviceAuth).toHaveBeenCalledWith('dev-123', 5, 'test.myshopify.com') + }) + + test('throws when startAuth called concurrently for same store', async () => { + const sessionManager = new SessionManager() + const deviceCode = { + deviceCode: 'dev-123', + userCode: 'USR-123', + verificationUri: 'https://accounts.shopify.com/activate', + verificationUriComplete: 'https://accounts.shopify.com/activate?user_code=USR-123', + expiresIn: 600, + interval: 5, + } + mockRequestDeviceCode.mockResolvedValue(deviceCode) + mockCompleteDeviceAuth.mockReturnValue(new Promise(() => {})) + + await sessionManager.startAuth('test') + await expect(sessionManager.startAuth('test')).rejects.toThrow('Authentication already in progress') + }) + + test('cleans up pendingAuth on background auth failure', async () => { + const sessionManager = new SessionManager() + const deviceCode = { + deviceCode: 'dev-fail', + userCode: 'USR-FAIL', + verificationUri: 'https://accounts.shopify.com/activate', + verificationUriComplete: 'https://accounts.shopify.com/activate?user_code=USR-FAIL', + expiresIn: 600, + interval: 5, + } + mockRequestDeviceCode.mockResolvedValue(deviceCode) + mockCompleteDeviceAuth.mockRejectedValue(new Error('Access denied')) + + await sessionManager.startAuth('test') + await vi.waitFor(() => Promise.resolve()) + + mockEnsureAuthenticatedAdmin.mockRejectedValue(new AbortError('No session')) + await expect(sessionManager.requireSession('test')).rejects.toThrow( + 'Not authenticated for store test.myshopify.com', + ) + }) + }) + + describe('requireSession', () => { + test('returns cached session', async () => { + const sessionManager = new SessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + mockEnsureAuthenticatedAdmin.mockResolvedValue(session) + + await sessionManager.getSession('test') + const result = await sessionManager.requireSession('test') + expect(result).toEqual(session) + }) + + test('waits for pending auth', async () => { + const sessionManager = new SessionManager() + const deviceCode = { + deviceCode: 'dev-123', + userCode: 'USR-123', + verificationUri: 'https://accounts.shopify.com/activate', + verificationUriComplete: 'https://accounts.shopify.com/activate?user_code=USR-123', + expiresIn: 600, + interval: 5, + } + mockRequestDeviceCode.mockResolvedValue(deviceCode) + + const session = {token: 'new-token', storeFqdn: 'test.myshopify.com'} + mockCompleteDeviceAuth.mockResolvedValue(session) + + await sessionManager.startAuth('test') + const result = await sessionManager.requireSession('test') + expect(result).toEqual(session) + }) + + test('throws friendly message when AbortError (no session)', async () => { + const sessionManager = new SessionManager() + mockEnsureAuthenticatedAdmin.mockRejectedValue(new AbortError('Unable to prompt')) + + await expect(sessionManager.requireSession('test')).rejects.toThrow( + 'Not authenticated for store test.myshopify.com', + ) + }) + + test('rethrows non-AbortError errors in requireSession', async () => { + const sessionManager = new SessionManager() + mockEnsureAuthenticatedAdmin.mockRejectedValue(new TypeError('Network failure')) + + await expect(sessionManager.requireSession('test')).rejects.toThrow('Network failure') + }) + }) + + describe('clearSession', () => { + test('removes cached session so next call re-fetches', async () => { + const sessionManager = new SessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + mockEnsureAuthenticatedAdmin.mockResolvedValue(session) + + await sessionManager.getSession('test') + sessionManager.clearSession('test') + + const session2 = {token: 'xyz', storeFqdn: 'test.myshopify.com'} + mockEnsureAuthenticatedAdmin.mockResolvedValue(session2) + + const result = await sessionManager.getSession('test') + expect(result).toEqual(session2) + expect(mockEnsureAuthenticatedAdmin).toHaveBeenCalledTimes(2) + }) + }) +}) diff --git a/packages/mcp/src/session-manager.ts b/packages/mcp/src/session-manager.ts new file mode 100644 index 00000000000..426379f02d5 --- /dev/null +++ b/packages/mcp/src/session-manager.ts @@ -0,0 +1,81 @@ +import {ensureAuthenticatedAdmin} from '@shopify/cli-kit/node/session' +import {requestDeviceCode, completeDeviceAuth} from '@shopify/cli-kit/node/mcp' +import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn' +import {AbortError} from '@shopify/cli-kit/node/error' +import type {AdminSession} from '@shopify/cli-kit/node/session' +import type {DeviceCodeResponse} from '@shopify/cli-kit/node/mcp' + +export class SessionManager { + private readonly sessions: Map = new Map() + private readonly pendingAuth: Map> = new Map() + + async getSession(store: string): Promise { + const storeFqdn = normalizeStoreFqdn(store) + const cached = this.sessions.get(storeFqdn) + if (cached) return cached + + try { + const session = await ensureAuthenticatedAdmin(storeFqdn, [], {noPrompt: true}) + this.sessions.set(storeFqdn, session) + return session + } catch (error) { + if (error instanceof AbortError) { + return undefined + } + throw error + } + } + + async startAuth(store: string): Promise { + const storeFqdn = normalizeStoreFqdn(store) + + if (this.pendingAuth.has(storeFqdn)) { + throw new Error(`Authentication already in progress for store ${storeFqdn}.`) + } + + const deviceCodeResponse = await requestDeviceCode() + + const authPromise = completeDeviceAuth(deviceCodeResponse.deviceCode, deviceCodeResponse.interval, storeFqdn).then( + (session) => { + this.sessions.set(storeFqdn, session) + this.pendingAuth.delete(storeFqdn) + return session + }, + (error: unknown) => { + this.pendingAuth.delete(storeFqdn) + throw error + }, + ) + + authPromise.catch(() => {}) + this.pendingAuth.set(storeFqdn, authPromise) + return deviceCodeResponse + } + + async requireSession(store: string): Promise { + const storeFqdn = normalizeStoreFqdn(store) + + const cached = this.sessions.get(storeFqdn) + if (cached) return cached + + const pending = this.pendingAuth.get(storeFqdn) + if (pending) return pending + + try { + const session = await ensureAuthenticatedAdmin(storeFqdn, [], {noPrompt: true}) + this.sessions.set(storeFqdn, session) + return session + } catch (error) { + if (error instanceof AbortError) { + throw new Error(`Not authenticated for store ${storeFqdn}. Call shopify_auth_login first.`) + } + throw error + } + } + + clearSession(store: string): void { + const storeFqdn = normalizeStoreFqdn(store) + this.sessions.delete(storeFqdn) + this.pendingAuth.delete(storeFqdn) + } +} diff --git a/packages/mcp/src/tools/auth.test.ts b/packages/mcp/src/tools/auth.test.ts new file mode 100644 index 00000000000..a6bf9b26e43 --- /dev/null +++ b/packages/mcp/src/tools/auth.test.ts @@ -0,0 +1,100 @@ +import {handleAuthLogin} from './auth.js' +import {describe, test, expect, vi, beforeEach, afterEach} from 'vitest' +import type {SessionManager} from '../session-manager.js' + +function createMockSessionManager(): SessionManager { + return { + getSession: vi.fn(), + startAuth: vi.fn(), + requireSession: vi.fn(), + clearSession: vi.fn(), + } as unknown as SessionManager +} + +describe('handleAuthLogin', () => { + const originalEnv = process.env + + beforeEach(() => { + process.env = {...originalEnv} + delete process.env.SHOPIFY_FLAG_STORE + }) + + afterEach(() => { + process.env = originalEnv + }) + + test('returns error when no store specified', async () => { + const sm = createMockSessionManager() + const result = await handleAuthLogin(sm, undefined) + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('No store specified') + }) + + test('uses SHOPIFY_FLAG_STORE env when no store param', async () => { + process.env.SHOPIFY_FLAG_STORE = 'env-store.myshopify.com' + const sm = createMockSessionManager() + ;(sm.getSession as ReturnType).mockResolvedValue({token: 'abc', storeFqdn: 'env-store.myshopify.com'}) + + const result = await handleAuthLogin(sm, undefined) + + expect(result.isError).toBeUndefined() + expect(result.content[0]!.text).toContain('Already authenticated') + expect(sm.getSession).toHaveBeenCalledWith('env-store.myshopify.com') + }) + + test('returns already authenticated when session exists', async () => { + const sm = createMockSessionManager() + ;(sm.getSession as ReturnType).mockResolvedValue({token: 'abc', storeFqdn: 'test.myshopify.com'}) + + const result = await handleAuthLogin(sm, 'test.myshopify.com') + + expect(result.isError).toBeUndefined() + expect(result.content[0]!.text).toContain('Already authenticated with store test.myshopify.com') + }) + + test('returns verification URL on new auth', async () => { + const sm = createMockSessionManager() + ;(sm.getSession as ReturnType).mockResolvedValue(undefined) + ;(sm.startAuth as ReturnType).mockResolvedValue({ + deviceCode: 'dev-123', + userCode: 'USR-123', + verificationUriComplete: 'https://accounts.shopify.com/activate?user_code=USR-123', + interval: 5, + }) + + const result = await handleAuthLogin(sm, 'test.myshopify.com') + + expect(result.isError).toBeUndefined() + expect(result.content[0]!.text).toContain('https://accounts.shopify.com/activate?user_code=USR-123') + expect(result.content[0]!.text).toContain('USR-123') + expect(result.content[0]!.text).toContain('After approving') + }) + + test('returns error on auth failure', async () => { + const sm = createMockSessionManager() + ;(sm.getSession as ReturnType).mockResolvedValue(undefined) + ;(sm.startAuth as ReturnType).mockRejectedValue(new Error('Network timeout')) + + const result = await handleAuthLogin(sm, 'test.myshopify.com') + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('Network timeout') + }) + + test('sanitizes tokens and paths in error messages', async () => { + const sm = createMockSessionManager() + ;(sm.getSession as ReturnType).mockResolvedValue(undefined) + ;(sm.startAuth as ReturnType).mockRejectedValue( + new Error('Failed with Bearer abc123token at /Users/dev/secret/path'), + ) + + const result = await handleAuthLogin(sm, 'test.myshopify.com') + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('Bearer [REDACTED]') + expect(result.content[0]!.text).toContain('[PATH]') + expect(result.content[0]!.text).not.toContain('abc123token') + expect(result.content[0]!.text).not.toContain('/Users/dev') + }) +}) diff --git a/packages/mcp/src/tools/auth.ts b/packages/mcp/src/tools/auth.ts new file mode 100644 index 00000000000..33e427650f3 --- /dev/null +++ b/packages/mcp/src/tools/auth.ts @@ -0,0 +1,68 @@ +import type {SessionManager} from '../session-manager.js' +import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js' +import {z} from 'zod' + +export interface ToolResult { + [key: string]: unknown + content: Array<{type: 'text'; text: string}> + isError?: boolean +} + +export function resolveStore(store: string | undefined): string | undefined { + return store ?? process.env.SHOPIFY_FLAG_STORE +} + +export async function handleAuthLogin(sessionManager: SessionManager, store: string | undefined): Promise { + const resolvedStore = resolveStore(store) + if (!resolvedStore) { + return { + content: [{type: 'text', text: 'Error: No store specified. Provide a store parameter or set SHOPIFY_FLAG_STORE environment variable.'}], + isError: true, + } + } + + try { + const existing = await sessionManager.getSession(resolvedStore) + if (existing) { + return { + content: [{type: 'text', text: `Already authenticated with store ${existing.storeFqdn}.`}], + } + } + + const deviceCode = await sessionManager.startAuth(resolvedStore) + return { + content: [ + { + type: 'text', + text: [ + 'To authenticate, open this URL in your browser:', + '', + deviceCode.verificationUriComplete, + '', + `User code: ${deviceCode.userCode}`, + '', + 'After approving in the browser, try your next request -- authentication will complete automatically.', + ].join('\n'), + }, + ], + } + } catch (error) { + const rawMessage = error instanceof Error ? error.message : String(error) + const message = rawMessage.replace(/Bearer\s+\S+/gi, 'Bearer [REDACTED]').replace(/\/Users\/[^\s]+/g, '[PATH]') + return { + content: [{type: 'text', text: `Authentication error: ${message}`}], + isError: true, + } + } +} + +export function registerAuthTool(server: McpServer, sessionManager: SessionManager) { + server.tool( + 'shopify_auth_login', + 'Authenticate with a Shopify store. Returns a URL the user must visit to complete login. After approval, subsequent shopify_graphql calls will automatically use the session.', + { + store: z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9\-.]*$/).optional().describe('Store domain (e.g. "my-store.myshopify.com"). Must match /^[a-zA-Z0-9][a-zA-Z0-9\\-.]*$/. Defaults to SHOPIFY_FLAG_STORE env var.'), + }, + ({store}) => handleAuthLogin(sessionManager, store), + ) +} diff --git a/packages/mcp/src/tools/graphql.test.ts b/packages/mcp/src/tools/graphql.test.ts new file mode 100644 index 00000000000..bf8df1c63ab --- /dev/null +++ b/packages/mcp/src/tools/graphql.test.ts @@ -0,0 +1,170 @@ +import {handleGraphql} from './graphql.js' +import {describe, test, expect, vi, beforeEach, afterEach} from 'vitest' +import type {SessionManager} from '../session-manager.js' + +const mockAdminRequest = vi.fn() + +vi.mock('@shopify/cli-kit/node/api/admin', () => ({ + adminRequest: (...args: unknown[]) => mockAdminRequest(...args), +})) + +function createMockSessionManager(): SessionManager { + return { + getSession: vi.fn(), + startAuth: vi.fn(), + requireSession: vi.fn(), + clearSession: vi.fn(), + } as unknown as SessionManager +} + +describe('handleGraphql', () => { + const originalEnv = process.env + + beforeEach(() => { + process.env = {...originalEnv} + delete process.env.SHOPIFY_FLAG_STORE + }) + + afterEach(() => { + process.env = originalEnv + }) + + test('returns error when no store specified', async () => { + const sm = createMockSessionManager() + const result = await handleGraphql(sm, {query: '{ shop { name } }', allowMutations: false}) + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('No store specified') + }) + + test('blocks mutations without allowMutations flag', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + + const result = await handleGraphql(sm, {query: 'mutation { productDelete(input: {id: "1"}) { deletedProductId } }', allowMutations: false}) + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('allowMutations: true') + }) + + test('allows mutations with allowMutations flag', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + ;(sm.requireSession as ReturnType).mockResolvedValue(session) + mockAdminRequest.mockResolvedValue({data: {productDelete: {deletedProductId: '1'}}}) + + const result = await handleGraphql(sm, { + query: 'mutation { productDelete(input: {id: "1"}) { deletedProductId } }', + allowMutations: true, + }) + + expect(result.isError).toBeUndefined() + expect(mockAdminRequest).toHaveBeenCalledWith('mutation { productDelete(input: {id: "1"}) { deletedProductId } }', session, undefined) + }) + + test('executes query and returns JSON result', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + ;(sm.requireSession as ReturnType).mockResolvedValue(session) + mockAdminRequest.mockResolvedValue({data: {shop: {name: 'Test Store'}}}) + + const result = await handleGraphql(sm, {query: '{ shop { name } }', allowMutations: false}) + + expect(result.isError).toBeUndefined() + const parsed = JSON.parse(result.content[0]!.text) + expect(parsed.data.shop.name).toBe('Test Store') + }) + + test('passes variables to adminRequest', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + ;(sm.requireSession as ReturnType).mockResolvedValue(session) + mockAdminRequest.mockResolvedValue({data: {node: {id: 'gid://shopify/Product/1'}}}) + + const variables = {id: 'gid://shopify/Product/1'} + await handleGraphql(sm, {query: 'query($id: ID!) { node(id: $id) { id } }', variables, allowMutations: false}) + + expect(mockAdminRequest).toHaveBeenCalledWith('query($id: ID!) { node(id: $id) { id } }', session, variables) + }) + + test('returns auth error when not authenticated', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + ;(sm.requireSession as ReturnType).mockRejectedValue(new Error('Not authenticated for store test.myshopify.com. Call shopify_auth_login first.')) + + const result = await handleGraphql(sm, {query: '{ shop { name } }', allowMutations: false}) + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('shopify_auth_login') + }) + + test('clears session and returns error on 401', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + const session = {token: 'expired', storeFqdn: 'test.myshopify.com'} + ;(sm.requireSession as ReturnType).mockResolvedValue(session) + mockAdminRequest.mockRejectedValue(new Error('401 Unauthorized')) + + const result = await handleGraphql(sm, {query: '{ shop { name } }', allowMutations: false}) + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('Session expired') + expect(sm.clearSession).toHaveBeenCalledWith('test.myshopify.com') + }) + + test('returns GraphQL error for non-auth failures', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + ;(sm.requireSession as ReturnType).mockResolvedValue(session) + mockAdminRequest.mockRejectedValue(new Error('Field "invalid" not found on type "Shop"')) + + const result = await handleGraphql(sm, {query: '{ shop { invalid } }', allowMutations: false}) + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('GraphQL error') + expect(result.content[0]!.text).toContain('Field "invalid" not found') + }) + + test('detects mutations with leading comments', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + const result = await handleGraphql(sm, { + query: '# comment\nmutation { productDelete(input: {id: "1"}) { deletedProductId } }', + allowMutations: false, + }) + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('allowMutations') + }) + + test('mutation pattern detection', () => { + const pattern = /^\s*mutation[\s({]/i + expect(pattern.test('mutation { shop { name } }')).toBe(true) + expect(pattern.test(' mutation CreateProduct($input: ProductInput!) { }')).toBe(true) + expect(pattern.test('mutation(')).toBe(true) + expect(pattern.test('MUTATION { }')).toBe(true) + expect(pattern.test('Mutation { }')).toBe(true) + expect(pattern.test('query { shop { name } }')).toBe(false) + expect(pattern.test('{ shop { name } }')).toBe(false) + expect(pattern.test('query GetMutationResults { }')).toBe(false) + }) + + test('sanitizes tokens and paths in error messages', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + const session = {token: 'abc', storeFqdn: 'test.myshopify.com'} + ;(sm.requireSession as ReturnType).mockResolvedValue(session) + mockAdminRequest.mockRejectedValue(new Error('Request failed with Bearer secretToken123 at /Users/dev/secret')) + + const result = await handleGraphql(sm, {query: '{ shop { name } }', allowMutations: false}) + + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('Bearer [REDACTED]') + expect(result.content[0]!.text).toContain('[PATH]') + expect(result.content[0]!.text).not.toContain('secretToken123') + expect(result.content[0]!.text).not.toContain('/Users/dev') + }) +}) diff --git a/packages/mcp/src/tools/graphql.ts b/packages/mcp/src/tools/graphql.ts new file mode 100644 index 00000000000..26de5045dcd --- /dev/null +++ b/packages/mcp/src/tools/graphql.ts @@ -0,0 +1,70 @@ +import type {SessionManager} from '../session-manager.js' +import type {ToolResult} from './auth.js' +import {resolveStore} from './auth.js' +import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js' +import {z} from 'zod' +import {adminRequest} from '@shopify/cli-kit/node/api/admin' + +const MUTATION_PATTERN = /^\s*mutation[\s({]/i + +export async function handleGraphql( + sessionManager: SessionManager, + params: {query: string; variables?: Record; store?: string; allowMutations: boolean}, +): Promise { + const resolvedStore = resolveStore(params.store) + if (!resolvedStore) { + return { + content: [{type: 'text', text: 'Error: No store specified. Provide a store parameter or set SHOPIFY_FLAG_STORE environment variable.'}], + isError: true, + } + } + + const stripped = params.query.replace(/^\s*(#[^\n]*\n)*/g, '') + if (MUTATION_PATTERN.test(stripped) && !params.allowMutations) { + return { + content: [{type: 'text', text: 'Error: Mutations require allowMutations: true. This is a safety measure to prevent unintended changes.'}], + isError: true, + } + } + + try { + const session = await sessionManager.requireSession(resolvedStore) + const result = await adminRequest(params.query, session, params.variables) + return { + content: [{type: 'text', text: JSON.stringify(result, null, 2)}], + } + } catch (error) { + const rawMessage = error instanceof Error ? error.message : String(error) + const message = rawMessage.replace(/Bearer\s+\S+/gi, 'Bearer [REDACTED]').replace(/\/Users\/[^\s]+/g, '[PATH]') + const isAuthError = message.includes('Not authenticated') || message.includes('shopify_auth_login') + + if (isAuthError) { + return {content: [{type: 'text', text: message}], isError: true} + } + + const isExpiredToken = message.includes('401') || message.includes('Unauthorized') + if (isExpiredToken) { + sessionManager.clearSession(resolvedStore) + return { + content: [{type: 'text', text: 'Session expired. Call shopify_auth_login to re-authenticate.'}], + isError: true, + } + } + + return {content: [{type: 'text', text: `GraphQL error: ${message}`}], isError: true} + } +} + +export function registerGraphqlTool(server: McpServer, sessionManager: SessionManager) { + server.tool( + 'shopify_graphql', + 'Execute a GraphQL query or mutation against the Shopify Admin API. Requires authentication via shopify_auth_login first. Uses the latest supported API version. Set allowMutations: true to run mutations.', + { + query: z.string().describe('GraphQL query or mutation string'), + variables: z.record(z.unknown()).optional().describe('GraphQL variables'), + store: z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9\-.]*$/).optional().describe('Store domain override. Must match /^[a-zA-Z0-9][a-zA-Z0-9\\-.]*$/. Defaults to SHOPIFY_FLAG_STORE env var.'), + allowMutations: z.boolean().optional().default(false).describe('Must be true to execute mutations'), + }, + ({query, variables, store, allowMutations}) => handleGraphql(sessionManager, {query, variables, store, allowMutations}), + ) +} diff --git a/packages/mcp/tsconfig.build.json b/packages/mcp/tsconfig.build.json new file mode 100644 index 00000000000..16506ad61a2 --- /dev/null +++ b/packages/mcp/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/*.test.ts"], + "references": [ + {"path": "../cli-kit"} + ] +} diff --git a/packages/mcp/tsconfig.json b/packages/mcp/tsconfig.json new file mode 100644 index 00000000000..ea7490fa22f --- /dev/null +++ b/packages/mcp/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../configurations/tsconfig.json", + "include": ["./src/**/*.ts"], + "exclude": ["./dist"], + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" + }, + "references": [ + {"path": "../cli-kit"} + ] +} diff --git a/packages/mcp/vite.config.ts b/packages/mcp/vite.config.ts new file mode 100644 index 00000000000..9536586ca45 --- /dev/null +++ b/packages/mcp/vite.config.ts @@ -0,0 +1,3 @@ +import config from '../../configurations/vite.config' + +export default config(__dirname) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 95bb35d5434..469c02fdf67 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,7 +51,7 @@ importers: version: 22.0.0 '@shopify/eslint-plugin-cli': specifier: file:packages/eslint-plugin-cli - version: file:packages/eslint-plugin-cli(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: file:packages/eslint-plugin-cli(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) '@shopify/generate-docs': specifier: 0.15.6 version: 0.15.6 @@ -66,7 +66,7 @@ importers: version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) ansi-colors: specifier: ^4.1.3 version: 4.1.3 @@ -144,7 +144,7 @@ importers: version: 5.9.3 vitest: specifier: ^3.1.4 - version: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + version: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) zod: specifier: 3.24.4 version: 3.24.4 @@ -259,7 +259,7 @@ importers: version: 8.18.1 '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) packages/cli: dependencies: @@ -305,7 +305,7 @@ importers: version: 3.0.0 '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) esbuild-plugin-copy: specifier: ^2.1.1 version: 2.1.1(esbuild@0.27.3) @@ -531,7 +531,7 @@ importers: version: 3.0.4 '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) msw: specifier: ^2.7.1 version: 2.12.10(@types/node@22.19.11)(typescript@5.9.3) @@ -559,7 +559,7 @@ importers: version: link:../cli-kit '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) esbuild-plugin-copy: specifier: ^2.1.1 version: 2.1.1(esbuild@0.27.3) @@ -601,7 +601,7 @@ importers: version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) '@vitest/eslint-plugin': specifier: 1.1.44 - version: 1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) debug: specifier: 4.4.0 version: 4.4.0(supports-color@8.1.1) @@ -667,6 +667,22 @@ importers: specifier: ^3.1.0 version: 3.1.0 + packages/mcp: + dependencies: + '@modelcontextprotocol/sdk': + specifier: 1.27.1 + version: 1.27.1(zod@3.25.76) + '@shopify/cli-kit': + specifier: 3.91.0 + version: 3.91.0(@types/react@18.3.12) + zod: + specifier: 3.25.76 + version: 3.25.76 + devDependencies: + '@vitest/coverage-istanbul': + specifier: ^3.1.4 + version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + packages/plugin-cloudflare: dependencies: '@oclif/core': @@ -678,7 +694,7 @@ importers: devDependencies: '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) packages/plugin-did-you-mean: dependencies: @@ -694,7 +710,7 @@ importers: devDependencies: '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) packages/theme: dependencies: @@ -725,7 +741,7 @@ importers: version: 0.0.18 '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0)) node-stream-zip: specifier: ^1.15.0 version: 1.15.0 @@ -777,7 +793,7 @@ importers: version: 18.3.7(@types/react@18.3.12) '@vitejs/plugin-react': specifier: ^5.1.4 - version: 5.1.4(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) + version: 5.2.0(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) jsdom: specifier: ^25.0.0 version: 25.0.1 @@ -792,13 +808,13 @@ importers: devDependencies: '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.12))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@18.3.12))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/react': specifier: 18.3.12 version: 18.3.12 '@vitejs/plugin-react': specifier: ^5.1.4 - version: 5.1.4(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) + version: 5.2.0(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) jsdom: specifier: ^25.0.0 version: 25.0.1 @@ -847,9 +863,6 @@ importers: packages: - '@acemir/cssom@0.9.31': - resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} - '@actions/core@1.11.1': resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==} @@ -886,16 +899,6 @@ packages: '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - '@asamuzakjp/css-color@5.0.1': - resolution: {integrity: sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/dom-selector@6.8.1': - resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==} - - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@ast-grep/napi-darwin-arm64@0.33.0': resolution: {integrity: sha512-FsBQiBNGbqeU6z2sjFgnV6MXuBa0wYUb4PViMnqsKLeWiO7kRii5crmXLCtdTD2hufXTG6Rll8X46AkYOAwGGQ==} engines: {node: '>= 10'} @@ -1728,10 +1731,6 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@bramus/specificity@2.4.2': - resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} - hasBin: true - '@bugsnag/browser@8.8.1': resolution: {integrity: sha512-wdDFZQtZBKlVkNWx57VWuOf+NKF3Pp+INn8E2SdYNwN42PQdsgsx7NliSMqY5MPiW0GeE9mgc7QMIMixOWp8Lw==} @@ -1821,10 +1820,6 @@ packages: resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} engines: {node: '>=18'} - '@csstools/color-helpers@6.0.2': - resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} - engines: {node: '>=20.19.0'} - '@csstools/css-calc@2.1.4': resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} engines: {node: '>=18'} @@ -1832,13 +1827,6 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-calc@3.1.1': - resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-color-parser@3.1.0': resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} engines: {node: '>=18'} @@ -1846,36 +1834,16 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-color-parser@4.0.2': - resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-parser-algorithms@3.0.5': resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} engines: {node: '>=18'} peerDependencies: '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-parser-algorithms@4.0.0': - resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-tokenizer': ^4.0.0 - - '@csstools/css-syntax-patches-for-csstree@1.1.0': - resolution: {integrity: sha512-H4tuz2nhWgNKLt1inYpoVCfbJbMwX/lQKp3g69rrrIMIYlFD9+zTykOKhNR8uGrAmbS/kT9n6hTFkmDkxLgeTA==} - '@csstools/css-tokenizer@3.0.4': resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@csstools/css-tokenizer@4.0.0': - resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} - engines: {node: '>=20.19.0'} - '@cucumber/ci-environment@13.0.0': resolution: {integrity: sha512-cs+3NzfNkGbcmHPddjEv4TKFiBpZRQ6WJEEufB9mw+ExS22V/4R/zpDSEG+fsJ/iSNCd6A2sATdY8PFOyY3YnA==} @@ -2317,15 +2285,6 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@exodus/bytes@1.15.0': - resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - '@noble/hashes': ^1.8.0 || ^2.0.0 - peerDependenciesMeta: - '@noble/hashes': - optional: true - '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} @@ -2625,6 +2584,12 @@ packages: peerDependencies: graphql: 16.10.0 + '@hono/node-server@1.19.9': + resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -2872,6 +2837,16 @@ packages: '@microsoft/tsdoc@0.15.1': resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + '@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 + '@mswjs/interceptors@0.41.3': resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} engines: {node: '>=18'} @@ -3628,6 +3603,11 @@ packages: vite: optional: true + '@shopify/cli-kit@3.91.0': + resolution: {integrity: sha512-s+nWuxTdkY8NHPOJi6m7QYaeKR3Yd8+99ojFRHhh3O32Y1WtkDPWPWjJG5eTjx4bc0Xh/ih2ky8ivoYphxkBhQ==} + engines: {node: '>=20.10.0'} + os: [darwin, linux, win32] + '@shopify/eslint-plugin-cli@file:packages/eslint-plugin-cli': resolution: {directory: packages/eslint-plugin-cli, type: directory} peerDependencies: @@ -4306,8 +4286,8 @@ packages: cpu: [x64] os: [win32] - '@vitejs/plugin-react@5.1.4': - resolution: {integrity: sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==} + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: 6.4.1 @@ -4396,6 +4376,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -4430,12 +4414,23 @@ packages: ajv: optional: true + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} @@ -4706,9 +4701,6 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -4720,6 +4712,10 @@ packages: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. @@ -4736,8 +4732,8 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + brace-expansion@5.0.3: + resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} engines: {node: 18 || 20 || >=22} braces@3.0.3: @@ -5085,6 +5081,10 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -5105,6 +5105,10 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.7.1: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} @@ -5122,6 +5126,10 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + cosmiconfig@7.1.0: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} @@ -5181,10 +5189,6 @@ packages: resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} engines: {node: '>=12'} - css-tree@3.2.1: - resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} @@ -5192,10 +5196,6 @@ packages: resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} engines: {node: '>=18'} - cssstyle@6.2.0: - resolution: {integrity: sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==} - engines: {node: '>=20'} - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -5213,10 +5213,6 @@ packages: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} - data-urls@7.0.0: - resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -5836,6 +5832,14 @@ packages: eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + eventsource-parser@3.0.6: + 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@7.2.0: resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} @@ -5844,10 +5848,20 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + express-rate-limit@8.2.1: + resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + express@4.21.2: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -5945,6 +5959,10 @@ packages: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-nearest-file@1.1.0: resolution: {integrity: sha512-NMsS0ITOwpBPrHOyO7YUtDhaVEGUKS0kBJDVaWZPuCzO7JMW+uzFQQVts/gPyIV9ioyNWDb5LjhHWXVf1OnBDA==} @@ -6035,6 +6053,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + front-matter@4.0.2: resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==} @@ -6333,6 +6355,10 @@ packages: headers-polyfill@4.0.3: resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + hono@4.12.3: + resolution: {integrity: sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg==} + engines: {node: '>=16.9.0'} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -6348,10 +6374,6 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -6366,6 +6388,10 @@ packages: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + 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'} @@ -6479,6 +6505,19 @@ packages: react-devtools-core: optional: true + ink@5.2.1: + resolution: {integrity: sha512-BqcUyWrG9zq5HIwW6JcfFHsIYebJkWWb4fczNah1goUO0vv5vneIlfwuS85twyJ5hYR/y18FlAYUxrO9ChIWVg==} + engines: {node: '>=18'} + peerDependencies: + '@types/react': 18.3.12 + react: '>=18.0.0' + react-devtools-core: ^4.19.1 + peerDependenciesMeta: + '@types/react': + optional: true + react-devtools-core: + optional: true + ink@6.2.0: resolution: {integrity: sha512-NQbNokT11cuxlIcCDfBMk1vEwaqc/cjTSqc4R4JugBO4BpWVe2B2A6ElC2koZQ9Vj91z0C40zid/jxOF2hJL9A==} engines: {node: '>=20'} @@ -6503,6 +6542,10 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ip-address@10.0.1: + resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -6676,6 +6719,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -6830,6 +6876,9 @@ packages: jose@5.9.6: resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -6857,15 +6906,6 @@ packages: canvas: optional: true - jsdom@28.1.0: - resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -6990,6 +7030,11 @@ packages: linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + liquidjs@10.20.1: + resolution: {integrity: sha512-eZ33jfxjj0It8tkY+I4gbKWfXvMmOvQvvraxVFSLcTjZWCjdWMLBnevk48qw9AQIwIHFp58vZc59vH9Qwdq7mw==} + engines: {node: '>=14'} + hasBin: true + liquidjs@10.25.0: resolution: {integrity: sha512-XpO7AiGULTG4xcTlwkcTI5JreFG7b6esLCLp+aUSh7YuQErJZEoUXre9u9rbdb0057pfWG4l0VursvLd5Q/eAw==} engines: {node: '>=16'} @@ -7148,9 +7193,6 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - mdn-data@2.27.1: - resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} @@ -7158,6 +7200,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + meow@6.1.1: resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} engines: {node: '>=8'} @@ -7165,6 +7211,10 @@ packages: merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + 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==} @@ -7193,10 +7243,18 @@ packages: 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'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -7231,19 +7289,23 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + minimatch@10.2.3: + resolution: {integrity: sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==} + engines: {node: 18 || 20 || >=22} + minimatch@10.2.4: resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@3.1.4: + resolution: {integrity: sha512-twmL+S8+7yIsE9wsqgzU3E8/LumN3M3QELrBZ20OdmQ9jB2JvW5oZtBEmft84k/Gs5CG9mqtWc6Y9vW+JEzGxw==} - minimatch@5.1.9: - resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + minimatch@5.1.8: + resolution: {integrity: sha512-7RN35vit8DeBclkofOVmBY0eDAZZQd1HzmukRdSyz95CRh8FT54eqnbj0krQr3mrHR6sfRyYkyhwBWjoV5uqlQ==} engines: {node: '>=10'} - minimatch@7.4.9: - resolution: {integrity: sha512-Brg/fp/iAVDOQoHxkuN5bEYhyQlZhxddI78yWsCbeEwTHXQjlNLtiJDUsp1GIptVqMI7/gkJMz4vVAc01mpoBw==} + minimatch@7.4.8: + resolution: {integrity: sha512-RF6JWsI+7ecN51cfjtARMkIQoJxVeo3MIPKebcjf3J+mvrsbEHuHIDnPmu3FivgmWtTSsZI29wFH5TGeyqWC0g==} engines: {node: '>=10'} minimatch@9.0.3: @@ -7349,6 +7411,10 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + network-interfaces@1.1.0: resolution: {integrity: sha512-fBk/Cm/RminFKhyUYKolI5nWI2de1m0pHlikz1mnTDbbe/1d2+ti+x/pWlOYuK8o/9p9vyK912+66h2NXGNUwQ==} @@ -7733,9 +7799,6 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - parse5@8.0.0: - resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -7801,6 +7864,9 @@ packages: path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -7851,6 +7917,10 @@ packages: resolution: {integrity: sha512-LFDwmhyWLBnmwO/2UFbWu1jEGVDzaPupaVdx0XcZ3tIAx1EDEBauzxXf2S0UcFK7oe+X9MApjH0hx9U1XMgfCA==} hasBin: true + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@5.0.0: resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} engines: {node: '>=10'} @@ -7969,6 +8039,10 @@ packages: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -8004,6 +8078,10 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} 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==} hasBin: true @@ -8284,6 +8362,10 @@ packages: 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'} + rrweb-cssom@0.7.1: resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} @@ -8360,6 +8442,10 @@ packages: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + sentence-case@3.0.4: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} @@ -8371,6 +8457,10 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -8439,6 +8529,9 @@ packages: signedsource@1.0.0: resolution: {integrity: sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww==} + simple-git@3.27.0: + resolution: {integrity: sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==} + simple-git@3.32.3: resolution: {integrity: sha512-56a5oxFdWlsGygOXHWrG+xjj5w9ZIt2uQbzqiIGdR/6i5iococ7WQ/bNPzWxCJdEUGUCmyMH0t9zMpRJTaKxmw==} @@ -8810,9 +8903,6 @@ packages: tldts-core@7.0.23: resolution: {integrity: sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==} - tldts-core@7.0.25: - resolution: {integrity: sha512-ZjCZK0rppSBu7rjHYDYsEaMOIbbT+nWF57hKkv4IUmZWBNrBWBOjIElc0mKRgLM8bm7x/BBlof6t2gi/Oq/Asw==} - tldts@6.1.86: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true @@ -8821,10 +8911,6 @@ packages: resolution: {integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==} hasBin: true - tldts@7.0.25: - resolution: {integrity: sha512-keinCnPbwXEUG3ilrWQZU+CqcTTzHq9m2HhoUP2l7Xmi8l1LuijAXLpAJ5zRW+ifKTNscs4NdCkfkDCBYm352w==} - hasBin: true - tmp@0.2.5: resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} engines: {node: '>=14.14'} @@ -8851,10 +8937,6 @@ packages: resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} engines: {node: '>=16'} - tough-cookie@6.0.1: - resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} - engines: {node: '>=16'} - tr46@5.1.1: resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} engines: {node: '>=18'} @@ -8969,6 +9051,10 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -9049,10 +9135,6 @@ packages: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} - undici@7.24.0: - resolution: {integrity: sha512-jxytwMHhsbdpBXxLAcuu0fzlQeXCNnWdDyRHpvWsUl8vd98UwYdl9YTyn8/HcpcJPC3pwUveefsa3zTxyD/ERg==} - engines: {node: '>=20.18.1'} - unenv@1.10.0: resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==} @@ -9278,10 +9360,6 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - webidl-conversions@8.0.1: - resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} - engines: {node: '>=20'} - whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -9291,10 +9369,6 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-mimetype@5.0.0: - resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} - engines: {node: '>=20'} - whatwg-url@14.0.0: resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} engines: {node: '>=18'} @@ -9477,19 +9551,27 @@ packages: resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} engines: {node: '>= 10'} + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + peerDependencies: + zod: ^3.25 || ^4 + zod-validation-error@3.5.4: resolution: {integrity: sha512-+hEiRIiPobgyuFlEojnqjJnhFvg4r/i3cqgcm67eehZf/WBaK3g6cD02YU9mtdVxZjv8CzCA9n/Rhrs3yAAvAw==} engines: {node: '>=18.0.0'} peerDependencies: zod: ^3.24.4 + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + zod@3.24.4: resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} -snapshots: + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - '@acemir/cssom@0.9.31': - optional: true +snapshots: '@actions/core@1.11.1': dependencies: @@ -9549,27 +9631,6 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 10.4.3 - '@asamuzakjp/css-color@5.0.1': - dependencies: - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - lru-cache: 11.2.6 - optional: true - - '@asamuzakjp/dom-selector@6.8.1': - dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.2.1 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.6 - optional: true - - '@asamuzakjp/nwsapi@2.3.9': - optional: true - '@ast-grep/napi-darwin-arm64@0.33.0': optional: true @@ -10887,11 +10948,6 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@bramus/specificity@2.4.2': - dependencies: - css-tree: 3.2.1 - optional: true - '@bugsnag/browser@8.8.1': dependencies: '@bugsnag/core': 8.8.0 @@ -11085,20 +11141,11 @@ snapshots: '@csstools/color-helpers@5.1.0': {} - '@csstools/color-helpers@6.0.2': - optional: true - '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true - '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/color-helpers': 5.1.0 @@ -11106,31 +11153,12 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true - '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-tokenizer': 4.0.0 - optional: true - - '@csstools/css-syntax-patches-for-csstree@1.1.0': - optional: true - '@csstools/css-tokenizer@3.0.4': {} - '@csstools/css-tokenizer@4.0.0': - optional: true - '@cucumber/ci-environment@13.0.0': {} '@cucumber/cucumber-expressions@19.0.0': @@ -11459,7 +11487,7 @@ snapshots: dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.0(supports-color@8.1.1) - minimatch: 3.1.5 + minimatch: 3.1.4 transitivePeerDependencies: - supports-color @@ -11480,7 +11508,7 @@ snapshots: ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 - minimatch: 3.1.5 + minimatch: 3.1.4 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color @@ -11494,9 +11522,6 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@exodus/bytes@1.15.0': - optional: true - '@fastify/busboy@2.1.1': {} '@fastify/busboy@3.2.0': {} @@ -12062,6 +12087,10 @@ snapshots: dependencies: graphql: 16.10.0 + '@hono/node-server@1.19.9(hono@4.12.3)': + dependencies: + hono: 4.12.3 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -12351,6 +12380,28 @@ snapshots: '@microsoft/tsdoc@0.15.1': {} + '@modelcontextprotocol/sdk@1.27.1(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.9(hono@4.12.3) + 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.2.1(express@5.2.1) + hono: 4.12.3 + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + transitivePeerDependencies: + - supports-color + '@mswjs/interceptors@0.41.3': dependencies: '@open-draft/deferred-promise': 2.2.0 @@ -12610,7 +12661,7 @@ snapshots: indent-string: 4.0.0 is-wsl: 2.2.0 lilconfig: 3.1.3 - minimatch: 10.2.4 + minimatch: 10.2.3 semver: 7.7.4 string-width: 4.2.3 supports-color: 8.1.1 @@ -13187,13 +13238,87 @@ snapshots: - react - react-dom - '@shopify/eslint-plugin-cli@file:packages/eslint-plugin-cli(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@shopify/cli-kit@3.91.0(@types/react@18.3.12)': + dependencies: + '@apidevtools/json-schema-ref-parser': 11.7.3 + '@bugsnag/js': 8.6.0 + '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) + '@iarna/toml': 2.2.5 + '@oclif/core': 4.5.3 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.30.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 1.30.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.28.0 + '@types/archiver': 5.3.2 + ajv: 8.17.1 + ansi-escapes: 6.2.1 + archiver: 5.3.2 + bottleneck: 2.19.5 + brotli: 1.3.3 + chalk: 5.4.1 + change-case: 4.1.2 + color-json: 3.0.5 + commondir: 1.0.1 + conf: 11.0.2 + deepmerge: 4.3.1 + del: 6.1.1 + dotenv: 16.4.7 + env-paths: 3.0.0 + execa: 7.2.0 + fast-glob: 3.3.3 + figures: 5.0.0 + find-up: 6.3.0 + form-data: 4.0.4 + fs-extra: 11.1.0 + get-port-please: 3.1.2 + gradient-string: 2.0.2 + graphql: 16.10.0 + graphql-request: 6.1.0(graphql@16.10.0) + ignore: 6.0.2 + ink: 5.2.1(@types/react@18.3.12)(react@18.3.1) + is-executable: 2.0.1 + is-interactive: 2.0.0 + is-wsl: 3.1.0 + jose: 5.9.6 + latest-version: 7.0.0 + liquidjs: 10.20.1 + lodash: 4.17.23 + macaddress: 0.5.3 + minimatch: 9.0.5 + mrmime: 1.0.1 + network-interfaces: 1.1.0 + node-abort-controller: 3.1.1 + node-fetch: 3.3.2 + open: 8.4.2 + pathe: 1.1.2 + react: 18.3.1 + semver: 7.6.3 + simple-git: 3.27.0 + stacktracey: 2.1.8 + strip-ansi: 7.1.0 + supports-hyperlinks: 3.1.0 + tempy: 3.1.0 + terminal-link: 3.0.0 + ts-error: 1.0.6 + which: 4.0.0 + zod: 3.24.1 + transitivePeerDependencies: + - '@types/react' + - bufferutil + - encoding + - react-devtools-core + - supports-color + - utf-8-validate + + '@shopify/eslint-plugin-cli@file:packages/eslint-plugin-cli(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': dependencies: '@babel/core': 7.27.4 '@shopify/eslint-plugin': 50.0.0(@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3) '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) - '@vitest/eslint-plugin': 1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + '@vitest/eslint-plugin': 1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) debug: 4.4.0(supports-color@8.1.1) eslint: 9.39.3(jiti@2.6.1) eslint-config-prettier: 10.1.5(eslint@9.39.3(jiti@2.6.1)) @@ -13753,6 +13878,16 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.7(@types/react@18.3.12) + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@18.3.12))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.28.6 + '@testing-library/dom': 10.4.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 19.2.3(@types/react@18.3.12) + '@theguild/federation-composition@0.21.3(graphql@16.10.0)': dependencies: constant-case: 3.0.4 @@ -13766,14 +13901,14 @@ snapshots: '@ts-morph/common@0.18.1': dependencies: fast-glob: 3.3.3 - minimatch: 5.1.9 + minimatch: 5.1.8 mkdirp: 1.0.4 path-browserify: 1.0.1 '@ts-morph/common@0.21.0': dependencies: fast-glob: 3.3.3 - minimatch: 7.4.9 + minimatch: 7.4.8 mkdirp: 2.1.6 path-browserify: 1.0.1 @@ -14042,7 +14177,7 @@ snapshots: '@typescript-eslint/types': 8.56.1 '@typescript-eslint/visitor-keys': 8.56.1 debug: 4.4.3(supports-color@8.1.1) - minimatch: 10.2.4 + minimatch: 10.2.3 semver: 7.7.4 tinyglobby: 0.2.15 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -14125,7 +14260,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-react@5.1.4(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2))': + '@vitejs/plugin-react@5.2.0(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -14137,7 +14272,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': dependencies: '@istanbuljs/schema': 0.1.3 debug: 4.4.3(supports-color@8.1.1) @@ -14149,11 +14284,11 @@ snapshots: magicast: 0.3.5 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + vitest: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0))': + '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0))': dependencies: '@istanbuljs/schema': 0.1.3 debug: 4.4.3(supports-color@8.1.1) @@ -14165,11 +14300,11 @@ snapshots: magicast: 0.3.5 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0) + vitest: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0) transitivePeerDependencies: - supports-color - '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': dependencies: '@istanbuljs/schema': 0.1.3 debug: 4.4.3(supports-color@8.1.1) @@ -14181,25 +14316,25 @@ snapshots: magicast: 0.3.5 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + vitest: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/eslint-plugin@1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@vitest/eslint-plugin@1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': dependencies: '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.3(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + vitest: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) - '@vitest/eslint-plugin@1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@vitest/eslint-plugin@1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': dependencies: '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.3(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + vitest: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) '@vitest/expect@3.2.4': dependencies: @@ -14294,6 +14429,11 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -14317,6 +14457,10 @@ snapshots: optionalDependencies: ajv: 8.18.0 + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 @@ -14331,6 +14475,13 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 @@ -14627,11 +14778,6 @@ snapshots: dependencies: is-windows: 1.0.2 - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - optional: true - binary-extensions@2.3.0: {} bl@4.1.0: @@ -14657,6 +14803,20 @@ snapshots: transitivePeerDependencies: - supports-color + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3(supports-color@8.1.1) + 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 + boolean@3.2.0: {} bottleneck@2.19.5: {} @@ -14672,7 +14832,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.4: + brace-expansion@5.0.3: dependencies: balanced-match: 4.0.4 @@ -15068,6 +15228,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-disposition@1.0.1: {} + content-type@1.0.5: {} convert-source-map@2.0.0: {} @@ -15080,6 +15242,8 @@ snapshots: cookie-signature@1.0.6: {} + cookie-signature@1.2.2: {} + cookie@0.7.1: {} cookie@1.1.1: {} @@ -15094,6 +15258,11 @@ snapshots: core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cosmiconfig@7.1.0: dependencies: '@types/parse-json': 4.0.2 @@ -15161,12 +15330,6 @@ snapshots: dependencies: type-fest: 1.4.0 - css-tree@3.2.1: - dependencies: - mdn-data: 2.27.1 - source-map-js: 1.2.1 - optional: true - css.escape@1.5.1: {} cssstyle@4.6.0: @@ -15174,14 +15337,6 @@ snapshots: '@asamuzakjp/css-color': 3.2.0 rrweb-cssom: 0.8.0 - cssstyle@6.2.0: - dependencies: - '@asamuzakjp/css-color': 5.0.1 - '@csstools/css-syntax-patches-for-csstree': 1.1.0 - css-tree: 3.2.1 - lru-cache: 11.2.6 - optional: true - csstype@3.2.3: {} damerau-levenshtein@1.0.8: {} @@ -15195,12 +15350,6 @@ snapshots: whatwg-mimetype: 4.0.0 whatwg-url: 14.0.0 - data-urls@7.0.0: - dependencies: - whatwg-mimetype: 5.0.0 - whatwg-url: 14.0.0 - optional: true - data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -15748,7 +15897,7 @@ snapshots: hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 - minimatch: 3.1.5 + minimatch: 3.1.4 object.fromentries: 2.0.8 safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 @@ -15811,7 +15960,7 @@ snapshots: estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 - minimatch: 3.1.5 + minimatch: 3.1.4 object.entries: 1.1.9 object.fromentries: 2.0.8 object.values: 1.2.1 @@ -15880,7 +16029,7 @@ snapshots: is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - minimatch: 3.1.5 + minimatch: 3.1.4 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -15924,6 +16073,12 @@ snapshots: eventemitter3@5.0.4: {} + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + execa@7.2.0: dependencies: cross-spawn: 7.0.6 @@ -15938,6 +16093,11 @@ snapshots: expect-type@1.3.0: {} + express-rate-limit@8.2.1(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.0.1 + express@4.21.2: dependencies: accepts: 1.3.8 @@ -15974,6 +16134,39 @@ snapshots: transitivePeerDependencies: - supports-color + 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.1 + cookie-signature: 1.2.2 + debug: 4.4.0(supports-color@8.1.1) + 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 + extendable-error@0.1.7: {} fast-content-type-parse@2.0.1: {} @@ -16062,7 +16255,7 @@ snapshots: filelist@1.0.5: dependencies: - minimatch: 10.2.4 + minimatch: 10.2.3 fill-range@7.1.1: dependencies: @@ -16080,6 +16273,17 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@2.1.1: + dependencies: + debug: 4.4.0(supports-color@8.1.1) + 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-nearest-file@1.1.0: {} find-replace@3.0.0: @@ -16167,6 +16371,8 @@ snapshots: fresh@0.5.2: {} + fresh@2.0.0: {} + front-matter@4.0.2: dependencies: js-yaml: 3.14.2 @@ -16307,7 +16513,7 @@ snapshots: glob@13.0.6: dependencies: - minimatch: 10.2.4 + minimatch: 10.2.3 minipass: 7.1.3 path-scurry: 2.0.2 @@ -16316,7 +16522,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.5 + minimatch: 3.1.4 once: 1.4.0 path-is-absolute: 1.0.1 @@ -16325,7 +16531,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.9 + minimatch: 5.1.8 once: 1.4.0 global-agent@3.0.0: @@ -16550,6 +16756,8 @@ snapshots: headers-polyfill@4.0.3: {} + hono@4.12.3: {} + hosted-git-info@2.8.9: {} hosted-git-info@7.0.2: @@ -16564,13 +16772,6 @@ snapshots: dependencies: whatwg-encoding: 3.1.1 - html-encoding-sniffer@6.0.0: - dependencies: - '@exodus/bytes': 1.15.0 - transitivePeerDependencies: - - '@noble/hashes' - optional: true - html-escaper@2.0.2: {} http-cache-semantics@4.2.0: {} @@ -16594,6 +16795,14 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + 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 @@ -16710,6 +16919,39 @@ snapshots: - bufferutil - utf-8-validate + ink@5.2.1(@types/react@18.3.12)(react@18.3.1): + dependencies: + '@alcalzone/ansi-tokenize': 0.1.3 + ansi-escapes: 7.3.0 + ansi-styles: 6.2.3 + auto-bind: 5.0.1 + chalk: 5.4.1 + cli-boxes: 3.0.0 + cli-cursor: 4.0.0 + cli-truncate: 4.0.0 + code-excerpt: 4.0.0 + es-toolkit: 1.44.0 + indent-string: 5.0.0 + is-in-ci: 1.0.0 + patch-console: 2.0.0 + react: 18.3.1 + react-reconciler: 0.29.2(react@18.3.1) + scheduler: 0.23.2 + signal-exit: 3.0.7 + slice-ansi: 7.1.2 + stack-utils: 2.0.6 + string-width: 7.2.0 + type-fest: 4.41.0 + widest-line: 5.0.0 + wrap-ansi: 9.0.2 + ws: 8.18.0 + yoga-layout: 3.2.1 + optionalDependencies: + '@types/react': 18.3.12 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + ink@6.2.0(@types/react@18.3.12)(react@19.2.4): dependencies: '@alcalzone/ansi-tokenize': 0.1.3 @@ -16755,6 +16997,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + ip-address@10.0.1: {} + ipaddr.js@1.9.1: {} iron-webcrypto@1.2.1: {} @@ -16896,6 +17140,8 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -17058,6 +17304,8 @@ snapshots: jose@5.9.6: {} + jose@6.1.3: {} + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -17101,34 +17349,6 @@ snapshots: - supports-color - utf-8-validate - jsdom@28.1.0: - dependencies: - '@acemir/cssom': 0.9.31 - '@asamuzakjp/dom-selector': 6.8.1 - '@bramus/specificity': 2.4.2 - '@exodus/bytes': 1.15.0 - cssstyle: 6.2.0 - data-urls: 7.0.0 - decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - is-potential-custom-element-name: 1.0.1 - parse5: 8.0.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.1 - undici: 7.24.0 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.1 - whatwg-mimetype: 5.0.0 - whatwg-url: 14.0.0 - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - '@noble/hashes' - - supports-color - optional: true - jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -17219,8 +17439,8 @@ snapshots: smol-toml: 1.6.0 strip-json-comments: 5.0.1 typescript: 5.9.3 - zod: 3.24.4 - zod-validation-error: 3.5.4(zod@3.24.4) + zod: 3.25.76 + zod-validation-error: 3.5.4(zod@3.25.76) knuth-shuffle-seeded@1.0.6: dependencies: @@ -17260,6 +17480,10 @@ snapshots: dependencies: uc.micro: 2.1.0 + liquidjs@10.20.1: + dependencies: + commander: 10.0.1 + liquidjs@10.25.0: dependencies: commander: 10.0.1 @@ -17401,13 +17625,12 @@ snapshots: math-intrinsics@1.1.0: {} - mdn-data@2.27.1: - optional: true - mdurl@2.0.0: {} media-typer@0.3.0: {} + media-typer@1.1.0: {} + meow@6.1.1: dependencies: '@types/minimist': 1.2.5 @@ -17424,6 +17647,8 @@ snapshots: merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -17446,10 +17671,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 + mime@1.6.0: {} mime@3.0.0: {} @@ -17466,19 +17697,23 @@ snapshots: min-indent@1.0.1: {} + minimatch@10.2.3: + dependencies: + brace-expansion: 5.0.3 + minimatch@10.2.4: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 5.0.3 - minimatch@3.1.5: + minimatch@3.1.4: dependencies: brace-expansion: 1.1.12 - minimatch@5.1.9: + minimatch@5.1.8: dependencies: brace-expansion: 2.0.2 - minimatch@7.4.9: + minimatch@7.4.8: dependencies: brace-expansion: 2.0.2 @@ -17492,7 +17727,7 @@ snapshots: minimatch@9.0.8: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 5.0.3 minimist-options@4.1.0: dependencies: @@ -17595,6 +17830,8 @@ snapshots: negotiator@0.6.3: {} + negotiator@1.0.0: {} + network-interfaces@1.1.0: {} no-case@3.0.4: @@ -18043,11 +18280,6 @@ snapshots: dependencies: entities: 6.0.1 - parse5@8.0.0: - dependencies: - entities: 6.0.1 - optional: true - parseurl@1.3.3: {} pascal-case@3.1.2: @@ -18101,6 +18333,8 @@ snapshots: path-to-regexp@6.3.0: {} + path-to-regexp@8.3.0: {} + path-type@4.0.0: {} pathe@1.1.1: {} @@ -18152,6 +18386,8 @@ snapshots: quick-format-unescaped: 1.1.2 split2: 2.2.0 + pkce-challenge@5.0.1: {} + pkg-dir@5.0.0: dependencies: find-up: 5.0.0 @@ -18274,6 +18510,10 @@ snapshots: dependencies: side-channel: 1.1.0 + qs@6.15.0: + dependencies: + side-channel: 1.1.0 + quansync@0.2.11: {} queue-microtask@1.2.3: {} @@ -18301,6 +18541,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 @@ -18439,7 +18686,7 @@ snapshots: readdir-glob@1.1.3: dependencies: - minimatch: 5.1.9 + minimatch: 5.1.8 readdirp@3.6.0: dependencies: @@ -18644,6 +18891,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.0(supports-color@8.1.1) + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.3.0 + transitivePeerDependencies: + - supports-color + rrweb-cssom@0.7.1: {} rrweb-cssom@0.8.0: {} @@ -18727,6 +18984,22 @@ snapshots: transitivePeerDependencies: - supports-color + send@1.2.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + 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 + sentence-case@3.0.4: dependencies: no-case: 3.0.4 @@ -18746,6 +19019,15 @@ snapshots: transitivePeerDependencies: - supports-color + 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-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -18824,6 +19106,14 @@ snapshots: signedsource@1.0.0: {} + simple-git@3.27.0: + dependencies: + '@kwsites/file-exists': 1.1.1 + '@kwsites/promise-deferred': 1.1.1 + debug: 4.4.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + simple-git@3.32.3: dependencies: '@kwsites/file-exists': 1.1.1 @@ -19187,7 +19477,7 @@ snapshots: dependencies: '@istanbuljs/schema': 0.1.3 glob: 10.5.0 - minimatch: 10.2.4 + minimatch: 10.2.3 thenify-all@1.6.0: dependencies: @@ -19238,9 +19528,6 @@ snapshots: tldts-core@7.0.23: {} - tldts-core@7.0.25: - optional: true - tldts@6.1.86: dependencies: tldts-core: 6.1.86 @@ -19249,11 +19536,6 @@ snapshots: dependencies: tldts-core: 7.0.23 - tldts@7.0.25: - dependencies: - tldts-core: 7.0.25 - optional: true - tmp@0.2.5: {} to-regex-range@5.0.1: @@ -19274,11 +19556,6 @@ snapshots: dependencies: tldts: 7.0.23 - tough-cookie@6.0.1: - dependencies: - tldts: 7.0.25 - optional: true - tr46@5.1.1: dependencies: punycode: 2.3.1 @@ -19375,6 +19652,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -19463,9 +19746,6 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - undici@7.24.0: - optional: true - unenv@1.10.0: dependencies: consola: 3.4.2 @@ -19684,7 +19964,7 @@ snapshots: sass: 1.97.3 yaml: 2.8.2 - vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2): + vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 @@ -19711,7 +19991,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 18.19.70 - jsdom: 28.1.0 + jsdom: 25.0.1 transitivePeerDependencies: - jiti - less @@ -19726,7 +20006,7 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0): + vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 @@ -19753,7 +20033,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.11 - jsdom: 28.1.0 + jsdom: 25.0.1 transitivePeerDependencies: - jiti - less @@ -19768,7 +20048,7 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2): + vitest@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(jsdom@25.0.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 @@ -19795,7 +20075,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.11 - jsdom: 28.1.0 + jsdom: 25.0.1 transitivePeerDependencies: - jiti - less @@ -19858,18 +20138,12 @@ snapshots: webidl-conversions@7.0.0: {} - webidl-conversions@8.0.1: - optional: true - whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 whatwg-mimetype@4.0.0: {} - whatwg-mimetype@5.0.0: - optional: true - whatwg-url@14.0.0: dependencies: tr46: 5.1.1 @@ -20040,8 +20314,16 @@ snapshots: compress-commons: 4.1.2 readable-stream: 3.6.2 - zod-validation-error@3.5.4(zod@3.24.4): + zod-to-json-schema@3.25.1(zod@3.25.76): dependencies: - zod: 3.24.4 + zod: 3.25.76 + + zod-validation-error@3.5.4(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.24.1: {} zod@3.24.4: {} + + zod@3.25.76: {} From e78400a78f0c17e5513c71320b05f31fce0783cc Mon Sep 17 00:00:00 2001 From: Jeremy Gayed Date: Mon, 2 Mar 2026 09:54:38 -0500 Subject: [PATCH 2/2] Add README for @shopify/mcp package Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 14 ++++ packages/cli-kit/src/public/node/mcp.ts | 2 +- packages/mcp/README.md | 50 ++++++++++++++ packages/mcp/package.json | 5 +- packages/mcp/src/tools/graphql.test.ts | 14 +++- packages/mcp/src/tools/graphql.ts | 4 +- pnpm-lock.yaml | 89 ++++++++----------------- 7 files changed, 112 insertions(+), 66 deletions(-) create mode 100644 packages/mcp/README.md diff --git a/package.json b/package.json index 3f6434c728a..049238821e5 100644 --- a/package.json +++ b/package.json @@ -253,6 +253,20 @@ ] } }, + "packages/mcp": { + "entry": [ + "**/src/index.ts!" + ], + "project": "**/*.ts!", + "ignoreDependencies": [ + "zod-to-json-schema" + ], + "vite": { + "config": [ + "vite.config.ts" + ] + } + }, "packages/plugin-did-you-mean": { "entry": [ "**/{commands,hooks}/**/*.ts!", diff --git a/packages/cli-kit/src/public/node/mcp.ts b/packages/cli-kit/src/public/node/mcp.ts index 8d62ad39e27..c77d6ccb5e5 100644 --- a/packages/cli-kit/src/public/node/mcp.ts +++ b/packages/cli-kit/src/public/node/mcp.ts @@ -28,7 +28,7 @@ export async function requestDeviceCode(): Promise { const fqdn = await identityFqdn() const identityClientId = clientId() const scopes = allDefaultScopes() - const params = `client_id=${identityClientId}&scope=${scopes.join(' ')}` + const params = new URLSearchParams({client_id: identityClientId, scope: scopes.join(' ')}).toString() const url = `https://${fqdn}/oauth/device_authorization` const response = await shopifyFetch(url, { diff --git a/packages/mcp/README.md b/packages/mcp/README.md new file mode 100644 index 00000000000..ba91abb7765 --- /dev/null +++ b/packages/mcp/README.md @@ -0,0 +1,50 @@ +# @shopify/mcp + +MCP server for the Shopify Admin API. Connects AI coding agents (Claude, Cursor, etc.) to your Shopify store via the [Model Context Protocol](https://modelcontextprotocol.io). + +## Setup + +```bash +claude mcp add shopify -- npx -y -p @shopify/mcp +``` + +Optionally set a default store so you don't have to pass it with every request: + +```bash +export SHOPIFY_FLAG_STORE=my-store.myshopify.com +``` + +## Tools + +### `shopify_auth_login` + +Authenticate with a Shopify store. Returns a URL the user must visit to complete login via device auth. After approval, subsequent `shopify_graphql` calls will use the session automatically. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `store` | string | No | Store domain. Defaults to `SHOPIFY_FLAG_STORE` env var. | + +### `shopify_graphql` + +Execute a GraphQL query or mutation against the Shopify Admin API. Uses the latest supported API version. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `query` | string | Yes | GraphQL query or mutation string | +| `variables` | object | No | GraphQL variables | +| `store` | string | No | Store domain override. Defaults to `SHOPIFY_FLAG_STORE` env var. | +| `allowMutations` | boolean | No | Must be `true` to execute mutations. Safety measure to prevent unintended changes. | + +## Example + +``` +Agent: "List my products" + +→ shopify_auth_login(store: "my-store.myshopify.com") +← "Open this URL to authenticate: https://accounts.shopify.com/activate?user_code=ABCD-EFGH" + +[user approves in browser] + +→ shopify_graphql(query: "{ products(first: 5) { edges { node { title } } } }") +← { "products": { "edges": [{ "node": { "title": "T-Shirt" } }, ...] } } +``` diff --git a/packages/mcp/package.json b/packages/mcp/package.json index e3ba4606949..4fcbfaff082 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -48,9 +48,10 @@ ] }, "dependencies": { - "@modelcontextprotocol/sdk": "1.27.1", + "@modelcontextprotocol/sdk": "1.22.0", "@shopify/cli-kit": "3.91.0", - "zod": "3.25.76" + "zod": "3.24.1", + "zod-to-json-schema": "3.24.5" }, "devDependencies": { "@vitest/coverage-istanbul": "^3.1.4" diff --git a/packages/mcp/src/tools/graphql.test.ts b/packages/mcp/src/tools/graphql.test.ts index bf8df1c63ab..a17cde27d3c 100644 --- a/packages/mcp/src/tools/graphql.test.ts +++ b/packages/mcp/src/tools/graphql.test.ts @@ -140,13 +140,25 @@ describe('handleGraphql', () => { expect(result.content[0]!.text).toContain('allowMutations') }) + test('detects mutations after a query in multi-operation document', async () => { + process.env.SHOPIFY_FLAG_STORE = 'test.myshopify.com' + const sm = createMockSessionManager() + const result = await handleGraphql(sm, { + query: 'query { shop { name } }\nmutation { productDelete(input: {id: "1"}) { deletedProductId } }', + allowMutations: false, + }) + expect(result.isError).toBe(true) + expect(result.content[0]!.text).toContain('allowMutations') + }) + test('mutation pattern detection', () => { - const pattern = /^\s*mutation[\s({]/i + const pattern = /(?:^|\n)\s*mutation[\s({]/i expect(pattern.test('mutation { shop { name } }')).toBe(true) expect(pattern.test(' mutation CreateProduct($input: ProductInput!) { }')).toBe(true) expect(pattern.test('mutation(')).toBe(true) expect(pattern.test('MUTATION { }')).toBe(true) expect(pattern.test('Mutation { }')).toBe(true) + expect(pattern.test('query { shop { name } }\nmutation { }')).toBe(true) expect(pattern.test('query { shop { name } }')).toBe(false) expect(pattern.test('{ shop { name } }')).toBe(false) expect(pattern.test('query GetMutationResults { }')).toBe(false) diff --git a/packages/mcp/src/tools/graphql.ts b/packages/mcp/src/tools/graphql.ts index 26de5045dcd..a5a2ee778e9 100644 --- a/packages/mcp/src/tools/graphql.ts +++ b/packages/mcp/src/tools/graphql.ts @@ -5,7 +5,7 @@ import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js' import {z} from 'zod' import {adminRequest} from '@shopify/cli-kit/node/api/admin' -const MUTATION_PATTERN = /^\s*mutation[\s({]/i +const MUTATION_PATTERN = /(?:^|\n)\s*mutation[\s({]/i export async function handleGraphql( sessionManager: SessionManager, @@ -19,7 +19,7 @@ export async function handleGraphql( } } - const stripped = params.query.replace(/^\s*(#[^\n]*\n)*/g, '') + const stripped = params.query.replace(/#[^\n]*/g, '') if (MUTATION_PATTERN.test(stripped) && !params.allowMutations) { return { content: [{type: 'text', text: 'Error: Mutations require allowMutations: true. This is a safety measure to prevent unintended changes.'}], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 469c02fdf67..f1a6e603652 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -670,14 +670,17 @@ importers: packages/mcp: dependencies: '@modelcontextprotocol/sdk': - specifier: 1.27.1 - version: 1.27.1(zod@3.25.76) + specifier: 1.22.0 + version: 1.22.0 '@shopify/cli-kit': specifier: 3.91.0 version: 3.91.0(@types/react@18.3.12) zod: - specifier: 3.25.76 - version: 3.25.76 + specifier: 3.24.1 + version: 3.24.1 + zod-to-json-schema: + specifier: 3.24.5 + version: 3.24.5(zod@3.24.1) devDependencies: '@vitest/coverage-istanbul': specifier: ^3.1.4 @@ -2584,12 +2587,6 @@ packages: peerDependencies: graphql: 16.10.0 - '@hono/node-server@1.19.9': - resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -2837,12 +2834,11 @@ packages: '@microsoft/tsdoc@0.15.1': resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} - '@modelcontextprotocol/sdk@1.27.1': - resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} + '@modelcontextprotocol/sdk@1.22.0': + resolution: {integrity: sha512-VUpl106XVTCpDmTBil2ehgJZjhyLY2QZikzF8NvTXtLRF1CvO5iEE2UNZdVIUer35vFOwMKYeUGbjJtvPWan3g==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 - zod: ^3.25 || ^4.0 peerDependenciesMeta: '@cfworker/json-schema': optional: true @@ -5848,8 +5844,8 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express-rate-limit@8.2.1: - resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} + express-rate-limit@7.5.1: + resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -6355,10 +6351,6 @@ packages: headers-polyfill@4.0.3: resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} - hono@4.12.3: - resolution: {integrity: sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg==} - engines: {node: '>=16.9.0'} - hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -6542,10 +6534,6 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ip-address@10.0.1: - resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} - engines: {node: '>= 12'} - ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -6876,9 +6864,6 @@ packages: jose@5.9.6: resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} - jose@6.1.3: - resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -9551,10 +9536,10 @@ packages: resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} engines: {node: '>= 10'} - zod-to-json-schema@3.25.1: - resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + zod-to-json-schema@3.24.5: + resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} peerDependencies: - zod: ^3.25 || ^4 + zod: ^3.24.1 zod-validation-error@3.5.4: resolution: {integrity: sha512-+hEiRIiPobgyuFlEojnqjJnhFvg4r/i3cqgcm67eehZf/WBaK3g6cD02YU9mtdVxZjv8CzCA9n/Rhrs3yAAvAw==} @@ -9568,9 +9553,6 @@ packages: zod@3.24.4: resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - snapshots: '@actions/core@1.11.1': @@ -12087,10 +12069,6 @@ snapshots: dependencies: graphql: 16.10.0 - '@hono/node-server@1.19.9(hono@4.12.3)': - dependencies: - hono: 4.12.3 - '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -12380,9 +12358,8 @@ snapshots: '@microsoft/tsdoc@0.15.1': {} - '@modelcontextprotocol/sdk@1.27.1(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.22.0': dependencies: - '@hono/node-server': 1.19.9(hono@4.12.3) ajv: 8.18.0 ajv-formats: 3.0.1(ajv@8.18.0) content-type: 1.0.5 @@ -12391,14 +12368,11 @@ snapshots: eventsource: 3.0.7 eventsource-parser: 3.0.6 express: 5.2.1 - express-rate-limit: 8.2.1(express@5.2.1) - hono: 4.12.3 - jose: 6.1.3 - json-schema-typed: 8.0.2 + express-rate-limit: 7.5.1(express@5.2.1) pkce-challenge: 5.0.1 raw-body: 3.0.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) + zod: 3.24.4 + zod-to-json-schema: 3.24.5(zod@3.24.4) transitivePeerDependencies: - supports-color @@ -16093,10 +16067,9 @@ snapshots: expect-type@1.3.0: {} - express-rate-limit@8.2.1(express@5.2.1): + express-rate-limit@7.5.1(express@5.2.1): dependencies: express: 5.2.1 - ip-address: 10.0.1 express@4.21.2: dependencies: @@ -16756,8 +16729,6 @@ snapshots: headers-polyfill@4.0.3: {} - hono@4.12.3: {} - hosted-git-info@2.8.9: {} hosted-git-info@7.0.2: @@ -16997,8 +16968,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - ip-address@10.0.1: {} - ipaddr.js@1.9.1: {} iron-webcrypto@1.2.1: {} @@ -17304,8 +17273,6 @@ snapshots: jose@5.9.6: {} - jose@6.1.3: {} - js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -17439,8 +17406,8 @@ snapshots: smol-toml: 1.6.0 strip-json-comments: 5.0.1 typescript: 5.9.3 - zod: 3.25.76 - zod-validation-error: 3.5.4(zod@3.25.76) + zod: 3.24.4 + zod-validation-error: 3.5.4(zod@3.24.4) knuth-shuffle-seeded@1.0.6: dependencies: @@ -20314,16 +20281,18 @@ snapshots: compress-commons: 4.1.2 readable-stream: 3.6.2 - zod-to-json-schema@3.25.1(zod@3.25.76): + zod-to-json-schema@3.24.5(zod@3.24.1): dependencies: - zod: 3.25.76 + zod: 3.24.1 + + zod-to-json-schema@3.24.5(zod@3.24.4): + dependencies: + zod: 3.24.4 - zod-validation-error@3.5.4(zod@3.25.76): + zod-validation-error@3.5.4(zod@3.24.4): dependencies: - zod: 3.25.76 + zod: 3.24.4 zod@3.24.1: {} zod@3.24.4: {} - - zod@3.25.76: {}