Skip to content

Host namespaces

./host is the curated host surface a page may call (decision-27). It is generated from qgis_sdk.bridge.host, ships inside this package, and is versioned with it, so it cannot drift from the Python it talks to.

import { createHost } from "@archont561/qgis-sdk/host";
const host = createHost(client);
const page = await host.layers.list({ limit: 20 });
const layer = await host.layers.get({ layer_id: page.items[0]!.id });
const theme = await host.settings.get({ key: "theme", default: "light" });
  • The declared inventory: layers.list, layers.get, layers.open_vector, project.layer_ids, settings.get, notifications.info, styles.apply, files.export, the network.fetch stream and, since 0.7.0, algorithms.providers, algorithms.list, algorithms.describe and algorithms.run (below). Anything else of the QGIS API is not reachable from a page; the operations it would need wait for their owning task, and the Python manifest records which.
  • Paged, never unbounded. Every list takes {limit?, cursor?} and returns {items, truncated, next_cursor?}. limit is capped at 200, and the generated validator refuses a larger one before the call leaves the page. A cursor is only ever the value the host handed back in next_cursor: anything else is refused as invalid_payload instead of being read as “start over”, and the generated validator refuses it before the call leaves the page.
  • Typed results. host.layers.get returns VectorLayerInfo, not a record: geometry_type is one of the declared literals and crs is string | null.
  • The same asymmetry as plugin operations. Arguments are closed (an unknown one is a QgisSdkHostContractError before the transport), responses are additive (a field a newer host added is tolerated, a missing one is refused). The error extends QgisSdkError with code: "contract_validation_failed" and names the operation.
  • Versioned. HOST_SCHEMA_VERSION and HOST_OPERATIONS are exported, and the handshake advertises the same version, so a page can tell what it is talking to before its first call.

Processing from a page: algorithms.* and runAlgorithm

Section titled “Processing from a page: algorithms.* and runAlgorithm”

The four algorithms operations (decision-64) expose the host’s Processing registry behind two grants: algorithms.read for providers, list({provider?, limit?, cursor?}) and describe({algorithm_id}) - pages of ProviderInfo / AlgorithmSummary and one AlgorithmInfo whose parameters carry required, default_json (the default as JSON text, null when none), options, bounds and destination - and algorithms.run for run({algorithm_id, params}). The wire is generic JSON: params is the map the algorithm’s own description validates on the host before anything runs, and the RunResult is a list of tagged outputs - {name, kind: "vector", layer}, {name, kind: "file", file} or {name, kind: "value", value}. A layer input is an owned layer id; a file input is a FileRef this view holds, resolved against the view before the algorithm sees it; a file the run produced comes back as a read-only FileRef minted for the view. HOST_FINGERPRINT moved once for the four operations.

The typing lives next to the page, not in this package. qgis-sdk processing generate --web-out web/src/processing.schema.ts (the scaffold’s bindings script runs it after bridge generate) renders, per algorithm, <Provider><Name>Params and <Provider><Name>Result, an AlgorithmRegistry keyed by id, and a runAlgorithm bound to it:

import { runAlgorithm } from "./processing.schema";
const { outputs } = await runAlgorithm(qgis, "native:buffer", {
INPUT: layer.id,
DISTANCE: 25,
});
outputs.OUTPUT; // VectorLayerInfo | undefined, as NativeBufferResult declares

Under it the root exports the generic pieces the generated module imports: runAlgorithm<R, K>(qgis, id, params, options?) (sends one algorithms.run and keys the tagged outputs by name), outputsByName, AlgorithmHost, AlgorithmRun<Result>, AlgorithmRegistryLike, and the value aliases LayerRef, Destination (FileRef | null: a page never names a path), Extent, PointValue and RangeValue. A test scripts the operation like any host id: harness.expectInvoke("algorithms.run", (payload) => ({ algorithm: "native:buffer", outputs: [...] })). The scaffold writes web/src/processing.schema.ts for native from the runtime’s own snapshot and grants algorithms.run; bindings regenerates it against the project’s QGIS, so a registry that differs shows up as drift rather than a stale type.