@braidlabs/sw 0.7.1 → 0.8.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.
package/README.md CHANGED
@@ -109,63 +109,160 @@ 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.
112
+ **What it keeps is one person's.** The parts are fetched with the user's cookies, and the cache
113
+ outlives the session. It keeps nothing the origin marked `Cache-Control: no-store` (and drops a copy
114
+ it kept before the origin said so), and nothing for a route no fragment pierces. `private` pages are
115
+ kept: that directive is about shared caches, this one is the browser's own, and the gateway marks
116
+ every pierced page `private` by default. So clear it at sign-out, or the next person on the device
117
+ is served the last one's pages whenever the network drops. A refresh still running when the clear
118
+ lands does not write afterwards:
119
+
120
+ ```ts
121
+ // in the page, at sign-out
122
+ navigator.serviceWorker.controller?.postMessage({ type: 'braid-sw:clear' }); // replies { type: 'braid-sw:cleared', ok }
123
+
124
+ // or in your own worker
125
+ import { clearBraidCaches } from '@braidlabs/sw';
126
+ await clearBraidCaches();
127
+ ```
128
+
129
+ ## The gateway in the worker, for static hosting (`@braidlabs/sw/gateway`, proof of concept)
130
+
131
+ Offline composition runs the gateway's piercing in the worker against the cache. The
132
+ `@braidlabs/sw/gateway` entry runs the **whole gateway** in the worker against the network. That's
133
+ for a shell on purely static hosting (a bucket, a CDN, GitHub Pages) with no server to put a gateway
134
+ on. It's the same `createGateway` the server runs, with the network as its shell.
135
+
136
+ ```js
137
+ // sw.js — bundled, and served from the root so its scope covers the shell
138
+ import { setupBraidGateway } from '@braidlabs/sw/gateway';
139
+
140
+ setupBraidGateway({
141
+ registry: [{ id: 'billing', endpoint: new URL('/billing-app/', self.location.origin).href, pierce: ['/billing/*'] }],
142
+ claimClients: true, // the installing page composes without a reload
143
+ assets: {}, // optional: the skew cache, in front of the in-worker gateway
144
+ });
145
+ ```
146
+
147
+ Its own entry, rather than part of `@braidlabs/sw`, because it is a different decision. The main
148
+ entry keeps a *server* gateway's assets alive and stays small enough to compose into any worker. It
149
+ bundles none of the gateway's router. This entry *is* the router, rewriter and piercing.
150
+
151
+ To compose it into a worker you already own, use `braidGatewayHandler(options)`. It returns a handler
152
+ that decides synchronously, as `respondWith` requires:
153
+ - It claims same-origin requests under `/__braid/` (or under `basePath`) and the browser's own GET
154
+ navigations.
155
+ - Everything else, including a page's own `fetch` for HTML, returns `null`.
156
+
157
+ Its `.fetch` routes any request through the gateway. Hand it to the asset handler, and the skew
158
+ cache sits in front of the in-worker gateway as it would in front of a server one. Without it, the
159
+ asset handler's misses go to the network, and on a static host that's a 404:
160
+
161
+ ```js
162
+ const braid = braidGatewayHandler({ registry });
163
+ const assets = braidFetchHandler({ fetch: braid.fetch });
164
+ self.addEventListener('fetch', (event) => {
165
+ if (!braid.claims(event.request)) return; // the asset handler matches by path alone, on any origin
166
+ const handled = assets(event.request) ?? braid(event.request);
167
+ if (handled) event.respondWith(handled);
168
+ });
169
+ ```
170
+
171
+ The page starts Braid once the worker controls it. Until then `/__braid/` is a 404 on a static host.
172
+ A hard reload loads the page past a worker that is already active, and an active worker doesn't
173
+ claim a page unasked, so the page asks:
174
+
175
+ ```js
176
+ if (!navigator.serviceWorker.controller) {
177
+ const changed = new Promise((resolve) => navigator.serviceWorker.addEventListener('controllerchange', resolve, { once: true }));
178
+ const registration = await navigator.serviceWorker.register('/sw.js', { type: 'module', scope: '/' });
179
+ registration.active?.postMessage({ type: 'braid-sw:claim' }); // BRAID_CLAIM_MESSAGE, honoured with claimClients
180
+ await changed;
181
+ }
182
+ initBraid();
183
+ ```
184
+
185
+ [`examples/sw-gateway`](../../examples/sw-gateway) is the proof of concept. It's a static server with
186
+ no gateway, serving the fragment zstd-compressed as a CDN would. The fragment composes, boots in its
187
+ realm, pierces, and comes back after a hard reload. The repository's e2e runs that example in
188
+ Chromium and asserts no `/__braid/` request ever reaches the server.
189
+
190
+ ### What running in a browser changed
191
+
192
+ The server never meets any of these. The e2e found each one, and fails without its fix:
193
+
194
+ - **Navigation requests can't be copied.** The gateway derives fragment requests with
195
+ `new Request(url, request)`, which a browser refuses for a `navigate`-mode request. The gateway
196
+ caught the error and pierced a placeholder.
197
+ - The handler now hands the gateway a non-navigation copy, and the shell still loads through the
198
+ browser's own navigation.
199
+ - The copy sends credentials as a page's own `fetch` would (same-origin), not as the navigation's
200
+ `include`.
201
+ - It keeps a POST's body.
202
+ - **`accept-encoding` is a forbidden header.** The gateway pins it on a server so it knows which
203
+ codings `fetch` decoded, and a browser silently drops the pin. The gateway now notices the header
204
+ didn't take and trusts the browser to have decoded whatever it asked for, instead of refusing
205
+ `zstd` with a 502.
206
+ - **Navigation preload is off.** The browser preloads *every* navigation in scope, including the
207
+ realm frames' navigations, which the worker answers itself. Each would also go to a server with no
208
+ answer for it. `setupBraidGateway` turns preload off. A worker of your own that enables it should
209
+ expect those requests.
210
+
211
+ Two came from review rather than the e2e, and have specs:
212
+ - **A redirecting shell is handed back to the browser.** A navigation's own `fetch` returns an
213
+ opaque redirect, for example when the host answers `/billing` with `/billing/`. It can't be copied
214
+ into a new response, so the gateway passes any status-0 shell through untouched.
215
+ - **A page's `fetch` for HTML isn't a navigation.** The gateway can't see `Sec-Fetch-Dest` from a
216
+ worker. Claiming an htmx or Turbo request by its `Accept` header would pierce it as a document.
217
+
218
+ ### Requirements, and where each stands
219
+
220
+ 1. **The first visit must work without a reload.** *Met in the POC, partly.*
221
+ - The page registers the worker and starts the runtime once a controller exists, and
222
+ `claimClients` hands it the page. A hard reload asks the active worker to claim it.
223
+ - The first paint isn't composed. Fragments boot client-side, and every later navigation is
224
+ pierced by the worker.
225
+ - Still open: build-time realm stubs, and a timeout on the wait.
226
+ 2. **Fragment origins must send CORS headers.** *Documented, not exercised.* The worker reads what
227
+ it pierces, so a cross-origin endpoint needs `Access-Control-Allow-Origin` naming the shell's
228
+ origin. The POC's endpoint is same-origin. The endpoint also has to be public: on a server it can
229
+ sit behind the gateway, but here the browser fetches it.
230
+ 3. **Authenticated fragments must be same-origin with the shell.** *Documented.* The worker can't set
231
+ `Cookie` by name, and its fragment requests send credentials same-origin only, as the page's own
232
+ do. So a same-origin endpoint gets the browser's cookies and a cross-origin one gets none.
233
+ `forwardCredentials` and per-fragment cookie scoping can't take effect: the browser's cookie rules
234
+ replace them.
235
+ 4. **There must be a fallback where no worker can run.** *Open.* Without a worker, the namespace is
236
+ a 404 on a static host. The POC page waits for a controller indefinitely.
237
+ 5. **What the server gateway enforces is advisory here.**
238
+ - `access` and `redirectOrigins` run on the user's device, where the user can change them.
239
+ Anything that must hold against the user stays on the fragment's own origin.
240
+ - Everything in the options ships in the public `sw.js`, `additionalHeaders` included, so they
241
+ must hold no secrets.
242
+ - A fragment's redirect comes back to the worker opaque, so `redirect: 'navigate'` can't be
243
+ honoured. It fails closed: a pierced slot falls back to its placeholder.
244
+ - On `SameSite`, by reasoning rather than a browser test: a worker pierce sends a same-origin
245
+ fragment the cookies the page's own client-side compose would send a moment later. That
246
+ includes `Strict` ones after a cross-site link, which a server pierce wouldn't see. The shell
247
+ should refuse cross-site framing, and the example sends `X-Frame-Options: SAMEORIGIN`.
248
+ 6. **The registry must be pinned.** *Open.* The POC bakes its registry into the worker, so a
249
+ registry change is a worker update. That's version discipline of a kind, but it isn't
250
+ `snapshotUrl` loading and verification.
251
+ 7. **The gateway core stays runtime-neutral.** *Holds.* The worker bundles the gateway apart from two
252
+ fixes that apply on any runtime: the coding fix above, and passing an opaque shell through. A
253
+ worker that imports only the main entry carries none of it.
161
254
 
