Skip to content

@ekrooh/bare/plugins

The plugins subpath exports the canonical plugin factories; the /plugins/*/events subpaths export the typed event builders for the frontend.

  • createDefaultPlugins(deps) — wires core.health, core.discovery, core.permissions, vendor.media, and core.logs with the runtime’s loopback server and host IPC bridge.

The core.* and vendor.* namespaces are reserved for these framework plugins: registering any other id there throws. Name your plugins in your own namespace (app.photos).

  • Types: DefaultPluginsDeps, DiscoveryPluginDeps, MediaPluginDeps, LogsPluginDeps.
PluginEventsPurpose
core.healthhealth.pingliveness for the web layer
core.discoverydiscovery.listruntime/capability discovery
core.permissionspermissions.request / permissions.statusstorage/camera permission abstraction
vendor.mediamedia.pick / media.captureout-of-band binary (photos/video)
core.logslogs.view / logs.clearbounded worklet + web log collection

Each plugin’s events.ts exports the same structure:

  • *Specs — the EventSpecs that drive definePlugin.
  • *Events — typed builders for dispatch/invoke calls, so the frontend never hand-builds headers:
import { healthEvents } from '@ekrooh/bare/plugins/health/events';
import { mediaEvents } from '@ekrooh/bare/plugins/media/events';
import { permissionEvents } from '@ekrooh/bare/plugins/permissions/events';
import { discoveryEvents } from '@ekrooh/bare/plugins/discovery/events';
import { logEvents } from '@ekrooh/bare/plugins/logs/events';

Builders are grouped by plugin namespace (mediaEvents.media.pick), and a page sends them through a PluginBus, which resolves to [error, result]:

import type { PluginBus } from '@ekrooh/bare/core';
import { discoveryEvents } from '@ekrooh/bare/plugins/discovery/events';
import { logEvents } from '@ekrooh/bare/plugins/logs/events';
import { mediaEvents } from '@ekrooh/bare/plugins/media/events';
import { permissionEvents } from '@ekrooh/bare/plugins/permissions/events';
declare const bus: PluginBus; // createPluginBus(messenger), see Transports
const [mediaErr, media] = await bus.invoke(mediaEvents.media.pick('image'));
const [, discovery] = await bus.invoke(discoveryEvents.discovery.list());
const [, permission] = await bus.invoke(
permissionEvents.permissions.request('camera'),
);
const [, logs] = await bus.invoke(
logEvents.logs.view({ tail: 20, level: 'warn' }),
);

Event args are untrusted page input. The canonical plugins check what they use: vendor.media allowlists kind, core.logs rejects a non-number tail or an unknown level/source with PLUGIN_ERROR, and the hosts allowlist permission ids (unknown ids are unsupported).

  • MediaResult — { url } (the on-device path never leaves the host/worklet).
  • PermissionResult — { permission, status } with granted | denied | notDetermined | unsupported.
  • DiscoveryListResult — { schemaVersion: 1, capabilities }, the worklet’s and the host’s capability rows.
  • LogsViewResult — { entries: LogEntry[] } where LogEntry is { seq, ts, level, source, tag?, message }.