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,137 @@
1
+ // partition_context.h - Cross-platform CEF partition (CefRequestContext) management.
2
+ //
3
+ // Consumers must already have included CEF headers that define
4
+ // CefRequestContext / CefRequestContextSettings / CefSchemeHandlerFactory
5
+ // (e.g. include/cef_app.h, which pulls them in transitively).
6
+ //
7
+ // Behavior (consistent across macOS, Linux, Windows):
8
+ // - partition == "" → fresh ephemeral CefRequestContext per call.
9
+ // We deliberately do NOT route the default partition to GetGlobalContext():
10
+ // under Chrome runtime, attaching multiple browsers to the global context in
11
+ // rapid succession races with Chrome's window-framework code and intermittently
12
+ // opens the browser in its own top-level chrome window (with URL bar) instead
13
+ // of honoring the embedder's SetAsChild. A per-webview ephemeral context
14
+ // sidesteps that race and matches the pre-consolidation Linux/Windows behavior.
15
+ // - partition starts with "persist:" → cached per identifier; first call creates
16
+ // a new CefRequestContext with a custom cache_path on disk, subsequent calls
17
+ // for the same identifier reuse it. Caching is required because CEF's Chrome
18
+ // runtime refuses to bind two CefRequestContexts to the same on-disk profile,
19
+ // and prior code crashed when a second webview tried to share a partition.
20
+ // - any other partition (e.g. "temp:foo") → fresh ephemeral in-memory context
21
+ // per call, never cached. Closing and reopening a webview that uses
22
+ // "temp:foo" therefore yields fresh storage.
23
+ // - if CefRequestContext::CreateContext returns null (some Chrome runtime
24
+ // configurations refuse custom profile paths), we fall back to the global
25
+ // context for that partition with a warning. The webview still loads;
26
+ // isolation is lost for that one partition.
27
+
28
+ #ifndef ELECTROBUN_PARTITION_CONTEXT_H
29
+ #define ELECTROBUN_PARTITION_CONTEXT_H
30
+
31
+ #include <string>
32
+ #include <map>
33
+ #include <mutex>
34
+ #include <cstdio>
35
+
36
+ namespace electrobun {
37
+
38
+ // Platform-provided. Returns the absolute filesystem cache_path for a
39
+ // persistent partition with the given name (e.g. "test1"), creating any
40
+ // missing parent directories. Returning an empty string causes the caller
41
+ // to fall back to an ephemeral (in-memory) context for that webview.
42
+ std::string buildAndEnsurePartitionCachePath(const std::string& partitionName);
43
+
44
+ inline std::map<std::string, CefRefPtr<CefRequestContext>>& partitionContextMap_() {
45
+ static std::map<std::string, CefRefPtr<CefRequestContext>> map;
46
+ return map;
47
+ }
48
+
49
+ inline std::mutex& partitionContextMutex_() {
50
+ static std::mutex m;
51
+ return m;
52
+ }
53
+
54
+ // Returns the CefRequestContext to use for a webview with the given partition
55
+ // identifier. Registers `schemeFactory` on every returned context so views://
56
+ // resolves correctly regardless of which context handles the request.
57
+ inline CefRefPtr<CefRequestContext> getOrCreateRequestContextForPartition(
58
+ const char* partitionIdentifier,
59
+ uint32_t webviewId,
60
+ CefRefPtr<CefSchemeHandlerFactory> schemeFactory) {
61
+
62
+ std::string identifier(partitionIdentifier ? partitionIdentifier : "");
63
+
64
+ auto registerScheme = [&](CefRefPtr<CefRequestContext> ctx) {
65
+ if (ctx && schemeFactory) {
66
+ ctx->RegisterSchemeHandlerFactory("views", "", schemeFactory);
67
+ }
68
+ };
69
+
70
+ bool isPersistent = identifier.size() >= 8 && identifier.compare(0, 8, "persist:") == 0;
71
+
72
+ // Default partition → fresh ephemeral context per webview.
73
+ // Avoids a Chrome-runtime race where multiple browsers attached to the
74
+ // global context can spawn their own top-level chrome window instead of
75
+ // embedding via SetAsChild. See behavior comment at top of file.
76
+ if (identifier.empty()) {
77
+ CefRequestContextSettings defaultSettings;
78
+ defaultSettings.persist_session_cookies = false;
79
+ CefRefPtr<CefRequestContext> ctx = CefRequestContext::CreateContext(defaultSettings, nullptr);
80
+ if (!ctx) {
81
+ fprintf(stderr, "[partition_context] WARNING: CreateContext returned null for default partition "
82
+ "— falling back to global context\n");
83
+ ctx = CefRequestContext::GetGlobalContext();
84
+ }
85
+ registerScheme(ctx);
86
+ return ctx;
87
+ }
88
+
89
+ // Reuse cached context for persist:* partitions only.
90
+ if (isPersistent) {
91
+ std::lock_guard<std::mutex> lock(partitionContextMutex_());
92
+ auto& map = partitionContextMap_();
93
+ auto it = map.find(identifier);
94
+ if (it != map.end()) {
95
+ return it->second;
96
+ }
97
+ }
98
+
99
+ CefRequestContextSettings settings;
100
+ if (isPersistent) {
101
+ std::string partitionName = identifier.substr(8);
102
+ std::string cachePathStr = buildAndEnsurePartitionCachePath(partitionName);
103
+ if (!cachePathStr.empty()) {
104
+ settings.persist_session_cookies = true;
105
+ CefString(&settings.cache_path).FromString(cachePathStr);
106
+ } else {
107
+ fprintf(stderr, "[partition_context] webview %u: failed to build cache path for '%s', "
108
+ "falling back to ephemeral\n",
109
+ webviewId, identifier.c_str());
110
+ settings.persist_session_cookies = false;
111
+ }
112
+ } else {
113
+ settings.persist_session_cookies = false;
114
+ }
115
+
116
+ CefRefPtr<CefRequestContext> context = CefRequestContext::CreateContext(settings, nullptr);
117
+
118
+ if (!context) {
119
+ fprintf(stderr, "[partition_context] WARNING: CreateContext returned null for partition '%s' "
120
+ "— falling back to global context (this partition will NOT be isolated)\n",
121
+ identifier.c_str());
122
+ context = CefRequestContext::GetGlobalContext();
123
+ }
124
+
125
+ registerScheme(context);
126
+
127
+ if (isPersistent) {
128
+ std::lock_guard<std::mutex> lock(partitionContextMutex_());
129
+ partitionContextMap_()[identifier] = context;
130
+ }
131
+
132
+ return context;
133
+ }
134
+
135
+ } // namespace electrobun
136
+
137
+ #endif // ELECTROBUN_PARTITION_CONTEXT_H
@@ -0,0 +1,45 @@
1
+ #pragma once
2
+
3
+ #include <algorithm>
4
+ #include <mutex>
5
+ #include <unordered_set>
6
+ #include <vector>
7
+
8
+ // Thread-safe queue that stores a set of dirty view pointers.
9
+ // Enqueue is idempotent per drain cycle.
10
+ class PendingResizeQueue {
11
+ public:
12
+ void enqueue(void* view) {
13
+ if (!view) return;
14
+ std::lock_guard<std::mutex> lock(mutex_);
15
+ if (set_.insert(view).second) {
16
+ queue_.push_back(view);
17
+ }
18
+ }
19
+
20
+ std::vector<void*> drain() {
21
+ std::lock_guard<std::mutex> lock(mutex_);
22
+ std::vector<void*> out;
23
+ out.swap(queue_);
24
+ set_.clear();
25
+ return out;
26
+ }
27
+
28
+ void remove(void* view) {
29
+ if (!view) return;
30
+ std::lock_guard<std::mutex> lock(mutex_);
31
+ if (set_.erase(view)) {
32
+ queue_.erase(std::remove(queue_.begin(), queue_.end(), view), queue_.end());
33
+ }
34
+ }
35
+
36
+ bool empty() const {
37
+ std::lock_guard<std::mutex> lock(mutex_);
38
+ return queue_.empty();
39
+ }
40
+
41
+ private:
42
+ mutable std::mutex mutex_;
43
+ std::unordered_set<void*> set_;
44
+ std::vector<void*> queue_;
45
+ };
@@ -0,0 +1,118 @@
1
+ // permissions.h - Cross-platform permission cache management
2
+ // Used for caching user media, geolocation, and notification permissions
3
+ // across Windows, macOS, and Linux
4
+ //
5
+ // This is a header-only implementation to avoid build complexity.
6
+
7
+ #ifndef ELECTROBUN_PERMISSIONS_H
8
+ #define ELECTROBUN_PERMISSIONS_H
9
+
10
+ #include <string>
11
+ #include <map>
12
+ #include <chrono>
13
+ #include <mutex>
14
+ #include <utility>
15
+
16
+ namespace electrobun {
17
+
18
+ enum class PermissionType {
19
+ USER_MEDIA,
20
+ GEOLOCATION,
21
+ NOTIFICATIONS,
22
+ OTHER
23
+ };
24
+
25
+ enum class PermissionStatus {
26
+ UNKNOWN,
27
+ ALLOWED,
28
+ DENIED
29
+ };
30
+
31
+ struct PermissionCacheEntry {
32
+ PermissionStatus status;
33
+ std::chrono::system_clock::time_point expiry;
34
+ };
35
+
36
+ // Thread-safe permission cache
37
+ class PermissionCache {
38
+ public:
39
+ static PermissionCache& getInstance() {
40
+ static PermissionCache instance;
41
+ return instance;
42
+ }
43
+
44
+ // Extract origin from a URL (e.g., "https://example.com/path" -> "https://example.com")
45
+ static std::string getOriginFromUrl(const std::string& url) {
46
+ // For views:// scheme, use a constant origin since these are local files
47
+ if (url.find("views://") == 0) {
48
+ return "views://";
49
+ }
50
+
51
+ // For other schemes, extract origin from URL
52
+ size_t protocolEnd = url.find("://");
53
+ if (protocolEnd == std::string::npos) return url;
54
+
55
+ size_t domainStart = protocolEnd + 3;
56
+ size_t pathStart = url.find('/', domainStart);
57
+
58
+ if (pathStart == std::string::npos) {
59
+ return url;
60
+ }
61
+
62
+ return url.substr(0, pathStart);
63
+ }
64
+
65
+ PermissionStatus get(const std::string& origin, PermissionType type) {
66
+ std::lock_guard<std::mutex> lock(mutex_);
67
+ auto key = std::make_pair(origin, type);
68
+ auto it = cache_.find(key);
69
+
70
+ if (it != cache_.end()) {
71
+ // Check if permission hasn't expired
72
+ auto now = std::chrono::system_clock::now();
73
+ if (now < it->second.expiry) {
74
+ return it->second.status;
75
+ } else {
76
+ // Permission expired, remove from cache
77
+ cache_.erase(it);
78
+ }
79
+ }
80
+
81
+ return PermissionStatus::UNKNOWN;
82
+ }
83
+
84
+ void set(const std::string& origin, PermissionType type, PermissionStatus status) {
85
+ std::lock_guard<std::mutex> lock(mutex_);
86
+ auto key = std::make_pair(origin, type);
87
+
88
+ // Cache permission for 24 hours
89
+ auto expiry = std::chrono::system_clock::now() + std::chrono::hours(24);
90
+
91
+ cache_[key] = {status, expiry};
92
+ }
93
+
94
+ private:
95
+ PermissionCache() = default;
96
+ PermissionCache(const PermissionCache&) = delete;
97
+ PermissionCache& operator=(const PermissionCache&) = delete;
98
+
99
+ std::map<std::pair<std::string, PermissionType>, PermissionCacheEntry> cache_;
100
+ std::mutex mutex_;
101
+ };
102
+
103
+ // Convenience functions that use the singleton (for easier migration from existing code)
104
+ inline std::string getOriginFromUrl(const std::string& url) {
105
+ return PermissionCache::getOriginFromUrl(url);
106
+ }
107
+
108
+ inline PermissionStatus getPermissionFromCache(const std::string& origin, PermissionType type) {
109
+ return PermissionCache::getInstance().get(origin, type);
110
+ }
111
+
112
+ inline void cachePermission(const std::string& origin, PermissionType type, PermissionStatus status) {
113
+ PermissionCache::getInstance().set(origin, type, status);
114
+ }
115
+
116
+ } // namespace electrobun
117
+
118
+ #endif // ELECTROBUN_PERMISSIONS_H
@@ -0,0 +1,74 @@
1
+ // permissions_cef.h - CEF-aware permission helpers
2
+ // Must be included AFTER include/cef_app.h (or any header that pulls in
3
+ // internal/cef_types.h) so the CEF_PERMISSION_TYPE_* constants are available.
4
+
5
+ #ifndef ELECTROBUN_PERMISSIONS_CEF_H
6
+ #define ELECTROBUN_PERMISSIONS_CEF_H
7
+
8
+ // Consumers must already have included CEF headers that define
9
+ // CEF_PERMISSION_TYPE_* (e.g. include/cef_app.h, which pulls in
10
+ // include/internal/cef_types.h transitively).
11
+
12
+ #include <string>
13
+ #include <cstdint>
14
+ #include <cstdio>
15
+
16
+ namespace electrobun {
17
+
18
+ // Decode a CEF permission bitmask (as passed to OnShowPermissionPrompt) into a
19
+ // human-readable comma-separated list of permission names. Used to build
20
+ // informative dialogs for permission types we don't have a dedicated UI for.
21
+ inline std::string describeCefPermissions(uint32_t mask) {
22
+ std::string out;
23
+ auto add = [&](const char* name) {
24
+ if (!out.empty()) out += ", ";
25
+ out += name;
26
+ };
27
+
28
+ if (mask & CEF_PERMISSION_TYPE_AR_SESSION) add("AR session");
29
+ if (mask & CEF_PERMISSION_TYPE_CAMERA_PAN_TILT_ZOOM) add("Camera pan/tilt/zoom");
30
+ if (mask & CEF_PERMISSION_TYPE_CAMERA_STREAM) add("Camera");
31
+ if (mask & CEF_PERMISSION_TYPE_CAPTURED_SURFACE_CONTROL) add("Captured surface control");
32
+ if (mask & CEF_PERMISSION_TYPE_CLIPBOARD) add("Clipboard");
33
+ if (mask & CEF_PERMISSION_TYPE_TOP_LEVEL_STORAGE_ACCESS) add("Top-level storage access");
34
+ if (mask & CEF_PERMISSION_TYPE_DISK_QUOTA) add("Disk quota");
35
+ if (mask & CEF_PERMISSION_TYPE_LOCAL_FONTS) add("Local fonts");
36
+ if (mask & CEF_PERMISSION_TYPE_GEOLOCATION) add("Location");
37
+ if (mask & CEF_PERMISSION_TYPE_HAND_TRACKING) add("Hand tracking");
38
+ if (mask & CEF_PERMISSION_TYPE_IDENTITY_PROVIDER) add("Identity provider");
39
+ if (mask & CEF_PERMISSION_TYPE_IDLE_DETECTION) add("Idle detection");
40
+ if (mask & CEF_PERMISSION_TYPE_MIC_STREAM) add("Microphone");
41
+ if (mask & CEF_PERMISSION_TYPE_MIDI_SYSEX) add("MIDI system-exclusive");
42
+ if (mask & CEF_PERMISSION_TYPE_MULTIPLE_DOWNLOADS) add("Multiple downloads");
43
+ if (mask & CEF_PERMISSION_TYPE_NOTIFICATIONS) add("Notifications");
44
+ if (mask & CEF_PERMISSION_TYPE_KEYBOARD_LOCK) add("Keyboard lock");
45
+ if (mask & CEF_PERMISSION_TYPE_POINTER_LOCK) add("Pointer lock");
46
+ if (mask & CEF_PERMISSION_TYPE_PROTECTED_MEDIA_IDENTIFIER) add("Protected media identifier");
47
+ if (mask & CEF_PERMISSION_TYPE_REGISTER_PROTOCOL_HANDLER) add("Register protocol handler");
48
+ if (mask & CEF_PERMISSION_TYPE_STORAGE_ACCESS) add("Storage access");
49
+ if (mask & CEF_PERMISSION_TYPE_VR_SESSION) add("VR session");
50
+ if (mask & CEF_PERMISSION_TYPE_WEB_APP_INSTALLATION) add("Web app installation");
51
+ if (mask & CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT) add("Window management");
52
+ if (mask & CEF_PERMISSION_TYPE_FILE_SYSTEM_ACCESS) add("File system access");
53
+ #if CEF_API_ADDED(13600)
54
+ if (mask & CEF_PERMISSION_TYPE_LOCAL_NETWORK_ACCESS) add("Local network access");
55
+ #endif
56
+ #if CEF_API_ADDED(14500)
57
+ if (mask & CEF_PERMISSION_TYPE_LOCAL_NETWORK) add("Local network");
58
+ if (mask & CEF_PERMISSION_TYPE_LOOPBACK_NETWORK) add("Loopback network");
59
+ #endif
60
+ #if CEF_API_ADDED(14700)
61
+ if (mask & CEF_PERMISSION_TYPE_SENSORS) add("Sensors");
62
+ #endif
63
+
64
+ if (out.empty()) {
65
+ char buf[64];
66
+ snprintf(buf, sizeof(buf), "unknown (bitmask 0x%x)", mask);
67
+ out = buf;
68
+ }
69
+ return out;
70
+ }
71
+
72
+ } // namespace electrobun
73
+
74
+ #endif // ELECTROBUN_PERMISSIONS_CEF_H
@@ -0,0 +1,71 @@
1
+ // preload_script.h - Cross-platform preload script management
2
+ // Used for storing and managing preload scripts across Windows, macOS, and Linux
3
+ //
4
+ // This is a header-only implementation to avoid build complexity.
5
+
6
+ #ifndef ELECTROBUN_PRELOAD_SCRIPT_H
7
+ #define ELECTROBUN_PRELOAD_SCRIPT_H
8
+
9
+ #include <string>
10
+ #include <map>
11
+ #include <mutex>
12
+
13
+ namespace electrobun {
14
+
15
+ // Represents a preload script to be injected into webviews
16
+ struct PreloadScript {
17
+ std::string code;
18
+ bool mainFrameOnly = true;
19
+
20
+ PreloadScript() = default;
21
+
22
+ PreloadScript(const std::string& scriptCode, bool mainOnly = true)
23
+ : code(scriptCode), mainFrameOnly(mainOnly) {}
24
+
25
+ bool empty() const { return code.empty(); }
26
+ };
27
+
28
+ // Thread-safe storage for preload scripts by browser/webview ID
29
+ class PreloadScriptStorage {
30
+ public:
31
+ static PreloadScriptStorage& getInstance() {
32
+ static PreloadScriptStorage instance;
33
+ return instance;
34
+ }
35
+
36
+ void set(int browserId, const std::string& script) {
37
+ std::lock_guard<std::mutex> lock(mutex_);
38
+ scripts_[browserId] = script;
39
+ }
40
+
41
+ std::string get(int browserId) const {
42
+ std::lock_guard<std::mutex> lock(mutex_);
43
+ auto it = scripts_.find(browserId);
44
+ if (it != scripts_.end()) {
45
+ return it->second;
46
+ }
47
+ return "";
48
+ }
49
+
50
+ void remove(int browserId) {
51
+ std::lock_guard<std::mutex> lock(mutex_);
52
+ scripts_.erase(browserId);
53
+ }
54
+
55
+ void clear() {
56
+ std::lock_guard<std::mutex> lock(mutex_);
57
+ scripts_.clear();
58
+ }
59
+
60
+ private:
61
+ PreloadScriptStorage() = default;
62
+ PreloadScriptStorage(const PreloadScriptStorage&) = delete;
63
+ PreloadScriptStorage& operator=(const PreloadScriptStorage&) = delete;
64
+
65
+ mutable std::mutex mutex_;
66
+ std::map<int, std::string> scripts_;
67
+ };
68
+
69
+ } // namespace electrobun
70
+
71
+ #endif // ELECTROBUN_PRELOAD_SCRIPT_H
@@ -0,0 +1,134 @@
1
+ // shutdown_guard.h - Cross-platform shutdown state management
2
+ // Prevents race conditions during application cleanup
3
+ // Used across Windows, macOS, and Linux
4
+ //
5
+ // This is a header-only implementation to avoid build complexity.
6
+
7
+ #ifndef ELECTROBUN_SHUTDOWN_GUARD_H
8
+ #define ELECTROBUN_SHUTDOWN_GUARD_H
9
+
10
+ #include <atomic>
11
+ #include <mutex>
12
+ #include <thread>
13
+ #include <chrono>
14
+
15
+ namespace electrobun {
16
+
17
+ // Singleton for managing global shutdown state
18
+ // Allows code to check if shutdown is in progress and avoid race conditions
19
+ class ShutdownManager {
20
+ public:
21
+ static ShutdownManager& getInstance() {
22
+ static ShutdownManager instance;
23
+ return instance;
24
+ }
25
+
26
+ // Signal that shutdown has begun
27
+ void initiateShutdown() {
28
+ shuttingDown_.store(true);
29
+ }
30
+
31
+ // Check if shutdown is in progress
32
+ bool isShuttingDown() const {
33
+ return shuttingDown_.load();
34
+ }
35
+
36
+ // Reset shutdown state (use with caution, mainly for testing)
37
+ void reset() {
38
+ shuttingDown_.store(false);
39
+ activeOperations_.store(0);
40
+ }
41
+
42
+ // Increment active operations counter
43
+ void beginOperation() {
44
+ activeOperations_.fetch_add(1);
45
+ }
46
+
47
+ // Decrement active operations counter
48
+ void endOperation() {
49
+ activeOperations_.fetch_sub(1);
50
+ }
51
+
52
+ // Get count of active operations
53
+ int getActiveOperations() const {
54
+ return activeOperations_.load();
55
+ }
56
+
57
+ // Wait for all operations to complete (with timeout)
58
+ // Returns true if all operations completed, false if timeout
59
+ bool waitForOperationsToComplete(int maxWaitMs = 5000) {
60
+ int waited = 0;
61
+ const int sleepMs = 10;
62
+ while (activeOperations_.load() > 0 && waited < maxWaitMs) {
63
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs));
64
+ waited += sleepMs;
65
+ }
66
+ return activeOperations_.load() == 0;
67
+ }
68
+
69
+ private:
70
+ ShutdownManager() : shuttingDown_(false), activeOperations_(0) {}
71
+ ShutdownManager(const ShutdownManager&) = delete;
72
+ ShutdownManager& operator=(const ShutdownManager&) = delete;
73
+
74
+ std::atomic<bool> shuttingDown_;
75
+ std::atomic<int> activeOperations_;
76
+ };
77
+
78
+ // RAII guard for operations that shouldn't run during shutdown
79
+ // Automatically checks shutdown state and tracks operation lifetime
80
+ class OperationGuard {
81
+ public:
82
+ OperationGuard() : valid_(!ShutdownManager::getInstance().isShuttingDown()) {
83
+ if (valid_) {
84
+ ShutdownManager::getInstance().beginOperation();
85
+ }
86
+ }
87
+
88
+ ~OperationGuard() {
89
+ if (valid_) {
90
+ ShutdownManager::getInstance().endOperation();
91
+ }
92
+ }
93
+
94
+ // Check if the operation is valid (not during shutdown)
95
+ bool isValid() const { return valid_; }
96
+
97
+ // Implicit conversion to bool for easy use in if statements
98
+ explicit operator bool() const { return valid_; }
99
+
100
+ // Non-copyable, non-movable
101
+ OperationGuard(const OperationGuard&) = delete;
102
+ OperationGuard& operator=(const OperationGuard&) = delete;
103
+ OperationGuard(OperationGuard&&) = delete;
104
+ OperationGuard& operator=(OperationGuard&&) = delete;
105
+
106
+ private:
107
+ bool valid_;
108
+ };
109
+
110
+ // Lightweight guard that only checks shutdown state without tracking
111
+ // Use when you don't need operation tracking, just shutdown checking
112
+ class ShutdownCheckGuard {
113
+ public:
114
+ ShutdownCheckGuard() : valid_(!ShutdownManager::getInstance().isShuttingDown()) {}
115
+
116
+ bool isValid() const { return valid_; }
117
+ explicit operator bool() const { return valid_; }
118
+
119
+ private:
120
+ bool valid_;
121
+ };
122
+
123
+ // Convenience functions
124
+ inline bool isShuttingDown() {
125
+ return ShutdownManager::getInstance().isShuttingDown();
126
+ }
127
+
128
+ inline void initiateShutdown() {
129
+ ShutdownManager::getInstance().initiateShutdown();
130
+ }
131
+
132
+ } // namespace electrobun
133
+
134
+ #endif // ELECTROBUN_SHUTDOWN_GUARD_H