Contents

MōBrowser 2.13.0

MōBrowser 2.13.0 lets renderer code make cross-origin requests to trusted destinations without disabling CORS globally, adds binary clipboard support through clipboard.writeBytes() and clipboard.readBytes(), and introduces an optional executableName so app.name can use any characters.

What’s new 

CORS for trusted origins 

Renderer code could not make cross-origin fetch or XMLHttpRequest requests to endpoints that don’t return an Access-Control-Allow-Origin header, such as an OAuth device-code endpoint like https://github.com/login/device/code. This failed even when your app explicitly trusted the destination:

Access to XMLHttpRequest at 'https://github.com/login/device/code' from origin
'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource.

MōBrowser now grants a narrowly scoped CORS bypass to the origins listed in app.trustedOrigins, while keeping CORS fully enforced for every other origin. Add the destination origin to trustedOrigins in mobrowser.conf.json:

"trustedOrigins": [ "https://github.com" ]

The app’s own origin can now read cross-origin responses from that destination, even when it omits the Access-Control-Allow-Origin header:

// Runs in the renderer at the app origin.
const response = await fetch('https://github.com/login/device/code', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({ client_id: '...', scope: 'read:user' }),
})

The relaxation is directional and scoped: only the app’s own origin is relaxed as the request initiator, and only toward the trusted destinations. Requests to untrusted origins continue to be blocked by CORS, and no other page hosted by the app gains any relaxation.

Binary clipboard data 

Previously the clipboard API could only read and write strings, so binary formats such as PDFs or images were mangled when encoded as text. The clipboard API can now read and write raw bytes through the new writeBytes() and readBytes() methods:

import { clipboard } from '@mobrowser/api';

// The identifier other apps expect: a Uniform Type Identifier on macOS,
// a MIME type elsewhere.
const pdfType = process.platform === 'darwin' ? 'com.adobe.pdf' : 'application/pdf'

// Write bytes to the clipboard.
clipboard.writeBytes(pdfType, new Uint8Array(pdfBytes))

// Read them back.
const bytes: Uint8Array = clipboard.readBytes(pdfType)

Custom executable name 

app.name is used both as the user-visible name and to name every file-system artifact (the executable, the .app bundle, the .exe, and the installers). This coupling prevented using non-ASCII or special characters in app.name, because downstream tools reject them — for example, Apple cannot code-sign a bundle whose name contains ō.

app.name may now contain any characters, including ones the file system or platform toolchains reject (e.g. MōBrowser). Set executableName under app.bundle.macOS, app.bundle.Windows, or app.bundle.Linux to control the ASCII-safe name used for the executable, bundle, and installers. Allowed characters are ASCII letters, digits, spaces, hyphens, and underscores:

{
  "app": {
    "name": "MōBrowser",
    "bundle": {
      "macOS": {
        "executableName": "MoBrowser"
      },
      "Windows": {
        "executableName": "MoBrowser"
      },
      "Linux": {
        "executableName": "MoBrowser"
      }
    }
  }
}

app.name remains the display name (the macOS CFBundleDisplayName, the window title, and so on). When executableName is omitted, app.name is used for both, so existing projects are unaffected.

Fixes and improvements 

  • Resolved the npm warnings printed on npm install in generated projects. Recent npm versions block dependency install scripts unless they are listed in the allowScripts field of package.json, which produced warnings for @mobrowser/sdk-* and fsevents. Generated projects now pre-approve exactly these trusted packages, so npm install runs cleanly while all other dependencies remain unable to run install scripts.