Expand description
§The host API (VAPP-91)
What a surface needs from its host, the same on all four platforms
(packages/exponential-ui/catalog/host.json): the router turning server
messages into ops, the wire decoders (JSONL, SSE, A2UI-over-MCP), the
function / URL / media policy, binding sources, catalog negotiation and
declarative app packages. A line-by-line port of the TypeScript reference
(packages/exponential-ui/src/host/) over serde_json::Value; every
output is JSON-equal to it, locked by fixtures/host-*.json. The I/O
(transports, the runtime host) stays on each platform; the Swift and
Kotlin painters reach this module through exponential-ui-ffi.
Re-exports§
pub use actions::action_call_name;pub use actions::action_var_types;pub use actions::apply_record_batch;pub use actions::apply_record_batch_as;pub use actions::function_effect;pub use actions::is_action_name;pub use actions::run_action;pub use actions::validate_package_actions;pub use actions::validate_package_effects;pub use actions::ActionContext;pub use actions::ACTION_CALL_PREFIX;pub use actions::ACTION_LIMIT_ACTIONS;pub use actions::ACTION_LIMIT_MAX_STEPS;pub use actions::ACTION_LIMIT_STEPS;pub use actions::ACTION_NAME_PATTERN;pub use actions::ACTION_STEP_KINDS;pub use actions::RECORDS_BATCH_FUNCTION;pub use components::validate_package_components;pub use expressions::literal_type;pub use expressions::record_row_type;pub use expressions::records_value_type;pub use expressions::schema_type;pub use expressions::validate_package_expressions;pub use expressions::validate_record_computed;pub use exposes::expose_action_access;pub use exposes::expose_issues;pub use exposes::expose_name_destructive;pub use exposes::expose_template_paths;pub use exposes::validate_package_exposes;pub use exposes::validate_upstreams;pub use exposes::ExposeIssue;pub use decoders::decode_jsonl;pub use decoders::mcp_action_call;pub use decoders::messages_from_mcp_result;pub use decoders::DecodeIssue;pub use decoders::Decoded;pub use decoders::JsonlDecoder;pub use decoders::SseDecoder;pub use package::available_extensions;pub use package::client_capabilities;pub use package::merge_data;pub use package::package_sources;pub use package::source_allowed;pub use package::supported_catalog_ids;pub use package::template_messages;pub use package::validate_package;pub use package::validate_package_in;pub use package::validate_package_with;pub use package::version_satisfies;pub use package::AvailableExtension;pub use package::PackageIssue;pub use package::PACKAGE_FORMAT_VERSION;pub use policy::combine_decisions;pub use policy::decide_function;pub use policy::decide_url;pub use policy::expand_link_base;pub use policy::image_dimensions;pub use policy::image_frames;pub use policy::image_header;pub use policy::is_builtin_function;pub use policy::is_private_host;pub use policy::media_image_check;pub use policy::ImageHeader;pub use policy::matches_pattern;pub use policy::media_image_within_limits;pub use policy::media_request;pub use policy::media_within_limits;pub use policy::package_policy;pub use policy::svg_dimensions;pub use policy::police_text_links;pub use policy::safe_href;pub use policy::FunctionDecision;pub use policy::FunctionPolicy;pub use policy::MediaOptions;pub use policy::MediaRequest;pub use policy::MediaRule;pub use policy::TextLink;pub use policy::UrlDecision;pub use policy::UrlPolicy;pub use policy::BUILTIN_FUNCTIONS;pub use router::normalize_path;pub use router::HostRouter;pub use router::SurfaceInfo;pub use screens::cross_app_target;pub use screens::cross_app_target_value;pub use screens::fill_screen_params;pub use screens::package_screens;pub use screens::resolve_screen;pub use screens::screen_data;pub use screens::validate_package_screens;pub use screens::ResolvedScreen;pub use screens::MAX_SCREENS;pub use screens::MAX_SCREEN_TITLE;pub use screens::MAX_EXPOSED_DESCRIPTION;pub use screens::NAVIGATE_FUNCTION;pub use screens::SCREEN_PARAMS_KEY;pub use query::computed_data;pub use query::expand_query_source;pub use query::fill_query_templates;pub use query::kind_computed;pub use query::kind_refs;pub use query::month_days;pub use query::month_label;pub use query::parse_records_json;pub use query::parse_records_query;pub use query::parse_records_source;pub use query::records_value;pub use query::records_value_owned;pub use query::shift_month;pub use query::RecordRow;pub use query::RecordRowRef;pub use query::RecordsAggregate;pub use query::RecordsAggregateOp;pub use query::RecordsBefore;pub use query::RecordsContext;pub use query::RecordsDay;pub use query::RecordsFilter;pub use query::RecordsFilterOp;pub use query::RecordsFilterValue;pub use query::RecordsGroupKey;pub use query::RecordsMonthView;pub use query::RecordsOrder;pub use query::RecordsQueryIssue;pub use query::RecordsRunning;pub use query::RecordsRunningOp;pub use query::RecordsQuery;pub use query::RecordsSortKey;pub use query::RECORDS_AGGREGATE_OPS;pub use query::RECORDS_AGGREGATE_RESERVED;pub use query::RECORDS_COMPUTED_MAX;pub use query::RECORDS_COMPUTED_ROW_KEYS;pub use query::RECORDS_FILTER_OPS;pub use query::RECORDS_MONTHS;pub use query::RECORDS_OP_ALIASES;pub use query::RECORDS_RUNNING_OPS;pub use query::RECORDS_RESERVED_PARAMS;pub use query::RECORDS_ROW_KEYS;pub use query::RECORDS_SCHEME;pub use query::RECORDS_WEEKDAYS;pub use record_migrations::is_version_range;pub use record_migrations::kind_changes;pub use record_migrations::kind_changes_json;pub use record_migrations::migrate_record;pub use record_migrations::migration_refusal;pub use record_migrations::package_migrations;pub use record_migrations::range_holds;pub use record_migrations::validate_migrations;pub use record_migrations::KindChange;pub use record_migrations::MigrateResult;pub use record_migrations::MIGRATION_OP_NAMES;pub use record_migrations::RECORD_MIGRATIONS_MAX;pub use record_migrations::RECORD_MIGRATION_OPS_MAX;pub use record_transitions::initial_states;pub use record_transitions::kind_transitions;pub use record_transitions::transition_refusal;pub use record_transitions::transitions_from;pub use record_transitions::validate_record_transitions;pub use record_transitions::RecordTransitions;pub use record_transitions::TransitionRefusal;pub use record_transitions::TransitionViewer;pub use record_transitions::RECORD_TRANSITIONS_ROW_KEY;pub use record_transitions::TRANSITION_LEVELS;pub use record_policy::readable_rows;pub use record_policy::record_allowed;pub use record_policy::record_policy;pub use record_policy::record_policy_copy;pub use record_policy::record_refusal;pub use record_policy::validate_record_policy;pub use record_policy::RecordOp;pub use record_policy::RecordPolicy;pub use record_policy::RecordViewer;pub use record_policy::APP_ACCESS_LEVELS;pub use record_policy::DEFAULT_RECORD_POLICY;pub use record_policy::RECORD_POLICY_LEVELS;pub use record_policy::RECORD_POLICY_OPS;pub use record_store::RECORDS_FUNCTIONS;pub use records::is_record_kind;pub use records::record_attachment_fields;pub use records::record_attachment_id;pub use records::record_attachment_ids;pub use records::validate_record;pub use records::validate_record_refs;pub use records::validate_record_schema;pub use records::RECORD_FIELD_TYPES;pub use records::RECORD_FORMATS;pub use records::RECORD_RESERVED_KEYS;pub use signature::canonical_json;pub use signature::package_file_signed_bytes;pub use signature::AUTHOR_KEY_PREFIX;pub use signature::AUTHOR_NAME_MAX;pub use signature::PACKAGE_FILE_SIGNATURE_ALG;pub use signature::PACKAGE_FILE_SIGNATURE_CONTEXT;pub use sources::parse_source;pub use sources::source_with_params;pub use sources::ParsedSource;pub use tests::package_test_issues;pub use tests::run_package_tests;pub use tests::test_failure;pub use tests::test_matches;pub use tests::validate_package_tests;pub use tests::PackageTestResult;pub use tests::PACKAGE_TEST_DEFAULT_AS;pub use tests::PACKAGE_TEST_DEFAULT_NOW;pub use tests::PACKAGE_TEST_DEFAULT_ROLE;pub use tests::PACKAGE_TEST_ROLES;pub use tests::PACKAGE_TEST_KINDS;pub use tests::PACKAGE_TEST_LIMIT_GOT_MAX;pub use tests::PACKAGE_TEST_LIMIT_TESTS;pub use tools::tool_call;pub use tools::tool_consent;pub use tools::tool_consent_key;pub use tools::validate_tools;pub use tools::ToolCall;pub use tools::ToolConsentRow;pub use tools::TOOL_KINDS;pub use contract::*;
Modules§
- actions
- VAPP-194 (eApps E1, spec docs/spec/apps.md §4.5): typed effects, the
twin of
packages/exponential-ui/src/host/actions.ts(read its header). - calendar
- eApps U3 (VAPP-232, spec §17 U3): the CALENDAR half of the records
query, the Rust twin of
packages/exponential-ui/src/host/calendar.ts(fixtures/records-query.json locks both): the month view’s weeks with their lanes, the week view and the timeline. Pure day maths over day numbers (crate::dates).host::queryfilters and sorts the rows, then hands each placed row here as aCalendarSpan. - components
- VAPP-203: install checks every template the way the renderer will. Each
template’s components go through the reducer (
reduce_surface: unknown components, missing or wrong props, child ids that name nothing, cycles, slots, styles), so a package that would render broken never installs. A reducer issue (keyed by a component id) becomes a JSON pointer: the component’s own entry, or, for an id no component has, every place that names it (children/<j>,children/componentId,slots/<name>). The twin ofsrc/host/components.ts(fixtures/host-router.json). - contract
- The host API contract (
catalog/host.json) as constants, plus the client messages every platform host sends (tests/host_fixtures.rsgates the constants against the JSON). - decoders
- The wire decoders every transport adapter shares (pure, incremental,
fixture-locked in
fixtures/host-transport.json): A2UI JSONL over a byte stream, Server-Sent Events, and the A2UI-over-MCP carrier. - exposes
- VAPP-180: the MCP tools a package EXPOSES (docs/package-format.md
“Exposes”): declarative bindings
{name, title, description, input, access, run}a host’s MCP broker lists and runs as the calling person, never code. The format half of the eMCP contract; what a run may reach on a given host is that host’s own check. Mirrorspackages/exponential-ui/src/host/exposes.tsline by line;fixtures/host-router.json(validation) replays it. - expressions
- VAPP-191 (eApps Q2): expressions are type-checked at package validation,
the twin of
src/host/expressions.ts. Every{"call": "expr", "args": {"expr": "<CEL>", "vars": {…}}}anywhere in a template is parsed and checked (crate::cel::check_expression) against the types of its vars: a literal’s own type, a records binding’s value (the kind’s schema fields) or the template data’s; anything else is open (dyn). An issue names the JSON pointer of the expression and the reason (fixtures/expressions.jsonpackages). - package
- Catalog negotiation and declarative app packages (VAPP-82: a manifest + A2UI templates + bindings, data never code).
- policy
- The policy rules every host applies before a client function, a URL open
or a media load (
catalog/host.jsonfunctions / urls / media). Pure;fixtures/host-policy.jsonlocks them on every platform. - query
- VAPP-189 (S1): THE records query, the Rust twin of
packages/exponential-ui/src/host/query.ts, locked byfixtures/records-query.json(parseCases,sourceCases,jsonCases,valueCases,expandCases;bucketCaseslockcrate::dates). A binding’s URL sugar (records:<kind>?q) parses INTO the structuredRecordsQuery;records_valueevaluates it over the rows of any store. The desktop host calls it directly; the Swift and Compose SDKs reach it throughexponential-ui-ffi(parse_records_query_json,parse_records_json,parse_records_source_json,records_value_json). - record_
macros - VAPP-217 (eApps U2): the HOST half of the RecordForm and RecordTable
macros, the mirror of
src/host/record-macros.ts(fixtures/record-macros.jsonlocks both). A macro sees only its node’s props, so before a template is reduced the host fills every RecordForm / RecordTable node of the flat component list from its kind’s schema: the fields with their checks, the table columns (the Data tab’s typed widths), the rows binding, the draft path and the actions. The macro table then expands the filled node like any other. - record_
migrations - eApps R8 (VAPP-233, docs/spec/apps.md §3.6/§2.3): declarative record
migrations between package versions. A line-by-line port of
src/host/record-migrations.ts;fixtures/record-migrations.jsonis the spec (tests/record_migrations.rsreplays it). - record_
policy - eApps R3 (docs/spec/apps.md §3.4, §9): who may read, create, update and
delete a kind’s records, under the member’s app access. A line-by-line
port of
src/host/record-policy.ts;fixtures/record-policy.jsonis the spec (tests/record_policy.rsreplays it). - record_
store - VAPP-161: the format’s NEUTRAL records (docs/package-format.md
“Records”). A surface reads a kind through the binding
records:<kind>?queryand writes through the host functionsrecords.upsert/records.delete; the HOST provides the store. The query and its value aresuper::query(VAPP-189: one evaluator over the rows of any store,fixtures/records-query.json). - record_
transitions - eApps R6 (VAPP-222, docs/spec/apps.md §3.3/§3.4): a kind’s state machine
on ONE enum field (
records.<kind>.transitions). A line-by-line port ofsrc/host/record-transitions.ts;fixtures/record-transitions.jsonis the spec (tests/record_transitions.rsreplays it). - records
- VAPP-122: an app’s RECORDS, its own data. The manifest declares every
kind with a JSON Schema SUBSET (
records: {<kind>: {schema}}); a host validates a record against it before it is stored. Mirrorspackages/exponential-ui/src/host/records.tsline by line;fixtures/host-router.jsonrecordsreplays it. - router
- The host router. Server messages in, ops out (
catalog/host.jsonops); the platform host performs them on its surfaces. Pure and synchronous, sofixtures/host-router.jsonlocks the same behaviour on every platform. - screens
- VAPP-218 (eApps U1): a package’s SCREENS, the navigation manifest. A
line-by-line port of
packages/exponential-ui/src/host/screens.ts;fixtures/host-router.json(validation,screens,navigate) locks the same behaviour on every platform.screens: [{template, title, icon?, params?, nav?, exposed?}]lists the templates a person can open (keyed by the template); the host draws the navigation;app.navigate {screen, params?}opens one, its params landing under/params/*. #EXP-1674:nav: false= a detail screen, left out of the navigation;exposed= the public contract other apps link to. - share
- VAPP-241 (eApps P1): a package’s PUBLIC LINK definitions, the mirror of
packages/exponential-ui/src/host/share.ts;fixtures/package-share.jsonlocks both. The links themselves are the host’s. - signature
- VAPP-161: the PACKAGE FILE’s signed bytes (docs/package-format.md “The
package file”): a context line + the RFC 8785 canonical JSON of the whole
file without
signature. MirrorscanonicalJson+packageFileSignedBytesofpackages/exponential-ui/src/host/signature.ts; the Ed25519 itself is the host’s own (no crypto here).fixtures/host-package.jsoncanonical+signatures[].signedTextreplay it. - sources
- Binding sources. A data model path can follow a host source
(
exp:issues?board=…): the host registers one resolver per scheme, the router emits abindop, the resolver’s emits land at the path. - tests
- VAPP-196 (eApps T1): PACKAGE TESTS, the twin of
packages/exponential-ui/src/host/tests.ts. A package carriestests: [{name, records?, now?, as?, expr | query | action, expect}];validate_packageruns every one on an otherwise valid package, each against its OWN in-memory store seeded withrecords, on a fixed clock (now, UTC) as the memberas. A failing test is an install issue at/tests/<i>(expected vs got). Locked byfixtures/package-tests.json. - tools
- VAPP-161: a package’s TOOLS (docs/package-format.md “Tools”): the MCP
servers and scripts its functions call (
tools.<id>.<name>for an MCP tool,tools.<id>for a script), each behind the consent card the host MUST show before the first call. Mirrorspackages/exponential-ui/src/host/tools.tsline by line;fixtures/host-router.json(validation) andfixtures/host-package.jsonconsent+toolCallsreplay it.