restage_a2ui 0.2.0 copy "restage_a2ui: ^0.2.0" to clipboard
restage_a2ui: ^0.2.0 copied to clipboard

Fail-closed pre-render capability checks and the Restage capability sidecar for apps rendering cached A2UI (Google genui) surfaces.

example/README.md

restage_a2ui example #

This example shows the whole @RestageWidget → A2UI catalog loop end to end: it compiles annotated Flutter widgets into a genui A2UI catalog, then gates payloads against that catalog with restage_a2ui's app-side, fail-closed pre-render check before handing them to genui. A payload the build can't render faithfully fails with a clean diagnostic instead of throwing mid-render.

What it generates #

Two custom widget libraries, authored as plain annotated Flutter widgets, are compiled by the build-time toolchain into a single genui A2UI catalog. The build writes the CatalogItems and the JSON schemas for you:

  • acme.widgets (capability version 3): CtaButton, IntegerListPicker, ProductCard, RatingPicker, and ScalarListPanel.
  • acme.lessons (capability version 1): SectionHeader, Callout, ComparisonPanel, QuizCheck.

The generated catalog contains exactly these widgets, all of them your own. Each library carries its own capability version in the emitted stamp. The two outputs (lib/generated/restage_a2ui_catalog.g.dart + lib/generated/restage_a2ui_catalog.a2ui.json) are regenerated from the annotated source, which is the only authoring input. The example has no app entrypoint:

dart run build_runner build   # regenerate the catalog + stamp from the @RestageWidget source
flutter test                  # render the generated widgets through genui 0.10.1

The tests render the generated catalog through genui's real surface runtime and prove the pre-render check rejects a payload that references a component the catalog does not contain (fail-closed). See the package README for the full step-by-step generation walkthrough.

The lesson surface also executes the generated custom payload convention: protocol-owned id and component stay on the envelope, while every exact constructor input is nested under required props. ComparisonPanel proves three independently named child-bearing inputs (introduction, examples, and conclusion) on one class, and Callout.detail proves that no input needs to be named child or children.

{
  "id": "root",
  "component": "ComparisonPanel",
  "props": {
    "heading": "Grammar showcase",
    "introduction": "header",
    "examples": ["callout", "quiz"],
    "conclusion": "summary"
  }
}

Gate a payload before rendering #

Build the check once (it is immutable, so reuse it for every payload), then gate each payload before render:

import 'package:genui/genui.dart';
import 'package:restage_a2ui/restage_a2ui.dart';

// The genui catalog your build emitted, and what it provides.
final catalog = buildRestageCatalog();
final installed = A2uiInstalledCapability.fromStampJson(restageCapability);

// One instance, reused for every payload.
final check = RestageA2uiPreRenderCheck(catalog: catalog, installed: installed);

Widget? renderCached(Map<String, Object?> payload) {
  switch (check.check(payload)) {
    case A2uiRenderable():
      return renderWithGenui(payload); // your genui render call
    case A2uiRejected(:final diagnostic):
      // Do NOT render. Fall back to a built-in surface and log why.
      debugPrint('A2UI rejected: $diagnostic');
      return null;
  }
}

The check fails closed for a malformed Restage sidecar envelope, an unknown component type in a well-formed {id, component} entry, an unmet version, or an unverifiable stamped payload. It does not validate every inner A2UI component shape; malformed entries can still fail when genui parses them.

See the package README for the capability sidecar, the version satisfaction rules, and how the catalog and stamp are produced.

Guiding notes on the example widgets #

Callout (acme.lessons) declares both a description and an A2UI-only @a2ui.Config.usage('…') note; SectionHeader declares only a description. The generated _restageA2uiSystemPromptFragments in lib/generated/restage_a2ui_catalog.g.dart shows the result: Callout gets its own usage line, SectionHeader falls back to its description, and buildRestageCatalog() (used above) hands both to genui as Catalog.systemPromptFragments, in your own words.

1
likes
150
points
106
downloads

Documentation

API reference

Publisher

verified publisherrestage.dev

Weekly Downloads

Fail-closed pre-render capability checks and the Restage capability sidecar for apps rendering cached A2UI (Google genui) surfaces.

Homepage
Repository (GitHub)
View/report issues
Contributing

Topics

#server-driven-ui #remote-ui #flutter

License

BSD-3-Clause (license)

Dependencies

a2ui_core, flutter, genui, json_schema_builder, restage_shared

More

Packages that depend on restage_a2ui