@vestra-player/sdk 1.5.24 → 1.5.26
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 +19 -0
- package/bin/vestra-plugin.mjs +85 -10
- package/dist/api-requests.d.ts +36 -0
- package/dist/api-requests.js +143 -0
- package/dist/capabilities.d.ts +6 -3
- package/dist/capabilities.js +16 -230
- package/dist/capability-check.d.ts +85 -0
- package/dist/capability-check.js +203 -0
- package/dist/capability-rules.d.ts +102 -0
- package/dist/capability-rules.js +132 -0
- package/dist/host-capabilities.d.ts +10 -0
- package/dist/host-capabilities.js +360 -0
- package/dist/player-runtime.d.ts +2 -1
- package/dist/player-runtime.js +2 -1
- package/dist/plugin/services.d.ts +35 -0
- package/dist/plugin/services.js +87 -2
- package/dist/plugin/testing.d.ts +24 -1
- package/dist/plugin/testing.js +71 -1
- package/dist/plugin/types.d.ts +79 -1
- package/dist/ts-plugin.d.ts +23 -0
- package/dist/ts-plugin.js +135 -0
- package/dist/wire.d.ts +12 -0
- package/dist/wire.js +10 -0
- package/llms-full.txt +201 -8
- package/llms.txt +23 -23
- package/package.json +9 -3
- package/ts-plugin/index.d.ts +8 -0
- package/ts-plugin/index.js +6 -0
- package/ts-plugin/package.json +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.5.26
|
|
4
|
+
|
|
5
|
+
**Who must change: authors whose plugin uses a member without one of the capabilities it needs, and only to `check`, `build` or `pack` again.** No API changes, `apiVersion` stays `vestra/1`, no player version needed, and packages already built keep running as before: the player decides at run time exactly as it did. What changes is that `vestra-plugin check` (and so `build` and `pack`) now fails on such a use, including uses that never failed at run time: a listener (`onChange`) without `events` never fires instead of failing; a subtitle change (`select`, `load`, `remove`, `setStyle`) without `subtitles.read` fails only when it reads the current selection; a capability's **Also needs** (`processing.video` without `playback.read`) was documented but not enforced. Such a plugin packed with 1.5.25 and stops packing with 1.5.26 until the missing capability is added to `manifest.json` (or the use removed). The player's built-in plugins and the plugin repository's plugins were checked with this release: no findings.
|
|
6
|
+
|
|
7
|
+
- **Undeclared capabilities are caught while writing and packing** (user ruling of 2026-10-27, doc/process/rounds/2026-10-capability-check.md in the player repository): every use of an API member whose capability `manifest.json` does not declare, with `file:line:column`, the member, the capability and the request. Type-aware: found through aliases, destructuring, parameters typed `Player` and so on; not through computed names, `any` or plain JavaScript. A member also needs its capabilities' **Also needs** (`requires`). Tests are not checked.
|
|
8
|
+
- **`vestra-plugin check`** runs it after the type check and fails on any finding; `build` and `pack` run `check` first. **`check --json`** prints the findings as JSON.
|
|
9
|
+
- **`@vestra-player/sdk/ts-plugin`**, a TypeScript language-service plugin: the same findings as errors in the editor, with the quick fix "Add '<capability>' to manifest.json". List it in `tsconfig.json` (`"plugins": [{ "name": "@vestra-player/sdk/ts-plugin" }]`) and use the workspace's TypeScript (VS Code: **Use Workspace Version**).
|
|
10
|
+
- **One rule with the player.** The SDK carries a copy of the player's generated capability table (`src/host/capabilities.json`: which request needs which capability, by event name or processing stage where it depends on one) and the requests each member sends. `CAPABILITY_INFO` is now built from them; its contents are unchanged. `HOST_CAPABILITIES` (`@vestra-player/sdk/runtime`, for the player's agreement test) is the copy.
|
|
11
|
+
- Docs: *Capabilities* gains *Catching a missing capability*; *Getting started* adds the `tsconfig.json` with the plugin and the VS Code step; *Command line* (the rule and `--json`); *Subtitles* and *Capabilities*: changes also need `subtitles.read` (they read the current selection first; the table now says so). `examples/tsconfig.json` lists the plugin. `llms.txt` and `llms-full.txt` regenerated.
|
|
12
|
+
|
|
13
|
+
## 1.5.25
|
|
14
|
+
|
|
15
|
+
**Who must change: nobody.** Plugins built on earlier SDKs keep working unchanged: `plugin.storage.json` and every other API do what they did. Additive; `apiVersion` stays `vestra/1`. The addition needs player 0.5.5.
|
|
16
|
+
|
|
17
|
+
- **`plugin.storage.session`** (`SessionStorage`, player 0.5.5; user ruling of 2026-10-27, after Chrome's `chrome.storage.session`): `get(key)`, `set(key, value)`, `delete(key)` and `keys()` of JSON values that live as long as the **player**, not the plugin's process. They survive every restart of the plugin within one player session (a reload, also of a development load, an upgrade, a crash, a failed start) and are cleared when the user disables or uninstalls the plugin, and when the player quits. Per plugin, no capability. Keys are 1–1024 bytes of well-formed text; a plugin's keys, values (as compact JSON) and 128 bytes per key are at most 1 MiB together, and a `set` beyond fails with `limit` and changes nothing. One value must also fit in one 1 MiB message. A value `JSON.stringify` cannot write, or one with a lone surrogate in a string, fails with `invalid`; the order of an object's properties is not kept; `get` returns `undefined` for a missing key. Each `set` is one acknowledged request, without debounce. Players before 0.5.5 reject the calls with `unsupported`, so set `"minPlayerVersion": "0.5.5"`.
|
|
18
|
+
- **`SESSION_STORAGE_LIMITS`** (`@vestra-player/sdk/testing` and `/runtime`): `keyBytes` 1024, `bytes` 1 MiB, `entryBytes` 128.
|
|
19
|
+
- **`TestHost.sessionStorage`** (the player's store for the plugin, with the player's key rule and quota, objects stored with sorted properties as the player returns them) and **`startPlugin(..., { sessionStorage })`** to start with the values an earlier run left, to test a restart within one player session. `TestHost` now refuses any request over the 1 MiB message limit with `limit`, as the plugin runner does.
|
|
20
|
+
- Docs: *How a plugin runs* gains *Restarts: activate can run more than once*: when the player restarts a plugin's process, and "keep state that must survive a restart in session storage (or persistent storage)", with a table of what survives what. *Test a plugin* (testing a restart with session values), *Reference: limits* (`SESSION_STORAGE_LIMITS`). `llms.txt` and `llms-full.txt` regenerated.
|
|
21
|
+
|
|
3
22
|
## 1.5.24
|
|
4
23
|
|
|
5
24
|
**Who must change: nobody.** Plugins built on earlier SDKs keep working unchanged: `when: "interlaced"` and `when: "all"` do what they did. Additive; `apiVersion` stays `vestra/1`. The addition needs player 0.5.4.
|
package/bin/vestra-plugin.mjs
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
* directory. Works in any project that depends on @vestra-player/sdk.
|
|
12
12
|
*
|
|
13
13
|
* check strict type check of the plugin's .ts files and tests/*.ts
|
|
14
|
+
* (then every use of an API member whose capability manifest.json
|
|
15
|
+
* does not declare: file:line, member, capability; fails on any;
|
|
16
|
+
* --json prints the findings as JSON)
|
|
14
17
|
* build check, then write dist/: .ts → .js with types stripped, other
|
|
15
18
|
* package files copied, dist/manifest.json with `version`
|
|
16
19
|
* test node --test on tests/*.test.{ts,mjs}
|
|
@@ -88,6 +91,9 @@ const i18n = await import(pathToFileURL(join(sdkRoot, "dist/i18n.js")).href);
|
|
|
88
91
|
const i18nTools = await import(
|
|
89
92
|
pathToFileURL(join(sdkRoot, "dist/i18n-tools.js")).href
|
|
90
93
|
);
|
|
94
|
+
const capabilityCheck = await import(
|
|
95
|
+
pathToFileURL(join(sdkRoot, "dist/capability-check.js")).href
|
|
96
|
+
);
|
|
91
97
|
const SDK = "@vestra-player/sdk";
|
|
92
98
|
|
|
93
99
|
/** Never part of a production package. */
|
|
@@ -234,7 +240,7 @@ function run(command, args, options = {}) {
|
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
/** npm dependencies are installed from the lock file when missing. */
|
|
237
|
-
function dependencies(target) {
|
|
243
|
+
function dependencies(target, quiet = false) {
|
|
238
244
|
const deps = {
|
|
239
245
|
...target.packageJson.dependencies,
|
|
240
246
|
...target.packageJson.devDependencies,
|
|
@@ -244,12 +250,15 @@ function dependencies(target) {
|
|
|
244
250
|
present(join(target.directory, "node_modules"))
|
|
245
251
|
)
|
|
246
252
|
return;
|
|
247
|
-
|
|
253
|
+
(quiet ? console.error : console.log)(
|
|
254
|
+
`${target.name}: installing dependencies (npm ci)`,
|
|
255
|
+
);
|
|
248
256
|
// npm is npm.cmd on Windows, which spawn only runs through a shell.
|
|
249
257
|
if (
|
|
250
258
|
run("npm", ["ci", "--no-audit", "--no-fund"], {
|
|
251
259
|
cwd: target.directory,
|
|
252
260
|
shell: process.platform === "win32",
|
|
261
|
+
...(quiet ? { stdio: ["ignore", process.stderr, "inherit"] } : {}),
|
|
253
262
|
}) !== 0
|
|
254
263
|
)
|
|
255
264
|
fail(
|
|
@@ -296,10 +305,10 @@ function checkConfig(target, sources) {
|
|
|
296
305
|
};
|
|
297
306
|
}
|
|
298
307
|
|
|
299
|
-
async function check(target) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
dependencies(target);
|
|
308
|
+
async function check(target, report = null) {
|
|
309
|
+
const say = report ? () => {} : (line) => console.log(line);
|
|
310
|
+
for (const hint of target.hints ?? []) say(`${target.name}: hint: ${hint}`);
|
|
311
|
+
dependencies(target, !!report);
|
|
303
312
|
const own = (await files(target.directory)).filter(
|
|
304
313
|
(file) => isTypeScript(file) || file.endsWith(".mts"),
|
|
305
314
|
);
|
|
@@ -312,20 +321,41 @@ async function check(target) {
|
|
|
312
321
|
join(target.directory, file),
|
|
313
322
|
);
|
|
314
323
|
if (!sources.length) {
|
|
315
|
-
|
|
324
|
+
say(`${target.name}: no TypeScript to check`);
|
|
325
|
+
report?.push({ plugin: target.name, findings: [] });
|
|
316
326
|
return;
|
|
317
327
|
}
|
|
318
328
|
const tsc = compiler("typescript/lib/tsc.js");
|
|
319
329
|
const scratch = await mkdtemp(join(tmpdir(), "vestra-plugin-check-"));
|
|
330
|
+
let findings;
|
|
320
331
|
try {
|
|
321
332
|
const config = join(scratch, "tsconfig.json");
|
|
322
333
|
await writeFile(config, JSON.stringify(checkConfig(target, sources)));
|
|
323
|
-
if (
|
|
334
|
+
if (
|
|
335
|
+
run(process.execPath, [tsc, "-p", config], {
|
|
336
|
+
stdio: report ? ["ignore", process.stderr, "inherit"] : "inherit",
|
|
337
|
+
}) !== 0
|
|
338
|
+
)
|
|
324
339
|
fail(`${target.name}: type check failed`);
|
|
340
|
+
say(`${target.name}: type check passed (${sources.length} files)`);
|
|
341
|
+
findings = await capabilityFindings(target, config);
|
|
325
342
|
} finally {
|
|
326
343
|
await rm(scratch, { recursive: true, force: true });
|
|
327
344
|
}
|
|
328
|
-
|
|
345
|
+
if (report) report.push({ plugin: target.name, findings });
|
|
346
|
+
else
|
|
347
|
+
for (const finding of findings)
|
|
348
|
+
console.error(
|
|
349
|
+
`${relative(process.cwd(), finding.file) || finding.file}:${finding.line}:${finding.column}: ${finding.message} (request ${finding.method})`,
|
|
350
|
+
);
|
|
351
|
+
if (findings.length) {
|
|
352
|
+
const missing = [...new Set(findings.map((each) => each.capability))];
|
|
353
|
+
fail(
|
|
354
|
+
`${target.name}: ${findings.length} use${findings.length === 1 ? "" : "s"} of undeclared capabilities; add ${missing.map((each) => `"${each}"`).join(", ")} to manifest.json "capabilities" (or stop using those members)`,
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
say(`${target.name}: capabilities declared for every API use`);
|
|
358
|
+
if (report) return;
|
|
329
359
|
// Translation warnings never fail the check.
|
|
330
360
|
if (present(join(target.directory, "locales"))) {
|
|
331
361
|
try {
|
|
@@ -338,6 +368,37 @@ async function check(target) {
|
|
|
338
368
|
}
|
|
339
369
|
}
|
|
340
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Uses of API members whose capability the manifest does not declare, in
|
|
373
|
+
* the plugin's production files (not tests/), with the type check's
|
|
374
|
+
* compiler options (src/capability-check.ts).
|
|
375
|
+
*/
|
|
376
|
+
async function capabilityFindings(target, config) {
|
|
377
|
+
const ts = await typescript();
|
|
378
|
+
const parsed = ts.getParsedCommandLineOfConfigFile(
|
|
379
|
+
config,
|
|
380
|
+
{},
|
|
381
|
+
{
|
|
382
|
+
...ts.sys,
|
|
383
|
+
onUnRecoverableConfigFileDiagnostic: (diagnostic) =>
|
|
384
|
+
fail(
|
|
385
|
+
`${target.name}: ${ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`,
|
|
386
|
+
),
|
|
387
|
+
},
|
|
388
|
+
);
|
|
389
|
+
const files = (await sourceFiles(target)).typescript.map((file) =>
|
|
390
|
+
join(target.directory, file),
|
|
391
|
+
);
|
|
392
|
+
if (!parsed || !files.length) return [];
|
|
393
|
+
const program = ts.createProgram(parsed.fileNames, parsed.options);
|
|
394
|
+
const capabilities = Array.isArray(target.manifest.capabilities)
|
|
395
|
+
? target.manifest.capabilities
|
|
396
|
+
: [];
|
|
397
|
+
return capabilityCheck
|
|
398
|
+
.findUndeclaredCapabilities(ts, program, { files, capabilities })
|
|
399
|
+
.map((finding) => ({ ...finding, file: resolve(finding.file) }));
|
|
400
|
+
}
|
|
401
|
+
|
|
341
402
|
/** The plugin's own production .ts / .mts and .slint files. */
|
|
342
403
|
async function sourceFiles(target) {
|
|
343
404
|
const all = await files(target.directory);
|
|
@@ -703,6 +764,7 @@ async function pack(target, flag, outDirectory) {
|
|
|
703
764
|
|
|
704
765
|
const USAGE = [
|
|
705
766
|
"usage: vestra-plugin <check|build|test|pack> [plugin-dir...] [--version x.y.z] [--out dir]",
|
|
767
|
+
" vestra-plugin check [plugin-dir...] --json",
|
|
706
768
|
" vestra-plugin i18n extract [plugin-dir...] [--locale <lang>]...",
|
|
707
769
|
" vestra-plugin i18n check [plugin-dir...]",
|
|
708
770
|
].join("\n");
|
|
@@ -740,6 +802,12 @@ async function main() {
|
|
|
740
802
|
}
|
|
741
803
|
if (locales.length && subcommand !== "extract")
|
|
742
804
|
fail("--locale applies to i18n extract");
|
|
805
|
+
const jsonIndex = args.indexOf("--json");
|
|
806
|
+
const report = jsonIndex >= 0 ? [] : null;
|
|
807
|
+
if (report) {
|
|
808
|
+
args.splice(jsonIndex, 1);
|
|
809
|
+
if (command !== "check") fail("--json applies to check");
|
|
810
|
+
}
|
|
743
811
|
const flag = option("--version");
|
|
744
812
|
const out = option("--out");
|
|
745
813
|
const directories = args.length ? args : ["."];
|
|
@@ -747,11 +815,12 @@ async function main() {
|
|
|
747
815
|
fail("--version applies to a single plugin");
|
|
748
816
|
const failed = [];
|
|
749
817
|
for (const directory of directories) {
|
|
818
|
+
const reported = report?.length ?? 0;
|
|
750
819
|
try {
|
|
751
820
|
const target = await plugin(directory);
|
|
752
821
|
if (subcommand === "extract") await i18nExtract(target, locales);
|
|
753
822
|
else if (subcommand === "check") await i18nCheck(target);
|
|
754
|
-
else if (command === "check") await check(target);
|
|
823
|
+
else if (command === "check") await check(target, report);
|
|
755
824
|
else if (command === "build") await build(target, flag);
|
|
756
825
|
else if (command === "pack") await pack(target, flag, out);
|
|
757
826
|
else await test(target);
|
|
@@ -759,8 +828,14 @@ async function main() {
|
|
|
759
828
|
if (!error.expected) throw error;
|
|
760
829
|
console.error(`✖ ${error.message}`);
|
|
761
830
|
failed.push(directory);
|
|
831
|
+
if (report) {
|
|
832
|
+
if (report.length === reported) report.push({ findings: [] });
|
|
833
|
+
report[reported].error = error.message;
|
|
834
|
+
}
|
|
762
835
|
}
|
|
836
|
+
if (report) report[reported] = { directory, ...report[reported] };
|
|
763
837
|
}
|
|
838
|
+
if (report) console.log(JSON.stringify(report, null, 2));
|
|
764
839
|
if (failed.length) {
|
|
765
840
|
console.error(
|
|
766
841
|
`${subcommand ? `i18n ${subcommand}` : command} failed for: ${failed.join(", ")}`,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which player requests each member of the plugin API sends: the SDK's half
|
|
3
|
+
* of the capability rule (the player's half, what each request needs, is
|
|
4
|
+
* `HOST_CAPABILITIES`). A member is written `Interface.member` as in
|
|
5
|
+
* `CAPABILITY_INFO`; members declared on `Scope` are written `Plugin.…`.
|
|
6
|
+
*
|
|
7
|
+
* List the requests that decide the member's capabilities: the one it
|
|
8
|
+
* sends to do its work, and for a listener the `events.subscribe` with its
|
|
9
|
+
* event name. A string parameter that the player's rule reads (`event`,
|
|
10
|
+
* `stage`) is given in `params`. `also: true` marks a request whose
|
|
11
|
+
* capability the member needs on top of its own (documented at the member,
|
|
12
|
+
* not listed in its capability's `CAPABILITY_INFO.apis`).
|
|
13
|
+
*
|
|
14
|
+
* Members that need no capability are left out, apart from a few that show
|
|
15
|
+
* a rule's "none" case. Members of objects that another listed member
|
|
16
|
+
* returns (a `Window` from `Windows.create`, a `Panel` from `Panels.mount`)
|
|
17
|
+
* are left out too: the call that created the object already needs the
|
|
18
|
+
* capability.
|
|
19
|
+
*
|
|
20
|
+
* Order matters for `CAPABILITY_INFO`: each capability lists its members in
|
|
21
|
+
* this table's order. test/capability-rules.test.ts checks every method and
|
|
22
|
+
* parameter against the player's table.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
/** @internal One request a member sends. */
|
|
27
|
+
export interface ApiRequest {
|
|
28
|
+
/** The wire method (`source.submit`). */
|
|
29
|
+
readonly method: string;
|
|
30
|
+
/** String parameters the player's rule for the method reads. */
|
|
31
|
+
readonly params?: Readonly<Record<string, string>>;
|
|
32
|
+
/** A further capability, documented at the member. */
|
|
33
|
+
readonly also?: true;
|
|
34
|
+
}
|
|
35
|
+
/** @internal */
|
|
36
|
+
export declare const API_REQUESTS: Readonly<Record<string, readonly ApiRequest[]>>;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which player requests each member of the plugin API sends: the SDK's half
|
|
3
|
+
* of the capability rule (the player's half, what each request needs, is
|
|
4
|
+
* `HOST_CAPABILITIES`). A member is written `Interface.member` as in
|
|
5
|
+
* `CAPABILITY_INFO`; members declared on `Scope` are written `Plugin.…`.
|
|
6
|
+
*
|
|
7
|
+
* List the requests that decide the member's capabilities: the one it
|
|
8
|
+
* sends to do its work, and for a listener the `events.subscribe` with its
|
|
9
|
+
* event name. A string parameter that the player's rule reads (`event`,
|
|
10
|
+
* `stage`) is given in `params`. `also: true` marks a request whose
|
|
11
|
+
* capability the member needs on top of its own (documented at the member,
|
|
12
|
+
* not listed in its capability's `CAPABILITY_INFO.apis`).
|
|
13
|
+
*
|
|
14
|
+
* Members that need no capability are left out, apart from a few that show
|
|
15
|
+
* a rule's "none" case. Members of objects that another listed member
|
|
16
|
+
* returns (a `Window` from `Windows.create`, a `Panel` from `Panels.mount`)
|
|
17
|
+
* are left out too: the call that created the object already needs the
|
|
18
|
+
* capability.
|
|
19
|
+
*
|
|
20
|
+
* Order matters for `CAPABILITY_INFO`: each capability lists its members in
|
|
21
|
+
* this table's order. test/capability-rules.test.ts checks every method and
|
|
22
|
+
* parameter against the player's table.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
const submit = [{ method: "source.submit" }, { method: "source.operation" }];
|
|
27
|
+
const readsSubtitles = { method: "subtitles.state", also: true };
|
|
28
|
+
const listen = (event, also) => also
|
|
29
|
+
? { method: "events.subscribe", params: { event }, also }
|
|
30
|
+
: { method: "events.subscribe", params: { event } };
|
|
31
|
+
/** @internal */
|
|
32
|
+
export const API_REQUESTS = Object.freeze({
|
|
33
|
+
"Player.state": [{ method: "source.state" }],
|
|
34
|
+
"Player.refresh": [{ method: "source.state" }],
|
|
35
|
+
"Player.stats": [{ method: "playback.stats" }],
|
|
36
|
+
"Player.chapters": [{ method: "player.chapters" }],
|
|
37
|
+
"Player.audioDevices": [{ method: "player.audioDevices" }],
|
|
38
|
+
"Player.onChange": [listen("source.state")],
|
|
39
|
+
"Player.open": submit,
|
|
40
|
+
"Player.openStream": [
|
|
41
|
+
{ method: "producer.prepare" },
|
|
42
|
+
{ method: "source.submit", also: true },
|
|
43
|
+
],
|
|
44
|
+
"Player.setPaused": submit,
|
|
45
|
+
"Player.seek": submit,
|
|
46
|
+
"Player.setRate": submit,
|
|
47
|
+
"Player.restart": submit,
|
|
48
|
+
"Player.close": submit,
|
|
49
|
+
"Player.scrub": submit,
|
|
50
|
+
"Player.setOutput": [{ method: "playback.set" }],
|
|
51
|
+
"Player.provideSequence": [{ method: "sequence.set" }],
|
|
52
|
+
"Player.next": [{ method: "sequence.step" }],
|
|
53
|
+
"Player.previous": [{ method: "sequence.step" }],
|
|
54
|
+
"Player.addAudioTrack": [{ method: "audio.addTrack" }],
|
|
55
|
+
"Player.selectAudioTrack": [{ method: "audio.selectTrack" }],
|
|
56
|
+
"Player.step": [{ method: "player.step" }],
|
|
57
|
+
"Player.setStepSeek": [{ method: "player.setStepSeek" }],
|
|
58
|
+
"Player.setLoop": [{ method: "player.setLoop" }],
|
|
59
|
+
"Player.setAudioDevice": [{ method: "player.setAudioDevice" }],
|
|
60
|
+
"Power.preventSleep": [{ method: "power.preventSleep" }],
|
|
61
|
+
"Subtitles.state": [{ method: "subtitles.state" }],
|
|
62
|
+
"Subtitles.onChange": [
|
|
63
|
+
listen("source.state"),
|
|
64
|
+
{ method: "subtitles.state" },
|
|
65
|
+
],
|
|
66
|
+
"Subtitles.refresh": [{ method: "subtitles.state" }],
|
|
67
|
+
// Changes read the current selection first (`refresh`), unless
|
|
68
|
+
// `ifCurrent` pins one; `load` always does.
|
|
69
|
+
"Subtitles.select": [{ method: "subtitles.select" }, readsSubtitles],
|
|
70
|
+
"Subtitles.load": [{ method: "subtitles.upload.begin" }, readsSubtitles],
|
|
71
|
+
"Subtitles.remove": [{ method: "subtitles.remove" }, readsSubtitles],
|
|
72
|
+
"Subtitles.setStyle": [{ method: "subtitles.style" }, readsSubtitles],
|
|
73
|
+
"Timeline.marks": [{ method: "timeline.marks" }],
|
|
74
|
+
"Timeline.onChange": [listen("timeline.changed")],
|
|
75
|
+
"Timeline.layer": [{ method: "timeline.set" }],
|
|
76
|
+
"MainWindow.onChange": [listen("window.state")],
|
|
77
|
+
"MainWindow.setVideoArea": [{ method: "window.setVideoArea" }],
|
|
78
|
+
"MainWindow.setAlwaysOnTop": [{ method: "window.setAlwaysOnTop" }],
|
|
79
|
+
"MainWindow.setCursorAutoHide": [{ method: "window.setCursorAutoHide" }],
|
|
80
|
+
"MainWindow.setPictureInPicture": [
|
|
81
|
+
{ method: "window.setPictureInPicture" },
|
|
82
|
+
],
|
|
83
|
+
"Appearance.onChange": [listen("appearance.changed")],
|
|
84
|
+
"Appearance.set": [{ method: "appearance.set" }],
|
|
85
|
+
"Appearance.setLanguage": [{ method: "appearance.setLanguage" }],
|
|
86
|
+
"Drops.provide": [{ method: "drops.provide" }],
|
|
87
|
+
"Panels.mount": [{ method: "ui.mount" }],
|
|
88
|
+
"Panels.bottom": [{ method: "layout.state" }],
|
|
89
|
+
"Panels.sidebar": [{ method: "layout.state" }],
|
|
90
|
+
"Panels.backdrop": [{ method: "layout.state" }],
|
|
91
|
+
"PanelSlot.onChange": [{ method: "layout.state" }, listen("window.state")],
|
|
92
|
+
"Panel.onChange": [{ method: "layout.state" }, listen("window.state")],
|
|
93
|
+
"Panel.onDrop": [{ method: "drops.listen" }],
|
|
94
|
+
"BackdropSlot.onChange": [
|
|
95
|
+
{ method: "layout.state" },
|
|
96
|
+
listen("window.state"),
|
|
97
|
+
],
|
|
98
|
+
"Resolvers.add": [{ method: "sourceResolvers.register" }],
|
|
99
|
+
"Resolvers.onFileTypesChange": [listen("resolvers.fileTypes")],
|
|
100
|
+
"Commands.add": [{ method: "commands.register" }],
|
|
101
|
+
"Host.run": [{ method: "host.run" }],
|
|
102
|
+
"Windows.create": [{ method: "ui.open" }],
|
|
103
|
+
"Dialogs.confirm": [{ method: "dialogs.confirm" }],
|
|
104
|
+
"Dialogs.openFile": [{ method: "dialogs.open" }],
|
|
105
|
+
"Dialogs.openFiles": [{ method: "dialogs.open" }],
|
|
106
|
+
"Dialogs.openDirectory": [{ method: "dialogs.open" }],
|
|
107
|
+
"Dialogs.saveFile": [{ method: "dialogs.open" }],
|
|
108
|
+
"Packages.list": [{ method: "packages.list" }],
|
|
109
|
+
"Packages.onChange": [listen("packages.changed")],
|
|
110
|
+
"Packages.validate": [{ method: "packages.validate" }],
|
|
111
|
+
"Packages.validateArchive": [{ method: "packages.validateArchive" }],
|
|
112
|
+
"Packages.setEnabled": [{ method: "packages.setEnabled" }],
|
|
113
|
+
"Packages.reload": [{ method: "packages.reload" }],
|
|
114
|
+
"Packages.uninstall": [{ method: "packages.uninstall" }],
|
|
115
|
+
"Plugin.video.filter": [
|
|
116
|
+
{ method: "processing.replace", params: { stage: "video" } },
|
|
117
|
+
listen("source.state", true),
|
|
118
|
+
],
|
|
119
|
+
"Plugin.video.view": [{ method: "video.view.set" }],
|
|
120
|
+
"Plugin.video.render": [{ method: "video.render.set" }],
|
|
121
|
+
"Plugin.audio.filter": [
|
|
122
|
+
{ method: "processing.replace", params: { stage: "audio" } },
|
|
123
|
+
],
|
|
124
|
+
"MediaCapture.capture": [
|
|
125
|
+
{ method: "snapshot.state" },
|
|
126
|
+
{ method: "snapshot.capture" },
|
|
127
|
+
],
|
|
128
|
+
"Snapshot.export": [{ method: "jobs.state" }, { method: "jobs.start" }],
|
|
129
|
+
"Osd.show": [{ method: "osd.show" }],
|
|
130
|
+
"Osd.panel": [{ method: "osd.panel" }],
|
|
131
|
+
"Clipboard.readText": [{ method: "clipboard.readText" }],
|
|
132
|
+
"Clipboard.writeText": [{ method: "clipboard.writeText" }],
|
|
133
|
+
"Clipboard.writeImage": [{ method: "clipboard.writeImage" }],
|
|
134
|
+
"Bindings.list": [{ method: "bindings.list" }],
|
|
135
|
+
"Bindings.set": [{ method: "bindings.set" }],
|
|
136
|
+
"Bindings.reset": [{ method: "bindings.reset" }],
|
|
137
|
+
"Bindings.onChange": [listen("bindings.changed")],
|
|
138
|
+
"Settings.page": [{ method: "settings.register" }],
|
|
139
|
+
"Settings.show": [{ method: "settings.show" }],
|
|
140
|
+
"Secrets.get": [{ method: "secrets.get" }],
|
|
141
|
+
"Secrets.set": [{ method: "secrets.set" }],
|
|
142
|
+
"Secrets.delete": [{ method: "secrets.delete" }],
|
|
143
|
+
});
|
package/dist/capabilities.d.ts
CHANGED
|
@@ -38,8 +38,11 @@ export interface CapabilityInfo {
|
|
|
38
38
|
/**
|
|
39
39
|
* Every manifest capability the player knows (`vestra/1`), in the player's
|
|
40
40
|
* order, with the members it opens, the capabilities they also need and the
|
|
41
|
-
* store's wording.
|
|
42
|
-
*
|
|
41
|
+
* store's wording. Built from the player's own capability table (its
|
|
42
|
+
* `src/host/capabilities.json`, copied into the SDK) and the requests each
|
|
43
|
+
* member sends, the same rule `vestra-plugin check` and the SDK's
|
|
44
|
+
* TypeScript plugin apply; the player's tests check that the copy is
|
|
45
|
+
* current.
|
|
43
46
|
*
|
|
44
47
|
* A member not listed under any capability needs none (`plugin.tools`,
|
|
45
48
|
* `plugin.storage`, `plugin.system`, `plugin.app`, `plugin.ui`,
|
|
@@ -62,7 +65,7 @@ export declare const CAPABILITY_INFO: Readonly<Record<string, CapabilityInfo>>;
|
|
|
62
65
|
/**
|
|
63
66
|
* Manifest capabilities the player knows (`vestra/1`): the keys of
|
|
64
67
|
* {@link CAPABILITY_INFO}, in the player's order. The same list as the
|
|
65
|
-
* player's `host/
|
|
68
|
+
* player's `host/capabilities.json`; the player's tests check that they agree.
|
|
66
69
|
*/
|
|
67
70
|
export declare const CAPABILITIES: readonly string[];
|
|
68
71
|
/** The plugin API version this SDK implements (`manifest.apiVersion`). */
|