positron.js 1.0.5 → 1.1.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/README.md +7 -8
- package/builder.js +160 -3
- package/core/linux/main.cpp +1123 -0
- package/core/mac/main.swift +52 -21
- package/core/mac/tray.swift +95 -0
- package/core/win/main.cs +58 -13
- package/core/win/tray.cs +142 -0
- package/index.js +91 -38
- package/package.json +3 -2
- package/packager.js +118 -12
- package/screen.js +7 -5
- package/tray.js +72 -0
package/README.md
CHANGED
|
@@ -34,6 +34,8 @@ Positron is built as a lightweight, secure alternative to Electron. Below is a d
|
|
|
34
34
|
- Node.js (v16+)
|
|
35
35
|
- macOS: Xcode Command Line Tools (swiftc)
|
|
36
36
|
- Windows: .NET SDK (CLI tools capable of executing `dotnet publish`)
|
|
37
|
+
- C++ compiler (G++ is the default), GTK+ 3 and WebKit2GTK on Linux
|
|
38
|
+
- Docker if building for Linux on macOS or Windows
|
|
37
39
|
|
|
38
40
|
## Install
|
|
39
41
|
```bash
|
|
@@ -76,7 +78,8 @@ To create a native extension, provide a custom positron property block within yo
|
|
|
76
78
|
"command": "toast:show",
|
|
77
79
|
"platforms": {
|
|
78
80
|
"darwin": "src/mac/ToastPlugin.swift",
|
|
79
|
-
"win32": "src/win/ToastPlugin.cs"
|
|
81
|
+
"win32": "src/win/ToastPlugin.cs",
|
|
82
|
+
"linux":"src/linux/ToastPlugin.cpp"
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
85
|
}
|
|
@@ -112,10 +115,10 @@ npx positron run
|
|
|
112
115
|
### Packaging
|
|
113
116
|
This will rebuild the binary, then create a deployable version of the app
|
|
114
117
|
```bash
|
|
115
|
-
npx positron package [--m | --w] [--arm64 || --x64]
|
|
118
|
+
npx positron package [--m | --w || --l] [--arm64 || --x64]
|
|
116
119
|
```
|
|
117
120
|
|
|
118
|
-
> Note: Windows
|
|
121
|
+
> Note: Windows & Linux support either arm64 or x64, while macOS only supports arm64.
|
|
119
122
|
|
|
120
123
|
## IPC Protocol Specification
|
|
121
124
|
Communication relies on structured JSON communication frames routed through the IPC WebSocket server.
|
|
@@ -143,12 +146,8 @@ Communication relies on structured JSON communication frames routed through the
|
|
|
143
146
|
}
|
|
144
147
|
```
|
|
145
148
|
|
|
146
|
-
## Environment Flags
|
|
147
|
-
- POSITRON_PACKAGED: Set to "true" inside production bundles to suppress localized development shell background re-compilation triggers.
|
|
148
|
-
- POSITRON_IPC_PORT: The port that the IPC server runs on.
|
|
149
|
-
|
|
150
149
|
## License
|
|
151
150
|
MIT
|
|
152
151
|
|
|
153
152
|
## Documentation
|
|
154
|
-
Read
|
|
153
|
+
[Read here](https://positronjs.gitbook.io/v1)
|
package/builder.js
CHANGED
|
@@ -11,11 +11,13 @@ function performNativeBuild() {
|
|
|
11
11
|
|
|
12
12
|
let buildingForWindows = process.argv.includes("--windows") || process.argv.includes("--w");
|
|
13
13
|
let buildingForMac = process.argv.includes("--mac") || process.argv.includes("--m");
|
|
14
|
+
let buildingForLinux = process.argv.includes("--linux") || process.argv.includes("--l");
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
const appRoot = process.cwd(); // The developer's project folder
|
|
17
18
|
const nativeExtensionsMac = [];
|
|
18
19
|
const nativeExtensionsWindows = [];
|
|
20
|
+
const nativeExtensionsLinux = [];
|
|
19
21
|
|
|
20
22
|
// 1. Discover Extensions from the developer's package.json
|
|
21
23
|
const rootPackagePath = path.join(appRoot, "package.json");
|
|
@@ -50,6 +52,7 @@ function performNativeBuild() {
|
|
|
50
52
|
else {
|
|
51
53
|
if(!depPackage.positron.platforms.darwin) missing.push("platforms.darwin");
|
|
52
54
|
if(!depPackage.positron.platforms.win32) missing.push("platforms.win32");
|
|
55
|
+
if(!depPackage.positron.platforms.linux) missing.push("platforms.linux");
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
if(missing.includes("className") || missing.includes("command") || missing.includes("platforms")) {
|
|
@@ -75,15 +78,26 @@ function performNativeBuild() {
|
|
|
75
78
|
} else {
|
|
76
79
|
warn(`[Builder] Dependency "${dep}" is missing a Windows platform source file. Skipping Windows native extension build for this dependency.`);
|
|
77
80
|
}
|
|
81
|
+
if(!missing.includes("platforms.linux")) {
|
|
82
|
+
nativeExtensionsLinux.push({
|
|
83
|
+
className: depPackage.positron.className,
|
|
84
|
+
command: depPackage.positron.command,
|
|
85
|
+
sourceFile: path.join(depDir, depPackage.positron.platforms.linux)
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
warn(`[Builder] Dependency "${dep}" is missing a Linux platform source file. Skipping Linux native extension build for this dependency.`);
|
|
89
|
+
}
|
|
78
90
|
}
|
|
79
91
|
}
|
|
80
92
|
}
|
|
81
93
|
|
|
82
|
-
if(buildingForWindows == false && buildingForMac == false) {
|
|
94
|
+
if(buildingForWindows == false && buildingForMac == false && buildingForLinux == false) {
|
|
83
95
|
if (process.platform === "win32") {
|
|
84
96
|
buildingForWindows = true;
|
|
85
97
|
} else if (process.platform === "darwin") {
|
|
86
98
|
buildingForMac = true;
|
|
99
|
+
} else if (process.platform === "linux") {
|
|
100
|
+
buildingForLinux = true;
|
|
87
101
|
} else {
|
|
88
102
|
error("[Builder] Unsupported platform for native build.");
|
|
89
103
|
return false;
|
|
@@ -91,7 +105,17 @@ function performNativeBuild() {
|
|
|
91
105
|
}
|
|
92
106
|
|
|
93
107
|
if (buildingForMac) {
|
|
94
|
-
|
|
108
|
+
|
|
109
|
+
const coreMacDir = path.join(__dirname, "core", "mac");
|
|
110
|
+
|
|
111
|
+
nativeExtensionsMac.push({
|
|
112
|
+
command:"createTray",
|
|
113
|
+
className:"TrayExtension",
|
|
114
|
+
sourceFile:path.join(coreMacDir, "tray.swift")
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// -1 to account for the built-in tray extension
|
|
118
|
+
info(`[Builder] Stitching ${nativeExtensionsMac.length-1} native extensions...`);
|
|
95
119
|
|
|
96
120
|
let registryContent = `// Auto-generated by Positron. Do not edit.\n`;
|
|
97
121
|
registryContent += `func getExtensionRegistry() -> [String: (Int, [String]) -> Void] {\n`;
|
|
@@ -112,7 +136,6 @@ function performNativeBuild() {
|
|
|
112
136
|
|
|
113
137
|
registryContent += `}\n`;
|
|
114
138
|
|
|
115
|
-
const coreMacDir = path.join(__dirname, "core", "mac");
|
|
116
139
|
fs.writeFileSync(path.join(coreMacDir, "Registry.swift"), registryContent);
|
|
117
140
|
|
|
118
141
|
info("[Builder] Compiling native binary...");
|
|
@@ -189,6 +212,7 @@ function performNativeBuild() {
|
|
|
189
212
|
const coreWinDir = path.join(__dirname, "core", "win");
|
|
190
213
|
const extensionsDir = path.join(coreWinDir, "extensions");
|
|
191
214
|
|
|
215
|
+
|
|
192
216
|
// 1. Clean and prepare a staging folder for all native extensions
|
|
193
217
|
if (fs.existsSync(extensionsDir)) fs.rmSync(extensionsDir, { recursive: true, force: true });
|
|
194
218
|
fs.mkdirSync(extensionsDir, { recursive: true });
|
|
@@ -235,6 +259,19 @@ function performNativeBuild() {
|
|
|
235
259
|
dotnetArgs.push(`/p:ApplicationIcon=${iconPath}`);
|
|
236
260
|
}
|
|
237
261
|
|
|
262
|
+
// Add package.json metadata to Windows executable
|
|
263
|
+
const appName = rootPackage.productName || rootPackage.name || "PositronApp";
|
|
264
|
+
const version = rootPackage.version || "1.0.0";
|
|
265
|
+
const author = rootPackage.author || "Positron";
|
|
266
|
+
const bundleId = rootPackage.bundleIdentifier || `com.${author.toLowerCase().replace(/[^a-z0-9]/g, '')}.${appName.toLowerCase().replace(/[^a-z0-9]/g, '')}`;
|
|
267
|
+
const winCategory = rootPackage.winCategory || rootPackage.macCategory || "An application built with Positron.js";
|
|
268
|
+
|
|
269
|
+
dotnetArgs.push(`/p:Version=${version}`);
|
|
270
|
+
dotnetArgs.push(`/p:Authors=${author}`);
|
|
271
|
+
dotnetArgs.push(`/p:Company=${author}`);
|
|
272
|
+
dotnetArgs.push(`/p:Product=${bundleId}`);
|
|
273
|
+
dotnetArgs.push(`/p:Description=${winCategory}`);
|
|
274
|
+
|
|
238
275
|
cp.execFileSync("dotnet", dotnetArgs, { stdio: "inherit" });
|
|
239
276
|
success("[Builder] Windows native compilation successful.");
|
|
240
277
|
return true;
|
|
@@ -244,6 +281,126 @@ function performNativeBuild() {
|
|
|
244
281
|
}
|
|
245
282
|
}
|
|
246
283
|
|
|
284
|
+
if (buildingForLinux) {
|
|
285
|
+
info(`[Builder] Stitching ${nativeExtensionsLinux.length} native Linux extensions...`);
|
|
286
|
+
|
|
287
|
+
const coreLinuxDir = path.join(__dirname, "core", "linux");
|
|
288
|
+
|
|
289
|
+
let registryContent = `// Auto-generated by Positron. Do not edit.\n`;
|
|
290
|
+
registryContent += `#include <string>\n#include <unordered_map>\n#include <vector>\n\n`;
|
|
291
|
+
registryContent += `using namespace std;\n\n`;
|
|
292
|
+
|
|
293
|
+
nativeExtensionsLinux.forEach((ext, index) => {
|
|
294
|
+
registryContent += `void handle_${ext.className}(int windowId, vector<string> args);\n`;
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
registryContent += `\nunordered_map<string, void(*)(int, vector<string>)> getExtensionRegistry() {\n`;
|
|
298
|
+
registryContent += ` return {\n`;
|
|
299
|
+
|
|
300
|
+
nativeExtensionsLinux.forEach((ext, index) => {
|
|
301
|
+
const comma = index === nativeExtensionsLinux.length - 1 ? "" : ",";
|
|
302
|
+
registryContent += ` {"${ext.command}", handle_${ext.className}}${comma}\n`;
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
registryContent += ` };\n}\n`;
|
|
306
|
+
|
|
307
|
+
fs.writeFileSync(path.join(coreLinuxDir, "Registry.cpp"), registryContent);
|
|
308
|
+
|
|
309
|
+
if (process.platform !== "linux") {
|
|
310
|
+
info("[Builder] Cross-compiling for Linux using Docker...");
|
|
311
|
+
try {
|
|
312
|
+
const dockerVer = cp.spawnSync("docker", ["--version"], { stdio: "ignore" });
|
|
313
|
+
if (dockerVer.error || dockerVer.status !== 0) throw new Error("Docker is not available");
|
|
314
|
+
} catch (e) {
|
|
315
|
+
error("[Builder] Fatal: Docker is required to cross-compile for Linux on macOS/Windows.");
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const dockerArch = arch === "arm64" ? "linux/arm64" : "linux/amd64";
|
|
320
|
+
const dockerTag = `positron-linux-builder-${arch}`;
|
|
321
|
+
const dockerfileContent = [
|
|
322
|
+
"FROM ubuntu:latest",
|
|
323
|
+
"ENV DEBIAN_FRONTEND=noninteractive",
|
|
324
|
+
"RUN apt-get update && apt-get install -y "+
|
|
325
|
+
"g++ pkg-config "+
|
|
326
|
+
"libgtk-3-dev libwebkit2gtk-4.1-dev libjson-glib-dev "+
|
|
327
|
+
"libsoup2.4-dev libnotify-dev",
|
|
328
|
+
"WORKDIR /app"
|
|
329
|
+
].join("\n");
|
|
330
|
+
|
|
331
|
+
fs.writeFileSync(path.join(coreLinuxDir, "Dockerfile.linux"), dockerfileContent);
|
|
332
|
+
info(`[Builder] Building Docker image for ${dockerArch}...`);
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
const buildRes = cp.spawnSync("docker", ["build", "--platform", dockerArch, "-t", dockerTag, "-f", path.join(coreLinuxDir, "Dockerfile.linux"), coreLinuxDir], { stdio: "inherit" });
|
|
336
|
+
if (buildRes.error) throw buildRes.error;
|
|
337
|
+
if (buildRes.status !== 0) throw new Error("Docker build failed");
|
|
338
|
+
|
|
339
|
+
const outBinaryDir = path.join(appRoot, "bin");
|
|
340
|
+
|
|
341
|
+
if(!fs.existsSync(outBinaryDir)) fs.mkdirSync(outBinaryDir, { recursive: true });
|
|
342
|
+
|
|
343
|
+
const extensionSources = nativeExtensionsLinux.map(e => e.sourceFile);
|
|
344
|
+
const mappedExtensions = extensionSources.map(s => {
|
|
345
|
+
if (s.startsWith(appRoot)) {
|
|
346
|
+
return "/app/" + path.relative(appRoot, s).replace(/\\/g, '/');
|
|
347
|
+
} else if (s.startsWith(__dirname)) {
|
|
348
|
+
return "/framework/" + path.relative(__dirname, s).replace(/\\/g, '/');
|
|
349
|
+
}
|
|
350
|
+
return s;
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const compiler = process.argv.find(arg => arg.startsWith("--compiler="))?.split("=")[1] || "g++";
|
|
354
|
+
|
|
355
|
+
const gccArgs = [
|
|
356
|
+
compiler, "-O3",
|
|
357
|
+
"/framework/core/linux/main.cpp",
|
|
358
|
+
"/framework/core/linux/Registry.cpp",
|
|
359
|
+
...mappedExtensions,
|
|
360
|
+
"-o", "/app/bin/positron-runtime",
|
|
361
|
+
"$(pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.1 json-glib-1.0 libnotify)"
|
|
362
|
+
].join(" ");
|
|
363
|
+
|
|
364
|
+
info("[Builder] Compiling inside Docker container...");
|
|
365
|
+
const runRes = cp.spawnSync("docker", ["run", "--rm", "--platform", dockerArch, "-v", `\${appRoot}:/app`, "-v", `\${__dirname}:/framework`, dockerTag, "bash", "-c", gccArgs], { stdio: "inherit" });
|
|
366
|
+
if (runRes.error) throw runRes.error;
|
|
367
|
+
if (runRes.status !== 0) throw new Error("Docker run failed");
|
|
368
|
+
|
|
369
|
+
success("[Builder] Linux native cross-compilation successful.");
|
|
370
|
+
return true;
|
|
371
|
+
} catch (err) {
|
|
372
|
+
error("[Builder] Linux cross-compilation via Docker failed:", err.message);
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
info("[Builder] Compiling Linux native binary natively via g++...");
|
|
377
|
+
try {
|
|
378
|
+
const pkgRes = cp.spawnSync("pkg-config", ["--cflags", "--libs", "gtk+-3.0", "webkit2gtk-4.1", "json-glib-1.0", "libnotify"], { encoding: 'utf8' });
|
|
379
|
+
if (pkgRes.error) throw pkgRes.error;
|
|
380
|
+
if (pkgRes.status !== 0) throw new Error("pkg-config failed");
|
|
381
|
+
const pkgConfigOutput = pkgRes.stdout.trim().split(/\\s+/);
|
|
382
|
+
|
|
383
|
+
const extensionSources = nativeExtensionsLinux.map(e => e.sourceFile);
|
|
384
|
+
const gccArgs = [
|
|
385
|
+
"-O3",
|
|
386
|
+
path.join(coreLinuxDir, "main.cpp"),
|
|
387
|
+
path.join(coreLinuxDir, "Registry.cpp"),
|
|
388
|
+
...extensionSources,
|
|
389
|
+
"-o", path.join(outBinaryDir, "positron-runtime"),
|
|
390
|
+
...pkgConfigOutput
|
|
391
|
+
];
|
|
392
|
+
|
|
393
|
+
cp.execFileSync("g++", gccArgs, { stdio: "inherit" });
|
|
394
|
+
success("[Builder] Linux native compilation successful.");
|
|
395
|
+
return true;
|
|
396
|
+
} catch (err) {
|
|
397
|
+
error("[Builder] Linux compilation failed:", err.message);
|
|
398
|
+
warn("Ensure you have installed: libgtk-3-dev libwebkit2gtk-4.1-dev libjson-glib-dev libsoup2.4-dev");
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
247
404
|
return false; // Unsupported platform
|
|
248
405
|
|
|
249
406
|
}
|