162
255
  ### Open questions
163
256
 
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.
257
+ - **Worker startup on every navigation.** With preload off, a navigation's shell request waits for
258
+ the worker to boot, which can be tens of milliseconds on mobile. Requests it doesn't answer no
259
+ longer pay that where the browser has static routing. `setupBraidGateway` declares its namespace
260
+ and navigations at install (`staticRoutes`, on by default), and everything else goes straight to
261
+ the network.
167
262
  - **Which `x-braid-composed` value** a worker-composed online page should carry, so it can be told
168
263
  apart from a server-composed one in telemetry.
264
+ - **`assets` together with `basePath`.** The asset handler only recognises the namespace at the
265
+ root, so `setupBraidGateway` refuses the combination for now.
169
266
 
170
267
  ## The worker is itself a skew vector
171
268
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@braidlabs/sw",
3
- "version": "0.7.1",
3
+ "version": "0.8.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",
@@ -22,11 +22,15 @@
22
22
  "types": "./src/index.d.ts",
23
23
  "default": "./src/index.js"
24
24
  },
25
+ "./gateway": {
26
+ "types": "./src/gateway.d.ts",
27
+ "default": "./src/gateway.js"
28
+ },
25
29
  "./package.json": "./package.json"
26
30
  },
27
31
  "peerDependencies": {
28
- "@braidlabs/data": "^0.7.1",
29
- "@braidlabs/gateway": "^0.7.1"
32
+ "@braidlabs/data": "^0.8.0",
33
+ "@braidlabs/gateway": "^0.8.0"
30
34
  },
