@vestra-player/sdk 1.5.7 → 1.5.9

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.
@@ -73,9 +73,8 @@ export interface Disposable {
73
73
  * | `timeout` | A time limit ran out (`openStream` start-up, `tools.run`, `system.*` after 10 s). |
74
74
  * | `stream`, `device` | `openStream`: the producer failed / the audio device is not ready. |
75
75
  * | `backend-uncertain` | The player's backend blocked a filter stage; call `retry()`. |
76
- * | `cleanup` | {@link PackageTrial.stop} could not confirm cleanup; call it again. |
77
76
  * | `limit` | A player-wide limit was reached (for example the number of commands). |
78
- * | `reserved` | {@link Packages.validate}, {@link PackageCandidate.trial}, {@link PackageCandidate.install}: the id is `vestra` or starts with `vestra.` (any case), which only the player's built-in plugins use (player 0.4.1). |
77
+ * | `reserved` | {@link Packages.validate}, {@link PackageCandidate.install}: the id is `vestra` or starts with `vestra.` (any case), which only the player's built-in plugins use (player 0.4.1). |
79
78
  * | `versionMismatch` | The package needs a newer player (`minPlayerVersion`) or another `apiVersion`. |
80
79
  * | `ui-prepare` | The player could not prepare a mounted panel or a settings page (its Slint file does not compile, a bound property is not declared, or another plugin's panel holds the slot); `message` has the diagnostics. |
81
80
  * | `ui` | The player could not apply a property to a tool window or a settings page, or could not build the Options window (a property the Slint file does not declare, a value of the wrong type); `message` has Slint's reason. |
@@ -195,7 +194,7 @@ export interface Scope extends Disposable {
195
194
  readonly media: MediaCapture;
196
195
  /** Page-URL to stream-URL resolvers (`source.resolve`). */
197
196
  readonly resolvers: Resolvers;
198
- /** The installed plugins; validation, trials, installs (`plugins.manage` for changes). */
197
+ /** The installed plugins; validation, installs (`plugins.manage` for changes). */
199
198
  readonly packages: Packages;
200
199
  /** On-screen messages over the video (`ui.osd`). */
201
200
  readonly osd: Osd;
@@ -225,8 +224,10 @@ export interface Scope extends Disposable {
225
224
  readonly timeline: Timeline;
226
225
  /** Files dropped on the video area, by extension (`ui.drop`). */
227
226
  readonly drops: Drops;
228
- /** The player's palette. */
227
+ /** The player's palette and the saved interface language. */
229
228
  readonly appearance: Appearance;
229
+ /** The interface language of this run (read-only). */
230
+ readonly i18n: I18n;
230
231
  /** Pages in the player's options window (`ui.settings`). */
231
232
  readonly settings: Settings;
232
233
  /**
@@ -320,8 +321,7 @@ export interface Plugin extends Scope {
320
321
  readonly id: string;
321
322
  /**
322
323
  * A writable directory for this plugin's own files (settings, remembered
323
- * folders). Kept across restarts, disabling and upgrades; a trial gets a
324
- * temporary one. Write files atomically: to a temporary name, then rename.
324
+ * folders). Kept across restarts, disabling and upgrades. Write files atomically: to a temporary name, then rename.
325
325
  * Throws `unavailable` when the player provided none.
326
326
  *
327
327
  * Location: `~/Library/Application Support/Vestra/plugin-data/<id>/` on
@@ -362,9 +362,9 @@ export interface CommandState {
362
362
  export type Bindable<T> = T | (() => T);
363
363
  /**
364
364
  * A built-in top-level menu of the player, named in a command path as
365
- * `@<id>` (see {@link CommandOptions.path}): Open (打开), Playback (播放),
366
- * Subtitles (字幕), Video (视频), Audio (声音), Screen (屏幕), Settings (设置).
367
- * The list is `MENU_IDS` in `@vestra-player/sdk/testing`.
365
+ * `@<id>` or by its English key (see {@link CommandOptions.path}): Open,
366
+ * Playback, Subtitles, Video, Audio, Screen, Settings. The list is
367
+ * `MENU_IDS` in `@vestra-player/sdk/testing`.
368
368
  */
369
369
  export type MenuId = "open" | "playback" | "subtitles" | "video" | "audio" | "screen" | "settings";
370
370
  /**
@@ -381,7 +381,7 @@ export type MenuId = "open" | "playback" | "subtitles" | "video" | "audio" | "sc
381
381
  * ({@link MenuId}) sit at fixed orders, whatever is inside them: Open 110,
382
382
  * Playback 200, Subtitles 300, Video 400, Audio 500, Screen 710, Settings
383
383
  * 830 (player 0.3.0). This holds whether the path names the menu by id
384
- * (`["@video", "Blur"]`) or by its title (`["视频", "Blur"]`), so a plugin's
384
+ * (`["@video", "Blur"]`) or by its key (`["Video", "Blur"]`), so a plugin's
385
385
  * item never moves the player's menu. Directly inside a built-in menu,
386
386
  * `order` 0 (the default) sorts after every other order: an item without
387
387
  * `order` goes at the end, after the player's own items (which all use 100
@@ -404,13 +404,20 @@ export interface CommandOptions {
404
404
  * one segment is a top-level item. Omit it for a command that is not in the
405
405
  * main menu (bindings and panel menus only); `title` is then required.
406
406
  *
407
- * Segments are menu titles, matched exactly. The player's own menus have
408
- * Chinese titles, so `["Video", "Blur"]` would add a second top-level menu
409
- * "Video". To join a built-in menu, start the path with its id, `@` plus a
410
- * {@link MenuId}: `@open`, `@playback`, `@subtitles`, `@video`, `@audio`,
411
- * `@screen` or `@settings`. Only the first segment is read as an id; an
412
- * unknown id, or an id with nothing after it, fails with `invalid`. Needs
413
- * player 0.3.0 (set `"minPlayerVersion": "0.3.0"`).
407
+ * Segments are English source text, and menus merge by them: commands
408
+ * of different plugins with the same leading segments share a submenu.
409
+ * The player shows each segment and the title in the interface language
410
+ * from the declaring plugin's catalog (`locales/<lang>.po`, see the
411
+ * [i18n guide](../../docs/how-to/i18n.md)); the player's own menus
412
+ * (Open, Playback, Subtitles, Video, Audio, Screen, Settings, and
413
+ * Playback ▸ Speed, Playback ▸ Seek) always show the player's words.
414
+ * A built-in menu can also be named by its id, `@` plus a {@link MenuId}:
415
+ * `@open`, `@playback`, `@subtitles`, `@video`, `@audio`, `@screen` or
416
+ * `@settings`. Only the first segment is read as an id; an unknown id, or
417
+ * an id with nothing after it, fails with `invalid`. Players up to 0.4.2
418
+ * titled their menus in Chinese (视频…): there `["Video", "Blur"]` is a
419
+ * menu of its own, so plugins for those players write `@video`; player
420
+ * 0.4.3 still accepts the old Chinese titles of its own menus.
414
421
  *
415
422
  * @example
416
423
  * ```ts
@@ -418,7 +425,10 @@ export interface CommandOptions {
418
425
  * ```
419
426
  */
420
427
  path?: string[];
421
- /** Menu label; defaults to the last path segment. */
428
+ /**
429
+ * Menu label (English source text, shown translated); defaults to the
430
+ * last path segment.
431
+ */
422
432
  title?: string;
423
433
  /**
424
434
  * Sibling order in the menu, ascending (integer, default 0). A submenu sits
@@ -1942,6 +1952,121 @@ export interface Appearance {
1942
1952
  * @since 1.0.0
1943
1953
  */
1944
1954
  set(theme: ThemeId): Promise<void>;
1955
+ /**
1956
+ * The saved interface language: `"system"` (follow the system's
1957
+ * languages, the default) or a {@link Locale}.
1958
+ *
1959
+ * @remarks
1960
+ * This is the choice for the next start. The language of this run is
1961
+ * {@link I18n.locale} and never changes while the player runs. Read before
1962
+ * activation; with `events` it follows other plugins' changes, without it
1963
+ * only this plugin's own. Players before 0.4.3 report `"system"`.
1964
+ *
1965
+ * @since 1.5.9
1966
+ */
1967
+ readonly language: LanguagePreference;
1968
+ /**
1969
+ * Save the interface language for the next start.
1970
+ *
1971
+ * @remarks
1972
+ * The player keeps the choice in its interface state; the language
1973
+ * changes when the player starts again (tell the user, for example "Takes
1974
+ * effect after restart"). Every plugin with `events` hears the change in
1975
+ * {@link Appearance.language}.
1976
+ *
1977
+ * @capability ui.theme
1978
+ * @player 0.4.3
1979
+ *
1980
+ * @param language - `"system"` or a {@link Locale}.
1981
+ * @returns Resolves once the player saved it; {@link Appearance.language}
1982
+ * has the new value.
1983
+ *
1984
+ * @throws `invalid` (rejects) `language` is not `"system"` or a {@link Locale}.
1985
+ * @throws `capability` (rejects) The manifest does not declare `ui.theme`.
1986
+ * @throws `unsupported` (rejects) A player before 0.4.3.
1987
+ *
1988
+ * @example
1989
+ * ```ts
1990
+ * await plugin.appearance.setLanguage("de");
1991
+ * await plugin.osd.show("Takes effect after restart");
1992
+ * ```
1993
+ *
1994
+ * @since 1.5.9
1995
+ */
1996
+ setLanguage(language: LanguagePreference): Promise<void>;
1997
+ }
1998
+ /**
1999
+ * An interface language of the player: English (`en`, the source language
2000
+ * of every plugin text) or a translation. The list is `LOCALES` in
2001
+ * `@vestra-player/sdk/testing`.
2002
+ *
2003
+ * @remarks
2004
+ * Simplified Chinese is `zh-Hans`. There is no Traditional Chinese: a
2005
+ * system set to Traditional Chinese (Taiwan, Hong Kong, Macao) gets English.
2006
+ *
2007
+ * @since 1.5.9
2008
+ * @category UI
2009
+ */
2010
+ export type Locale = "en" | "zh-Hans" | "ja" | "ko" | "de" | "fr" | "es";
2011
+ /**
2012
+ * The saved interface language ({@link Appearance.language}): follow the
2013
+ * system, or one {@link Locale}.
2014
+ *
2015
+ * @since 1.5.9
2016
+ * @category UI
2017
+ */
2018
+ export type LanguagePreference = "system" | Locale;
2019
+ /**
2020
+ * Arguments of a template sentence ({@link Osd.show},
2021
+ * {@link OsdPanel.set}, {@link ConfirmOptions.args}): an array for `{}` and
2022
+ * `{0}`, `{1}` placeholders, or an object for `{name}` placeholders. At most
2023
+ * 16 strings and finite numbers; whole numbers print without a fraction.
2024
+ *
2025
+ * @since 1.5.9
2026
+ * @category UI
2027
+ */
2028
+ export type TemplateArgs = readonly (string | number)[] | Readonly<Record<string, string | number>>;
2029
+ /**
2030
+ * The interface language of this run. `plugin.i18n`.
2031
+ *
2032
+ * @remarks
2033
+ * Plugins write no translation code. Every user-visible text is English
2034
+ * source text in one of three places, and the player translates it with
2035
+ * the plugin's own catalog (`locales/<lang>.po`, compiled into the package
2036
+ * by `vestra-plugin build`):
2037
+ *
2038
+ * 1. declarations: command titles and paths, settings page and panel
2039
+ * titles, the manifest's `name`, `punchline`, `description` and `tags`;
2040
+ * 2. Slint: `@tr("…")` in the plugin's `.slint` files;
2041
+ * 3. sentences the plugin hands the player: {@link Osd.show},
2042
+ * {@link OsdPanel.set} and {@link Dialogs.confirm} take a template and
2043
+ * its arguments (`osd.show("Speed {}×", [rate])`), never a sentence
2044
+ * composed in TypeScript.
2045
+ *
2046
+ * The language is fixed when the player starts: {@link I18n.locale} never
2047
+ * changes during a run. Read it for what is not text, such as the order of
2048
+ * names or a date format. `vestra-plugin i18n extract` collects the texts
2049
+ * into `locales/messages.pot`; see the
2050
+ * [i18n guide](../../docs/how-to/i18n.md).
2051
+ *
2052
+ * @capability None.
2053
+ *
2054
+ * @example Format a date the way the interface language writes it
2055
+ * ```ts
2056
+ * const day = new Date().toLocaleDateString(plugin.i18n.locale);
2057
+ * await plugin.osd.show("Today is {}", [day]);
2058
+ * ```
2059
+ *
2060
+ * @since 1.5.9
2061
+ * @category UI
2062
+ */
2063
+ export interface I18n {
2064
+ /**
2065
+ * The interface language of this run, chosen at start-up from the saved
2066
+ * {@link Appearance.language} or the system's languages; English when
2067
+ * neither names a {@link Locale}. Players before 0.4.3 report `"en"`.
2068
+ */
2069
+ readonly locale: Locale;
1945
2070
  }
1946
2071
  /**
1947
2072
  * The categories of the Options window. The tree shows them in this order:
@@ -2582,6 +2707,16 @@ export interface ConfirmOptions {
2582
2707
  destructive?: boolean;
2583
2708
  /** A checkbox under the text, such as "Don't ask again"; 1–40 characters. */
2584
2709
  checkbox?: string;
2710
+ /**
2711
+ * Values for the placeholders of `message` and `detail` (player 0.4.3).
2712
+ * Every text of the dialog is English source text that the player shows
2713
+ * translated from the plugin's catalog; `message` and `detail` are
2714
+ * templates like {@link Osd.show}'s. The length limits apply to the shown
2715
+ * text.
2716
+ *
2717
+ * @since 1.5.9
2718
+ */
2719
+ args?: TemplateArgs;
2585
2720
  }
2586
2721
  /**
2587
2722
  * The system's own dialogs: a confirmation alert and the open and save file
@@ -3351,18 +3486,20 @@ export interface OsdPanel extends Disposable {
3351
3486
  * @capability ui.osd
3352
3487
  *
3353
3488
  * @param text - The text, with `\n` between lines: at most 32 lines and
3354
- * 4096 bytes. `null` hides the block.
3489
+ * 4096 bytes once translated and formatted. `null` hides the block. A
3490
+ * template, like {@link Osd.show}'s.
3491
+ * @param args - Values for its placeholders (player 0.4.3).
3355
3492
  *
3356
3493
  * @example
3357
3494
  * ```ts
3358
3495
  * const info = plugin.osd.panel();
3359
- * info.set("A: 12.0 s\nB: 18.5 s");
3496
+ * info.set("A: {} s\nB: {} s", ["12.0", "18.5"]);
3360
3497
  * info.set(null); // hide it
3361
3498
  * ```
3362
3499
  *
3363
3500
  * @since 1.0.0
3364
3501
  */
3365
- set(text: string | null): void;
3502
+ set(text: string | null, args?: TemplateArgs): void;
3366
3503
  }
3367
3504
  /**
3368
3505
  * Text the player draws over the video: short messages and an information
@@ -3400,24 +3537,35 @@ export interface Osd {
3400
3537
  * Replaces the message on screen, whichever plugin showed it. A message
3401
3538
  * that is on screen when the plugin stops still disappears on time.
3402
3539
  *
3540
+ * The text is a template in English: the player shows its translation
3541
+ * from the plugin's catalog, with the placeholders (`{}`, `{0}`, `{name}`;
3542
+ * `{{` and `}}` for braces) filled from `args`. Without `args` the text
3543
+ * shows as it is (braces included). Untranslated, the English template is
3544
+ * formatted. Never compose the sentence in TypeScript
3545
+ * (`` `Speed ${rate}×` ``): translators can only translate whole templates.
3546
+ *
3403
3547
  * @capability ui.osd
3404
3548
  *
3405
- * @param text - 1–200 characters; line breaks become spaces.
3549
+ * @param text - The template, 1–200 characters once translated and
3550
+ * formatted; line breaks become spaces.
3551
+ * @param args - Values for its placeholders (player 0.4.3; older players
3552
+ * show the template as it is).
3406
3553
  * @returns Resolves once the message is on screen.
3407
3554
  *
3408
- * @throws `invalid` (rejects) `text` is empty, only white space, or longer
3409
- * than 200 characters.
3555
+ * @throws `invalid` (rejects) The shown text is empty, only white space,
3556
+ * or longer than 200 characters, or `args` is not a {@link TemplateArgs}.
3410
3557
  * @throws `unavailable` (rejects) The player runs without a user interface.
3411
3558
  * @throws `capability` (rejects) The manifest does not declare `ui.osd`.
3412
3559
  *
3413
3560
  * @example
3414
3561
  * ```ts
3415
3562
  * await plugin.osd.show("Bookmark added");
3563
+ * await plugin.osd.show("Speed {}×", [plugin.player.state.rate]);
3416
3564
  * ```
3417
3565
  *
3418
3566
  * @since 1.0.0
3419
3567
  */
3420
- show(text: string): Promise<void>;
3568
+ show(text: string, args?: TemplateArgs): Promise<void>;
3421
3569
  /**
3422
3570
  * Create this plugin's information block.
3423
3571
  *
@@ -4008,6 +4156,47 @@ export interface Resolvers {
4008
4156
  * error's message.
4009
4157
  */
4010
4158
  add(options: ResolverOptions): Resolver;
4159
+ /**
4160
+ * The extensions some plugin's file resolver handles (SDK 1.5.8, player
4161
+ * 0.4.2): lower case, without the dot, sorted, each once; not who
4162
+ * registered them. Reading needs no capability; `[]` from older players.
4163
+ * Without `events` it is the list from when the plugin first read it.
4164
+ * Use it to accept such files beside the player's own media types, for
4165
+ * example in a playlist's drop or folder scan.
4166
+ *
4167
+ * @example
4168
+ * ```ts
4169
+ * const MEDIA = ["mp4", "mkv", "mp3"];
4170
+ * const accepted = (path: string) => {
4171
+ * const extension = path.split(".").pop()?.toLowerCase() ?? "";
4172
+ * return MEDIA.includes(extension) || plugin.resolvers.fileTypes.includes(extension);
4173
+ * };
4174
+ * ```
4175
+ *
4176
+ * @capability None.
4177
+ * @player 0.4.2
4178
+ * @since 1.5.8
4179
+ */
4180
+ readonly fileTypes: readonly string[];
4181
+ /**
4182
+ * {@link Resolvers.fileTypes} changed: a file resolver was added, or its
4183
+ * plugin stopped. Needs `events`; without it the listener never fires.
4184
+ *
4185
+ * @param listener - Receives the new list.
4186
+ * @returns A handle that removes the listener.
4187
+ *
4188
+ * @example
4189
+ * ```ts
4190
+ * plugin.resolvers.onFileTypesChange((types) => {
4191
+ * void plugin.osd.show(`Also accepted: ${types.join(", ")}`);
4192
+ * });
4193
+ * ```
4194
+ *
4195
+ * @capability `events`
4196
+ * @player 0.4.2
4197
+ * @since 1.5.8
4198
+ */
4199
+ onFileTypesChange(listener: (types: string[]) => void): Disposable;
4011
4200
  }
