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.
Files changed (131) hide show
  1. package/bin/sparkbun.cjs +18 -0
  2. package/dist-linux-arm64/bsdiff +0 -0
  3. package/dist-linux-arm64/bspatch +0 -0
  4. package/dist-linux-arm64/libElectrobunCore.so +0 -0
  5. package/dist-linux-arm64/libNativeWrapper.so +0 -0
  6. package/dist-linux-arm64/libasar.so +0 -0
  7. package/dist-linux-x64/bsdiff +0 -0
  8. package/dist-linux-x64/bspatch +0 -0
  9. package/dist-linux-x64/libElectrobunCore.so +0 -0
  10. package/dist-linux-x64/libNativeWrapper.so +0 -0
  11. package/dist-linux-x64/libasar.so +0 -0
  12. package/dist-macos-arm64/bsdiff +0 -0
  13. package/dist-macos-arm64/bspatch +0 -0
  14. package/dist-macos-arm64/libElectrobunCore.dylib +0 -0
  15. package/dist-macos-arm64/libNativeWrapper.dylib +0 -0
  16. package/dist-macos-arm64/libasar.dylib +0 -0
  17. package/dist-macos-arm64/libwebgpu_dawn.dylib +0 -0
  18. package/dist-macos-arm64/preload-full.js +885 -0
  19. package/dist-macos-arm64/preload-sandboxed.js +111 -0
  20. package/dist-macos-arm64/process_helper +0 -0
  21. package/dist-win-x64/ElectrobunCore.dll +0 -0
  22. package/dist-win-x64/WebView2Loader.dll +0 -0
  23. package/dist-win-x64/bsdiff.exe +0 -0
  24. package/dist-win-x64/bspatch.exe +0 -0
  25. package/dist-win-x64/libNativeWrapper.dll +0 -0
  26. package/dist-win-x64/zig-asar/arm64/libasar.dll +0 -0
  27. package/dist-win-x64/zig-asar/x64/libasar.dll +0 -0
  28. package/package.json +47 -0
  29. package/scripts/build-and-upload-artifacts.js +207 -0
  30. package/scripts/gen-webgpu-ffi.mjs +162 -0
  31. package/scripts/install-windows-deps.ps1 +80 -0
  32. package/scripts/package-release.js +237 -0
  33. package/scripts/push-version.js +84 -0
  34. package/scripts/update-bun-version.ts +122 -0
  35. package/scripts/update-cef-version.ts +145 -0
  36. package/src/browser/builtinrpcSchema.ts +19 -0
  37. package/src/browser/global.d.ts +36 -0
  38. package/src/browser/index.ts +234 -0
  39. package/src/browser/webviewtag.ts +88 -0
  40. package/src/browser/wgputag.ts +48 -0
  41. package/src/bun/SparkBunConfig.ts +497 -0
  42. package/src/bun/__tests__/ffi-contract.test.ts +105 -0
  43. package/src/bun/core/ApplicationMenu.ts +70 -0
  44. package/src/bun/core/BrowserView.ts +416 -0
  45. package/src/bun/core/BrowserWindow.ts +396 -0
  46. package/src/bun/core/BuildConfig.ts +71 -0
  47. package/src/bun/core/ContextMenu.ts +75 -0
  48. package/src/bun/core/GpuWindow.ts +289 -0
  49. package/src/bun/core/Paths.ts +5 -0
  50. package/src/bun/core/Socket.ts +22 -0
  51. package/src/bun/core/Tray.ts +197 -0
  52. package/src/bun/core/Updater.ts +1131 -0
  53. package/src/bun/core/Utils.ts +487 -0
  54. package/src/bun/core/WGPUView.ts +167 -0
  55. package/src/bun/core/menuRoles.ts +181 -0
  56. package/src/bun/events/ApplicationEvents.ts +22 -0
  57. package/src/bun/events/event.ts +27 -0
  58. package/src/bun/events/eventEmitter.ts +45 -0
  59. package/src/bun/events/trayEvents.ts +11 -0
  60. package/src/bun/events/webviewEvents.ts +39 -0
  61. package/src/bun/events/windowEvents.ts +23 -0
  62. package/src/bun/index.ts +120 -0
  63. package/src/bun/preload/.generated/compiled.ts +2 -0
  64. package/src/bun/preload/build.ts +65 -0
  65. package/src/bun/preload/dragRegions.ts +41 -0
  66. package/src/bun/preload/encryption.ts +86 -0
  67. package/src/bun/preload/events.ts +171 -0
  68. package/src/bun/preload/globals.d.ts +45 -0
  69. package/src/bun/preload/index-sandboxed.ts +28 -0
  70. package/src/bun/preload/index.ts +77 -0
  71. package/src/bun/preload/internalRpc.ts +80 -0
  72. package/src/bun/preload/overlaySync.ts +107 -0
  73. package/src/bun/preload/webviewTag.ts +451 -0
  74. package/src/bun/preload/wgpuTag.ts +246 -0
  75. package/src/bun/proc/linux.md +43 -0
  76. package/src/bun/proc/native.ts +3253 -0
  77. package/src/bun/webGPU.ts +346 -0
  78. package/src/bun/webgpuAdapter.ts +3011 -0
  79. package/src/cli/bun.lockb +0 -0
  80. package/src/cli/index.ts +4653 -0
  81. package/src/cli/package-lock.json +81 -0
  82. package/src/cli/package.json +11 -0
  83. package/src/cli/templates/embedded.ts +2 -0
  84. package/src/core/build.zig +16 -0
  85. package/src/core/main.zig +3378 -0
  86. package/src/extractor/build.zig +22 -0
  87. package/src/installer/installer-template.ts +216 -0
  88. package/src/launcher/main.ts +221 -0
  89. package/src/native/build/libNativeWrapper.so +0 -0
  90. package/src/native/linux/build/nativeWrapper.o +0 -0
  91. package/src/native/linux/cef_loader.cpp +110 -0
  92. package/src/native/linux/cef_loader.h +28 -0
  93. package/src/native/linux/cef_process_helper_linux.cpp +160 -0
  94. package/src/native/linux/nativeWrapper.cpp +11768 -0
  95. package/src/native/macos/cef_process_helper_mac.cc +160 -0
  96. package/src/native/macos/nativeWrapper.mm +9172 -0
  97. package/src/native/shared/accelerator_parser.h +72 -0
  98. package/src/native/shared/app_paths.h +110 -0
  99. package/src/native/shared/asar.h +35 -0
  100. package/src/native/shared/cache_migration.h +244 -0
  101. package/src/native/shared/callbacks.h +57 -0
  102. package/src/native/shared/cef_response_filter.h +189 -0
  103. package/src/native/shared/chromium_flags.h +181 -0
  104. package/src/native/shared/config.h +66 -0
  105. package/src/native/shared/download_event.h +197 -0
  106. package/src/native/shared/ffi_helpers.h +139 -0
  107. package/src/native/shared/glob_match.h +59 -0
  108. package/src/native/shared/json_menu_parser.h +223 -0
  109. package/src/native/shared/mime_types.h +101 -0
  110. package/src/native/shared/navigation_rules.h +98 -0
  111. package/src/native/shared/partition_context.h +137 -0
  112. package/src/native/shared/pending_resize_queue.h +45 -0
  113. package/src/native/shared/permissions.h +118 -0
  114. package/src/native/shared/permissions_cef.h +74 -0
  115. package/src/native/shared/preload_script.h +71 -0
  116. package/src/native/shared/shutdown_guard.h +134 -0
  117. package/src/native/shared/thread_safe_map.h +138 -0
  118. package/src/native/shared/webview_storage.h +91 -0
  119. package/src/native/win/cef_process_helper_win.cpp +143 -0
  120. package/src/native/win/dcomp_compositor.h +352 -0
  121. package/src/native/win/nativeWrapper.cpp +12434 -0
  122. package/src/npmbin/index.js +34 -0
  123. package/src/shared/bun-version.ts +3 -0
  124. package/src/shared/cef-version.ts +5 -0
  125. package/src/shared/naming.test.ts +327 -0
  126. package/src/shared/naming.ts +188 -0
  127. package/src/shared/platform.ts +48 -0
  128. package/src/shared/rpc.ts +541 -0
  129. package/src/shared/sparkbun-version.ts +2 -0
  130. package/src/types/three.d.ts +1 -0
  131. 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