@vestra-player/sdk 1.5.48 → 1.5.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,6 +37,15 @@ export type Change = ReadonlyMap<string, ReadonlySet<string>>;
37
37
  * without `update()`) still shows within about this long.
38
38
  */
39
39
  export declare const SAFETY_PASS_MS = 1000;
40
+ /** How the plugin is run: the player's runner, or `TestHost`. */
41
+ export interface RuntimeOptions {
42
+ /**
43
+ * A declaration the player refuses during activation fails activation
44
+ * (`startPlugin`, so a plugin's tests show it) instead of being logged,
45
+ * reported to `onError` and skipped (the player's runner).
46
+ */
47
+ strictDeclarations?: boolean;
48
+ }
40
49
  export declare const same: (a: Json | undefined, b: Json | undefined) => boolean;
41
50
  /** One value in flight, only the newest waiting. Each push learns its fate. */
42
51
  export declare class Latest<T> {
@@ -74,7 +83,7 @@ export declare class Runtime {
74
83
  * property writes). Not part of the plugin API; empty for older players.
75
84
  */
76
85
  readonly features: ReadonlySet<string>;
77
- constructor(transport: Transport, manifest: PluginManifest, directory: string, dataDirectory?: string, app?: unknown);
86
+ constructor(transport: Transport, manifest: PluginManifest, directory: string, dataDirectory?: string, app?: unknown, options?: RuntimeOptions);
78
87
  can(capability: string): boolean;
79
88
  /** Lazily created singletons shared by every scope of this plugin. */
80
89
  service<T>(name: string, create: () => T): T;
@@ -83,6 +92,16 @@ export declare class Runtime {
83
92
  * plugin reports ready; later ones report failures to their scope.
84
93
  */
85
94
  starting<T>(work: Promise<T>, report: (error: unknown) => void): Promise<T>;
95
+ /**
96
+ * A declaration the player checks on its own (`what`: "command x"),
97
+ * started like `starting`. In the player's runner a refusal of it during
98
+ * activation (`invalid`, `conflict`, `limit`) does not fail the plugin:
99
+ * it is logged, skipped and reported to the scope once activation
100
+ * completes, so an `onError` added anywhere in `activate` hears it (SDK
101
+ * 1.5.49; VS Code logs a bad contribution and activates the extension).
102
+ * Under `strictDeclarations` (TestHost) it fails activation as before.
103
+ */
104
+ declaring<T>(work: Promise<T>, what: string, report: (error: unknown) => void): Promise<T>;
86
105
  activated(): Promise<void>;
87
106
  bind(evaluate: () => void): Disposable;
88
107
  /**
@@ -86,6 +86,16 @@ function merge(into, from) {
86
86
  * without `update()`) still shows within about this long.
87
87
  */
88
88
  export const SAFETY_PASS_MS = 1000;
89
+ /**
90
+ * The player's answers to a declaration that refuse that one declaration
91
+ * (a command's path, texts or count): during activation they skip it
92
+ * instead of failing the plugin (`Runtime.declaring`, SDK 1.5.49).
93
+ */
94
+ const DECLARATION_REFUSALS = new Set([
95
+ "invalid",
96
+ "conflict",
97
+ "limit",
98
+ ]);
89
99
  export const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
90
100
  /** One value in flight, only the newest waiting. Each push learns its fate. */
91
101
  export class Latest {
@@ -149,6 +159,10 @@ export class Runtime {
149
159
  /** Registrations that activation must wait for before reporting ready. */
150
160
  startup = new Set();
151
161
  #activating = true;
162
+ /** `RuntimeOptions.strictDeclarations`. */
163
+ #strict;
164
+ /** Declarations skipped during activation: reported once it completes. */
165
+ #refusals = [];
152
166
  #transport;
153
167
  /** Each binding with the events whose state it read last time (held). */
154
168
  #bindings = new Map();
@@ -187,8 +201,9 @@ export class Runtime {
187
201
  * property writes). Not part of the plugin API; empty for older players.
188
202
  */
189
203
  features;
190
- constructor(transport, manifest, directory, dataDirectory, app) {
204
+ constructor(transport, manifest, directory, dataDirectory, app, options = {}) {
191
205
  this.#transport = transport;
206
+ this.#strict = options.strictDeclarations ?? false;
192
207
  this.dataDirectory = dataDirectory;
193
208
  this.local = transport.local;
194
209
  this.host = createWire(transport);
@@ -233,6 +248,32 @@ export class Runtime {
233
248
  work.catch(() => { });
234
249
  return work;
235
250
  }
251
+ /**
252
+ * A declaration the player checks on its own (`what`: "command x"),
253
+ * started like `starting`. In the player's runner a refusal of it during
254
+ * activation (`invalid`, `conflict`, `limit`) does not fail the plugin:
255
+ * it is logged, skipped and reported to the scope once activation
256
+ * completes, so an `onError` added anywhere in `activate` hears it (SDK
257
+ * 1.5.49; VS Code logs a bad contribution and activates the extension).
258
+ * Under `strictDeclarations` (TestHost) it fails activation as before.
259
+ */
260
+ declaring(work, what, report) {
261
+ if (!this.#activating || this.#strict)
262
+ return this.starting(work, report);
263
+ const settled = work.then(() => { }, (error) => {
264
+ if (!(error instanceof HostError) ||
265
+ !DECLARATION_REFUSALS.has(error.code))
266
+ throw error;
267
+ console.error(`[${this.manifest.id}] ${what} skipped, the player refused it (${error.code}): ${error.message}`);
268
+ this.#refusals.push(() => report(error));
269
+ });
270
+ // Observed now: `activated()` may come after `activate` awaits, and
271
+ // its `allSettled` still sees the rejection.
272
+ settled.catch(() => { });
273
+ this.startup.add(settled);
274
+ work.catch(() => { });
275
+ return work;
276
+ }
236
277
  async activated() {
237
278
  while (this.startup.size) {
238
279
  const pending = [...this.startup];
@@ -242,6 +283,8 @@ export class Runtime {
242
283
  throw result.reason;
243
284
  }
244
285
  this.#activating = false;
286
+ for (const report of this.#refusals.splice(0))
287
+ report();
245
288
  }
246
289
  bind(evaluate) {
247
290
  const held = new Map();
@@ -2728,8 +2728,11 @@ export declare class TestHost implements Transport {
2728
2728
  *
2729
2729
  * Rejects when `manifest.json` cannot be read or parsed, when `activate`
2730
2730
  * throws, or when a registration made during activation fails (for example
2731
- * `limit`, `conflict`, `invalid`), which is when the player would fail the
2732
- * activation.
2731
+ * `limit`, `conflict`, `invalid`). Stricter than the player's runner for
2732
+ * commands (SDK 1.5.49): there the SDK logs a command declaration the
2733
+ * player refuses during activation, skips it and activates the rest of the
2734
+ * plugin (`onError` hears it); `startPlugin` fails, so a test shows the
2735
+ * bad declaration.
2733
2736
  *
2734
2737
  * @param activate - The plugin's default-exported `activate` function.
2735
2738
  * @param options - Where the plugin lives and how to start it.
@@ -3956,14 +3956,23 @@ export class TestHost {
3956
3956
  !BAR_BUTTON_ICONS.includes(icon))
3957
3957
  throw commandInvalid(`unknown button icon ${JSON.stringify(icon)}: a name of @vestra/icons.slint (${BAR_BUTTON_ICONS.join(", ")}) or an image from plugin.ui.image`);
3958
3958
  }
3959
+ // The binding table's `Table::canonical` (player 0.6.1): each binding
3960
+ // parsed, and each input once, compared parsed, before the reason,
3961
+ // conflicts and limits.
3959
3962
  const bindings = (declaration.bindings ?? []);
3960
- for (const binding of bindings)
3963
+ const seen = new Set();
3964
+ for (const binding of bindings.map(String)) {
3965
+ let input;
3961
3966
  try {
3962
- canonical(String(binding));
3967
+ input = canonical(binding);
3963
3968
  }
3964
3969
  catch (error) {
3965
3970
  throw commandInvalid(error.message);
3966
3971
  }
3972
+ if (seen.has(input))
3973
+ throw commandInvalid(`binding ${binding} is listed twice`);
3974
+ seen.add(input);
3975
+ }
3967
3976
  if (reason !== null)
3968
3977
  commandText(reason, "reason", COMMAND_LIMITS.reasonBytes);
3969
3978
  if (this.commands.has(id))
@@ -3991,13 +4000,6 @@ export class TestHost {
3991
4000
  this.commands.size + this.coreCommands.size + hostOnly.length >=
3992
4001
  COMMAND_LIMITS.total)
3993
4002
  throw new HostError("limit", "command registry limit reached");
3994
- // The binding table: each input once per command.
3995
- const seen = new Set();
3996
- for (const binding of bindings.map(String)) {
3997
- if (seen.has(binding))
3998
- throw new HostError("invalid", `binding ${binding} is listed twice`);
3999
- seen.add(binding);
4000
- }
4001
4003
  const host = this;
4002
4004
  let sent = p.state;
4003
4005
  this.commands.set(id, {
@@ -5426,8 +5428,11 @@ function tellResidency(host) {
5426
5428
  *
5427
5429
  * Rejects when `manifest.json` cannot be read or parsed, when `activate`
5428
5430
  * throws, or when a registration made during activation fails (for example
5429
- * `limit`, `conflict`, `invalid`), which is when the player would fail the
5430
- * activation.
5431
+ * `limit`, `conflict`, `invalid`). Stricter than the player's runner for
5432
+ * commands (SDK 1.5.49): there the SDK logs a command declaration the
5433
+ * player refuses during activation, skips it and activates the rest of the
5434
+ * plugin (`onError` hears it); `startPlugin` fails, so a test shows the
5435
+ * bad declaration.
5431
5436
  *
5432
5437
  * @param activate - The plugin's default-exported `activate` function.
5433
5438
  * @param options - Where the plugin lives and how to start it.
@@ -5512,7 +5517,10 @@ export async function startPlugin(activate, options = {}) {
5512
5517
  const instance = await createPlugin(host, manifest, directory, data,
5513
5518
  // Like the player: protocol additions it takes (`app.features` set on
5514
5519
  // the host replaces them, e.g. `[]` for an older player's behaviour).
5515
- { features: [PATCH_FEATURE], ...host.app });
5520
+ { features: [PATCH_FEATURE], ...host.app },
5521
+ // Unlike the player's runner, which logs a refused command declaration
5522
+ // and activates the rest: a plugin's tests show the refusal.
5523
+ { strictDeclarations: true });
5516
5524
  await activate(instance.plugin);
5517
5525
  // Like the player: a position or resolver another plugin holds is not an
5518
5526
  // activation failure.
@@ -487,7 +487,11 @@ export interface Scope extends Disposable {
487
487
  * Registrations started during activation (commands, panels, resolvers,
488
488
  * subscriptions) do not need to be awaited: the plugin is reported ready
489
489
  * once they all succeed, and activation fails if `activate` throws or any
490
- * of them fails. The entry module must **default-export** `activate`.
490
+ * of them fails. A command declaration the player refuses is the exception
491
+ * (SDK 1.5.49): the SDK logs and skips it, its `ready` rejects and
492
+ * {@link Scope.onError} hears it, the rest of the plugin activates
493
+ * (`startPlugin` still fails on it). The entry module must
494
+ * **default-export** `activate`.
491
495
  *
492
496
  * Stopping: the player first revokes everything the plugin owns on its side
493
497
  * (menus, windows, panels, filters, subtitle layers, snapshots, jobs,
@@ -1138,8 +1142,21 @@ export interface Command extends Disposable {
1138
1142
  * Resolves when the host has registered the command. Rejects with
1139
1143
  * `conflict` (path already taken), `invalid` or `limit` (more than 160
1140
1144
  * commands in this plugin, or 1024 in the whole player). You rarely need
1141
- * to await it: during activation a failure fails activation, later it
1142
- * goes to {@link Scope.onError}.
1145
+ * to await it: the refusal goes to {@link Scope.onError}. During
1146
+ * activation the SDK, in the plugin's process, logs the refusal with the
1147
+ * command id and the player's message, skips the command and lets the
1148
+ * rest of the plugin activate (SDK 1.5.49; before, the refusal failed
1149
+ * activation); the error reaches `onError` once activation completes,
1150
+ * so a listener added anywhere in `activate` hears it. `startPlugin`
1151
+ * stays strict: there a refusal during activation fails it, so tests
1152
+ * show the bad declaration. Any other failure during activation
1153
+ * (`capability`, no answer) fails activation.
1154
+ *
1155
+ * Only the player's answer is skipped. What {@link Commands.add} checks
1156
+ * itself still throws from `add` (an unknown `@` menu id, more than 8
1157
+ * path segments, an `order` out of range, a malformed binding or one
1158
+ * listed twice, a bad `button`, a reason text of the wrong shape, an id
1159
+ * already declared), and fails activation unless the plugin catches it.
1143
1160
  *
1144
1161
  * @throws `conflict` (rejects) Another command already has this menu path,
1145
1162
  * or the path would be both a menu item and a submenu.
@@ -1161,8 +1178,9 @@ export interface Command extends Disposable {
1161
1178
  * when the user picks the item, presses a key or clicks the button.
1162
1179
  * Commands of all plugins merge into the player's menus by their English
1163
1180
  * path keys. Registration is asynchronous: `add` returns at once, and
1164
- * {@link Command.ready} reports the player's answer (during activation a
1165
- * refusal fails activation).
1181
+ * {@link Command.ready} reports the player's answer (during activation
1182
+ * the SDK logs a refusal and skips that command, SDK 1.5.49;
1183
+ * `startPlugin` fails on it). What `add` checks itself throws from `add`.
1166
1184
  *
1167
1185
  * @capability commands
1168
1186
  *
package/llms.txt CHANGED
@@ -1,148 +1,42 @@
1
1
  # Vestra Player SDK
2
2
 
3
- > @vestra-player/sdk 1.5.48: write plugins for Vestra Player in TypeScript (plugin API `vestra/1`). A plugin is a folder with `manifest.json` and an entry module whose default export `activate(plugin)` the player calls; it runs in its own Node.js process (the player's built-in plugins share one). Everything a plugin creates (commands, windows, panels, filters, listeners…) is a handle that is released automatically when the plugin stops. L<n>: a line of llms-full.txt (next to this file), which has every page, declaration and example.
3
+ > @vestra-player/sdk 1.5.50: write plugins for Vestra Player in TypeScript (plugin API `vestra/1`). A plugin is a folder with `manifest.json` and an entry module whose default export `activate(plugin)` the player calls. The documentation is a tree of short pages read by path, like `go doc`: the same pages and API as https://vestrasys.github.io/vestra-player-sdk/.
4
4
 
5
- **Rules**
5
+ ## Read the documentation
6
6
 
7
- - **Only the public SDK.** Import `@vestra-player/sdk` with `import type` only (a runtime import fails `vestra-plugin build`) and `@vestra-player/sdk/testing` only in tests.
8
- - **No other plugins.** Do not import another plugin's code, read its directory or data directory, or talk to it privately (shared files, sockets, messages).
9
- - **No system commands.** Do not run `open`, `sips`, `plutil`, `security`, `cmd`, `powershell` or similar.
10
- - **macOS and Windows.** The same code runs on both: build paths with `node:path`, write package paths with `/`, and handle `unsupported` where a method documents a platform difference.
11
- - **Your own id.** `<owner>.<name>`, where the owner is your GitHub user or organization.
7
+ - **Command line** (any coding agent): `npx -p @vestra-player/sdk vestra-plugin docs [path] [--page N]` prints one node of the tree; `npx -p @vestra-player/sdk vestra-plugin docs --search <words>` lists the matching paths. In a project that depends on the SDK, `npx vestra-plugin docs` is enough.
8
+ - **In a Node.js program**: `import { docs, searchDocs } from "@vestra-player/sdk/docs"`; `docs(path, { page })` and `searchDocs(query, { page })` return the same text.
9
+ - **Paths**: `/` lists the top level; every answer lists the paths one level down with a one-line summary. `/API/<category>/<symbol>/<member>` is one declaration with its signature, parameters, return value, errors, capability, player version and examples, for example `/API/Media/Snapshot/dispose`. `/Guides/<group>/<page>` is a page of the site, for example `/Guides/How-to/Test a plugin` (the file name works too: `/Guides/How-to/testing`). Case, spaces and punctuation do not matter, the leading `/` is optional, `.` works like `/`, a name alone finds its declaration (`TestHost`, `Snapshot.export`, `plugin.player`), and `#heading` opens the page of a long answer that has that section.
10
+ - **Size**: every answer is at most 8 KB; a longer one ends with the number of its next page (`--page 2`).
11
+ - **Before writing code**, read `/Guides/Tutorials/Getting started` and `/Guides/Guidelines`, then the API of what you use. Test with `/Guides/How-to/Test a plugin`.
12
12
 
13
- **Files**
13
+ ## Top level
14
14
 
15
- ```text
16
- my-plugin/
17
- manifest.json identity and capabilities
18
- main.ts the entry module
19
- ui/hello.slint optional: user interface
20
- tests/main.test.ts tests (node:test)
21
- package.json dev dependency and scripts
22
- ```
15
+ - `/Overview`: The package's README: what the SDK is, installing it and where to start.
16
+ - `/Guides`: The documentation pages, by group: tutorials, how-to guides, reference, explanation, guidelines, examples, upgrading.
17
+ - `/API`: Every type and value of @vestra-player/sdk (the plugin API), @vestra-player/sdk/testing (the test host) and @vestra-player/sdk/docs (this tree), by category.
23
18
 
24
- **manifest.json**
19
+ ## Guides
25
20
 
26
- ```json
27
- {
28
- "id": "me.hello",
29
- "version": "0.1.0",
30
- "apiVersion": "vestra/1",
31
- "entry": "main.ts",
32
- "capabilities": ["commands", "ui.osd", "playback.read", "events"]
33
- }
34
- ```
35
-
36
- Fields: `id`, `version`, `apiVersion`, `entry`, `capabilities`, `name`, `author`, `punchline`, `description`, `tags`, `icon`, `readme`, `changelog`, `sourceUrl`, `license`, `minPlayerVersion`; unknown fields and capabilities are rejected. Rules and limits: L2218–2292.
37
-
38
- **main.ts**
39
-
40
- ```ts
41
- import type { Plugin } from "@vestra-player/sdk";
42
-
43
- export default async function activate(plugin: Plugin) {
44
- plugin.commands.add({
45
- id: "hello",
46
- path: ["Tools", "Hello"],
47
- run: () => plugin.osd.show("Hello"),
48
- });
49
- }
50
- ```
51
-
52
- **Capabilities** (without one a call fails: `capability`)
53
-
54
- - `producer.av`: Player.openStream (also `playback.control`)
55
- - `playback.read`: Player.state/refresh/stats/chapters/audioDevices, Timeline.marks
56
- - `playback.control`: Player.open/setPaused/seek/setRate/restart/close/scrub/setOutput/provideSequence/next/previous/addAudioTrack/selectAudioTrack/step/setStepSeek/setLoop/setAudioDevice, Power.preventSleep
57
- - `source.resolve`: Resolvers.add
58
- - `events`: Player/Subtitles/Timeline/MainWindow/Appearance/PanelSlot/Panel/BackdropSlot.onChange, Resolvers.onFileTypesChange
59
- - `commands`: Commands.add, Host.run
60
- - `ui.window`: Windows.create
61
- - `ui.mount`: Panels.mount/bottom/sidebar/backdrop, PanelSlot/Panel/BackdropSlot.onChange
62
- - `ui.dialog`: Dialogs.confirm/openFile/openFiles/openDirectory/saveFile
63
- - `plugins.manage`: Packages.validate/validateArchive/setEnabled/reload/uninstall
64
- - `processing.video`: Plugin.video.filter/video.view/video.render/video.shaders (also `playback.read`)
65
- - `processing.audio`: Plugin.audio.filter (also `playback.read`, `events`)
66
- - `subtitles.read`: Subtitles.state/onChange/refresh
67
- - `subtitles.control`: Subtitles.select/load/remove/setStyle
68
- - `media.read`: MediaCapture.capture, Snapshot.export (also `media.control`)
69
- - `media.control`: MediaCapture.capture, Snapshot.export (also `media.read`)
70
- - `ui.osd`: Osd.show/panel
71
- - `clipboard`: Clipboard.readText/writeText/writeImage
72
- - `window.control`: MainWindow.setVideoArea/setAlwaysOnTop/setCursorAutoHide/setPictureInPicture
73
- - `bindings.manage`: Bindings.list/set/reset/onChange
74
- - `timeline.marks`: Timeline.layer
75
- - `ui.drop`: Drops.provide, Panel.onDrop
76
- - `ui.settings`: Settings.page/show
77
- - `ui.theme`: Appearance.set/setLanguage
78
- - `secrets`: Secrets.get/set/delete
79
- - `rendering.manage`: Rendering.setPreference/restartPlayer
80
- - `video.upscaling`: VideoUpscaling.state/set/onChange
81
- - No capability: `tools`, `storage`, `system`, `app`, `ui` (images and Markdown), `i18n`, reading window.state, appearance.theme, packages.list and rendering.state. Details: L2293–2353.
82
-
83
- **Test**: `tests/*.test.ts` with `node:test`, run by `vestra-plugin test`. `startPlugin(activate, { directory: new URL("..", import.meta.url) })` from `@vestra-player/sdk/testing` returns `{ host, stop }`, `host` an in-memory player (TestHost): act (`host.command(id).run()`, `host.press(key)`), `await host.settle()`, assert on `host.osd`, `host.window(id).props`… Guide: L1861–2021; TestHost: L15502.
84
-
85
- **Command line**
86
-
87
- - `vestra-plugin check`: strict type check of the plugin's .ts files and tests/*.ts
88
- - `vestra-plugin build`: check, then write dist/
89
- - `vestra-plugin test`: node --test on tests/*.test.{ts,mjs}
90
- - `vestra-plugin pack`: build, then dist/ → <out>/<id>-<version>.vxp
91
- - `vestra-plugin i18n extract`: find the texts to translate, write locales/messages.pot and merge it into every locales/<lang>.po
92
- - `vestra-plugin i18n check`: coverage per language, placeholder and plural problems, a stale messages.pot
93
- - `vestra-player --plugin <dir>` runs a plugin from source, no build needed.
94
-
95
- **Error codes** (`error.code`; branch on it, never on `message`)
96
-
97
- - `stale`: A condition no longer held
98
- - `capability`: The manifest does not declare the capability the call needs
99
- - `invalid`: A bad argument
100
- - `missing`: The target does not exist
101
- - `busy`: The player is still doing a previous call of the same kind
102
- - `conflict`: Another plugin owns the resource
103
- - `unavailable`: Not possible right now
104
- - `unsupported`: Not possible on this system, build or source
105
- - `failed`: The operation ran and failed
106
- - `aborted`: An `AbortSignal` fired
107
- - `timeout`: A time limit ran out
108
- - `limit`: A player-wide limit was reached, a property value is over the limits of PropValue
109
- - `reserved`: The id is `vestra` or starts with `vestra.`
110
- - `versionMismatch`: The package needs a newer player
111
- - Others: PluginError, llms-full.txt L5966.
112
-
113
- ## Reference
114
-
115
- - [llms-full.txt](https://vestrasys.github.io/vestra-player-sdk/llms-full.txt), also node_modules/@vestra-player/sdk/llms-full.txt; pages: [site](https://vestrasys.github.io/vestra-player-sdk/).
116
- - Tutorials: Getting started L9–134; Add a window L135–213; Add settings and translations L214–367; Test, check, pack and publish L368–424; Write your own blur kernel L425–685
117
- - How-to: Control playback L686–854; Store a plugin's data L855–961; Load subtitles from a plugin L962–1074; Keep a slider responsive while dragging L1075–1262; Remember a window's state between runs L1263–1414; Offer a GPU rendering switch L1415–1540; Keep a command's state without keeping the plugin running L1541–1697; Translate a plugin L1698–1860; Test a plugin L1861–2021; Publish a plugin L2022–2123; Troubleshooting L2124–2217
118
- - Reference: Manifest L2218–2292; Capabilities L2293–2353; Limits L2354–2506; Commands, menus and bindings L2507–3033; Platforms L3034–3064; Theme L3065–3414; Command line L3415–3472; Error codes L3473–3520; Translations L3521–3613; Test host L3614–3800
119
- - Explanation: How a plugin runs L3801–4003; Commands, menus and key bindings L4004–4158; Playback state, controls and sources L4159–4318; Video and audio processing L4319–4439; Windows, panels, settings pages, dialogs and the OSD L4440–4704; GPU and software rendering L4705–4721; The player's Rust core L4722–5063; How the player runs and talks to plugins L5064–5403
120
- - Guidelines: Plugin rules L5404–5415; Interface guidelines L5416–5532; Menu guidelines L5533–5591
121
- - Upgrading: Migrate a plugin to English source text L5592–5741; Migrating off package rollback (1.5.16, removed in 1.5.17) L5742–5819; Who must change, release by release L5820–5888
122
- - [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L5889–15175
123
- - [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L15176–18059
21
+ - `/Guides/Tutorials`: Step-by-step lessons; the first four build one plugin, from an empty folder to a tested package in the plugin store.
22
+ - `/Guides/How-to`: Short guides that each answer one practical question about writing, translating, testing or publishing a plugin.
23
+ - `/Guides/Reference`: Lookup tables that span many symbols (capabilities, manifest fields and player versions, limits, menu and binding names, platform differences, theme, command line), generated from the SDK's code.
24
+ - `/Guides/Explanation`: What each part of the player and its plugins is, why it works the way it does and how the parts fit together.
25
+ - `/Guides/Guidelines`: The rules a plugin follows so that its windows, panels, messages and menu items look and behave like the rest of Vestra Player.
26
+ - `/Guides/Examples`: Complete, tested example plugins with a screenshot each and a step-by-step walkthrough of their code.
27
+ - `/Guides/Upgrading`: What to change in a plugin when an SDK or player release deprecates, removes or changes something it uses.
124
28
 
125
29
  ## API
126
30
 
127
- Where each `plugin.<module>` is declared:
128
-
129
- - Plugin L6305, Scope L6041, PluginError L5966, Disposable L5904
130
- - Commands L6900; When L6492; Windows L7847; Panels L9293; Dialogs L9963; Player L10704; video: VideoFilter L11584, VideoView L11684, RenderOptions L11771, VideoShaders L11849, VideoUpscaling L12207; audio: AudioFilter L11629; Subtitles L12443; media: MediaCapture L12847; Resolvers L13077; Packages L13479; Osd L11449; Host L11291; Clipboard L13808; Power L13895; Tools L13954; Storage L14106; System L14305; Secrets L14385; window: MainWindow L9610; App L9790; Rendering L14648; Bindings L13707; Ui L7193; Timeline L9522; Drops L8540; Appearance L8621; I18n L8854; Settings L9137.
131
-
132
- ## Examples
133
-
134
- Tested plugins in [examples/](https://github.com/vestrasys/vestra-player-sdk/tree/main/examples):
135
-
136
- - hello: The README Quick start: one menu command and an on-screen message. L18494–18589
137
- - blur: A tool window with one slider that blurs the playing video. L18590–18857
138
- - signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L18858–19196
139
- - bookmark: A tool window bound to the playback state: remember the position and jump back to it. L19197–19389
140
- - panel-menu: A sidebar panel with its own right-click menu. L19390–19604
141
- - menus: Radio menu items, separator groups and a menu item whose title changes. L19605–19770
142
- - theme-widgets: A tool window drawn with the player's theme and widgets. L19771–19940
143
- - markdown: A window that shows a Markdown document. L19941–20143
144
- - i18n: A plugin in the player's language: English source text, a Chinese translation. L20144–20317
145
-
146
- ## Optional
147
-
148
- - [Changelog](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md); full doc comments in the package's dist/plugin/*.d.ts; Slint library in slint/vestra/.
31
+ - `/API/Commands`: 15 entries: CommandState, Bindable, Condition, When, MenuId, BarButtonIcon, CommandButton, CommandOptions, Command, Commands, HostAction, Host, BindingRef, BindingInfo, Bindings
32
+ - `/API/Media`: 6 entries: CaptureOptions, Snapshot, ExportOptions, JobState, ExportJob, MediaCapture
33
+ - `/API/Packages`: 10 entries: PackageManifest, PackageSource, InstallOptions, PackageCandidate, PackageChangeStatus, PackageChange, PluginInfo, PluginDisplay, PluginWarning, Packages
34
+ - `/API/Playback`: 18 entries: MarkKind, TimelineMark, TimelineLayer, Timeline, AudioTrack, PlayerState, AudioDevice, Chapter, Conditional, Media, Scrub, StreamFrame, StreamOptions, StreamStartError, Stream,…
35
+ - `/API/Plugin`: 11 entries: Disposable, PluginError, Scope, Plugin, WindowState, MainWindow, AppInfo, App, SystemInfo, DisplayInfo, Json
36
+ - `/API/Processing`: 18 entries: FilterStatus, VideoFilter, AudioFilter, ViewSettings, VideoView, RenderSettings, RenderOptions, VideoShaders, UpscalingReasonCode, UpscalingReason, UpscalingDecodingCause,…
37
+ - `/API/Services`: 15 entries: Clipboard, Power, ToolResult, Tools, JsonStore, Storage, SessionStorage, System, Secrets, RenderingMode, RenderingPreference, RenderingReasonCode, RenderingReason, RenderingState,…
38
+ - `/API/Sources`: 7 entries: ResolverOptions, WebResolverOptions, FileResolverOptions, ResolvedStream, Resolver, Resolvers, ResolvedMedia
39
+ - `/API/Subtitles`: 5 entries: SubtitleTrack, SubtitlesState, SubtitleConditional, Subtitles, SubtitleStyle
40
+ - `/API/UI`: 42 entries: ImageRef, ImageOptions, MarkdownRef, MarkdownOptions, PropValue, PropData, Props, Ui, View, Window, Windows, SlotState, SlotPanel, PanelState, PanelSlot, SidebarSlot, Panel,…
41
+ - `/API/Testing`: 32 entries: CapabilityInfo, CAPABILITY_INFO, MESSAGE_LIMIT, COMMAND_LIMITS, MENU_IDS, BAR_BUTTON_ICONS, BAR_BUTTON_LIMITS, BuiltinSubmenu, BUILTIN_SUBMENUS, BuiltinCommand, BUILTIN_COMMANDS, LOCALES,…
42
+ - `/API/Docs`: 4 entries: DOCS_PAGE_BYTES, DocsOptions, docs, searchDocs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vestra-player/sdk",
3
- "version": "1.5.48",
3
+ "version": "1.5.50",
4
4
  "description": "Plugin API types, test host and plugin CLI for Vestra Player (apiVersion vestra/1)",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -24,12 +24,15 @@
24
24
  "types": "./dist/player-runtime.d.ts",
25
25
  "default": "./dist/player-runtime.js"
26
26
  },
27
+ "./docs": {
28
+ "types": "./dist/docs.d.ts",
29
+ "default": "./dist/docs.js"
30
+ },
27
31
  "./ts-plugin": {
28
32
  "types": "./ts-plugin/index.d.ts",
29
33
  "default": "./ts-plugin/index.js"
30
34
  },
31
35
  "./llms.txt": "./llms.txt",
32
- "./llms-full.txt": "./llms-full.txt",
33
36
  "./package.json": "./package.json"
34
37
  },
35
38
  "bin": {
@@ -43,8 +46,7 @@
43
46
  "README.md",
44
47
  "CHANGELOG.md",
45
48
  "LICENSE",
46
- "llms.txt",
47
- "llms-full.txt"
49
+ "llms.txt"
48
50
  ],
49
51
  "scripts": {
50
52
  "build": "node scripts/build.mjs",