Lace / docs

Lace-320 · HTTP Browser Compatibility

Tags: browser, http, compatibility, dx

Purpose

Applications need to use 300 browser addresses in ordinary HTTP browsers. This specification defines an HTTP bridge, JavaScript address classes, and a fallback for ordinary HTML links.

The bridge provides address compatibility, not checked native-browser resolution. The HTTP server chooses the executable bytes and asserts any Group, App, or interface key metadata presented to JavaScript. The future checked resolution design is non-normative and lives under docs/experimental/browser/.

One HTTP path carries every browser coordinate

A compatibility host exposes a bridge base such as:

https://host.example/lace

Appending a 300 encoded coordinate gives its HTTP path:

lace://u//jukebox/http//join.html
https://host.example/lace//u//jukebox/http//join.html

Everything after /lace uses the 300 encoded-coordinate grammar:

//<group>//<app>//<name>

The host may configure any number of (Group, App) mappings. Each mapping names an interface key, represented by a canonical By value, and a filesystem checkout or another app-owned resource source. A syntactically valid coordinate always has an HTTP projection; an unconfigured mapping returns not found.

Lace-300 requires the HTTP-compatible frontend identified by <app-name> to publish its entry at //u//<app-name>/http//index.html. A compatibility host serving that bundle therefore maps Group u and App <app-name>/http. The /http segment remains part of App in window.address; HTTP projection does not translate it to the base bundle’s <app-name> App scope. Application-chosen addresses outside that publication coordinate retain their ordinary 300 meaning.

This path shape preserves ordinary relative references. From:

https://host.example/lace//u//jukebox/http//pages/join.html

../main.mjs resolves to:

https://host.example/lace//u//jukebox/http//main.mjs

There is no separate static-resource route.

The host parses the raw request target

The host matches the bridge base on a segment boundary and parses the remaining raw path with the 300 custom coordinate parser. It splits structural separators before percent-decoding and decodes each field exactly once.

The host MUST reject malformed encoding, encoded /, decoded backslash, empty segments, . or .. traversal, and decoded values invalid under 010. A reverse proxy that merges //, decodes separators, or normalizes the path before the host sees it is incompatible with the bridge.

A host root outside the bridge may redirect to one configured entry address. The bridge itself serves only complete Group/App/Name paths and does not infer an entry Name from an incomplete coordinate.

Query and fragment text do not enter Name.

HTTP query and fragment project JSONqa

The HTTP projection supports top-level JSONqa strings and arrays:

Examples:

?page=5                     -> {page:5}
?tag=a&tag=b                -> {tag:[a,b]}
?draft=                     -> {draft}
?page=5#results             -> {page:5,#:results}
?via=wss%3Ahost%2Finterlace -> {via:"wss:host/interlace"}
?by=V.EXAMPLE.H3            -> {by:V.EXAMPLE.H3}

Query parsing uses UTF-8 application/x-www-form-urlencoded decoding, including + as SP. Fragment parsing uses UTF-8 percent-decoding without translating +. Malformed encoding is invalid. Decoded keys and values MUST satisfy 310, and #, via, and by MUST satisfy 300.

The inverse emits a scalar as one query pair, an app-defined array as repeated pairs, and # as the fragment. Nested objects and nested arrays are not representable. A compatibility URL generator rejects a browser address outside this subset.

EXAMPLE By values are symbolic rather than valid 009 payloads.

Bootstrap describes the current interface

The compatibility bootstrap descriptor has this shape:

{
  "profile": "lace-http-browser-compat-v1",
  "group": "u",
  "app": "jukebox/http",
  "by": "V.EXAMPLE_INTERFACE_BY.H3",
  "bridgeBase": "https://host.example/lace"
}

All fields are required for a bridge page that installs window.address. Group and App validate under 010, and by uses canonical 009 verification-key text. The V prefix is 009’s verification-key type tag. bridgeBase is an absolute HTTP or HTTPS URL with no query or fragment. A page that only installs Lace-anchor fallback needs bridgeBase but no current Group/App descriptor. How the page receives configuration is an app-hosting choice.

