|
Some checks are pending
CI / Lint (push) Waiting to run
CI / Build Test (stage-tamagotchi) (push) Waiting to run
CI / Build Test (stage-tamagotchi-godot) (push) Waiting to run
CI / Build Test (stage-web) (push) Waiting to run
CI / Build Test (ui-loading-screens) (push) Waiting to run
CI / Build Test (ui-transitions) (push) Waiting to run
CI / Unit Test (push) Waiting to run
CI / Type Check (push) Waiting to run
CI / Check Provenance (push) Waiting to run
Cloudflare Pages (Auth UI) / Deploy - ui-server-auth (push) Waiting to run
Cloudflare Workers / Deploy - stage-web (push) Waiting to run
Update Nix pnpmDeps Hash / update (push) Waiting to run
|
||
|---|---|---|
| .. | ||
| docs/design | ||
| src | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| tsdown.config.ts | ||
| vitest.config.ts | ||
@proj-airi/plugin-sdk
Runtime-agnostic SDK for AIRI extensions.
Kit API Naming
Kits should hide transport details from extension authors. A normal extension should use a kit as a normal API object directly from setup:
const gamelets = await ctx.kits.use(gameletKit)
await gamelets.mount(input)
Explicit module scopes are an advanced lifecycle and attribution API. Use module.kits.use(...) only when the host needs a contribution to be associated with a sub-scope that may later be inspected, disposed, or restarted independently.
When a kit needs to work across process or network boundaries, expose shared Eventa invoke contracts from the kit package and build the client from those contracts. Do not introduce kit-specific transport method names such as invokeGamelet, gameletRpc, or gameletRuntime.
Use these names consistently:
| Name | Meaning |
|---|---|
gameletKitApis |
Shared Eventa API contract exported by the kit package. This is usually a map of defineInvokeEventa(...) entries. |
gameletKitService |
Host-side implementation of the kit behavior. It owns real side effects such as mounting, updating, and cleaning up UI. |
gameletKit |
The kit definition consumed by ctx.kits.use(...) or an optional module scope. It owns identity, version, availability policy, and client creation. |
gamelets |
The client instance returned to extension authors. Prefer a plural namespace when the client exposes multiple operations. |
createGameletKit(...) |
Factory that wires dependencies into gameletKit, including local client creation and remote Eventa-backed client creation. |
Example shape:
export const gameletKitApis = {
mount: defineInvokeEventa<GameletMountResult, GameletMountInput>(
'airi:kit:gamelet:mount',
),
}
export interface GameletKitService {
mount: (input: GameletMountInput, scope: KitCallScope) => Promise<GameletMountResult>
}
export function createGameletKit(options: { service: GameletKitService }) {
return defineKit<GameletClient>({
id: 'kit.gamelet',
version: '1.0.0',
createClient(runtime) {
return {
mount: input => options.service.mount(input, runtime),
}
},
})
}
Remote clients should reuse Eventa invoke instead of defining a parallel RPC protocol. Use a lazy context callback when the underlying transport can reconnect or be created after the client object:
const mount = defineInvoke(getContext, gameletKitApis.mount)
const gamelets = {
mount(input: GameletMountInput) {
return mount(input, scope)
},
}
The shared artifact is the Eventa API contract, not the implementation function. Local clients may call gameletKitService directly; remote clients call the same API through Eventa. Both should expose the same authoring shape.