@vestra-player/sdk 1.5.9 → 1.5.12

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/llms-full.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @vestra-player/sdk 1.5.9: full reference
1
+ # @vestra-player/sdk 1.5.12: full reference
2
2
 
3
3
  > Everything needed to write a Vestra Player plugin (plugin API `vestra/1`): the guides, every public declaration of `@vestra-player/sdk` and `@vestra-player/sdk/testing` with its documentation, and the complete source of the example plugins. Generated from the SDK's sources by scripts/llms.mjs; the short index is llms.txt.
4
4
 
@@ -998,11 +998,11 @@ change).
998
998
  | `timeout` | A time limit ran out (`openStream` start-up, `tools.run`, `system.*` after 10 s). |
999
999
  | `stream`, `device` | `openStream`: the producer failed / the audio device is not ready. |
1000
1000
  | `backend-uncertain` | The player's backend blocked a filter stage; call `retry()`. |
1001
- | `limit` | A player-wide limit was reached (for example the number of commands). |
1001
+ | `limit` | A player-wide limit was reached (for example the number of commands), a property value is over the limits of PropValue, or a request is longer than the player's 1 MiB message. |
1002
1002
  | `reserved` | Packages.validate, 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). |
1003
1003
  | `versionMismatch` | The package needs a newer player (`minPlayerVersion`) or another `apiVersion`. |
1004
1004
  | `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. |
1005
- | `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. |
1005
+ | `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. Also reported to Scope.onError without a request: a callback whose arguments the player could not convert, a property it could not show again when it rebuilt a view (an image file removed since). |
1006
1006
  | `host` | Any other failure inside the player; `message` is the player's reason. |
1007
1007
  | `disabled` | The plugin is being stopped; pending requests fail with it. |
1008
1008
  | `unknown`, `rejected`, `expired` | After a transport problem the SDK could not confirm the outcome (does not happen in normal operation). |
@@ -1201,8 +1201,8 @@ interface CommandState {
1201
1201
  checked: boolean | null;
1202
1202
  /** Shown as busy; like `enabled: false`, the player does not call `run`. Default false. */
1203
1203
  busy: boolean;
1204
- /** Shown when the command is disabled or busy. */
1205
- reason: string | null;
1204
+ /** Shown when the command is disabled or busy: English source text the player translates, or a Text (SDK 1.5.11). */
1205
+ reason: TextValue | null;
1206
1206
  }
1207
1207
  ```
1208
1208
 
