microsoft-webui-protocol 0.0.26

Core protocol definitions for WebUI framework
Documentation
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

syntax = "proto3";

package webui;

// Per-component metadata keyed by tag name.
message ComponentData {
  // Non-WebUI client-side template payload.
  // FAST plugins store complete <f-template> HTML here.
  string template = 1;
  // Compiled component CSS content for the Style and Module strategies.
  // Empty for Link and for components without CSS.
  string css = 2;
  // External stylesheet href for the Link CSS strategy.
  // Set to e.g. "/my-card.css" when the component has a CSS file and the
  // build used CssStrategy::Link. Empty for Style/Module strategies and
  // for components without CSS.
  // Ordered style closures decide which Document or ShadowRoot owns the link.
  string css_href = 3;
  // WebUI plugin JSON-safe component metadata.
  // Stored separately from executable condition closures so handlers can emit
  // the static metadata in application/json data blocks.
  string template_json = 4;
  // WebUI plugin component-local JavaScript condition closure array.
  // Empty when the component has no conditions or boolean attributes.
  string template_functions = 5;
  // Exact @observable + @attr property keys when hydration_mode is KEYS.
  // Existing SSR host attributes take precedence; bootstrap state fills
  // attribute-backed properties that were not materialized on the host.
  // Template roots already exist in the trusted SSR DOM and do not enter
  // initial state solely because a component has authored browser code.
  // Sorted and deduplicated; empty for NONE and ALL.
  repeated string hydration_keys = 6;
  // Exact partial-navigation keys when navigation_mode is KEYS. Authored
  // components use @observable + @attr property keys plus template roots.
  // Scriptless compiled templates include only their template roots.
  // Sorted and deduplicated; empty for NONE and ALL.
  repeated string navigation_keys = 7;
  // How initial hydration state is selected for this component.
  StateProjectionMode hydration_mode = 8;
  // How partial-navigation state is selected for this component. Presence is
  // significant: protocols produced before projection metadata leave this
  // absent, so handlers preserve full state instead of treating it as NONE.
  optional StateProjectionMode navigation_mode = 9;
  // Whether this component effectively uses Shadow DOM after build-time
  // fallback and authored declarative Shadow DOM resolution.
  bool uses_shadow_dom = 10;
  // Compiler-owned client work policy. Zero/eager is absent on the wire.
  ComponentWorkPolicy work_policy = 11;
}

// Per-component client work scheduling policy.
enum ComponentWorkPolicy {
  COMPONENT_WORK_POLICY_EAGER = 0;
  COMPONENT_WORK_POLICY_LAZY_HYDRATION = 1;
  COMPONENT_WORK_POLICY_LAZY_RENDER = 2;
  COMPONENT_WORK_POLICY_INTERACTION = 3;
  COMPONENT_WORK_POLICY_LAZY_RENDER_INTERACTION = 4;
}

// Link stylesheet metadata for one static component asset root.
//
// Shadow builds publish this finite manifest so the framework can begin CSS
// beside the root module on interaction. Light builds emit the hrefs as
// deduplicated document stylesheets because their CSS is globally scoped.
message ComponentAssetStylePreload {
  // Root component tag used by defineComponentAssets().
  string root = 1;
  // Final Link-mode stylesheet hrefs required by this asset graph.
  repeated string style_hrefs = 2;
}

// Build-wide initial-state behavior.
enum InitialStateStrategy {
  // Emit the complete state object. Used by default and non-WebUI plugins.
  INITIAL_STATE_STRATEGY_FULL = 0;
  // Select state from reachable WebUI component surfaces.
  INITIAL_STATE_STRATEGY_COMPONENTS = 1;
}

// Per-component state selection.
enum StateProjectionMode {
  // The component is known not to consume state through this channel.
  STATE_PROJECTION_MODE_NONE = 0;
  // Select the component's explicit sorted key list.
  STATE_PROJECTION_MODE_KEYS = 1;
  // The complete surface is unknown, so preserve correctness with full state.
  STATE_PROJECTION_MODE_ALL = 2;
}

// CSS delivery strategy chosen at build time.
enum CssStrategy {
  CSS_STRATEGY_LINK = 0;
  CSS_STRATEGY_STYLE = 1;
  CSS_STRATEGY_MODULE = 2;
}

