@vestra-player/sdk 1.5.55 → 1.5.57
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 +14 -0
- package/dist/docs-tree.json.gz +0 -0
- package/dist/plugin/appearance.js +49 -2
- package/dist/plugin/resolvers.js +29 -4
- package/dist/plugin/types.d.ts +15 -2
- package/llms.txt +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.5.57
|
|
4
|
+
|
|
5
|
+
**Who must change: nobody.** The first npm release with 1.5.56's fix: no change to the TypeScript API or the wire, `apiVersion` stays `vestra/1`, no new capability, no player version needed.
|
|
6
|
+
|
|
7
|
+
- **1.5.56 never reached npm.** Its tag was pushed, but the release run (41502365359) skipped `publish` because GitHub never gave its two macOS jobs a hosted runner (capacity) and they were cancelled. 1.5.57 publishes the same code: `appearance.onChange` and `resolvers.onFileTypesChange` hear a change the player woke the plugin for, and the session-storage clearing docs, as described under [1.5.56](#1556). Install 1.5.57; there is no `@vestra-player/sdk@1.5.56` on npm.
|
|
8
|
+
- _Release process_: runner capacity no longer blocks a release (product-owner ruling, 2026-11-02). `release.yml` publishes once `verify`, `static`, `build`, `docs` and the Ubuntu and Windows tests and examples pass; macOS tests and examples still run on every release as `test-macos`, beside `publish` and without gating it. `_test.yml` takes an `os` input (a JSON array of runner labels, all three by default), so pull requests and `main` still test and gate on Ubuntu, Windows and macOS as before. [Maintaining › Releasing](docs/maintaining.md#releasing) says so.
|
|
9
|
+
|
|
10
|
+
## 1.5.56
|
|
11
|
+
|
|
12
|
+
**Who must change: nobody.** A fix: no change to the TypeScript API or the wire, `apiVersion` stays `vestra/1`, no new capability, no player version needed.
|
|
13
|
+
|
|
14
|
+
- **`appearance.onChange` and `resolvers.onFileTypesChange` hear a change the player woke the plugin for.** A plugin the player stopped and starts again to deliver a palette or file-type change ([Idle plugins are stopped](docs/explanation/plugins.md#idle-plugins-are-stopped)) read the new value with `window.state` at start; the held `appearance.changed` or `resolvers.fileTypes` that followed compared equal to it, so the listeners never ran. The SDK now compares an event with what the listeners last heard, not with the value read at start: they hear the change once, and the same value again is still not a change. The player sends `resolvers.fileTypes` only when the list changed. It sends `appearance.changed` when the theme or the language changed, both values each time; an event whose language differs from the last one the SDK saw is a language change, and as before does not call `onChange` unless the theme differs too (also for the echo of the plugin's own `setLanguage`). One case remains: a plugin the player woke for a language change alone cannot tell it from a theme change, since the event does not say what changed, and its `onChange` may hear the unchanged theme once. A field naming the change could be added to the event later without breaking anything. `appearance.theme`, `resolvers.fileTypes` and views read the same values as before. `packages.onChange` and `bindings.onChange` (the other two events that wake a plugin) never compared, and are unchanged.
|
|
15
|
+
- _Docs_: when session storage is cleared, corrected against the player: also when a store or another plugin with `plugins.manage` disables the plugin (`packages.setEnabled(id, false)`, or an update installed with `enabled: false`, player 0.6.4), and when an earlier installation kept for a later reinstall (after a `replace`) is dropped because the player keeps only so many; [How a plugin runs › Stopping](docs/explanation/plugins.md#stopping) names other plugins with `plugins.manage` too. `SessionStorage`, [How a plugin runs › Restarts](docs/explanation/plugins.md#restarts-activate-can-run-more-than-once) and [Store a plugin's data](docs/how-to/store-data.md) say so. `Appearance.onChange` and `Resolvers.onFileTypesChange` describe the wake.
|
|
16
|
+
|
|
3
17
|
## 1.5.55
|
|
4
18
|
|
|
5
19
|
**Who must change: nobody, but check `TestHost` tests that update a disabled plugin.** Additive: `InstallOptions` gains `enabled` and `TestHost` gains `installKeepsDisabled`, `apiVersion` stays `vestra/1`, no new capability, and existing code still compiles. Older players ignore the option, and an install there always enables the plugin. One `TestHost` behaviour change at run time: like player 0.6.4, it now keeps a `disabled` entry disabled when the plugin under test installs an update or reinstall over it without `enabled`, where it used to make it `running`. A test that expects the update to run (the player's Store test did) sets `host.installKeepsDisabled = false` to keep playing players up to 0.6.3, or asserts the new rule; a test that covers both runs once with each.
|
package/dist/docs-tree.json.gz
CHANGED
|
Binary file
|
|
@@ -18,12 +18,34 @@ class AppearanceService {
|
|
|
18
18
|
/** The saved interface language (the next start's). */
|
|
19
19
|
language;
|
|
20
20
|
#listeners = new Set();
|
|
21
|
+
/**
|
|
22
|
+
* The theme listeners last heard (or the last event's), not the one read
|
|
23
|
+
* at start: a plugin woken from standby reads the new theme from
|
|
24
|
+
* `window.state`, then gets the `appearance.changed` the player held for
|
|
25
|
+
* it, and its listeners still hear that change. Left unset until the
|
|
26
|
+
* first event on purpose: set from the start-up read, it would hide that
|
|
27
|
+
* held change again.
|
|
28
|
+
*/
|
|
29
|
+
#notified;
|
|
30
|
+
/**
|
|
31
|
+
* The language as the start-up read and later events carried it (not
|
|
32
|
+
* `language`, which the plugin's own `setLanguage` changes before its
|
|
33
|
+
* echo arrives). The player sends `appearance.changed` once per change
|
|
34
|
+
* of the theme or of the language, each with both values: an event whose
|
|
35
|
+
* language differs from this one is a language change, and its theme is
|
|
36
|
+
* compared with `theme` as before. Only a newest event that repeats the
|
|
37
|
+
* start-up language is taken for a theme change; a plugin woken for a
|
|
38
|
+
* language change gets that too, so its listeners may hear the unchanged
|
|
39
|
+
* theme once (the event does not say what changed).
|
|
40
|
+
*/
|
|
41
|
+
#eventLanguage;
|
|
21
42
|
#started = false;
|
|
22
43
|
constructor(runtime) {
|
|
23
44
|
this.#runtime = runtime;
|
|
24
45
|
this.theme =
|
|
25
46
|
windowOf(runtime).appearance ?? "vestra";
|
|
26
47
|
this.language = preference(windowOf(runtime).language) ?? "system";
|
|
48
|
+
this.#eventLanguage = this.language;
|
|
27
49
|
}
|
|
28
50
|
start() {
|
|
29
51
|
if (this.#started)
|
|
@@ -33,22 +55,47 @@ class AppearanceService {
|
|
|
33
55
|
this.#runtime.on("appearance.changed", (data) => {
|
|
34
56
|
const event = data;
|
|
35
57
|
const language = preference(event?.language);
|
|
58
|
+
// Older players send no language: their events are theme changes.
|
|
59
|
+
const languageChanged = language !== undefined && language !== this.#eventLanguage;
|
|
60
|
+
if (language)
|
|
61
|
+
this.#eventLanguage = language;
|
|
36
62
|
if (language && language !== this.language) {
|
|
37
63
|
this.language = language;
|
|
38
64
|
this.#runtime.invalidate();
|
|
39
65
|
}
|
|
40
66
|
const theme = event?.theme;
|
|
41
|
-
if (theme
|
|
67
|
+
if (!theme || !THEMES.includes(theme))
|
|
68
|
+
return;
|
|
69
|
+
if (languageChanged) {
|
|
70
|
+
// The theme came along unchanged (or this plugin set it already).
|
|
42
71
|
this.accept(theme);
|
|
72
|
+
this.#notified = theme;
|
|
73
|
+
}
|
|
74
|
+
else
|
|
75
|
+
this.changed(theme);
|
|
43
76
|
}, "events", true);
|
|
44
77
|
}
|
|
78
|
+
/** A theme change event: listeners hear it unless they already did. */
|
|
79
|
+
changed(theme) {
|
|
80
|
+
const changed = theme !== this.theme;
|
|
81
|
+
this.theme = theme;
|
|
82
|
+
if (theme !== this.#notified)
|
|
83
|
+
this.#notify(theme);
|
|
84
|
+
if (changed)
|
|
85
|
+
this.#runtime.invalidate();
|
|
86
|
+
}
|
|
87
|
+
/** After this plugin's own `set`: only a change from the current theme. */
|
|
45
88
|
accept(theme) {
|
|
46
89
|
if (theme === this.theme)
|
|
47
90
|
return;
|
|
48
91
|
this.theme = theme;
|
|
92
|
+
this.#notify(theme);
|
|
93
|
+
this.#runtime.invalidate();
|
|
94
|
+
}
|
|
95
|
+
#notify(theme) {
|
|
96
|
+
this.#notified = theme;
|
|
49
97
|
for (const listener of [...this.#listeners])
|
|
50
98
|
listener(theme);
|
|
51
|
-
this.#runtime.invalidate();
|
|
52
99
|
}
|
|
53
100
|
watch(listener) {
|
|
54
101
|
this.#listeners.add(listener);
|
package/dist/plugin/resolvers.js
CHANGED
|
@@ -17,6 +17,14 @@ class FileTypesService {
|
|
|
17
17
|
#runtime;
|
|
18
18
|
types;
|
|
19
19
|
#listeners = new Set();
|
|
20
|
+
/**
|
|
21
|
+
* The list listeners last heard, not the one read at start: a plugin
|
|
22
|
+
* woken from standby reads the new list from `window.state`, then gets
|
|
23
|
+
* the `resolvers.fileTypes` the player held for it, and its listeners
|
|
24
|
+
* still hear that change. The player sends the event only when the list
|
|
25
|
+
* changed, so a first event is always news to the listeners.
|
|
26
|
+
*/
|
|
27
|
+
#notified;
|
|
20
28
|
#started = false;
|
|
21
29
|
constructor(runtime) {
|
|
22
30
|
this.#runtime = runtime;
|
|
@@ -30,7 +38,7 @@ class FileTypesService {
|
|
|
30
38
|
this.#runtime.on("resolvers.fileTypes", (data) => {
|
|
31
39
|
const types = data?.fileTypes;
|
|
32
40
|
if (Array.isArray(types) && types.every((t) => typeof t === "string"))
|
|
33
|
-
this.
|
|
41
|
+
this.changed(types);
|
|
34
42
|
}, "events", true);
|
|
35
43
|
// What changed between the start-up read and the subscription.
|
|
36
44
|
const window = windowOf(this.#runtime);
|
|
@@ -39,16 +47,33 @@ class FileTypesService {
|
|
|
39
47
|
this.accept(window.fileTypes, this.#runtime.can("events"));
|
|
40
48
|
});
|
|
41
49
|
}
|
|
42
|
-
/** `
|
|
50
|
+
/** From `resolvers.fileTypes`: listeners hear it unless they already did. */
|
|
51
|
+
changed(types) {
|
|
52
|
+
const changed = !sameTypes(types, this.types);
|
|
53
|
+
if (changed)
|
|
54
|
+
this.types = Object.freeze([...types]);
|
|
55
|
+
if (!this.#notified || !sameTypes(types, this.#notified))
|
|
56
|
+
this.#notify(types);
|
|
57
|
+
if (changed)
|
|
58
|
+
this.#runtime.invalidate();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* From a `window.state` read: only a change from the current list.
|
|
62
|
+
* `notify`: false without `events`, whose listeners never fire.
|
|
63
|
+
*/
|
|
43
64
|
accept(types, notify = true) {
|
|
44
65
|
if (sameTypes(types, this.types))
|
|
45
66
|
return;
|
|
46
67
|
this.types = Object.freeze([...types]);
|
|
47
68
|
if (notify)
|
|
48
|
-
|
|
49
|
-
listener([...types]);
|
|
69
|
+
this.#notify(types);
|
|
50
70
|
this.#runtime.invalidate();
|
|
51
71
|
}
|
|
72
|
+
#notify(types) {
|
|
73
|
+
this.#notified = Object.freeze([...types]);
|
|
74
|
+
for (const listener of [...this.#listeners])
|
|
75
|
+
listener([...types]);
|
|
76
|
+
}
|
|
52
77
|
watch(listener) {
|
|
53
78
|
this.#listeners.add(listener);
|
|
54
79
|
const held = this.#runtime.hold("resolvers.fileTypes");
|
package/dist/plugin/types.d.ts
CHANGED
|
@@ -3140,7 +3140,13 @@ export interface Appearance {
|
|
|
3140
3140
|
* Needs `events`: without it the listener never runs for other plugins'
|
|
3141
3141
|
* changes. Views need no help to follow the palette; use this for things
|
|
3142
3142
|
* the plugin draws itself (a rendered image, colours it computes). Errors
|
|
3143
|
-
* go to {@link Scope.onError}.
|
|
3143
|
+
* go to {@link Scope.onError}. When the player starts a stopped plugin
|
|
3144
|
+
* for a palette change (player 0.5.21), {@link Appearance.theme} already
|
|
3145
|
+
* has the new palette at start and the listener still hears the change
|
|
3146
|
+
* (SDK 1.5.56; before, it did not run). A language change does not call
|
|
3147
|
+
* it, except in one case: a plugin started for a language change alone
|
|
3148
|
+
* may hear the unchanged palette once, since the player's event does not
|
|
3149
|
+
* say which of the two changed.
|
|
3144
3150
|
*
|
|
3145
3151
|
* @capability events
|
|
3146
3152
|
*
|
|
@@ -8424,6 +8430,10 @@ export interface Resolvers {
|
|
|
8424
8430
|
/**
|
|
8425
8431
|
* {@link Resolvers.fileTypes} changed: a file resolver was added, or its
|
|
8426
8432
|
* plugin stopped. Needs `events`; without it the listener never fires.
|
|
8433
|
+
* When the player starts a stopped plugin for this change (player
|
|
8434
|
+
* 0.5.21), {@link Resolvers.fileTypes} already has the new list at start
|
|
8435
|
+
* and the listener still hears the change (SDK 1.5.56; before, it did not
|
|
8436
|
+
* run).
|
|
8427
8437
|
*
|
|
8428
8438
|
* @param listener - Receives the new list.
|
|
8429
8439
|
* @returns A handle that removes the listener.
|
|
@@ -9721,7 +9731,10 @@ export interface Storage {
|
|
|
9721
9731
|
* | --- | --- |
|
|
9722
9732
|
* | The plugin's process restarts: reload, upgrade, crash | kept |
|
|
9723
9733
|
* | The plugin failed to start or failed, and starts again | kept |
|
|
9724
|
-
* | The user
|
|
9734
|
+
* | The user, or a plugin with `plugins.manage` (`packages.setEnabled(id, false)`), disables the plugin | cleared |
|
|
9735
|
+
* | An update or reinstall with `enabled: false` switches an enabled plugin off (player 0.6.4) | cleared |
|
|
9736
|
+
* | The plugin is uninstalled | cleared |
|
|
9737
|
+
* | An earlier installation kept for a later reinstall (after a `replace`) is dropped because the player keeps only so many | cleared |
|
|
9725
9738
|
* | The player quits | cleared |
|
|
9726
9739
|
*
|
|
9727
9740
|
* - **Per plugin.** A plugin sees only its own keys. Like
|
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vestra Player SDK
|
|
2
2
|
|
|
3
|
-
> @vestra-player/sdk 1.5.
|
|
3
|
+
> @vestra-player/sdk 1.5.57: 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
5
|
## Read the documentation
|
|
6
6
|
|