@vestra-player/sdk 1.5.17 → 1.5.18

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.18
4
+
5
+ Fixes for Windows and for a vendored SDK, and built-ins that can no longer be disabled. `apiVersion` stays `vestra/1`; plugins that do not manage other plugins need no change.
6
+
7
+ - **`TestHost` streams on Windows**: `openStream`'s default transport listened on a socket file in the temp folder, which Windows refuses (`listen EACCES`), so stream tests failed there. It now listens on a named pipe (`\\.\pipe\vestra-test-host-…-producer-<id>`) on Windows and on a Unix socket elsewhere. `producerTransport = "tcp"` still gives the player's own Windows transport (loopback TCP with a token).
8
+ - **The CLI runs from an SDK outside any `node_modules`** (a copy with TypeScript on `NODE_PATH`, as the player's AI workshop vendors it): `dist/i18n-tools.js` resolved TypeScript with a bare ES module import, which ignores `NODE_PATH`, so `vestra-plugin` stopped at start with `ERR_MODULE_NOT_FOUND`. It now resolves TypeScript as the rest of the CLI does.
9
+ - **Built-in plugins cannot be disabled** (user ruling, 2026-10-26: users manage third-party plugins only). The player and `TestHost` answer `packages.setEnabled(builtin, false)` with `unsupported`; a built-in an older player let the user disable runs again after the upgrade. `PluginInfo.builtin`, `Packages.setEnabled` and *Migrating off package rollback* say so; a plugin manager offers no action for a built-in.
10
+
3
11
  ## 1.5.17
4
12
 
5
13
  **Package rollback is removed**, as announced in 1.5.16: the player keeps no previous plugin version. `apiVersion` stays `vestra/1` (a patch release, as when 1.5.8 removed `PackageCandidate.trial()`); plugins that do not manage other plugins need no change. A plugin manager that still calls `rollback` or reads `previousVersion` no longer compiles. Migration: [Migrating off package rollback](docs/how-to/rollback-migration.md).
@@ -1,4 +1,4 @@
1
- import ts from "typescript";
1
+ import type TS from "typescript";
2
2
  /** A translatable text found in the sources. */
3
3
  export interface Message {
4
4
  context?: string;
@@ -27,7 +27,7 @@ export interface ExtractOptions {
27
27
  /** The plugin's production `.ts` / `.mts` files, relative to `directory`. */
28
28
  typescript: readonly string[];
29
29
  /** Compiler options for a program over those files (as `check` uses). */
30
- compilerOptions?: ts.CompilerOptions;
30
+ compilerOptions?: TS.CompilerOptions;
31
31
  }
32
32
  export declare const pluralForms: (language: string) => "nplurals=1; plural=0;" | "nplurals=2; plural=(n != 1);";
33
33
  /** Find every translatable text of a plugin, in reference order. */
@@ -1,3 +1,11 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
1
9
  /**
2
10
  * `vestra-plugin i18n extract` and `vestra-plugin i18n check`, and the
3
11
  * catalog step of `vestra-plugin build` (docs/how-to/i18n.md): find the
@@ -16,9 +24,19 @@
16
24
  * @module
17
25
  */
18
26
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
27
+ import { createRequire } from "node:module";
19
28
  import { join, relative, sep } from "node:path";
20
- import ts from "typescript";
29
+ import { pathToFileURL } from "node:url";
21
30
  import { compileCatalog, keyOf, LOCALES, parsePo, placeholders, scanSlint, writePo, } from "./i18n.js";
31
+ /**
32
+ * The SDK's TypeScript dependency, resolved the way the CLI resolves it
33
+ * (`compiler()` in bin/vestra-plugin.mjs): through `require` resolution from
34
+ * this package, which also searches `NODE_PATH`. A bare `import` of
35
+ * "typescript" would search only ancestor `node_modules` directories, so an
36
+ * SDK copied outside any (the player's AI workshop vendors one, and supplies
37
+ * TypeScript on `NODE_PATH`) could not start the CLI.
38
+ */
39
+ const ts = (await import(__rewriteRelativeImportExtension(pathToFileURL(createRequire(import.meta.url).resolve("typescript")).href))).default;
22
40
  /** Locales whose plural has one form (`n == 1` and other are the same). */
23
41
  const ONE_FORM = new Set(["zh-Hans", "ja", "ko"]);
24
42
  export const pluralForms = (language) => ONE_FORM.has(language)
@@ -4,4 +4,11 @@ import type { LocalServices } from "../wire.ts";
4
4
  * `ffmpeg` with each `PATHEXT` extension (`ffmpeg.exe` first by default).
5
5
  */
6
6
  export declare function executableNames(tool: string, platform?: NodeJS.Platform, pathext?: string | undefined): string[];
7
+ /**
8
+ * Where a local stream listens: a Unix socket file `<name>.sock` in
9
+ * `directory` on macOS and Linux; on Windows a named pipe
10
+ * (`\\.\pipe\<directory's name>-<name>`), which Node's `net` listens on and
11
+ * connects to by that path (a socket file there fails with `EACCES`).
12
+ */
13
+ export declare function localSocketPath(directory: string, name: string, platform?: NodeJS.Platform): string;
7
14
  export declare const systemServices: LocalServices;
@@ -31,6 +31,18 @@ export function executableNames(tool, platform = process.platform, pathext = pro
31
31
  .filter((extension) => extension.startsWith("."));
32
32
  return [...new Set(extensions)].map((extension) => tool + extension);
33
33
  }
34
+ /**
35
+ * Where a local stream listens: a Unix socket file `<name>.sock` in
36
+ * `directory` on macOS and Linux; on Windows a named pipe
37
+ * (`\\.\pipe\<directory's name>-<name>`), which Node's `net` listens on and
38
+ * connects to by that path (a socket file there fails with `EACCES`).
39
+ */
40
+ export function localSocketPath(directory, name, platform = process.platform) {
41
+ if (platform !== "win32")
42
+ return join(directory, `${name}.sock`);
43
+ const scope = directory.split(/[\\/]/).filter(Boolean).at(-1) ?? "vestra";
44
+ return `\\\\.\\pipe\\${scope}-${name}`;
45
+ }
34
46
  async function executable(path) {
35
47
  try {
36
48
  await access(path, constants.X_OK);
@@ -917,8 +917,9 @@ export declare class TestHost implements Transport {
917
917
  */
918
918
  readonly jobs: Map<number, MediaJob>;
919
919
  /**
920
- * `openStream`'s transport: a Unix socket (macOS, Linux) or, with `"tcp"`,
921
- * loopback TCP where the plugin must send the token first (Windows).
920
+ * `openStream`'s transport: a local stream (a Unix socket on macOS and
921
+ * Linux, a named pipe on Windows) or, with `"tcp"`, loopback TCP where the
922
+ * plugin must send the token first, as the player on Windows answers.
922
923
  * Set it before the plugin calls `openStream`.
923
924
  */
924
925
  producerTransport: "unix" | "tcp";
@@ -65,6 +65,7 @@ import { tmpdir } from "node:os";
65
65
  import { extname, isAbsolute, join } from "node:path";
66
66
  import { fileURLToPath } from "node:url";
67
67
  import { HostError } from "../wire.js";
68
+ import { localSocketPath } from "./local.js";
68
69
  import { BUILTIN_COMMANDS, BUILTIN_SUBMENUS, COMMAND_LIMITS, MENU_IDS, } from "../commands.js";
69
70
  import { CAPABILITY_INFO, MESSAGE_LIMIT } from "../capabilities.js";
70
71
  import { OSD_LIMITS } from "./osd.js";
@@ -1013,8 +1014,9 @@ export class TestHost {
1013
1014
  */
1014
1015
  jobs = new Map();
1015
1016
  /**
1016
- * `openStream`'s transport: a Unix socket (macOS, Linux) or, with `"tcp"`,
1017
- * loopback TCP where the plugin must send the token first (Windows).
1017
+ * `openStream`'s transport: a local stream (a Unix socket on macOS and
1018
+ * Linux, a named pipe on Windows) or, with `"tcp"`, loopback TCP where the
1019
+ * plugin must send the token first, as the player on Windows answers.
1018
1020
  * Set it before the plugin calls `openStream`.
1019
1021
  */
1020
1022
  producerTransport = "unix";
@@ -3161,6 +3163,9 @@ export class TestHost {
3161
3163
  const entry = this.packages.find((each) => each.id === id);
3162
3164
  if (!entry)
3163
3165
  throw new HostError("missing", `no plugin ${id}`);
3166
+ // As the player (with SDK 1.5.18 on): users manage third-party plugins only.
3167
+ if (entry.builtin && p.enabled === false)
3168
+ throw new HostError("unsupported", `${id} is a built-in plugin: built-in plugins cannot be disabled`);
3164
3169
  this.packageCalls.push({
3165
3170
  method: "setEnabled",
3166
3171
  id,
@@ -3221,7 +3226,7 @@ export class TestHost {
3221
3226
  if (!entry)
3222
3227
  throw new HostError("missing", `no plugin ${id}`);
3223
3228
  if (entry.builtin)
3224
- throw new HostError("unsupported", "built-in plugins can be disabled but not uninstalled");
3229
+ throw new HostError("unsupported", "built-in plugins cannot be uninstalled");
3225
3230
  if (entry.origin !== "installed")
3226
3231
  throw new HostError("unsupported", "only installed plugins can be uninstalled");
3227
3232
  this.packageCalls.push({
@@ -3436,7 +3441,8 @@ export class TestHost {
3436
3441
  const id = ++this.#next.producer;
3437
3442
  const tcp = this.producerTransport === "tcp";
3438
3443
  const token = tcp ? randomBytes(32) : null;
3439
- const path = join(this.#scratch, `producer-${id}.sock`);
3444
+ // A Unix socket, or a named pipe on Windows (`localSocketPath`).
3445
+ const path = localSocketPath(this.#scratch, `producer-${id}`);
3440
3446
  const producer = {
3441
3447
  id,
3442
3448
  receivedFrames: 0,
@@ -4733,8 +4733,9 @@ export interface PluginInfo {
4733
4733
  */
4734
4734
  directory: string;
4735
4735
  /**
4736
- * Shipped with the player: it can be disabled, not uninstalled or
4737
- * replaced. `false` from players before 0.2.0.
4736
+ * Shipped with the player: it always runs; it cannot be disabled,
4737
+ * uninstalled or replaced (older players, before SDK 1.5.18, let it be disabled).
4738
+ * `false` from players before 0.2.0.
4738
4739
  */
4739
4740
  builtin: boolean;
4740
4741
  /** Where an installed plugin came from; `null` for development loads. */
@@ -4838,7 +4839,9 @@ export interface Packages {
4838
4839
  * Stop or start a plugin (`plugins.manage`). An installed plugin stays
4839
4840
  * disabled across launches; a development load only for this run.
4840
4841
  * `invalid` to disable oneself, `missing` unknown.
4841
- * `busy` while it is being installed.
4842
+ * `busy` while it is being installed. `unsupported` to disable a built-in
4843
+ * ({@link PluginInfo.builtin}): users manage third-party plugins only
4844
+ * (players released with SDK 1.5.18 on; older ones disabled built-ins too).
4842
4845
  */
4843
4846
  setEnabled(id: string, enabled: boolean): Promise<void>;
4844
4847
  /**
package/llms-full.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @vestra-player/sdk 1.5.17: full reference
1
+ # @vestra-player/sdk 1.5.18: full reference
2
2
 
3
3
  > Everything needed to write a Vestra Player plugin (plugin API `vestra/1`): the guides, every public declaration of `@vestra-player/sdk` and `@vestra-player/sdk/testing` with its documentation, and the complete source of the example plugins. Generated from the SDK's sources by scripts/llms.mjs; the short index is llms.txt.
4
4
 
@@ -1850,7 +1850,7 @@ The player no longer keeps a previous version of a plugin. An upgrade replaces t
1850
1850
 
1851
1851
  - There is no `packages.rollback`: the player answers the wire method with `unsupported` ("unknown package method"), and SDK 1.5.17 no longer has it.
1852
1852
  - `packages.list()` and `packages.onChange` entries have no `previousVersion` (always `null` with SDK 1.5.16, removed in 1.5.17).
1853
- - Built-in plugins (`builtin: true`) run in place from the player installation. They can be disabled and enabled, never uninstalled or replaced; `uninstall` fails with `unsupported`. A built-in's `directory` is inside the installation (`<install resources>/plugins/<id>`) and read-only.
1853
+ - Built-in plugins (`builtin: true`) run in place from the player installation. Users manage only third-party plugins: a built-in can be neither uninstalled, replaced nor (from SDK 1.5.18 and the players released with it) disabled; `uninstall` and `setEnabled(id, false)` fail with `unsupported`, and a built-in an older player let the user disable runs again after the upgrade. A built-in's `directory` is inside the installation (`<install resources>/plugins/<id>`) and read-only.
1854
1854
  - Third-party plugins can still be uninstalled.
1855
1855
 
1856
1856
  Why: built-ins now run from the read-only installation instead of a copy, and an upgrade replaces the package instead of keeping the old one beside it. Going back to an older version becomes an ordinary uninstall and install that the user starts.
@@ -1862,14 +1862,15 @@ Why: built-ins now run from the read-only installation instead of a copy, and an
1862
1862
  Before:
1863
1863
 
1864
1864
  ```ts nocheck
1865
- if (info.previousVersion !== null) showButton("Roll back", () => plugin.packages.rollback(info.id));
1865
+ if (info.previousVersion !== null)
1866
+ showButton("Roll back", () => plugin.packages.rollback(info.id));
1866
1867
  ```
1867
1868
 
1868
1869
  After: delete both. There is no replacement call; nothing on the player can restore an earlier package. Remove the button, menu item or command, and any state, text or test that depends on `previousVersion`. With SDK 1.5.17 the compiler finds every remaining use.
1869
1870
 
1870
1871
  #### 2. Going back to an older version
1871
1872
 
1872
- Managing plugins has exactly three operations: **install**, **uninstall** and **disable/enable**. There is no rollback, no "install older version" and no "Undo install".
1873
+ Managing third-party plugins has exactly three operations: **install**, **uninstall** and **disable/enable**. Built-ins have none of them. There is no rollback, no "install older version" and no "Undo install".
1873
1874
 
1874
1875
  To go back to an older version, the user uninstalls the plugin and installs the older version's `.vxp` file themselves, as two ordinary operations. Do not offer an action that does both, an older-version install from a store, or an "Undo" after an install (the official store and the AI window drop theirs). Uninstalling without `removeData` keeps the plugin's data, and a reinstall from the same source reconnects to it; a `.vxp` file is a different source from a repository, so a plugin first installed from the store gets a new, empty data directory.
1875
1876
 
@@ -1884,13 +1885,13 @@ Check `builtin` before offering actions:
1884
1885
  ```ts
1885
1886
  for (const info of await plugin.packages.list()) {
1886
1887
  const actions = info.builtin
1887
- ? [info.state === "disabled" ? "Enable" : "Disable"]
1888
- : ["Disable", "Uninstall"];
1888
+ ? []
1889
+ : [info.state === "disabled" ? "Enable" : "Disable", "Uninstall"];
1889
1890
  console.log(info.id, actions);
1890
1891
  }
1891
1892
  ```
1892
1893
 
1893
- - Offer only disable and enable for a built-in (`packages.setEnabled`); never uninstall or install over it.
1894
+ - Offer no action for a built-in: never disable, uninstall or install over it (the player answers `unsupported`). Built-ins that an older player listed as `disabled` come back as running.
1894
1895
  - Never write into a built-in's `directory`, or into any plugin's `directory`: read `manifest.json` from it if you need to. A plugin writes only under its own plugin.dataDirectory.
1895
1896
 
1896
1897
  #### 5. Tests
@@ -1899,17 +1900,18 @@ With SDK 1.5.17, `host.packages` entries have no `previousVersion` field: delete
1899
1900
 
1900
1901
  #### Timeline
1901
1902
 
1902
- | SDK | Player | What happens |
1903
- | --- | --- | --- |
1904
- | 1.5.16 | ships with it | `Packages.rollback` and `PluginInfo.previousVersion` (and the wire field) are `@deprecated`. The player and `TestHost` answer rollback with `unsupported` and list `previousVersion: null`. Code still compiles. |
1903
+ | SDK | Player | What happens |
1904
+ | ------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1905
+ | 1.5.16 | ships with it | `Packages.rollback` and `PluginInfo.previousVersion` (and the wire field) are `@deprecated`. The player and `TestHost` answer rollback with `unsupported` and list `previousVersion: null`. Code still compiles. |
1905
1906
  | 1.5.17 | ships with it | **Removed:** `Packages.rollback`, `PluginInfo.previousVersion`, the wire method `packages.rollback` and the wire field `previousVersion`, `TestHost`'s `previousVersion` field and its `packages.rollback` handler, and `Packages.rollback` in the `plugins.manage` capability. Remaining uses are TypeScript compile errors. |
1907
+ | 1.5.18 | ships with it | Built-ins can no longer be disabled: the player and `TestHost` answer `setEnabled(builtin, false)` with `unsupported` (user ruling 2026-10-26). |
1906
1908
 
1907
1909
  `apiVersion` stays `vestra/1` in both releases, as when 1.5.8 removed `PackageCandidate.trial()`.
1908
1910
 
1909
1911
  #### Before you hand it in
1910
1912
 
1911
1913
  - [ ] No call to `packages.rollback`; no UI or logic gated on `previousVersion`.
1912
- - [ ] Built-ins offer only disable and enable.
1914
+ - [ ] Built-ins offer no Disable, Enable or Uninstall.
1913
1915
  - [ ] Nothing writes into a plugin's `directory`.
1914
1916
  - [ ] No Undo after an install, no older-version install; older versions go through uninstall and a user-chosen `.vxp`.
1915
1917
  - [ ] Tests compile and pass with SDK 1.5.17; no `previousVersion` is left in `host.packages` test data.
@@ -6007,7 +6009,9 @@ interface PluginInfo {
6007
6009
  * The package directory (read its `manifest.json` for display fields). A built-in's directory is inside the player installation (`<install resources>/plugins/<id>`) and read-only: a plugin writes only under its own Plugin.dataDirectory.
6008
6010
  */
6009
6011
  directory: string;
6010
- /** Shipped with the player: it can be disabled, not uninstalled or replaced. `false` from players before 0.2.0. */
6012
+ /**
6013
+ * Shipped with the player: it always runs; it cannot be disabled, uninstalled or replaced (older players, before SDK 1.5.18, let it be disabled). `false` from players before 0.2.0.
6014
+ */
6011
6015
  builtin: boolean;
6012
6016
  /** Where an installed plugin came from; `null` for development loads. */
6013
6017
  source: PackageSource | null;
@@ -6085,7 +6089,7 @@ interface Packages {
6085
6089
  /** The new list after any start, stop, failure, install or uninstall. No capability. */
6086
6090
  onChange(listener: (plugins: PluginInfo[]) => void): Disposable;
6087
6091
  /**
6088
- * Stop or start a plugin (`plugins.manage`). An installed plugin stays disabled across launches; a development load only for this run. `invalid` to disable oneself, `missing` unknown. `busy` while it is being installed.
6092
+ * Stop or start a plugin (`plugins.manage`). An installed plugin stays disabled across launches; a development load only for this run. `invalid` to disable oneself, `missing` unknown. `busy` while it is being installed. `unsupported` to disable a built-in (PluginInfo.builtin): users manage third-party plugins only (players released with SDK 1.5.18 on; older ones disabled built-ins too).
6089
6093
  */
6090
6094
  setEnabled(id: string, enabled: boolean): Promise<void>;
6091
6095
  /**
@@ -7181,7 +7185,7 @@ class TestHost implements Transport {
7181
7185
  /** Export jobs by job id. Each state query advances a job one step (`queued` → `running` → `completed`; `cancelling` → `cancelled`). Wire-level. */
7182
7186
  readonly jobs: Map<number, MediaJob>;
7183
7187
  /**
7184
- * `openStream`'s transport: a Unix socket (macOS, Linux) or, with `"tcp"`, loopback TCP where the plugin must send the token first (Windows). Set it before the plugin calls `openStream`.
7188
+ * `openStream`'s transport: a local stream (a Unix socket on macOS and Linux, a named pipe on Windows) or, with `"tcp"`, loopback TCP where the plugin must send the token first, as the player on Windows answers. Set it before the plugin calls `openStream`.
7185
7189
  */
7186
7190
  producerTransport: "unix" | "tcp";
7187
7191
  /** Generated streams (`player.openStream`) by producer id: the fake player end of each frame connection. Wire-level beyond the FakeProducer fields. */
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # Vestra Player SDK
2
2
 
3
- > @vestra-player/sdk 1.5.17: 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. Everything a plugin creates (commands, windows, panels, filters, listeners…) is a handle that is released automatically when the plugin stops. L<n> are line numbers in llms-full.txt, next to this file: every page, declaration and example.
3
+ > @vestra-player/sdk 1.5.18: 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. Everything a plugin creates (commands, windows, panels, filters, listeners…) is a handle that is released automatically when the plugin stops. L<n> are line numbers in llms-full.txt, next to this file: every page, declaration and example.
4
4
 
5
5
  **Rules**
6
6
 
@@ -33,7 +33,7 @@ my-plugin/
33
33
  }
34
34
  ```
35
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: L2100–2163.
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: L2102–2165.
37
37
 
38
38
  **main.ts**
39
39
 
@@ -76,9 +76,9 @@ export default async function activate(plugin: Plugin) {
76
76
  - `ui.settings`: Settings.page/show
77
77
  - `ui.theme`: Appearance.set/setLanguage
78
78
  - `secrets`: Secrets.get/set/delete
79
- - No capability: `tools`, `storage`, `system`, `app`, `ui` (images and Markdown), `i18n`, reading window.state, appearance.theme and packages.list. Details: L2164–2206.
79
+ - No capability: `tools`, `storage`, `system`, `app`, `ui` (images and Markdown), `i18n`, reading window.state, appearance.theme and packages.list. Details: L2166–2208.
80
80
 
81
- **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` is a TestHost (an in-memory player): `host.setSource(…)`, `host.command(id).run()`, `host.press(key)`, `await host.settle()`, then assert on `host.osd`, `host.window(id).props`… Guide: L1588–1753; TestHost: L6747.
81
+ **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` is a TestHost (an in-memory player): `host.setSource(…)`, `host.command(id).run()`, `host.press(key)`, `await host.settle()`, then assert on `host.osd`, `host.window(id).props`… Guide: L1588–1753; TestHost: L6751.
82
82
 
83
83
  **Command line**
84
84
 
@@ -106,39 +106,39 @@ export default async function activate(plugin: Plugin) {
106
106
  - `limit`: A player-wide limit was reached, a property value is over the limits of PropValue
107
107
  - `reserved`: The id is `vestra` or starts with `vestra.`
108
108
  - `versionMismatch`: The package needs a newer player or another `apiVersion`
109
- - Others: PluginError, llms-full.txt L3103.
109
+ - Others: PluginError, llms-full.txt L3105.
110
110
 
111
111
  ## Reference
112
112
 
113
113
  - [llms-full.txt](https://vestrasys.github.io/vestra-player-sdk/llms-full.txt), also node_modules/@vestra-player/sdk/llms-full.txt; the pages are on the [site](https://vestrasys.github.io/vestra-player-sdk/).
114
114
  - Tutorials: Getting started L9–214
115
115
  - Concepts: How a plugin runs L215–364; Commands, menus and key bindings L365–462; Playback state, controls and sources L463–585; Video and audio processing L586–663; Windows, panels, settings pages, dialogs and the OSD L664–950
116
- - How-to: Keep a slider responsive while dragging L951–1125; Remember a window's state between runs L1126–1255; Translate a plugin L1256–1439; Migrate a plugin to English source text L1440–1587; Test a plugin L1588–1753; Publish a plugin L1754–1842; Migrating off package rollback (1.5.16, removed in 1.5.17) L1843–1916
117
- - Guidelines: Interface guidelines L1917–2001; Menu guidelines L2002–2099
118
- - Reference: Manifest L2100–2163; Capabilities L2164–2206; Limits L2207–2301; Commands, menus and bindings L2302–2770; Platforms L2771–2799; Theme L2800–3004; Command line L3005–3060
119
- - [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L3061–6582
120
- - [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L6583–7905
116
+ - How-to: Keep a slider responsive while dragging L951–1125; Remember a window's state between runs L1126–1255; Translate a plugin L1256–1439; Migrate a plugin to English source text L1440–1587; Test a plugin L1588–1753; Publish a plugin L1754–1842; Migrating off package rollback (1.5.16, removed in 1.5.17) L1843–1918
117
+ - Guidelines: Interface guidelines L1919–2003; Menu guidelines L2004–2101
118
+ - Reference: Manifest L2102–2165; Capabilities L2166–2208; Limits L2209–2303; Commands, menus and bindings L2304–2772; Platforms L2773–2801; Theme L2802–3006; Command line L3007–3062
119
+ - [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L3063–6586
120
+ - [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L6587–7909
121
121
 
122
122
  ## API
123
123
 
124
124
  Where each module of `plugin` (`plugin.<module>`) is declared:
125
125
 
126
- - Plugin L3295, Scope L3164, PluginError L3103, Disposable L3076
127
- - Commands L3507; Windows L3712; Panels L4355; Dialogs L4641; Player L5089; video: VideoFilter L5354, VideoView L5417, RenderOptions L5459; audio: AudioFilter L5378; Subtitles L5557; media: MediaCapture L5717; Resolvers L5822; Packages L6062; Osd L5290; Host L5238; Clipboard L6177; Power L6197; Tools L6230; Storage L6273; System L6296; Secrets L6314; window: MainWindow L4478; App L4559; Bindings L6147; Ui L3599; Timeline L4435; Drops L4011; Appearance L4040; I18n L4182; Settings L4288.
126
+ - Plugin L3297, Scope L3166, PluginError L3105, Disposable L3078
127
+ - Commands L3509; Windows L3714; Panels L4357; Dialogs L4643; Player L5091; video: VideoFilter L5356, VideoView L5419, RenderOptions L5461; audio: AudioFilter L5380; Subtitles L5559; media: MediaCapture L5719; Resolvers L5824; Packages L6066; Osd L5292; Host L5240; Clipboard L6181; Power L6201; Tools L6234; Storage L6277; System L6300; Secrets L6318; window: MainWindow L4480; App L4561; Bindings L6151; Ui L3601; Timeline L4437; Drops L4013; Appearance L4042; I18n L4184; Settings L4290.
128
128
 
129
129
  ## Examples
130
130
 
131
131
  Tested plugins in [examples/](https://github.com/vestrasys/vestra-player-sdk/tree/main/examples):
132
132
 
133
- - hello: The README Quick start: one menu command and an on-screen message. L8329–8418
134
- - blur: A tool window with one slider that blurs the playing video. L8419–8680
135
- - signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L8681–9013
136
- - bookmark: A tool window bound to the playback state: remember the position and jump back to it. L9014–9198
137
- - panel-menu: A sidebar panel with its own right-click menu. L9199–9404
138
- - menus: Radio menu items, separator groups and a menu item whose title changes. L9405–9564
139
- - theme-widgets: A tool window drawn with the player's theme and widgets. L9565–9728
140
- - markdown: A window that shows a Markdown document. L9729–9923
141
- - i18n: A plugin in the player's language: English source text, a Chinese translation. L9924–10091
133
+ - hello: The README Quick start: one menu command and an on-screen message. L8333–8422
134
+ - blur: A tool window with one slider that blurs the playing video. L8423–8684
135
+ - signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L8685–9017
136
+ - bookmark: A tool window bound to the playback state: remember the position and jump back to it. L9018–9202
137
+ - panel-menu: A sidebar panel with its own right-click menu. L9203–9408
138
+ - menus: Radio menu items, separator groups and a menu item whose title changes. L9409–9568
139
+ - theme-widgets: A tool window drawn with the player's theme and widgets. L9569–9732
140
+ - markdown: A window that shows a Markdown document. L9733–9927
141
+ - i18n: A plugin in the player's language: English source text, a Chinese translation. L9928–10095
142
142
 
143
143
  ## Optional
144
144
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vestra-player/sdk",
3
- "version": "1.5.17",
3
+ "version": "1.5.18",
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": {