Core API

Everything in @playerstack/core.

Playerstack singleton

The entry point. Register plugins, then call define() to register the custom element.

import { Playerstack } from "@playerstack/core";

Playerstack.use(somePlugin).use(anotherPlugin).define();
MethodReturnsDescription
use(plugin)Playerstack (chainable)Register a plugin. Throws on duplicate name
plugins()readonly PlayerstackPlugin[]Snapshot of registered plugins (read-only)
define()voidRegister <player-stack> custom element. Idempotent

PlayerstackPlugin

The interface every plugin implements:

interface PlayerstackPlugin {
  readonly name: string;
  init(ctx: PlayerstackContext): void | Promise<void>;
  destroy?(ctx: PlayerstackContext): void;
}

PlayerstackContext

What init and destroy receive:

interface PlayerstackContext {
  events: EventBus; // typed pub/sub
  container: HTMLElement; // the <player-stack> itself
  mediaPlayer: HTMLElement; // the inner <media-player>
  config: PlayerstackConfig;
}

Plugins read their slice of config and mutate mediaPlayer and container as needed. Use events to communicate with other plugins or your application.

EventBus

Strongly typed pub/sub.

const bus = createEventBus<{ "cta:click": { label: string; url: string } }>();

const unsubscribe = bus.on("cta:click", ({ label, url }) => {
  console.log(label, url);
});

bus.emit("cta:click", { label: "Buy", url: "..." });
unsubscribe();
// or:
const removed = bus.off("cta:click", handler); // returns boolean
MethodReturns
on(name, handler)unsubscribe function
off(name, handler)boolean (was it removed?)
emit(name, payload)void

Handlers that throw don’t stop later handlers — errors are logged.

ConfigProvider

How config gets loaded for a <player-stack> element.

interface ConfigProvider {
  readonly name: string;
  load(element: HTMLElement): Promise<PlayerstackConfig>;
}

The default is createInlineConfigProvider(), which reads src, poster, title attributes plus the data-config JSON attribute. JSON wins on merge.

Replace the default via:

import { setConfigProviderForElement } from "@playerstack/core";
setConfigProviderForElement(myProvider);

See sellf-adapter for an example.

PlayerstackConfig

interface PlayerstackConfig {
  src: string; // required
  poster?: string;
  title?: string;
  [key: string]: unknown; // plugin-specific slices
}

Plugin-specific slices live alongside the core fields:

See each plugin’s docs for its slice schema.

PluginRegistry

Lower-level — you usually don’t need this directly. The Playerstack singleton uses it internally. Exposed in case you’re writing tooling.

import { createPluginRegistry } from "@playerstack/core";

const reg = createPluginRegistry();
reg.register(plugin);
await reg.init(ctx);
// ...
reg.destroy();

reg.init(ctx) throws if called twice without destroy() in between.