126 Commits
Author SHA1 Message Date
ars9 e85acc8fb2 feat(scenario): shared browser per run, sign step type, key loading helper
- all steps in a run share one browser/page instance so wizard state persists
- add 'sign' step type: execCode is {keyId} and signs via EDS widget on current page
- extract AuthService.loadKeyDescriptor() to deduplicate key file parsing
- extend StepType, DTOs, and MCP enums to include 'sign'
2026-04-08 15:42:42 +03:00
ars9 eeece70866 refactor(config): derive APP_NAME and APP_VERSION defaults from package.json 2026-04-08 12:58:59 +03:00
ars9 8e62ad8b4e style(logging): clean up log format with ISO8601 timestamps and no PID prefix
- override getTimestamp() to emit ISO 8601 instead of locale string
- override formatMessage() to drop PID prefix and level padding
- enable timestamp: true so timestampDiff (+Nms) appears on each line
- pass TraceLogger instance to NestFactory so framework logs use same format
2026-04-08 12:57:28 +03:00
ars9 3367828c39 docs(mcp): replace @All with explicit POST/GET/DELETE and add OpenAPI descriptions
- restrict endpoint to spec-mandated HTTP methods only
- POST: JSON-RPC messages, responds with application/json or SSE
- GET: opens persistent SSE stream for server-to-client push
- DELETE: optional client-initiated session termination via Mcp-Session-Id
2026-04-08 12:30:07 +03:00
ars9 6fd991811f feat(logging): add trace ID propagation via AsyncLocalStorage
- add TraceInterceptor that reads x-trace-id header or generates a UUID
- add AsyncLocalStorage store in common/trace-context for request-scoped trace ID
- replace NestJS Logger with TraceLogger (extends ConsoleLogger) that injects trace ID into log context
- register TraceInterceptor globally before LoggingInterceptor
- move HealthController into HealthModule so global interceptors apply to /healthz
- omit body/response from log lines when empty or null
2026-04-08 12:20:06 +03:00
ars9 7f5a2bfe18 refactor(mcp): hoist McpServer to singleton, read name/version from package.json
- server instantiated once in constructor, tools registered once
- per-request transport created fresh and closed in finally to reset server state
- name and version sourced from package.json instead of hard-coded strings
2026-04-08 11:45:52 +03:00
ars9 f0437d9390 refactor(browser): make sessionName optional, add selector filter, deduplicate session setup
- sessionName is now optional in open/exec; skips session restore when omitted
- add selector param to open: returns outerHTML or textContent of matched element
- extract session restore logic into private setupSession() to remove duplication
- replace per-exception instanceof checks with single HttpException base class check
- embed label into InternalServerErrorException message instead of logging separately
- update MCP tool schemas and HTTP DTOs to reflect optional sessionName and new selector
- add integration tests: sessionless open/exec, selector, selector+readerMode
2026-04-08 11:10:08 +03:00
ars9 f1dadc602a feat(mcp): add helpers.dumpDom() to exec_code context
- new dom-helpers.ts exports dumpDom(page, selector?) that evaluates a
  browser-side tree walker returning a lean DomNode structure
- filters ignored tags (svg, script, path, etc.) and hidden elements
- captures role, data-testid, data-qa, data-action, data-element-id,
  id, type, name, href (relativized), checked, disabled, and text
- prunes single-child non-significant divs; discards empty non-sig nodes
- code-executor wraps dumpDom in a pageHelpers object passed as helpers
  param so user scripts can call helpers.dumpDom() or helpers.dumpDom('main')
- 29 unit tests covering all behaviours via fake DOM builder
2026-04-07 19:33:21 +03:00
ars9 ae8852d738 feat(auth): add login/password authentication strategy
- KeyDescriptor now accepts optional login field alongside keyFile
- when login is present, clicks login/password auth method, fills email+password fields, and submits
- file-key flow unchanged; validation ensures exactly one strategy is present
2026-04-07 19:33:08 +03:00
ars9 02630e4919 fix(browser): pass executablePath from env var in all chromium.launch() calls
- system Chromium path from PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH was not forwarded
  to the launch options, causing 'executable doesn't exist' errors in Docker
2026-04-07 18:02:33 +03:00
ars9 36f8b8c0ca feat(pagination): add generic typed pagination with ordering to all list endpoints
- add PaginationQueryDto<TOrderBy> generic with orderBy and orderDir fields
- add SessionOrderBy, EnvironmentOrderBy, ScenarioOrderBy type aliases
- update session, environment, scenario services and controllers to use typed pagination
- update MCP list_sessions, list_environments, list_scenarios tools to expose orderBy/orderDir
- update tests for all list endpoints to cover page, limit, ordering, and invalid param rejection
2026-04-07 17:54:23 +03:00
ars9 d9cdb64ee2 feat(mcp): add scenario tools and fix per-request server lifecycle
- add list_scenarios, get_scenario, create_scenario, update_scenario, delete_scenario
- add create_scenario_step, get_scenario_step, update_scenario_step, delete_scenario_step
- add list_scenario_runs, run_scenario
- import ScenarioModule into McpModule so ScenarioService is injectable
- move tool registration to private registerTools(server) method; create
  fresh McpServer per request in handle() to satisfy SDK one-connection rule
