Developer Docs

How to create, publish, and maintain Saltshaker plugins using the public registry and the exposed plugin API.

Quickstart

  1. Create a plugin repository (your source code lives here).
  2. Produce a bundled JavaScript entry file (self-contained runtime output).
  3. Export the required lifecycle hooks (onInit, optional onDispose).
  4. Add a per-plugin manifest to the public registry catalog (metadata only).
  5. Use the registry workflow to bundle and publish a versioned release artifact.

Plugin contract

A Saltshaker plugin is a Node-compatible module that exports lifecycle hooks. Saltshaker will call:

  • onInit(api) (required): initialize, subscribe, and begin emitting outputs
  • onDispose() (recommended): unsubscribe, remove handlers, and clean up
Core responsibility

Your plugin is responsible for deriving: (1) a stable user identifier (uid) and (2) a shared room code (roomCode) so Saltshaker can coordinate peer-to-peer behavior across users.

Runtime API surface

The plugin runtime injects a single object named api into your plugin. The following surfaces are currently supported.

API Description
api.log(...args) Writes plugin-prefixed logs to the client log stream.
api.sendEvent(name, ...args) Emits an outbound plugin event to the platform (e.g. connect, disconnect).
api.on(name, handler) Subscribes to an inbound platform event. Returns a disposer function that removes the handler.
api.settings.get(key, fallback) Reads a plugin setting value (typed at the manifest level).
api.settings.onChange(handler) Receives setting updates for the active plugin (if supported by the runtime).
api.host.file.readText(resourceId) Reads a declared resource as text (permission-gated).
api.host.file.readJson(resourceId) Reads a declared resource as JSON (permission-gated).
api.host.dolphin.subscribe({ events: [...] }) Subscribes to Dolphin events (permission-gated).
api.host.dolphin.unsubscribe({ events: [...] }) Unsubscribes from Dolphin events you previously subscribed to.
Common event names
Inbound
  • dolphin:GameStart
  • dolphin:GameEnd
  • dolphin:Disconnected
  • dolphin:Error
Outbound (typical)
  • connect(roomCode, uid)
  • disconnect(roomCode, uid)

Permissions

Permissions are declared in the registry manifest and determine which host capabilities are available at runtime. Request the minimum set needed.

Typical permissions
  • file.read — allows reading declared resources via api.host.file
  • dolphin.subscribe — allows subscribing to Dolphin events via api.host.dolphin

Resources

Resources are a whitelist of files that Saltshaker will allow your plugin to read. Resources are accessed by ID rather than by filesystem path.

How resources are used
  • The registry manifest declares { id, path, type } for each resource.
  • The plugin reads the resource using api.host.file.readText(resourceId) or readJson(resourceId).
  • Plugins should treat resource contents as sensitive user data.

Settings

Settings are declared in the registry manifest so Saltshaker can render configuration UI for users. Plugins read settings at runtime and can optionally react to changes.

Recommended pattern
  • Read setting values during onInit using api.settings.get.
  • If supported, subscribe to changes using api.settings.onChange.
  • Use safe defaults when settings are missing or unreadable.

Publishing via the registry

Saltshaker uses a public plugin registry repository that contains metadata and release artifacts. You publish a plugin by adding or updating the per-plugin manifest in the registry and triggering the bundling workflow.

Registry manifest responsibilities
  • Declare plugin metadata: id, name, description, version, repository, commit, minClientVersion.
  • Declare required permissions, resources, and settings.
  • Do not manually set the artifact URL or SHA-256 hash; those are populated by the bundling workflow.
  • Update the catalog index to point “latest” at the new version after publishing.

Best practices

  • Be deterministic. Emit connect/disconnect idempotently and avoid oscillation.
  • Clean up aggressively. Unsubscribe from upstream sources and remove listeners during disposal.
  • Keep permissions minimal. Request only what you need for the plugin’s function.
  • Avoid collecting data. Only derive what is required to operate (uid, roomCode).
  • Fail safe. If required inputs are missing (e.g. no user identifier), suppress connect/disconnect rather than emitting malformed events.
Contribution expectations
  • Provide a clear README for users and maintainers.
  • Document what permissions you require and why.
  • Keep changes narrowly scoped and testable.