4012
4201
  /**
4013
4202
  * The manifest of a package, as validated. The display fields and
@@ -4099,11 +4288,6 @@ export interface PackageCandidate {
4099
4288
  readonly manifest: PackageManifest;
4100
4289
  /** The checks the player ran. */
4101
4290
  readonly checks: string[];
4102
- /**
4103
- * Load it temporarily alongside the installed plugins. A reserved id
4104
- * (`vestra.*`) fails with `reserved`.
4105
- */
4106
- trial(): Promise<PackageTrial>;
4107
4291
  /**
4108
4292
  * Install it. The same source upgrades the installed plugin (its data
4109
4293
  * stays); another source fails with `conflict` unless `replace` is set;
@@ -4114,17 +4298,6 @@ export interface PackageCandidate {
4114
4298
  */
4115
4299
  install(options?: InstallOptions): Promise<PackageChange>;
4116
4300
  }
4117
- /** A trial load of a package. Disposing it stops the trial and waits for cleanup. */
4118
- export interface PackageTrial extends Disposable {
4119
- /** The trial's status as the player reports it. */
4120
- readonly status: string;
4121
- /**
4122
- * Stop and wait until the host confirmed cleanup. Rejects with code
4123
- * `cleanup` when the host stopped the trial without confirming cleanup;
4124
- * calling `stop()` again then asks the host again.
4125
- */
4126
- stop(): Promise<void>;
4127
- }
4128
4301
  /** The progress of an install, rollback or uninstall. */