// Root protocol containing all fragment records and build metadata.
message WebUIProtocol {
  map<string, FragmentList> fragments = 1;
  // Sorted, deduplicated CSS custom property names used across all components
  // and entry page styles (e.g., "colorBrandBackground", "spacingMedium").
  // Only usage via var(--name) is included; local definitions are excluded.
  repeated string tokens = 2;
  // Per-component data keyed by tag name (f-template + CSS).
  map<string, ComponentData> components = 3;
  // Build-wide CSS delivery strategy. Determines how compiled component
  // resources are installed in each CSS tree.
  CssStrategy css_strategy = 4;
  reserved 5;
  reserved "dom_strategy";
  // Whether initial SSR metadata contains full state or WebUI component
  // projection. Partial-navigation state remains component-driven.
  InitialStateStrategy initial_state_strategy = 6;
  // Ready-to-write `<link rel="modulepreload">` hrefs for the shared chunks
  // that the page's critical module entries statically import, in the exact
  // order they must be emitted (largest chunk first).
  //
  // These chunks are named only inside the entry's own bytes, so the browser's
  // preload scanner cannot discover them until it has downloaded and parsed
  // the entry. Emitting them as hints removes that serialization.
  //
  // Order is load-bearing: preloads are issued in document order over one
  // connection, so a small chunk ahead of a large one delays the long pole.
  // The compiler resolves and sorts these at build time so the handler writes
  // them verbatim with no per-request work.
  repeated string module_preloads = 7;
  // Build-generated document-level rules for component rendering policies.
  // Empty when no component opts into lazy rendering.
  string component_render_css = 9;
  // Ordered, deduplicated component style resource tags for each Document or
  // component-root CSS tree entry point.
  map<string, ComponentStyleClosure> style_closures = 10;
  // Bundled stylesheets in global cascade order. Empty unless the build
  // enabled CSS bundling, in which case every component that owns a style
  // resource belongs to exactly one chunk and handlers deliver chunks instead
  // of individual component resources.
  repeated StyleChunk style_chunks = 11;
  // Build-generated eager metadata for static component asset roots.
  //
  // Entries are sorted by root tag. Builds without component assets omit the
  // field from the wire.
  repeated ComponentAssetStylePreload component_asset_style_preloads = 12;
}

// Compile-time component style resources for one CSS tree.
message ComponentStyleClosure {
  // Component tags in cascade-sensitive first-discovery order.
  repeated string component_tags = 1;
  // Indices into WebUIProtocol.style_chunks covering exactly the components in
  // component_tags, in the same cascade order. Empty unless the build enabled
  // CSS bundling. A chunk is listed only when the closure consumes every
  // component the chunk carries, so delivering a chunk never over-delivers.
  repeated uint32 style_chunks = 2;
}

// One bundled stylesheet carrying a contiguous run of component styles that
// share the same set of consuming CSS trees.
message StyleChunk {
  // Stable build-time chunk name. Surfaces as the data-webui-resource value so
  // delivered stylesheets stay attributable without a source map.
  string name = 1;
  // Concatenated compiled CSS for the Style and Module strategies.
  // Empty for Link.
  string css = 2;
  // External stylesheet href for the Link strategy.
  // Empty for Style and Module.
  string css_href = 3;
  // Component tags whose CSS this chunk concatenates, in cascade order.
  repeated string component_tags = 4;
}

// A list of fragments (needed because protobuf maps cannot have repeated values directly).
message FragmentList {
  repeated WebUIFragment fragments = 1;
  // True when this record directly or transitively reaches a boundary
  // declaration. Computed once at build time so handlers never graph-walk a
  // request merely to decide whether rendering can suspend.
  bool contains_boundary = 2;
}

// A single fragment — one of several types.
message WebUIFragment {
  oneof fragment {
    WebUIFragmentRaw raw = 1;
    WebUIFragmentComponent component = 2;
    WebUIFragmentFor for_loop = 3;
    WebUIFragmentSignal signal = 4;
    WebUIFragmentIf if_cond = 5;
    WebUIFragmentAttribute attribute = 6;
    WebUIFragmentPlugin plugin = 7;
    WebUIFragmentRoute route = 8;
    WebUIFragmentOutlet outlet = 9;
    WebUIFragmentBoundary boundary = 10;
  }
}

// Which end of an inline boundary tape a fragment marks.
enum BoundaryPhase {
  // Opens a boundary body. Carries the full declaration metadata.
  BOUNDARY_PHASE_START = 0;
  // Closes the body opened by the matching start in the same record. Only
  // declaration_id is meaningful.
  BOUNDARY_PHASE_END = 1;
}

// Compile-time streaming boundary declaration, written as an inline tape.
//
// A declaration emits a start marker and an end marker into its owner's
// fragment record, with the body fragments in between. Ordinary rendering
// therefore walks the body without any extra record lookup, and streaming
// suspends and resumes inside the record it is already traversing.
//
// A declaration can produce multiple response-local occurrences through
// components, conditions, loops, and routes. Runtime occurrence IDs are
// therefore assigned later by the handler and are not stored here.
message WebUIFragmentBoundary {
  // Stable build-local declaration identity. Shared by the start/end pair.
  uint32 declaration_id = 1;
  // Entry or reusable component template that authored this declaration.
  string owner_fragment_id = 2;
  // Free-form authored name, unique only within owner_fragment_id.
  string name = 3;
  // Optional authored key expression preserved verbatim for handler evaluation.
  optional string key = 4;
  // Field 5 previously held the separately parsed boundary body record. Bodies
  // are now inline between the start and end markers.
  reserved 5;
  reserved "fragment_id";
  // Conservative graph result: this declaration may produce multiple runtime
  // occurrences through repeated component callsites. A `<for>` repeat can no
  // longer contribute: the build rejects every boundary a repeat body reaches
  // (`boundary-in-repeat`), because a repeat iteration cannot suspend.
  bool may_repeat = 6;
  // Whether this fragment opens or closes the declaration's body.
  BoundaryPhase phase = 7;
}

