@abide/abide 0.32.2 → 0.33.1

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 (50) hide show
  1. package/AGENTS.md +3 -3
  2. package/CHANGELOG.md +85 -63
  3. package/bin/abide.ts +6 -2
  4. package/package.json +6 -2
  5. package/src/devEntry.ts +12 -1
  6. package/src/lib/bundle/exitWithParent.ts +7 -7
  7. package/src/lib/server/runtime/buildCacheSnapshot.ts +5 -4
  8. package/src/lib/server/runtime/types/InspectorCacheEntry.ts +1 -1
  9. package/src/lib/shared/cache.ts +43 -29
  10. package/src/lib/shared/types/CacheEntry.ts +12 -12
  11. package/src/lib/shared/types/CacheOptions.ts +17 -13
  12. package/src/lib/ui/README.md +1 -1
  13. package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +4 -1
  14. package/src/lib/ui/compile/componentWrapperTag.ts +1 -1
  15. package/src/lib/ui/compile/generateBuild.ts +265 -121
  16. package/src/lib/ui/compile/generateSSR.ts +78 -37
  17. package/src/lib/ui/compile/parseTemplate.ts +34 -0
  18. package/src/lib/ui/compile/skeletonable.ts +80 -0
  19. package/src/lib/ui/dom/MATHML_NAMESPACE.ts +6 -0
  20. package/src/lib/ui/dom/SVG_NAMESPACE.ts +7 -0
  21. package/src/lib/ui/dom/anchorCursor.ts +24 -0
  22. package/src/lib/ui/dom/appendSnippet.ts +1 -1
  23. package/src/lib/ui/dom/appendTextAt.ts +70 -0
  24. package/src/lib/ui/dom/awaitBlock.ts +27 -7
  25. package/src/lib/ui/dom/cloneStatic.ts +14 -7
  26. package/src/lib/ui/dom/each.ts +44 -25
  27. package/src/lib/ui/dom/eachAsync.ts +6 -2
  28. package/src/lib/ui/dom/effectiveChildNamespace.ts +13 -0
  29. package/src/lib/ui/dom/enterNamespace.ts +20 -0
  30. package/src/lib/ui/dom/fillBefore.ts +20 -3
  31. package/src/lib/ui/dom/foreignWrapperTag.ts +22 -0
  32. package/src/lib/ui/dom/hydrate.ts +1 -1
  33. package/src/lib/ui/dom/inheritedNamespace.ts +19 -0
  34. package/src/lib/ui/dom/mountSlot.ts +32 -0
  35. package/src/lib/ui/dom/openMarker.ts +4 -2
  36. package/src/lib/ui/dom/skeleton.ts +202 -0
  37. package/src/lib/ui/dom/switchBlock.ts +10 -3
  38. package/src/lib/ui/dom/tryBlock.ts +7 -5
  39. package/src/lib/ui/dom/types/SkeletonHoles.ts +8 -0
  40. package/src/lib/ui/dom/when.ts +6 -2
  41. package/src/lib/ui/installHotBridge.ts +8 -2
  42. package/src/lib/ui/runtime/HOLE_ATTRIBUTE.ts +9 -0
  43. package/src/lib/ui/runtime/RENDER.ts +7 -0
  44. package/src/lib/ui/runtime/types/UiProps.ts +3 -4
  45. package/template/src/ui/pages/about/page.abide +4 -6
  46. package/template/src/ui/pages/layout.abide +21 -0
  47. package/template/src/ui/pages/page.abide +5 -8
  48. package/src/lib/ui/compile/partitionSlots.ts +0 -36
  49. package/src/lib/ui/dom/openChild.ts +0 -22
  50. package/template/src/ui/Layout.abide +0 -19
@@ -39,20 +39,20 @@ into `__SSR__`; ones still pending were consumed via `{#await}` (render emitted
39
39
  the pending branch without blocking) and stream a resolve chunk instead.
40
40
 
41
41
  `refreshing` flips true while this entry is reloading data it already held —
