Skip to main content

Module host

Module host 

Source
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::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::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::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::nav_screens;
pub use screens::navigate_target;
pub use screens::navigate_target_value;
pub use screens::package_screens;
pub use screens::resolve_screen;
pub use screens::screen_data;
pub use screens::validate_package_screens;
pub use screens::NavigateTarget;
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_author_of;
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::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::query filters and sorts the rows, then hands each placed row here as a CalendarSpan.
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 of src/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.rs gates 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. Mirrors packages/exponential-ui/src/host/exposes.ts line 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.json packages).
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.json functions / urls / media). Pure; fixtures/host-policy.json locks them on every platform.
query
VAPP-189 (S1): THE records query, the Rust twin of packages/exponential-ui/src/host/query.ts, locked by fixtures/records-query.json (parseCases, sourceCases, jsonCases, valueCases, expandCases; bucketCases lock crate::dates). A binding’s URL sugar (records:<kind>?q) parses INTO the structured RecordsQuery; records_value evaluates it over the rows of any store. The desktop host calls it directly; the Swift and Compose SDKs reach it through exponential-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.json locks 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.json is the spec (tests/record_migrations.rs replays 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.json is the spec (tests/record_policy.rs replays 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>?query and writes through the host functions records.upsert / records.delete; the HOST provides the store. The query and its value are super::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 of src/host/record-transitions.ts; fixtures/record-transitions.json is the spec (tests/record_transitions.rs replays 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. Mirrors packages/exponential-ui/src/host/records.ts line by line; fixtures/host-router.json records replays it.
router
The host router. Server messages in, ops out (catalog/host.json ops); the platform host performs them on its surfaces. Pure and synchronous, so fixtures/host-router.json locks 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.json locks 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. Mirrors canonicalJson + packageFileSignedBytes of packages/exponential-ui/src/host/signature.ts; the Ed25519 itself is the host’s own (no crypto here). fixtures/host-package.json canonical + signatures[].signedText replay 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 a bind op, 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 carries tests: [{name, records?, now?, as?, expr | query | action, expect}]; validate_package runs every one on an otherwise valid package, each against its OWN in-memory store seeded with records, on a fixed clock (now, UTC) as the member as. A failing test is an install issue at /tests/<i> (expected vs got). Locked by fixtures/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. Mirrors packages/exponential-ui/src/host/tools.ts line by line; fixtures/host-router.json (validation) and fixtures/host-package.json consent + toolCalls replay it.