GXWF_WEB_SERVER_PLAN

gxwf-web TypeScript Server Plan

Package: @galaxy-tool-util/gxwf-web in the galaxy-tool-util pnpm monorepo
Goal: TypeScript mirror of the Python gxwf-web FastAPI server — same API surface, backed by this monorepo’s Effect-based validation/lint/clean/convert/roundtrip infrastructure. Shares a generated typed client with the Python version.


Architecture

@galaxy-tool-util/gxwf-web
├── openapi.json            — vendored Python OpenAPI spec (Phase 3)
├── src/
│   ├── app.ts              — createApp(directory) → { server, state, ready }
│   ├── router.ts           — createRequestHandler(state): hand-rolled route matcher
│   ├── contents.ts         — Jupyter Contents API (port of Python contents.py)
│   ├── models.ts           — ContentsModel, CheckpointModel, CreateRequest, RenameRequest
│   ├── workflows.ts        — discoverWorkflows + operateValidate/Lint/Clean/... (Phase 2b)
│   ├── generated/
│   │   └── api-types.ts    — openapi-typescript output from openapi.json (Phase 3, checked in)
│   └── bin/gxwf-web.ts     — CLI entry: directory arg, --host, --port, --cache-dir, --output-schema
└── test/
    └── contents.test.ts    — 67 tests (contents + workflow discovery/ops + --output-schema)

Uses Node’s built-in node:http (same pattern as @galaxy-tool-util/tool-cache-proxy). Depends on @galaxy-tool-util/schema for validation/lint/clean/convert/roundtrip and @galaxy-tool-util/core for ToolCache. Depends on @galaxy-tool-util/cli for step validation orchestration (validateNativeSteps, lintWorkflowReport, etc.).


Phases

Phase 1: Scaffold + Contents API ✅ DONE

Commits: c4df435 (scaffold + 52 tests), bc7e6a8 (review fixes)

What was built:

Review fixes applied:

Test coverage: 52 tests, all green. 3 workflow-related tests (auto-refresh) deferred to Phase 2b.


Phase 2a: Complete TS Report Types ✅ DONE

Goal: All Python API response shapes defined in @galaxy-tool-util/schema before wiring HTTP routes.

The existing report-models.ts already matches Python for SingleValidationReport, SingleLintReport, SingleCleanReport, but is missing types for the other 3 workflow endpoints and some nested types.

Add to report-models.ts:

TypeUsed byNotes
WorkflowEntryWorkflowIndexrelative_path, format, category
WorkflowIndexGET /workflowsdirectory, workflows: WorkflowEntry[]
ConnectionResultConnectionStepResultsource_step, source_output, target_step, target_input, status: "ok"|"invalid"|"skip", mapping|null, errors
ConnectionStepResultConnectionValidationReportstep, tool_id|null, version|null, step_type, map_over|null, connections, resolved_outputs, errors
ConnectionValidationReportSingleValidationReportvalid, step_results, summary, has_details
BenignArtifactStepDiffreason, proven_by
DiffTypeStepDiffenum: value_mismatch|missing_in_roundtrip|missing_in_original|connection_mismatch|...
DiffSeverityStepDiffenum: error|benign
StepDiffRoundTripValidationResultstep_path, key_path, diff_type, severity, description, original_value|null, roundtrip_value|null, benign_artifact|null
RoundTripResultRoundTripValidationResultworkflow_name, direction, step_results: StepResult[]
StepIdMappingResultRoundTripValidationResultmapping, match_methods
RoundTripValidationResultSingleRoundTripReportFull shape incl. diffs, stale_clean_results, step_id_mapping, computed error_diffs/benign_diffs/ok/status/conversion_failure_lines/summary_line
SingleRoundTripReportGET /roundtripworkflow, result: RoundTripValidationResult
SingleExportReportGET /to-format2workflow, ok, steps_converted, steps_fallback, summary
StepEncodeStatusToNativeResultstep_id, step_label|null, tool_id|null, encoded, error|null
ToNativeResultGET /to-nativenative_dict, steps: StepEncodeStatus[], all_encoded, summary

Also fix: SingleValidationReport.connection_report is currently a null placeholder — change to ConnectionValidationReport | null.

Export all new types from index.ts.

Source of truth: docs/_static/openapi.json in gxwf-web repo (post-8b3ead5), which now has full $ref schemas for all components.

What was done:

Note: Type-level tests for new types were planned but deferred — Phase 2b wiring will exercise these shapes.

Phase 2b: Workflow Discovery + Operations ✅ DONE

Goal: /workflows routes backed by existing monorepo capabilities.

What was done:

Notes:

Phase 3: OpenAPI Client Generation + Parity ✅ DONE

Goal: Generate a typed client from the Python spec; export a compatible TS spec.

What was done:

Note on --output-schema approach: The plan referenced Effect HttpApi’s OpenAPI generation, but since the TS server uses hand-rolled node:http (not Effect HttpServer), we vendor the Python spec instead. The spec is the Python server’s spec — it’s the source of truth for the shared API surface.

Phase 4: Remaining Parity + Polish ✅ DONE

Commits: 0124aac

What was done:

Remaining gaps (require future work):


Key Decisions


Resolved Questions

Unresolved Questions

  1. --tool-source/--tool-source-cache-dir — support in TS server, or rely on proxy server YAML config? Resolved: both servers share WorkflowToolConfig from @galaxy-tool-util/core; gxwf-web accepts --config with the same YAML format (galaxy.workflows.toolSources, galaxy.workflows.toolCache).
  2. Tree batch endpoints (POST /workflows/validate-all etc.) — keep TS-only or add to Python too?
  3. allow/deny/preserve/strip — implement StaleKeyPolicy in stale-keys.ts? Needed for full validate/lint/clean parity.
  4. connections validation — implement connection-level step validation in TS? Types exist (ConnectionValidationReport) but no logic.
  5. mode=json-schema — wire to json-schema validation path (see validate-workflow-json-schema.ts)?
  6. StepResult.diffs: string[] in Python — upgrade to StepDiff[] (tracked as issue #32)?