@scm-js/plugin-api 1.9.0 → 1.11.0

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.
Files changed (2) hide show
  1. package/index.d.ts +74 -6
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -1810,7 +1810,20 @@ export interface Preferences {
1810
1810
  checkOnStart: boolean;
1811
1811
  nightly: boolean;
1812
1812
  };
1813
+ /**
1814
+ * What to do when an installed plugin has a newer release than the one running
1815
+ * (`plugins/updates.ts`). `notify` looks a few seconds after the plugins start and
1816
+ * raises a notice with a button to the rows offering the update; `manual` asks nothing
1817
+ * until **Check for update** is pressed on a row; `auto` installs what it finds, for the
1818
+ * plugins the user added — a default moves with the editor's own releases and is only
1819
+ * ever named in the notice. Every mode leaves the confirmation on a row's button alone.
1820
+ */
1821
+ plugins: {
1822
+ updates: PluginUpdateMode;
1823
+ };
1813
1824
  }
1825
+ /** See `Preferences.plugins.updates`. */
1826
+ export type PluginUpdateMode = "notify" | "manual" | "auto";
1814
1827
  /**
1815
1828
  * The version a host provides; a manifest that asks for a newer one is refused. It stays
1816
1829
  * at 1 while the API is only used by the plugins in the scm-js organisation and grows
@@ -1827,8 +1840,9 @@ export interface Disposable {
1827
1840
  * builders (`document.edit` and `document.update`) are the exception, and deliberately
1828
1841
  * so: their operations apply as they are called and one commit closes the transaction
1829
1842
  * when the builder returns, so an `async` builder would commit the part of its work that
1830
- * ran before the first `await` and leave the rest to land outside the entry, breaking
1831
- * undo without an error. Do the awaiting *before* the call:
1843
+ * ran before the first `await` and leave the rest with nowhere to land: the transaction
1844
+ * is closed once the builder returns, and every call on it throws from then on. Do the
1845
+ * awaiting *before* the call:
1832
1846
  *
1833
1847
  * ```ts
1834
1848
  * await api.tileset.load(); // the async part, first
@@ -1954,6 +1968,8 @@ export interface PluginApi {
1954
1968
  /** Key combinations, tried before the editor's own and never while a text field has focus. */
1955
1969
  readonly hotkeys: HotkeyApi;
1956
1970
  readonly commands: CommandsApi;
1971
+ /** Live objects one plugin holds out for others to use, found by name and watched for arriving. */
1972
+ readonly services: ServicesApi;
1957
1973
  readonly events: EventsApi;
1958
1974
  /**
1959
1975
  * A small key-value store of the plugin's own, kept in the browser's local storage under
@@ -2076,7 +2092,11 @@ export interface DocumentApi {
2076
2092
  * Returns an all-zero result with `changed: false` when no map is open.
2077
2093
  *
2078
2094
  * `build` is synchronous — see `Sync`. Await what you need (graphics, a pick, a
2079
- * fetch) before the call, then write in one go.
2095
+ * fetch) before the call, then write in one go. The transaction is closed when
2096
+ * `build` returns; a call on it after that throws.
2097
+ *
2098
+ * A builder that throws is rolled back: what it had applied is taken off the map
2099
+ * again, nothing reaches the history or the modified flag, and the error reaches you.
2080
2100
  *
2081
2101
  * @example
2082
2102
  * // One undo entry called "Fill", however many operations it takes.
@@ -2093,7 +2113,11 @@ export interface DocumentApi {
2093
2113
  * transaction, the way a settings dialog's OK applies its whole form at once.
2094
2114
  * Operations apply as they are called; the commit marks the map modified and bumps
2095
2115
  * what the chrome reads. There is no undo entry: keep your own if you need one.
2096
- * `build` is synchronous, as `edit`'s is.
2116
+ * `build` is synchronous, as `edit`'s is, and closed when it returns.
2117
+ *
2118
+ * There is nothing to roll an update back with, so a builder that throws leaves what
2119
+ * it wrote: the sections it touched are committed — the map is modified and the
2120
+ * chrome re-reads — and the error reaches you.
2097
2121
  *
2098
2122
  * @example
2099
2123
  * api.document.update("Rename", (tx) => {
@@ -2806,6 +2830,46 @@ export interface CommandsApi {
2806
2830
  /** Every command registered by every plugin. */
