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,72 @@
|
|
|
1
|
+
// accelerator_parser.h - Cross-platform Electron-style accelerator string parser
|
|
2
|
+
// Parses strings like "CommandOrControl+Shift+T" into modifier flags and a key.
|
|
3
|
+
// Header-only to match the pattern of json_menu_parser.h.
|
|
4
|
+
|
|
5
|
+
#ifndef ELECTROBUN_ACCELERATOR_PARSER_H
|
|
6
|
+
#define ELECTROBUN_ACCELERATOR_PARSER_H
|
|
7
|
+
|
|
8
|
+
#include <string>
|
|
9
|
+
#include <vector>
|
|
10
|
+
#include <algorithm>
|
|
11
|
+
|
|
12
|
+
namespace electrobun {
|
|
13
|
+
|
|
14
|
+
struct AcceleratorParts {
|
|
15
|
+
std::string key; // The key, lowercased (e.g. "t", "f1", "space")
|
|
16
|
+
bool commandOrControl = false; // "commandorcontrol" or "cmdorctrl"
|
|
17
|
+
bool command = false; // "command" or "cmd"
|
|
18
|
+
bool control = false; // "control" or "ctrl"
|
|
19
|
+
bool alt = false; // "alt" or "option"
|
|
20
|
+
bool shift = false; // "shift"
|
|
21
|
+
bool super = false; // "super", "meta", or "win"
|
|
22
|
+
|
|
23
|
+
// True when the accelerator was a bare key with no modifier prefix.
|
|
24
|
+
bool isBareKey = false;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Parse an Electron-style accelerator string into its component parts.
|
|
28
|
+
// Modifier names are case-insensitive. The key is always lowercased.
|
|
29
|
+
inline AcceleratorParts parseAccelerator(const std::string& accelerator) {
|
|
30
|
+
AcceleratorParts result;
|
|
31
|
+
std::vector<std::string> parts;
|
|
32
|
+
|
|
33
|
+
// Split by '+'
|
|
34
|
+
size_t start = 0, end;
|
|
35
|
+
while ((end = accelerator.find('+', start)) != std::string::npos) {
|
|
36
|
+
parts.push_back(accelerator.substr(start, end - start));
|
|
37
|
+
start = end + 1;
|
|
38
|
+
}
|
|
39
|
+
parts.push_back(accelerator.substr(start));
|
|
40
|
+
|
|
41
|
+
// Last component is the key
|
|
42
|
+
result.key = parts.back();
|
|
43
|
+
std::transform(result.key.begin(), result.key.end(), result.key.begin(), ::tolower);
|
|
44
|
+
parts.pop_back();
|
|
45
|
+
|
|
46
|
+
result.isBareKey = parts.empty();
|
|
47
|
+
|
|
48
|
+
for (const auto& part : parts) {
|
|
49
|
+
std::string lower = part;
|
|
50
|
+
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
|
|
51
|
+
|
|
52
|
+
if (lower == "commandorcontrol" || lower == "cmdorctrl") {
|
|
53
|
+
result.commandOrControl = true;
|
|
54
|
+
} else if (lower == "command" || lower == "cmd") {
|
|
55
|
+
result.command = true;
|
|
56
|
+
} else if (lower == "control" || lower == "ctrl") {
|
|
57
|
+
result.control = true;
|
|
58
|
+
} else if (lower == "alt" || lower == "option") {
|
|
59
|
+
result.alt = true;
|
|
60
|
+
} else if (lower == "shift") {
|
|
61
|
+
result.shift = true;
|
|
62
|
+
} else if (lower == "super" || lower == "meta" || lower == "win") {
|
|
63
|
+
result.super = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
} // namespace electrobun
|
|
71
|
+
|
|
72
|
+
#endif // ELECTROBUN_ACCELERATOR_PARSER_H
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#ifndef ELECTROBUN_APP_PATHS_H
|
|
2
|
+
#define ELECTROBUN_APP_PATHS_H
|
|
3
|
+
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
namespace electrobun {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Build the app data path using identifier/channel structure.
|
|
10
|
+
* This ensures consistent path structure across all platforms and matches
|
|
11
|
+
* the CLI and updater conventions.
|
|
12
|
+
*
|
|
13
|
+
* @param basePath The base application support/data path (e.g., ~/Library/Application Support)
|
|
14
|
+
* @param identifier The app identifier (e.g., "sh.blackboard.electrobun-kitchen")
|
|
15
|
+
* @param channel The release channel (e.g., "dev", "canary", "stable")
|
|
16
|
+
* @param suffix Optional suffix to append (e.g., "CEF", "WebView2")
|
|
17
|
+
* @param pathSeparator The path separator to use ('/' for Unix, '\\' for Windows)
|
|
18
|
+
* @return The full path: basePath/identifier/channel/suffix
|
|
19
|
+
*/
|
|
20
|
+
inline std::string buildAppDataPath(
|
|
21
|
+
const std::string& basePath,
|
|
22
|
+
const std::string& identifier,
|
|
23
|
+
const std::string& channel,
|
|
24
|
+
const std::string& suffix = "",
|
|
25
|
+
char pathSeparator = '/'
|
|
26
|
+
) {
|
|
27
|
+
std::string appId = !identifier.empty() ? identifier : "Electrobun";
|
|
28
|
+
std::string channelPath = !channel.empty() ? channel : "default";
|
|
29
|
+
|
|
30
|
+
std::string result = basePath;
|
|
31
|
+
result += pathSeparator;
|
|
32
|
+
result += appId;
|
|
33
|
+
result += pathSeparator;
|
|
34
|
+
result += channelPath;
|
|
35
|
+
|
|
36
|
+
if (!suffix.empty()) {
|
|
37
|
+
result += pathSeparator;
|
|
38
|
+
result += suffix;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Build a partition-specific path under the app data directory.
|
|
46
|
+
*
|
|
47
|
+
* @param basePath The base application support/data path
|
|
48
|
+
* @param identifier The app identifier
|
|
49
|
+
* @param channel The release channel
|
|
50
|
+
* @param renderer The renderer type (e.g., "CEF", "WebView2", "WebKit")
|
|
51
|
+
* @param partitionName The partition name
|
|
52
|
+
* @param pathSeparator The path separator to use
|
|
53
|
+
* @return The full path: basePath/identifier/channel/renderer/Partitions/partitionName
|
|
54
|
+
*/
|
|
55
|
+
inline std::string buildPartitionPath(
|
|
56
|
+
const std::string& basePath,
|
|
57
|
+
const std::string& identifier,
|
|
58
|
+
const std::string& channel,
|
|
59
|
+
const std::string& renderer,
|
|
60
|
+
const std::string& partitionName,
|
|
61
|
+
char pathSeparator = '/'
|
|
62
|
+
) {
|
|
63
|
+
std::string base = buildAppDataPath(basePath, identifier, channel, renderer, pathSeparator);
|
|
64
|
+
base += pathSeparator;
|
|
65
|
+
base += "Partitions";
|
|
66
|
+
base += pathSeparator;
|
|
67
|
+
base += partitionName;
|
|
68
|
+
return base;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build a CEF partition-specific path under the renderer root.
|
|
73
|
+
*
|
|
74
|
+
* Partitions live in a `partitions/` subdirectory of the renderer cache root
|
|
75
|
+
* rather than directly under it. The renderer root itself is CefSettings.cache_path,
|
|
76
|
+
* which Chromium populates with auto-created profile directories such as
|
|
77
|
+
* `Default`, `System Profile`, etc. On case-insensitive filesystems (Windows
|
|
78
|
+
* NTFS, macOS APFS in default config) a partition literally named `default`
|
|
79
|
+
* would collide with that auto-created `Default` folder; CEF then refuses to
|
|
80
|
+
* bind a CefRequestContext to the colliding path and CreateBrowserSync
|
|
81
|
+
* silently returns null. Nesting under `partitions/` keeps user partitions
|
|
82
|
+
* cleanly separated from Chromium's own profile state.
|
|
83
|
+
*
|
|
84
|
+
* @param basePath The base application support/data path
|
|
85
|
+
* @param identifier The app identifier
|
|
86
|
+
* @param channel The release channel
|
|
87
|
+
* @param renderer The renderer type (typically "CEF")
|
|
88
|
+
* @param partitionName The partition name
|
|
89
|
+
* @param pathSeparator The path separator to use
|
|
90
|
+
* @return The full path: basePath/identifier/channel/renderer/partitions/partitionName
|
|
91
|
+
*/
|
|
92
|
+
inline std::string buildCEFPartitionPath(
|
|
93
|
+
const std::string& basePath,
|
|
94
|
+
const std::string& identifier,
|
|
95
|
+
const std::string& channel,
|
|
96
|
+
const std::string& renderer,
|
|
97
|
+
const std::string& partitionName,
|
|
98
|
+
char pathSeparator = '/'
|
|
99
|
+
) {
|
|
100
|
+
std::string base = buildAppDataPath(basePath, identifier, channel, renderer, pathSeparator);
|
|
101
|
+
base += pathSeparator;
|
|
102
|
+
base += "partitions";
|
|
103
|
+
base += pathSeparator;
|
|
104
|
+
base += partitionName;
|
|
105
|
+
return base;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
} // namespace electrobun
|
|
109
|
+
|
|
110
|
+
#endif // ELECTROBUN_APP_PATHS_H
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// asar.h - Cross-platform ASAR archive C FFI declarations
|
|
2
|
+
// Used for reading files from ASAR archives across Windows, macOS, and Linux
|
|
3
|
+
//
|
|
4
|
+
// This is a header-only declaration file. The actual implementation is provided by:
|
|
5
|
+
// - libasar library (macOS, Linux)
|
|
6
|
+
// - Built-in AsarArchive class (Windows)
|
|
7
|
+
|
|
8
|
+
#ifndef ELECTROBUN_ASAR_H
|
|
9
|
+
#define ELECTROBUN_ASAR_H
|
|
10
|
+
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
#include <cstddef>
|
|
13
|
+
#include <mutex>
|
|
14
|
+
|
|
15
|
+
// C FFI declarations for ASAR archive operations
|
|
16
|
+
// These match the libasar library API
|
|
17
|
+
extern "C" {
|
|
18
|
+
typedef struct AsarArchive AsarArchive;
|
|
19
|
+
|
|
20
|
+
AsarArchive* asar_open(const char* path);
|
|
21
|
+
void asar_close(AsarArchive* archive);
|
|
22
|
+
const uint8_t* asar_read_file(AsarArchive* archive, const char* path, size_t* size_out);
|
|
23
|
+
void asar_free_buffer(const uint8_t* buffer, size_t size);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
namespace electrobun {
|
|
27
|
+
|
|
28
|
+
// Global ASAR archive handle (lazy-loaded) with thread-safe initialization
|
|
29
|
+
// Each platform should define these in their nativeWrapper implementation
|
|
30
|
+
// as: static AsarArchive* g_asarArchive = nullptr;
|
|
31
|
+
// static std::once_flag g_asarArchiveInitFlag;
|
|
32
|
+
|
|
33
|
+
} // namespace electrobun
|
|
34
|
+
|
|
35
|
+
#endif // ELECTROBUN_ASAR_H
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// cache_migration.h - One-shot CEF cache folder wipe on Electrobun upgrades.
|
|
2
|
+
//
|
|
3
|
+
// When Electrobun ships a release whose CEF cache folder layout/contents are
|
|
4
|
+
// incompatible with prior releases (e.g. a CEF major bump that surfaces
|
|
5
|
+
// "Profile error" dialogs, or an Electrobun-side change to partition layout),
|
|
6
|
+
// the simplest reliable recovery is to wipe the cache folder. End users will
|
|
7
|
+
// be logged out of sites they were logged into via the app, but the app
|
|
8
|
+
// starts cleanly with no dialogs.
|
|
9
|
+
//
|
|
10
|
+
// Bump CEF_CACHE_FORMAT_VERSION below MANUALLY when (and only when) such a
|
|
11
|
+
// breaking change ships. Independent of CEF_VERSION — bumping CEF does not
|
|
12
|
+
// always require a wipe.
|
|
13
|
+
//
|
|
14
|
+
// Behavior:
|
|
15
|
+
// 1. Reads <cacheFolder>/.electrobun_cef_cache_version on startup.
|
|
16
|
+
// 2. If the sentinel is missing OR its value != CEF_CACHE_FORMAT_VERSION,
|
|
17
|
+
// deletes everything inside cacheFolder (preserving the folder itself)
|
|
18
|
+
// and writes a fresh sentinel.
|
|
19
|
+
// 3. If the folder doesn't exist yet (fresh install), creates it and
|
|
20
|
+
// writes the sentinel — so first real launch isn't mistaken for an
|
|
21
|
+
// "old layout" that needs wiping.
|
|
22
|
+
// 4. If the folder exists but is effectively empty (no contents, or only
|
|
23
|
+
// our sentinel), refreshes the sentinel without wiping anything.
|
|
24
|
+
//
|
|
25
|
+
// Safety guards (any failure → no-op, never wipe):
|
|
26
|
+
// - empty / null / relative paths
|
|
27
|
+
// - paths whose final component isn't a known Electrobun cache name
|
|
28
|
+
// - paths shallower than 3 components below the filesystem root
|
|
29
|
+
// - any std::filesystem exception
|
|
30
|
+
//
|
|
31
|
+
// Callers must invoke this AFTER computing the cache path and BEFORE
|
|
32
|
+
// CefInitialize is called for that path. Multi-process locking is NOT
|
|
33
|
+
// implemented: Electrobun's app process starts before any windows open,
|
|
34
|
+
// so concurrent first-launch races aren't a concern in practice.
|
|
35
|
+
|
|
36
|
+
#ifndef ELECTROBUN_CACHE_MIGRATION_H
|
|
37
|
+
#define ELECTROBUN_CACHE_MIGRATION_H
|
|
38
|
+
|
|
39
|
+
#include <cstdint>
|
|
40
|
+
#include <cstdio>
|
|
41
|
+
#include <exception>
|
|
42
|
+
#include <filesystem>
|
|
43
|
+
#include <fstream>
|
|
44
|
+
#include <string>
|
|
45
|
+
#include <system_error>
|
|
46
|
+
|
|
47
|
+
namespace electrobun {
|
|
48
|
+
|
|
49
|
+
// MANUAL bump only. Increment when a release requires that end users'
|
|
50
|
+
// existing CEF cache folders be wiped on first launch after upgrade.
|
|
51
|
+
// Reasons that justify a bump:
|
|
52
|
+
// - CEF major-version jump that's known to surface profile-error dialogs
|
|
53
|
+
// - Electrobun-side change to cache folder layout (e.g. partition path)
|
|
54
|
+
// - Any other situation where stale state would degrade the user experience
|
|
55
|
+
// in a way Chromium's own forward-migration can't handle.
|
|
56
|
+
// Bumping invalidates cookies/logins/site data for all users on first launch.
|
|
57
|
+
// v2: partitions moved from <root>/<name> to <root>/partitions/<name> to
|
|
58
|
+
// avoid case-insensitive collisions with Chromium's auto-created
|
|
59
|
+
// <root>/Default profile folder.
|
|
60
|
+
constexpr uint32_t CEF_CACHE_FORMAT_VERSION = 2;
|
|
61
|
+
|
|
62
|
+
inline const char* cacheSentinelFilename() {
|
|
63
|
+
return ".electrobun_cef_cache_version";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
inline uint32_t readCacheSentinel(const std::filesystem::path& sentinelPath) {
|
|
67
|
+
std::ifstream in(sentinelPath);
|
|
68
|
+
if (!in) return 0;
|
|
69
|
+
uint32_t v = 0;
|
|
70
|
+
in >> v;
|
|
71
|
+
return in ? v : 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
inline void writeCacheSentinel(const std::filesystem::path& sentinelPath,
|
|
75
|
+
uint32_t version) {
|
|
76
|
+
std::filesystem::path tmpPath = sentinelPath;
|
|
77
|
+
tmpPath += ".tmp";
|
|
78
|
+
{
|
|
79
|
+
std::ofstream out(tmpPath, std::ios::trunc);
|
|
80
|
+
if (!out) {
|
|
81
|
+
fprintf(stderr,
|
|
82
|
+
"[cache_migration] warning: cannot open sentinel temp file: %s\n",
|
|
83
|
+
tmpPath.string().c_str());
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
out << version << "\n";
|
|
87
|
+
if (!out) {
|
|
88
|
+
fprintf(stderr,
|
|
89
|
+
"[cache_migration] warning: failed writing sentinel temp file\n");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
std::error_code ec;
|
|
94
|
+
std::filesystem::rename(tmpPath, sentinelPath, ec);
|
|
95
|
+
if (ec) {
|
|
96
|
+
fprintf(stderr,
|
|
97
|
+
"[cache_migration] warning: failed to commit sentinel: %s\n",
|
|
98
|
+
ec.message().c_str());
|
|
99
|
+
std::error_code rmEc;
|
|
100
|
+
std::filesystem::remove(tmpPath, rmEc);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Refuses paths that look unsafe to wipe. Returns true only when the path
|
|
105
|
+
// is absolute, ends in a recognized Electrobun cache folder name, and is
|
|
106
|
+
// at least 3 components deep below the filesystem root.
|
|
107
|
+
inline bool isCachePathSafeToWipe(const std::filesystem::path& cachePath) {
|
|
108
|
+
if (cachePath.empty()) return false;
|
|
109
|
+
if (!cachePath.is_absolute()) return false;
|
|
110
|
+
|
|
111
|
+
const std::string leaf = cachePath.filename().string();
|
|
112
|
+
if (leaf != "CEF" && leaf != "cef_cache") return false;
|
|
113
|
+
|
|
114
|
+
size_t depth = 0;
|
|
115
|
+
for (const auto& part : cachePath.relative_path()) {
|
|
116
|
+
(void)part;
|
|
117
|
+
++depth;
|
|
118
|
+
}
|
|
119
|
+
// Require at least: <user-dir-component>/<identifier>/<channel>/<leaf>
|
|
120
|
+
// i.e. four below the root. Three is the floor; below that we refuse.
|
|
121
|
+
if (depth < 3) return false;
|
|
122
|
+
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
inline void migrateCacheFolderIfNeeded(const std::string& cacheFolderPath) {
|
|
127
|
+
try {
|
|
128
|
+
if (cacheFolderPath.empty()) {
|
|
129
|
+
fprintf(stderr,
|
|
130
|
+
"[cache_migration] skipped: empty cache path\n");
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const std::filesystem::path cachePath(cacheFolderPath);
|
|
135
|
+
|
|
136
|
+
if (!isCachePathSafeToWipe(cachePath)) {
|
|
137
|
+
fprintf(stderr,
|
|
138
|
+
"[cache_migration] skipped: path failed safety check: %s\n",
|
|
139
|
+
cacheFolderPath.c_str());
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const std::filesystem::path sentinelPath =
|
|
144
|
+
cachePath / cacheSentinelFilename();
|
|
145
|
+
|
|
146
|
+
std::error_code ec;
|
|
147
|
+
const bool cacheExists = std::filesystem::exists(cachePath, ec);
|
|
148
|
+
|
|
149
|
+
if (!cacheExists) {
|
|
150
|
+
// Fresh install: create the folder and stamp the current sentinel
|
|
151
|
+
// so the next launch (when CEF has populated it) doesn't see a
|
|
152
|
+
// populated folder + missing sentinel and mistake it for an old
|
|
153
|
+
// layout that needs wiping.
|
|
154
|
+
std::error_code mkEc;
|
|
155
|
+
std::filesystem::create_directories(cachePath, mkEc);
|
|
156
|
+
if (mkEc) {
|
|
157
|
+
fprintf(stderr,
|
|
158
|
+
"[cache_migration] skipped: cannot create cache folder %s (%s)\n",
|
|
159
|
+
cacheFolderPath.c_str(), mkEc.message().c_str());
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
writeCacheSentinel(sentinelPath, CEF_CACHE_FORMAT_VERSION);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!std::filesystem::is_directory(cachePath, ec)) {
|
|
167
|
+
fprintf(stderr,
|
|
168
|
+
"[cache_migration] skipped: path exists but is not a directory: %s\n",
|
|
169
|
+
cacheFolderPath.c_str());
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Determine if folder is effectively empty (only sentinel or nothing).
|
|
174
|
+
bool effectivelyEmpty = true;
|
|
175
|
+
{
|
|
176
|
+
std::error_code itEc;
|
|
177
|
+
std::filesystem::directory_iterator it(cachePath, itEc);
|
|
178
|
+
if (itEc) {
|
|
179
|
+
fprintf(stderr,
|
|
180
|
+
"[cache_migration] skipped: cannot enumerate cache folder %s (%s)\n",
|
|
181
|
+
cacheFolderPath.c_str(), itEc.message().c_str());
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
for (const auto& entry : it) {
|
|
185
|
+
if (entry.path().filename() == sentinelPath.filename()) continue;
|
|
186
|
+
effectivelyEmpty = false;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (effectivelyEmpty) {
|
|
192
|
+
writeCacheSentinel(sentinelPath, CEF_CACHE_FORMAT_VERSION);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const uint32_t existingVersion =
|
|
197
|
+
std::filesystem::exists(sentinelPath, ec)
|
|
198
|
+
? readCacheSentinel(sentinelPath)
|
|
199
|
+
: 0;
|
|
200
|
+
|
|
201
|
+
if (existingVersion == CEF_CACHE_FORMAT_VERSION) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
fprintf(stderr,
|
|
206
|
+
"[cache_migration] wiping CEF cache folder (format %u -> %u): %s\n",
|
|
207
|
+
existingVersion, CEF_CACHE_FORMAT_VERSION,
|
|
208
|
+
cacheFolderPath.c_str());
|
|
209
|
+
|
|
210
|
+
// Wipe contents but preserve the folder itself. Per-entry failures
|
|
211
|
+
// are warned and skipped — a partial wipe still beats refusing to
|
|
212
|
+
// start the app cleanly.
|
|
213
|
+
std::error_code itEc;
|
|
214
|
+
std::filesystem::directory_iterator it(cachePath, itEc);
|
|
215
|
+
if (itEc) {
|
|
216
|
+
fprintf(stderr,
|
|
217
|
+
"[cache_migration] warning: cannot enumerate cache folder for wipe %s (%s)\n",
|
|
218
|
+
cacheFolderPath.c_str(), itEc.message().c_str());
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
for (const auto& entry : it) {
|
|
222
|
+
std::error_code rmEc;
|
|
223
|
+
std::filesystem::remove_all(entry.path(), rmEc);
|
|
224
|
+
if (rmEc) {
|
|
225
|
+
fprintf(stderr,
|
|
226
|
+
"[cache_migration] warning: failed to remove %s (%s)\n",
|
|
227
|
+
entry.path().string().c_str(), rmEc.message().c_str());
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
writeCacheSentinel(sentinelPath, CEF_CACHE_FORMAT_VERSION);
|
|
232
|
+
} catch (const std::exception& e) {
|
|
233
|
+
fprintf(stderr,
|
|
234
|
+
"[cache_migration] aborting due to filesystem error: %s\n",
|
|
235
|
+
e.what());
|
|
236
|
+
} catch (...) {
|
|
237
|
+
fprintf(stderr,
|
|
238
|
+
"[cache_migration] aborting due to unknown error\n");
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
} // namespace electrobun
|
|
243
|
+
|
|
244
|
+
#endif // ELECTROBUN_CACHE_MIGRATION_H
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// callbacks.h - Cross-platform callback type definitions
|
|
2
|
+
// Used for bridging between native code and Zig/Bun FFI across Windows, macOS, and Linux
|
|
3
|
+
//
|
|
4
|
+
// This is a header-only implementation to avoid build complexity.
|
|
5
|
+
|
|
6
|
+
#ifndef ELECTROBUN_CALLBACKS_H
|
|
7
|
+
#define ELECTROBUN_CALLBACKS_H
|
|
8
|
+
|
|
9
|
+
#include <cstdint>
|
|
10
|
+
|
|
11
|
+
namespace electrobun {
|
|
12
|
+
|
|
13
|
+
// Webview navigation and event callbacks
|
|
14
|
+
// NOTE: Bun's FFIType.true doesn't play well with Objective-C's YES/NO char booleans
|
|
15
|
+
// so when sending booleans from JSCallbacks we use uint32_t
|
|
16
|
+
typedef uint32_t (*DecideNavigationCallback)(uint32_t webviewId, const char* url);
|
|
17
|
+
typedef void (*WebviewEventHandler)(uint32_t webviewId, const char* type, const char* url);
|
|
18
|
+
typedef void (*HandlePostMessage)(uint32_t webviewId, const char* message);
|
|
19
|
+
typedef const char* (*HandlePostMessageWithReply)(uint32_t webviewId, const char* message);
|
|
20
|
+
typedef void (*AsyncJavascriptCompletionHandler)(const char* messageId, uint32_t webviewId, uint32_t hostWebviewId, const char* responseJSON);
|
|
21
|
+
|
|
22
|
+
// Window chrome style enum, shared across platforms for titleBarStyle handling
|
|
23
|
+
enum class ChromeStyle : uint32_t { Default, Hidden, HiddenInset };
|
|
24
|
+
|
|
25
|
+
// Window event callbacks
|
|
26
|
+
typedef void (*WindowCloseHandler)(uint32_t windowId);
|
|
27
|
+
typedef void (*WindowMoveHandler)(uint32_t windowId, double x, double y);
|
|
28
|
+
typedef void (*WindowResizeHandler)(uint32_t windowId, double x, double y, double width, double height);
|
|
29
|
+
typedef void (*WindowFocusHandler)(uint32_t windowId);
|
|
30
|
+
typedef void (*WindowBlurHandler)(uint32_t windowId);
|
|
31
|
+
typedef void (*WindowKeyHandler)(uint32_t windowId, uint32_t keyCode, uint32_t modifiers, uint32_t isDown, uint32_t isRepeat);
|
|
32
|
+
|
|
33
|
+
// Tray and menu callbacks
|
|
34
|
+
typedef void (*StatusItemHandler)(uint32_t trayId, const char* action);
|
|
35
|
+
typedef void (*MenuHandler)(const char* menuItemId);
|
|
36
|
+
|
|
37
|
+
// Snapshot callback
|
|
38
|
+
typedef void (*SnapshotCallback)(uint32_t hostId, uint32_t webviewId, const char* dataUrl);
|
|
39
|
+
|
|
40
|
+
// URL open handler for deep linking
|
|
41
|
+
typedef void (*URLOpenHandler)(const char* url);
|
|
42
|
+
|
|
43
|
+
// App reopen handler - called when the user re-opens an already running app
|
|
44
|
+
// (for example via Finder, Launchpad, or `open -a` on macOS)
|
|
45
|
+
typedef void (*AppReopenHandler)();
|
|
46
|
+
|
|
47
|
+
// Quit request handler - called by native code when quit is requested externally
|
|
48
|
+
// (e.g., dock icon quit, system shutdown, console close)
|
|
49
|
+
typedef void (*QuitRequestedHandler)();
|
|
50
|
+
|
|
51
|
+
// JS Utils callbacks (DEPRECATED: Now using map-based approach instead)
|
|
52
|
+
typedef const char* (*GetMimeType)(const char* filePath);
|
|
53
|
+
typedef const char* (*GetHTMLForWebviewSync)(uint32_t webviewId);
|
|
54
|
+
|
|
55
|
+
} // namespace electrobun
|
|
56
|
+
|
|
57
|
+
#endif // ELECTROBUN_CALLBACKS_H
|