deck-plugin-sdk 1.14.0 → 1.15.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/bin/deck-plugin.mjs +16 -3
- package/package.json +1 -1
- package/permissions.json +4 -0
- package/publish.mjs +2 -1
- package/shim/bridge.js +4 -0
- package/template/plugin.json +1 -1
- package/types/core/app/platform.d.ts +14 -0
- package/types/core/bridge.d.ts +5 -0
- package/types/core/browser/bookmarksources.d.ts +9 -0
- package/types/core/browser/browser.d.ts +2 -8
- package/types/core/keys/keys.d.ts +0 -6
- package/types/core/workspaces/windows.d.ts +1 -1
- package/validate.mjs +19 -0
package/bin/deck-plugin.mjs
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// Run from a plugin's own directory.
|
|
14
14
|
import { watch } from "node:fs";
|
|
15
15
|
import { cpSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
16
|
+
import { homedir } from "node:os";
|
|
16
17
|
import { join } from "node:path";
|
|
17
18
|
import { buildPlugin } from "../build-plugin.mjs";
|
|
18
19
|
import { publish } from "../publish.mjs";
|
|
@@ -70,15 +71,27 @@ function check() {
|
|
|
70
71
|
* writes to your real Deck ("main"), for when the plugin is done.
|
|
71
72
|
*/
|
|
72
73
|
function pluginsDir(defaultTarget) {
|
|
73
|
-
const appData = process.env.APPDATA;
|
|
74
|
-
if (!appData) die("APPDATA is not set — this command is for Windows, where Deck runs");
|
|
75
74
|
const target = targetFlag ?? defaultTarget;
|
|
76
75
|
if (target !== "test" && target !== "main") die(`--target is "test" or "main", not "${target}"`);
|
|
77
|
-
return { target, dir: join(
|
|
76
|
+
return { target, dir: join(configRoot(), target === "test" ? "Deck-Dev" : "Deck", "plugins") };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Where Deck keeps its folder, as its Rust side finds it: %APPDATA% on Windows, $XDG_CONFIG_HOME
|
|
80
|
+
* or ~/.config on Linux, ~/Library/Application Support on macOS. */
|
|
81
|
+
function configRoot() {
|
|
82
|
+
if (process.platform === "win32") return process.env.APPDATA || die("APPDATA is not set");
|
|
83
|
+
if (process.platform === "darwin") return join(homedir(), "Library", "Application Support");
|
|
84
|
+
return process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
/** Copy the built plugin into a Deck's plugins folder. Deck watches it and reloads the plugin. */
|
|
81
88
|
function copyInto(manifest, defaultTarget) {
|
|
89
|
+
// A plugin that lists the systems it runs on is not put into a Deck on any other, which would not
|
|
90
|
+
// load it anyway.
|
|
91
|
+
const here = { win32: "windows", darwin: "mac" }[process.platform] ?? "linux";
|
|
92
|
+
if (Array.isArray(manifest.platforms) && manifest.platforms.length && !manifest.platforms.includes(here)) {
|
|
93
|
+
die(`${manifest.id} runs on ${manifest.platforms.join(", ")} only (its plugin.json "platforms"), and this is ${here}`);
|
|
94
|
+
}
|
|
82
95
|
const { target, dir: plugins } = pluginsDir(defaultTarget);
|
|
83
96
|
const dest = join(plugins, manifest.id);
|
|
84
97
|
mkdirSync(dest, { recursive: true });
|
package/package.json
CHANGED
package/permissions.json
CHANGED
|
@@ -231,6 +231,7 @@
|
|
|
231
231
|
"fsHomeDir",
|
|
232
232
|
"getAutostart",
|
|
233
233
|
"isFullscreen",
|
|
234
|
+
"isWindows",
|
|
234
235
|
"languagesDir",
|
|
235
236
|
"launchUrls",
|
|
236
237
|
"mediaSetNowPlaying",
|
|
@@ -238,6 +239,7 @@
|
|
|
238
239
|
"memUsage",
|
|
239
240
|
"notifyOs",
|
|
240
241
|
"openExternal",
|
|
242
|
+
"pathKey",
|
|
241
243
|
"pickAnyFile",
|
|
242
244
|
"pickExe",
|
|
243
245
|
"pickFile",
|
|
@@ -245,8 +247,10 @@
|
|
|
245
247
|
"pickImage",
|
|
246
248
|
"pickSavePath",
|
|
247
249
|
"pickScript",
|
|
250
|
+
"platform",
|
|
248
251
|
"pluginsDir",
|
|
249
252
|
"revealInFolder",
|
|
253
|
+
"samePath",
|
|
250
254
|
"startupMarks",
|
|
251
255
|
"toggleFullscreen"
|
|
252
256
|
]
|
package/publish.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { execFileSync } from "node:child_process";
|
|
|
18
18
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
19
19
|
import { dirname, join } from "node:path";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
|
-
import { checkAssets, checkIcon, checkId, checkLockfile, checkManifest, checkPermissions, fileFacts, ICON_FILE, points } from "./validate.mjs";
|
|
21
|
+
import { checkAssets, checkIcon, checkId, checkLockfile, checkManifest, checkPermissions, checkPortable, fileFacts, ICON_FILE, points } from "./validate.mjs";
|
|
22
22
|
|
|
23
23
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
24
24
|
const REGISTRY = "deck-desktop/deck-registry";
|
|
@@ -83,6 +83,7 @@ export async function publish(dir, manifest, { dryRun, buildPlugin }) {
|
|
|
83
83
|
const perms = checkPermissions(manifest.permissions, readFileSync(join(dir, "plugin.js"), "utf8"), table, manifest.id);
|
|
84
84
|
errors.push(...perms.errors);
|
|
85
85
|
notes.push(...perms.notes);
|
|
86
|
+
notes.push(...checkPortable(manifest, readFileSync(join(dir, "plugin.js"), "utf8")));
|
|
86
87
|
if (errors.length) {
|
|
87
88
|
for (const e of errors) console.error(` ✗ ${e}`);
|
|
88
89
|
process.exit(1);
|
package/shim/bridge.js
CHANGED
|
@@ -161,6 +161,7 @@ export const installAgentMcp = (...a) => b().installAgentMcp(...a);
|
|
|
161
161
|
export const installAgentSkills = (...a) => b().installAgentSkills(...a);
|
|
162
162
|
export const installFromRegistry = (...a) => b().installFromRegistry(...a);
|
|
163
163
|
export const isFullscreen = (...a) => b().isFullscreen(...a);
|
|
164
|
+
export const isWindows = (...a) => b().isWindows(...a);
|
|
164
165
|
export const languagesDir = (...a) => b().languagesDir(...a);
|
|
165
166
|
export const launchFiles = (...a) => b().launchFiles(...a);
|
|
166
167
|
export const launchUrls = (...a) => b().launchUrls(...a);
|
|
@@ -176,6 +177,7 @@ export const notifyOs = (...a) => b().notifyOs(...a);
|
|
|
176
177
|
export const openExternal = (...a) => b().openExternal(...a);
|
|
177
178
|
export const openFile = (...a) => b().openFile(...a);
|
|
178
179
|
export const openTestDeck = (...a) => b().openTestDeck(...a);
|
|
180
|
+
export const pathKey = (...a) => b().pathKey(...a);
|
|
179
181
|
export const pickAnyFile = (...a) => b().pickAnyFile(...a);
|
|
180
182
|
export const pickExe = (...a) => b().pickExe(...a);
|
|
181
183
|
export const pickFile = (...a) => b().pickFile(...a);
|
|
@@ -183,6 +185,7 @@ export const pickFolder = (...a) => b().pickFolder(...a);
|
|
|
183
185
|
export const pickImage = (...a) => b().pickImage(...a);
|
|
184
186
|
export const pickSavePath = (...a) => b().pickSavePath(...a);
|
|
185
187
|
export const pickScript = (...a) => b().pickScript(...a);
|
|
188
|
+
export const platform = (...a) => b().platform(...a);
|
|
186
189
|
export const pluginsDir = (...a) => b().pluginsDir(...a);
|
|
187
190
|
export const procKill = (...a) => b().procKill(...a);
|
|
188
191
|
export const procStream = (...a) => b().procStream(...a);
|
|
@@ -198,6 +201,7 @@ export const removeLanguage = (...a) => b().removeLanguage(...a);
|
|
|
198
201
|
export const restartApp = (...a) => b().restartApp(...a);
|
|
199
202
|
export const revealInFolder = (...a) => b().revealInFolder(...a);
|
|
200
203
|
export const runScriptNow = (...a) => b().runScriptNow(...a);
|
|
204
|
+
export const samePath = (...a) => b().samePath(...a);
|
|
201
205
|
export const sessionList = (...a) => b().sessionList(...a);
|
|
202
206
|
export const setAutostart = (...a) => b().setAutostart(...a);
|
|
203
207
|
export const setDebugTargets = (...a) => b().setDebugTargets(...a);
|
package/template/plugin.json
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
|
|
2
|
+
export type Platform = "windows" | "linux" | "mac";
|
|
3
|
+
/** Which system Deck runs on. A function, as everything plugins reach through the bridge is. */
|
|
4
|
+
export declare const platform: () => Platform;
|
|
5
|
+
export declare const isWindows: () => boolean;
|
|
6
|
+
/** Whether two paths name the same file: without regard to case on Windows, whose file system
|
|
7
|
+
* ignores it, and exactly elsewhere, where `Readme.md` and `README.md` are two files. */
|
|
8
|
+
export declare function samePath(a: string, b: string): boolean;
|
|
9
|
+
/** A path as a key that `samePath` would match: lowercased on Windows only. */
|
|
10
|
+
export declare function pathKey(p: string): string;
|
|
11
|
+
/** The system's name, for words shown to the user. */
|
|
12
|
+
export declare const osName: () => string;
|
|
13
|
+
/** The menu item that shows a file in the system's file manager. */
|
|
14
|
+
export declare const revealLabel: () => string;
|
package/types/core/bridge.d.ts
CHANGED
|
@@ -672,6 +672,11 @@ export interface TrackMeta {
|
|
|
672
672
|
}
|
|
673
673
|
export declare const readTrackMeta: (paths: string[]) => Promise<TrackMeta[]>;
|
|
674
674
|
export { convertFileSrc } from "@tauri-apps/api/core";
|
|
675
|
+
export { platform } from "./app/platform";
|
|
676
|
+
export { isWindows } from "./app/platform";
|
|
677
|
+
export { samePath } from "./app/platform";
|
|
678
|
+
export { pathKey } from "./app/platform";
|
|
679
|
+
export type { Platform } from "./app/platform";
|
|
675
680
|
/** Start a sign-in. Returns the consent URL to open in the browser. */
|
|
676
681
|
export declare const googleSignIn: () => Promise<string>;
|
|
677
682
|
/** A valid access token, refreshed if needed. Rejects when not connected. */
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
|
|
2
|
+
/** A Chromium browser's bookmarks on this machine, one per profile that has any. */
|
|
3
|
+
export interface BookmarkSource {
|
|
4
|
+
browser: string;
|
|
5
|
+
profile: string;
|
|
6
|
+
path: string;
|
|
7
|
+
}
|
|
8
|
+
/** Every profile of Chrome, Edge and Brave with a Bookmarks file. A browser not installed is no error. */
|
|
9
|
+
export declare function findBookmarkSources(): Promise<BookmarkSource[]>;
|
|
@@ -203,14 +203,8 @@ export declare function forgetDownload(key: string): void;
|
|
|
203
203
|
export declare function clearDownloads(): void;
|
|
204
204
|
export declare const browserBookmarks: () => Bookmarks;
|
|
205
205
|
export declare function setBookmarks(next: Bookmarks): void;
|
|
206
|
-
|
|
207
|
-
export
|
|
208
|
-
browser: string;
|
|
209
|
-
profile: string;
|
|
210
|
-
path: string;
|
|
211
|
-
}
|
|
212
|
-
/** Every profile of Chrome, Edge and Brave with a Bookmarks file. A browser not installed is no error. */
|
|
213
|
-
export declare function findBookmarkSources(): Promise<BookmarkSource[]>;
|
|
206
|
+
import type { BookmarkSource } from "./bookmarksources";
|
|
207
|
+
export { findBookmarkSources, type BookmarkSource } from "./bookmarksources";
|
|
214
208
|
/** Import one source's bookmarks as a "From Chrome" folder in each root. Returns how many pages. */
|
|
215
209
|
export declare function importBookmarks(src: BookmarkSource): Promise<number>;
|
|
216
210
|
/** Every bookmark to a bookmarks HTML file, which any browser imports, and Deck too. How many pages. */
|
|
@@ -89,10 +89,4 @@ export declare function toMonaco(chord: string, mods: {
|
|
|
89
89
|
Shift: number;
|
|
90
90
|
WinCtrl: number;
|
|
91
91
|
}, codes: Record<string, number>): number | null;
|
|
92
|
-
/**
|
|
93
|
-
* Deck's built-in bindings.
|
|
94
|
-
*
|
|
95
|
-
* Plugin bindings are not here — they arrive at load time through the `keybindings` export and
|
|
96
|
-
* are concatenated on, so a disabled plugin's chords leave the table with it.
|
|
97
|
-
*/
|
|
98
92
|
export declare const DEFAULT_BINDINGS: readonly KeyBinding[];
|
|
@@ -32,7 +32,7 @@ export declare function activeElement(): Element | null;
|
|
|
32
32
|
/** Run `fn` for every Deck window, now and as floats open; what it returns runs when that window goes, or on the returned unsubscribe. */
|
|
33
33
|
export declare function onEachWindow(fn: Hook): () => void;
|
|
34
34
|
/** A floating window opened (floatwin.ts), its label known: every hook runs for it. */
|
|
35
|
-
export declare function addWindow(win: Window): void;
|
|
35
|
+
export declare function addWindow(win: Window, label?: string): void;
|
|
36
36
|
/** A floating window is going: what each hook installed in it is undone. */
|
|
37
37
|
export declare function removeWindow(win: Window): void;
|
|
38
38
|
/**
|
package/validate.mjs
CHANGED
|
@@ -44,6 +44,10 @@ export function checkManifest(m) {
|
|
|
44
44
|
if (typeof m.version !== "string" || !SEMVER.test(m.version)) errors.push("`version` must be a version, such as \"1.0.0\"");
|
|
45
45
|
if (typeof m.minDeck !== "string" || !SEMVER.test(m.minDeck)) errors.push("`minDeck` must say which Deck it needs, such as \"1.8.0\"");
|
|
46
46
|
if (m.color !== undefined && !/^#[0-9a-f]{6}$/i.test(m.color)) errors.push("`color` must be #rrggbb");
|
|
47
|
+
// Where it runs: absent means every system. Deck will not load or install it on any other.
|
|
48
|
+
if (m.platforms !== undefined && (!Array.isArray(m.platforms) || !m.platforms.length || !m.platforms.every((p) => ["windows", "linux", "mac"].includes(p)))) {
|
|
49
|
+
errors.push("`platforms` lists the systems it runs on, from \"windows\", \"linux\" and \"mac\"; leave it out to run on all of them");
|
|
50
|
+
}
|
|
47
51
|
if (typeof m.icon === "string" && m.icon.endsWith(".svg") && m.icon !== ICON_FILE) errors.push(`an icon of its own must be named ${ICON_FILE}`);
|
|
48
52
|
return errors;
|
|
49
53
|
}
|
|
@@ -152,6 +156,21 @@ export function checkPermissions(declared, bundle, table, id) {
|
|
|
152
156
|
return { errors, notes, used: [...needs.keys()] };
|
|
153
157
|
}
|
|
154
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Windows-only habits in a plugin that says it runs on Linux too (no "platforms", or a list naming
|
|
161
|
+
* "linux"): a path joined with a backslash, a program named with ".exe". Notes, not errors, and
|
|
162
|
+
* none for a bundle that asks isWindows(), which keeps a Windows branch beside a Linux one.
|
|
163
|
+
*/
|
|
164
|
+
export function checkPortable(manifest, bundle) {
|
|
165
|
+
const runs = Array.isArray(manifest.platforms) ? manifest.platforms : ["windows", "linux"];
|
|
166
|
+
if (!runs.includes("linux") || /\(\)\.isWindows\(|\bisWindows\(/.test(bundle)) return [];
|
|
167
|
+
const notes = [];
|
|
168
|
+
const joins = (bundle.match(/\}\\\\|["'`]\\\\["'`]/g) ?? []).length;
|
|
169
|
+
if (joins) notes.push(`It joins paths with a backslash (${joins} place${joins > 1 ? "s" : ""}), which on Linux is part of a file name: ask isWindows() from the bridge for the separator, or say "platforms": ["windows"] in plugin.json.`);
|
|
170
|
+
if (/\.exe["'`]/.test(bundle)) notes.push(`It names a program with ".exe", which Linux programs do not have: ask isWindows() from the bridge, or say "platforms": ["windows"] in plugin.json.`);
|
|
171
|
+
return notes;
|
|
172
|
+
}
|
|
173
|
+
|
|
155
174
|
// ---- points ----
|
|
156
175
|
// A version's points: advice for whoever is choosing a plugin, never a gate (the checks above are
|
|
157
176
|
// that). Worked out once when it is published, by the registry for a submission and by
|