42
- either a policy stale-while-revalidate refetch (value still visible) or the
43
- default drop-then-reload (the prior entry was invalidated and dropped, this is
44
- its replacement read). It backs refreshing(), distinguishing a reload from a
42
+ either an `swr` refetch (stale value still visible) or the default
43
+ drop-then-reload (the prior entry was invalidated and dropped, this is its
44
+ replacement read). It backs refreshing(), distinguishing a reload from a
45
45
  first-ever load; cleared when the read settles.
46
46
 
47
- `invalidation` holds an `invalidate` throttle/debounce policy: the refetch
48
- thunk (the call captured with its args) plus the policy and its runtime timer
49
- state, so invalidate() can rate-limit refetches of this key instead of dropping
50
- the entry and refetching on every invalidation. Set at registration when the
51
- creating read declared a policy, or attached by a later read declaring one on
52
- an entry that lacks it (hydrated snapshot entries always start without one) —
53
- first policy wins. An armed `timer` is cleared if the entry is evicted, so a
54
- dead key never refetches. Wrap-time validation guarantees a policy never
55
- coexists with ttl: 0 and never sits on a non-replayable remote method.
47
+ `invalidation` holds the entry's `swr` policy: the refetch thunk (the call
48
+ captured with its args) plus its optional throttle/debounce window and runtime
49
+ timer state, so invalidate() keeps the stale value and revalidates this key
50
+ rate-limited by the window instead of dropping the entry. Set at registration
51
+ when the creating read declared `swr`, or attached by a later read declaring it
52
+ on an entry that lacks it (hydrated snapshot entries always start without one) —
53
+ first wins. An armed `timer` is cleared if the entry is evicted, so a dead key
54
+ never refetches. Wrap-time validation guarantees `swr` never coexists with
55
+ ttl: 0 and never sits on a non-replayable remote method.
56
56
  */
