Skip to content

feat!: add lazy clients and transport-neutral command contracts - #225

Merged
patrickleet merged 4 commits into
v5from
refactor/core-command-contract
Sep 7, 2026
Merged

patrickleet merged 4 commits into
v5from
refactor/core-command-contract

Conversation

@patrickleet

@patrickleet patrickleet commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

Why

Command semantics belong to the domain-facing framework, not to a particular gateway. Read-only browser visits also should not have to initialize every command implementation.

This PR includes the lazy generated command loading from #224 alongside the transport-neutral command contract. It supersedes #224 and targets v5, so the breaking Rust API migration can ship with the other v5 changes rather than entering the current main release line.

What application authors gain

  • Transport-neutral commands: outcomes, consistency, prepared completions, input validation and structural data shapes live in distributed::command. GraphQL exposes those contracts alongside queries and subscriptions.
  • Smaller initial browser bundles: provideDistributedLazy registers the small authority catalog immediately and loads one shared command runtime on preload or first invocation. Query/SSR loading and command call signatures are unchanged.
  • One existing execution protocol: lazy loading delegates projections, retries, pending receipts and status recovery to the same runtime. Eventual/Atomic consistency and projection sealing retain their behavior.

Examples

Domain DTOs describe commands without depending on GraphQL authoring types:

use distributed::{CommandInput, CommandOutput};
use distributed::command::{typed_command, Succeeded};
use serde::{Deserialize, Serialize};

#[derive(Deserialize, CommandInput)]
struct CreateOrder { title: String }

#[derive(Serialize, CommandOutput)]
struct OrderCreated { order_id: String }

let declaration = typed_command::<CreateOrder, Succeeded<OrderCreated>>("orders.create")
    .roles(["user"]);

Opt into lazy loading in the generated SvelteKit client while keeping existing provider options and command calls:

import { provideDistributedLazy as provideDistributed } from '$distributed';

// When opening an editor, optionally warm the shared command runtime:
await client.preloadCommands();

The loader validates the loaded surface/inventory, fences scope changes and cancellation during imports, and preserves preparation order across cold/warm calls. Controlled reload preloads before an existing recovery callback; loading code never replays commands.

Breaking Rust migration

  • Replace GraphqlInput / GraphqlOutput with CommandInput / CommandOutput, including nested DTOs.
  • Import outcomes, typed declarations and projection command helpers from distributed::command.
  • Replace manual GraphQL metadata implementations with CommandInputType / CommandOutputType, command_type(), and CommandTypeDef / CommandTypeField.

The old GraphQL command derives, traits, shape types, conversions and re-exports are removed. The e2e-ui domains, integration tests, application fixtures and service templates are migrated. GraphQL validates naming when exposing a command; the core accepts Serde names independently.

Bundle measurements

A representative larger application's frozen 4.12.1 manifest was regenerated with this CLI and built with this runtime and Vite 6.4.3:

Initial-home JS Eager Lazy Reduction
Raw 766,443 B 566,049 B 26.1%
gzip 162,364 B 138,234 B 14.9%
Brotli 135,105 B 116,593 B 13.7%

The first command needs another 28,856 B gzip; total emitted JS gzip grows from 217,193 to 221,944 B. These are sums of independently compressed emitted JS files and their initial static dependencies, excluding HTML, SSR data, CSS and request overhead. This moves work off startup; no browser CPU/LCP improvement is claimed. Query splitting is excluded because the earlier experiment showed little compressed-size benefit.

Validation

  • Lazy-client validation: 354 JavaScript tests, generated TypeScript checks, packed-consumer smoke and publint passed on Node 24. Bundle tests verify command definitions/runtime stay outside the initial browser closure; behavioral tests cover SSR/hydration, query prefetch, shared loading, cancellation, invocation order, retries, pending IDs and reload recovery ordering.
  • Command-contract validation: 745 no-default-feature library tests, 3 neutral contract tests, 1,053 GraphQL/SQLite library/application/causal tests, 106 e2e-ui library tests, 248 CLI unit tests, 9 scaffold tests and 6 manifest-harness tests passed during feat!: add lazy clients and transport-neutral command contracts #225 development.
  • All checks passed on the pre-rebase head b9f2960a, including both live browser suites and celld Queue/NATS. The earlier compile-fail failure was a diagnostic snapshot missing the standard-library source span; the correction restores the full CI diagnostic. All 35 fixtures pass locally with rust-src installed. No browser assertion was weakened.
  • Rebased onto v5 after feat!: make projections and dev runtime recovery-safe #226. Its fencing, typed application assembly and lifecycle command-proof tests are retained. Fresh CI verifies the rebased branch; consult the current checks rather than treating earlier development counts as a substitute.
  • Post-rebase local validation: cargo test --workspace --all-features --locked passes (environment-gated live tests are not credited as live evidence); JavaScript npm run quality passes with 355 tests, generated TypeScript checks, packed-consumer smoke and publint; all 5 lifecycle command-proof tests pass.

Implements tasks/client-artifact-loading-2 and tasks/core-command-contract-1.

@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 76804722-837e-4ef8-a976-28965c30ae94

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@patrickleet patrickleet changed the title refactor: extract transport-neutral command contracts refactor!: move command contracts out of GraphQL Sep 6, 2026
Register authority before loading, preserve command lifecycle and dispatch order, and expose generated preload support.

Implements [[tasks/client-artifact-loading-2]]
Move command outcomes, shape metadata, validation, and consistency contracts into distributed::command. Adapt GraphQL and legacy derives at the boundary while retaining canonical artifacts and fingerprints.

Implements [[tasks/core-command-contract-1]]
Use command-owned derives, metadata, and outcomes throughout library tests, e2e-ui domains, fixtures, and generated services. Remove legacy GraphQL traits, conversions, derives, and re-exports.

BREAKING CHANGE: command authors must use distributed::command and the CommandInput/CommandOutput derives. GraphqlInput/GraphqlOutput and GraphQL command exports are removed.

Implements [[tasks/core-command-contract-1]]
Keep the full rust-src diagnostic used in CI; document the regeneration prerequisite. All 35 compile-fail fixtures pass with rust-src installed.

Refs: tasks/distributed-v5-pr-stack
@patrickleet
patrickleet force-pushed the refactor/core-command-contract branch from b9f2960 to 8f1f54f Compare September 6, 2026 23:30
@patrickleet patrickleet changed the title refactor!: move command contracts out of GraphQL feat!: add lazy clients and transport-neutral command contracts Sep 6, 2026
@patrickleet
patrickleet changed the base branch from perf/lazy-generated-commands to v5 September 6, 2026 23:31
@patrickleet
patrickleet merged commit fff00d1 into v5 Sep 7, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant