@vestra-player/sdk 1.5.30 → 1.5.33

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,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.33
4
+
5
+ 1.5.32 was not published (a tag error).
6
+
7
+ **Who must change: nobody.** No API changes, `apiVersion` stays `vestra/1`, no player version needed. Only documentation, its checks and the generated `llms-full.txt` change.
8
+
9
+ - **Five more categories reach the full reference standard** and join `STRICT_CATEGORIES`: Subtitles (`Subtitles` and its state and track types), Sources (`Resolvers`, `Resolver` and the resolver option and result types), Media (`MediaCapture`, `Snapshot`, `ExportJob` and their options), Processing (`VideoFilter`, `AudioFilter`, `VideoView`, `RenderOptions` and the node and settings types) and Packages (`Packages`, `PackageCandidate`, `PackageChange` and the manifest and plugin-info types); `Bindings` joins Commands, `Timeline` and `TimelineLayer` join Playback, `Drops` joins UI. Every method has an example (what it does and how it works), `@capability`, `@since` and a `@throws` per error code, checked against the SDK and the player's source; every type has `@category`. Methods with an explained example: 121 of 191 → 153.
10
+ - Facts the reference now states, from the source: an `ExportJob` and a `PackageChange` are polled (about every 350 ms and 400 ms) until they end, and their `done` resolves with a failed outcome rather than rejecting; a plugin holds at most 4 snapshots (16 in the player); `VideoView.set`, `RenderOptions.set` and the filters' `set` never throw (a refusal shows in `status` and goes to `onError`); `Resolver.ready` rejects with `conflict` without failing activation when another plugin holds the extension or host.
11
+ - **The rest reaches the standard: every declaration is now in `STRICT_CATEGORIES`.** Plugin (`Plugin`, `Scope`, `Disposable`, `MainWindow`, `App` and their data types) and Testing (`TestHost`, `startPlugin`, the fakes, `HostError` and the limit and table constants) join the other categories; `doc-lint` now checks declarations of `@vestra-player/sdk/testing` too. Methods with an explained example: 182 of 191; the other 9 are callback fields of option types, documented on the owning type.
12
+ - **Corrections from the review against the player's and the SDK's source.** Subtitles have no event: the SDK reads the subtitle state again on source, phase or backend changes, so a selection changed in the player shows after `refresh()`; a change without `ifCurrent` reads the newest state first and almost never fails with `stale`, and the select example passes `ifCurrent` (embedded tracks are chosen by number). `setStyle` reports a font not in `state.fonts` as `unsupported`. Packages: the player copies a package when it validates it, so `staleDigest` is not a code the SDK sees; a broken package is `host` (with `javascript` and `slint` for code that does not parse or compile), `versionMismatch` only for a newer `minPlayerVersion`; `cancel` of a committed change answers `tooLate` and the change stays `committed`. The Drops example claims `.ch8`: the built-in playlist claims every audio and video extension first. More codes: `missing`, `unavailable` and `busy` for subtitle changes, `busy` (2 exports per plugin, 8 in the player) and `unavailable` for `Snapshot.export`, `busy` and `revisionConflict` for install and uninstall, `busy` (16 resolvers) for `Resolver.ready`, `missing` for `Bindings.reset`, `command` for `FakeCommand.run`; `plugin.video.view()` and `render()` throw `capability` or a plain `Error` for a second handle, and `render()` is `failed` with `unsupported` at once under software rendering.
13
+ - **TestHost follows the player more closely.** A core action run from its menu record (`host.coreAction(id).run()`) while it is disabled now rejects with `command`, like the player (it rejected with `unavailable`, which is what `plugin.host.run` gives). When only disabled commands hold a pressed key, `press` now looks only at the first of them, as the player does: without a `reason` the key passes, even if a later one has a reason. Tests that relied on the old behaviour see a different code or `"passed"`.
14
+ - More corrections from the review: built-in plugins cannot be disabled, so another plugin never gets the built-in playlist's drop extensions or the sequence provider (except a development load replacing the playlist); `validateArchive` reports an archive that cannot be unpacked (over 64 MB, too many files, damaged, unsafe paths) as `invalid` and a broken unpacked package as `host`; `install` is `busy` only while the library is being cleaned up or 64 change records are kept, and `revisionConflict` is retried by calling `install` again; the `PluginError` table no longer lists `staleDigest`, and `versionMismatch` means a newer `minPlayerVersion` only.
15
+ - `llms.txt` may now be 10 KB (10,240 bytes, up from 9 KB) to leave room for about 20 more how-to pages in its index; it stays under 2.6k tokens.
16
+ - New how-to guide: *Load subtitles from a plugin* (reading tracks, selecting with `stale`, uploading SRT/ASS with the limits, the style layer and which plugin's layer the player shows).
17
+
18
+ ## 1.5.31
19
+
20
+ **Who must change: nobody.** No API changes, `apiVersion` stays `vestra/1`, no player version needed. Only documentation, its checks and the generated `llms-full.txt` change.
21
+
22
+ - **The Commands, Playback and Services categories reach the full reference standard** (they are now in `STRICT_CATEGORIES`, so CI keeps them complete): `Commands`, `Command`, `Host` and their option types; `Player`, `Media`, `Scrub`, `Stream` and the playback state and stream types; `Storage`, `JsonStore`, `SessionStorage`, `Secrets`, `Clipboard`, `System`, `Tools`, `Power`. Every method has an example (what it does and how it works), `@capability`, `@since` and a `@throws` per error code it can reject with, checked against the SDK and the player's source; every type has `@category`, so the API reference lists them under their category instead of "Other". Methods with an explained example: 75 of 191 → 121.
23
+ - Error codes the reference now names, from the player's source: a control while nothing is open is `invalid` (`close` is not: closing with nothing open just succeeds); `setRate` takes 0.05–10 (the player's own keys stay within 0.25–4); `setOutput`'s volume outside 0–200 is `invalid`; `Stream.stop` rejects only when closing the source fails, and releases the stream either way.
24
+ - **Corrections from the review against the player's source.** `stale` means any change of the source since the state a call is based on: another file or a close, but also any pause, seek or speed change by the user or another plugin. A second sequence provider is refused with `conflict` (`sequence-taken`) without failing activation, and the built-in playlist registers first. `VESTRA_FFMPEG` / `VESTRA_FFPROBE` replace the `PATH` search instead of coming before it. More `@throws`: `capability` for `Secrets` and `Clipboard`; for a generated stream `busy` and `unsupported` for `seek` and `setRate`, `busy` for `setPaused` and `unsupported` for `restart`; `replaced`, `busy` and the resolver failures (`backend`, `unsupported`, `unavailable`) for `open`; `capability` for `Command.ready`; `aborted` for `openStream`; `stale` and `unsupported` for `Scrub.seek`; `disabled` and `unsupported` (players before 0.5.5) for session storage; `failed` and `timeout` (macOS) for `System`. *Store a plugin's data* no longer promises that a quit right after `save` loses nothing (a stopping plugin gets about 300 ms).
25
+ - New how-to guides: *Control playback* (reading and following the state, `stale` and `ifCurrent`, `Media`, core actions, Next and Previous) and *Store a plugin's data* (settings files, session values, secrets, your own files).
26
+ - `doc-lint`: `--list explained` lists the methods without an explained example; its summary line no longer says "Not enforced yet" (every example has been enforced since 1.5.30).
27
+ - Comments and docs name the player's host files at their new places (`src/host/src/packages/manifest.rs`, `ui/ui_image.rs`, `ui/ui_values.rs`, `playback/effects.rs`, `ui/theme.rs`).
28
+
3
29
  ## 1.5.30
4
30
 
5
31
  **Who must change: nobody.** No API changes, `apiVersion` stays `vestra/1`, no player version needed. Only documentation, its checks and the generated `llms-full.txt` change.
@@ -4,6 +4,8 @@
4
4
  * entry of {@link CAPABILITY_INFO}.
5
5
  *
6
6
  * @since 1.5.14
7
+ *
8
+ * @category Testing
7
9
  */
8
10
  export interface CapabilityInfo {
9
11
  /**
@@ -70,6 +72,8 @@ export interface CapabilityInfo {
70
72
  * ```
71
73
  *
72
74
  * @since 1.5.14
75
+ *
76
+ * @category Testing
73
77
  */
74
78
  export declare const CAPABILITY_INFO: Readonly<Record<string, CapabilityInfo>>;
75
79
  /**
@@ -88,5 +92,7 @@ export declare const API_VERSION = "vestra/1";
88
92
  * {@link UI_VALUE_LIMITS} before this.
89
93
  *
90
94
  * @since 1.5.14
95
+ *
96
+ * @category Testing
91
97
  */
92
98
  export declare const MESSAGE_LIMIT: number;
@@ -34,6 +34,8 @@ import { capabilityInfo } from "./capability-rules.js";
34
34
  * ```
35
35
  *
36
36
  * @since 1.5.14
37
+ *
38
+ * @category Testing
37
39
  */
38
40
  export const CAPABILITY_INFO = Object.freeze(Object.fromEntries(Object.entries(capabilityInfo()).map(([name, info]) => [
39
41
  name,
@@ -60,5 +62,7 @@ export const API_VERSION = "vestra/1";
60
62
  * {@link UI_VALUE_LIMITS} before this.
61
63
  *
62
64
  * @since 1.5.14
65
+ *
66
+ * @category Testing
63
67
  */
64
68
  export const MESSAGE_LIMIT = 1024 * 1024;
@@ -29,6 +29,9 @@ import type { ListJson, TextJson } from "./i18n.ts";
29
29
  * // 20 slots stay free for the plugin's own commands.
30
30
  * const shown = chapters.slice(0, Math.min(50, COMMAND_LIMITS.perPlugin - 20));
31
31
  * ```
32
+ *
33
+ * @since 1.0.0
34
+ * @category Testing
32
35
  */
33
36
  export declare const COMMAND_LIMITS: {
34
37
  /**
@@ -63,6 +66,9 @@ export declare const COMMAND_LIMITS: {
63
66
  * plugin.commands.add({ id: "blur", path: ["@video", "Blur"], run() {} });
64
67
  * assert.ok(MENU_IDS.includes("video")); // a menu id, not a title
65
68
  * ```
69
+ *
70
+ * @since 1.3.0
71
+ * @category Testing
66
72
  */
67
73
  export declare const MENU_IDS: readonly ["open", "playback", "subtitles", "video", "audio", "screen", "settings"];
68
74
  /**
@@ -84,6 +90,8 @@ export declare const MENU_IDS: readonly ["open", "playback", "subtitles", "video
84
90
  * ```
85
91
  *
86
92
  * @since 1.5.29
93
+ *
94
+ * @category Testing
87
95
  */
88
96
  export declare const BAR_BUTTON_ICONS: readonly ["play", "pause", "stop", "back", "forward", "open", "volume", "mute", "playlist", "detach", "attach", "close", "failed", "move-top", "move-up", "move-down", "move-bottom", "search", "chapter", "bookmark", "check-task", "check-box", "menu-check", "submenu", "scroll-up", "scroll-down", "caret-down", "sort-asc", "sort-desc", "tag-remove", "preview-play", "add", "remove", "sort", "fullscreen", "exit-fullscreen", "store", "ai"];
89
97
  /**
@@ -97,6 +105,8 @@ export declare const BAR_BUTTON_ICONS: readonly ["play", "pause", "stop", "back"
97
105
  * then the earlier declaration, goes first).
98
106
  *
99
107
  * @since 1.5.29
108
+ *
109
+ * @category Testing
100
110
  */
101
111
  export declare const BAR_BUTTON_LIMITS: {
102
112
  /** Buttons one plugin shows (1). */
@@ -111,6 +121,8 @@ export declare const BAR_BUTTON_LIMITS: {
111
121
  * {@link BUILTIN_SUBMENUS}.
112
122
  *
113
123
  * @since 1.5.14
124
+ *
125
+ * @category Testing
114
126
  */
115
127
  export interface BuiltinSubmenu {
116
128
  /**
@@ -156,6 +168,8 @@ export interface BuiltinSubmenu {
156
168
  * ```
157
169
  *
158
170
  * @since 1.5.14
171
+ *
172
+ * @category Testing
159
173
  */
160
174
  export declare const BUILTIN_SUBMENUS: readonly BuiltinSubmenu[];
161
175
  /**
@@ -163,6 +177,8 @@ export declare const BUILTIN_SUBMENUS: readonly BuiltinSubmenu[];
163
177
  * of {@link BUILTIN_COMMANDS}.
164
178
  *
165
179
  * @since 1.5.14
180
+ *
181
+ * @category Testing
166
182
  */
167
183
  export interface BuiltinCommand {
168
184
  /** `"host"` for the player's own commands, else the built-in plugin's id. */
@@ -208,6 +224,8 @@ export interface BuiltinCommand {
208
224
  * ```
209
225
  *
210
226
  * @since 1.5.14
227
+ *
228
+ * @category Testing
211
229
  */
212
230
  export declare const BUILTIN_COMMANDS: readonly BuiltinCommand[];
213
231
  export type CommandState = {
package/dist/commands.js CHANGED
@@ -26,6 +26,9 @@
26
26
  * // 20 slots stay free for the plugin's own commands.
27
27
  * const shown = chapters.slice(0, Math.min(50, COMMAND_LIMITS.perPlugin - 20));
28
28
  * ```
29
+ *
30
+ * @since 1.0.0
31
+ * @category Testing
29
32
  */
30
33
  export const COMMAND_LIMITS = {
31
34
  /**
@@ -60,6 +63,9 @@ export const COMMAND_LIMITS = {
60
63
  * plugin.commands.add({ id: "blur", path: ["@video", "Blur"], run() {} });
61
64
  * assert.ok(MENU_IDS.includes("video")); // a menu id, not a title
62
65
  * ```
66
+ *
67
+ * @since 1.3.0
68
+ * @category Testing
63
69
  */
64
70
  export const MENU_IDS = [
65
71
  "open",
@@ -89,6 +95,8 @@ export const MENU_IDS = [
89
95
  * ```
90
96
  *
91
97
  * @since 1.5.29
98
+ *
99
+ * @category Testing
92
100
  */
93
101
  export const BAR_BUTTON_ICONS = [
94
102
  "play",
@@ -141,6 +149,8 @@ export const BAR_BUTTON_ICONS = [
141
149
  * then the earlier declaration, goes first).
142
150
  *
143
151
  * @since 1.5.29
152
+ *
153
+ * @category Testing
144
154
  */
145
155
  export const BAR_BUTTON_LIMITS = {
146
156
  /** Buttons one plugin shows (1). */
@@ -183,6 +193,8 @@ export const BAR_BUTTON_LIMITS = {
183
193
  * ```
184
194
  *
185
195
  * @since 1.5.14
196
+ *
197
+ * @category Testing
186
198
  */
187
199
  export const BUILTIN_SUBMENUS = Object.freeze([
188
200
  { path: ["Open", "Recently Played"], plugins: ["vestra.history"] },
@@ -584,6 +596,8 @@ vestra.playlist | playlist.settings | (Playlist Settings…) | F5 | panel
584
596
  * ```
585
597
  *
586
598
  * @since 1.5.14
599
+ *
600
+ * @category Testing
587
601
  */
588
602
  export const BUILTIN_COMMANDS = Object.freeze(BUILTIN_COMMAND_TABLE.trim()
589
603
  .split("\n")
package/dist/i18n.d.ts CHANGED
@@ -3,6 +3,9 @@ import type { ListStyle, Locale } from "./plugin/types.ts";
3
3
  * The player's interface languages: English (the source language) first,
4
4
  * then the translations, as the player's own table (its tests check that
5
5
  * they agree).
6
+ *
7
+ * @since 1.5.9
8
+ * @category Testing
6
9
  */
7
10
  export declare const LOCALES: readonly ["en", "zh-Hans", "ja", "ko", "de", "fr", "es"];
8
11
  /** One message of a `.po` file (the header `msgid ""` is not one). */
@@ -94,6 +97,9 @@ export declare const LIST_STYLES: readonly ListStyle[];
94
97
  /**
95
98
  * The separator of each list style per interface language, as the player's
96
99
  * table (`i18n::text::SEPARATORS`; its tests check that they agree).
100
+ *
101
+ * @since 1.5.11
102
+ * @category Testing
97
103
  */
98
104
  export declare const LIST_SEPARATORS: Readonly<Record<Locale, Readonly<Record<ListStyle, string>>>>;
99
105
  /**
@@ -101,6 +107,9 @@ export declare const LIST_SEPARATORS: Readonly<Record<Locale, Readonly<Record<Li
101
107
  * {@link @vestra-player/sdk!Text | Text} or
102
108
  * {@link @vestra-player/sdk!TextList | TextList} with everything nested in it), as the player's
103
109
  * `i18n::text` (its tests check that they agree).
110
+ *
111
+ * @since 1.5.11
112
+ * @category Testing
104
113
  */
105
114
  export declare const TEXT_LIMITS: {
106
115
  /** Nesting depth of texts and lists; the value itself is depth 0 (8). */
package/dist/i18n.js CHANGED
@@ -14,6 +14,9 @@ import { join } from "node:path";
14
14
  * The player's interface languages: English (the source language) first,
15
15
  * then the translations, as the player's own table (its tests check that
16
16
  * they agree).
17
+ *
18
+ * @since 1.5.9
19
+ * @category Testing
17
20
  */
18
21
  export const LOCALES = ["en", "zh-Hans", "ja", "ko", "de", "fr", "es"];
19
22
  /** The catalog key: `msgid`, or `msgctxt` U+0004 `msgid`. */
@@ -359,6 +362,9 @@ export const LIST_STYLES = [
359
362
  /**
360
363
  * The separator of each list style per interface language, as the player's
361
364
  * table (`i18n::text::SEPARATORS`; its tests check that they agree).
365
+ *
366
+ * @since 1.5.11
367
+ * @category Testing
362
368
  */
363
369
  export const LIST_SEPARATORS = {
364
370
  en: {
@@ -416,6 +422,9 @@ export const LIST_SEPARATORS = {
416
422
  * {@link @vestra-player/sdk!Text | Text} or
417
423
  * {@link @vestra-player/sdk!TextList | TextList} with everything nested in it), as the player's
418
424
  * `i18n::text` (its tests check that they agree).
425
+ *
426
+ * @since 1.5.11
427
+ * @category Testing
419
428
  */
420
429
  export const TEXT_LIMITS = {
421
430
  /** Nesting depth of texts and lists; the value itself is depth 0 (8). */
package/dist/manifest.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The manifest rules `vestra-plugin check` applies; the same table as the
3
- * player's `host/src/manifest.rs` (the player's tests compare the limits).
3
+ * player's `src/host/src/packages/manifest.rs` (the player's tests compare the limits).
4
4
  * Paths in the manifest are checked against the plugin directory.
5
5
  */
6
6
  import { existsSync, lstatSync, readFileSync, realpathSync } from "node:fs";
@@ -33,5 +33,7 @@
33
33
  * ```
34
34
  *
35
35
  * @since 1.5.14
36
+ *
37
+ * @category Testing
36
38
  */
37
39
  export declare const THEME_PALETTES: Readonly<Record<"vestra" | "vestra-light", Readonly<Record<string, string>>>>;
package/dist/palettes.js CHANGED
@@ -33,6 +33,8 @@
33
33
  * ```
34
34
  *
35
35
  * @since 1.5.14
36
+ *
37
+ * @category Testing
36
38
  */
37
39
  export const THEME_PALETTES = Object.freeze({
38
40
  vestra: Object.freeze({
@@ -44,6 +44,8 @@ import type { Bindings } from "./types.ts";
44
44
  * ```
45
45
  *
46
46
  * @since 1.5.14
47
+ *
48
+ * @category Testing
47
49
  */
48
50
  export declare const BINDING_INPUTS: Readonly<{
49
51
  /**
@@ -51,6 +51,8 @@ import { failure } from "./runtime.js";
51
51
  * ```
52
52
  *
53
53
  * @since 1.5.14
54
+ *
55
+ * @category Testing
54
56
  */
55
57
  export const BINDING_INPUTS = Object.freeze({
56
58
  /**
@@ -29,6 +29,8 @@ import type { TemplateArgsJson, TextValueJson } from "../wire.ts";
29
29
  * ```
30
30
  *
31
31
  * @since 1.5.14
32
+ *
33
+ * @category Testing
32
34
  */
33
35
  export declare const OSD_LIMITS: Readonly<{
34
36
  /**
@@ -30,6 +30,8 @@ import { isTextValue, textProblem } from "../i18n.js";
30
30
  * ```
31
31
  *
32
32
  * @since 1.5.14
33
+ *
34
+ * @category Testing
33
35
  */
34
36
  export const OSD_LIMITS = Object.freeze({
35
37
  /**
@@ -41,6 +41,8 @@ export declare function tools(scope: ScopeImpl): Tools;
41
41
  * ```
42
42
  *
43
43
  * @since 1.5.25
44
+ *
45
+ * @category Testing
44
46
  */
45
47
  export declare const SESSION_STORAGE_LIMITS: Readonly<{
46
48
  /** UTF-8 bytes of a key (1024, at least 1; no NUL character). */
@@ -69,7 +71,8 @@ export declare function system(scope: ScopeImpl): System;
69
71
  * too long. Values are 1–1024 bytes counted in UTF-8, so the check uses
70
72
  * `Buffer.byteLength`; `secrets.set` would refuse other values with
71
73
  * `invalid`. The store itself can still refuse (`unsupported` without a
72
- * system store, `unavailable` or `failed` when it denies access): only
74
+ * system store, `unavailable` when it cannot be reached, `failed` when the
75
+ * user denies access): only
73
76
  * those codes get the "could not be saved" message, anything else (a
74
77
  * missing `secrets` capability) is a bug and is thrown on.
75
78
  * ```ts
@@ -94,6 +97,8 @@ export declare function system(scope: ScopeImpl): System;
94
97
  * ```
95
98
  *
96
99
  * @since 1.5.14
100
+ *
101
+ * @category Testing
97
102
  */
98
103
  export declare const SECRET_LIMITS: Readonly<{
99
104
  /**
@@ -275,6 +275,8 @@ class Store {
275
275
  * ```
276
276
  *
277
277
  * @since 1.5.25
278
+ *
279
+ * @category Testing
278
280
  */
279
281
  export const SESSION_STORAGE_LIMITS = Object.freeze({
280
282
  /** UTF-8 bytes of a key (1024, at least 1; no NUL character). */
@@ -413,7 +415,8 @@ export function system(scope) {
413
415
  * too long. Values are 1–1024 bytes counted in UTF-8, so the check uses
414
416
  * `Buffer.byteLength`; `secrets.set` would refuse other values with
415
417
  * `invalid`. The store itself can still refuse (`unsupported` without a
416
- * system store, `unavailable` or `failed` when it denies access): only
418
+ * system store, `unavailable` when it cannot be reached, `failed` when the
419
+ * user denies access): only
417
420
  * those codes get the "could not be saved" message, anything else (a
418
421
  * missing `secrets` capability) is a bug and is thrown on.
419
422
  * ```ts
@@ -438,6 +441,8 @@ export function system(scope) {
438
441
  * ```
439
442
  *
440
443
  * @since 1.5.14
444
+ *
445
+ * @category Testing
441
446
  */
442
447
  export const SECRET_LIMITS = Object.freeze({
443
448
  /**