Client manifest
Package Trax.StateMachineNamespace Trax.StateMachineSource ClientManifest.cs, TraxClientExport.cs, ITraxStartupCheck.cs, TraxClientManifestExtensions.cs
A host exports one JSON file that trax client reads to generate a frontend's client: every persisted document a
client may send, by id, each exposed machine's IR, and the GraphQL types those documents reach. The host writes it
with the code that registers its documents, so every id in it is one the host serves. The CLI reads only the file, so
a frontend's build needs no running server, no database and no credential, and Trax.Cli never references Trax.Api.
Members
Three namespaces: ClientManifest and its records are in Trax.StateMachine; TraxClientExport and
ITraxStartupCheck in Trax.Effect.Configuration.ClientExport; RunTraxAsync in
Trax.Api.GraphQL.PersistedOperations.Extensions.
| Member | Description |
|---|---|
app.RunTraxAsync(string[]? args = null) | Runs the host as app.RunAsync() does, unless the process was started with --trax-export-client <path>: then it runs the host's startup checks, writes the manifest to the path and returns without serving. args defaults to the process's command line. In Trax.Api.GraphQL.PersistedOperations.Extensions. |
TraxClientExport.Argument | --trax-export-client. It takes the path next (--trax-export-client out/client.json) or after =. |
TraxClientExport.Requested, TraxClientExport.Path | Whether, and where to, the process was started to export, read from its command line when first used. UsePostgres and UseSqlite skip their migration when it is set; a host skips its own seeding the same way. The argument without a path throws an ArgumentException that says so where it is read. |
TraxClientExport.PathIn(IReadOnlyList<string> args) | The path args name after the argument, or null. The argument without a path throws. |
ITraxStartupCheck | Marks a hosted service that only checks configuration and the host's own types at startup and refuses a host that is wrong. An export runs every one of these and no other hosted service. Trax's own startup validators carry it, except the two that read the database or call a remote schema. |
ClientManifest | The file's content: Format, Machines, Trains, QueryModels, FilterInputs, Progress and Types. FilterInputs names the types in Types that are filter or sort inputs, which a client document writes in its text rather than passing as a variable. Progress holds the runProgress query's and subscription's documents, and is empty when no train lets its starter follow it. ClientManifest.Write(manifest) gives its text, ClientManifest.Read(text) reads it. ClientManifest.CurrentFormat is the format this version writes and reads. |
ClientManifestMachine | One exposed machine: Id, IrHash, Ir and its Documents. Requires is null: each event's own rule applies. IrText() gives the IR as canonical JSON, the bytes IrHash is the SHA-256 of. |
ClientManifestTrain | One exposed train: its Field, Root, Namespace, Answer (the field's type as SDL writes it), Arguments, Requires, and Progress, whether it carries [TraxRunProgress]. It carries no document: a frontend reaches a train through a client document it writes. |
ClientManifestQueryModel | One query model, a field under discover: its Field, Namespace, Answer (a connection when the model is paged, a list otherwise), Arguments (first, after, where, order, as the model turns them on) and Requires, what its entity's attributes ask of a caller. |
ClientManifestArgument | One argument of a train's field: its Name, its Type as SDL writes it (StartRunInput!), and its Default as GraphQL writes it, or null. |
ClientManifestDocument | One persisted document: the Id a client sends, its Operation and its Document text. |
ClientManifestRequirement | What a caller needs, as the train's attributes declare it: Anonymous ([TraxAllowAnonymous]), RoleSets (one per attribute naming roles; the caller holds a role of every set) and Policies (each of them). The server enforces it either way. |
Behavior
- Nothing runs but the checks. The export resolves the schema and runs every
ITraxStartupCheckbefore it writes, so a configuration production refuses fails the export too. No other hosted service starts: nothing listens, sweeps, registers documents or opens a database. A host that seeds data at startup checksTraxClientExport.Requestedfirst. - Started to export, never serves. A host started with
--trax-export-clientwhose provider skipped its migration refuses to start if it serves anyway, because it callsapp.Run()rather thanRunTraxAsync: its database was not migrated. The refusal namesRunTraxAsync. - Only what a client sends. The manifest lists the documents the host generates (each exposed machine's, and
runProgress's), never one underoperations, and each exposed train's and query model's field and arguments.Typesholds the SDL of the types those documents reach, and every type an exposed train's or query model's arguments and answer reach, its filter and sort inputs included, so a client document may select any of it; nothing else. The root operation types and every type a namespace field reaches (dispatch,discover,machinesand the namespaces under them) are left out, since each lists every sibling operation, so the rest of the schema stays on the server. A train's answer type is in itsAnswerinstead. - The same bytes.
Writewrites compact JSON and a final newline, the same bytes for the same content, so a committed manifest can be compared in CI. - Shared output schemas once. When two or more outcomes, in any of the machines, carry the same output schema
(invoking states whose trains answer with one type),
Writeputs it once under a top-level$defsand each outcome'soutputis{"$ref": "#/$defs/<name>"}.Readputs it back, so each machine'sIr, and theIrHashits documents carry, is the one the host exported. The generated twin likewise writes such a schema once, as a const each outcome names. - Format 3. A train lists its
Argumentswhere format 2 listed a generated document, since the host generates no document for a train any more. A format 2 file is exported again; atrax clientof an earlier version refuses a format 3 file rather than generating functions with no document. - One format.
Readrefuses a file in any format other thanCurrentFormat, naming both, and anything that is not a manifest. A newer file needs a newer tool; an older one is exported again. - Export the production configuration. A machine's IR, and so every document id, can depend on configuration (a timer's duration, for one). Export with the configuration the host serves in production.
Example
using Trax.Api.GraphQL.PersistedOperations.Extensions; // RunTraxAsync
using Trax.Effect.Configuration.ClientExport; // TraxClientExport
var app = builder.Build();
if (!TraxClientExport.Requested)
await Seed(app.Services);
app.UseTraxGraphQL();
await app.RunTraxAsync(args);ASPNETCORE_ENVIRONMENT=Production dotnet run --project Api -- --trax-export-client ../web/src/trax/manifest.jsonSee also
- The machines root, the documents the manifest lists.
- TypeScript package, what the generated client calls.