npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@braidlabs/gateway

v0.6.0

Published

Braid gateway — fetch-native origin-front middleware that routes fragment traffic by exact id under the reserved /__braid/frag/ namespace, loads fragment manifests, and passes everything else through to your existing app.

Readme

@braidlabs/gateway

Every /__braid/… URL this package serves — what asks for it, when, and what comes back — is walked through in Braid, explained.

The Braid gateway: fetch-native, platform-neutral origin-front middleware. Routes fragment traffic by exact id under the reserved /__braid/frag/:fragmentId/* namespace — no route pattern sniffing, no header-trust fallback — and passes everything else through to your existing app.

Braid's founding architecture lives in docs/braid-architecture.md.

Also see: failure modes · CDN configuration · using Braid without the gateway

Usage

import { createGateway } from '@braidlabs/gateway';

const gateway = createGateway({
  registry: [
    // adapter defaults to "compat" — zero fragment code required
    { id: 'legacy-billing', endpoint: 'https://billing.internal', pierce: ['/billing/*'] },
  ],
});

The registry is data, not code: pass inline manifests, a URL to a JSON array of manifests, or an async loader (file/KV/database). Deploying a fragment never redeploys the gateway.

A fragment that ships a web component rather than a whole app declares the adapter, the module to load, and the element to mount:

{ id: 'rating', endpoint: 'https://widgets.example.com',
  adapter: 'custom-element', entry: '/star-rating.js', element: 'star-rating',
  events: ['rating:change'] }

The registry as an FDC3 App Directory

createGateway({ registry, discovery: { appd: true } });

Serves the same registry as an FDC3 2.2 App Directory: /__braid/registry/appd/v2/apps lists { applications, message }, and /appd/v2/apps/{appId} returns the bare Application record. It is a projection, not a second directory — same manifests, same access.list rules — so a caller can never see through AppD a resolver that discovery would have hidden. findIntent becomes a registry query, and a user only sees resolvers they may use.

Manifests contribute intents through an fdc3 block and listing metadata through appd:

{ id: 'billing', endpoint: '…', pierce: ['/billing/*'],
  fdc3: { listensFor: { ViewInvoice: { contexts: ['fdc3.instrument'] } },
          raises: { ViewChart: ['fdc3.instrument'] } },
  appd: { publisher: 'Payments', contactEmail: '[email protected]' } }

Two mapping decisions worth knowing:

  • details.url is a page, when there is one. AppD asks where a web app lives; a fragment lives inside a host page. If the fragment declares pierce, the first concrete pattern names a page it actually appears on and that is the URL — follow it and you see the app. Otherwise the mount is used, and hostManifests.braid.standalonePage says which you got.
  • Braid launch detail rides in hostManifests, which is what AppD reserves for exactly this. A fragment is mounted into a page, not opened as a window, so a Braid-aware agent reads hostManifests.braid and mounts a <fragment-slot>; one that does not falls back to the URL.

An app the caller may not list 404s (with AppD's { code, message } error body) exactly as an unregistered one does — distinguishing them would let an unauthorized caller enumerate the registry one id at a time.

Records are validated in the test suite against FDC3 2.2's own App Directory schema. Relative icon src values are resolved against the origin, since AppD requires absolute URLs, and a link that is not http(s) is dropped rather than passed on. Optional members Braid has no data for (lang, screenshots, localizedVersions, interop.appChannels) are not produced. To serve the same directory from the governed registry instead of a gateway, see createRegistryApi({ appd }) in @braidlabs/registry; to give fragments window.fdc3, see @braidlabs/fdc3.

A relative entry is re-rooted into the fragment's namespace, so the module and its imports are fetched through the gateway rather than from the host's root. Such a fragment serves no document, and the gateway answers its document request with 204 rather than forwarding it.

Bindings

The core is handle(request, next) — fetch-native and platform-neutral. Piercing needs to read the shell's response, so each binding differs in how it obtains it. All three below are covered by integration tests against the real frameworks (bindings.spec.ts).

Express / Connect / Vite / plain http — mount it first; next() runs the rest of the app, and the gateway reads what it writes:

import { toNodeMiddleware } from '@braidlabs/gateway/node';

app.use(toNodeMiddleware(gateway));

Angular SSR (@angular/ssr/node) — mount toNodeMiddleware on Express before the Angular handler, and enable trustProxyHeaders on AngularNodeAppEngine so forwarded gateway headers are accepted:

const angularApp = new AngularNodeAppEngine({
  allowedHosts: ['localhost', '127.0.0.1'],
  trustProxyHeaders: true,
});
app.use(toNodeMiddleware(gateway));

NestJS — the Express adapter is a Connect stack, so the same binding applies:

const app = await NestFactory.create(AppModule);
app.use(toNodeMiddleware(gateway));

Nitro / h3 / Workers / Deno / Bun — wrap the app's fetch handler:

import { toFetchHandler } from '@braidlabs/gateway';
import { toWebHandler } from 'h3';

export default toFetchHandler(gateway, toWebHandler(app));

For a built Nitro app, the gateway also composes in front of the generated Node listener, which needs no Nitro internals and matches the "origin-front middleware" model:

import { listener } from './.output/server/index.mjs';

const braid = toNodeMiddleware(gateway);
createServer((req, res) => braid(req, res, () => listener(req, res)));

A fetch-style middleware form is available too: toWebMiddleware(gateway)(request, () => shellResponse). In every binding the shell application runs at most once per request.

What it serves

  • Realm stubs (/__braid/realm/:id/*): a minimal document carrying the composition protocol version, the manifest-declared adapter, and a <base> that keeps every relative subresource request inside the fragment's namespace. Version mismatches fail in the client as named errors — no title-check heuristics.
  • Fragment documents (/__braid/doc/:id/*): the fragment's HTML prepared for the host page's DOM — exactly what piercing injects, for the client-boot path. Fetched at the page's route, unless the manifest declares documentPath (/index.html) for an SPA on a static origin that 404s every route. A fragment's redirect here is reported as an error, or — for a fragment that opts in — followed as a page navigation; see Login redirects.
  • Fragment assets/data (/__braid/frag/:id/*): forwarded to the endpoint with the prefix stripped, so endpoints see the same paths they serve standalone. Redirects pass through unfollowed; each fragment gets a manifest-declared timeout budget.
  • Pierced documents: see below.
  • Unknown ids: 404, never the app shell.

Piercing

Add pierce patterns to a manifest and the gateway server-renders that fragment into the page:

{ id: 'legacy-billing', endpoint: 'https://billing.internal', pierce: ['/billing', '/billing/*'] }

On a matching document request the gateway fetches the shell and every matching fragment concurrently, then interleaves the fragments into the shell's response stream — a fragment never serializes behind the shell. Each fragment lands in the <fragment-slot> that names it, as a declarative shadow root, so the browser parses it into exactly the shape the client runtime would have built; the slot then adopts it instead of fetching. Shells with no matching slot get one created before </body>.

A shell can instead mark one <fragment-slot outlet>. It takes the page's routed (bound) fragment, the first in registration order that no earlier named slot claimed, and is named after it. A shell that composes many routes then needs one slot rather than one per fragment id. Unbound widgets never fill an outlet. A named slot after the outlet is too late for a fragment the outlet already took, so the gateway unnames it (data-braid-in-outlet) and warns, rather than let the client boot a second copy. The outlet is filled on full page loads only.

Fragment HTML is transformed on the way through: the doctype is stripped, <html>/<head>/<body> become braid-html/braid-head/braid-body (start and end tags), scripts are neutralized to type="inert", and script preload links become rel="inert-*". Fragment scripts are therefore never live in the host realm, not even between parsing and activation. The gateway does add <link rel="prefetch"> hints for the fragment's own scripts (inside its shadow root, never inside its document) so their downloads start before the client boots it; a prefetch fetches into the HTTP cache and never executes anything.

If a fragment can't be server-rendered, the page still renders and the slot is left for the client runtime to fill — a transient SSR failure self-heals rather than becoming a visible error. Set fallback: 'error-html' on the manifest when a missing section is worse than a visible failure.

The three namespaces

Each kind of thing the gateway serves has its own path. That is a caching decision: a URL whose response depends on a request header needs that header in every cache key between here and the browser, and most CDNs ignore Vary on anything but Accept-Encoding.

| Path | Serves | Cacheable | | --- | --- | --- | | /__braid/frag/:id/* | the fragment's own endpoint — assets, data, anything it serves | yes, on URL alone — this is nearly all the traffic | | /__braid/realm/:id/* | the realm stub the fragment's hidden iframe boots from | yes, on URL alone (1h + stale-while-revalidate) | | /__braid/doc/:id/* | the fragment's document, prepared for the host page's DOM | per the fragment's own cache headers |

No braid URL varies on a request header. Point a CDN at them and they cache correctly with no configuration at all.

Mounting under a path

A host that shares its domain and does not own the root — /manage/ behind a load balancer — moves the namespaces under its mount. Set the same basePath on both sides:

createGateway({ registry, basePath: '/manage' }); // serves /manage/__braid/{frag,realm,doc}/…
initBraid({ basePath: '/manage' });               // host page: requests them there

The gateway then leaves root /__braid/* alone. Page URLs are unaffected: pierce patterns still match the full pathname (/manage/goals/*). serviceWorker, discovery, and telemetry.webVitals do not support a basePath yet, and combining them with one throws.

The one thing that does vary

| Header | URL | Response changes to | Why | | --- | --- | --- | --- | | sec-fetch-dest: document | a page URL some fragment pierces | the shell with fragments composed into it | A page navigation gets a complete document with fragments already inside. The same URL fetched by a client-side router wants the SPA's own payload, and injecting a declarative shadow root into that would corrupt it. The browser sets this header; it must reach the origin. |

Both representations carry Vary: sec-fetch-dest — and, because most CDNs honor Vary only for Accept-Encoding, the gateway also rewrites Cache-Control on these URLs to keep them out of shared caches: public and s-maxage are dropped, private is added, and your own max-age / no-store / stale-while-revalidate are untouched. Browser caching still works.

Set pierceCacheControl: 'preserve' to opt out — only if the pages are anonymous and you have put sec-fetch-dest into the edge's cache key. See CDN configuration.

The gateway sends Vary: sec-fetch-dest on those page responses.

Why Vary at all. HTTP caches key on the URL. When one URL can return different bodies depending on a request header, the cache must include that header in its key or it hands the wrong body to the next caller. Vary is how the origin says which headers matter — but it is advisory, and many CDNs honor it only for Accept-Encoding. Since only page URLs vary now, and page URLs are usually personalized and uncacheable anyway, the practical advice is simply: don't edge-cache pierced pages. See CDN setup.

Login redirects (opt-in)

A fragment that needs a login answers its document request with a redirect. A browser fetch cannot act on that: followed, it dies as a CORS error; told not to follow, it hides where the redirect was going. So by default the client reports a named fragment-fetch error, and the redirect goes nowhere.

A fragment can opt in to having the page follow it instead:

createGateway({
  registry: [{ id: 'goals', endpoint: 'https://goals.internal/', redirect: 'navigate' }],
  redirectOrigins: ['https://login.example.com', 'https://*.example.com'],
  additionalHeaders: (request) => ({ 'x-user': signedIdentityFor(request) }), // see below
});

For that fragment's /__braid/doc/ requests the gateway answers a redirect with a 409 carrying the target in x-braid-redirect-location (never a 3xx, which the browser would hide again), and the client navigates the whole page there — what the shell would have done had the redirect hit the top-level request. Nothing else changes: other fragments, and the /__braid/frag/ namespace, keep passing redirects through.

Where it may go. The target is chosen by the fragment's endpoint and becomes a top-level navigation, so it is checked, and anything else is refused with a 502:

| Target | Result | | --- | --- | | A path on the host's own origin (including /__braid/…, for a login that is itself a fragment) | followed as a host path | | A path inside the fragment's own endpoint (/apps/goals/login for https://goals.internal/apps/goals/) | mapped to the same path on the host (/login) | | An origin in redirectOrigins — exact (https://login.example.com) or a subdomain wildcard (https://*.example.com, which does not match example.com itself) | followed as given | | javascript:, data:, any other scheme, any other origin | refused |

Return URLs. A fragment builds ?next= from the URL it saw, which is its own and means nothing to the user. A query parameter whose whole value is that URL (its path, on the fragment's origin or the host's; the query is ignored) is pointed at the page the user was on, taken from the x-braid-return-url header the client sends (the Referer header is the fallback, and only a page on the gateway's origin is ever used). The header is read by the gateway and not forwarded to the fragment, because a page URL can carry a token in its hash. Other parameters keep their exact bytes. Not rewritten: a return URL buried inside another parameter's value (an OAuth state, say), and a parameter equal to the fragment's bare root /, which is usually an OAuth redirect_uri.

Concurrent requests are not coalesced for a fragment that opts in: a redirect's cookies carry the login's state and nonce, and sharing one with another caller would share those too.

The loop. The gateway strips the caller's cookies by default, so a fragment that redirects because it cannot see who the user is will redirect again after login sends them back — forever. The client follows a given fragment's redirect at most once per 30 seconds (remembered in sessionStorage; if that is unavailable it does not follow at all) and reports an error instead. It only works end to end once the fragment can see the user: forwardCredentials, or a per-caller header via additionalHeaders. The gateway warns when a fragment opts in and neither is set — at startup for an inline registry, on the first redirect for a URL or loader registry.

Discovery endpoint (optional)

For shells that build their UI from the registry rather than hard-coding slot names — a launcher, an admin console, a directory of available apps — the gateway can publish a paginated listing. It is off by default, because a registry describes internal topology.

const gateway = createGateway({
  registry,
  discovery: {
    path: '/__braid/registry', // default
    pageSize: 100, // default; also the ceiling unless maxPageSize says otherwise
    principal: (request) => sessionFrom(request), // → { roles, permissions }
  },
});
GET /__braid/registry?page=2&pageSize=50
{
  "items": [{ "id": "billing", "title": "Billing", "adapter": "compat", "mount": "/__braid/frag/billing/" }],
  "page": 2, "pageSize": 50, "total": 137, "totalPages": 3, "hasMore": true,
  "protocolVersion": "1"
}

Defaults that protect you. Internal endpoint values are withheld unless you set includeEndpoints. Listings are no-store and vary on cookie/authorization, so a shared cache can never serve one caller's listing to another. Page size is capped however large a number the caller asks for.

Development mode lists everything — every fragment, with endpoints, ignoring access rules — and logs a warning at startup saying so. That is deliberate for local debugging and must not ship; the response carries "unfiltered": true so a client can tell.

Access: who may list, who may load

Everything is public by default. A manifest with no access is listed for everyone and loadable by everyone. Restrict only what needs restricting, and declare it at registration so a fragment's own team owns its exposure rather than every host re-deciding it.

{
  "id": "payroll",
  "endpoint": "https://payroll.internal",
  "access": {
    "list": { "roles": ["finance", "admin"] },   // who sees it in the registry
    "fetch": { "roles": ["finance"] }            // who may actually load it
  }
}

The two rules are independent, which is the point:

| list | fetch | Behavior | | --- | --- | --- | | open | open | the default — a public fragment | | open | restricted | shown in a launcher, refused on load; listings mark it "loadable": false so the UI can render that state | | restricted | open | kept out of listings, still loadable by anyone with a deep link | | restricted | restricted | invisible and unreachable — to that caller it does not exist |

Within a rule, roles are any-of (holding one of them is enough) and scopes are all-of (an operation requiring two scopes needs both). Declare either or both.

Wire up who is asking once, at the gateway:

createGateway({
  registry,
  principal: (request) => sessionFrom(request), // → { roles, scopes }
  discovery: {},
});

principal is only consulted for fragments that actually declare access, so a public registry never pays for a session lookup on asset requests.

Enforcement. access.fetch applies to every namespace request — the realm stub, the document, and every asset — and to piercing, where an unauthorized fragment is simply not composed into the page (the slot is left empty rather than the page failing). A caller who may list but not load gets 403; a caller who may not even list it gets 404, because confirming existence would turn the namespace into an inventory of what they cannot reach.

Development mode bypasses access rules entirely, so local work needs no session wiring.

This is authorization for composition, not a substitute for the fragment's own. The fragment's endpoint should still authorize the requests it receives.

Telemetry (optional)

Off unless configured. One hook, two kinds of event — what the gateway did, and what the browser experienced — both attributed to the fragment responsible.

createGateway({
  registry,
  telemetry: {
    on: (event) => otel.emit(event),
    webVitals: true,   // also collect LCP/CLS/INP/FCP/TTFB in the browser
    sampleRate: 0.1,   // of browser sessions, not of metrics
  },
});

| Event | When | Carries | | --- | --- | --- | | fragment-fetch | the gateway fetched a fragment endpoint | fragmentId, phase, outcome, status, durationMs | | web-vital | a browser reported a vital | name, value, rating, fragmentId, pathname |

phase separates a pierce fetch, which delays the page, from a namespace fetch, which delays only that fragment. outcome reports a 5xx as ok with its status: the distinction an operator needs is did we reach it, and folding a reachable-but-broken endpoint in with an unreachable one loses it.

Why per-fragment vitals are the point

Server-side timings per fragment are ordinary — a reverse proxy gives you those. Web vitals per fragment are not, because in a composed page the page-level number is an average over apps owned by different teams. "The page has a CLS of 0.31" starts an argument; "ninety percent of the layout shift happened inside reviews" ends it.

Attribution works by climbing from the reported element to its enclosing <fragment-slot> — through shadow roots, since a pierced fragment's DOM lives in a declarative shadow root where closest() stops at the boundary. fragmentId: null is a real answer, not a gap: TTFB belongs to the document, and an LCP element in the shell's own markup is genuinely the shell's.

webVitals is off by default because it serves a collector from /__braid/vitals.js and injects it into every composed page, which is a deployment's decision rather than a library's. The collector is ~2 kB, hand-written rather than pulling in web-vitals, and beacons to /__braid/vitals on visibilitychange/pagehide.

That endpoint is reachable by anyone who can load the page, so nothing it receives is trusted: metric names are checked against the five, values must be finite and positive, the pathname is stripped of its query and length-capped, the batch is capped, and a fragmentId the registry does not know is nulled rather than relayed. It always answers 204 — the browser is unloading and nothing is listening, so a status code would only tell a prober what the endpoint accepts.

The hook is wrapped: a throwing sink is logged once and then muted, because a feature meant to be left on in production must not be able to take the site down. (observe deliberately does not do this — a broken analysis hook should fail loudly, since silently recording nothing corrupts the decisions its data feeds.)

What the listing publishes

Each entry carries what a consumer needs to embed the fragment, not just name it: id, title, adapter, mount, pierce, loadable, and — because they change the required markup — bound and src. A widget embedded without its src renders an empty shell on every page, so a listing that omitted it would force every consumer to guess. endpoint appears only when includeEndpoints is on, or in development.

The registry console uses exactly this to generate copy-pasteable integration code per fragment.

Circuit breaker (optional)

createGateway({ registry, breaker: true });            // 3 failures, 10s cooldown
createGateway({ registry, breaker: { failureThreshold: 5, resetTimeoutMs: 30_000 } });

The problem is compounding, not failure. A fragment endpoint that is down already costs its full timeoutMs — but it costs that on every request, because nothing remembers the last one. Four fragments at a 3s budget is a page held hostage to the worst of them, repeatedly, with the shell's response waiting behind it. The fallback machinery already handles a fragment that fails; what it cannot do is stop paying to rediscover that it fails.

So this is a latency control first, an availability control second. When the circuit is open the manifest's declared fallback is served immediately instead of after the budget expires — the rendered result is identical, it just arrives in ~0ms.

Per fragment id, never global: fragments are independently deployed, and one team's bad release must not shed another team's traffic. A 5xx counts as a failure (reachable is not the same as working). A shed request reports outcome: 'shed' rather than 'error', so an operator counting failures does not count our own load-shedding as the endpoint failing again. Transitions arrive on the telemetry hook as kind: 'breaker' — on the four state edges only, never per request.

Off unless configured, because shedding load is a behaviour change a deployment should opt into.

Concurrent-fetch coalescing (on by default)

Composing a page costs one origin fetch per fragment. A widget pierced into / and /* is fetched once per render, so fifty concurrent renders are fifty identical fetches of the same header panel. The gateway collapses those into one.

createGateway({ registry });                                  // on
createGateway({ registry, coalesceFragmentFetches: false });  // off

Not a cache. It only notices that a fetch it is already making is the one another request wants; nothing outlives the request that started it. No TTL, no invalidation, no shared state, and no dependence on which instance a request lands on — which is what makes it safe by default on ECS or any horizontally scaled deployment.

The key is computed from the request that is actually sent, so it contains exactly what the endpoint can see: user-agent, the negotiation headers, any header the gateway itself added via additionalHeaders, and — when forwardCredentials is on — cookie and authorization. A fragment declaring access rules is never shared at all.

Because credentials are not forwarded by default, two signed-in users produce a byte-identical fragment request and do share a flight, which is correct: the endpoint cannot tell them apart. Turn on forwardCredentials, or add a per-caller header, and they stop sharing again. Sharing a render across identities the endpoint can distinguish is a data leak wearing a performance feature's clothes, so anything that varies by caller has to be in the key.

For an endpoint that varies on something the gateway cannot see — a tenant or feature-flag header — opt out on the manifest with coalesce: false.

How much it saves scales with endpoint latency × concurrency. Against a 120ms endpoint, ten parallel renders collapse to one fetch; against a fragment on localhost answering in 10ms the requests barely overlap and it saves nothing. Measure somewhere that resembles production.

Content Security Policy

The gateway injects inline markup into someone else's document: the <style> that makes slots lay out as blocks, and — when webVitals is on — the collector <script>. Under a strict policy (script-src 'nonce-…') the browser drops anything unstamped silently, which is the worst failure shape available: the page renders, the slot layout rule is gone, and no server log mentions it.

So the gateway reads the nonce from the shell's own Content-Security-Policy response header and stamps what it injects. Nothing to configure — it works if your shell already sends a nonce.

It never mints one. A nonce the shell's policy does not list is not trusted, and a nonce reused across responses is not a nonce. A shell with no policy, or one using hashes or 'unsafe-inline', gets unstamped markup, which is correct for all three.

Security posture

The trusted tier is namespace isolation, not a security boundary: fragments are same-origin with the host and share its cookies, storage, and DOM reachability. What the gateway does guarantee is that no code a fragment's markup carries inline can execute outside the fragment's realm or navigate the host page — with one opt-in exception, login redirects, whose targets are restricted to the host's origin, the fragment's own endpoint, and redirectOrigins — scripts are neutralized, inline on* handlers are stripped, <meta http-equiv="refresh"> is defanged, and frames whose document the markup carries inline lose it: iframe[srcdoc], and any iframe/embed/object URL other than http(s):, a path, or about:blank (so javascript:, data:, blob:). srcdoc and javascript: run on parse with the host's origin, no click needed; data: and blob: are refused alongside them as the same markup-as-document shape. Each removal is named on the tag in data-braid-blocked. The rule is deliberately blunt — it also removes a sandboxed srcdoc and a data: PDF or SVG in an object — so serve such content from a URL instead. A frame that loads a document from the fragment's own namespace (<iframe src="widget.html">) is left alone: it runs the fragment's code with the host's origin, which its realm already does. The full list, the trade-offs and the workarounds: What the gateway does to fragment markup.

Deliberately not neutralized, because they require a user to click rather than executing on parse: javascript: URLs on links (a, area) and form actions. A trusted fragment can navigate a page the user clicks through.

Defaults worth knowing: x-forwarded-proto/x-forwarded-host are overwritten from the real request (opt into passthrough with trustForwardedHeaders only behind a proxy you control); an endpoint's path is a boundary, so endpoint: 'https://internal/apps/billing/' cannot be used to reach the rest of that origin; and the caller's Cookie and Authorization are not forwarded to fragment endpoints.

That last one is the trust boundary between a shell and the fragments it composes. Those headers authenticate the caller to the shell's origin, and a fragment endpoint is frequently a different team and often a different company — forwarding them would let every fragment backend act as that user against the shell. A fragment that needs to know who is asking should be given something scoped to it: a per-request assertion via additionalHeaders, or a token exchanged for the fragment's own audience. forwardCredentials: true restores the old behaviour, and is only appropriate when every endpoint in the registry sits inside the same trust boundary as the shell. When only some do, pass a function instead, forwardCredentials: (fragment) => …, and the gateway decides per fragment. A function that throws forwards nothing, and websocket upgrades follow the same decision. proxy-authorization is stripped with them, and credentialHeaders adds any identity header an auth proxy in front of the shell injects (x-auth-request-access-token, cf-access-jwt-assertion, …).

Not yet implemented from the architecture's security section: allow-listed manifest origins and signed manifests. Until those land, treat the registry as trusted configuration.

The rewriter is owned, not forked. rewriteHtmlStream is a small streaming HTML rewriter with bounded memory and chunk-boundary safety; its conformance vectors (html-rewrite-stream.spec.ts) are the oracle any second implementation — a native HTMLRewriter path on workerd, say — must pass before it is allowed to serve traffic. Only the owned path ships today, because HTMLRewriter does not exist in Node and an untested dual path is how the upstream project got wasm/native drift.