lit-ui-router-ssr 0.4.0 → 0.6.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 (83) hide show
  1. package/README.md +125 -41
  2. package/dist/client.d.ts +126 -4
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +149 -25
  5. package/dist/client.js.map +1 -1
  6. package/dist/dev-warn.d.ts +10 -0
  7. package/dist/dev-warn.d.ts.map +1 -1
  8. package/dist/dev-warn.js +1 -0
  9. package/dist/dev-warn.js.map +1 -1
  10. package/dist/development/client.js +162 -30
  11. package/dist/development/client.js.map +1 -1
  12. package/dist/development/dev-warn.js +4 -0
  13. package/dist/development/dev-warn.js.map +1 -1
  14. package/dist/development/index.js +2 -1
  15. package/dist/development/index.js.map +1 -1
  16. package/dist/development/light-dom-brand.js +7 -0
  17. package/dist/development/light-dom-brand.js.map +1 -0
  18. package/dist/development/light-dom.js +55 -0
  19. package/dist/development/light-dom.js.map +1 -0
  20. package/dist/development/light-element-renderer.js +16 -0
  21. package/dist/development/light-element-renderer.js.map +1 -0
  22. package/dist/development/prerender.js +19 -138
  23. package/dist/development/prerender.js.map +1 -1
  24. package/dist/development/served-markers.js +1 -1
  25. package/dist/development/served-view.js +18 -15
  26. package/dist/development/served-view.js.map +1 -1
  27. package/dist/development/signature.js +3 -1
  28. package/dist/development/signature.js.map +1 -1
  29. package/dist/development/ui-view-renderer.js +12 -2
  30. package/dist/development/ui-view-renderer.js.map +1 -1
  31. package/dist/index.d.ts +2 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +2 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/light-dom-brand.d.ts +20 -0
  36. package/dist/light-dom-brand.d.ts.map +1 -0
  37. package/dist/light-dom-brand.js +7 -0
  38. package/dist/light-dom-brand.js.map +1 -0
  39. package/dist/light-dom.d.ts +61 -0
  40. package/dist/light-dom.d.ts.map +1 -0
  41. package/dist/light-dom.js +55 -0
  42. package/dist/light-dom.js.map +1 -0
  43. package/dist/light-element-renderer.d.ts +45 -0
  44. package/dist/light-element-renderer.d.ts.map +1 -0
  45. package/dist/light-element-renderer.js +16 -0
  46. package/dist/light-element-renderer.js.map +1 -0
  47. package/dist/prerender.d.ts +23 -108
  48. package/dist/prerender.d.ts.map +1 -1
  49. package/dist/prerender.js +19 -121
  50. package/dist/prerender.js.map +1 -1
  51. package/dist/served-markers.d.ts +4 -4
  52. package/dist/served-markers.js +1 -1
  53. package/dist/served-view.d.ts +43 -0
  54. package/dist/served-view.d.ts.map +1 -1
  55. package/dist/served-view.js +16 -11
  56. package/dist/served-view.js.map +1 -1
  57. package/dist/signature.d.ts +10 -0
  58. package/dist/signature.d.ts.map +1 -1
  59. package/dist/signature.js +3 -1
  60. package/dist/signature.js.map +1 -1
  61. package/dist/ui-view-renderer.d.ts +27 -1
  62. package/dist/ui-view-renderer.d.ts.map +1 -1
  63. package/dist/ui-view-renderer.js +12 -2
  64. package/dist/ui-view-renderer.js.map +1 -1
  65. package/package.json +2 -2
  66. package/src/client.ts +444 -58
  67. package/src/dev-warn.ts +19 -1
  68. package/src/index.ts +3 -1
  69. package/src/light-dom-brand.ts +34 -0
  70. package/src/light-dom.ts +139 -0
  71. package/src/light-element-renderer.ts +66 -0
  72. package/src/prerender.ts +78 -382
  73. package/src/served-markers.ts +4 -4
  74. package/src/served-view.ts +80 -31
  75. package/src/signature.ts +26 -0
  76. package/src/ui-view-renderer.ts +45 -4
  77. package/dist/development/settle.js +0 -48
  78. package/dist/development/settle.js.map +0 -1
  79. package/dist/settle.d.ts +0 -49
  80. package/dist/settle.d.ts.map +0 -1
  81. package/dist/settle.js +0 -48
  82. package/dist/settle.js.map +0 -1
  83. package/src/settle.ts +0 -154
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # lit-ui-router-ssr
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/lit-ui-router-ssr.svg)](https://npmx.dev/package/lit-ui-router-ssr)
4
- [![GitHub Release](https://img.shields.io/github/v/release/simshanith/lit-ui-router?filter=lit-ui-router-ssr@*)](https://github.com/simshanith/lit-ui-router/releases/?q=lit-ui-router-ssr)
4
+ [![GitHub Release](https://img.shields.io/github/v/release/simshanith/lit-ui-router?filter=lit-ui-router-ssr@*)](https://lit-ui-router.dev/gh/releases/lit-ui-router-ssr/latest)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
6
  [![Website](https://img.shields.io/website?url=https%3A%2F%2Flit-ui-router.dev)](https://lit-ui-router.dev/packages/ssr)
7
7
  [![codecov](https://codecov.io/gh/simshanith/lit-ui-router/graph/badge.svg?component=lit-ui-router-ssr)](https://app.codecov.io/gh/simshanith/lit-ui-router?components%5B0%5D=lit-ui-router-ssr)
@@ -26,10 +26,12 @@ imports the pre-1.0 renderer or re-derives the incantation.
26
26
  `<script type="application/json" data-lit-ui-router-ssr>`, naming this package's version, the
27
27
  state the router stood on, and that state's url parameter values. A page `renderShell` returns
28
28
  as a string is written as-is, without one.
29
- - **The emit loop.** Verdict to file name, redirect to rules line, tally, warnings for paths that
30
- matched nothing.
31
- - **The host rules file.** `_redirects` by default, every generated line paired with and without a
32
- trailing slash. No SPA catch-all is ever written: one turns every 404 into a 200.
29
+ - **The lit render inside the emit loop.** The loop itself — verdict to file name, redirect to
30
+ rules line, the `_redirects` file, delegating states skipped, tally, warnings for paths that
31
+ matched nothing — is
32
+ `prerender` from `ui-router-server/prerender`, which takes any render. This package's `prerender`
33
+ supplies the lit one and takes the same options, plus `router`, `renderShell`, `document`,
34
+ `root` and `elementRenderers`. No SPA catch-all is ever written: one turns every 404 into a 200.
33
35
  - **`<ui-view>` on both sides.** `UiViewRenderer` fills the element's light DOM on the server;
34
36
  `lit-ui-router-ssr/client` adopts what it drew.
35
37
 
@@ -66,9 +68,13 @@ const result = await prerender({
66
68
  document: (body, { path }) => fillShell(titles.get(path), body),
67
69
  });
68
70
 
69
- console.log(result.tally); // { shell: 2, redirect: 1, notFound: 0, document: 1 }
71
+ console.log(result.tally); // { shell: 2, redirect: 1, notFound: 0, delegate: 0, document: 1 }
70
72
  ```
71
73
 
74
+ `result.delegated` lists the paths that matched a delegating state. They get no page and no rules
75
+ line, so route them to your server; on Cloudflare, list them in the Worker's
76
+ `assets.run_worker_first` so the asset layer doesn't answer them first.
77
+
72
78
  `result.pages` lists every artefact in enumeration order, `result.rules` every line the host file
73
79
  carries, and `result.warnings` the paths that matched no route and had no projection to fall back
74
80
  on. `dryRun: true` plans all of it and writes nothing.
@@ -100,11 +106,12 @@ first page's slashed spelling does not resolve to the same shell.
100
106
  ## Settling the router on each path
101
107
 
102
108
  A server render reads the router only once its transition has landed, resolves included.
103
- `settle(router, path)` sets the url, syncs the router to it, and resolves with the transition that
104
- landed, so the synchronous render after it reads every resolve. A `redirectTo` chain settles on its
105
- final state, and a path the router already stands on resolves at once.
109
+ `settle(router, path)`, the `ui-router-server/ssr` step this package re-exports, sets the url, syncs
110
+ the router to it, and resolves with the transition that landed, so the synchronous render after it
111
+ reads every resolve. A `redirectTo` chain settles on its final state, and a path the router already
112
+ stands on resolves at once.
106
113
 
107
- A page fails to land in three ways, and each rejects rather than hangs:
114
+ A page fails to land in four ways, and each rejects rather than hangs:
108
115
 
109
116
  - **No rule matches.** A url no state claims, on a router with no `otherwise` rule, rejects with an
110
117
  `Error` naming it. An `otherwise` rule is itself a match and settles on its state.
@@ -112,14 +119,18 @@ A page fails to land in three ways, and each rejects rather than hangs:
112
119
  `Rejection`, the resolve's error in its `detail`. Core's `defaultErrorHandler` still logs it.
113
120
  - **Nothing lands in time.** `{ timeout }` bounds the wait, `10_000` ms by default; `0` waits without
114
121
  a limit.
122
+ - **The url keeps rewriting.** `{ maxRewrites }` bounds a chain of url rules that rewrite the url to
123
+ another url, `10` by default.
115
124
 
116
125
  `settle()` never calls `router.start()`, which runs once per router: it drives `urlService`
117
126
  directly, so a page loop calls it once per path on the same router, started or not.
118
127
 
119
128
  ## The routed view, drawn on the server
120
129
 
121
- `elementRenderers` defaults to `[UiViewRenderer]` — not `@lit-labs/ssr`'s `[LitElementRenderer]`,
122
- which wraps every custom element in a declarative shadow root it never asked for. `UiViewRenderer`
130
+ `elementRenderers` defaults to `[UiViewRenderer, LightElementRenderer]` — not `@lit-labs/ssr`'s
131
+ `[LitElementRenderer]`, which wraps every custom element in a declarative shadow root it never asked
132
+ for. `LightElementRenderer` answers only for an element that opted in (see
133
+ [Light-DOM elements](#light-dom-elements)). `UiViewRenderer`
123
134
  answers for `ui-view`: it registers the view at the address its `name` attribute and enclosing
124
135
  `<ui-view>`s spell, takes the `ViewConfig` the registration syncs back, and writes the routed
125
136
  component into the element's light DOM between the part markers the element's own `render()`
@@ -169,8 +180,8 @@ card empty:
169
180
  ```
170
181
 
171
182
  `@lit-labs/ssr` writes a `.prop=${…}` binding as its part marker and nothing else — no attribute, no
172
- child, no value. Setting the property is an element renderer's job, and `elementRenderers` defaults
173
- to `[UiViewRenderer]`, which answers for `ui-view` alone. The card has no renderer, so nothing on
183
+ child, no value. Setting the property is an element renderer's job, and the default `elementRenderers`
184
+ answer for `ui-view` and for opted-in light-DOM elements alone. The card has no renderer, so nothing on
174
185
  the server sets `post` or runs its `render()`: the card first draws on the client, once hydration
175
186
  sets the property, and the served page shows an empty tag where it stands.
176
187
 
@@ -230,11 +241,16 @@ shadow root:
230
241
 
231
242
  ```typescript
232
243
  import { LitElementRenderer } from '@lit-labs/ssr';
233
- import { prerender, UiViewRenderer } from 'lit-ui-router-ssr';
244
+ import {
245
+ LightElementRenderer,
246
+ prerender,
247
+ UiViewRenderer,
248
+ } from 'lit-ui-router-ssr';
234
249
 
235
250
  await prerender({
236
251
  // …
237
- elementRenderers: [UiViewRenderer, LitElementRenderer],
252
+ // The list replaces the default; LightElementRenderer stays ahead of the shadow-root renderer.
253
+ elementRenderers: [UiViewRenderer, LightElementRenderer, LitElementRenderer],
238
254
  });
239
255
  ```
240
256
 
@@ -267,16 +283,14 @@ registers `<ui-view>`. That entry defines `<ui-router>` from core and `<ui-view>
267
283
  `withServedRender(UiView)`. Every value the app takes from the router — `UIRouterLit`, `srefHref`,
268
284
  `srefActiveClass`, `srefAriaCurrent` — comes from `lit-ui-router/pure`, which registers nothing;
269
285
  the root entry registers the plain `<ui-view>` as a side effect, and imported after this one it
270
- warns that the tag is already defined. Then the router boots and one call adopts the page:
286
+ warns that the tag is already defined. Then one call boots the router and adopts the page:
271
287
 
272
288
  ```typescript
273
289
  import 'lit-ui-router-ssr/register';
274
290
  import { UIRouterLit, srefHref } from 'lit-ui-router/pure';
275
- import { hydrateRoot } from 'lit-ui-router-ssr/client';
291
+ import { bootstrap } from 'lit-ui-router-ssr/client';
276
292
 
277
- router.start();
278
- await booted; // the first successful transition
279
- const release = hydrateRoot(root, page(router));
293
+ await bootstrap(router, root, page(router));
280
294
  ```
281
295
 
282
296
  A `<ui-view>` another class already defined throws, naming both ways out.
@@ -322,29 +336,41 @@ The result still extends core's `UiView`, so an enclosing view adopts it as a pa
322
336
 
323
337
  ## The client half
324
338
 
325
- `lit-ui-router-ssr/client` is the adopt side — no import side effects. The router boots
326
- first, and one call adopts the page:
339
+ `lit-ui-router-ssr/client` is the adopt side — no import side effects. One call boots the router
340
+ and adopts the page, or renders it cold, and resolves once the page is live:
327
341
 
328
342
  ```typescript
329
- import { hydrateRoot, uiViewSlot } from 'lit-ui-router-ssr/client';
330
-
331
- const booted = new Promise<void>((resolve) => {
332
- const off = router.transitionService.onSuccess({}, () => {
333
- off();
334
- resolve();
335
- });
336
- });
337
- router.start();
338
- await booted;
343
+ import { bootstrap } from 'lit-ui-router-ssr/client';
339
344
 
340
- const release = hydrateRoot(root, page(router));
341
- if (!release) render(page(router), root);
345
+ const { outcome } = await bootstrap(router, root, page(router));
342
346
  ```
343
347
 
344
- - **The sequence is the contract.** `router.start()`, await its first successful transition, then
345
- `hydrateRoot()`. The walk commits `.uiRouter` onto `<ui-router>` and each `<ui-view>` re-seeks the
346
- router before its own first render, so every view finds the settled router rather than the
347
- placeholder it registered against. Nothing constrains when `lit-ui-router-ssr/register` is imported.
348
+ - **`bootstrap(router, container, value, options?)` owns the boot.** It reads the container's
349
+ signature, starts the router, waits for the boot transition to land — following redirects to the
350
+ one that succeeds — then runs `hydrateRoot()`. The walk commits `.uiRouter` onto `<ui-router>` and
351
+ each `<ui-view>` re-seeks the router before its own first render, so every view finds the settled
352
+ router rather than the placeholder it registered against. The call waits for every awake
353
+ `<ui-view>`, nested ones included, to finish updating, then releases the adopter. It resolves with
354
+ `outcome` — `adopted` or `cold` — and `signature` (`BootstrapSignature`): `matched` when the boot
355
+ landed on the state and url parameters the signature names, `elsewhere` when the document carried
356
+ a signature and the boot landed somewhere else or landed no transition, and `absent` when it
357
+ carried none. Nothing constrains when `lit-ui-router-ssr/register` is imported.
358
+ - **The cold path is the same call.** A container with nothing to adopt is emptied and `value`
359
+ rendered into it before the router starts. A boot transition that fails, a url that starts none,
360
+ and a root `hydrate()` that throws over a mutated document all empty the container and render
361
+ `value` cold too, and the call resolves with the cause in `error` rather than rejecting.
362
+ - **The boot decides mismatches once.** A boot that lands where the document was drawn adopts every
363
+ view, and a view that still mismatches warns in development: the two halves render that template
364
+ differently. A boot that lands elsewhere — one static document served for a family of urls, or a
365
+ redirect — adopts the views that match and renders the rest cold without a warning each; once the
366
+ page is live, the development build warns once, naming both states and how many views rendered
367
+ cold.
368
+ - **The boot transition takes a seed.** `options.payload` is handed to `seed()` from
369
+ `ui-router-server/ssr/client` before the router starts, so the boot transition adopts the
370
+ resolved values a server render drew in place of running their resolve functions.
371
+ - **`hydrateRoot()` is the step underneath.** An app that owns its own boot calls `router.start()`,
372
+ awaits the first successful transition, then `hydrateRoot(root, page(router))`, and renders
373
+ `page(router)` itself when that returns `false`.
348
374
  - **The signature decides first.** `hydrateRoot()` reads the container's hydration signature before
349
375
  it touches the document, and returns `false` over an emptied container when there is none — a
350
376
  cold client render, a dev server, a page from an earlier `prerender()`, a string `renderShell` —
@@ -365,7 +391,9 @@ if (!release) render(page(router), root);
365
391
  before that update stays asleep, holding its nodes, until it is attached again. The walk pins the
366
392
  adopter to every served view it passes, so that view is adopted on its return even once the root
367
393
  provider is released. A view the walk never reached drops those nodes, renders cold, and warns in
368
- development.
394
+ development. A deferred element no walk reaches — one the render wrote no marker for — wakes
395
+ with the adoption of the view that holds it, after that view's hydrate, or with the root walk when
396
+ no view holds it.
369
397
  - **The prefix is the protocol, and both halves are here.** `UiViewRenderer` writes a plain outer
370
398
  part pair around each view's routed markup and prefixes every marker between them; `hydrate()`
371
399
  reads past a prefixed comment, so the walk hydrating a view's surroundings stops at that pair. The
@@ -389,11 +417,67 @@ if (!release) render(page(router), root);
389
417
  (`uiViewAdoptEventName`), bubbling and composed, with `detail.outcome` one of `adopted` — its
390
418
  served nodes are the live ones — `fell-back` — a mismatch or a lost pair, with `detail.error`
391
419
  carrying the cause — or `none`, nothing to adopt. It fires once per view, parent first, in
392
- production as in development. `hydrateRoot()`'s `onAdopt(view, outcome, error)` option receives
420
+ production as in development. The `onAdopt(view, outcome, error)` option of `bootstrap()` and `hydrateRoot()` receives
393
421
  the same reports for every view its walk reaches, a view the pin adopts after the release included.
394
422
  - **A mutated document throws.** `hydrateRoot()` rethrows what `hydrate()` threw, over a container it
395
423
  first empties. The caller renders into it.
396
424
 
425
+ ### Light-DOM elements
426
+
427
+ A consumer's own `LitElement` that renders into its light DOM opts in to the same sleep-then-adopt
428
+ cycle with `LightDomHydrating(Base)` from `lit-ui-router-ssr/client`. `LightElementRenderer` from
429
+ `lit-ui-router-ssr`, one of `prerender()`'s default renderers, draws it on the server, and
430
+ `lightSlot()` marks the hole at the use site:
431
+
432
+ ```typescript
433
+ import { html, LitElement } from 'lit';
434
+ import { property } from 'lit/decorators.js';
435
+ import { LightDomHydrating, lightSlot } from 'lit-ui-router-ssr/client';
436
+
437
+ export class AppCard extends LightDomHydrating(LitElement) {
438
+ @property() label = '';
439
+
440
+ render() {
441
+ return html`<p>${this.label}</p>`;
442
+ }
443
+ }
444
+
445
+ export const card = (label: string) =>
446
+ html`<app-card .label=${label}>${lightSlot()}</app-card>`;
447
+ ```
448
+
449
+ - **Each class opts in.** The mixin stamps a `Symbol.for` brand on the class it returns, and the
450
+ renderer matches that brand, so a subclass stays opted in, the base class does not, and a second
451
+ copy of this package recognises it. An element that did not opt in is served empty and renders
452
+ cold.
453
+ - **The server writes `render()` into the light DOM.** `LightElementRenderer` extends
454
+ `@lit-labs/ssr`'s `LitElementRenderer`: it builds the element, sets its attributes and properties,
455
+ runs `willUpdate`, and writes the render where a shadow root would go, prefixing its markers as
456
+ `UiViewRenderer` prefixes a view's. Custom elements inside it, `<ui-view>` included, render too.
457
+ An explicit `elementRenderers` replaces the default, so keep it in that list, ahead of any
458
+ `LitElementRenderer`: the first renderer that matches a class wins. A render that awaits is not
459
+ served.
460
+ - **`lightSlot()` is the hole.** It is `uiViewSlot()` under a name that does not read as a view: the
461
+ server reaches the renderer through it, and on the client it wakes the element when the
462
+ enclosing walk reaches it, parent first, and pins the adopter to it.
463
+ - **The element wakes through the adopter.** It sleeps under `defer-hydration`, which `prerender()`
464
+ writes on every custom element, and its first update requests `adoptUiViewContext`. The adopter
465
+ hydrates `render()` against the served nodes in place, then wakes the elements inside it. A view's
466
+ reveal stops at a light-DOM element and the element's stops at a view or another light-DOM
467
+ element, so each interior waits for its own wake. With no adopter, the element drops the served
468
+ nodes and renders cold, warning in development.
469
+ - **It reports through its own event.** Each opted-in element dispatches `light-dom:adopt`
470
+ (`lightDomAdoptEventName`) with the same `detail` as `ui-view:adopt`. `onAdopt`, and the count of
471
+ views `bootstrap()` rendered cold, report views only.
472
+ - **A mismatch falls back.** A hydrate that throws drops the element's served nodes, and it renders
473
+ cold, warning in development; its surroundings keep theirs.
474
+ - **An author child with bindings of its own falls back every time.** A child the use site writes
475
+ beside `lightSlot()` keeps its markers ahead of the element's pair, and the element's hydrate
476
+ meets them first. Static author children are kept, ahead of the render, as they are in a
477
+ `<ui-view>`.
478
+ - **`static styles` do not apply.** A light-DOM element has no shadow root to adopt them into; it
479
+ takes the document's styles.
480
+
397
481
  ### How this compares
398
482
 
399
483
  Two axes separate the hydration models in circulation: where the code that wakes the markup comes
package/dist/client.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import { renderLight } from "@lit-labs/ssr-client/directives/render-light.js";
2
2
  import type { RenderOptions } from "lit";
3
+ import type { UIRouterLit } from "lit-ui-router/pure";
4
+ import type { ResolvePayload } from "ui-router-server/ssr/client";
3
5
  import type { HydrationSignature } from "./signature.js";
4
6
  export { adoptUiViewContext, type AdoptableView, type AdoptUiViewContext, type AdoptUiViewContextKey } from "./adopt-context.js";
5
7
  export { isServedViewClass, type ServedUiView, type ServedUiViewConstructor, servedViewBrand, withServedRender } from "./served-view.js";
8
+ export { LightDomHydrating, type LightDomHydratingConstructor, type LightDomHydratingElement, type LitElementConstructor } from "./light-dom.js";
6
9
  export type { HydrationSignature } from "./signature.js";
7
10
  /**
8
11
  * What a served `<ui-view>`'s wake came to.
@@ -16,7 +19,7 @@ export type { HydrationSignature } from "./signature.js";
16
19
  export type AdoptOutcome = "adopted" | "fell-back" | "none";
17
20
  /**
18
21
  * The name of the event a served `<ui-view>` dispatches once its wake's
19
- * outcome is known, in the `ui-view:` house style of the served markers.
22
+ * outcome is known.
20
23
  */
21
24
  export declare const uiViewAdoptEventName: "ui-view:adopt";
22
25
  /**
@@ -34,6 +37,14 @@ export interface UiViewAdoptDetail {
34
37
  */
35
38
  export type UiViewAdoptEvent = CustomEvent<UiViewAdoptDetail>;
36
39
  /**
40
+ * The event a light-DOM hydrating element dispatches from itself at its wake,
41
+ * once its outcome is known. It carries the same detail as {@link
42
+ * uiViewAdoptEventName}, and it does not reach `onAdopt`, which reports views.
43
+ */
44
+ export declare const lightDomAdoptEventName: "light-dom:adopt";
45
+ /** A light-DOM hydrating element's hydration outcome. */
46
+ export type LightDomAdoptEvent = CustomEvent<UiViewAdoptDetail>;
47
+ /**
37
48
  * Receives each served view's outcome, as {@link HydrateRootOptions.onAdopt}.
38
49
  */
39
50
  export type AdoptReporter = (view: Element, outcome: AdoptOutcome, error?: unknown) => void;
@@ -53,6 +64,8 @@ declare global {
53
64
  interface HTMLElementEventMap {
54
65
  /** A served `<ui-view>`'s hydration outcome; see {@link UiViewAdoptEvent}. */
55
66
  "ui-view:adopt": UiViewAdoptEvent;
67
+ /** A light-DOM hydrating element's hydration outcome; see {@link LightDomAdoptEvent}. */
68
+ "light-dom:adopt": LightDomAdoptEvent;
56
69
  }
57
70
  }
58
71
  /**
@@ -77,6 +90,21 @@ declare global {
77
90
  */
78
91
  export declare const uiViewSlot: typeof renderLight;
79
92
  /**
93
+ * The hole a `LightDomHydrating` element fills, written at the use site: the
94
+ * {@link uiViewSlot} directive under a name that does not read as a view.
95
+ *
96
+ * On the server it reaches `LightElementRenderer`'s `renderLight()`, so the
97
+ * element's own render goes where the template puts it. On the client it wakes
98
+ * the element when the enclosing walk reaches it, parent first, and pins the
99
+ * adopter to it.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * html`<app-card .title=${title}>${lightSlot()}</app-card>`;
104
+ * ```
105
+ */
106
+ export declare const lightSlot: typeof renderLight;
107
+ /**
80
108
  * Reads the hydration signature `prerender()` wrote ahead of the render a
81
109
  * container holds: the version of this package that drew the document, and
82
110
  * the state and parameter values it was drawn for.
@@ -97,7 +125,7 @@ export declare const uiViewSlot: typeof renderLight;
97
125
  *
98
126
  * await booted;
99
127
  * const { state } = readHydrationSignature(root) ?? {};
100
- * const drawnForBoot = state === router.globals.current.name;
128
+ * const bootedWhereDrawn = state === router.globals.current.name;
101
129
  * const release = hydrateRoot(root, page(router));
102
130
  * ```
103
131
  *
@@ -132,7 +160,9 @@ export declare function readHydrationSignature(container: ParentNode): Hydration
132
160
  * outside `container`, or one whose attribute the app cleared itself after the
133
161
  * release — is answered by nobody: core drops its held nodes and warns in
134
162
  * development. An element the render deferred and wrote no marker for is woken
135
- * once the walk has finished, since nothing in the walk reaches it.
163
+ * once the walk has finished, since nothing in the walk reaches it — except
164
+ * one inside a `<ui-view>`, which wakes once that view has hydrated its own
165
+ * render, so a routed element never wakes ahead of the view that routes it.
136
166
  *
137
167
  * The provider answers synchronously and stops immediate propagation, so an
138
168
  * outer provider never answers the same request twice. It outlives this call,
@@ -150,7 +180,8 @@ export declare function readHydrationSignature(container: ParentNode): Hydration
150
180
  * A `hydrate()` that throws is rethrown, over a container emptied the same
151
181
  * way. The caller renders into it.
152
182
  *
153
- * The boot is the router first: `router.start()`, await its first successful
183
+ * {@link bootstrap} runs the whole boot around this call. Called directly, the
184
+ * boot is the router first: `router.start()`, await its first successful
154
185
  * transition, then this call. The walk commits `.uiRouter` onto `<ui-router>`
155
186
  * and each woken `<ui-view>` re-seeks the router before its own first render,
156
187
  * so the views find the settled router rather than the placeholder they
@@ -172,4 +203,95 @@ export declare function readHydrationSignature(container: ParentNode): Hydration
172
203
  * @returns the function that releases the provider, or `false`, over an emptied container, when there is nothing to adopt — no signature, as on a cold client render or a dev server, one from another release line, or one no render marker follows
173
204
  */
174
205
  export declare function hydrateRoot(container: HTMLElement, value: unknown, options?: HydrateRootOptions): false | (() => void);
206
+ /** What {@link bootstrap} came to, once the page is live. */
207
+ export type BootstrapOutcome = "adopted" | "cold";
208
+ /**
209
+ * How a boot compares with the {@link readHydrationSignature | hydration
210
+ * signature} the document carried.
211
+ *
212
+ * - `matched`: the boot transition landed on the state and url parameters the
213
+ * signature names.
214
+ * - `elsewhere`: the document carried a signature, and the boot landed on
215
+ * another state or other parameters — a redirect, or a static host serving
216
+ * one document for a family of urls. A signed document whose boot landed no
217
+ * transition reports this too, beside `outcome: 'cold'` and its `error`.
218
+ * - `absent`: the document carried no signature.
219
+ *
220
+ * A signature from another release line, or one no render marker follows, is
221
+ * still compared, though the container renders cold.
222
+ */
223
+ export type BootstrapSignature = "matched" | "elsewhere" | "absent";
224
+ /** What {@link bootstrap} resolves with. */
225
+ export interface BootstrapResult {
226
+ /**
227
+ * `adopted`: the served document was hydrated, and each served view reported
228
+ * its own {@link AdoptOutcome}. `cold`: the container was emptied and the
229
+ * template rendered into it.
230
+ */
231
+ readonly outcome: BootstrapOutcome;
232
+ /** How the boot compares with the document's hydration signature; see {@link BootstrapSignature}. */
233
+ readonly signature: BootstrapSignature;
234
+ /**
235
+ * The boot transition's `Rejection`, or what the root `hydrate()` threw;
236
+ * present only on a cold boot that one of them caused.
237
+ */
238
+ readonly error?: unknown;
239
+ }
240
+ /** {@link bootstrap}'s options: {@link HydrateRootOptions}, plus the boot transition's seed. */
241
+ export interface BootstrapOptions extends HydrateRootOptions {
242
+ /**
243
+ * Resolved values the document was drawn with, handed to `seed` from
244
+ * `ui-router-server/ssr/client` before the router starts, so the boot
245
+ * transition adopts them in place of running their resolve functions.
246
+ */
247
+ readonly payload?: ResolvePayload;
248
+ }
249
+ /**
250
+ * Boots `router` into the page `container` holds, and resolves once that page
251
+ * is live.
252
+ *
253
+ * It owns the whole client boot. `options.payload`, when given, seeds the boot
254
+ * transition first. The container's {@link readHydrationSignature | signature}
255
+ * is read before anything else touches the document; a container {@link
256
+ * hydrateRoot} would not adopt — no signature, another release line, stripped
257
+ * markers — is emptied and `value` rendered into it at once, and the router
258
+ * then starts. Otherwise the router starts, the call waits for the boot
259
+ * transition to land, following redirects to the one that succeeds, and then
260
+ * hydrates the container with `value`.
261
+ *
262
+ * The boot decides once what the page does:
263
+ *
264
+ * - The boot lands where the signature says the document was drawn: every
265
+ * served view adopts, and a view that still mismatches warns in development,
266
+ * since that is a template the two halves render differently.
267
+ * - The boot lands elsewhere — a static host serving one document for a
268
+ * family of urls, or a redirect: the views that match adopt, and the views
269
+ * that differ render cold without a warning of their own. Once the page is
270
+ * live, one development warning names both states and how many views
271
+ * rendered cold, when any did.
272
+ * - The boot fails, or the url starts no transition: the container is emptied
273
+ * and `value` rendered cold. The root `hydrate()` throwing, as over a
274
+ * mutated document, does the same. The call resolves rather than rejects.
275
+ *
276
+ * Every served view still reports its own {@link AdoptOutcome}, as a {@link
277
+ * UiViewAdoptEvent} and to `options.onAdopt`. The call waits for each awake
278
+ * `<ui-view>` to finish updating, nested views included, then releases the
279
+ * adopter `hydrateRoot()` provided; a view the app detached keeps its pin.
280
+ *
281
+ * @example
282
+ * ```ts
283
+ * import { bootstrap } from 'lit-ui-router-ssr/client';
284
+ *
285
+ * const { outcome } = await bootstrap(router, root, page(router));
286
+ * ```
287
+ *
288
+ * @param router - the client router, its states registered and not yet started
289
+ * @param container - the element the server's markup was written into, or an empty one
290
+ * @param value - the same template the server rendered, with every `<ui-view>` hole empty
291
+ * @param options - lit render options, `onAdopt`, and the boot transition's `payload`
292
+ * @returns what the boot came to, once every awake view has updated
293
+ * @throws what `router.start()` throws, as on a router already started
294
+ * @throws the `TypeError` `seed` throws on a payload with no `resolves`, before the router starts
295
+ */
296
+ export declare function bootstrap(router: UIRouterLit, container: HTMLElement, value: unknown, options?: BootstrapOptions): Promise<BootstrapResult>;
175
297
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","mappings":"AAOA,SAAS,mBAAmB;AAI5B,cAAyB,qBAAqB;AAW9C,cAAc,0BAA0B;AAExC,SACE,yBACK,oBACA,yBACA,6BACA;AAEP,SACE,wBACK,mBACA,yBACL,iBACA,wBACK;AAEP,cAAc,0BAA0B;;;;;;;;;;AAcxC,YAAY,eAAe,YAAY,cAAc;;;;;AAMrD,OAAO,cAAM,sBAAuB;;;;AAKpC,iBAAiB,kBAAkB;;UAExB,SAAS;;UAET;AACX;;;;;AAMA,YAAY,mBAAmB,YAAY;;;;AAK3C,YAAY,iBACV,MAAM,SACN,SAAS,cAET;;;;;AAOF,iBAAiB,2BAA2B,cAAc;;;;;;CAMxD,UAAU;AACZ;eAEe;WACH,oBAAoB;;EAE5B,iBAAiB;CACnB;AACF;;;;;;;;;;;;;;;;;;;;;AAgEA,OAAO,cAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmVhC,OAAO,iBAAS,uBACd,WAAW,aACV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4IH,OAAO,iBAAS,YACd,WAAW,aAEX,gBACA,UAAS,qBACR","names":[],"ignoreList":[],"sources":["../src/client.ts"]}
1
+ {"version":3,"file":"client.d.ts","mappings":"AAQA,SAAS,mBAAmB;AAK5B,cAAyB,qBAAqB;AAM9C,cAAc,mBAAmB;AAEjC,cAAc,sBAAsB;AAOpC,cAAc,0BAA0B;AAExC,SACE,yBACK,oBACA,yBACA,6BACA;AAEP,SACE,wBACK,mBACA,yBACL,iBACA,wBACK;AAEP,SACE,wBACK,mCACA,+BACA,6BACA;AAEP,cAAc,0BAA0B;;;;;;;;;;AAcxC,YAAY,eAAe,YAAY,cAAc;;;;;AAMrD,OAAO,cAAM,sBAAuB;;;;AAKpC,iBAAiB,kBAAkB;;UAExB,SAAS;;UAET;AACX;;;;;AAMA,YAAY,mBAAmB,YAAY;;;;;;AAO3C,OAAO,cAAM,wBAAyB;;AAGtC,YAAY,qBAAqB,YAAY;;;;AAK7C,YAAY,iBACV,MAAM,SACN,SAAS,cAET;;;;;AAOF,iBAAiB,2BAA2B,cAAc;;;;;;CAMxD,UAAU;AACZ;eAEe;WACH,oBAAoB;;EAE5B,iBAAiB;;EAEjB,mBAAmB;CACrB;AACF;;;;;;;;;;;;;;;;;;;;;AAgEA,OAAO,cAAM,mBAAmB;;;;;;;;;;;;;;;AAgBhC,OAAO,cAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuY/B,OAAO,iBAAS,uBACd,WAAW,aACV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+IH,OAAO,iBAAS,YACd,WAAW,aAEX,gBACA,UAAS,qBACR;;AAsCH,YAAY,mBAAmB,YAAY;;;;;;;;;;;;;;;;AAiB3C,YAAY,qBAAqB,YAAY,cAAc;;AAG3D,iBAAiB,gBAAgB;;;;;;UAMtB,SAAS;;UAET,WAAW;;;;;UAKX;AACX;;AAGA,iBAAiB,yBAAyB,mBAAmB;;;;;;UAMlD,UAAU;AACrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0JA,OAAO,iBAAe,UACpB,QAAQ,aACR,WAAW,aAEX,gBACA,UAAS,mBACR,QAAQ","names":[],"ignoreList":[],"sources":["../src/client.ts"]}