Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions package/src/bun/core/BrowserWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export type WindowOptionsType<T = undefined> = {
// Use for untrusted content (remote URLs) to prevent malicious sites from
// accessing internal APIs, creating OOPIFs, or communicating with Bun
sandbox: boolean;
// CEF partition for session/cookie isolation. Use "persist:<name>" for persistent storage.
partition: string | null;
};

const defaultOptions: WindowOptionsType = {
Expand All @@ -62,6 +64,7 @@ const defaultOptions: WindowOptionsType = {
hidden: false,
navigationRules: null,
sandbox: false,
partition: null,
};

export const BrowserWindowMap: {
Expand Down Expand Up @@ -126,6 +129,7 @@ export class BrowserWindow<T extends RPCWithTransport = RPCWithTransport> {
navigationRules: string | null = null;
// Sandbox mode disables RPC and only allows event emission (for untrusted content)
sandbox: boolean = false;
partition: string | null = null;
frame: {
x: number;
y: number;
Expand Down Expand Up @@ -155,6 +159,7 @@ export class BrowserWindow<T extends RPCWithTransport = RPCWithTransport> {
this.hidden = options.hidden ?? false;
this.navigationRules = options.navigationRules || null;
this.sandbox = options.sandbox ?? false;
this.partition = options.partition || null;

this.init(options);
}
Expand Down Expand Up @@ -238,6 +243,7 @@ export class BrowserWindow<T extends RPCWithTransport = RPCWithTransport> {
windowId: this.id,
navigationRules: this.navigationRules,
sandbox: this.sandbox,
partition: this.partition,
startPassthrough: this.passthrough,
});

Expand Down
63 changes: 27 additions & 36 deletions package/src/native/macos/nativeWrapper.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5788,45 +5788,34 @@ void Cancel() override {
CefRefPtr<CefRequestContext> CreateRequestContextForPartition(const char* partitionIdentifier,
uint32_t webviewId) {
NSLog(@"DEBUG CEF: CreateRequestContextForPartition called for webview %u, partition: %s", webviewId, partitionIdentifier ? partitionIdentifier : "null");
CefRequestContextSettings settings;
if (!partitionIdentifier || !partitionIdentifier[0]) {
settings.persist_session_cookies = false;
} else {
std::string identifier(partitionIdentifier);
bool isPersistent = identifier.substr(0, 8) == "persist:";

if (isPersistent) {
std::string partitionName = identifier.substr(8);
NSString* appSupportPath = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject];

// Build path with identifier/channel structure to match root_cache_path logic
std::string cachePathStr = buildPartitionPath(
[appSupportPath UTF8String],
g_electrobunIdentifier,
g_electrobunChannel,
"CEF",
partitionName
);
NSString* cachePath = [NSString stringWithUTF8String:cachePathStr.c_str()];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:cachePath]) {
[fileManager createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:nil];
}
settings.persist_session_cookies = true;
CefString(&settings.cache_path).FromString([cachePath UTF8String]);
} else {
settings.persist_session_cookies = false;
}

std::string identifier(partitionIdentifier ? partitionIdentifier : "");
bool isPersistent = identifier.size() >= 8 && identifier.substr(0, 8) == "persist:";

// For persistent partitions, use the global request context which already has
// a working profile at root_cache_path/Default with cookie persistence.
// CefRequestContext::CreateContext with custom cache_path fails in Chrome runtime
// with "Cannot create profile at path" — the global context avoids this entirely.
if (isPersistent) {
CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
NSLog(@"DEBUG CEF: Using global request context for persistent partition '%s'", partitionIdentifier);

// Register scheme handler factory for views:// protocol
static CefRefPtr<ElectrobunSchemeHandlerFactory> schemeFactory = new ElectrobunSchemeHandlerFactory();
bool registered = context->RegisterSchemeHandlerFactory("views", "", schemeFactory);
NSLog(@"DEBUG CEF: Registered scheme handler factory - success: %s", registered ? "yes" : "no");

return context;
}

// Non-persistent (ephemeral) partition — create an isolated in-memory context
CefRequestContextSettings settings;
settings.persist_session_cookies = false;
CefRefPtr<CefRequestContext> context = CefRequestContext::CreateContext(settings, nullptr);

// Register scheme handler factory for this request context
// Note: Each CefRequestContext needs its own registration - it's not global
static CefRefPtr<ElectrobunSchemeHandlerFactory> schemeFactory = new ElectrobunSchemeHandlerFactory();
bool registered = context->RegisterSchemeHandlerFactory("views", "", schemeFactory);
NSLog(@"DEBUG CEF: Registered scheme handler factory for partition '%s' - success: %s",
partitionIdentifier ? partitionIdentifier : "(default)", registered ? "yes" : "no");
NSLog(@"DEBUG CEF: Registered scheme handler factory for ephemeral partition - success: %s", registered ? "yes" : "no");

return context;
}
Expand Down Expand Up @@ -6537,6 +6526,11 @@ - (void)windowDidResignKey:(NSNotification *)notification {



// Forward declaration — ElectrobunWindow interface needed before initWebview
@interface ElectrobunWindow : NSWindow
@property (nonatomic, assign) BOOL backgroundMediaEnabled;
@end

// Global flags set by setNextWebviewFlags, consumed by initWebview
static struct {
bool startTransparent;
Expand Down Expand Up @@ -7013,9 +7007,6 @@ - (void)windowDidResignKey:(NSNotification *)notification {
}


@interface ElectrobunWindow : NSWindow
@end

@implementation ElectrobunWindow
- (BOOL)canBecomeKeyWindow { return YES; }
- (BOOL)canBecomeMainWindow { return YES; }
Expand Down