2807
2831
  list(): CommandInfo[];
2808
2832
  }
2833
+ export interface ServiceInfo {
2834
+ id: string;
2835
+ pluginId: string;
2836
+ version: number;
2837
+ }
2838
+ export interface ServiceOptions {
2839
+ /** The provider's version of the contract, 1 by default; a consumer that needs a newer one checks `ServiceInfo.version`. */
2840
+ version?: number;
2841
+ }
2842
+ /**
2843
+ * A command is one thing to do; a service is a thing to *hold* — an account another
2844
+ * plugin signs in through, a connection, a catalogue. A plugin provides one live object
2845
+ * under a name and every other plugin reaches it by that name, whatever order they were
2846
+ * activated in: `watch` answers at once with what is there and again whenever the
2847
+ * provider arrives or goes.
2848
+ *
2849
+ * The object's shape is the provider's to publish (a `contract.d.ts` in its repository,
2850
+ * taken as a dev dependency and imported with `import type`, which is erased before the
2851
+ * loader sees it); the editor never reads it. A name without a dot is namespaced under
2852
+ * the plugin (`"account"` → `"scmjs-dev.account"`); one with a dot is taken as it is.
2853
+ *
2854
+ * @example
2855
+ * // The provider:
2856
+ * api.services.provide("account", accountService);
2857
+ * // A consumer:
2858
+ * api.services.watch<AccountService>("scmjs-dev.account", (account) => {
2859
+ * if (account) useSessionFrom(account); else useOwnSignIn();
2860
+ * });
2861
+ */
2862
+ export interface ServicesApi {
2863
+ /** Hold an object out under a name. Providing the same name again replaces it; the Disposable withdraws it. */
2864
+ provide<T extends object>(id: string, service: T, options?: ServiceOptions): Disposable;
2865
+ /** The object under a name, or null when no plugin provides it. */
2866
+ get<T extends object>(id: string): T | null;
2867
+ has(id: string): boolean;
2868
+ /** Called at once with the current object (or null) and again on every change of provider. */
2869
+ watch<T extends object>(id: string, listener: (service: T | null, info: ServiceInfo | null) => void): Disposable;
2870
+ /** Every service provided by every plugin. */
2871
+ list(): ServiceInfo[];
2872
+ }
2809
2873
  /** A picture the editor already has: the canvas it draws from, and its size in pixels. */
2810
2874
  export interface PluginImage {
2811
2875
  image: HTMLCanvasElement;
@@ -4068,9 +4132,11 @@ export interface WidgetsApi {
4068
4132
  export type TopMenu = "File" | "Edit" | "View" | "Layer" | "Scenario" | "Triggers" | "Tools" | "Plugins" | "Help";
4069
4133
  /**
4070
4134
  * A top-level menu, or a submenu by label: `"File/Import"`. A last segment that names no
4071
- * submenu gets one of the plugin's own, at the end of the menu (`"Tools/AI"`).
4135
+ * submenu gets one of the plugin's own, at the end of the menu (`"Tools/AI"`), and a
4136
+ * first segment that names no top-level menu gets one made for the plugin, placed before
4137
+ * Help (`"Account"`).
4072
4138
  */
4073
- export type MenuPath = TopMenu | `${TopMenu}/${string}`;
4139
+ export type MenuPath = TopMenu | `${TopMenu}/${string}` | (string & {});
4074
4140
  export interface MenuItemSpec {
4075
4141
  label: string;
4076
4142
  /** Display only — bind the key with `hotkeys.add`. */
@@ -4174,6 +4240,8 @@ export type PluginEvent =
4174
4240
  | "file"
4175
4241
  /** A plugin registered or removed a command — how a plugin learns that one it calls by id has arrived. */
4176
4242
  | "commands"
4243
+ /** A plugin provided or withdrew a service — `services.watch` is the usual way to hear this for one name. */
4244
+ | "services"
4177
4245
  /** The game data source changed: installed, switched to another data set, or a copy removed. `gameData.source()` says what it is now. */
4178
4246
  | "gameData";
4179
4247
  /** Why the document changed. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-js/plugin-api",
3
- "version": "1.9.0",
3
+ "version": "1.11.0",
4
4
  "description": "Type declarations for the scmJS plugin API",
5
5
  "license": "MIT",
6
6
  "types": "index.d.ts",