4129
4302
  export type PackageChangeStatus = "preparing" | "activating" | "restoring" | "committed" | "cancelled" | "failed" | "failedDegraded" | "tooLate";
4130
4303
  /**
@@ -4149,8 +4322,8 @@ export interface PluginInfo {
4149
4322
  id: string;
4150
4323
  /** Version, `null` when unknown. */
4151
4324
  version: string | null;
4152
- /** From the install library, a `--plugin` development load, or a trial. */
4153
- origin: "installed" | "development" | "trial";
4325
+ /** From the install library, or a `--plugin` development load. */
4326
+ origin: "installed" | "development";
4154
4327
  /** Run state. */
4155
4328
  state: "starting" | "running" | "disabled" | "failed" | "stopped";
4156
4329
  /** Why it failed (`state: "failed"`). */
@@ -4166,7 +4339,7 @@ export interface PluginInfo {
4166
4339
  * replaced. `false` from players before 0.2.0.
4167
4340
  */
4168
4341
  builtin: boolean;
4169
- /** Where an installed plugin came from; `null` for development loads and trials. */
4342
+ /** Where an installed plugin came from; `null` for development loads. */
4170
4343
  source: PackageSource | null;
4171
4344
  /**
4172
4345
  * Its data directory (`plugin.dataDirectory` of that plugin); `null` when
@@ -4184,6 +4357,30 @@ export interface PluginInfo {
4184
4357
  * @since 1.5.2
4185
4358
  */
4186
4359
  warnings?: readonly PluginWarning[];
4360
+ /**
4361
+ * The manifest's display texts in the interface language, translated
4362
+ * with that package's catalog; absent from players before 0.4.3 (read
4363
+ * `manifest.json` there).
4364
+ *
4365
+ * @since 1.5.9
4366
+ */
4367
+ display?: PluginDisplay;
4368
+ }
4369
+ /**
4370
+ * {@link PluginInfo.display}: a package's `name`, `punchline`,
4371
+ * `description` and `tags` as the player shows them.
4372
+ *
4373
+ * @since 1.5.9
4374
+ */
4375
+ export interface PluginDisplay {
4376
+ /** `name`, translated; `null` when the manifest has none. */
4377
+ readonly name: string | null;
4378
+ /** `punchline`, translated; `null` when the manifest has none. */
4379
+ readonly punchline: string | null;
4380
+ /** `description`, translated; `null` when the manifest has none. */
4381
+ readonly description: string | null;
4382
+ /** `tags`, each translated. */
4383
+ readonly tags: readonly string[];
4187
4384
  }
