Provide and invoke an intent
An intent is a named, versioned capability one app offers and another invokes. The shell resolves a provider and relays the call; neither app imports the other.
Provide an intent
Section titled “Provide an intent”Declare the intent in your contract with its payload and result JSON schemas:
// in contract.tsprovides: [ { intent: "customer.lookup", version: "1.0", kind: "request", payloadSchema: { type: "object", properties: { q: { type: "string" } }, required: ["q"] }, resultSchema: { type: "object", properties: { matches: { type: "array" } } }, },],Wire the handler with platform.provide. It returns a disposer; call it on teardown.
import { Component, OnDestroy, inject } from "@angular/core";import { PLATFORM } from "../shared/platform.token";
interface LookupPayload { q: string;}interface Customer { id: string; name: string; email: string;}
// Providing an intent: other apps can invoke "customer.lookup@1.0" and the shell routes it here. The// declaration belongs in contract.ts (with payload/result JSON schemas); provide() wires the handler.// It returns a disposer — call it on teardown.@Component({ selector: "lookup-provider", template: `` })export class LookupProvider implements OnDestroy { private readonly platform = inject(PLATFORM); private readonly dispose: () => void;
constructor() { this.dispose = this.platform.provide<LookupPayload>( "customer.lookup", "1.0", async (payload) => { const matches = await this.search(payload.q); return { matches }; }, ); this.platform.ready(); }
private async search(q: string): Promise<Customer[]> { const res = await fetch(`/api/customers?q=${encodeURIComponent(q)}`, { credentials: "same-origin", }); return (await res.json()) as Customer[]; }
ngOnDestroy(): void { this.dispose(); }}Invoke an intent
Section titled “Invoke an intent”Call platform.invoke. It rejects with a PlatformError on
timeout, no provider, or a handler error. Options let you pin a version, choose a resolve policy, or
target a specific provider.
import { Component, inject, signal } from "@angular/core";import type { PlatformError } from "@platform/sdk";import { PLATFORM } from "../shared/platform.token";
interface LookupResult { matches: { id: string; name: string; email: string }[];}
// Invoking another app's intent. The shell resolves a provider and relays the call; invoke() rejects// with a PlatformError on timeout, no provider, or a handler error. Options let you pin a version,// choose a resolve policy, or target a specific provider.@Component({ selector: "lookup-box", template: ` <input #q (keyup.enter)="lookup(q.value)" /> @if (error(); as e) { <p class="error">{{ e }}</p> } <ul> @for (m of matches(); track m.id) { <li>{{ m.name }}</li> } </ul> `,})export class LookupBox { private readonly platform = inject(PLATFORM); protected readonly matches = signal<LookupResult["matches"]>([]); protected readonly error = signal<string | null>(null);
async lookup(q: string): Promise<void> { this.error.set(null); try { const result = await this.platform.invoke<LookupResult>( "customer.lookup", { q }, { resolve: "first", timeoutMs: 5000 }, ); this.matches.set(result.matches); } catch (e) { this.error.set((e as PlatformError).message); } }}See also
Section titled “See also”Platform.provideandPlatform.invokein the reference.- Surfaces vs modals vs intents vs events — when to reach for which.