- fix mcp.controller.spec: parse SSE data line instead of res.body; assert
  exact status 200 everywhere; remove vague toBeLessThan(500) guards
2026-04-07 17:25:55 +03:00
ars9 00f310e899 test: add jest test suite with controller specs and mocks
- add jest, ts-jest, supertest, and related dev dependencies
- add test scripts (test, test:debug, test:watch) to package.json
- add jest.config.js with ts-jest transform and module name mappers
- add controller specs for auth, browser, environment, mcp, scenario, session
- add mocks for jsdom, playwright, and readability
- add test/tsconfig.json and exclude test dir from main tsconfig
2026-04-07 15:54:13 +03:00
ars9 cff36ffeff feat(scenario): add scheduler, cancelled step status, and runs list endpoint
- install @nestjs/schedule and register ScheduleModule in AppModule
- add ScenarioSchedulerService with two 1s interval jobs:
  - activatePendingRuns: flips pending runs to in_progress
  - processPendingStepRuns: executes next pending step run (login or exec),
    runs optional validateCode, advances or fails the run accordingly
- on step pass: next waiting step becomes pending; last step pass flips run to pass
- on step fail: remaining steps set to cancelled, run flipped to fail
- add cancelled to RunStepStatus union
- add GET /scenarios/:id/runs with pagination and optional ?status= filter
2026-04-07 14:51:37 +03:00
ars9 caf120741d feat(scenario): add scenario runs, run steps, and step ordering
- add ScenarioRunEntity (pending|in_progress|pass|fail) and ScenarioRunStepEntity (waiting|pending|in_progress|pass|fail)
- add POST /scenarios/:id/run — creates run with first step pending, rest waiting
- add order field to ScenarioStepEntity and ScenarioRunStepEntity for deterministic sequential execution
- findOne and createRun now sort steps/stepRuns by order ASC
2026-04-07 14:27:17 +03:00
ars9 d669bf1c59 feat(scenario): add scenario and scenario step CRUD module
- add ScenarioEntity and ScenarioStepEntity with cascade delete
- step fields: type (login|exec), sessionName (required), execCode, validateCode
- login steps create a named session; exec steps consume it by sessionName
- full CRUD controller under /scenarios and /scenarios/:id/steps
- paginated GET /scenarios with page/limit query params returning { data, total, page, limit }
- register ScenarioModule and entities in AppModule
2026-04-07 14:13:06 +03:00
ars9 5ac26ecb3a feat(observability): add exception filter, logging interceptor, and CodeExecutorModule
- add HttpExceptionFilter logging BadRequestException at warn and InternalServerErrorException at error with cause chain
- add LoggingInterceptor logging request/response pairs at debug level with method, path, body, status, and duration
- extract CodeExecutorService into standalone CodeExecutorModule imported by BrowserModule and McpModule
- thread { cause: err } into all catch blocks across auth, browser, and code-executor services
2026-04-07 13:49:02 +03:00
ars9 bf1b6249a9 feat(mcp): add MCP endpoint; fix TODOs (pkg.json name/version, NestJS Logger) 2026-04-07 13:20:15 +03:00
ars9 6f23c0f736 chore(docker): add Dockerfile, docker-compose.yaml, and .dockerignore 2026-04-07 13:06:33 +03:00
ars9 de48a912d4 feat(environment): add environment CRUD module and wire into auth login 2026-04-07 13:00:54 +03:00
ars9 49dd1aa14c feat(sessions): add GET /sessions and DELETE /sessions/:id endpoints 2026-04-07 12:44:08 +03:00
ars9 238ce0289c feat(auth): add GET /keys to list available key identifiers 2026-04-07 12:40:03 +03:00
ars9 9898fb6472 feat(browser): add POST /exec for custom Playwright code execution
- accepts sessionName, optional url, and arbitrary JS code string
- restores cookies and localStorage from session before execution
- exposes page and context to user code as async function arguments
- session not found now returns 404 instead of 400
2026-04-07 12:36:27 +03:00
ars9 9e5a813e9d feat(browser): add POST /open with session restore and reader mode
- restores cookies and localStorage from DB before page navigation
- readerMode flag extracts plain text via @mozilla/readability (Firefox reader engine)
- add localStorage default '{}' on session entity for clean schema migrations
2026-04-07 12:27:34 +03:00
ars9 41dbddd2a1 feat(auth): add POST /login with Playwright automation and SQLite session storage
- automates file-key login on the ID portal using Playwright/Chromium
- captures token, cookies, and localStorage after successful redirect
- stores session data in SQLite via TypeORM (better-sqlite3)
- sessions are keyed by sessionName (auto-generated UUID if not provided)
- login URL, cabinet redirect URL, keys dir, and DB path are all configurable via env
2026-04-07 12:07:13 +03:00
ars9 70f016d113 Initial commit 2026-04-07 11:36:33 +03:00