deck-plugin-sdk 1.1.0 → 1.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deck-plugin-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Build a plugin for Deck, outside the Deck repository.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/shim/p2p.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ // GENERATED by sdk/gen-shim.mjs — do not edit.
2
+ //
3
+ // Deck's real types, so a plugin is checked against the actual shape.
4
+ export * from "../types/core/p2p";
package/shim/p2p.js ADDED
@@ -0,0 +1,15 @@
1
+ // GENERATED by sdk/gen-shim.mjs — do not edit.
2
+ //
3
+ // Deck's live connections to other Decks. Resolved at USE time like the bridge: a plugin module is evaluated
4
+ // during loadPlugins, and a reference copied out at import time would capture a half-built
5
+ // object. One transport for every plugin, so a fix to it reaches all of them.
6
+ const t = () => {
7
+ const x = window.__deck?.p2p;
8
+ if (!x) throw new Error("window.__deck.p2p is missing — this plugin only runs inside Deck");
9
+ return x;
10
+ };
11
+
12
+ export const cleanCode = (...a) => t().cleanCode(...a);
13
+ export const newCode = (...a) => t().newCode(...a);
14
+ export const selfId = (...a) => t().selfId(...a);
15
+ export const share = (...a) => t().share(...a);
@@ -1,5 +1,5 @@
1
1
  // GENERATED by sdk/gen-shim.mjs — do not edit.
2
2
  //
3
3
  // Deck's real settings types, so a plugin is checked against the actual shape.
4
- export { useSettings, getSettings, saveSettings } from "../types/core/settingsstore";
4
+ export { useSettings, getSettings, saveSettings, userName } from "../types/core/settingsstore";
5
5
  export type { Settings } from "../types/core/bridge";