31
35
  "publishConfig": {
32
36
  "access": "public"
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `@braidlabs/sw/gateway` — the Braid gateway, run inside the service worker.
3
+ *
4
+ * Its own entry rather than part of `@braidlabs/sw`, because it is a different decision: the main
5
+ * entry keeps a server gateway's assets alive across deploys, and stays small enough to compose
6
+ * into any worker. This one *is* the gateway — the whole router, rewriter, and piercing — for an
7
+ * origin with no server to run it on. A worker that imports only the main entry never bundles it.
8
+ */
9
+ export { braidGatewayHandler, setupBraidGateway, BRAID_CLAIM_MESSAGE, } from './lib/gateway.js';
10
+ export type { BraidGatewayHandler, BraidGatewayHandlerOptions, BraidGatewayWorkerOptions, } from './lib/gateway.js';
package/src/gateway.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `@braidlabs/sw/gateway` — the Braid gateway, run inside the service worker.
3
+ *
4
+ * Its own entry rather than part of `@braidlabs/sw`, because it is a different decision: the main
5
+ * entry keeps a server gateway's assets alive across deploys, and stays small enough to compose
6
+ * into any worker. This one *is* the gateway — the whole router, rewriter, and piercing — for an
7
+ * origin with no server to run it on. A worker that imports only the main entry never bundles it.
8
+ */
9
+ export { braidGatewayHandler, setupBraidGateway, BRAID_CLAIM_MESSAGE, } from './lib/gateway.js';
10
+ //# sourceMappingURL=gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../../../libs/braid-sw/src/gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC"}
package/src/index.d.ts CHANGED
@@ -14,7 +14,7 @@ export { braidFetchHandler, pruneFragmentCaches } from './lib/asset-handler.js';
14
14
  export type { BraidFetchHandlerOptions, AssetOutcome, AssetReport } from './lib/asset-handler.js';
15
15
  export { setupBraidWorker } from './lib/worker.js';
16
16
  export type { BraidWorkerOptions } from './lib/worker.js';
17
- export { braidNavigationHandler } from './lib/compose.js';
17
+ export { braidNavigationHandler, clearBraidCaches } from './lib/compose.js';
18
18
  export type { OfflineCompositionOptions } from './lib/compose.js';
19
19
  export { precacheRealmStubs } from './lib/precache.js';
20
20
  export type { PrecacheOptions, PrecacheResult } from './lib/precache.js';
package/src/index.js CHANGED
@@ -12,7 +12,7 @@
12
12
  */
13
13
  export { braidFetchHandler, pruneFragmentCaches } from './lib/asset-handler.js';
14
14
  export { setupBraidWorker } from './lib/worker.js';
15
- export { braidNavigationHandler } from './lib/compose.js';
15
+ export { braidNavigationHandler, clearBraidCaches } from './lib/compose.js';
16
16
  export { precacheRealmStubs } from './lib/precache.js';
17
17
  export { createReportQueue, BRAID_REPORT_SYNC_TAG } from './lib/reports.js';
18
18
  export { diagnoseSkew, BRAID_BUILD_HEADER, BRAID_SNAPSHOT_HEADER } from './lib/skew-report.js';
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/braid-sw/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAGhF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG5E,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/braid-sw/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAGhF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAG5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG5E,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { type FragmentCacheOptions } from './fragment-caches.js';
1
2
  /**
2
3
  * Skew-aware asset serving: the one layer that can keep an open page working after a deploy.
3
4
  *
@@ -28,7 +29,7 @@ export interface AssetReport {
28
29
  /** The cache partition that answered, or would have. */
29
30
  partition: string;
30
31
  }