// Declarative route definition linking a URL path template to a component.
// Nested routes are expressed via repeated children.
message WebUIFragmentRoute {
  string path = 1;
  string fragment_id = 2;
  bool exact = 3;
  // Nested child routes rendered at the component's <outlet />.
  repeated WebUIFragmentRoute children = 4;
  // Comma-separated allowlist of query parameters forwarded as attributes.
  // Empty string means no query params are forwarded (deny-by-default).
  string allowed_query = 5;
  // When true, the router preserves the mounted component instance across
  // navigations instead of destroying and recreating it. Opt-in per route.
  bool keep_alive = 6;
  // Cache tag templates for this route (e.g. "thread:{threadId}", "inbox").
  // Placeholders like {param} are resolved at render time with actual param values.
  repeated string cache_tags = 7;
  // Invalidation tag templates (e.g. "inbox", "thread:{threadId}").
  // After a mutation action on this route, these tags are auto-invalidated.
  // Supports {param} placeholders resolved at render time.
  repeated string invalidates = 8;
  // Component tag name for the pending/loading UI (e.g. "mail-skeleton").
  // Validated at build time — build fails if the component does not exist.
  string pending_component = 9;
  // Component tag name for the error boundary UI (e.g. "error-page").
  // Validated at build time — build fails if the component does not exist.
  string error_component = 10;
  // Optional runtime content authored directly inside this route. The record
  // contains typed boundary references and is rendered only for this route
  // path; nested route declarations remain in children.
  string content_fragment_id = 11;
}

// Outlet placeholder — marks where matched child route content renders.
// Components use this to indicate where nested route children are rendered.
message WebUIFragmentOutlet {}

// Opaque plugin-specific data passed from parser plugin to handler plugin.
// WebUI framework does not interpret this data — it is a pass-through conduit.
// Each parser/handler plugin pair defines its own binary contract for the data field.
message WebUIFragmentPlugin {
  bytes data = 1;
}

// Static text or HTML content.
message WebUIFragmentRaw {
  string value = 1;
}

// Reference to a reusable component fragment.
message WebUIFragmentComponent {
  string fragment_id = 1;
}

// Loop directive iterating over a collection.
message WebUIFragmentFor {
  string item = 1;
  string collection = 2;
  string fragment_id = 3;
}

// Dynamic data binding via signal.
message WebUIFragmentSignal {
  string value = 1;
  bool raw = 2;
  // True inside an HTML raw-text context such as <style>. Raw-text signals do
  // not own replaceable HTML sibling ranges because comments parse as text.
  bool raw_text_context = 3;
}

// Conditional rendering fragment.
message WebUIFragmentIf {
  ConditionExpr condition = 1;
  string fragment_id = 2;
}

// Dynamic attribute binding.
message WebUIFragmentAttribute {
  string name = 1;
  // For simple dynamic attrs, the signal name.
  string value = 2;
  // For mixed (template) attrs, the sub-stream ID.
  string template = 3;
  // True for :-prefixed complex attributes.
  bool complex = 4;
  // True for the first dynamic attribute on a component element.
  bool attr_start = 5;
  // True for skipped attributes (class, style, role, data-*, aria-*).
  bool attr_skip = 6;
  // True for static attribute values on components.
  bool raw_value = 7;
  // For ?-prefixed boolean attributes, the condition tree.
  ConditionExpr condition_tree = 8;
}

// A condition expression tree.
message ConditionExpr {
  oneof expr {
    Predicate predicate = 1;
    NotCondition not = 2;
    CompoundCondition compound = 3;
    IdentifierCondition identifier = 4;
  }
}

// Simple comparison predicate.
message Predicate {
  string left = 1;
  ComparisonOperator operator = 2;
  string right = 3;
}

// Negation wrapper.
message NotCondition {
  ConditionExpr condition = 1;
}

// Two conditions joined by a logical operator.
message CompoundCondition {
  ConditionExpr left = 1;
  LogicalOperator op = 2;
  ConditionExpr right = 3;
}

// Single identifier (variable name).
message IdentifierCondition {
  string value = 1;
}

enum LogicalOperator {
  LOGICAL_OPERATOR_UNSPECIFIED = 0;
  AND = 1;
  OR = 2;
}

enum ComparisonOperator {
  COMPARISON_OPERATOR_UNSPECIFIED = 0;
  GREATER_THAN = 1;
  LESS_THAN = 2;
  EQUAL = 3;
  NOT_EQUAL = 4;
  GREATER_THAN_OR_EQUAL = 5;
  LESS_THAN_OR_EQUAL = 6;
}