4188
4385
  /**
4189
4386
  * One refusal in {@link PluginInfo.warnings}.
@@ -4222,6 +4419,10 @@ export interface Packages {
4222
4419
  * Validate a package directory (`plugins.manage`). A package whose id is
4223
4420
  * reserved for the built-in plugins (`vestra` or `vestra.*`) fails with
4224
4421
  * `reserved` (player 0.4.1).
4422
+ *
4423
+ * The player keeps the 32 most recent candidates of all plugins; an
4424
+ * older one's `install` fails with `stale` (validate again). Before
4425
+ * player 0.4.2 the 33rd validation of a run failed with `busy` instead.
4225
4426
  */
4226
4427
  validate(directory: string): Promise<PackageCandidate>;
4227
4428
  /**
@@ -4240,7 +4441,7 @@ export interface Packages {
4240
4441
  /**
4241
4442
  * Stop or start a plugin (`plugins.manage`). An installed plugin stays
4242
4443
  * disabled across launches; a development load only for this run.
4243
- * `invalid` to disable oneself, `unsupported` for a trial, `missing` unknown.
4444
+ * `invalid` to disable oneself, `missing` unknown.
4244
4445
  * `busy` while it is being installed.
4245
4446
  */
4246
4447
  setEnabled(id: string, enabled: boolean): Promise<void>;
