chore: extract utils folder (#876)

This commit is contained in:
Pavel Feldman
2025-08-12 14:33:00 -07:00
committed by GitHub
parent dbd44110f1
commit c091a11d76
32 changed files with 51 additions and 87 deletions

View File

@@ -1,6 +1,7 @@
[*]
./tools/
./mcp/
./utils/
[program.ts]
***

View File

@@ -23,8 +23,8 @@ import * as playwright from 'playwright';
import { registryDirectory } from 'playwright-core/lib/server/registry/index';
// @ts-ignore
import { startTraceViewerServer } from 'playwright-core/lib/server';
import { logUnhandledError, testDebug } from './log.js';
import { createHash } from './utils.js';
import { logUnhandledError, testDebug } from './utils/log.js';
import { createHash } from './utils/guid.js';
import { outputFile } from './config.js';
import type { FullConfig } from './config.js';

View File

@@ -17,11 +17,11 @@
import { fileURLToPath } from 'url';
import { FullConfig } from './config.js';
import { Context } from './context.js';
import { logUnhandledError } from './log.js';
import { logUnhandledError } from './utils/log.js';
import { Response } from './response.js';
import { SessionLog } from './sessionLog.js';
import { filteredTools } from './tools.js';
import { packageJSON } from './package.js';
import { packageJSON } from './utils/package.js';
import { toToolDefinition } from './tools/tool.js';
import type { Tool } from './tools/tool.js';

View File

@@ -18,7 +18,7 @@ import fs from 'fs';
import os from 'os';
import path from 'path';
import { devices } from 'playwright';
import { sanitizeForFilePath } from './utils.js';
import { sanitizeForFilePath } from './utils/fileUtils.js';
import type { Config, ToolCapability } from '../config.js';
import type { BrowserContextOptions, LaunchOptions } from 'playwright';

View File

@@ -17,7 +17,7 @@
import debug from 'debug';
import * as playwright from 'playwright';
import { logUnhandledError } from './log.js';
import { logUnhandledError } from './utils/log.js';
import { Tab } from './tab.js';
import { outputFile } from './config.js';

View File

@@ -1,3 +1,3 @@
[*]
../
../mcp/
../utils/

View File

@@ -26,9 +26,9 @@ import { spawn } from 'child_process';
import http from 'http';
import debug from 'debug';
import { WebSocket, WebSocketServer } from 'ws';
import { httpAddressToString } from '../httpServer.js';
import { logUnhandledError } from '../log.js';
import { ManualPromise } from '../manualPromise.js';
import { httpAddressToString } from '../utils/httpServer.js';
import { logUnhandledError } from '../utils/log.js';
import { ManualPromise } from '../utils/manualPromise.js';
import type websocket from 'ws';
import type { ClientInfo } from '../browserContextFactory.js';

View File

@@ -16,7 +16,7 @@
import debug from 'debug';
import * as playwright from 'playwright';
import { startHttpServer } from '../httpServer.js';
import { startHttpServer } from '../utils/httpServer.js';
import { CDPRelayServer } from './cdpRelay.js';
import type { BrowserContextFactory, ClientInfo } from '../browserContextFactory.js';

View File

@@ -1,38 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ExtensionContextFactory } from './extensionContextFactory.js';
import { BrowserServerBackend } from '../browserServerBackend.js';
import { InProcessClientFactory } from '../inProcessClient.js';
import * as mcpTransport from '../mcp/transport.js';
import type { FullConfig } from '../config.js';
import type { ClientFactory } from '../mcp/proxyBackend.js';
export async function runWithExtension(config: FullConfig) {
const contextFactory = createExtensionContextFactory(config);
const serverBackendFactory = () => new BrowserServerBackend(config, contextFactory);
await mcpTransport.start(serverBackendFactory, config.server);
}
export function createExtensionClientFactory(config: FullConfig): ClientFactory {
return new InProcessClientFactory(createExtensionContextFactory(config), config);
}
function createExtensionContextFactory(config: FullConfig) {
return new ExtensionContextFactory(config.browser.launchOptions.channel || 'chrome', config.browser.userDataDir);
}

