sparkbun 0.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/bin/sparkbun.cjs +18 -0
- package/dist-linux-arm64/bsdiff +0 -0
- package/dist-linux-arm64/bspatch +0 -0
- package/dist-linux-arm64/libElectrobunCore.so +0 -0
- package/dist-linux-arm64/libNativeWrapper.so +0 -0
- package/dist-linux-arm64/libasar.so +0 -0
- package/dist-linux-x64/bsdiff +0 -0
- package/dist-linux-x64/bspatch +0 -0
- package/dist-linux-x64/libElectrobunCore.so +0 -0
- package/dist-linux-x64/libNativeWrapper.so +0 -0
- package/dist-linux-x64/libasar.so +0 -0
- package/dist-macos-arm64/bsdiff +0 -0
- package/dist-macos-arm64/bspatch +0 -0
- package/dist-macos-arm64/libElectrobunCore.dylib +0 -0
- package/dist-macos-arm64/libNativeWrapper.dylib +0 -0
- package/dist-macos-arm64/libasar.dylib +0 -0
- package/dist-macos-arm64/libwebgpu_dawn.dylib +0 -0
- package/dist-macos-arm64/preload-full.js +885 -0
- package/dist-macos-arm64/preload-sandboxed.js +111 -0
- package/dist-macos-arm64/process_helper +0 -0
- package/dist-win-x64/ElectrobunCore.dll +0 -0
- package/dist-win-x64/WebView2Loader.dll +0 -0
- package/dist-win-x64/bsdiff.exe +0 -0
- package/dist-win-x64/bspatch.exe +0 -0
- package/dist-win-x64/libNativeWrapper.dll +0 -0
- package/dist-win-x64/zig-asar/arm64/libasar.dll +0 -0
- package/dist-win-x64/zig-asar/x64/libasar.dll +0 -0
- package/package.json +47 -0
- package/scripts/build-and-upload-artifacts.js +207 -0
- package/scripts/gen-webgpu-ffi.mjs +162 -0
- package/scripts/install-windows-deps.ps1 +80 -0
- package/scripts/package-release.js +237 -0
- package/scripts/push-version.js +84 -0
- package/scripts/update-bun-version.ts +122 -0
- package/scripts/update-cef-version.ts +145 -0
- package/src/browser/builtinrpcSchema.ts +19 -0
- package/src/browser/global.d.ts +36 -0
- package/src/browser/index.ts +234 -0
- package/src/browser/webviewtag.ts +88 -0
- package/src/browser/wgputag.ts +48 -0
- package/src/bun/SparkBunConfig.ts +497 -0
- package/src/bun/__tests__/ffi-contract.test.ts +105 -0
- package/src/bun/core/ApplicationMenu.ts +70 -0
- package/src/bun/core/BrowserView.ts +416 -0
- package/src/bun/core/BrowserWindow.ts +396 -0
- package/src/bun/core/BuildConfig.ts +71 -0
- package/src/bun/core/ContextMenu.ts +75 -0
- package/src/bun/core/GpuWindow.ts +289 -0
- package/src/bun/core/Paths.ts +5 -0
- package/src/bun/core/Socket.ts +22 -0
- package/src/bun/core/Tray.ts +197 -0
- package/src/bun/core/Updater.ts +1131 -0
- package/src/bun/core/Utils.ts +487 -0
- package/src/bun/core/WGPUView.ts +167 -0
- package/src/bun/core/menuRoles.ts +181 -0
- package/src/bun/events/ApplicationEvents.ts +22 -0
- package/src/bun/events/event.ts +27 -0
- package/src/bun/events/eventEmitter.ts +45 -0
- package/src/bun/events/trayEvents.ts +11 -0
- package/src/bun/events/webviewEvents.ts +39 -0
- package/src/bun/events/windowEvents.ts +23 -0
- package/src/bun/index.ts +120 -0
- package/src/bun/preload/.generated/compiled.ts +2 -0
- package/src/bun/preload/build.ts +65 -0
- package/src/bun/preload/dragRegions.ts +41 -0
- package/src/bun/preload/encryption.ts +86 -0
- package/src/bun/preload/events.ts +171 -0
- package/src/bun/preload/globals.d.ts +45 -0
- package/src/bun/preload/index-sandboxed.ts +28 -0
- package/src/bun/preload/index.ts +77 -0
- package/src/bun/preload/internalRpc.ts +80 -0
- package/src/bun/preload/overlaySync.ts +107 -0
- package/src/bun/preload/webviewTag.ts +451 -0
- package/src/bun/preload/wgpuTag.ts +246 -0
- package/src/bun/proc/linux.md +43 -0
- package/src/bun/proc/native.ts +3253 -0
- package/src/bun/webGPU.ts +346 -0
- package/src/bun/webgpuAdapter.ts +3011 -0
- package/src/cli/bun.lockb +0 -0
- package/src/cli/index.ts +4653 -0
- package/src/cli/package-lock.json +81 -0
- package/src/cli/package.json +11 -0
- package/src/cli/templates/embedded.ts +2 -0
- package/src/core/build.zig +16 -0
- package/src/core/main.zig +3378 -0
- package/src/extractor/build.zig +22 -0
- package/src/installer/installer-template.ts +216 -0
- package/src/launcher/main.ts +221 -0
- package/src/native/build/libNativeWrapper.so +0 -0
- package/src/native/linux/build/nativeWrapper.o +0 -0
- package/src/native/linux/cef_loader.cpp +110 -0
- package/src/native/linux/cef_loader.h +28 -0
- package/src/native/linux/cef_process_helper_linux.cpp +160 -0
- package/src/native/linux/nativeWrapper.cpp +11768 -0
- package/src/native/macos/cef_process_helper_mac.cc +160 -0
- package/src/native/macos/nativeWrapper.mm +9172 -0
- package/src/native/shared/accelerator_parser.h +72 -0
- package/src/native/shared/app_paths.h +110 -0
- package/src/native/shared/asar.h +35 -0
- package/src/native/shared/cache_migration.h +244 -0
- package/src/native/shared/callbacks.h +57 -0
- package/src/native/shared/cef_response_filter.h +189 -0
- package/src/native/shared/chromium_flags.h +181 -0
- package/src/native/shared/config.h +66 -0
- package/src/native/shared/download_event.h +197 -0
- package/src/native/shared/ffi_helpers.h +139 -0
- package/src/native/shared/glob_match.h +59 -0
- package/src/native/shared/json_menu_parser.h +223 -0
- package/src/native/shared/mime_types.h +101 -0
- package/src/native/shared/navigation_rules.h +98 -0
- package/src/native/shared/partition_context.h +137 -0
- package/src/native/shared/pending_resize_queue.h +45 -0
- package/src/native/shared/permissions.h +118 -0
- package/src/native/shared/permissions_cef.h +74 -0
- package/src/native/shared/preload_script.h +71 -0
- package/src/native/shared/shutdown_guard.h +134 -0
- package/src/native/shared/thread_safe_map.h +138 -0
- package/src/native/shared/webview_storage.h +91 -0
- package/src/native/win/cef_process_helper_win.cpp +143 -0
- package/src/native/win/dcomp_compositor.h +352 -0
- package/src/native/win/nativeWrapper.cpp +12434 -0
- package/src/npmbin/index.js +34 -0
- package/src/shared/bun-version.ts +3 -0
- package/src/shared/cef-version.ts +5 -0
- package/src/shared/naming.test.ts +327 -0
- package/src/shared/naming.ts +188 -0
- package/src/shared/platform.ts +48 -0
- package/src/shared/rpc.ts +541 -0
- package/src/shared/sparkbun-version.ts +2 -0
- package/src/types/three.d.ts +1 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { platform } from "os";
|
|
4
|
+
import { join, dirname } from "path";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
import { spawnSync } from "child_process";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
|
|
9
|
+
// Since this is sometimes run from a developer's package.json and sometimes from
|
|
10
|
+
// electrobun's playground package.json script by the root electrobun repo's package.json script
|
|
11
|
+
// we need to get the path to this file
|
|
12
|
+
|
|
13
|
+
// Get the nearest node_modules folder
|
|
14
|
+
// process.argv[1]:
|
|
15
|
+
/// macos: /Users/yoav/code/electrobun/playground/node_modules/.bin/electrobun
|
|
16
|
+
/// win: C:\Users\Yoav\code\electrobun\playground\node_modules\electrobun\dist\npmbin.js
|
|
17
|
+
const nodeModules = process.argv[1].split("node_modules")[0] + "node_modules";
|
|
18
|
+
const electrobunDir = join(nodeModules, "electrobun");
|
|
19
|
+
|
|
20
|
+
const DEV_CLI_PATH = join(
|
|
21
|
+
electrobunDir,
|
|
22
|
+
"dist",
|
|
23
|
+
platform() === "win32" ? "electrobun.exe" : "electrobun",
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
async function main() {
|
|
27
|
+
// For electrobun development, use local binary
|
|
28
|
+
if (existsSync(DEV_CLI_PATH)) {
|
|
29
|
+
spawnSync(DEV_CLI_PATH, process.argv.slice(2), { stdio: "inherit" });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Default CEF version shipped with this SparkBun release.
|
|
2
|
+
// All platforms use the same version. Update this single pair when bumping CEF.
|
|
3
|
+
export const CEF_VERSION = `147.0.10+gd58e84d`;
|
|
4
|
+
export const CHROMIUM_VERSION = `147.0.7727.118`;
|
|
5
|
+
export const DEFAULT_CEF_VERSION_STRING = `${CEF_VERSION}+chromium-${CHROMIUM_VERSION}`;
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
sanitizeAppName,
|
|
4
|
+
getAppFileName,
|
|
5
|
+
getBundleFileName,
|
|
6
|
+
getPlatformPrefix,
|
|
7
|
+
getTarballFileName,
|
|
8
|
+
getWindowsSetupFileName,
|
|
9
|
+
getLinuxAppImageBaseName,
|
|
10
|
+
getLinuxAppImageFileName,
|
|
11
|
+
sanitizeVolumeNameForHdiutil,
|
|
12
|
+
getDmgVolumeName,
|
|
13
|
+
getUpdateInfoUrl,
|
|
14
|
+
getPatchFileUrl,
|
|
15
|
+
getTarballUrl,
|
|
16
|
+
} from "./naming";
|
|
17
|
+
|
|
18
|
+
describe("sanitizeAppName", () => {
|
|
19
|
+
it("removes spaces from app name", () => {
|
|
20
|
+
expect(sanitizeAppName("My App")).toBe("MyApp");
|
|
21
|
+
expect(sanitizeAppName("My Multi Spaced App")).toBe("MyMultiSpacedApp");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("preserves names without spaces", () => {
|
|
25
|
+
expect(sanitizeAppName("MyApp")).toBe("MyApp");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("handles empty string", () => {
|
|
29
|
+
expect(sanitizeAppName("")).toBe("");
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("getAppFileName", () => {
|
|
34
|
+
it("returns sanitized name without suffix for stable builds", () => {
|
|
35
|
+
expect(getAppFileName("My App", "stable")).toBe("MyApp");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("appends channel suffix for canary builds", () => {
|
|
39
|
+
expect(getAppFileName("My App", "canary")).toBe("MyApp-canary");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("appends channel suffix for dev builds", () => {
|
|
43
|
+
expect(getAppFileName("My App", "dev")).toBe("MyApp-dev");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("handles custom channels", () => {
|
|
47
|
+
expect(getAppFileName("My App", "beta")).toBe("MyApp-beta");
|
|
48
|
+
expect(getAppFileName("My App", "nightly")).toBe("MyApp-nightly");
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("getBundleFileName", () => {
|
|
53
|
+
describe("macOS", () => {
|
|
54
|
+
it("adds .app extension for stable builds", () => {
|
|
55
|
+
expect(getBundleFileName("My App", "stable", "macos")).toBe("MyApp.app");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("adds .app extension for canary builds", () => {
|
|
59
|
+
expect(getBundleFileName("My App", "canary", "macos")).toBe(
|
|
60
|
+
"MyApp-canary.app",
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("Windows", () => {
|
|
66
|
+
it("returns plain name for stable builds", () => {
|
|
67
|
+
expect(getBundleFileName("My App", "stable", "win")).toBe("MyApp");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("returns plain name with suffix for canary builds", () => {
|
|
71
|
+
expect(getBundleFileName("My App", "canary", "win")).toBe("MyApp-canary");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("Linux", () => {
|
|
76
|
+
it("returns plain name for stable builds", () => {
|
|
77
|
+
expect(getBundleFileName("My App", "stable", "linux")).toBe("MyApp");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("returns plain name with suffix for canary builds", () => {
|
|
81
|
+
expect(getBundleFileName("My App", "canary", "linux")).toBe(
|
|
82
|
+
"MyApp-canary",
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("getPlatformPrefix", () => {
|
|
89
|
+
it("constructs correct prefix format for all platform combinations", () => {
|
|
90
|
+
expect(getPlatformPrefix("stable", "macos", "arm64")).toBe(
|
|
91
|
+
"stable-macos-arm64",
|
|
92
|
+
);
|
|
93
|
+
expect(getPlatformPrefix("stable", "macos", "x64")).toBe(
|
|
94
|
+
"stable-macos-x64",
|
|
95
|
+
);
|
|
96
|
+
expect(getPlatformPrefix("canary", "win", "x64")).toBe("canary-win-x64");
|
|
97
|
+
expect(getPlatformPrefix("dev", "linux", "arm64")).toBe("dev-linux-arm64");
|
|
98
|
+
expect(getPlatformPrefix("dev", "linux", "x64")).toBe("dev-linux-x64");
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("getTarballFileName", () => {
|
|
103
|
+
describe("macOS", () => {
|
|
104
|
+
it("uses .app.tar.gz extension", () => {
|
|
105
|
+
expect(getTarballFileName("MyApp", "macos")).toBe("MyApp.app.tar.gz");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("preserves channel suffix in filename", () => {
|
|
109
|
+
expect(getTarballFileName("MyApp-canary", "macos")).toBe(
|
|
110
|
+
"MyApp-canary.app.tar.gz",
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe("Windows", () => {
|
|
116
|
+
it("uses .tar.gz extension", () => {
|
|
117
|
+
expect(getTarballFileName("MyApp", "win")).toBe("MyApp.tar.gz");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("preserves channel suffix in filename", () => {
|
|
121
|
+
expect(getTarballFileName("MyApp-canary", "win")).toBe(
|
|
122
|
+
"MyApp-canary.tar.gz",
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe("Linux", () => {
|
|
128
|
+
it("uses .tar.gz extension", () => {
|
|
129
|
+
expect(getTarballFileName("MyApp", "linux")).toBe("MyApp.tar.gz");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("preserves channel suffix in filename", () => {
|
|
133
|
+
expect(getTarballFileName("MyApp-canary", "linux")).toBe(
|
|
134
|
+
"MyApp-canary.tar.gz",
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe("getWindowsSetupFileName", () => {
|
|
141
|
+
it("returns AppName.exe for stable builds", () => {
|
|
142
|
+
expect(getWindowsSetupFileName("MyApp", "stable")).toBe("MyApp.exe");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("includes channel suffix for canary builds", () => {
|
|
146
|
+
expect(getWindowsSetupFileName("MyApp", "canary")).toBe(
|
|
147
|
+
"MyApp-canary.exe",
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("includes channel suffix for dev builds", () => {
|
|
152
|
+
expect(getWindowsSetupFileName("MyApp", "dev")).toBe("MyApp-dev.exe");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("preserves spaces in app name", () => {
|
|
156
|
+
expect(getWindowsSetupFileName("My App", "stable")).toBe(
|
|
157
|
+
"My App.exe",
|
|
158
|
+
);
|
|
159
|
+
expect(getWindowsSetupFileName("My App", "canary")).toBe(
|
|
160
|
+
"My App-canary.exe",
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("getLinuxAppImageBaseName", () => {
|
|
166
|
+
it("returns AppName-Setup for stable builds", () => {
|
|
167
|
+
expect(getLinuxAppImageBaseName("MyApp", "stable")).toBe("MyApp-Setup");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("includes channel suffix for canary builds", () => {
|
|
171
|
+
expect(getLinuxAppImageBaseName("MyApp", "canary")).toBe(
|
|
172
|
+
"MyApp-Setup-canary",
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("preserves spaces in app name", () => {
|
|
177
|
+
expect(getLinuxAppImageBaseName("My App", "stable")).toBe("My App-Setup");
|
|
178
|
+
expect(getLinuxAppImageBaseName("My App", "canary")).toBe(
|
|
179
|
+
"My App-Setup-canary",
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe("getLinuxAppImageFileName", () => {
|
|
185
|
+
it("returns full filename with .AppImage extension for stable", () => {
|
|
186
|
+
expect(getLinuxAppImageFileName("MyApp", "stable")).toBe(
|
|
187
|
+
"MyApp-Setup.AppImage",
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("returns full filename with .AppImage extension for canary", () => {
|
|
192
|
+
expect(getLinuxAppImageFileName("MyApp", "canary")).toBe(
|
|
193
|
+
"MyApp-Setup-canary.AppImage",
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("preserves spaces in app name", () => {
|
|
198
|
+
expect(getLinuxAppImageFileName("My App", "stable")).toBe(
|
|
199
|
+
"My App-Setup.AppImage",
|
|
200
|
+
);
|
|
201
|
+
expect(getLinuxAppImageFileName("My App", "canary")).toBe(
|
|
202
|
+
"My App-Setup-canary.AppImage",
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe("sanitizeVolumeNameForHdiutil", () => {
|
|
208
|
+
it("removes special characters", () => {
|
|
209
|
+
expect(sanitizeVolumeNameForHdiutil("My-App_v1.0")).toBe("MyAppv10");
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("removes parentheses and other punctuation", () => {
|
|
213
|
+
expect(sanitizeVolumeNameForHdiutil("My App (Beta)")).toBe("My App Beta");
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("preserves spaces and alphanumerics", () => {
|
|
217
|
+
expect(sanitizeVolumeNameForHdiutil("My App 2024")).toBe("My App 2024");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("trims leading and trailing whitespace", () => {
|
|
221
|
+
expect(sanitizeVolumeNameForHdiutil(" My App ")).toBe("My App");
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("handles names with only special characters", () => {
|
|
225
|
+
expect(sanitizeVolumeNameForHdiutil("---")).toBe("");
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("getDmgVolumeName", () => {
|
|
230
|
+
it("returns plain name for stable builds", () => {
|
|
231
|
+
expect(getDmgVolumeName("MyApp", "stable")).toBe("MyApp");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("adds channel suffix for non-stable builds", () => {
|
|
235
|
+
expect(getDmgVolumeName("MyApp", "canary")).toBe("MyApp-canary");
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("sanitizes special characters", () => {
|
|
239
|
+
expect(getDmgVolumeName("My-App", "stable")).toBe("MyApp");
|
|
240
|
+
expect(getDmgVolumeName("My-App", "canary")).toBe("MyApp-canary");
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe("URL construction functions", () => {
|
|
245
|
+
const baseUrl = "https://storage.example.com/releases";
|
|
246
|
+
const platformPrefix = "canary-macos-arm64";
|
|
247
|
+
|
|
248
|
+
describe("getUpdateInfoUrl", () => {
|
|
249
|
+
it("constructs correct flat URL with prefix", () => {
|
|
250
|
+
expect(getUpdateInfoUrl(baseUrl, platformPrefix)).toBe(
|
|
251
|
+
"https://storage.example.com/releases/canary-macos-arm64-update.json",
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("handles bucket URLs with trailing content", () => {
|
|
256
|
+
expect(
|
|
257
|
+
getUpdateInfoUrl("https://example.com/bucket", "stable-win-x64"),
|
|
258
|
+
).toBe("https://example.com/bucket/stable-win-x64-update.json");
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe("getPatchFileUrl", () => {
|
|
263
|
+
it("constructs correct flat URL with prefix and hash", () => {
|
|
264
|
+
expect(getPatchFileUrl(baseUrl, platformPrefix, "abc123def456")).toBe(
|
|
265
|
+
"https://storage.example.com/releases/canary-macos-arm64-abc123def456.patch",
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
describe("getTarballUrl", () => {
|
|
271
|
+
it("constructs correct flat URL for macOS tarball", () => {
|
|
272
|
+
expect(getTarballUrl(baseUrl, platformPrefix, "MyApp.app.tar.gz")).toBe(
|
|
273
|
+
"https://storage.example.com/releases/canary-macos-arm64-MyApp.app.tar.gz",
|
|
274
|
+
);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("constructs correct flat URL for Windows tarball", () => {
|
|
278
|
+
expect(getTarballUrl(baseUrl, "stable-win-x64", "MyApp.tar.gz")).toBe(
|
|
279
|
+
"https://storage.example.com/releases/stable-win-x64-MyApp.tar.gz",
|
|
280
|
+
);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Integration tests that verify CLI and Updater would produce matching values
|
|
286
|
+
describe("CLI and Updater consistency", () => {
|
|
287
|
+
it("produces matching platform prefixes", () => {
|
|
288
|
+
// CLI uses: `${buildEnvironment}-${currentTarget.os}-${currentTarget.arch}`
|
|
289
|
+
// Updater uses: `${localInfo.channel}-${currentOS}-${currentArch}`
|
|
290
|
+
// Both should use getPlatformPrefix()
|
|
291
|
+
const cliResult = getPlatformPrefix("canary", "macos", "arm64");
|
|
292
|
+
const updaterResult = getPlatformPrefix("canary", "macos", "arm64");
|
|
293
|
+
expect(cliResult).toBe(updaterResult);
|
|
294
|
+
expect(cliResult).toBe("canary-macos-arm64");
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("produces matching tarball names for macOS", () => {
|
|
298
|
+
const appFileName = getAppFileName("My App", "canary");
|
|
299
|
+
const tarballName = getTarballFileName(appFileName, "macos");
|
|
300
|
+
expect(tarballName).toBe("MyApp-canary.app.tar.gz");
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("produces matching tarball names for Windows", () => {
|
|
304
|
+
const appFileName = getAppFileName("My App", "stable");
|
|
305
|
+
const tarballName = getTarballFileName(appFileName, "win");
|
|
306
|
+
expect(tarballName).toBe("MyApp.tar.gz");
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("produces matching tarball names for Linux", () => {
|
|
310
|
+
const appFileName = getAppFileName("My App", "dev");
|
|
311
|
+
const tarballName = getTarballFileName(appFileName, "linux");
|
|
312
|
+
expect(tarballName).toBe("MyApp-dev.tar.gz");
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it("stable builds have no channel suffix in artifact names", () => {
|
|
316
|
+
// This is the regression test for the -stable bug
|
|
317
|
+
expect(getAppFileName("MyApp", "stable")).toBe("MyApp");
|
|
318
|
+
expect(getAppFileName("MyApp", "stable")).not.toContain("-stable");
|
|
319
|
+
expect(getTarballFileName(getAppFileName("MyApp", "stable"), "macos")).toBe(
|
|
320
|
+
"MyApp.app.tar.gz",
|
|
321
|
+
);
|
|
322
|
+
expect(getWindowsSetupFileName("MyApp", "stable")).toBe("MyApp.exe");
|
|
323
|
+
expect(getLinuxAppImageFileName("MyApp", "stable")).toBe(
|
|
324
|
+
"MyApp-Setup.AppImage",
|
|
325
|
+
);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import type { SupportedOS, SupportedArch } from "./platform";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build environment/channel types.
|
|
5
|
+
* "stable" is special - it produces artifacts without a channel suffix.
|
|
6
|
+
*/
|
|
7
|
+
export type BuildEnvironment = "stable" | "canary" | "dev" | (string & {});
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sanitizes an app name by removing spaces.
|
|
11
|
+
* Used as the base for all artifact naming.
|
|
12
|
+
*/
|
|
13
|
+
export function sanitizeAppName(appName: string): string {
|
|
14
|
+
return appName.replace(/ /g, "");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Generates the app file name based on build environment.
|
|
19
|
+
* Format: "AppName" (stable) or "AppName-channel" (non-stable)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* getAppFileName("My App", "stable") // "MyApp"
|
|
23
|
+
* getAppFileName("My App", "canary") // "MyApp-canary"
|
|
24
|
+
*/
|
|
25
|
+
export function getAppFileName(
|
|
26
|
+
appName: string,
|
|
27
|
+
buildEnvironment: BuildEnvironment,
|
|
28
|
+
): string {
|
|
29
|
+
const sanitized = sanitizeAppName(appName);
|
|
30
|
+
return buildEnvironment === "stable"
|
|
31
|
+
? sanitized
|
|
32
|
+
: `${sanitized}-${buildEnvironment}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Generates the macOS bundle display name (with spaces preserved).
|
|
37
|
+
* Used for the actual .app folder name on macOS.
|
|
38
|
+
* Format: "App Name" (stable) or "App Name-channel" (non-stable)
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* getMacOSBundleDisplayName("My App", "stable") // "My App"
|
|
42
|
+
* getMacOSBundleDisplayName("My App", "canary") // "My App-canary"
|
|
43
|
+
*/
|
|
44
|
+
export function getMacOSBundleDisplayName(
|
|
45
|
+
appName: string,
|
|
46
|
+
buildEnvironment: BuildEnvironment,
|
|
47
|
+
): string {
|
|
48
|
+
return buildEnvironment === "stable"
|
|
49
|
+
? appName
|
|
50
|
+
: `${appName}-${buildEnvironment}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Generates the bundle file name (with platform-specific extension).
|
|
55
|
+
* macOS: "AppName.app" or "AppName-channel.app"
|
|
56
|
+
* Others: "AppName" or "AppName-channel"
|
|
57
|
+
*/
|
|
58
|
+
export function getBundleFileName(
|
|
59
|
+
appName: string,
|
|
60
|
+
buildEnvironment: BuildEnvironment,
|
|
61
|
+
os: SupportedOS,
|
|
62
|
+
): string {
|
|
63
|
+
const appFileName = getAppFileName(appName, buildEnvironment);
|
|
64
|
+
return os === "macos" ? `${appFileName}.app` : appFileName;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Generates the platform prefix for artifacts.
|
|
69
|
+
* Format: "channel-os-arch" (e.g., "stable-macos-arm64", "canary-win-x64")
|
|
70
|
+
* Used for flat file naming in artifact folders and bucket URLs.
|
|
71
|
+
*/
|
|
72
|
+
export function getPlatformPrefix(
|
|
73
|
+
buildEnvironment: BuildEnvironment,
|
|
74
|
+
os: SupportedOS,
|
|
75
|
+
arch: SupportedArch,
|
|
76
|
+
): string {
|
|
77
|
+
return `${buildEnvironment}-${os}-${arch}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Generates the tarball file name for update distribution.
|
|
82
|
+
* macOS: "AppFileName.app.tar.gz"
|
|
83
|
+
* Others: "AppFileName.tar.gz"
|
|
84
|
+
*/
|
|
85
|
+
export function getTarballFileName(
|
|
86
|
+
appFileName: string,
|
|
87
|
+
os: SupportedOS,
|
|
88
|
+
): string {
|
|
89
|
+
return os === "macos"
|
|
90
|
+
? `${appFileName}.app.tar.gz`
|
|
91
|
+
: `${appFileName}.tar.gz`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Generates the Windows installer file name.
|
|
96
|
+
* Preserves spaces in app name for user-friendly display.
|
|
97
|
+
* Format: "App Name.exe" (stable) or "App Name-channel.exe" (non-stable)
|
|
98
|
+
*/
|
|
99
|
+
export function getWindowsSetupFileName(
|
|
100
|
+
appName: string,
|
|
101
|
+
buildEnvironment: BuildEnvironment,
|
|
102
|
+
): string {
|
|
103
|
+
return buildEnvironment === "stable"
|
|
104
|
+
? `${appName}.exe`
|
|
105
|
+
: `${appName}-${buildEnvironment}.exe`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Generates the Linux AppImage wrapper name (without extension).
|
|
110
|
+
* Preserves spaces in app name for user-friendly display.
|
|
111
|
+
* Format: "App Name-Setup" (stable) or "App Name-Setup-channel" (non-stable)
|
|
112
|
+
*/
|
|
113
|
+
export function getLinuxAppImageBaseName(
|
|
114
|
+
appName: string,
|
|
115
|
+
buildEnvironment: BuildEnvironment,
|
|
116
|
+
): string {
|
|
117
|
+
return buildEnvironment === "stable"
|
|
118
|
+
? `${appName}-Setup`
|
|
119
|
+
: `${appName}-Setup-${buildEnvironment}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Generates the full Linux AppImage file name.
|
|
124
|
+
*/
|
|
125
|
+
export function getLinuxAppImageFileName(
|
|
126
|
+
appName: string,
|
|
127
|
+
buildEnvironment: BuildEnvironment,
|
|
128
|
+
): string {
|
|
129
|
+
return `${getLinuxAppImageBaseName(appName, buildEnvironment)}.AppImage`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Sanitizes a volume name for hdiutil (macOS DMG creation).
|
|
134
|
+
* Removes all non-alphanumeric characters except spaces.
|
|
135
|
+
*/
|
|
136
|
+
export function sanitizeVolumeNameForHdiutil(name: string): string {
|
|
137
|
+
return name.replace(/[^a-zA-Z0-9 ]/g, "").trim();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Generates the DMG volume name for macOS.
|
|
142
|
+
* Takes the original app name (with spaces) and preserves them for display.
|
|
143
|
+
* Format: "App Name" (stable) or "App Name-channel" (non-stable)
|
|
144
|
+
*/
|
|
145
|
+
export function getDmgVolumeName(
|
|
146
|
+
appName: string,
|
|
147
|
+
buildEnvironment: BuildEnvironment,
|
|
148
|
+
): string {
|
|
149
|
+
const baseName = sanitizeVolumeNameForHdiutil(appName);
|
|
150
|
+
return buildEnvironment === "stable"
|
|
151
|
+
? baseName
|
|
152
|
+
: `${baseName}-${buildEnvironment}`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Constructs the full URL for the update.json file.
|
|
157
|
+
* Uses flat prefix-based naming for compatibility with GitHub Releases and other hosts.
|
|
158
|
+
*/
|
|
159
|
+
export function getUpdateInfoUrl(
|
|
160
|
+
baseUrl: string,
|
|
161
|
+
platformPrefix: string,
|
|
162
|
+
): string {
|
|
163
|
+
return `${baseUrl.replace(/\/+$/, "")}/${platformPrefix}-update.json`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Constructs the full URL for a patch file.
|
|
168
|
+
* Uses flat prefix-based naming for compatibility with GitHub Releases and other hosts.
|
|
169
|
+
*/
|
|
170
|
+
export function getPatchFileUrl(
|
|
171
|
+
baseUrl: string,
|
|
172
|
+
platformPrefix: string,
|
|
173
|
+
hash: string,
|
|
174
|
+
): string {
|
|
175
|
+
return `${baseUrl.replace(/\/+$/, "")}/${platformPrefix}-${hash}.patch`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Constructs the full URL for a tarball.
|
|
180
|
+
* Uses flat prefix-based naming for compatibility with GitHub Releases and other hosts.
|
|
181
|
+
*/
|
|
182
|
+
export function getTarballUrl(
|
|
183
|
+
baseUrl: string,
|
|
184
|
+
platformPrefix: string,
|
|
185
|
+
tarballFileName: string,
|
|
186
|
+
): string {
|
|
187
|
+
return `${baseUrl.replace(/\/+$/, "")}/${platformPrefix}-${tarballFileName}`;
|
|
188
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { platform, arch } from "os";
|
|
2
|
+
|
|
3
|
+
export type SupportedOS = "macos" | "win" | "linux";
|
|
4
|
+
export type SupportedArch = "arm64" | "x64";
|
|
5
|
+
|
|
6
|
+
// Cache platform() result to avoid multiple system calls
|
|
7
|
+
const platformName = platform();
|
|
8
|
+
const archName = arch();
|
|
9
|
+
|
|
10
|
+
// Determine OS once
|
|
11
|
+
export const OS: SupportedOS = (() => {
|
|
12
|
+
switch (platformName) {
|
|
13
|
+
case "win32":
|
|
14
|
+
return "win";
|
|
15
|
+
case "darwin":
|
|
16
|
+
return "macos";
|
|
17
|
+
case "linux":
|
|
18
|
+
return "linux";
|
|
19
|
+
default:
|
|
20
|
+
throw new Error(`Unsupported platform: ${platformName}`);
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
23
|
+
|
|
24
|
+
// Determine ARCH once, with Windows override
|
|
25
|
+
export const ARCH: SupportedArch = (() => {
|
|
26
|
+
// Always use x64 for Windows since we only build x64 Windows binaries
|
|
27
|
+
if (OS === "win") {
|
|
28
|
+
return "x64";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (archName) {
|
|
32
|
+
case "arm64":
|
|
33
|
+
return "arm64";
|
|
34
|
+
case "x64":
|
|
35
|
+
return "x64";
|
|
36
|
+
default:
|
|
37
|
+
throw new Error(`Unsupported architecture: ${archName}`);
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
|
|
41
|
+
// Export functions for backwards compatibility if needed
|
|
42
|
+
export function getPlatformOS(): SupportedOS {
|
|
43
|
+
return OS;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getPlatformArch(): SupportedArch {
|
|
47
|
+
return ARCH;
|
|
48
|
+
}
|