31
- export interface BraidFetchHandlerOptions {
32
+ export interface BraidFetchHandlerOptions extends FragmentCacheOptions {
32
33
  /**
33
34
  * The build this worker was shipped as.
34
35
  *
@@ -66,7 +67,4 @@ export declare function braidFetchHandler(options?: BraidFetchHandlerOptions): (
66
67
  * old chunks this handler exists to keep. A fragment that has left the registry, on the other hand,
67
68
  * is never coming back for them.
68
69
  */
69
- export declare function pruneFragmentCaches(keep: readonly string[], options?: {
70
- cachePrefix?: string;
71
- caches?: CacheStorage;
72
- }): Promise<string[]>;
70
+ export declare function pruneFragmentCaches(keep: readonly string[], options?: FragmentCacheOptions): Promise<string[]>;
@@ -1,5 +1,5 @@
1
1
  import { parseBraidPathname } from '@braidlabs/gateway';
2
- const DEFAULT_CACHE_PREFIX = 'braid-frag';
2
+ import { DEFAULT_CACHE_PREFIX, deleteFragmentBuckets, keptWithBuckets, openFragmentCache, usesBuckets } from './fragment-caches.js';
3
3
  /**
4
4
  * Builds a fetch handler for the Braid namespace.
5
5
  *
@@ -13,7 +13,6 @@ const DEFAULT_CACHE_PREFIX = 'braid-frag';
13
13
  */
14
14
  export function braidFetchHandler(options = {}) {
15
15
  const cachePrefix = options.cachePrefix ?? DEFAULT_CACHE_PREFIX;
16
- const cacheStorage = options.caches ?? globalThis.caches;
17
16
  const networkFetch = options.fetch ?? globalThis.fetch;
18
17
  return (request) => {
19
18
  // GET only. A cache cannot answer a POST, and pretending otherwise is how a worker turns a
@@ -32,7 +31,7 @@ export function braidFetchHandler(options = {}) {
32
31
  async function serve(request, url, fragmentId) {
33
32
  const partition = `${cachePrefix}:${fragmentId}`;
34
33
  const report = (outcome) => options.onReport?.({ fragmentId, url: url.href, outcome, partition });
35
- const cache = await cacheStorage?.open(partition);
34
+ const cache = await openFragmentCache(fragmentId, options);
36
35
  try {
37
36
  const response = await networkFetch(request);
38
37
  // 404 is the deploy case, and the only status worth reaching into the cache for. A 500 is the
@@ -77,16 +76,19 @@ export function braidFetchHandler(options = {}) {
77
76
  export async function pruneFragmentCaches(keep, options = {}) {
78
77
  const cachePrefix = options.cachePrefix ?? DEFAULT_CACHE_PREFIX;
79
78
  const cacheStorage = options.caches ?? globalThis.caches;
80
- if (!cacheStorage)
81
- return [];
82
79
  const kept = new Set(keep.map((id) => `${cachePrefix}:${id}`));
83
80
  const removed = [];
84
- for (const name of await cacheStorage.keys()) {
85
- if (!name.startsWith(`${cachePrefix}:`) || kept.has(name))
81
+ // The shared cache storage first: with buckets on, this is also where a worker that just
82
+ // switched left its old per-fragment caches. A kept fragment's shared cache is superseded only
83
+ // once its bucket exists; one whose bucket was refused falls back to it, and keeps it.
84
+ const superseded = new Set(usesBuckets(options) ? await keptWithBuckets(keep, options) : []);
85
+ for (const name of (await cacheStorage?.keys()) ?? []) {
86
+ if (!name.startsWith(`${cachePrefix}:`) || (kept.has(name) && !superseded.has(name.slice(cachePrefix.length + 1))))
86
87
  continue;
87
88
  await cacheStorage.delete(name);
88
89
  removed.push(name);
89
90
  }
91
+ removed.push(...(await deleteFragmentBuckets(keep, options)));
90
92
  return removed;
91
93
  }
92
94
  //# sourceMappingURL=asset-handler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset-handler.js","sourceRoot":"","sources":["../../../../../libs/braid-sw/src/lib/asset-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"asset-handler.js","sourceRoot":"","sources":["../../../../../libs/braid-sw/src/lib/asset-handler.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { type FragmentCacheOptions } from './fragment-caches.js';
1
2
  /**
2
3
  * Offline composition: the gateway's own piercing, run inside the worker.
3
4
  *
@@ -29,6 +30,8 @@ export interface OfflineCompositionOptions {
29
30
  snapshotUrl: string;
30
31
  cachePrefix?: string;
31
32
  caches?: CacheStorage;
33
+ /** Keep fragment documents in per-fragment Storage Buckets, as the asset handler does with `buckets`. */
34
+ buckets?: boolean;
32
35
  fetch?: typeof fetch;
33
36
  /** Called when a page is composed offline, so a shell can say so rather than look merely slow. */
34
37
  onCompose?: (event: {
@@ -52,3 +55,9 @@ export interface OfflineCompositionOptions {
52
55
  * while the worker is still booting, rather than after.
53
56
  */
54
57
  export declare function braidNavigationHandler(options: OfflineCompositionOptions): (request: Request, preloadResponse?: Promise<Response | undefined>) => Promise<Response> | null;
58
+ /**
59
+ * Deletes every page and fragment document kept for offline composition, and the fragments' cached
60
+ * assets with them. Call it at sign-out: what was composed for one person must not be composed for
61
+ * the next. A page can ask its worker to do it with `postMessage({ type: 'braid-sw:clear' })`.
62
+ */
63
+ export declare function clearBraidCaches(options?: FragmentCacheOptions): Promise<void>;
@@ -1,5 +1,10 @@
1
1
  import { BRAID_DOCUMENT_PREFIX, Registry, pierceShellHtml, } from '@braidlabs/gateway';
2
- const DEFAULT_CACHE_PREFIX = 'braid-frag';
2
+ import { DEFAULT_CACHE_PREFIX, deleteFragmentBuckets, openFragmentCache } from './fragment-caches.js';
3
+ /**
4
+ * Bumped by every clear. A refresh started before a clear must not write after it: it was fetched
5
+ * with the previous person's cookies, and putting it back would undo the sign-out it raced.
6
+ */
7
+ let generation = 0;
3
8
  const SHELL_CACHE = 'braid-shell';
4
9
  const SNAPSHOT_CACHE = 'braid-snapshot';
5
10
  /**
@@ -54,25 +59,44 @@ export function braidNavigationHandler(options) {
54
59
  async function refresh(request) {
55
60
  if (!cacheStorage)
56
61
  return;
62
+ const startedIn = generation;
63
+ const current = () => generation === startedIn;
57
64
  const url = new URL(request.url);
58
65
  const manifests = await loadSnapshot(url.origin);
59
66
  if (!manifests)
60
67
  return;
61
68
  const registry = new Registry([...manifests]);
62
69
  const matches = await registry.matchPierceRoutes(url.pathname);
70
+ // A route no fragment pierces has nothing to compose, and its page is not worth keeping.
71
+ if (matches.length === 0)
72
+ return;
63
73
  const shell = await networkFetch(new Request(request.url, { headers: { 'sec-fetch-dest': 'empty' } }));
64
- if (shell.ok) {
65
- const shellCache = await cacheStorage.open(SHELL_CACHE);
74
+ if (!current())
75
+ return;
76
+ const shellCache = await cacheStorage.open(SHELL_CACHE);
77
+ if (shell.ok && mayKeep(shell))
66
78
  await shellCache.put(shellKey(url), shell.clone());
67
- }
79
+ // A page the origin now says must not be stored loses the copy kept before it said so.
80
+ else if (shell.ok)
81
+ await shellCache.delete(shellKey(url));
68
82
  for (const manifest of matches) {
69
83
  const documentUrl = `${url.origin}${BRAID_DOCUMENT_PREFIX}${encodeURIComponent(manifest.id)}${documentPath(manifest, url)}`;
70
84
  const response = await networkFetch(documentUrl);
85
+ if (!current())
86
+ return;
71
87
  if (!response.ok)
72
88
  continue;
73
89
  // In the fragment's own partition, so pruning a retired fragment takes its documents too.
74
- const cache = await cacheStorage.open(`${cachePrefix}:${manifest.id}`);
75
- await cache.put(documentUrl, response.clone());
90
+ const cache = await openFragmentCache(manifest.id, options);
91
+ // a sign-out may have cleared while the bucket opened: nothing of the old session is written back
92
+ if (!current())
93
+ return;
94
+ if (!cache)
95
+ continue;
96
+ if (mayKeep(response))
97
+ await cache.put(documentUrl, response.clone());
98
+ else
99
+ await cache.delete(documentUrl);
76
100
  }
77
101
  }
78
102
  async function composeFromCache(request) {
@@ -88,11 +112,14 @@ export function braidNavigationHandler(options) {
88
112
  return null;
89
113
  const registry = new Registry([...manifests]);
90
114
  const matches = await registry.matchPierceRoutes(url.pathname);
115
+ // Nothing to compose: a shell kept for this route by an older build is not served alone.
116
+ if (matches.length === 0)
117
+ return null;
91
118
  const fragments = [];
92
119
  for (const manifest of matches) {
93
- const cache = await cacheStorage.open(`${cachePrefix}:${manifest.id}`);
120
+ const cache = await openFragmentCache(manifest.id, options);
94
121
  const documentUrl = `${url.origin}${BRAID_DOCUMENT_PREFIX}${encodeURIComponent(manifest.id)}${documentPath(manifest, url)}`;
95
- const cached = await cache.match(documentUrl);
122
+ const cached = await cache?.match(documentUrl);
96
123
  // A fragment with nothing cached pierces nothing and is marked, exactly as a failed fetch is
97
124
  // server-side: the slot degrades to a placeholder rather than the page failing.
98
125
  fragments.push({
@@ -140,6 +167,34 @@ export function braidNavigationHandler(options) {
140
167
  }
141
168
  }
142
169
  }
170
+ /**
171
+ * Whether a response may be kept for an offline compose: anything but `no-store`.
172
+ *
173
+ * `private` is no reason to refuse. It keeps a response out of *shared* caches, and this cache is the
174
+ * browser's own — and the gateway adds `private` to every pierced page by default, so refusing it
175
+ * would turn offline composition off. What a private page needs is to leave with its person, which
176
+ * is `clearBraidCaches` at sign-out.
177
+ */
178
+ function mayKeep(response) {
179
+ const directives = (response.headers.get('cache-control') ?? '').toLowerCase().split(',').map((part) => part.trim());
180
+ return !directives.includes('no-store');
181
+ }
182
+ /**
183
+ * Deletes every page and fragment document kept for offline composition, and the fragments' cached
184
+ * assets with them. Call it at sign-out: what was composed for one person must not be composed for
185
+ * the next. A page can ask its worker to do it with `postMessage({ type: 'braid-sw:clear' })`.
186
+ */
187
+ export async function clearBraidCaches(options = {}) {
188
+ // Before anything else, so a refresh already running does not write after this clear.
189
+ generation += 1;
190
+ const cacheStorage = options.caches ?? globalThis.caches;
191
+ if (!cacheStorage)
192
+ return;
193
+ const prefix = `${options.cachePrefix ?? DEFAULT_CACHE_PREFIX}:`;
194
+ const names = await cacheStorage.keys();
195
+ await Promise.all(names.filter((name) => name === SHELL_CACHE || name.startsWith(prefix)).map((name) => cacheStorage.delete(name)));
196
+ await deleteFragmentBuckets(null, options, { always: true });
197
+ }
143
198
  /** Unbound fragments are fetched at their own path, bound ones at the page's — as on the server. */
144
199
  function documentPath(manifest, url) {
145
200
  return manifest.bound === false && manifest.src ? manifest.src : `${url.pathname}${url.search}`;
@@ -1 +1 @@
1
- {"version":3,"file":"compose.js","sourceRoot":"","sources":["../../../../../libs/braid-sw/src/lib/compose.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compose.js","sourceRoot":"","sources":["../../../../../libs/braid-sw/src/lib/compose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Where a fragment's cached files live: one Cache Storage cache per fragment (`braid-frag:<id>`),
3
+ * or, with `buckets: true` where the browser has Storage Buckets (Chromium), that same cache inside
4
+ * a bucket of the fragment's own.
5
+ *
6
+ * A bucket is the browser's unit of eviction, quota and deletion. In one shared Cache Storage, a
7
+ * device short on space can evict every fragment's files at once, and the deploy-skew save — the
8
+ * chunk an old page still asks for after a deploy — goes with them. Per-fragment buckets are evicted
9
+ * one fragment at a time, and pruning a fragment that left the registry deletes its bucket outright.
10
+ *
11
+ * Opt-in: turning it on moves where files are kept, so a worker that switches starts with empty
12
+ * fragment caches once (pruning removes the old ones).
13
+ */
14
+ /** The per-fragment cache prefix, unless a worker names its own. */
15
+ export declare const DEFAULT_CACHE_PREFIX = "braid-frag";
16
+ export interface FragmentCacheOptions {
17
+ /** Prefix for the per-fragment caches. Defaults to `braid-frag`. */
18
+ cachePrefix?: string;
19
+ /** Cache storage to use (tests, or a worker that wraps it). Defaults to the global. */
20
+ caches?: CacheStorage;
21
+ /** Keep each fragment's cache in a Storage Bucket of its own where the browser has them. */
22
+ buckets?: boolean;
23
+ /** The bucket manager to use (tests). Defaults to `navigator.storageBuckets`. */
24
+ storageBuckets?: StorageBucketsLike;
25
+ }
26
+ export interface StorageBucketsLike {
27
+ open(name: string): Promise<{
28
+ caches: CacheStorage;
29
+ }>;
30
+ keys(): Promise<string[]>;
31
+ delete(name: string): Promise<void>;
32
+ }
33
+ /** The cache a fragment's files are kept in, or undefined where there is no cache storage. */
34
+ export declare function openFragmentCache(fragmentId: string, options?: FragmentCacheOptions): Promise<Cache | undefined>;
35
+ /**
36
+ * Deletes the fragment buckets this worker's prefix made, except those for `keep` (all of them when
37
+ * null). Only names in this worker's exact format: buckets are the whole origin's, and a looser match
38
+ * would take the realm's database buckets (`braid-db-…`), another worker's, or the app's own.
39
+ *
40
+ * `always` deletes even when `buckets` is off, where the API exists: sign-out must not leave a
41
+ * previous configuration's buckets, which may hold a previous user's offline documents.
42
+ */
43
+ export declare function deleteFragmentBuckets(keep: readonly string[] | null, options?: FragmentCacheOptions, { always }?: {
44
+ always?: boolean;
45
+ }): Promise<string[]>;
46
+ /** Whether this worker keeps fragment caches in buckets: asked for, and available. */
47
+ export declare function usesBuckets(options: FragmentCacheOptions): boolean;
48
+ /** The fragments among `keep` whose bucket exists, so their shared caches are superseded. */
49
+ export declare function keptWithBuckets(keep: readonly string[], options: FragmentCacheOptions): Promise<string[]>;
50
+ /**
51
+ * A fragment's bucket name: lowercase letters, digits, `-` and `_`, at most 64 characters, as the
52
+ * API requires. The readable part may collide once folded; the hash of the exact id keeps two
53
+ * fragments apart.
54
+ */
55
+ export declare function bucketFor(fragmentId: string, options?: FragmentCacheOptions): string;