@jano-editor/editor 1.0.0-alpha.1

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/dist/cli.js ADDED
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { homedir, platform } from "node:os";
5
+ import AdmZip from "adm-zip";
6
+ //#region packages/editor/src/plugins/config.ts
7
+ function resolvePaths() {
8
+ if (process.env.JANO_HOME) {
9
+ const base = process.env.JANO_HOME;
10
+ return {
11
+ config: base,
12
+ data: base,
13
+ plugins: join(base, "plugins"),
14
+ cache: join(base, "cache")
15
+ };
16
+ }
17
+ const home = process.env.SNAP_REAL_HOME || process.env.HOME || process.env.USERPROFILE || homedir();
18
+ const os = platform();
19
+ if (os === "win32") {
20
+ const appData = process.env.APPDATA || join(home, "AppData", "Roaming");
21
+ const localAppData = process.env.LOCALAPPDATA || join(home, "AppData", "Local");
22
+ const config = join(appData, "jano");
23
+ const data = join(localAppData, "jano");
24
+ return {
25
+ config,
26
+ data,
27
+ plugins: join(data, "plugins"),
28
+ cache: join(localAppData, "jano", "cache")
29
+ };
30
+ }
31
+ if (os === "darwin") {
32
+ const appSupport = join(home, "Library", "Application Support", "jano");
33
+ return {
34
+ config: appSupport,
35
+ data: appSupport,
36
+ plugins: join(appSupport, "plugins"),
37
+ cache: join(home, "Library", "Caches", "jano")
38
+ };
39
+ }
40
+ const isSnapped = (v) => v && v.includes("/snap/");
41
+ const configDir = !isSnapped(process.env.XDG_CONFIG_HOME) && process.env.XDG_CONFIG_HOME || join(home, ".config");
42
+ const dataDir = !isSnapped(process.env.XDG_DATA_HOME) && process.env.XDG_DATA_HOME || join(home, ".local", "share");
43
+ const cacheDir = !isSnapped(process.env.XDG_CACHE_HOME) && process.env.XDG_CACHE_HOME || join(home, ".cache");
44
+ return {
45
+ config: join(configDir, "jano"),
46
+ data: join(dataDir, "jano"),
47
+ plugins: join(dataDir, "jano", "plugins"),
48
+ cache: join(cacheDir, "jano")
49
+ };
50
+ }
51
+ var paths = resolvePaths();
52
+ function getPaths() {
53
+ return paths;
54
+ }
55
+ function getPluginsDir() {
56
+ return paths.plugins;
57
+ }
58
+ function getConfigPath() {
59
+ return join(paths.config, "config.json");
60
+ }
61
+ function ensureDirs() {
62
+ for (const dir of [
63
+ paths.config,
64
+ paths.data,
65
+ paths.plugins,
66
+ paths.cache
67
+ ]) if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
68
+ }
69
+ function loadConfig() {
70
+ ensureDirs();
71
+ const configPath = getConfigPath();
72
+ if (!existsSync(configPath)) return { plugins: {} };
73
+ try {
74
+ const raw = readFileSync(configPath, "utf8");
75
+ return JSON.parse(raw);
76
+ } catch {
77
+ return { plugins: {} };
78
+ }
79
+ }
80
+ function isPluginEnabled(config, name) {
81
+ return config.plugins[name]?.enabled !== false;
82
+ }
83
+ //#endregion
84
+ //#region packages/editor/src/plugins/registry.ts
85
+ var REGISTRY_URL = "https://janoeditor.dev/api";
86
+ async function fetchPluginList() {
87
+ const res = await fetch(`${REGISTRY_URL}/plugins`);
88
+ if (!res.ok) throw new Error(`Failed to fetch plugin list: ${res.statusText}`);
89
+ return res.json();
90
+ }
91
+ async function fetchPluginDetail(name) {
92
+ const res = await fetch(`${REGISTRY_URL}/plugins/${name}`);
93
+ if (!res.ok) {
94
+ if (res.status === 404) throw new Error(`Plugin '${name}' not found.`);
95
+ throw new Error(`Failed to fetch plugin: ${res.statusText}`);
96
+ }
97
+ return res.json();
98
+ }
99
+ async function downloadPlugin(name, version) {
100
+ const url = version ? `${REGISTRY_URL}/plugins/${name}/download?version=${version}` : `${REGISTRY_URL}/plugins/${name}/download`;
101
+ const res = await fetch(url);
102
+ if (!res.ok) {
103
+ if (res.status === 404) throw new Error(`Plugin '${name}'${version ? ` v${version}` : ""} not found.`);
104
+ throw new Error(`Download failed: ${res.statusText}`);
105
+ }
106
+ return Buffer.from(await res.arrayBuffer());
107
+ }
108
+ async function installPlugin(nameWithVersion) {
109
+ let name;
110
+ let requestedVersion;
111
+ if (nameWithVersion.includes("@")) {
112
+ const parts = nameWithVersion.split("@");
113
+ name = parts[0];
114
+ requestedVersion = parts[1];
115
+ } else name = nameWithVersion;
116
+ try {
117
+ console.log(`[jano] Fetching plugin info for '${name}'...`);
118
+ const detail = await fetchPluginDetail(name);
119
+ const version = requestedVersion || detail.latestVersion;
120
+ if (requestedVersion) {
121
+ if (!detail.versions.some((v) => v.version === requestedVersion)) {
122
+ const available = detail.versions.map((v) => v.version).join(", ");
123
+ return {
124
+ success: false,
125
+ name,
126
+ version,
127
+ error: `Version ${requestedVersion} not found. Available: ${available}`
128
+ };
129
+ }
130
+ }
131
+ const pluginDir = join(getPluginsDir(), name);
132
+ const manifestPath = join(pluginDir, "plugin.json");
133
+ let installedVersion = null;
134
+ try {
135
+ const { readFileSync } = await import("node:fs");
136
+ installedVersion = JSON.parse(readFileSync(manifestPath, "utf8")).version;
137
+ } catch {}
138
+ if (installedVersion) {
139
+ if (installedVersion === version) return {
140
+ success: true,
141
+ name,
142
+ version,
143
+ error: `Already installed at v${version}.`
144
+ };
145
+ console.log(`[jano] ${name}: ${installedVersion < version ? "upgrade" : "downgrade"} from v${installedVersion} to v${version}`);
146
+ }
147
+ console.log(`[jano] Downloading ${name} v${version}...`);
148
+ const zipBuffer = await downloadPlugin(name, requestedVersion);
149
+ console.log(`[jano] Installing to ${pluginDir}...`);
150
+ mkdirSync(pluginDir, { recursive: true });
151
+ new AdmZip(zipBuffer).extractAllTo(pluginDir, true);
152
+ console.log(`[jano] ✓ Installed ${name} v${version}`);
153
+ return {
154
+ success: true,
155
+ name,
156
+ version
157
+ };
158
+ } catch (err) {
159
+ const msg = err instanceof Error ? err.message : String(err);
160
+ return {
161
+ success: false,
162
+ name,
163
+ version: requestedVersion || "unknown",
164
+ error: msg
165
+ };
166
+ }
167
+ }
168
+ async function searchPlugins(query) {
169
+ const all = await fetchPluginList();
170
+ const q = query.toLowerCase();
171
+ return all.filter((p) => p.name.toLowerCase().includes(q) || p.description.toLowerCase().includes(q) || p.extensions.some((e) => e.toLowerCase().includes(q)));
172
+ }
173
+ //#endregion
174
+ //#region packages/editor/src/cli.ts
175
+ var args = process.argv.slice(2);
176
+ async function handlePluginCommand() {
177
+ switch (args[1]) {
178
+ case "install": {
179
+ const target = args[2];
180
+ if (!target) {
181
+ console.error("Usage: jano plugin install <name[@version]>");
182
+ process.exit(1);
183
+ }
184
+ const result = await installPlugin(target);
185
+ if (result.success) if (result.error) console.log(`[jano] ${result.error}`);
186
+ else console.log(`[jano] ✓ ${result.name} v${result.version} installed.`);
187
+ else {
188
+ console.error(`[jano] ✗ ${result.error}`);
189
+ process.exit(1);
190
+ }
191
+ break;
192
+ }
193
+ case "list": {
194
+ const pluginsDir = getPluginsDir();
195
+ if (!existsSync(pluginsDir)) {
196
+ console.log("No plugins installed.");
197
+ break;
198
+ }
199
+ const dirs = readdirSync(pluginsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
200
+ if (dirs.length === 0) {
201
+ console.log("No plugins installed.");
202
+ break;
203
+ }
204
+ console.log("Installed plugins:\n");
205
+ for (const dir of dirs) {
206
+ const manifestPath = join(pluginsDir, dir.name, "plugin.json");
207
+ try {
208
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
209
+ console.log(` ${manifest.name} v${manifest.version} (${manifest.extensions.join(", ")})`);
210
+ } catch {
211
+ console.log(` ${dir.name} (invalid plugin.json)`);
212
+ }
213
+ }
214
+ break;
215
+ }
216
+ case "remove": {
217
+ const name = args[2];
218
+ if (!name) {
219
+ console.error("Usage: jano plugin remove <name>");
220
+ process.exit(1);
221
+ }
222
+ const pluginDir = join(getPluginsDir(), name);
223
+ if (!existsSync(pluginDir)) {
224
+ console.error(`[jano] Plugin '${name}' is not installed.`);
225
+ process.exit(1);
226
+ }
227
+ rmSync(pluginDir, { recursive: true });
228
+ console.log(`[jano] ✓ Removed ${name}.`);
229
+ break;
230
+ }
231
+ case "search": {
232
+ const query = args[2];
233
+ if (!query) {
234
+ const all = await fetchPluginList();
235
+ if (all.length === 0) {
236
+ console.log("No plugins available.");
237
+ break;
238
+ }
239
+ console.log("Available plugins:\n");
240
+ for (const p of all) console.log(` ${p.name} v${p.latestVersion} ${p.description}`);
241
+ } else {
242
+ const results = await searchPlugins(query);
243
+ if (results.length === 0) {
244
+ console.log(`No plugins found for '${query}'.`);
245
+ break;
246
+ }
247
+ console.log(`Found ${results.length} plugin(s):\n`);
248
+ for (const p of results) console.log(` ${p.name} v${p.latestVersion} ${p.description}`);
249
+ }
250
+ break;
251
+ }
252
+ default:
253
+ console.error("Usage: jano plugin <install|list|remove|search> [args]");
254
+ process.exit(1);
255
+ }
256
+ }
257
+ if (args[0] === "plugin") handlePluginCommand();
258
+ else import("./src-wMDtJsWF.js");
259
+ //#endregion
260
+ export { loadConfig as i, getPluginsDir as n, isPluginEnabled as r, getPaths as t };