sparkbun 0.2.5 → 0.2.6

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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkbun",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Build fast, lightweight, cross-platform desktop apps with TypeScript and Bun.",
5
5
  "license": "MIT",
6
6
  "author": "SparkBun Contributors",
@@ -29,6 +29,12 @@ export type WindowOptionsType<T = undefined> = {
29
29
  preload: string | null;
30
30
  viewsRoot: string | null;
31
31
  renderer: "native" | "cef";
32
+ // Storage partition for the webview's cookies/localStorage/cache/IndexedDB.
33
+ // A value starting with "persist:" is written to disk; any other non-empty
34
+ // value is ephemeral — in-memory only, gone when the process exits — which
35
+ // is what incognito-style/diskless sessions want. Omitted/null falls back to
36
+ // "persist:default" (on-disk).
37
+ partition?: string;
32
38
  rpc?: T;
33
39
  styleMask?: {};
34
40
  // titleBarStyle options:
@@ -105,6 +111,7 @@ export class BrowserWindow<T extends RPCWithTransport = AnyRPC> {
105
111
  html: string | null = null;
106
112
  preload: string | null = null;
107
113
  viewsRoot: string | null = null;
114
+ partition: string | null = null;
108
115
  renderer: "native" | "cef" = "native";
109
116
  transparent: boolean = false;
110
117
  passthrough: boolean = false;
@@ -139,6 +146,7 @@ export class BrowserWindow<T extends RPCWithTransport = AnyRPC> {
139
146
  this.html = options.html || null;
140
147
  this.preload = options.preload || null;
141
148
  this.viewsRoot = options.viewsRoot || null;
149
+ this.partition = options.partition ?? null;
142
150
  this.renderer = options.renderer || defaultOptions.renderer;
143
151
  this.transparent = options.transparent ?? false;
144
152
  this.passthrough = options.passthrough ?? false;
@@ -223,6 +231,7 @@ export class BrowserWindow<T extends RPCWithTransport = AnyRPC> {
223
231
  html: this.html,
224
232
  preload: this.preload,
225
233
  viewsRoot: this.viewsRoot,
234
+ partition: this.partition,
226
235
  // frame: this.frame,
227
236
  renderer: this.renderer,
228
237
  frame: {
@@ -11208,55 +11208,66 @@ static std::map<std::string, WebKitWebsiteDataManager*> g_partitionDataManagers;
11208
11208
  static WebKitWebsiteDataManager* getDataManagerForPartition(const char* partitionIdentifier) {
11209
11209
  std::string partition = partitionIdentifier ? partitionIdentifier : "";
11210
11210
 
11211
+ // Prefer the data manager owned by the live webview context for this
11212
+ // partition. getContextForPartition() builds each webview's context around
11213
+ // its own WebKitWebsiteDataManager; creating a separate manager here — even
11214
+ // one pointing at the same on-disk directory — clears a different instance
11215
+ // and leaves the running webview's storage untouched, which made
11216
+ // clearStorageData()/cookies.clear() appear to do nothing. Resolving through
11217
+ // the context keeps clears on the exact store the page reads and writes.
11218
+ if (partition.empty()) {
11219
+ WebKitWebContext* context = webkit_web_context_get_default();
11220
+ return webkit_web_context_get_website_data_manager(context);
11221
+ }
11222
+
11223
+ auto ctxIt = g_partitionContexts.find(partition);
11224
+ if (ctxIt != g_partitionContexts.end() && ctxIt->second) {
11225
+ return webkit_web_context_get_website_data_manager(ctxIt->second);
11226
+ }
11227
+
11228
+ // No live context for this partition yet — fall back to a standalone manager
11229
+ // (cached) so cookie/storage APIs still work before a webview is created.
11211
11230
  auto it = g_partitionDataManagers.find(partition);
11212
11231
  if (it != g_partitionDataManagers.end()) {
11213
11232
  return it->second;
11214
11233
  }
11215
11234
 
11216
11235
  WebKitWebsiteDataManager* dataManager = nullptr;
11236
+ bool isPersistent = partition.substr(0, 8) == "persist:";
11217
11237
 
11218
- if (partition.empty()) {
11219
- // Default: use default context's data manager
11220
- WebKitWebContext* context = webkit_web_context_get_default();
11221
- dataManager = webkit_web_context_get_website_data_manager(context);
11222
- } else {
11223
- bool isPersistent = partition.substr(0, 8) == "persist:";
11238
+ if (isPersistent) {
11239
+ std::string partitionName = partition.substr(8);
11224
11240
 
11225
- if (isPersistent) {
11226
- std::string partitionName = partition.substr(8);
11241
+ // Build paths with identifier/channel structure (consistent with CLI and updater)
11242
+ char* home = getenv("HOME");
11243
+ std::string homeStr = home ? std::string(home) : "/tmp";
11244
+ std::string dataPath = buildPartitionPath(homeStr + "/.local/share", g_sparkbunIdentifier, g_sparkbunChannel, "WebKit", partitionName);
11245
+ std::string cachePath = buildPartitionPath(homeStr + "/.cache", g_sparkbunIdentifier, g_sparkbunChannel, "WebKit", partitionName);
11227
11246
 
11228
- // Build paths with identifier/channel structure (consistent with CLI and updater)
11229
- char* home = getenv("HOME");
11230
- std::string homeStr = home ? std::string(home) : "/tmp";
11231
- std::string dataPath = buildPartitionPath(homeStr + "/.local/share", g_sparkbunIdentifier, g_sparkbunChannel, "WebKit", partitionName);
11232
- std::string cachePath = buildPartitionPath(homeStr + "/.cache", g_sparkbunIdentifier, g_sparkbunChannel, "WebKit", partitionName);
11247
+ g_mkdir_with_parents(dataPath.c_str(), 0755);
11248
+ g_mkdir_with_parents(cachePath.c_str(), 0755);
11233
11249
 
11234
- g_mkdir_with_parents(dataPath.c_str(), 0755);
11235
- g_mkdir_with_parents(cachePath.c_str(), 0755);
11250
+ dataManager = webkit_website_data_manager_new(
11251
+ "base-data-directory", dataPath.c_str(),
11252
+ "base-cache-directory", cachePath.c_str(),
11253
+ NULL
11254
+ );
11236
11255
 
11237
- dataManager = webkit_website_data_manager_new(
11238
- "base-data-directory", dataPath.c_str(),
11239
- "base-cache-directory", cachePath.c_str(),
11240
- NULL
11256
+ // Enable persistent cookie storage (SQLite-backed)
11257
+ WebKitCookieManager* cookieManager = webkit_website_data_manager_get_cookie_manager(dataManager);
11258
+ if (cookieManager) {
11259
+ std::string cookiePath = dataPath + "/cookies.sqlite";
11260
+ webkit_cookie_manager_set_persistent_storage(
11261
+ cookieManager,
11262
+ cookiePath.c_str(),
11263
+ WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE
11241
11264
  );
11242
-
11243
- // Enable persistent cookie storage (SQLite-backed)
11244
- WebKitCookieManager* cookieManager = webkit_website_data_manager_get_cookie_manager(dataManager);
11245
- if (cookieManager) {
11246
- std::string cookiePath = dataPath + "/cookies.sqlite";
11247
- webkit_cookie_manager_set_persistent_storage(
11248
- cookieManager,
11249
- cookiePath.c_str(),
11250
- WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE
11251
- );
11252
- }
11253
- } else {
11254
- dataManager = webkit_website_data_manager_new_ephemeral();
11255
11265
  }
11256
-
11257
- g_partitionDataManagers[partition] = dataManager;
11266
+ } else {
11267
+ dataManager = webkit_website_data_manager_new_ephemeral();
11258
11268
  }
11259
11269
 
11270
+ g_partitionDataManagers[partition] = dataManager;
11260
11271
  return dataManager;
11261
11272
  }
11262
11273
 
@@ -11651,11 +11662,44 @@ SPARKBUN_EXPORT bool sessionRemoveCookie(const char* partitionIdentifier, const
11651
11662
  // Clear all cookies (WebKit2GTK)
11652
11663
  // Clear all cookies (WebKit2GTK) - STUB implementation to prevent crashes
11653
11664
  SPARKBUN_EXPORT void sessionClearCookies(const char* partitionIdentifier) {
11654
- // Stub implementation: do nothing and return immediately
11655
- // This prevents crashes from complex WebKit async patterns during tests
11656
- // while maintaining API compatibility
11657
- (void)partitionIdentifier; // Suppress unused parameter warning
11658
- return;
11665
+ // Copy argument before dispatching to main thread
11666
+ std::string partitionStr = partitionIdentifier ? partitionIdentifier : "";
11667
+
11668
+ // Clear cookies via the website data manager rather than per-cookie
11669
+ // get/delete. This reuses the same dispatch + GMainLoop pattern as
11670
+ // sessionClearStorageData (which is stable) instead of the async cookie
11671
+ // enumeration that previously crashed and led to this being stubbed out.
11672
+ dispatch_sync_main_void([partitionStr]() {
11673
+ WebKitWebsiteDataManager* dataManager = getDataManagerForPartition(partitionStr.c_str());
11674
+ if (!dataManager) {
11675
+ return;
11676
+ }
11677
+
11678
+ GMainLoop* loop = g_main_loop_new(NULL, FALSE);
11679
+
11680
+ webkit_website_data_manager_clear(dataManager, WEBKIT_WEBSITE_DATA_COOKIES, 0, nullptr,
11681
+ [](GObject* source, GAsyncResult* result, gpointer user_data) {
11682
+ GMainLoop* loop = static_cast<GMainLoop*>(user_data);
11683
+ GError* error = nullptr;
11684
+ webkit_website_data_manager_clear_finish(WEBKIT_WEBSITE_DATA_MANAGER(source), result, &error);
11685
+ if (error) {
11686
+ g_error_free(error);
11687
+ }
11688
+ g_main_loop_quit(loop);
11689
+ }, loop);
11690
+
11691
+ GSource* timeout = g_timeout_source_new(10000);
11692
+ g_source_set_callback(timeout, [](gpointer data) -> gboolean {
11693
+ g_main_loop_quit(static_cast<GMainLoop*>(data));
11694
+ return G_SOURCE_REMOVE;
11695
+ }, loop, nullptr);
11696
+ g_source_attach(timeout, g_main_loop_get_context(loop));
11697
+
11698
+ g_main_loop_run(loop);
11699
+ g_source_destroy(timeout);
11700
+ g_source_unref(timeout);
11701
+ g_main_loop_unref(loop);
11702
+ });
11659
11703
  }
11660
11704
 
11661
11705
  // Clear storage data (WebKit2GTK)