package/shim/settings.js CHANGED
@@ -11,3 +11,6 @@ const s = () => {
11
11
  export const useSettings = (...a) => s().use(...a);
12
12
  export const getSettings = (...a) => s().get(...a);
13
13
  export const saveSettings = (...a) => s().save(...a);
14
+ // What to call the user (needs a Deck newer than 1.1): the name set in Settings, else their Google or Windows
15
+ // account's. For a plugin that shows the user to someone else.
16
+ export const userName = (...a) => s().userName(...a);
@@ -1,4 +1,4 @@
1
1
  // GENERATED by sdk/gen-shim.mjs — do not edit.
2
2
  //
3
- // Deck's real terminal types, so a plugin is checked against the actual layout shape.
3
+ // Deck's real types, so a plugin is checked against the actual shape.
4
4
  export * from "../types/core/terminals";
@@ -1,8 +1,9 @@
1
- {
2
- "id": "__ID__",
3
- "name": "__NAME__",
4
- "description": "One line on what this is for, shown under its name in Settings.",
5
- "icon": "Sparkles",
6
- "version": "0.1.0",
7
- "minDeck": "0.17.0"
8
- }
1
+ {
2
+ "id": "__ID__",
3
+ "name": "__NAME__",
4
+ "description": "One line on what this is for, shown under its name in Settings.",
5
+ "icon": "Sparkles",
6
+ "color": "#a78bfa",
7
+ "version": "0.1.0",
8
+ "minDeck": "0.17.0"
9
+ }
@@ -28,7 +28,7 @@ export interface MenuItem {
28
28
  checked?: boolean;
29
29
  }
30
30
  export type MenuEntry = MenuItem | "sep";
31
- export declare function ContextMenu({ x, y, items, alignRight, onClose, onReorder, flipAt }: {
31
+ export declare function ContextMenu({ x, y, items, alignRight, onClose, onReorder, flipAt, up }: {
32
32
  x: number;
33
33
  y: number;
34
34
  items: MenuEntry[];
@@ -36,6 +36,8 @@ export declare function ContextMenu({ x, y, items, alignRight, onClose, onReorde
36
36
  onClose: () => void;
37
37
  /** A submenu flips around its parent row's LEFT edge, not the point it opened at. */
38
38
  flipAt?: number;
39
+ /** Open upward from (x, y) when it fits: a menu from a bottom bar, above the bar's buttons. */
40
+ up?: boolean;
39
41
  /** Called with (draggedId, newIndexAmongDraggableRows) after a drag-sort. */
40
42
  onReorder?: (id: string, toIndex: number) => void;
41
43
  }): import("react").ReactPortal;
@@ -27,4 +27,10 @@ export declare function place(x: number, y: number, width: number, height: numbe
27
27
  *
28
28
  * Left out by a menu raised at a cursor, which has no width and so flips around itself.
29
29
  */
30
- flipAt?: number): Placement;
30
+ flipAt?: number,
31
+ /**
32
+ * Open upward from (x, y) whenever it fits there. For a menu raised from a button in a bottom
33
+ * bar: opening downward fits too (the window's edge is further down), and then covers the very
34
+ * buttons the menu is about.
35
+ */
36
+ up?: boolean): Placement;
@@ -76,6 +76,12 @@ export interface Settings {
76
76
  /** Drawer tabs left-to-right. Ids missing from it keep their discovery order, after the rest. */
77
77
  drawerOrder: string[];
78
78
  httpMcpRevealSecrets: boolean;
79
+ /**
80
+ * What to call the user: shown to the others when sharing (a Canvas board's cursor and the
81
+ * host's "wants to join"). "" means work it out: the Google account's name when signed in,
82
+ * else the Windows account's (see `userName` in settingsstore.ts).
83
+ */
84
+ userName: string;
79
85
  }
80
86
  export declare const DEFAULT_SETTINGS: Settings;
81
87
  export declare const setAutostart: (on: boolean) => Promise<void>;
@@ -1,190 +1,193 @@
1
- // GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
2
- import { monaco } from "./monaco";
3
- /** How to launch the server — passed straight to Rust, which implements the strategies. */
4
- interface ServerSpec {
5
- /** "path" | "node-module" | "exe-search" — see resolve_server() in lsp.rs. */
6
- strategy: string;
7
- command?: string;
8
- module?: string;
9
- args?: string[];
10
- /** How to install the server, for the Install button in Settings › Languages. */
11
- install?: Install;
12
- }
13
- /**
14
- * What to install for a server or a debugger, as one of a few kinds Deck turns into a command
15
- * itself (tools.rs): a definition from the registry never names a command to run.
16
- */
17
- export type InstallSpec = {
18
- kind: "pip" | "npm";
19
- packages: string[];
20
- } | {
21
- kind: "github-release";
22
- name: string;
23
- repo: string;
24
- tag: string;
25
- asset: string;
26
- sha256: string;
27
- };
28
- /** A structured install, or a sentence for what Deck cannot install itself (an SDK). */
29
- export type Install = InstallSpec | string;
30
- /** An install as one sentence, for where a button would not fit or there is nothing to run. */
31
- export declare function installText(i: Install): string;
32
- /** Whether Deck can run it (an Install button), rather than only describe it. */
33
- export declare const canInstall: (i: Install | undefined) => i is InstallSpec;
34
- /** A language's server or debugger install entry, if its definition has one. */
35
- export declare function installFor(languageId: string, what: "server" | "debug"): Install | undefined;
36
- /** A language's debug adapter, or null when its definition names none (or there is no such language). */
37
- export declare function debugAdapterFor(languageId: string): {
38
- adapter: ServerSpec;
39
- type: string;
40
- rootMarker: string;
41
- launch?: Record<string, unknown>;
42
- launchUnless?: string;
43
- install?: Install;
44
- } | null;
45
- /**
46
- * Whether a language's debug adapter runs on this machine: starts it and sees whether it is still
47
- * running a moment later. Resolves to what was run, rejects with why not (the adapter's first line
48
- * of output: Python's "No module named debugpy", Node's "Cannot find module"). Null when the
49
- * language names no adapter.
50
- */
51
- export declare function probeDebugger(languageId: string): Promise<string | null>;
52
- /**
53
- * Load every language definition from %APPDATA%\Deck\languages.
54
- *
55
- * This is the ONLY source of languages. Deck used to compile a few in from src/languages/, which
56
- * meant the shipped ones and a user's own obeyed different rules — one needed a rebuild to
57
- * change, the other a restart, and only the first could carry snippets. Now there is one kind of
58
- * language definition, and Deck ships none: an empty folder means Monaco's own highlighting and
59
- * no language server, which is a coherent state rather than a broken one.
60
- *
61
- * Never rejects. A language that fails to load is one language that does not work; it is not a
62
- * reason for the editor not to start, and the same contract loadPlugins states.
63
- */
64
- export declare function loadExternalLanguages(): Promise<void>;
65
- /** One language, as Settings lists it. Flattened from its LangDef — the panel shows what a
66
- * definition claims, not the definition itself. */
67
- export interface LoadedLanguage {
68
- languageId: string;
69
- serverId: string;
70
- extensions: string[];
71
- rootMarker: string;
72
- strategy: string;
73
- /** The command or node module the strategy will look for. */
74
- command: string;
75
- /** The folder it came from, which is the name to look for on disk. */
76
- folder: string;
77
- /** language.json's version, or "" when it has none (a pack from before versions). */
78
- version: string;
79
- snippets?: number;
80
- }
81
- export interface LanguageError {
82
- folder: string;
83
- message: string;
84
- }
85
- /** Every language definition that loaded. */
86
- export declare function loadedLanguages(): readonly LoadedLanguage[];
87
- /**
88
- * Re-read the languages folder whenever it changes on disk. Called once at startup.
89
- *
90
- * What makes installing a language from the registry take effect without a restart, the same way
91
- * the plugin watcher does for a plugin. Debounced: writing a definition and its snippets emits
92
- * several events, and each would otherwise re-read the whole folder.
93
- *
94
- * Only NEW definitions and changed data are picked up. A language whose server is already
95
- * running keeps that session — lsp.rs owns it, and restarting one because a snippet file changed
96
- * would lose whatever it had analysed.
97
- */
98
- export declare function watchLanguages(): void;
99
- /**
100
- * Whether a language's server is actually installed, without opening a file of that type.
101
- *
102
- * Until this existed, a definition naming a server you do not have was only discoverable by
103
- * opening such a file and reading the error — so "Python needs basedpyright installed" was
104
- * something Deck knew and never said.
105
- *
106
- * `root` is optional and usually empty: a node module resolves from the project's node_modules
107
- * first, so a check with no project answers "is it installed globally".
108
- */
109
- export declare function probeLanguage(languageId: string, root?: string): Promise<string>;
110
- /**
111
- * Folders that failed to load, and why.
112
- *
113
- * The point of surfacing these: a definition with a typo is otherwise completely silent — the
114
- * language simply does not work, with nothing on screen to say a file was even read.
115
- */
116
- export declare function languageErrors(): readonly LanguageError[];
117
- export declare function lspSupports(languageId: string): boolean;
118
- export type LspPhase = "starting" | "ready" | "error" | "stopped";
119
- export interface LspStatus {
120
- id: string;
121
- serverId: string;
122
- root: string;
123
- phase: LspPhase;
124
- detail: string;
125
- log: string[];
126
- }
127
- /** React hook: current LSP server statuses (for the editor indicator). */
128
- export declare function useLspStatus(): LspStatus[];
129
- export declare function lspErrorVersion(): number;
130
- /** Live path -> error count. Read after subscribing to changes with subscribeLspErrors. */
131
- export declare function lspErrorCounts(): Map<string, number>;
132
- export declare function subscribeLspErrors(cb: () => void): () => void;
133
- /** Notify the server a document is open. Call when a file tab opens. */
134
- export declare function lspOpenDoc(path: string, content: string, root: string): Promise<void>;
135
- /**
136
- * Notify the server a document changed. Call for EVERY Monaco change, synchronously — no
137
- * debounce.
138
- *
139
- * Under incremental sync each notification describes one edit relative to the server's current
140
- * copy, so dropping or reordering any of them desynchronizes the document permanently. That is
141
- * also why this is no longer debounced: a debounce necessarily drops intermediate states, which
142
- * is only legal when every message carries the whole file. Sending immediately has the better
143
- * property anyway — completion and hover fire on the keystroke, so under the old 300ms debounce
144
- * they queried a server whose buffer was up to 300ms stale and answered for a position that did
145
- * not exist there yet.
146
- *
147
- * `changes` comes straight from Monaco's content-change event. Its ranges are in pre-edit
148
- * coordinates and it orders them end-of-document first, which is exactly what LSP expects for a
149
- * sequentially-applied batch: applying a later-in-document edit never shifts an earlier range.
150
- * Do not sort them.
151
- */
152
- export declare function lspChangeDoc(path: string, content: string, root: string, changes?: readonly monaco.editor.IModelContentChange[]): Promise<void>;
153
- /** Notify the server a document closed. Call when a tab closes. */
154
- export declare function lspCloseDoc(path: string, root: string): Promise<void>;
155
- /** One result of a project-wide symbol search (Ctrl+T). `line` and `col` are 1-based. */
156
- export interface ProjectSymbol {
157
- name: string;
158
- kind: number;
159
- container: string;
160
- path: string;
161
- line: number;
162
- col: number;
163
- }
164
- /**
165
- * Classes, functions and the rest whose name matches `query`, from every language server running
166
- * for `root` (a TypeScript and a Python server can share one), each server's own ranking kept and
167
- * the lists joined. Only servers already running answer: Ctrl+T does not start one. [] for an
168
- * empty query.
169
- */
170
- export declare function workspaceSymbols(root: string, query: string): Promise<ProjectSymbol[]>;
171
- /** A file's outline from its language server, or [] when no server has it open. Also what the
172
- * debugger's inline values use to find the function a frame is in. */
173
- export declare function documentSymbols(model: monaco.editor.ITextModel): Promise<monaco.languages.DocumentSymbol[]>;
174
- type OpenFileHandler = (path: string, line: number, column: number) => void;
175
- export declare function setLspOpenFileHandler(fn: OpenFileHandler): void;
176
- /** Stop the servers no project has touched for IDLE_STOP_MS. Exported for the check. */
177
- export declare function stopIdleServers(now?: number): string[];
178
- /** Stop all sessions (e.g. on workspace close). */
179
- export declare function lspStopAll(): void;
180
- /** Restart one server (UI action from the status popover). */
181
- /**
182
- * Stop a language server. The next file opened for that root starts a fresh one, which is why
183
- * this is both the Restart action and the memory readout's stop button — there is no difference
184
- * between the two beyond what the caller says about it.
185
- *
186
- * Deleting the frontend session alongside the process matters: leaving it would send didOpen to
187
- * a dead pipe on the next open, and the editor would sit at "ready" with no diagnostics.
188
- */
189
- export declare function lspRestart(id: string): Promise<void>;
190
- export {};
1
+ // GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
2
+ import { monaco } from "./monaco";
3
+ /** How to launch the server — passed straight to Rust, which implements the strategies. */
4
+ interface ServerSpec {
5
+ /** "path" | "node-module" | "exe-search" — see resolve_server() in lsp.rs. */
6
+ strategy: string;
7
+ command?: string;
8
+ module?: string;
9
+ args?: string[];
10
+ /** How to install the server, for the Install button in Settings › Languages. */
11
+ install?: Install;
12
+ }
13
+ /**
14
+ * What to install for a server or a debugger, as one of a few kinds Deck turns into a command
15
+ * itself (tools.rs): a definition from the registry never names a command to run.
16
+ */
17
+ export type InstallSpec = {
18
+ kind: "pip" | "npm";
19
+ packages: string[];
20
+ } | {
21
+ kind: "github-release";
22
+ name: string;
23
+ repo: string;
24
+ tag: string;
25
+ asset: string;
26
+ sha256: string;
27
+ };
28
+ /** A structured install, or a sentence for what Deck cannot install itself (an SDK). */
29
+ export type Install = InstallSpec | string;
30
+ /** An install as one sentence, for where a button would not fit or there is nothing to run. */
31
+ export declare function installText(i: Install): string;
32
+ /** Whether Deck can run it (an Install button), rather than only describe it. */
33
+ export declare const canInstall: (i: Install | undefined) => i is InstallSpec;
34
+ /** A language's server or debugger install entry, if its definition has one. */
35
+ export declare function installFor(languageId: string, what: "server" | "debug"): Install | undefined;
36
+ /** A language's debug adapter, or null when its definition names none (or there is no such language). */
37
+ export declare function debugAdapterFor(languageId: string): {
38
+ adapter: ServerSpec;
39
+ type: string;
40
+ rootMarker: string;
41
+ launch?: Record<string, unknown>;
42
+ launchUnless?: string;
43
+ install?: Install;
44
+ } | null;
45
+ /**
46
+ * Whether a language's debug adapter runs on this machine: starts it and sees whether it is still
47
+ * running a moment later. Resolves to what was run, rejects with why not (the adapter's first line
48
+ * of output: Python's "No module named debugpy", Node's "Cannot find module"). Null when the
49
+ * language names no adapter.
50
+ */
51
+ export declare function probeDebugger(languageId: string): Promise<string | null>;
52
+ /**
53
+ * Load every language definition from %APPDATA%\Deck\languages.
54
+ *
55
+ * This is the ONLY source of languages. Deck used to compile a few in from src/languages/, which
56
+ * meant the shipped ones and a user's own obeyed different rules — one needed a rebuild to
57
+ * change, the other a restart, and only the first could carry snippets. Now there is one kind of
58
+ * language definition, and Deck ships none: an empty folder means Monaco's own highlighting and
59
+ * no language server, which is a coherent state rather than a broken one.
60
+ *
61
+ * Never rejects. A language that fails to load is one language that does not work; it is not a
62
+ * reason for the editor not to start, and the same contract loadPlugins states.
63
+ */
64
+ export declare function loadExternalLanguages(): Promise<void>;
65
+ /** One language, as Settings lists it. Flattened from its LangDef — the panel shows what a
66
+ * definition claims, not the definition itself. */
67
+ export interface LoadedLanguage {
68
+ languageId: string;
69
+ serverId: string;
70
+ extensions: string[];
71
+ rootMarker: string;
72
+ strategy: string;
73
+ /** The command or node module the strategy will look for. */
74
+ command: string;
75
+ /** The folder it came from, which is the name to look for on disk. */
76
+ folder: string;
77
+ /** language.json's version, or "" when it has none (a pack from before versions). */
78
+ version: string;
79
+ /** Its lucide icon name and colour from language.json; "" when it names none. */
80
+ icon: string;
81
+ color: string;
82
+ snippets?: number;
83
+ }
84
+ export interface LanguageError {
85
+ folder: string;
86
+ message: string;
87
+ }
88
+ /** Every language definition that loaded. */
89
+ export declare function loadedLanguages(): readonly LoadedLanguage[];
90
+ /**
91
+ * Re-read the languages folder whenever it changes on disk. Called once at startup.
92
+ *
93
+ * What makes installing a language from the registry take effect without a restart, the same way
94
+ * the plugin watcher does for a plugin. Debounced: writing a definition and its snippets emits
95
+ * several events, and each would otherwise re-read the whole folder.
96
+ *
97
+ * Only NEW definitions and changed data are picked up. A language whose server is already
98
+ * running keeps that session — lsp.rs owns it, and restarting one because a snippet file changed
99
+ * would lose whatever it had analysed.
100
+ */
101
+ export declare function watchLanguages(): void;
102
+ /**
103
+ * Whether a language's server is actually installed, without opening a file of that type.
104
+ *
105
+ * Until this existed, a definition naming a server you do not have was only discoverable by
106
+ * opening such a file and reading the error — so "Python needs basedpyright installed" was
107
+ * something Deck knew and never said.
108
+ *
109
+ * `root` is optional and usually empty: a node module resolves from the project's node_modules
110
+ * first, so a check with no project answers "is it installed globally".
111
+ */
112
+ export declare function probeLanguage(languageId: string, root?: string): Promise<string>;
113
+ /**
114
+ * Folders that failed to load, and why.
115
+ *
116
+ * The point of surfacing these: a definition with a typo is otherwise completely silent — the
117
+ * language simply does not work, with nothing on screen to say a file was even read.
118
+ */
119
+ export declare function languageErrors(): readonly LanguageError[];
120
+ export declare function lspSupports(languageId: string): boolean;
121
+ export type LspPhase = "starting" | "ready" | "error" | "stopped";
122
+ export interface LspStatus {
123
+ id: string;
124
+ serverId: string;
125
+ root: string;
126
+ phase: LspPhase;
127
+ detail: string;
128
+ log: string[];
129
+ }
130
+ /** React hook: current LSP server statuses (for the editor indicator). */
131
+ export declare function useLspStatus(): LspStatus[];
132
+ export declare function lspErrorVersion(): number;
133
+ /** Live path -> error count. Read after subscribing to changes with subscribeLspErrors. */
134
+ export declare function lspErrorCounts(): Map<string, number>;
135
+ export declare function subscribeLspErrors(cb: () => void): () => void;
136
+ /** Notify the server a document is open. Call when a file tab opens. */
137
+ export declare function lspOpenDoc(path: string, content: string, root: string): Promise<void>;
138
+ /**
139
+ * Notify the server a document changed. Call for EVERY Monaco change, synchronously — no
140
+ * debounce.
141
+ *
142
+ * Under incremental sync each notification describes one edit relative to the server's current
143
+ * copy, so dropping or reordering any of them desynchronizes the document permanently. That is
144
+ * also why this is no longer debounced: a debounce necessarily drops intermediate states, which
145
+ * is only legal when every message carries the whole file. Sending immediately has the better
146
+ * property anyway — completion and hover fire on the keystroke, so under the old 300ms debounce
147
+ * they queried a server whose buffer was up to 300ms stale and answered for a position that did
148
+ * not exist there yet.
149
+ *
150
+ * `changes` comes straight from Monaco's content-change event. Its ranges are in pre-edit
151
+ * coordinates and it orders them end-of-document first, which is exactly what LSP expects for a
152
+ * sequentially-applied batch: applying a later-in-document edit never shifts an earlier range.
153
+ * Do not sort them.
154
+ */
155
+ export declare function lspChangeDoc(path: string, content: string, root: string, changes?: readonly monaco.editor.IModelContentChange[]): Promise<void>;
156
+ /** Notify the server a document closed. Call when a tab closes. */
157
+ export declare function lspCloseDoc(path: string, root: string): Promise<void>;
158
+ /** One result of a project-wide symbol search (Ctrl+T). `line` and `col` are 1-based. */
159
+ export interface ProjectSymbol {
160
+ name: string;
161
+ kind: number;
162
+ container: string;
163
+ path: string;
164
+ line: number;
165
+ col: number;
166
+ }
167
+ /**
168
+ * Classes, functions and the rest whose name matches `query`, from every language server running
169
+ * for `root` (a TypeScript and a Python server can share one), each server's own ranking kept and
170
+ * the lists joined. Only servers already running answer: Ctrl+T does not start one. [] for an
171
+ * empty query.
172
+ */
173
+ export declare function workspaceSymbols(root: string, query: string): Promise<ProjectSymbol[]>;
174
+ /** A file's outline from its language server, or [] when no server has it open. Also what the
175
+ * debugger's inline values use to find the function a frame is in. */
176
+ export declare function documentSymbols(model: monaco.editor.ITextModel): Promise<monaco.languages.DocumentSymbol[]>;
177
+ type OpenFileHandler = (path: string, line: number, column: number) => void;
178
+ export declare function setLspOpenFileHandler(fn: OpenFileHandler): void;
179
+ /** Stop the servers no project has touched for IDLE_STOP_MS. Exported for the check. */
180
+ export declare function stopIdleServers(now?: number): string[];
181
+ /** Stop all sessions (e.g. on workspace close). */
182
+ export declare function lspStopAll(): void;
183
+ /** Restart one server (UI action from the status popover). */
184
+ /**
185
+ * Stop a language server. The next file opened for that root starts a fresh one, which is why
186
+ * this is both the Restart action and the memory readout's stop button — there is no difference
187
+ * between the two beyond what the caller says about it.
188
+ *
189
+ * Deleting the frontend session alongside the process matters: leaving it would send didOpen to
190
+ * a dead pipe on the next open, and the editor would sit at "ready" with no diagnostics.
191
+ */
192
+ export declare function lspRestart(id: string): Promise<void>;
193
+ export {};
@@ -0,0 +1,117 @@
1
+ // GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
2
+ /** What can travel: anything JSON can carry. */
3
+ export type Json = string | number | boolean | null | Json[] | {
4
+ [k: string]: Json;
5
+ };
6
+ /** Whether someone may change what is shared, or only watch. */
7
+ export type Mode = "edit" | "view";
8
+ /** Who may change things: a default for everyone, and a choice per person that wins over it. */
9
+ export interface Roles {
10
+ def: Mode;
11
+ per: Record<string, Mode>;
12
+ }
13
+ /** Why a share ended for a joiner: the host stopped, vanished, removed this Deck, turned it away,
14
+ * or speaks another version. */
15
+ export type Gone = "ended" | "lost" | "removed" | "denied" | "version";
16
+ export interface Person {
17
+ id: string;
18
+ name: string; /** Round trip in ms, once measured. */
19
+ ms?: number;
20
+ }
21
+ /** What a share's bar and dialogs show. Replaced, never mutated, so React sees a change. */
22
+ export interface ShareView {
23
+ /** Who is in and connected: on the host, everyone let in; on a joiner, the host and the others. */
24
+ peers: Person[];
25
+ /** On the host: who is asking to be let in. */
26
+ knocking: Person[];
27
+ /** On a joiner: the host is there but has not let this Deck in yet. */
28
+ waiting: boolean;
29
+ /** On a joiner: no host heard from for a while (wrong code, or a network that blocks it). */
30
+ stuck: boolean;
31
+ gone: Gone | null;
32
+ hostName: string;
33
+ /** A passing line: someone on another version, or whatever the plugin `say`s. */
34
+ note: string;
35
+ roles: Roles;
36
+ /** Whether this Deck may change things. */
37
+ canEdit: boolean;
38
+ }
39
+ export interface ShareOptions {
40
+ /** What the share is for, e.g. "canvas-share". Decks only meet others using the same one. */
41
+ app: string;
42
+ /** The share code, which names the room (see newCode). */
43
+ code: string;
44
+ /** Optional extra secret, needed with the code to connect at all. Sharing works without one. */
45
+ password?: string;
46
+ /** The plugin's message channel, at most 12 bytes (Trystero's cap). Defaults to "msg". */
47
+ channel?: string;
48
+ /** Whether this Deck is the one sharing. */
49
+ host: boolean;
50
+ /** Shown to the others: in the host's knock, on cursors, in the list of who is here. */
51
+ name: string;
52
+ /** The plugin's own protocol version. Decks on different versions do not share. */
53
+ version: number;
54
+ /** The host's default for who may change things. Joiners may until the host says otherwise. */
55
+ mode?: Mode;
56
+ }
57
+ export interface ShareHandlers<T> {
58
+ /** A plugin message, only ever from someone let in (and the host). Check `mayEdit(peer)` before
59
+ * applying a change: a view-only person's edits are to be dropped by every Deck. */
60
+ message: (msg: T, peer: string) => void;
61
+ /** On the host: someone was just let in. Send them what they need to start, e.g. the board. */
62
+ welcome?: (peer: string) => void;
63
+ /** Someone left or was removed: forget what was kept for them (a cursor). */
64
+ left?: (peer: string) => void;
65
+ }
66
+ export interface P2pShare<T> {
67
+ readonly host: boolean;
68
+ /** Send a plugin message to everyone let in, or to one of them. Sends nothing before this Deck is
69
+ * let in. Settles once handed to the connection, so awaiting it paces the sender. */
70
+ send(msg: T, to?: string): Promise<void>;
71
+ /** Whether a peer may change things: the host always, anyone else by the roles. */
72
+ mayEdit(peer: string): boolean;
73
+ /** The host: let someone in, or turn them away. */
74
+ allow(peer: string): void;
75
+ deny(peer: string): void;
76
+ /** The host: remove someone who was let in. They cannot come back with the same Deck. */
77
+ kick(peer: string): void;
78
+ /** The host: everyone's default, and one person's own choice (`null` follows the default). */
79
+ setDefault(mode: Mode): void;
80
+ setPerson(peer: string, mode: Mode | null): void;
81
+ /** Show a passing line in the view for a few seconds. */
82
+ say(note: string): void;
83
+ /** Leave. With `announce` (the host ending on purpose) everyone is told first, so they end at
84
+ * once rather than when the connection times out. Safe to call twice. */
85
+ close(announce?: boolean): Promise<void>;
86
+ /** For useSyncExternalStore. */
87
+ subscribe(fn: () => void): () => void;
88
+ getView(): ShareView;
89
+ }
90
+ /** The part of a Trystero room a share uses: a seam, so the check can run a share without a network. */
91
+ export interface RoomLike {
92
+ /** This Deck's id in the room; Trystero's own is `selfId()`. */
93
+ selfId?: string;
94
+ makeAction(name: string, config: {
95
+ onMessage: (data: any, ctx: {
96
+ peerId: string;
97
+ }) => void;
98
+ }): {
99
+ send(data: any, options?: {
100
+ target?: string | string[];
101
+ }): Promise<void>;
102
+ };
103
+ ping(peer: string): Promise<number>;
104
+ leave(): Promise<void>;
105
+ getPeers(): Record<string, unknown>;
106
+ onPeerJoin: ((peer: string) => void) | null;
107
+ onPeerLeave: ((peer: string) => void) | null;
108
+ }
109
+ /** This Deck's id in every share: the one the others know it by. The same for the whole session,
110
+ * so someone let in who rejoins after a dropped connection is let straight back in. */
111
+ export declare function selfId(): string;
112
+ /** Start sharing (`host`), or ask to join someone's share. */
113
+ export declare function share<T extends Json>(opts: ShareOptions, on: ShareHandlers<T>, room?: RoomLike): P2pShare<T>;
114
+ /** A share code: 16 random characters in four groups, easy to read out or paste. */
115
+ export declare function newCode(random?: (n: number) => Uint8Array): string;
116
+ /** A pasted code, tidied: spaces dropped, case folded. Empty when it is not a code. */
117
+ export declare function cleanCode(text: string): string;
@@ -13,4 +13,5 @@ export declare function publishSettings(s: Settings): void;
13
13
  export declare function saveSettings(next: Settings): void;
14
14
  /** Current settings for non-React callers (the palette's providers). */
15
15
  export declare const getSettings: () => Settings;
16
+ export declare function userName(): Promise<string>;
16
17
  export declare function useSettings(): Settings;