feat(browser,mcp): resolve environment and credentials from DB in exec
- POST /exec now accepts environmentId (UUID) and credentials (alias → UUID) instead of raw payloads; resolves entities via EnvironmentService and CredentialService before passing data to browserService.exec - exec_code MCP tool updated with same schema: environmentId + credentials map - CredentialModule imported into BrowserModule and McpModule - docs(scenario): rewrite script runtime section for single context argument - docs(mcp): update exec_code description to reflect new parameter shapes - style: reorder imports across server source (formatter)
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import { Body, Controller, Post } from "@nestjs/common";
|
||||
import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
||||
import { BrowserService, ExecResult, OpenResult } from "./browser.service";
|
||||
import { CodeExecutorService } from "../code-executor/code-executor.service";
|
||||
import { OpenDto } from "./dto/open.dto";
|
||||
import { CredentialService } from "../credential/credential.service";
|
||||
import { EnvironmentService } from "../environment/environment.service";
|
||||
import { BrowserService, ExecResult, OpenResult } from "./browser.service";
|
||||
import { ExecDto } from "./dto/exec.dto";
|
||||
import { OpenDto } from "./dto/open.dto";
|
||||
|
||||
@ApiTags("browser")
|
||||
@Controller()
|
||||
@@ -11,6 +13,8 @@ export class BrowserController {
|
||||
constructor(
|
||||
private readonly browserService: BrowserService,
|
||||
private readonly codeExecutor: CodeExecutorService,
|
||||
private readonly environmentService: EnvironmentService,
|
||||
private readonly credentialService: CredentialService,
|
||||
) {}
|
||||
|
||||
@Post("open")
|
||||
@@ -54,8 +58,26 @@ export class BrowserController {
|
||||
@ApiResponse({ status: 400, description: "Invalid input" })
|
||||
@ApiResponse({ status: 404, description: "Session not found" })
|
||||
@ApiResponse({ status: 500, description: "Execution failed" })
|
||||
exec(@Body() dto: ExecDto): Promise<ExecResult> {
|
||||
async exec(@Body() dto: ExecDto): Promise<ExecResult> {
|
||||
this.codeExecutor.validate(dto.code);
|
||||
return this.browserService.exec(dto.sessionName, dto.code, dto.url, dto.environment, dto.credentials);
|
||||
|
||||
// Resolve environment from DB
|
||||
let environment: Record<string, string | undefined> | undefined;
|
||||
if (dto.environmentId) {
|
||||
const env = await this.environmentService.findOne(dto.environmentId);
|
||||
environment = env.data;
|
||||
}
|
||||
|
||||
// Resolve credentials from DB (alias → payload)
|
||||
let credentials: Record<string, unknown> | undefined;
|
||||
if (dto.credentials && Object.keys(dto.credentials).length > 0) {
|
||||
credentials = {};
|
||||
for (const [alias, credId] of Object.entries(dto.credentials)) {
|
||||
const cred = await this.credentialService.findOne(credId);
|
||||
credentials[alias] = cred.data ? JSON.parse(cred.data) : {};
|
||||
}
|
||||
}
|
||||
|
||||
return this.browserService.exec(dto.sessionName, dto.code, dto.url, environment, credentials);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { CodeExecutorModule } from "../code-executor/code-executor.module";
|
||||
import { CredentialModule } from "../credential/credential.module";
|
||||
import { EnvironmentModule } from "../environment/environment.module";
|
||||
import { SessionModule } from "../session/session.module";
|
||||
import { SnippetModule } from "../snippet/snippet.module";
|
||||
import { BrowserController } from "./browser.controller";
|
||||
import { BrowserService } from "./browser.service";
|
||||
import { SessionModule } from "../session/session.module";
|
||||
import { CodeExecutorModule } from "../code-executor/code-executor.module";
|
||||
import { SnippetModule } from "../snippet/snippet.module";
|
||||
|
||||
@Module({
|
||||
imports: [SessionModule, CodeExecutorModule, SnippetModule],
|
||||
imports: [SessionModule, CodeExecutorModule, SnippetModule, EnvironmentModule, CredentialModule],
|
||||
controllers: [BrowserController],
|
||||
providers: [BrowserService],
|
||||
exports: [BrowserService],
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import { Readability } from "@mozilla/readability";
|
||||
import {
|
||||
Injectable,
|
||||
HttpException,
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
} from "@nestjs/common";
|
||||
import { TraceLogger } from "../common/trace-logger";
|
||||
import { chromium } from "playwright";
|
||||
import type { BrowserContext } from "playwright";
|
||||
import { Readability } from "@mozilla/readability";
|
||||
import { JSDOM } from "jsdom";
|
||||
import type { BrowserContext, Cookie } from "playwright";
|
||||
import { chromium } from "playwright";
|
||||
import type { ExecResult, ScriptLogger } from "../code-executor/code-executor.service";
|
||||
import { CodeExecutorService } from "../code-executor/code-executor.service";
|
||||
import { TraceLogger } from "../common/trace-logger";
|
||||
import type { EnvironmentData } from "../environment/environment.entity";
|
||||
import { SessionContextService } from "../session/session-context.service";
|
||||
import { SessionService } from "../session/session.service";
|
||||
import { CodeExecutorService } from "../code-executor/code-executor.service";
|
||||
import type { ExecResult, ScriptLogger } from "../code-executor/code-executor.service";
|
||||
import { SnippetService } from "../snippet/snippet.service";
|
||||
import type { Cookie } from "playwright";
|
||||
import type { EnvironmentData } from "../environment/environment.entity";
|
||||
|
||||
export type { ExecResult } from "../code-executor/code-executor.service";
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { IsObject, IsOptional, IsString, IsUrl } from "class-validator";
|
||||
import type { EnvironmentData } from "../../environment/environment.entity";
|
||||
import { IsObject, IsOptional, IsString, IsUUID, IsUrl } from "class-validator";
|
||||
|
||||
export class ExecDto {
|
||||
@ApiPropertyOptional({
|
||||
@@ -23,27 +22,27 @@ export class ExecDto {
|
||||
|
||||
@ApiProperty({
|
||||
description:
|
||||
"JavaScript code to execute. Receives `page` (Playwright Page) and `context` (BrowserContext) as arguments. May be async. Return value is serialised and returned.",
|
||||
example: "return await page.title();",
|
||||
"Async JavaScript body. Use `context.page` for Playwright, `context.getEnv(key)`, `context.getCredential(alias)`, `context.runSnippet(name, ...args)`.",
|
||||
example: "return await context.page.title();",
|
||||
})
|
||||
@IsString()
|
||||
code: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
"Key/value map of environment variables available via `helpers.env` and `helpers.getEnv()` in the script.",
|
||||
example: { BASE_URL: "https://example.com" },
|
||||
"UUID of an existing environment entity. Its key/value data is available via `context.env` and `context.getEnv()` in the script.",
|
||||
example: "a6a1fca5-0f61-48ed-ae97-011dc7236387",
|
||||
})
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
environment?: EnvironmentData;
|
||||
@IsUUID()
|
||||
environmentId?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
"Key/value map of credentials available via `helpers.getCredential()` in the script.",
|
||||
example: { admin: { username: "user", password: "pass" } },
|
||||
"Map of alias → credential UUID. Each credential is loaded from the DB and available via `context.getCredential(alias)` in the script.",
|
||||
example: { pkcs_key: "e3b0c442-98fc-11d8-9669-0800200c9a66" },
|
||||
})
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
credentials?: Record<string, unknown>;
|
||||
credentials?: Record<string, string>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user