@braidlabs/sw 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +58 -0
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -109,6 +109,64 @@ and cache a composed response (a page pierced against a registry that has since
109
109
  the stale artifact this package exists to avoid). Composed pages carry
110
110
  `x-braid-composed: offline` so a shell can say so rather than look merely slow.
111
111
 
112
+ ## The gateway in the worker, for static hosting (requirements, not built)
113
+
114
+ Offline composition already runs the gateway's piercing in the worker. The open question is whether
115
+ the worker can be the gateway **while online**, for a shell on purely static hosting (a bucket, a
116
+ CDN, GitHub Pages) with no server in front of it. Nothing below is built. It records what an
117
+ implementation must satisfy, so the design starts from the constraints rather than discovering them.
118
+
119
+ **What it would do.** It would serve `/__braid/realm/:id/*` stubs, proxy `/__braid/frag/:id/*` and
120
+ `/__braid/doc/:id/*` to each fragment's origin, and pierce document navigations, all with the
121
+ gateway's own code. That is exactly what offline composition does now, but against the network.
122
+
123
+ ### Requirements
124
+
125
+ 1. **The first visit must work without a reload.** No worker is installed on a first visit, so the
126
+ design is:
127
+ - The static host serves the shell and realm stubs generated at build time. Stubs are
128
+ byte-stable per registry snapshot, so they can be plain files.
129
+ - The page registers the worker, and the worker calls `clients.claim()` for this mode. This is
130
+ a deliberate exception to the `claimClients: false` default above: there is no earlier worker
131
+ to swap out from under the page.
132
+ - Slots wait for `navigator.serviceWorker.ready`, with a timeout, before booting. From then on
133
+ the realm iframes' navigations and the namespace fetches are the worker's to answer.
134
+ - The first visit's first paint is not composed. Fragments boot client-side, which already works
135
+ without piercing. Every later navigation is composed by the worker.
136
+ 2. **Fragment origins must send CORS headers.** The worker fetches them cross-origin. Documents and
137
+ assets need `Access-Control-Allow-Origin` naming the shell's origin, and module scripts need it
138
+ regardless.
139
+ 3. **Authenticated fragments must be same-site with the shell** (subdomains of one registrable
140
+ domain). With credentials, the worker's cross-origin requests also need
141
+ `Access-Control-Allow-Credentials`. Across sites, third-party cookie blocking (Safari, Firefox,
142
+ and Chrome where enabled) drops the session. A fragment that needs login cookies from another
143
+ site cannot be composed this way, and the build should refuse its manifest rather than let it
144
+ fail at runtime.
145
+ 4. **There must be a fallback where no worker can run.** Some private-browsing modes and enterprise
146
+ policies disable service workers. Without a worker, compat fragments have no namespace, so the
147
+ page must boot those slots as contract or untrusted fragments, or show their fallback content.
148
+ It must never leave them half-booted.
149
+ 5. **What the server gateway enforces must stay enforced.** Today's server gateway strips
150
+ credentials (`forwardCredentials`), checks `access`, and decides redirects (`redirectOrigins`).
151
+ In the worker, all of that runs on the user's device, which makes it advisory: a user can
152
+ change it. Anything that must hold against the user stays on the fragment's own origin. The
153
+ docs must say so plainly, as the boundary docs do for trusted fragments.
154
+ 6. **The registry must be pinned.** The worker loads one snapshot (`snapshotUrl`), verifies it as
155
+ the registry does, and composes only from it. Updating the snapshot follows the worker's
156
+ version discipline (see below), so configuration churn never becomes an unannounced change of
157
+ composition mid-session.
158
+ 7. **The gateway core stays runtime-neutral.** No `node:` imports in the gateway, registry or
159
+ rewriter, which offline composition already depends on. A new dependency of the core that
160
+ breaks this breaks both.
161
+
162
+ ### Open questions
163
+
164
+ - **Worker startup on every navigation.** A cold start can add tens of milliseconds on mobile.
165
+ Navigation preload can fetch the shell while the worker boots, but there is no server to ask for
166
+ the fragments early.
167
+ - **Which `x-braid-composed` value** a worker-composed online page should carry, so it can be told
168
+ apart from a server-composed one in telemetry.
169
+
112
170
  ## The worker is itself a skew vector
113
171
 
114
172
  It is a long-lived deployment artifact that updates on its own schedule — a version boundary added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@braidlabs/sw",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Braid service worker — skew-aware asset serving for composed pages: each fragment gets its own build-keyed cache partition, so a page already open keeps getting the chunks it was built against after a deploy lands. Ships as a handler to compose into an existing worker, and as a complete worker.",
5
5
  "keywords": [
6
6
  "micro-frontends",
@@ -25,8 +25,8 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "peerDependencies": {
28
- "@braidlabs/data": "^0.6.0",
29
- "@braidlabs/gateway": "^0.6.0"
28
+ "@braidlabs/data": "^0.7.0",
29
+ "@braidlabs/gateway": "^0.7.0"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"