In HTTP mode, the server and compatibility library assert this metadata. They do not create browser authority. A projected by value must equal the configured interface key; mismatch fails startup.

Compatibility uses the 300 address classes

The library supplies the URC, Address, WindowAddress, and LaceWindowAddress classes defined by 300.

On a bridge page, window.address is one stable LaceWindowAddress. Reading window.address.href returns the canonical 300 address reconstructed from the HTTP path, query, and fragment. Assigning a valid browser URC to window.address.href converts it to the HTTP bridge URL and navigates with window.location. Assigning window.address forwards to href.

App and fragment changes with unchanged via and by update the live address without reloading. Changing via or by performs a full HTTP navigation.

Apps use window.address.href for programmatic Lace navigation. They do not assign window.location a lace: URL in compatibility mode.

Lace anchors become ordinary HTTP anchors

Any HTTP page that installs the compatibility library with a bridgeBase may write a canonical Lace link:

<a href="lace://u//whatsup/http//index.html{room:general}">
  Open room
</a>

In compatibility mode the library parses the Lace address, stores its canonical form in data-lace-href, and replaces href with the HTTP projection:

<a
  href="https://host.example/lace//u//whatsup/http//index.html?room=general"
  data-lace-href="lace://u//whatsup/http//index.html{room:general}"
>
  Open room
</a>

The library processes existing anchors and anchors added or changed later. An invalid or unrepresentable Lace address fails conversion and MUST NOT fall through to external-protocol navigation.

Rewriting href preserves normal left click, middle click, context-menu, target, and new-window behavior. HTTP browsers copy the HTTP fallback from the rewritten href; applications that offer a Lace-address share action use data-lace-href or an Address value.

The compatibility library assumes that it is the active fallback and does not try to detect an operating-system protocol handler.

The HTTP server has final say

The reference host serves configured filesystem trees. Another app host may produce the same HTTP shape from its own resource source, but the HTTP browser cannot distinguish sources from JavaScript address state. This profile does not define a checked-record resolver. The server can replace the bytes or compatibility code, so HTTP remains the execution authority.

An HTTP origin may host several Lace (Group, App) address scopes. The HTTP browser treats them as same-origin and collapses their DOM, storage, worker, cookie, and window isolation. This is a known bridge limitation, not an invalid deployment.

Response behavior stays ordinary HTTP

The host should support GET and HEAD and return a non-success status for an unknown or invalid coordinate. HEAD returns the GET metadata without a body.

Active resources need a correct Content-Type and X-Content-Type-Options: nosniff. The host preserves relative document, module, stylesheet, worker, image, and media paths. It does not turn an unknown Name into a command or unrelated entry page.

Normal HTTP cache, CSP, referrer, TLS, proxy, authentication, and access-control policy remains deployment policy.

via remains a Lace hint

An HTTP query via projects the 300 acquisition hint. The app may use it with browser Lace operations. It does not make the HTTP server or endpoint an interface authority, prove peer identity, or grant app authority. A consuming runtime may use canonical wss: for the 060 confidential-channel default, but PeerConfidential still requires the live minimal Seal proof. A reverse proxy terminating WSS and forwarding WS to laced requires the explicit backend trust-confidential-channel override; that complete proxy path becomes trusted.

An app-specific default endpoint stays outside address state unless the host redirects to an HTTP URL containing via.

laced is not the compatibility host

The compatibility host is app or reference infrastructure. A laced ILTP listener MUST NOT serve these application routes.

A reverse proxy may expose the app host and a laced WebSocket listener under one public host, but /lace and /interlace remain separate roles.

Failure

The bridge rejects malformed bootstrap values, coordinates, path encoding, query or fragment state, JSONqa, and by mismatches. It returns an error for an unconfigured Group/App or missing interface resource.