@brust/runtime-dom 2.0.0-alpha.31 → 2.0.0-alpha.33

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/package.json +1 -1
  2. package/src/nav/nav.ts +12 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brust/runtime-dom",
3
- "version": "2.0.0-alpha.31",
3
+ "version": "2.0.0-alpha.33",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/nav/nav.ts CHANGED
@@ -52,14 +52,21 @@ export function boot(load: Load = (u) => import(/* @vite-ignore */ u)): () => vo
52
52
  }
53
53
 
54
54
  // ---- the page cache (§10.1): an LRU of 32 documents by URL without its hash, filled by prefetches and navigations,
55
- // fresh for 5 minutes (`data-brust-cache` seconds), any age for back/forward; a fetch in flight (at: Infinity) is shared
55
+ // fresh for 5 minutes (`data-brust-cache` seconds), any age for back/forward; a fetch in flight (at: Infinity) is shared.
56
+ // `seen` (F479): when each URL was last fetched, kept or not (32 of them, oldest out): a prefetch of one fetched less than
57
+ // `data-brust-prefetch-gap` seconds ago (10; 0 = no gap) does nothing. It gates prefetches only; a navigation never waits.
56
58
  const cache = new Map<string, [Promise<Got>, number]>()
59
+ const seen = new Map<string, number>()
60
+ const gap = () => { const s = html.getAttribute('data-brust-prefetch-gap'); return s == null || isNaN(+s) ? 1e4 : +s * 1e3 }
57
61
  const ttl = () => { const s = html.getAttribute('data-brust-cache'); return s == null || isNaN(+s) ? 3e5 : +s * 1e3 }
58
62
  const get = (u: string, any?: boolean, init?: RequestInit): Promise<Got> => {
59
63
  const k = noHash(u)
60
64
  let e = cache.get(k)
61
65
  cache.delete(k)
62
66
  if (!e || !(any || Date.now() - e[1] < ttl())) {
67
+ seen.delete(k)
68
+ seen.set(k, Date.now())
69
+ if (seen.size > 32) seen.delete(seen.keys().next().value!)
63
70
  const p = fetch(k, init).then(async (r) => ({ status: r.status, url: r.url, type: r.headers.get('content-type') ?? '', text: await r.text(), no: r.status >= 400 || /no-store/i.test(r.headers.get('cache-control') ?? '') }))
64
71
  const f = (e = [p, Infinity])
65
72
  const drop = () => cache.get(k) === f && cache.delete(k)
@@ -117,7 +124,9 @@ export function boot(load: Load = (u) => import(/* @vite-ignore */ u)): () => vo
117
124
  const prefetch = (t: EventTarget | null) => {
118
125
  const l = target(t)
119
126
  const c = (navigator as { connection?: { saveData?: boolean; effectiveType?: string } }).connection
120
- if (!l || l[0].closest('[data-brust-prefetch="false"]') || c?.saveData || /2g/.test(c?.effectiveType ?? '')) return
127
+ if (!l || l[0].closest('[data-brust-prefetch="false"]') || c?.saveData || /2g/.test(c?.effectiveType ?? '') || sameDoc(l[1], location.href)) return
128
+ const at = seen.get(noHash(l[1]))
129
+ if (at != null && Date.now() - at < gap()) return
121
130
  get(l[1], false, { priority: 'low' } as RequestInit).catch(() => {})
122
131
  }
123
132
 
@@ -249,7 +258,7 @@ export function boot(load: Load = (u) => import(/* @vite-ignore */ u)): () => vo
249
258
  location[o?.replace ? 'replace' : 'assign'](url)
250
259
  return Promise.resolve()
251
260
  }
252
- g[KEY] = { navigate, clearCache: () => cache.clear() }
261
+ g[KEY] = { navigate, clearCache: () => (cache.clear(), seen.clear()) }
253
262
 
254
263
  on(document, 'click', (e: MouseEvent) => {
255
264
  if (e.defaultPrevented || e.button || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return