57
57
  export type CacheEntry = {
58
58
  key: string
@@ -18,22 +18,26 @@ for per-request data: the default keeps a per-user response from leaking across
18
18
  requests. Write only `global: true`; there is no `false` form. On the client
19
19
  there is a single tab store, so the flag is a no-op there.
20
20
 
21
- `invalidate` controls how a `cache.invalidate` hit on this key is applied, in ms.
22
- `{ throttle: N }` refetches on the leading edge then at most once per N ms while
23
- invalidations keep arriving; `{ debounce: N }` refetches only after N ms of
24
- quiet. Both coalesce a burst of invalidations (e.g. a socket spraying
25
- `cache.invalidate`) into far fewer calls and keep serving the existing (stale)
26
- value until the refetch resolves stale-while-revalidate. They affect only the
27
- refetch-after-invalidate; the first fetch and arg-change fetches stay immediate.
28
- A policy declares the call safe to re-run unprompted: cache() throws at wrap
29
- time on both set at once, on ttl: 0 (nothing retained, nothing to revalidate),
30
- and on a non-replayable remote method (replaying a write is a state change
31
- disguised as a refresh). Producers are uncheckable declare a policy only on
32
- a producer that is a pure read.
21
+ `swr` is stale-while-revalidate: it changes what a `cache.invalidate` hit does
22
+ to this key. Without it, an invalidate drops the entry and the next read shows
23
+ `pending()`. With it, the entry is kept and refetched in the background — the
24
+ existing (stale) value stays visible and `refreshing()` reports the in-flight
25
+ reload so the reader never blanks. It governs only the refetch-after-invalidate;
26
+ the first fetch and arg-change fetches stay immediate regardless.
27
+
28
+ `swr: true` refetches immediately on every invalidate. An optional window
29
+ coalesces a burst (e.g. a socket spraying `cache.invalidate`) into far fewer
30
+ calls: `swr: { throttle: N }` refetches on the leading edge then at most once
31
+ per N ms while invalidations keep arriving; `swr: { debounce: N }` refetches
32
+ only after N ms of quiet. `swr` declares the call safe to re-run unprompted:
33
+ cache() throws at wrap time on throttle+debounce set at once, on ttl: 0 (nothing
34
+ retained, nothing to revalidate), and on a non-replayable remote method
35
+ (replaying a write is a state change disguised as a refresh). Producers are
36
+ uncheckable — set `swr` only on a producer that is a pure read.
33
37
  */
34
38
  export type CacheOptions = {
35
39
  ttl?: number
36
40
  scope?: string | string[]
37
41
  global?: boolean
38
- invalidate?: { throttle?: number; debounce?: number }
42
+ swr?: boolean | { throttle?: number; debounce?: number }
39
43
  }
@@ -70,7 +70,7 @@ write-path microbench this runs ~20× faster than a deep-proxy signal baseline.
70
70
  ```
71
71
  .abide → analyzeComponent (split script/style/template, desugar signals → doc,
72
72
  lower data access, scope CSS)
73
- → generateBuild (client: openChild/appendText/attr/on/each/when/…)
73
+ → generateBuild (client: skeleton/cloneStatic/appendText/attr/on/each/when/…)
74
74
  → generateSSR (server: HTML-string back-end, await markers)
75
75
  → hoistCells (static paths → cells)
76
76
  → compileModule (ES module: default mount + render() for SSR)
@@ -14,11 +14,13 @@ export const UI_RUNTIME_IMPORTS: { name: string; specifier: string }[] = [
14
14
  { name: 'derived', specifier: 'ui/derived' },
15
15
  { name: 'effect', specifier: 'ui/effect' },
16
16
  { name: 'mount', specifier: 'ui/dom/mount' },
17
- { name: 'openChild', specifier: 'ui/dom/openChild' },
18
17
  { name: 'appendText', specifier: 'ui/dom/appendText' },
18
+ { name: 'appendTextAt', specifier: 'ui/dom/appendTextAt' },
19
19
  { name: 'appendSnippet', specifier: 'ui/dom/appendSnippet' },
20
20
  { name: 'appendStatic', specifier: 'ui/dom/appendStatic' },
21
21
  { name: 'cloneStatic', specifier: 'ui/dom/cloneStatic' },
22
+ { name: 'skeleton', specifier: 'ui/dom/skeleton' },
23
+ { name: 'anchorCursor', specifier: 'ui/dom/anchorCursor' },
22
24
  { name: 'attr', specifier: 'ui/dom/attr' },
23
25
  { name: 'on', specifier: 'ui/dom/on' },
24
26
  { name: 'attach', specifier: 'ui/dom/attach' },
@@ -28,6 +30,7 @@ export const UI_RUNTIME_IMPORTS: { name: string; specifier: string }[] = [
28
30
  { name: 'awaitBlock', specifier: 'ui/dom/awaitBlock' },
29
31
  { name: 'tryBlock', specifier: 'ui/dom/tryBlock' },
30
32
  { name: 'switchBlock', specifier: 'ui/dom/switchBlock' },
33
+ { name: 'mountSlot', specifier: 'ui/dom/mountSlot' },
31
34
  { name: 'mountChild', specifier: 'ui/dom/mountChild' },
32
35
  { name: 'hydrate', specifier: 'ui/dom/hydrate' },
33
36
  { name: 'nextBlockId', specifier: 'ui/runtime/nextBlockId' },
@@ -6,7 +6,7 @@ lowercased — readable in devtools, a real box like any abide wrapper. But a na
6
6
  that lowercases to a real HTML element (`Button`→`button`, `Input`→`input`) yields a
7
7
  wrapper with a content model the parser enforces: void elements self-close, and
8
8
  `<button>`/`<a>`/table/list/select families reject or foster the component's own
9
- markup as the wrapper's siblings — so on hydration `openChild` finds the wrapper
9
+ markup as the wrapper's siblings — so on hydration the skeleton locates the wrapper
10
10
  empty, claims `null`, and `attr` throws on it. Those names map to a hyphenated
11
11
  custom-element tag (a custom element is never void and has no content model) made
12
12
  layout-transparent with `display:contents`, so the component's real root still lays