Xanthos 0.3.1
dotnet add package Xanthos --version 0.3.1
NuGet\Install-Package Xanthos -Version 0.3.1
<PackageReference Include="Xanthos" Version="0.3.1" />
<PackageVersion Include="Xanthos" Version="0.3.1" />
<PackageReference Include="Xanthos" />
paket add Xanthos --version 0.3.1
#r "nuget: Xanthos, 0.3.1"
#:package Xanthos@0.3.1
#addin nuget:?package=Xanthos&version=0.3.1
#tool nuget:?package=Xanthos&version=0.3.1
Xanthos
F# wrapper library for the JRA-VAN Data Lab. JV-Link COM API.
Overview
Xanthos provides a type-safe, modern F# interface to the legacy JV-Link ActiveX
COM component. It leverages F#'s powerful type system to model the JRA-VAN API safely,
converting COM exceptions and error codes into idiomatic Result<'T, Error> workflows.
Features
- Type-safe API: Discriminated unions and records model JV-Link data structures
- Error handling: COM errors mapped to F# Result types
- Streaming support:
seqandIAsyncEnumerablestreams for large data sets - Cross-platform development: Core logic runs on any .NET platform (COM interop requires Windows)
- Stub mode: Deterministic
JvLinkStubenables full testability in CI where COM is unavailable - CLI tooling: Rich command surface with E2E coverage in stub mode
Installation
Requirements: .NET 10 SDK. COM interop functionality is only available on Windows.
Target
net10.0-windowsand run an x64 process with JV-Link 5.0 x64 installed and its service key registered. COM registration and key setup are specific to the installed architecture; an x86 registration does not satisfy x64 activation. The portablenet10.0target supports parsing and deterministic tests.
dotnet add package Xanthos
From Source
git clone https://github.com/cariandrum22/Xanthos.git
cd Xanthos
dotnet tool restore
dotnet build src/Xanthos/Xanthos.fsproj
Quick Start
open Xanthos
let version =
JvLink.withSession ConnectionOptions.Default (fun session ->
JvLink.init "UNKNOWN" session
|> Result.bind (fun () -> session |> JvLink.getVersion))
match version with
| Ok text -> printfn "JV-Link %s" text
| Error error -> eprintfn "%s: %s (code=%A)" error.Api error.Message error.Code
Public SDK operations are curried functions with Session last. withSession
releases its COM instance and STA after success, an error result, or a consumer
exception. See the functional API contract,
compiled examples, and
record migration guide.
Architecture
Xanthos follows a three-layer architecture:
- Core (
Xanthos.Core) - Domain models, error types, text/encoding helpers - Interop (
Xanthos.Interop) - COM interface implementations and test stubs - Runtime (
Xanthos.Runtime) - High-level service orchestration
See design/architecture/README.md for detailed documentation.
CLI Commands (E2E Coverage)
All commands support global options:
--sid --service-key --save-path [--stub] [--diag].
| Command | Description |
|---|---|
version |
Show JV-Link version and evidence markers |
download |
Bulk dataspec download & preview (optional persistence) |
session-check |
Real COM open/status/read/skip/cancel/close/reopen in one Session |
realtime |
Stream realtime payloads until end/cancel |
status |
Report completed file count |
skip |
Skip current file |
cancel |
Cancel any active session |
delete-file |
Delete a saved JV file by name |
set-save-flag |
Enable/disable persistence flag |
get-save-flag |
Show persistence flag |
set-save-path |
Set save path |
get-save-path |
Show save path |
set-service-key |
Set service key |
get-service-key |
Report whether a service key is registered |
set-payoff-dialog |
Set payoff dialog suppression (COM: use set-ui-properties) |
get-payoff-dialog |
Show payoff dialog suppression |
set-parent-hwnd |
Set parent window handle (UI) |
get-parent-hwnd |
Show parent window handle (COM: unsupported; ParentHWnd is write-only) |
course-file |
Retrieve course diagram file path + explanation |
course-file2 |
Retrieve course diagram file path |
silks-file |
Generate silks bitmap file |
silks-binary |
Retrieve silks bytes |
movie-check |
Check movie availability |
movie-check-with-type |
Check movie availability with type code |
movie-play / movie-play-with-type |
Request playback |
movie-open |
Retrieve all workout video listings |
help |
Show detailed usage text |
Note: The
status,skip, andcancelcommands require an active JVOpen session in the same process. These commands query or control an ongoing download operation and will return error code -203 if no session is open. In typical CLI usage, they are only meaningful when called from the same long-running process that initiated a download.
CLI Evidence Markers
CLI output includes:
EVIDENCE:MODE=COM|STUBEVIDENCE:VERSION=<string>
Used by E2E tests to assert activation pathway and version retrieval logic.
Streaming APIs
StreamRealtimePayloads(sync): handlesFileBoundary(skips) andDownloadPending(incremental backoff) without breaking enumeration.StreamRealtimeAsync(IAsyncEnumerable): cooperative cancellation; swallowsOperationCanceledExceptionand returnsfalsefrom enumerator for graceful termination. The oldStreamRealtimePayloadsAsyncmethod name remains as a forwarding alias for backward compatibility.- Boundary tests cover consecutive
FileBoundarymarkers and prolongedDownloadPendingsequences.
Threading note: The
*Asyncmethods returnIAsyncEnumerableand supportawait foreachsemantics with cooperative cancellation between iterations. However, individual JV-Link COM calls execute synchronously on the STA thread and will block the calling thread for their duration. The async pattern enables cancellation checking and poll interval delays between COM calls, not true non-blocking I/O. This is a fundamental limitation of COM interop. Heads-up:FetchPayloadsWithBytesreplaces the olderFetchPayloadsWithSize. The legacy name still exists as an alias so existing callers keep working, but new code should prefer the clearer*WithBytesflavor.
Development Environment
Native Diagnostics
When you need to inspect the raw IDispatch surface or verify the actual JV-Link
COM behaviour outside of .NET, refer to design/notes/jvlink-early-binding.md
for the investigation summary.
We confirmed that, despite the Type Library declaring [out] BSTR*, the COM server
expects caller-managed buffers, so Xanthos intentionally sticks to late-bound
invocation in production.
Note: The
JVDTLab.JVLinkCOM server exposes a Type Library that marksJVReadparameters as[out] BSTR*, but the actual implementation expects caller-managed buffers and does not accept theIJVLinkearly-bound interface generated from Type Library. As a result, Xanthos intentionally relies on the late-boundInvokeMemberpath forJVRead(and related methods) and treats the type-safeIJVLinkstubs as non-functional diagnostics only.
Using Nix (Recommended)
nix develop
This provides .NET SDK, Mono, and development tools with telemetry disabled.
The SDK is pinned to global.json for local development and CI. The Nix shell
uses official SDK archives pinned by SHA-512 in .config/dotnet-sdk-sources.json
while nixpkgs catches up. When upgrading the SDK, update both files using
Microsoft's .NET release metadata, then verify nix develop --command dotnet --version.
Manual Setup
This project requires the .NET 10 SDK. Follow these steps to install:
Windows (winget)
winget install Microsoft.DotNet.SDK.10
macOS (Homebrew)
brew install --cask dotnet-sdk
Linux / Manual Download
Download the .NET 10 SDK from the .NET 10 downloads page. Select your platform and follow the installation instructions.
Verify Installation
dotnet --version
# Should output 10.0.xxx
Note: If you have multiple .NET SDKs installed, you can use a
global.jsonfile to pin the SDK version. This project already includes one.
Code Formatting and Linting
Fantomas and FSharpLint are provided via dotnet tools:
dotnet tool restore
dotnet fantomas . # format all F# sources
dotnet fsharplint lint Xanthos.sln # run FSharpLint
Documentation
Generate API documentation locally using FSharp.Formatting:
dotnet tool restore
dotnet fsdocs build --clean \
--parameters \
fsdocs-logo-src img/logo.png \
fsdocs-favicon-src img/favicon.png \
fsdocs-license-link \
https://github.com/cariandrum22/Xanthos/blob/main/LICENSE \
fsdocs-release-notes-link \
https://github.com/cariandrum22/Xanthos/releases \
fsdocs-repository-link \
https://github.com/cariandrum22/Xanthos
The generated site is output to output/. View with dotnet fsdocs watch.
Pre-commit Hooks
Enable pre-commit checks locally:
pip install --user pre-commit
pre-commit install
Run manually with pre-commit run --all-files.
Testing
Running Tests Locally
# Run the required managed profile (PowerShell 7)
pwsh ./scripts/run-test-profile.ps1 -Profile Fast -RunId local-fast-01
# Run unit tests only
dotnet test tests/Xanthos.UnitTests
# Run E2E tests in stub mode
XANTHOS_E2E_MODE=STUB \
dotnet test tests/Xanthos.Cli.E2E
Text Encoding
- In-memory: Xanthos represents text as Unicode
string(UTF-16). - CLI / logs:
samples/Xanthos.Cliconfigures stdout/stderr as UTF-8 (no BOM) to keep Japanese output readable in redirected logs and test harnesses.
Test Structure
| Project | Description | Platform |
|---|---|---|
Xanthos.UnitTests |
Unit, independent record contracts and generators | All |
Xanthos.PropertyTests |
FsCheck property-based tests | All |
Xanthos.Cli.E2E |
Legacy Stub CLI smoke and harness checks | All |
Xanthos.FunctionalScenarioTests |
Production CLI and F# functions with controlled native boundary | All |
Xanthos.WindowsTests |
WINDOWS assembly, STA, locale and ABI without SDK | Windows x64 |
Xanthos.ComTests |
Actual JV-Link CLI verification | Windows x64 with SDK |
See tests/README.md for the naming conventions used across the unit-test suite
(e.g., how *ErrorTests vs *AbnormalTests are scoped, and the preferred
Given/When/Then style for test names).
For CLI E2E test design and coverage details, see
design/tests/e2e-cli.md.
CI/CD
The project uses GitHub Actions for continuous integration:
- Build & Test: Runs on Linux, macOS, and Windows
- Functional scenarios: Production CLI with a controlled native boundary; legacy Stub smoke is separate
- WindowsManaged: Windows x64 STA/ABI tests without JV-Link activation
- Code Quality: Format checking with
dotnet fantomas --check . - Coverage: VSTest Coverlet Cobertura, exact test-ID gates and separate OS/TFM artifacts
See .github/workflows/ci.yml for details.
Windows COM Verification
CI checks the managed Windows boundary without activating JV-Link. Actual SDK operations require the separate local COM profile with an installed SDK and registered subscription key before release.
Before tagging the initial release (and for any later COM regression), run the bundled PowerShell workflow on a Windows machine with JV-Link installed:
pwsh scripts/run-com-verification.ps1 `
-FromTime "20260905000000"
Parameters:
FromTimeis required: choose an available RACE publication interval (yyyyMMddHHmmss, JST). Update the example date for the data available to your installation.OutputDirectoryselects the ignored output directory.-SkipPublish -CliPath C:/absolute/path/Xanthos.Cli.exetests an existing x64 executable.
The script reuses the registered x64 key, publishes the Windows CLI and verifies all 15 required/negative COM tests without skips or stub fallback. Run it on the signed-in Windows desktop. See COM verification and functional CLI for stateful acquisition, consent and separate playback/live-notification checks.
Updating Error Catalog
src/Xanthos/Core/ErrorCatalog.fs is generated from the official tables in
design/specs/error_codes.md.
If the specification changes, regenerate the catalog before building:
python3 scripts/generate_error_catalog.py
Do not hand-edit the generated F# source; update the markdown spec and rerun the script.
COM vs Stub Mode
- Stub mode (default in CI) guarantees deterministic responses; no JV-Link installation required.
- COM mode (Windows only) can be used locally if JV-Link is installed and ProgID registered.
- CLI outputs
EVIDENCE:MODEso tests can assert which path executed.
JV-Link Installation Check (Windows)
Ensure the JV-Link COM registration exists before running the COM-backed samples:
pwsh scripts/check-jvlink.ps1
The script resolves the default ProgID and exits non-zero if missing.
License
MIT License - see LICENSE for details.
Contributing
The coverage badge reports the union of production source lines exercised by the Linux UnitTests, PropertyTests and FunctionalScenarioTests Coverage suites. A line is counted once and is covered when any suite executes it; percentages are not averaged. This is portable managed coverage, not evidence of native COM execution. The linked JSON records the measured commit and CI run. After all required checks pass on a develop push, CI refreshes only the generated badge files if that source commit is still the branch tip. These bot commits do not rerun CI. Main receives the recorded snapshot through the normal release PR; CI never writes to main.
Contributions are welcome. Please:
- Fork & clone.
- Add tests for new record parsers or CLI commands.
- Regenerate the error catalog if you modify the spec.
- Ensure all tests pass in stub mode.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. net10.0-windows7.0 is compatible. |
-
net10.0
- FSharp.Core (>= 10.1.401)
-
net10.0-windows7.0
- FSharp.Core (>= 10.1.401)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.