View File

@@ -3,3 +3,4 @@
../loop/
../mcp/
../tools/
../utils/

View File

@@ -18,7 +18,7 @@ import dotenv from 'dotenv';
import * as mcpServer from '../mcp/server.js';
import * as mcpTransport from '../mcp/transport.js';
import { packageJSON } from '../package.js';
import { packageJSON } from '../utils/package.js';
import { Context } from './context.js';
import { perform } from './perform.js';
import { snapshot } from './snapshot.js';

View File

@@ -1,7 +1,2 @@
[*]
../log.js
../manualPromise.js
../httpServer.js
[proxyBackend.ts]
../package.js
../utils/

View File

@@ -18,8 +18,8 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
import { logUnhandledError } from '../log.js';
import { packageJSON } from '../package.js';
import { logUnhandledError } from '../utils/log.js';
import { packageJSON } from '../utils/package.js';
import { ToolDefinition, ServerBackend, ToolResponse } from './server.js';
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';

View File

@@ -17,8 +17,8 @@
import debug from 'debug';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { ManualPromise } from '../manualPromise.js';
import { logUnhandledError } from '../log.js';
import { ManualPromise } from '../utils/manualPromise.js';
import { logUnhandledError } from '../utils/log.js';
import type { ImageContent, TextContent, Tool } from '@modelcontextprotocol/sdk/types.js';
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';

View File

@@ -21,7 +21,7 @@ import debug from 'debug';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { httpAddressToString, startHttpServer } from '../httpServer.js';
import { httpAddressToString, startHttpServer } from '../utils/httpServer.js';
import * as mcpServer from './server.js';
import type { ServerBackendFactory } from './server.js';

View File

