@vestra-player/sdk 1.5.25 → 1.5.27
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 +17 -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 +1 -0
- package/dist/player-runtime.js +1 -0
- package/dist/plugin/stream.js +56 -8
- package/dist/plugin/types.d.ts +2 -1
- package/dist/ts-plugin.d.ts +23 -0
- package/dist/ts-plugin.js +135 -0
- package/llms-full.txt +52 -7
- 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,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.5.27
|
|
4
|
+
|
|
5
|
+
**Who must change: nobody.** No API changes, `apiVersion` stays `vestra/1`, no player version needed. Plugins pick the fix up with the player's next SDK upgrade (the player builds the `plugin` object with its own copy); nothing in a plugin changes.
|
|
6
|
+
|
|
7
|
+
- **Generated streams reach their full frame rate on Windows.** A stream from `openStream` or a file resolver (the NES emulator: one 1/60 s picture per `frame()`) played at 23–26 frames a second on Windows instead of 60. The SDK asked the player how much audio the sound card had played, rendered at most one frame, and waited 5 ms before asking again; Windows rounds that wait up to its 15.6 ms timer tick, and with the round trip one pass took about 40 ms, so one frame per pass could not keep up. macOS timers are about 1 ms, which hid it. Each pass now calls `frame()` as many times in a row as it takes to refill the whole lead (about 50 ms of audio, unchanged, so latency is unchanged), at most 16 times, and stops early when a frame carries no audio; and a pass that rendered frames and already took longer than 5 ms is followed at once instead of after another timer tick. A pass that rendered nothing (paused, lead full) still waits 5 ms after it ends, so an idle or paused stream asks the player no more often than before. Measured against a real-time audio clock with the NES core and its homebrew ROM: with a 15–30 ms round trip 1.5.26 rendered 22–32 frames a second and let the device run dry, 1.5.27 renders 60 and keeps it fed; only a round trip near 50 ms (the whole lead) still lets it run dry now and then. Controls (start, pause, seek) still apply between frames and never while one renders, and `stop()` still ends after the frame being rendered.
|
|
8
|
+
- Docs: *Example: signal generator* says `frame()` may be called several times back to back. `llms.txt` and `llms-full.txt` regenerated.
|
|
9
|
+
|
|
10
|
+
## 1.5.26
|
|
11
|
+
|
|
12
|
+
**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.
|
|
13
|
+
|
|
14
|
+
- **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.
|
|
15
|
+
- **`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.
|
|
16
|
+
- **`@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**).
|
|
17
|
+
- **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.
|
|
18
|
+
- 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.
|
|
19
|
+
|
|
3
20
|
## 1.5.25
|
|
4
21
|
|
|
5
22
|
**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.
|
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`). */
|