TAU/ DOCS

Cross-Origin Isolation

Configure COOP, COEP, and CORP headers so SharedArrayBuffer-backed kernels (multi-threaded WASM and geometry pool) load on every browser, including Safari.

@taucad/runtime needs crossOriginIsolated === true for its SharedArrayBuffer-backed features. Two layers own SABs — the active transport allocates the geometry pool and cooperative-abort channel internally, and the multi-threaded OpenCASCADE WASM heap belongs to the kernel — but they share one isolation requirement: the top-level document must be served with the right COOP, COEP, and CORP headers.

Without isolation the runtime still works, degraded: the geometry pool falls back to copy delivery, render abort to wire notification, and auto-selected OCCT kernels to single-threaded WASM. The worker logs a structured warning naming the degradation, so the failure is observable in telemetry rather than silent.

The runtime ships an adapter for each layer that produces responses. Use them; do not duplicate header strings in your app.

The required headers

SharedArrayBuffer is blocked by default to mitigate Spectre-class attacks. To opt in, the document must declare:

HeaderValuePurpose
Cross-Origin-Opener-Policysame-originIsolates the top-level browsing context.
Cross-Origin-Embedder-Policyrequire-corpForces every embedded resource to declare CORP.
Cross-Origin-Resource-Policysame-originAllows the document and same-origin subresources to load under COEP.

Safari is strictly conformant: under require-corp, every subresource — including same-origin worker scripts and WASM binaries — must carry an explicit CORP header. Chromium and Firefox are more permissive, which is why a missing CORP header on a worker often appears as a Safari-only eternal-loading bug. Set the headers at every layer that produces a response; missing any one of HTML, worker-script, or WASM responses breaks Safari.

LayerAdapter
Vite dev/preview server@taucad/runtime/vite#tauRuntime
Next.js@taucad/runtime/nextjs/config#withTauRuntime
React Router SSR (the HTML document)@taucad/runtime/react-router
Express/Connect production server@taucad/runtime/cross-origin-isolation/express
Electron renderer session@taucad/runtime/electron/main
Static host with declarative headersYour host's config (e.g. netlify.toml, _headers)

Vite dev/preview

import { tauRuntime } from '@taucad/runtime/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [tauRuntime()],
});

tauRuntime() includes the isolation adapter plus the runtime's asset and worker invariants. Reach for the lower-level crossOriginIsolation() export only when another integration already supplies those build invariants.

Next.js

import { withTauRuntime } from '@taucad/runtime/nextjs/config';

export default withTauRuntime();

withTauRuntime() composes existing application headers with the canonical runtime rules. Use nextRuntimeHeaders() only when another config composer owns the bundler configuration.

React Router SSR

import { applyHandleRequestHeaders } from '@taucad/runtime/react-router';

export default function handleRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  routerContext: EntryContext,
) {
  applyHandleRequestHeaders(responseHeaders);
  // …existing renderToPipeableStream logic
}

Express production server

Mount coiMiddleware() before express.static so worker scripts and WASM responses carry CORP. The middleware also suppresses downstream res.append() of COI headers, so a downstream Response writer (e.g. @react-router/express) cannot duplicate the triple:

import express, { type Express } from 'express';
import { createRequestHandler } from '@react-router/express';
import { coiMiddleware } from '@taucad/runtime/cross-origin-isolation/express';

type ServerBuild = Parameters<typeof createRequestHandler>[0]['build'];

export function createApp(build: ServerBuild): Express {
  const app = express();
  app.disable('x-powered-by');
  app.use(coiMiddleware());
  app.use('/assets', express.static('build/client/assets', { immutable: true, maxAge: '1y' }));
  app.use(express.static('build/client', { maxAge: '1h' }));
  app.all('*splat', createRequestHandler({ build }));
  return app;
}

Electron

Install the renderer-session headers after app.whenReady() and before creating runtime windows:

import { app } from 'electron';
import { installElectronRuntimeHeaders } from '@taucad/runtime/electron/main';

await app.whenReady();
installElectronRuntimeHeaders();

Static hosts

Behind a CDN, configure the headers declaratively. For Netlify:

[[headers]]
  for = "/*"
  [headers.values]
    Cross-Origin-Opener-Policy = "same-origin"
    Cross-Origin-Embedder-Policy = "require-corp"
    Cross-Origin-Resource-Policy = "same-origin"

Verify

Check each response class — HTML document, worker script, WASM binary — for exactly one copy of all three headers:

curl -sI http://localhost:3000/ | grep -i cross-origin
curl -sI http://localhost:3000/assets/file-manager.worker-XXXXX.js | grep -i cross-origin
find apps/ui/build/client/assets -name '*.wasm' -print
curl -sI http://localhost:3000/assets/EMITTED-ASSET.wasm | grep -Ei 'content-type|cross-origin'

Then confirm crossOriginIsolated === true in the browser DevTools console.

Cross-origin APIs

When the isolated document fetches a different origin (an analytics or asset CDN), that origin must opt in with Cross-Origin-Resource-Policy: cross-origin. Use the apiHeaders constant or applyApiHeaders() from @taucad/runtime/cross-origin-isolation on your API responses.

References

On this page