electrobun 1.18.1 → 1.18.4-beta.10
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 +37 -14
- package/dash.config.ts +28 -0
- package/dist/api/browser/global.d.ts +6 -0
- package/dist/api/browser/index.ts +162 -44
- package/dist/api/{bun → config}/ElectrobunConfig.ts +109 -40
- package/dist/api/config/validate.test.ts +31 -0
- package/dist/api/config/validate.ts +19 -0
- package/dist/api/preload/.generated/compiled.ts +8 -0
- package/dist/api/{bun/preload → preload}/build.ts +6 -6
- package/dist/api/{bun/preload → preload}/encryption.ts +11 -5
- package/dist/api/{bun/preload → preload}/globals.d.ts +8 -0
- package/dist/api/{bun/preload → preload}/index.ts +18 -8
- package/dist/api/{bun/preload → preload}/webviewTag.ts +32 -3
- package/dist/api/{bun/preload → preload}/wgpuTag.ts +33 -2
- package/dist/api/{bun → sdks/bun}/__tests__/ffi-contract.test.ts +6 -9
- package/dist/api/{bun → sdks/bun}/core/BrowserView.ts +96 -55
- package/dist/api/{bun → sdks/bun}/core/BrowserWindow.ts +20 -30
- package/dist/api/{bun → sdks/bun}/core/BuildConfig.ts +32 -5
- package/dist/api/{bun → sdks/bun}/core/GpuWindow.ts +20 -7
- package/dist/api/sdks/bun/core/Socket.ts +22 -0
- package/dist/api/{bun → sdks/bun}/core/Tray.ts +33 -32
- package/dist/api/{bun → sdks/bun}/core/Updater.ts +10 -10
- package/dist/api/{bun → sdks/bun}/core/Utils.ts +3 -5
- package/dist/api/{bun → sdks/bun}/core/WGPUView.ts +43 -13
- package/dist/api/{bun → sdks/bun}/index.ts +39 -10
- package/dist/api/{bun → sdks/bun}/proc/native.ts +942 -746
- package/dist/api/{bun → sdks/bun}/webGPU.ts +1 -1
- package/dist/api/{bun → sdks/bun}/webgpuAdapter.ts +40 -33
- package/dist/api/shared/build-dependencies.test.ts +48 -0
- package/dist/api/shared/build-dependencies.ts +46 -0
- package/dist/api/shared/go-version.ts +3 -0
- package/dist/api/shared/odin-version.ts +6 -0
- package/dist/api/shared/rust-version.ts +3 -0
- package/dist/go-sdk/callbacks.go +260 -0
- package/dist/go-sdk/electrobun.go +2021 -0
- package/dist/main.js +35 -28
- package/dist/odin-sdk/electrobun/electrobun.odin +2337 -0
- package/dist/preload-full.js +948 -0
- package/dist/preload-sandboxed.js +111 -0
- package/dist/rust-sdk/electrobun.rs +2396 -0
- package/dist/zig-sdk/electrobun.zig +2005 -0
- package/package.json +5 -29
- package/src/cli/index.ts +868 -654
- package/bin/electrobun.cjs +0 -169
- package/dist/api/bun/core/Socket.ts +0 -205
- package/dist/api/bun/core/windowIds.ts +0 -5
- package/dist/api/bun/preload/.generated/compiled.ts +0 -8
- package/dist/api/shared/bun-version.ts +0 -3
- /package/dist/api/{bun/preload → preload}/dragRegions.ts +0 -0
- /package/dist/api/{bun/preload → preload}/events.ts +0 -0
- /package/dist/api/{bun/preload → preload}/index-sandboxed.ts +0 -0
- /package/dist/api/{bun/preload → preload}/internalRpc.ts +0 -0
- /package/dist/api/{bun/preload → preload}/overlaySync.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/core/ApplicationMenu.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/core/ContextMenu.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/core/Paths.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/core/menuRoles.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/ApplicationEvents.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/event.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/eventEmitter.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/trayEvents.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/webviewEvents.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/events/windowEvents.ts +0 -0
- /package/dist/api/{bun → sdks/bun}/proc/linux.md +0 -0
|
@@ -2,14 +2,12 @@ import { ffi, type MenuItemConfig, type Rectangle } from "../proc/native";
|
|
|
2
2
|
import electrobunEventEmitter from "../events/eventEmitter";
|
|
3
3
|
import { VIEWS_FOLDER } from "./Paths";
|
|
4
4
|
import { join } from "path";
|
|
5
|
-
import { type Pointer } from "bun:ffi";
|
|
6
5
|
|
|
7
6
|
type NonDividerMenuItem = Exclude<
|
|
8
7
|
MenuItemConfig,
|
|
9
8
|
{ type: "divider" | "separator" }
|
|
10
9
|
>;
|
|
11
10
|
|
|
12
|
-
let nextTrayId = 1;
|
|
13
11
|
const TrayMap: { [id: number]: Tray } = {};
|
|
14
12
|
|
|
15
13
|
export type TrayOptions = {
|
|
@@ -21,9 +19,8 @@ export type TrayOptions = {
|
|
|
21
19
|
};
|
|
22
20
|
|
|
23
21
|
export class Tray {
|
|
24
|
-
id
|
|
25
|
-
|
|
26
|
-
visible = true;
|
|
22
|
+
id = 0;
|
|
23
|
+
visible = false;
|
|
27
24
|
title = "";
|
|
28
25
|
image = "";
|
|
29
26
|
template = true;
|
|
@@ -44,36 +41,35 @@ export class Tray {
|
|
|
44
41
|
this.width = width;
|
|
45
42
|
this.height = height;
|
|
46
43
|
|
|
47
|
-
this.createNativeTray()
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
if (this.createNativeTray()) {
|
|
45
|
+
TrayMap[this.id] = this;
|
|
46
|
+
}
|
|
50
47
|
}
|
|
51
48
|
|
|
52
|
-
private createNativeTray() {
|
|
49
|
+
private createNativeTray(): boolean {
|
|
53
50
|
try {
|
|
54
|
-
|
|
55
|
-
id: this.id,
|
|
51
|
+
const trayId = ffi.request.createTray({
|
|
56
52
|
title: this.title,
|
|
57
53
|
image: this.resolveImagePath(this.image),
|
|
58
54
|
template: this.template,
|
|
59
55
|
width: this.width,
|
|
60
56
|
height: this.height,
|
|
61
|
-
}) as
|
|
57
|
+
}) as number;
|
|
58
|
+
|
|
59
|
+
if (!trayId) {
|
|
60
|
+
throw new Error("Tray creation returned an invalid id");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.id = trayId;
|
|
62
64
|
this.visible = true;
|
|
65
|
+
return true;
|
|
63
66
|
} catch (error) {
|
|
64
67
|
console.warn("Tray creation failed:", error);
|
|
65
68
|
console.warn(
|
|
66
69
|
"System tray functionality may not be available on this platform",
|
|
67
70
|
);
|
|
68
|
-
this.ptr = null;
|
|
69
71
|
this.visible = false;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (this.ptr && this.menu) {
|
|
73
|
-
ffi.request.setTrayMenu({
|
|
74
|
-
id: this.id,
|
|
75
|
-
menuConfig: JSON.stringify(menuConfigWithDefaults(this.menu)),
|
|
76
|
-
});
|
|
72
|
+
return false;
|
|
77
73
|
}
|
|
78
74
|
}
|
|
79
75
|
|
|
@@ -88,13 +84,13 @@ export class Tray {
|
|
|
88
84
|
|
|
89
85
|
setTitle(title: string) {
|
|
90
86
|
this.title = title;
|
|
91
|
-
if (!this.
|
|
87
|
+
if (!this.id) return;
|
|
92
88
|
ffi.request.setTrayTitle({ id: this.id, title });
|
|
93
89
|
}
|
|
94
90
|
|
|
95
91
|
setImage(imgPath: string) {
|
|
96
92
|
this.image = imgPath;
|
|
97
|
-
if (!this.
|
|
93
|
+
if (!this.id) return;
|
|
98
94
|
ffi.request.setTrayImage({
|
|
99
95
|
id: this.id,
|
|
100
96
|
image: this.resolveImagePath(imgPath),
|
|
@@ -103,7 +99,7 @@ export class Tray {
|
|
|
103
99
|
|
|
104
100
|
setMenu(menu: Array<MenuItemConfig>) {
|
|
105
101
|
this.menu = menu;
|
|
106
|
-
if (!this.
|
|
102
|
+
if (!this.id) return;
|
|
107
103
|
const menuWithDefaults = menuConfigWithDefaults(menu);
|
|
108
104
|
ffi.request.setTrayMenu({
|
|
109
105
|
id: this.id,
|
|
@@ -122,15 +118,19 @@ export class Tray {
|
|
|
122
118
|
}
|
|
123
119
|
|
|
124
120
|
if (!visible) {
|
|
125
|
-
if (this.
|
|
126
|
-
ffi.request.removeTray({ id: this.id });
|
|
127
|
-
this.ptr = null;
|
|
128
|
-
}
|
|
121
|
+
if (this.id) ffi.request.hideTray({ id: this.id });
|
|
129
122
|
this.visible = false;
|
|
130
123
|
return;
|
|
131
124
|
}
|
|
132
125
|
|
|
133
|
-
this.
|
|
126
|
+
if (!this.id) {
|
|
127
|
+
if (this.createNativeTray()) {
|
|
128
|
+
TrayMap[this.id] = this;
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.visible = ffi.request.showTray({ id: this.id }) as boolean;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
getBounds(): Rectangle {
|
|
@@ -139,12 +139,13 @@ export class Tray {
|
|
|
139
139
|
|
|
140
140
|
remove() {
|
|
141
141
|
console.log("Tray.remove() called for id:", this.id);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
const trayId = this.id;
|
|
143
|
+
if (trayId) {
|
|
144
|
+
ffi.request.removeTray({ id: trayId });
|
|
145
145
|
}
|
|
146
146
|
this.visible = false;
|
|
147
|
-
delete TrayMap[
|
|
147
|
+
delete TrayMap[trayId];
|
|
148
|
+
this.id = 0;
|
|
148
149
|
console.log("Tray removed from TrayMap");
|
|
149
150
|
}
|
|
150
151
|
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
readdirSync,
|
|
10
10
|
} from "fs";
|
|
11
11
|
import { execSync } from "child_process";
|
|
12
|
-
import { OS as currentOS, ARCH as currentArch } from "
|
|
13
|
-
import { getPlatformPrefix, getTarballFileName } from "
|
|
12
|
+
import { OS as currentOS, ARCH as currentArch } from "../../../shared/platform";
|
|
13
|
+
import { getPlatformPrefix, getTarballFileName } from "../../../shared/naming";
|
|
14
14
|
import { quit } from "./Utils";
|
|
15
15
|
|
|
16
16
|
// Update status types for granular progress tracking
|
|
@@ -855,7 +855,7 @@ const Updater = {
|
|
|
855
855
|
} else if (currentOS === "win") {
|
|
856
856
|
// On Windows, the actual app is inside a subdirectory.
|
|
857
857
|
// version.json's `name` field already contains the formatted app
|
|
858
|
-
// file name (e.g. "MyApp-canary" for
|
|
858
|
+
// file name (e.g. "MyApp-canary" for canary, "MyApp" for production),
|
|
859
859
|
// so don't re-apply getAppFileName or it doubles the channel suffix.
|
|
860
860
|
newAppBundlePath = join(extractionDir, localInfo.name);
|
|
861
861
|
|
|
@@ -934,9 +934,9 @@ const Updater = {
|
|
|
934
934
|
}
|
|
935
935
|
|
|
936
936
|
// Also ensure other binaries are executable
|
|
937
|
-
const
|
|
938
|
-
if (statSync(
|
|
939
|
-
execSync(`chmod +x "${
|
|
937
|
+
const cottontailPath = join(appBundleDir, "bin", "cottontail");
|
|
938
|
+
if (statSync(cottontailPath, { throwIfNoEntry: false })) {
|
|
939
|
+
execSync(`chmod +x "${cottontailPath}"`);
|
|
940
940
|
}
|
|
941
941
|
}
|
|
942
942
|
|
|
@@ -974,13 +974,13 @@ const Updater = {
|
|
|
974
974
|
setlocal
|
|
975
975
|
|
|
976
976
|
:: Wait for the app and any CEF helper processes to fully exit.
|
|
977
|
-
:: launcher.exe spawns
|
|
977
|
+
:: launcher.exe spawns cottontail.exe and "main Helper*.exe" processes that
|
|
978
978
|
:: keep libcef.dll locked; if we proceed too early, rmdir partially fails.
|
|
979
979
|
:waitloop
|
|
980
980
|
tasklist /FI "IMAGENAME eq launcher.exe" 2>NUL | find /I /N "launcher.exe">NUL && goto waitsleep
|
|
981
|
-
tasklist /FI "IMAGENAME eq
|
|
982
|
-
tasklist /FI "IMAGENAME eq
|
|
983
|
-
tasklist 2>NUL | find /I "
|
|
981
|
+
tasklist /FI "IMAGENAME eq cottontail.exe" 2>NUL | find /I /N "cottontail.exe">NUL && goto waitsleep
|
|
982
|
+
tasklist /FI "IMAGENAME eq main Helper.exe" 2>NUL | find /I /N "main Helper.exe">NUL && goto waitsleep
|
|
983
|
+
tasklist 2>NUL | find /I "main Helper">NUL && goto waitsleep
|
|
984
984
|
goto waitdone
|
|
985
985
|
:waitsleep
|
|
986
986
|
timeout /t 1 /nobreak >nul
|
|
@@ -3,7 +3,7 @@ import { electrobunEventEmitter } from "../events/eventEmitter";
|
|
|
3
3
|
import { homedir, tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { readFileSync } from "node:fs";
|
|
6
|
-
import { OS } from "
|
|
6
|
+
import { OS } from "../../../shared/platform";
|
|
7
7
|
|
|
8
8
|
export const moveToTrash = (path: string) => {
|
|
9
9
|
return ffi.request.moveToTrash({ path });
|
|
@@ -137,9 +137,7 @@ export const quit = () => {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
if (native) {
|
|
140
|
-
|
|
141
|
-
native.symbols.waitForShutdownComplete(5000);
|
|
142
|
-
native.symbols.forceExit(0);
|
|
140
|
+
ffi.request.quitGracefully({ code: 0, timeoutMs: 5000 });
|
|
143
141
|
} else {
|
|
144
142
|
process.exit(0);
|
|
145
143
|
}
|
|
@@ -150,7 +148,7 @@ const _originalProcessExit = process.exit;
|
|
|
150
148
|
process.exit = ((code?: number) => {
|
|
151
149
|
if (native) {
|
|
152
150
|
if (isQuitting) {
|
|
153
|
-
|
|
151
|
+
ffi.request.quitGracefully({ code: code ?? 0, timeoutMs: 0 });
|
|
154
152
|
return;
|
|
155
153
|
}
|
|
156
154
|
quit();
|
|
@@ -6,8 +6,6 @@ const WGPUViewMap: {
|
|
|
6
6
|
[id: number]: WGPUView;
|
|
7
7
|
} = {};
|
|
8
8
|
|
|
9
|
-
let nextWGPUViewId = 1;
|
|
10
|
-
|
|
11
9
|
export type WGPUViewOptions = {
|
|
12
10
|
frame: {
|
|
13
11
|
x: number;
|
|
@@ -34,8 +32,7 @@ const defaultOptions: Partial<WGPUViewOptions> = {
|
|
|
34
32
|
};
|
|
35
33
|
|
|
36
34
|
export class WGPUView {
|
|
37
|
-
id: number =
|
|
38
|
-
ptr!: Pointer;
|
|
35
|
+
id: number = 0;
|
|
39
36
|
windowId!: number;
|
|
40
37
|
autoResize: boolean = true;
|
|
41
38
|
frame: {
|
|
@@ -51,6 +48,14 @@ export class WGPUView {
|
|
|
51
48
|
};
|
|
52
49
|
startTransparent: boolean = false;
|
|
53
50
|
startPassthrough: boolean = false;
|
|
51
|
+
isRemoved: boolean = false;
|
|
52
|
+
|
|
53
|
+
get ptr(): Pointer | null {
|
|
54
|
+
if (this.isRemoved) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return ffi.request.getWGPUViewPointer({ id: this.id }) as Pointer | null;
|
|
58
|
+
}
|
|
54
59
|
|
|
55
60
|
constructor(options: Partial<WGPUViewOptions> = defaultOptions) {
|
|
56
61
|
this.frame = {
|
|
@@ -64,13 +69,12 @@ export class WGPUView {
|
|
|
64
69
|
this.startTransparent = options.startTransparent ?? false;
|
|
65
70
|
this.startPassthrough = options.startPassthrough ?? false;
|
|
66
71
|
|
|
72
|
+
this.id = this.init() as number;
|
|
67
73
|
WGPUViewMap[this.id] = this;
|
|
68
|
-
this.ptr = this.init() as Pointer;
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
init() {
|
|
72
77
|
return ffi.request.createWGPUView({
|
|
73
|
-
id: this.id,
|
|
74
78
|
windowId: this.windowId,
|
|
75
79
|
frame: {
|
|
76
80
|
width: this.frame.width,
|
|
@@ -107,20 +111,18 @@ export class WGPUView {
|
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
remove() {
|
|
110
|
-
|
|
111
|
-
if (this.ptr === null) {
|
|
114
|
+
if (this.isRemoved) {
|
|
112
115
|
return;
|
|
113
116
|
}
|
|
114
|
-
|
|
117
|
+
|
|
118
|
+
this.isRemoved = true;
|
|
119
|
+
delete WGPUViewMap[this.id];
|
|
120
|
+
|
|
115
121
|
try {
|
|
116
122
|
ffi.request.wgpuViewRemove({ id: this.id });
|
|
117
123
|
} catch (e) {
|
|
118
124
|
console.error(`Error removing WGPU view ${this.id}:`, e);
|
|
119
125
|
}
|
|
120
|
-
|
|
121
|
-
delete WGPUViewMap[this.id];
|
|
122
|
-
// Clear the pointer to prevent any accidental access
|
|
123
|
-
this.ptr = null as any;
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
getNativeHandle() {
|
|
@@ -131,6 +133,34 @@ export class WGPUView {
|
|
|
131
133
|
return WGPUViewMap[id];
|
|
132
134
|
}
|
|
133
135
|
|
|
136
|
+
static adoptExisting(id: number, options: Partial<WGPUViewOptions> = {}) {
|
|
137
|
+
const existing = WGPUViewMap[id];
|
|
138
|
+
if (existing) {
|
|
139
|
+
return existing;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const ptr = ffi.request.getWGPUViewPointer({ id }) as Pointer | null;
|
|
143
|
+
if (!ptr) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const view = Object.create(WGPUView.prototype) as WGPUView;
|
|
148
|
+
view.id = id;
|
|
149
|
+
view.windowId = options.windowId ?? 0;
|
|
150
|
+
view.autoResize = options.autoResize === false ? false : true;
|
|
151
|
+
view.frame = {
|
|
152
|
+
x: options.frame?.x ?? defaultOptions.frame!.x,
|
|
153
|
+
y: options.frame?.y ?? defaultOptions.frame!.y,
|
|
154
|
+
width: options.frame?.width ?? defaultOptions.frame!.width,
|
|
155
|
+
height: options.frame?.height ?? defaultOptions.frame!.height,
|
|
156
|
+
};
|
|
157
|
+
view.startTransparent = options.startTransparent ?? false;
|
|
158
|
+
view.startPassthrough = options.startPassthrough ?? false;
|
|
159
|
+
view.isRemoved = false;
|
|
160
|
+
WGPUViewMap[id] = view;
|
|
161
|
+
return view;
|
|
162
|
+
}
|
|
163
|
+
|
|
134
164
|
static getAll() {
|
|
135
165
|
return Object.values(WGPUViewMap);
|
|
136
166
|
}
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
type ElectrobunRPCSchema,
|
|
24
24
|
createRPC,
|
|
25
25
|
defineElectrobunRPC,
|
|
26
|
-
} from "
|
|
26
|
+
} from "../../shared/rpc.js";
|
|
27
27
|
import type ElectrobunEvent from "./events/event";
|
|
28
28
|
import * as PATHS from "./core/Paths";
|
|
29
29
|
import * as Socket from "./core/Socket";
|
|
@@ -31,7 +31,7 @@ import WGPU from "./webGPU";
|
|
|
31
31
|
import webgpu from "./webgpuAdapter";
|
|
32
32
|
import * as three from "three";
|
|
33
33
|
import * as babylon from "@babylonjs/core";
|
|
34
|
-
import type { ElectrobunConfig } from "
|
|
34
|
+
import type { ElectrobunConfig } from "../../config/ElectrobunConfig";
|
|
35
35
|
import { GlobalShortcut, Screen, Session, WGPUBridge } from "./proc/native";
|
|
36
36
|
import type {
|
|
37
37
|
Display,
|
|
@@ -48,7 +48,7 @@ import { bridge, hasFFI } from "./proc/native";
|
|
|
48
48
|
|
|
49
49
|
// Carrot boot state — populated from __bunnyCarrotBootstrap injected by Bunny Ears
|
|
50
50
|
let _carrotManifest: Record<string, unknown> | null = null;
|
|
51
|
-
let _carrotContext: { currentDir?: string; statePath?: string; logsPath?: string;
|
|
51
|
+
let _carrotContext: { currentDir?: string; statePath?: string; logsPath?: string; authToken?: string | null; channel?: string } | null = null;
|
|
52
52
|
|
|
53
53
|
const _bootstrap = (globalThis as any).__bunnyCarrotBootstrap as { manifest?: any; context?: any } | undefined;
|
|
54
54
|
if (_bootstrap) {
|
|
@@ -104,7 +104,21 @@ export const Carrots = {
|
|
|
104
104
|
if (!bridge) throw new Error("Carrots.list() is only available when running as a carrot inside Bunny Ears");
|
|
105
105
|
return bridge.requestHost<Array<{
|
|
106
106
|
id: string; name: string; description: string; version: string;
|
|
107
|
-
mode: string;
|
|
107
|
+
mode: string; status: string; devMode: boolean;
|
|
108
|
+
remoteUIs?: Array<{ id: string; name: string; path: string }>;
|
|
109
|
+
slateUIs?: Array<{ id: string; name: string; path: string }>;
|
|
110
|
+
contributions?: {
|
|
111
|
+
fileActivators?: Array<{
|
|
112
|
+
baseName?: string;
|
|
113
|
+
nodeType?: "file" | "dir" | "any";
|
|
114
|
+
slate: {
|
|
115
|
+
type: string;
|
|
116
|
+
name?: string;
|
|
117
|
+
icon?: string;
|
|
118
|
+
config?: Record<string, unknown>;
|
|
119
|
+
};
|
|
120
|
+
}>;
|
|
121
|
+
};
|
|
108
122
|
}>>("list-carrots");
|
|
109
123
|
},
|
|
110
124
|
async start(carrotId: string) {
|
|
@@ -134,12 +148,6 @@ export const app = {
|
|
|
134
148
|
get manifest() {
|
|
135
149
|
return _carrotManifest;
|
|
136
150
|
},
|
|
137
|
-
get permissions() {
|
|
138
|
-
return _carrotContext?.permissions ?? [];
|
|
139
|
-
},
|
|
140
|
-
get grantedPermissions() {
|
|
141
|
-
return _carrotContext?.grantedPermissions ?? {};
|
|
142
|
-
},
|
|
143
151
|
get currentDir() {
|
|
144
152
|
return _carrotContext?.currentDir ?? "";
|
|
145
153
|
},
|
|
@@ -167,6 +175,27 @@ export const app = {
|
|
|
167
175
|
_carrotContext.authToken = token;
|
|
168
176
|
}
|
|
169
177
|
},
|
|
178
|
+
async setDeviceToken(token: string, tokenId?: string): Promise<void> {
|
|
179
|
+
if (!bridge) return;
|
|
180
|
+
await bridge.requestHost("set-device-token", { token, tokenId });
|
|
181
|
+
},
|
|
182
|
+
async getMachineInfo(): Promise<{ machineId: string; hostname: string; platform: string }> {
|
|
183
|
+
if (!bridge) {
|
|
184
|
+
return { machineId: "", hostname: "", platform: "" };
|
|
185
|
+
}
|
|
186
|
+
return bridge.requestHost<{ machineId: string; hostname: string; platform: string }>(
|
|
187
|
+
"get-machine-info",
|
|
188
|
+
);
|
|
189
|
+
},
|
|
190
|
+
async updateCarrots(): Promise<void> {
|
|
191
|
+
if (!bridge) return;
|
|
192
|
+
await bridge.requestHost("update-carrots");
|
|
193
|
+
},
|
|
194
|
+
async getWebBridgePort(): Promise<number | null> {
|
|
195
|
+
if (!bridge) return null;
|
|
196
|
+
const result = await bridge.requestHost<{ port: number | null }>("get-web-bridge-port");
|
|
197
|
+
return typeof result?.port === "number" ? result.port : null;
|
|
198
|
+
},
|
|
170
199
|
get channel() {
|
|
171
200
|
return _carrotContext?.channel ?? "";
|
|
172
201
|
},
|