@@ -4248,7 +4449,7 @@ export interface Packages {
4248
4449
  * Remove an installed plugin (`plugins.manage`); `removeData` also deletes
4249
4450
  * its data directory, otherwise reinstalling it from the same source
4250
4451
  * reconnects to its data. Its user bindings stay (as orphans).
4251
- * `unsupported` for built-ins, development loads and trials, `missing`
4452
+ * `unsupported` for built-ins and development loads, `missing`
4252
4453
  * unknown, `invalid` for oneself.
4253
4454
  */
4254
4455
  uninstall(id: string, options?: {
package/dist/plugin/ui.js CHANGED
@@ -1,4 +1,5 @@
1
1
  /** Tool windows, docked panels and system dialogs. */
2
+ import { templateArgs } from "./osd.js";
2
3
  import { readFileSync } from "node:fs";
3
4
  import { basename, extname, resolve } from "node:path";
4
5
  import { failure, Latest, quiet } from "./runtime.js";
@@ -651,7 +652,8 @@ export const dialogs = (scope) => {
651
652
  };
652
653
  return {
653
654
  async confirm(options) {
654
- const { message, detail, confirm, cancel, destructive, checkbox } = options ?? {};
655
+ const { message, detail, confirm, cancel, destructive, checkbox, args } = options ?? {};
656
+ const values = templateArgs(args);
655
657
  const length = (text, min, max) => typeof text === "string" &&
656
658
  [...text].length >= min &&
657
659
  [...text].length <= max;
@@ -669,6 +671,7 @@ export const dialogs = (scope) => {
669
671
  ...(cancel === undefined ? {} : { cancel }),
670
672
  ...(destructive === undefined ? {} : { destructive }),
671
673
  ...(checkbox === undefined ? {} : { checkbox }),
674
+ ...(values === undefined ? {} : { args: values }),
672
675
  });
673
676
  return {
674
677
  confirmed: answer.confirmed === true,
@@ -19,6 +19,10 @@ export declare class WindowService {
19
19
  start(): void;
20
20
  /** The palette, as the `window.state` reply carried it (`plugin.appearance`). */
21
21
  appearance: string | undefined;
22
+ /** The file resolvers' extensions, as the reply carried them (`plugin.resolvers.fileTypes`). */
23
+ fileTypes: string[] | undefined;
24
+ /** The saved interface language, as the reply carried it (`plugin.appearance.language`). */
25
+ language: string | undefined;
22
26
  accept(facts: WindowFacts): void;
23
27
  read(): Promise<void>;
24
28
  watch(listener: (state: WindowState) => void): {
@@ -52,9 +52,17 @@ export class WindowService {
52
52
  }
53
53
  /** The palette, as the `window.state` reply carried it (`plugin.appearance`). */
54
54
  appearance;
55
+ /** The file resolvers' extensions, as the reply carried them (`plugin.resolvers.fileTypes`). */
56
+ fileTypes;
57
+ /** The saved interface language, as the reply carried it (`plugin.appearance.language`). */
58
+ language;
55
59
  accept(facts) {
56
60
  if (facts.appearance)
57
61
  this.appearance = facts.appearance;
62
+ if (facts.language)
63
+ this.language = facts.language;
64
+ if (Array.isArray(facts.fileTypes))
65
+ this.fileTypes = [...facts.fileTypes];
58
66
  const next = view(facts);
59
67
  if (JSON.stringify(next) === JSON.stringify(this.state))
60
68
  return;
package/dist/wire.d.ts CHANGED
@@ -25,12 +25,6 @@ export interface PackageValidation {
25
25
  checks: string[];
26
26
  trustedExecution: true;
27
27
  }
28
- export interface PackageTrial {
29
- trialId: number;
30
- activationOwner?: number;
31
- status: string;
32
- cleanupConfirmed?: boolean;
33
- }
34
28
  export interface InstalledPackage {
35
29
  revision: number;
36
30
  current: null | {
@@ -102,7 +96,7 @@ export declare class HostError extends Error {
102
96
  export interface PackageInfo {
103
97
  id: string;
104
98
  version: string | null;
105
- origin: "installed" | "development" | "trial";
99
+ origin: "installed" | "development";
106
100
  state: "starting" | "running" | "disabled" | "failed" | "stopped";
107
101
  error: string | null;
108
102
  capabilities: string[];
@@ -118,6 +112,13 @@ export interface PackageInfo {
118
112
  slot?: string;
119
113
  owner?: string;
120
114
  }[];
115
+ /** The manifest's display texts in the interface language (player 0.4.3). */
116
+ display?: {
117
+ name: string | null;
118
+ punchline: string | null;
119
+ description: string | null;
120
+ tags: string[];
121
+ };
121
122
  }
122
123
  /** Where an installed package came from (`packages.install` `source`). */
123
124
  export type WireSource = {
@@ -175,6 +176,12 @@ export interface WindowFacts {
175
176
  };
176
177
  /** The palette (`plugin.appearance`), with the `window.state` reply; a newer player may name a palette this SDK does not list. */
177
178
  appearance?: string;
179
+ /** The file resolvers' extensions (`plugin.resolvers.fileTypes`; player 0.4.2). */
180
+ fileTypes?: string[];
181
+ /** The saved interface language, `"system"` or a locale (player 0.4.3). */
182
+ language?: string;
183
+ /** The interface language of this run (player 0.4.3). */
184
+ locale?: string;
178
185
  }
179
186
  /** One timeline mark as the player merges them (`timeline.marks`). */
180
187
  export interface WireMark {
@@ -280,11 +287,20 @@ export interface WireSystemInfo {
280
287
  primary: boolean;
281
288
  }[];
282
289
  }
290
+ /** Template arguments on the wire (`osd.show`, `osd.panel`, `dialogs.confirm`). */
291
+ export type TemplateArgsJson = (string | number)[] | {
292
+ [name: string]: string | number;
293
+ };
283
294
  export interface Transport {
284
295
  request<T>(method: string, params?: Json): Promise<T>;
285
296
  on(event: string, listener: (data: unknown) => void): () => void;
286
297
  /** Replaces the real local services (test host). */
287
298
  local?: LocalServices;
299
+ /**
300
+ * The interface language of this run (`plugin.i18n.locale`): the runner
301
+ * passes the player's `VESTRA_LOCALE`, the test host its `locale`.
302
+ */
303
+ locale?: string;
288
304
  }
289
305
  export declare function createWire(transport: Transport): {
290
306
  processing: {
@@ -310,6 +326,7 @@ export declare function createWire(transport: Transport): {
310
326
  cancelled: boolean;
311
327
  paths: string[];
312
328
  }>;
329
+ /** Message and detail are templates formatted with `args` (player 0.4.3). */
313
330
  confirm: (options: {
314
331
  [key: string]: Json;
315
332
  }) => Promise<{
@@ -355,6 +372,8 @@ export declare function createWire(transport: Transport): {
355
372
  /** The palette (`ui.theme` to change it). */
356
373
  appearance: {
357
374
  set: (theme: string) => Promise<void>;
375
+ /** The interface language for the next start (player 0.4.3). */
376
+ setLanguage: (language: string) => Promise<void>;
358
377
  };
359
378
  /** Settings pages in the player's options window (`ui.settings`). */
360
379
  settings: {
@@ -473,9 +492,10 @@ export declare function createWire(transport: Transport): {
473
492
  } | null) => Promise<void>;
474
493
  step: (direction: "next" | "previous") => Promise<void>;
475
494
  };
495
+ /** `text` is a template in the plugin's catalog, formatted with `args` (player 0.4.3). */
476
496
  osd: {
477
- show: (text: string) => Promise<void>;
478
- panel: (text: string | null) => Promise<void>;
497
+ show: (text: string, args?: TemplateArgsJson) => Promise<void>;
498
+ panel: (text: string | null, args?: TemplateArgsJson) => Promise<void>;
479
499
  };
480
500
  layout: {
481
501
  state: () => Promise<{
@@ -530,11 +550,6 @@ export declare function createWire(transport: Transport): {
530
550
  validate: (directory: string, apiVersion?: string) => Promise<PackageValidation>;
531
551
  /** Player 0.2.0: a `.vxp` file. */
532
552
  validateArchive: (file: string) => Promise<PackageValidation>;
533
- /** `requestId` recovers a lost first reply in this owner session. */
534
- trial: (token: string, requestId: string) => Promise<PackageTrial>;
535
- trialStateByRequest: (requestId: string) => Promise<PackageTrial>;
536
- trialState: (trialId: number) => Promise<PackageTrial>;
537
- stopTrial: (trialId: number) => Promise<PackageTrial>;
538
553
  installed: (id: string) => Promise<InstalledPackage>;
539
554
  /** `source` and `replace` are sent only when given (player 0.2.0). */
540
555
  install: (token: string, expectedRevision: number, requestId: string, options?: {