@@ -1279,10 +1279,15 @@ interface CommandOptions {
1279
1279
  * titled their menus in Chinese (视频…): there `["Video", "Blur"]` is a
1280
1280
  * menu of its own, so plugins for those players write `@video`; player
1281
1281
  * 0.4.3 still accepts the old Chinese titles of its own menus.
1282
+ *
1283
+ * A segment that mixes words with data (a track number, a count) is a
1284
+ * Text (SDK 1.5.11, player 0.4.3): `plugin.i18n.text("Track {}
1285
+ * ({})", [n, codec])`. The menu shows it translated and filled in; it
1286
+ * merges by its English rendering ("Track 2 (opus)").
1282
1287
  */
1283
- path?: string[];
1284
- /** Menu label (English source text, shown translated); defaults to the last path segment. */
1285
- title?: string;
1288
+ path?: (string | Text)[];
1289
+ /** Menu label (English source text, shown translated, or a Text); defaults to the last path segment. */
1290
+ title?: string | Text;
1286
1291
  /**
1287
1292
  * Sibling order in the menu, ascending (integer, default 0). A submenu sits where its first command sits, except a built-in menu, which keeps its fixed place. Directly inside a built-in menu, 0 (the default) sorts last. Equal orders: plugin id, then declaration order. Range ±1,000,000. See CommandOptions for the menu order rules.
1288
1293
  */
@@ -1324,8 +1329,8 @@ interface CommandOptions {
1324
1329
  checked?: Bindable<boolean | null>;
1325
1330
  /** Busy state (default false); the player does not call `run` while busy. */
1326
1331
  busy?: Bindable<boolean>;
1327
- /** Why the command is disabled or busy (shown to the user). */
1328
- reason?: Bindable<string | null>;
1332
+ /** Why the command is disabled or busy (shown to the user): English source text, or a Text for one with data in it (SDK 1.5.11). */
1333
+ reason?: Bindable<TextValue | null>;
1329
1334
  /**
1330
1335
  * Run the command (menu item, binding, panel menu or `host.command(id).run()` in tests). It may return a promise; errors and rejections go to Scope.onError, and bound values are re-evaluated when it returns and when its promise settles.
1331
1336
  */
@@ -1432,7 +1437,7 @@ JSON whose values may also be Markdown documents, at any depth: the part
1432
1437
  of PropValue that nests.
1433
1438
 
1434
1439
  ```ts
1435
- type PropData = null | boolean | number | string | MarkdownRef | PropData[] | {
1440
+ type PropData = null | boolean | number | string | MarkdownRef | Text | TextList | PropData[] | {
1436
1441
  [key: string]: PropData;
1437
1442
  };
1438
1443
  ```
@@ -1948,12 +1953,82 @@ type LanguagePreference = "system" | Locale;
1948
1953
  ### TemplateArgs
1949
1954
 
1950
1955
  Arguments of a template sentence (Osd.show,
1951
- OsdPanel.set, ConfirmOptions.args): an array for `{}` and
1952
- `{0}`, `{1}` placeholders, or an object for `{name}` placeholders. At most
1953
- 16 strings and finite numbers; whole numbers print without a fraction.
1956
+ OsdPanel.set, ConfirmOptions.args, I18n.text): an
1957
+ array for `{}` and `{0}`, `{1}` placeholders, or an object for `{name}`
1958
+ placeholders. At most 16. Strings and finite numbers are data, shown as
1959
+ they are (whole numbers without a fraction); a Text or
1960
+ TextList argument (SDK 1.5.11, player 0.4.3) is translated too,
1961
+ so a sentence can be built from translated parts.
1954
1962
 
1955
1963
  ```ts
1956
- type TemplateArgs = readonly (string | number)[] | Readonly<Record<string, string | number>>;
1964
+ type TemplateArgs = readonly TextArg[] | Readonly<Record<string, TextArg>>;
1965
+ ```
1966
+
1967
+ ### Text
1968
+
1969
+ A text the player translates with the plugin's catalog and fills in:
1970
+ English source text with its arguments. Made by I18n.text; plain
1971
+ data, not a translation (the plugin never sees the translated string).
1972
+
1973
+ ```ts
1974
+ interface Text {
1975
+ /** The English source text: a template with `{}`, `{0}` or `{name}`. */
1976
+ readonly $vestraText: string;
1977
+ /** Values for its placeholders. */
1978
+ readonly args?: TemplateArgs;
1979
+ }
1980
+ ```
1981
+
1982
+ ### TextList
1983
+
1984
+ Values joined the way the interface language joins them ("a, b" in
1985
+ English, "a、b" in Chinese). Made by I18n.list; accepted where a
1986
+ Text is.
1987
+
1988
+ ```ts
1989
+ interface TextList {
1990
+ /** The items: data, or texts the player translates. */
1991
+ readonly $vestraList: readonly TextArg[];
1992
+ /** How they are joined; `"list"` by default. */
1993
+ readonly style?: ListStyle;
1994
+ }
1995
+ ```
1996
+
1997
+ ### ListStyle
1998
+
1999
+ How a TextList is joined, per interface language:
2000
+
2001
+ | style | English | 简体中文 | 日本語 |
2002
+ | --- | --- | --- | --- |
2003
+ | `list` (enumeration) | `, ` | `、` | `、` |
2004
+ | `clauses` (parts of one sentence) | `, ` | `,` | `、` |
2005
+ | `semicolons` | `; ` | `;` | `;` |
2006
+ | `sentences` (no final full stop) | `. ` | `。` | `。` |
2007
+ | `lines` | line break | line break | line break |
2008
+
2009
+ Korean, German and Spanish join as English; French puts a narrow space
2010
+ before `;`.
2011
+
2012
+ ```ts
2013
+ type ListStyle = "list" | "clauses" | "semicolons" | "sentences" | "lines";
2014
+ ```
2015
+
2016
+ ### TextArg
2017
+
2018
+ An argument of a template: data (a string or a finite number, shown as it
2019
+ is) or a Text or TextList (translated).
2020
+
2021
+ ```ts
2022
+ type TextArg = string | number | Text | TextList;
2023
+ ```
2024
+
2025
+ ### TextValue
2026
+
2027
+ A text the player shows: English source text (translated as a whole), a
2028
+ Text or a TextList.
2029
+
2030
+ ```ts
2031
+ type TextValue = string | Text | TextList;
1957
2032
  ```
1958
2033
 
1959
2034
  ### I18n
@@ -1968,6 +2043,68 @@ interface I18n {
1968
2043
  * The interface language of this run, chosen at start-up from the saved Appearance.language or the system's languages; English when neither names a Locale. Players before 0.4.3 report `"en"`.
1969
2044
  */
1970
2045
  readonly locale: Locale;
2046
+ /**
2047
+ * A text that mixes words with data, for the player to translate: the
2048
+ * English source text (a template) and its arguments. It returns a plain
2049
+ * Text value, not a translation; pass it where the player shows
2050
+ * text (see Text) and the player shows it translated with this
2051
+ * plugin's catalog. `vestra-plugin i18n extract` collects `source` from
2052
+ * every call, so write it as a literal (or a conditional of literals, or
2053
+ * an `as const` table entry).
2054
+ *
2055
+ * Arguments are data unless they are texts themselves, so a sentence can
2056
+ * be built from translated parts without composing it in TypeScript.
2057
+ * `text` does not use `this`: `const { text, list } = plugin.i18n` works.
2058
+ * @param source - English source text; `{}`, `{0}` or `{name}` for the arguments, `{{` and `}}` for braces.
2059
+ * @param args - Values for its placeholders.
2060
+ * @throws invalid A malformed or over-limit value (`TEXT_LIMITS`).
2061
+ * @capability None.
2062
+ */
2063
+ text(source: string, args?: TemplateArgs): Text;
2064
+ /**
2065
+ * Items joined the way the interface language joins them (see ListStyle): `list(["a.glsl", "b.glsl"])` shows "a.glsl, b.glsl" in English and "a.glsl、b.glsl" in Chinese. Items are data, or texts the player translates. Accepted where a Text is.
2066
+ * @param items - At most 256.
2067
+ * @param style - `"list"` by default.
2068
+ * @throws invalid A malformed or over-limit value.
2069
+ * @capability None.
2070
+ */
2071
+ list(items: readonly TextArg[], style?: ListStyle): TextList;
2072
+ /**
2073
+ * An `Error` whose words the player shows translated: throw it where the player shows a plugin's failure to the user, such as from a file or web resolver's `resolve` (FileResolverOptions, WebResolverOptions) (also when a stream fails while it starts). The player shows `text` translated with this plugin's catalog (as `player.state.error` and the failure message); `message` is the English rendering, for logs and older players. Elsewhere it is an ordinary `Error`.
2074
+ * @param source - English source text, as I18n.text's.
2075
+ * @param args - Values for its placeholders.
2076
+ * @throws invalid A malformed or over-limit value.
2077
+ * @capability None.
2078
+ */
2079
+ error(source: string, args?: TemplateArgs): TextError;
2080
+ /**
2081
+ * The string a text shows in this run's language, for text that leaves
2082
+ * the player: what the plugin copies to the clipboard or writes to a file
2083
+ * ("Copy info", "Save as…"). Translated with this plugin's catalog (a
2084
+ * string as a whole, a Text or TextList with its
2085
+ * arguments), the way the player would show it.
2086
+ *
2087
+ * Only for text leaving the player. Never use it for the interface (a
2088
+ * window, the menu, the OSD, a dialog): pass the value itself there, so
2089
+ * the player translates it and `vestra-plugin i18n check` can see the
2090
+ * sentence is whole.
2091
+ * @param value - Source text, or a text value.
2092
+ * @returns The translated string.
2093
+ * @throws invalid A malformed value.
2094
+ * @capability None.
2095
+ */
2096
+ resolve(value: TextValue): string;
2097
+ }
2098
+ ```
2099
+
2100
+ ### TextError
2101
+
2102
+ An `Error` the player shows translated (I18n.error).
2103
+
2104
+ ```ts
2105
+ interface TextError extends Error {
2106
+ /** What the player shows. */
2107
+ readonly text: Text;
1971
2108
  }
1972
2109
  ```
1973
2110
 
@@ -2135,12 +2272,12 @@ This plugin's own marks; disposing it removes them.
2135
2272
  ```ts
2136
2273
  interface TimelineLayer extends Disposable {
2137
2274
  /**
2138
- * Replace the layer (last write wins; `[]` clears it). At most 1000 marks, titles ≤ 100 characters, times within the media. Failures go to `onError`; with `ifCurrent`, a write for another source is dropped silently.
2275
+ * Replace the layer (last write wins; `[]` clears it). At most 1000 marks, titles ≤ 100 characters, times within the media. Failures go to `onError`; with `ifCurrent`, a write for another source is dropped silently. A title is data (a chapter's or bookmark's own name), or a Text the player translates (`text("Chapter {}", [n])`, SDK 1.5.11); other plugins read the shown string.
2139
2276
  */
2140
2277
  set(marks: {
2141
2278
  time: number;
2142
2279
  kind: MarkKind;
2143
- title?: string;
2280
+ title?: string | Text;
2144
2281
  }[], options?: {
2145
2282
  ifCurrent?: PlayerState;
2146
2283
  }): void;
@@ -2335,19 +2472,19 @@ Chinese character is one character).
2335
2472
  ```ts
2336
2473
  interface ConfirmOptions {
2337
2474
  /** The question, shown in bold; 1–200 characters. */
2338
- message: string;
2475
+ message: TextValue;
2339
2476
  /** More text under the message; at most 2000 characters. */
2340
- detail?: string;
2477
+ detail?: TextValue;
2341
2478
  /** The confirm button's text (the default button: Enter picks it); 1–40 characters. */
2342
- confirm: string;
2479
+ confirm: TextValue;
2343
2480
  /** The cancel button's text (Escape picks it); 1–40 characters. */
2344
- cancel?: string;
2481
+ cancel?: TextValue;
2345
2482
  /** Mark the confirm button as destructive: red text on macOS, a warning icon on Windows. */
2346
2483
  destructive?: boolean;
2347
2484
  /** A checkbox under the text, such as "Don't ask again"; 1–40 characters. */
2348
- checkbox?: string;
2485
+ checkbox?: TextValue;
2349
2486
  /**
2350
- * Values for the placeholders of `message` and `detail` (player 0.4.3). Every text of the dialog is English source text that the player shows translated from the plugin's catalog; `message` and `detail` are templates like Osd.show's. The length limits apply to the shown text.
2487
+ * Values for the placeholders of `message` and `detail` (player 0.4.3). Any of the texts may instead be a Text (SDK 1.5.11), which carries its own arguments; `args` only fills the string ones. Every text of the dialog is English source text that the player shows translated from the plugin's catalog; `message` and `detail` are templates like Osd.show's. The length limits apply to the shown text.
2351
2488
  */
2352
2489
  args?: TemplateArgs;
2353
2490
  }
@@ -2390,8 +2527,8 @@ interface Dialogs {
2390
2527
  * @throws capability (rejects) The manifest does not declare `ui.dialog`.
2391
2528
  */
2392
2529
  openFile(options?: {
2393
- /** The dialog's title, at most 256 bytes. */
2394
- title?: string;
2530
+ /** The dialog's title (English source text or a Text), at most 256 bytes. */
2531
+ title?: TextValue;
2395
2532
  }): Promise<string | null>;
2396
2533
  /**
2397
2534
  * Ask the user for one or more files to open.
@@ -2404,8 +2541,8 @@ interface Dialogs {
2404
2541
  * @throws capability (rejects) The manifest does not declare `ui.dialog`.
2405
2542
  */
2406
2543
  openFiles(options?: {
2407
- /** The dialog's title, at most 256 bytes. */
2408
- title?: string;
2544
+ /** The dialog's title (English source text or a Text), at most 256 bytes. */
2545
+ title?: TextValue;
2409
2546
  }): Promise<string[]>;
2410
2547
  /**
2411
2548
  * Ask the user for a folder.
@@ -2418,8 +2555,8 @@ interface Dialogs {
2418
2555
  * @throws capability (rejects) The manifest does not declare `ui.dialog`.
2419
2556
  */
2420
2557
  openDirectory(options?: {
2421
- /** The dialog's title, at most 256 bytes. */
2422
- title?: string;
2558
+ /** The dialog's title (English source text or a Text), at most 256 bytes. */
2559
+ title?: TextValue;
2423
2560
  }): Promise<string | null>;
2424
2561
  /**
2425
2562
  * Ask the user where to save a file.
@@ -2432,10 +2569,12 @@ interface Dialogs {
2432
2569
  * @throws capability (rejects) The manifest does not declare `ui.dialog`.
2433
2570
  */
2434
2571
  saveFile(options?: {
2435
- /** The dialog's title, at most 256 bytes. */
2436
- title?: string;
2437
- /** The proposed file name: a plain name, at most 256 bytes. */
2438
- fileName?: string;
2572
+ /** The dialog's title (English source text or a Text), at most 256 bytes. */
2573
+ title?: TextValue;
2574
+ /**
2575
+ * The proposed file name: a plain name, at most 256 bytes. A string is data (not translated); a Text (SDK 1.5.11) is shown translated, `text("Playlist.m3u8")` (a `/` or `\\` in a translation becomes `-`).
2576
+ */
2577
+ fileName?: TextValue;
2439
2578
  }): Promise<string | null>;
2440
2579
  }
2441
2580
  ```
@@ -2973,9 +3112,23 @@ interface OsdPanel extends Disposable {
2973
3112
  * Show the block with this text, change it, or hide it.
2974
3113
  * @capability ui.osd
2975
3114
  * @param text - The text, with `\n` between lines: at most 32 lines and 4096 bytes once translated and formatted. `null` hides the block. A template, like Osd.show's.
2976
- * @param args - Values for its placeholders (player 0.4.3).
3115
+ * @param args - Values for its placeholders (player 0.4.3); `null` or omitted for none.
3116
+ * @param options - `maxColumns`: cut long lines (SDK 1.5.11).
2977
3117
  */
2978
- set(text: string | null, args?: TemplateArgs): void;
3118
+ set(text: TextValue | null, args?: TemplateArgs | null, options?: OsdPanelOptions): void;
3119
+ }
3120
+ ```
3121
+
3122
+ ### OsdPanelOptions
3123
+
3124
+ Options of OsdPanel.set.
3125
+
3126
+ ```ts
3127
+ interface OsdPanelOptions {
3128
+ /**
3129
+ * Cut every line longer than this many columns, after translation and formatting, ending it with `…`: a wide character (Chinese, Japanese, Korean, full-width forms) is two columns, a combining mark none, any other one. An integer from 8 to 1000 (player 0.4.3; older players show whole lines). Measure the video area to choose it.
3130
+ */
3131
+ maxColumns?: number;
2979
3132
  }
2980
3133
  ```
2981
3134
 
@@ -2998,7 +3151,7 @@ interface Osd {
2998
3151
  * @throws unavailable (rejects) The player runs without a user interface.
2999
3152
  * @throws capability (rejects) The manifest does not declare `ui.osd`.
3000
3153
  */
3001
- show(text: string, args?: TemplateArgs): Promise<void>;
3154
+ show(text: TextValue, args?: TemplateArgs): Promise<void>;
3002
3155
  /**
3003
3156
  * Create this plugin's information block.
3004
3157
  * @capability ui.osd
@@ -3268,7 +3421,9 @@ interface Subtitles {
3268
3421
  /**
3269
3422
  * Upload a subtitle file's bytes (UTF-8 SRT, or ASS/SSA with
3270
3423
  * `format: "ass"`) for the current source; select it unless
3271
- * `select: "none"`. `title` (1–200 characters) names the track. Aborting
3424
+ * `select: "none"`. `title` (1–200 characters) names the track: data, or
3425
+ * a Text the player translates (`text("{} · {}", [text("Simplified
3426
+ * Chinese"), file])`, SDK 1.5.11). Aborting
3272
3427
  * `signal` before the commit discards the upload (rejects with AbortError);
3273
3428
  * once the commit was sent it completes.
3274
3429
  *
@@ -3278,7 +3433,7 @@ interface Subtitles {
3278
3433
  */
3279
3434
  load(bytes: Uint8Array, options?: SubtitleConditional & {
3280
3435
  format?: "srt" | "ass";
3281
- title?: string;
3436
+ title?: string | Text;
3282
3437
  select?: "primary" | "secondary" | "none";
3283
3438
  signal?: AbortSignal;
3284
3439
  }): Promise<SubtitleTrack>;
@@ -3810,8 +3965,12 @@ One command's bindings, from Bindings.list.
3810
3965
  interface BindingInfo extends BindingRef {
3811
3966
  /** Menu title. */
3812
3967
  title: string;
3813
- /** Menu path; `null` for a command outside the menu. */
3968
+ /** Menu path as shown; `null` for a command outside the menu. */
3814
3969
  path: string[] | null;
3970
+ /**
3971
+ * The menu path's keys: the English text menus merge by, the same in every interface language (`["Playback", "Seek", "Back 5 s"]`; a built-in menu by its key, `"Video"`, also when declared as `@video`). `null` for a command outside the menu, and from players before 0.4.3. Find a command by where it is in the menu with this, not with `path`. Always set by `list()`; optional so that test fakes written for older SDKs still type-check.
3972
+ */
3973
+ key?: string[] | null;
3815
3974
  /** Global, or only while the plugin's panel has focus. */
3816
3975
  scope: "global" | "panel";
3817
3976
  /** The command's own bindings. */
@@ -4287,8 +4446,9 @@ and its semantics are simplified:
4287
4446
  value ranges (an out-of-range `filter.set` ends in `failed` with
4288
4447
  `invalid`), an empty chain removes the plugin's chain, a chain on a
4289
4448
  generated stream fails `unsupported` (the player's own conformance
4290
- cases check all three), and the command limits (COMMAND_LIMITS)
4291
- and menu ids (MENU_IDS) are enforced.
4449
+ cases check all three), and the command limits (COMMAND_LIMITS),
4450
+ property value limits (UI_VALUE_LIMITS) and menu ids
4451
+ (MENU_IDS) are enforced.
4292
4452
 
4293
4453
  Typical workflow: start the plugin with startPlugin (it reads the
4294
4454
  plugin's `manifest.json`), drive it the way the user or another plugin
@@ -4329,6 +4489,21 @@ interface FakeWindow {
4329
4489
  }
4330
4490
  ```
4331
4491
 
4492
+ ### FileDialogText
4493
+
4494
+ A file dialog as the player shows it (TestHost.fileDialogs).
4495
+
4496
+ ```ts
4497
+ interface FileDialogText {
4498
+ /** Which dialog. */
4499
+ kind: "openFile" | "openFiles" | "openDirectory" | "saveFile";
4500
+ /** Its title as shown, if the plugin gave one. */
4501
+ title?: string;
4502
+ /** The proposed file name as shown, if the plugin gave one. */
4503
+ fileName?: string;
4504
+ }
4505
+ ```
4506
+
4332
4507
  ### FakeCommand
4333
4508
 
4334
4509
  A command the plugin registered with `plugin.commands.add`, as the test
@@ -4347,6 +4522,10 @@ interface FakeCommand {
4347
4522
  title: string;
4348
4523
  /** Each segment of the path as shown; empty without a path. */
4349
4524
  path: string[];
4525
+ /**
4526
+ * The disabled or busy reason as shown, `null` without one (a plugin command's; not enumerable, so comparing `display` with `{ title, path }` still works).
4527
+ */
4528
+ reason?: string | null;
4350
4529
  };
4351
4530
  /** The command state the player last received (after the update pass). */
4352
4531
  state: {
@@ -4356,8 +4535,8 @@ interface FakeCommand {
4356
4535
  checked: boolean | null;
4357
4536
  /** `true` while the plugin reports the command as busy. */
4358
4537
  busy: boolean;
4359
- /** The reason shown when the command is disabled or busy. */
4360
- reason: string | null;
4538
+ /** The reason the plugin sent (source text or a text value; see `display.reason`). */
4539
+ reason: TextValue | null;
4361
4540
  };
4362
4541
  /** The state revision the player holds; increases with every state update the SDK sends. */
4363
4542
  revision: number;
@@ -4518,7 +4697,7 @@ class TestHost implements Transport {
4518
4697
  * @param args - Values for its placeholders.
4519
4698
  * @returns The shown text.
4520
4699
  */
4521
- translate(text: string, args?: TemplateArgs): string;
4700
+ translate(text: TextValue, args?: TemplateArgs): string;
4522
4701
  /** The saved interface language (`plugin.appearance.language`), changed by `appearance.setLanguage` or TestHost.setLanguage. */
4523
4702
  language: LanguagePreference;
4524
4703
  /**
@@ -4541,6 +4720,10 @@ class TestHost implements Transport {
4541
4720
  /** The checkbox, if any. */
4542
4721
  checkbox?: string;
4543
4722
  }[];
4723
+ /**
4724
+ * Every file dialog (`openFile`, `openFiles`, `openDirectory`, `saveFile`) as the player shows it: the title translated, a text file name translated, newest last. The options the plugin sent are in `host.sent("dialogs.open")`.
4725
+ */
4726
+ readonly fileDialogs: FileDialogText[];
4544
4727
  /** The sequence provider's flags, `null` without a provider. */
4545
4728
  sequence: {
4546
4729
  /** The provider's `canNext`, as last evaluated. */
@@ -5047,11 +5230,12 @@ class TestHost implements Transport {
5047
5230
  */
5048
5231
  failStream(producerId: number, message: string): void;
5049
5232
  /**
5050
- * Press a binding like the host's table would: panel-focus bindings first when `panel` is true, then global ones; the earliest registration wins a conflict. Resolves after the command ran; rejects when nothing is bound or the command is disabled or busy. Bindings use the reference syntax (`"Space"`, `"Ctrl+O"`, `"Mouse:WheelUp"`); the player's core actions match first, and user overrides in `bindings.overlay` apply.
5233
+ * Press a binding like the host's table would: panel-focus bindings first when `panel` is true, then global ones; within a scope the earliest registration first (the player's own commands before the plugin's), as the conflict rule orders them. A disabled command lets the key pass to the next command bound to it (SDK 1.5.12, as player 0.4.3): the one it shadowed, then the global scope. The first enabled one runs; `press` resolves after it ran (`"ran"`), or rejects when it is busy. When only disabled commands hold the key, the first one with a `reason` shows the reason on the OSD and eats the key (`"reason"`, see `host.osd`); without a reason the key goes on to the focused control (`"passed"`, nothing runs). Rejects when nothing is bound. Bindings use the reference syntax (`"Space"`, `"Ctrl+O"`, `"Mouse:WheelUp"`), and user overrides in `bindings.overlay` apply.
5234
+ * @returns What the key did: `"ran"`, `"reason"` or `"passed"`.
5051
5235
  */
5052
5236
  press(binding: string, options?: {
5053
5237
  panel?: boolean;
5054
- }): Promise<void>;
5238
+ }): Promise<"ran" | "reason" | "passed">;
5055
5239
  /** Bindings declared by more than one command, each as `[binding, winner, ...ignored]` (command ids; core actions as `host/<id>`). Empty when there are none. */
5056
5240
  get conflicts(): string[][];
5057
5241
  /** The binding overlay `plugin.bindings.set` writes (`"<plugin>/<command>"` to inputs; preset it to simulate saved overrides). `press` honours it. */
@@ -5257,6 +5441,70 @@ they agree).
5257
5441
  const LOCALES: readonly ["en", "zh-Hans", "ja", "ko", "de", "fr", "es"];
5258
5442
  ```
5259
5443
 
5444
+ ### LIST_SEPARATORS
5445
+
5446
+ The separator of each list style per interface language, as the player's
5447
+ table (`i18n::text::SEPARATORS`; its tests check that they agree).
5448
+
5449
+ ```ts
5450
+ const LIST_SEPARATORS: Readonly<Record<Locale, Readonly<Record<ListStyle, string>>>>;
5451
+ ```
5452
+
5453
+ ### TEXT_LIMITS
5454
+
5455
+ The player's limits on one text value (a
5456
+ Text or
5457
+ TextList with everything nested in it), as the player's
5458
+ `i18n::text` (its tests check that they agree).
5459
+
5460
+ ```ts
5461
+ const TEXT_LIMITS: {
5462
+ /** Nesting depth of texts and lists; the value itself is depth 0 (8). */
5463
+ readonly depth: 8;
5464
+ /** Texts, lists and arguments in all, the value itself included (1024). */
5465
+ readonly nodes: 1024;
5466
+ /** Arguments of one text (16). */
5467
+ readonly args: 16;
5468
+ /** Items of one list (256). */
5469
+ readonly items: 256;
5470
+ /** UTF-8 bytes of a source text or a string argument (4096). */
5471
+ readonly stringBytes: 4096;
5472
+ };
5473
+ ```
5474
+
5475
+ ### UI_VALUE_LIMITS
5476
+
5477
+ The player's limits on one property value (a `PropValue` as written
5478
+ by `View.set` or `View.bind`, or an initial property of a
5479
+ window, panel or settings page). The player's tests check that these
5480
+ agree with the player; TestHost enforces them the same way.
5481
+
5482
+ A value over a limit is refused whole with code `limit` (the property
5483
+ keeps what it showed) and reported to `Scope.onError`: a write by
5484
+ `View.set` or `View.bind` as described there. As an initial property it
5485
+ makes `Window.show` reject; a panel or settings page opens without it and
5486
+ the failure goes to the plugin's `onError`.
5487
+
5488
+ They bound the work one write costs the player's interface thread; they
5489
+ are not meant as list sizes to aim for. A list that can grow without
5490
+ bound (a playlist, a history) should send the rows near the view and say
5491
+ how many there are, not the whole list.
5492
+
5493
+ ```ts
5494
+ const UI_VALUE_LIMITS: {
5495
+ /** Nesting depth; the value itself is depth 0 (8). */
5496
+ readonly depth: 8;
5497
+ /** Values in all, counting every array, object, string, number, boolean and null, the value itself included; a Markdown document is one (16384). */
5498
+ readonly values: 16384;
5499
+ /** Rows of one array (4096). */
5500
+ readonly arrayRows: 4096;
5501
+ /** UTF-8 bytes of one string or object field name (64 KiB). */
5502
+ readonly stringBytes: number;
5503
+ /** UTF-8 bytes of all strings and field names together, the text of the value's Markdown documents included (1 MiB). */
5504
+ readonly textBytes: number;
5505
+ };
5506
+ ```
5507
+
5260
5508
  ### HostError
5261
5509
 
5262
5510
  A definite refusal from the player (or the plugin runner), with a stable
@@ -5653,9 +5901,10 @@ interface WireSystemInfo {
5653
5901
 
5654
5902
  ```ts
5655
5903
  type CommandDeclaration = {
5656
- title: string;
5657
- /** Complete primary menu path INCLUDING its leaf; empty = not in the main menu. */
5658
- path: string[];
5904
+ /** Source text, or a text value (player 0.4.3). */
5905
+ title: string | TextJson;
5906
+ /** Complete primary menu path INCLUDING its leaf; empty = not in the main menu. Segments may be text values (player 0.4.3). */
5907
+ path: (string | TextJson)[];
5659
5908
  /** Sibling order, ascending; a submenu takes its first command's order (a built-in menu keeps a fixed one). */
5660
5909
  order: number;
5661
5910
  /** Separator label: adjacent siblings of different groups get a line. */