@@ -18,17 +18,18 @@ import { program, Option } from 'commander';
import * as mcpTransport from './mcp/transport.js';
import { commaSeparatedList, resolveCLIConfig, semicolonSeparatedList } from './config.js';
import { packageJSON } from './package.js';
import { createExtensionClientFactory, runWithExtension } from './extension/main.js';
import { packageJSON } from './utils/package.js';
import { Context } from './context.js';
import { contextFactory } from './browserContextFactory.js';
import { runLoopTools } from './loopTools/main.js';
import { ProxyBackend } from './mcp/proxyBackend.js';
import { InProcessClientFactory } from './inProcessClient.js';
import { BrowserServerBackend } from './browserServerBackend.js';
import { ExtensionContextFactory } from './extension/extensionContextFactory.js';
import type { ClientFactoryList } from './mcp/proxyBackend.js';
import type { ServerBackendFactory } from './mcp/server.js';
import type { FullConfig } from './config.js';
program
.version('Version ' + packageJSON.version)
@@ -73,7 +74,9 @@ program
const config = await resolveCLIConfig(options);
if (options.extension) {
await runWithExtension(config);
const contextFactory = createExtensionContextFactory(config);
const serverBackendFactory = () => new BrowserServerBackend(config, contextFactory);
await mcpTransport.start(serverBackendFactory, config.server);
return;
}
if (options.loopTools) {
@@ -86,7 +89,7 @@ program
if (options.connectTool) {
const factories: ClientFactoryList = [
new InProcessClientFactory(browserContextFactory, config),
createExtensionClientFactory(config)
new InProcessClientFactory(createExtensionContextFactory(config), config),
];
serverBackendFactory = () => new ProxyBackend(factories);
} else {
@@ -111,4 +114,8 @@ function setupExitWatchdog() {
process.on('SIGTERM', handleExit);
}
function createExtensionContextFactory(config: FullConfig) {
return new ExtensionContextFactory(config.browser.launchOptions.channel || 'chrome', config.browser.userDataDir);
}
void program.parseAsync(process.argv);

View File

@@ -18,7 +18,7 @@ import fs from 'fs';
import path from 'path';
import { Response } from './response.js';
import { logUnhandledError } from './log.js';
import { logUnhandledError } from './utils/log.js';
import { outputFile } from './config.js';
import type { FullConfig } from './config.js';

View File

@@ -17,8 +17,8 @@
import { EventEmitter } from 'events';
import * as playwright from 'playwright';
import { callOnPageNoTrace, waitForCompletion } from './tools/utils.js';
import { logUnhandledError } from './log.js';
import { ManualPromise } from './manualPromise.js';
import { logUnhandledError } from './utils/log.js';
import { ManualPromise } from './utils/manualPromise.js';
import { ModalState } from './tools/tool.js';
import type { Context } from './context.js';

View File

@@ -1,4 +1,2 @@
[*]
../javascript.js
../log.js
../manualPromise.js
../utils/

View File

@@ -17,7 +17,7 @@
import { z } from 'zod';
import { defineTabTool } from './tool.js';
import * as javascript from '../javascript.js';
import * as javascript from '../utils/codegen.js';
import { generateLocator } from './utils.js';
import type * as playwright from 'playwright';

View File

@@ -19,7 +19,7 @@ import { z } from 'zod';
import { defineTabTool } from './tool.js';
import { elementSchema } from './snapshot.js';
import { generateLocator } from './utils.js';
import * as javascript from '../javascript.js';
import * as javascript from '../utils/codegen.js';
const pressKey = defineTabTool({
capability: 'core',

View File

@@ -17,7 +17,7 @@
import { z } from 'zod';
import { defineTabTool } from './tool.js';
import * as javascript from '../javascript.js';
import * as javascript from '../utils/codegen.js';
const pdfSchema = z.object({
filename: z.string().optional().describe('File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.'),

View File

@@ -17,7 +17,7 @@
import { z } from 'zod';
import { defineTabTool } from './tool.js';
import * as javascript from '../javascript.js';
import * as javascript from '../utils/codegen.js';
import { generateLocator } from './utils.js';
import type * as playwright from 'playwright';

View File

@@ -17,7 +17,7 @@
import { z } from 'zod';
import { defineTabTool, defineTool } from './tool.js';
import * as javascript from '../javascript.js';
import * as javascript from '../utils/codegen.js';
import { generateLocator } from './utils.js';
const snapshot = defineTool({

View File

@@ -17,7 +17,7 @@
import os from 'node:os';
import path from 'node:path';
import type { FullConfig } from './config.js';
import type { FullConfig } from '../config.js';
export function cacheDir() {
let cacheDirectory: string;
@@ -35,3 +35,11 @@ export function cacheDir() {
export async function userDataDir(browserConfig: FullConfig['browser']) {
return path.join(cacheDir(), 'ms-playwright', `mcp-${browserConfig.launchOptions?.channel ?? browserConfig?.browserName}-profile`);
}
export function sanitizeForFilePath(s: string) {
const sanitize = (s: string) => s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-');
const separator = s.lastIndexOf('.');
if (separator === -1)
return sanitize(s);
return sanitize(s.substring(0, separator)) + '.' + sanitize(s.substring(separator + 1));
}

View File

@@ -19,11 +19,3 @@ import crypto from 'crypto';
export function createHash(data: string): string {
return crypto.createHash('sha256').update(data).digest('hex').slice(0, 7);
}
export function sanitizeForFilePath(s: string) {
const sanitize = (s: string) => s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-');
const separator = s.lastIndexOf('.');
if (separator === -1)
return sanitize(s);
return sanitize(s.substring(0, separator)) + '.' + sanitize(s.substring(separator + 1));
}

View File

@@ -19,4 +19,4 @@ import path from 'path';
import url from 'url';
const __filename = url.fileURLToPath(import.meta.url);
export const packageJSON = JSON.parse(fs.readFileSync(path.join(path.dirname(__filename), '..', 'package.json'), 'utf8'));
export const packageJSON = JSON.parse(fs.readFileSync(path.join(path.dirname(__filename), '..', '..', 'package.json'), 'utf8'));

View File

@@ -19,7 +19,7 @@ import path from 'path';
import { pathToFileURL } from 'url';
import { test, expect } from './fixtures.js';
import { createHash } from '../src/utils.js';
import { createHash } from '../src/utils/guid.js';
const p = process.platform === 'win32' ? 'c:\\non\\existent\\folder' : '/non/existent/folder';