@ultimat3/render 26.1.0 → 26.1.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.
package/CLAUDE.md CHANGED
@@ -10,7 +10,12 @@ loaders that make an app's `.tsx` and `.scss` runnable**.
10
10
  `node:url`, which a browser build cannot link; no `sideEffects` value repairs that). Never re-export
11
11
  a name from both barrels: `index.test.ts` asserts the empty name intersection and that `index.ts`'s
12
12
  runtime import graph reaches none of those seven modules; `scripts/browser-barrel.test.ts` holds
13
- the end property.
13
+ the end property. **`"./client"` (`client.ts`) is THE browser entry** for what an island calls
14
+ (`navigate`, `refresh`, `openModal`, `closeModal`, the modal refusal, the three event names): its
15
+ graph never reaches `errors.ts` (the barrel's `sideEffects` keeps that table in every chunk), held
16
+ by `client-bundle.test.ts`. A name there stays on `.` too (additive); a refusal it can construct
17
+ lives in its own module over `@ultimat3/core/page`'s `UltimateError` (`navigation-errors.ts`) and
18
+ `errors.ts` re-exports it — one class, never two.
14
19
 
15
20
  `island()` is a **factory over the route's own `hydrate`**, not a ninth primitive and not a second
16
21
  render mode. It adds no key to `defineRoute`.
package/README.md CHANGED
@@ -143,8 +143,9 @@ reaching a page — a link, a redirect after a POST, a pasted hash.
143
143
 
144
144
  From code — an island, an app script — `navigate(url, { replace? })`, `refresh()`,
145
145
  `openModal(path)` and `closeModal()` go through the router when the page has one and fall back to
146
- `location.assign`/`replace`/`reload` when it does not; they import the router's type only.
147
- [Navigating from code](../../wiki/Client-Navigation.md#navigating-from-code).
146
+ `location.assign`/`replace`/`reload` when it does not; they import the router's type only. An
147
+ island imports them from **`@ultimat3/render/client`**, never the barrel — see
148
+ [Two entry points](#two-entry-points). [Navigating from code](../../wiki/Client-Navigation.md#navigating-from-code).
148
149
 
149
150
  ## Mode invariants, checked at registration
150
151
 
@@ -483,6 +484,19 @@ does.
483
484
  side effect. Anything that loads an app's source — `x dev`, `x build`, `server.ts`, a test that
484
485
  `await import()`s a `page.tsx` — reaches it before the module it loads.
485
486
 
487
+ `@ultimat3/render/client` is the **browser** entry — what an island or a page script calls:
488
+ `navigate`, `refresh`, `openModal`, `closeModal`, `NavigateToOptions`,
489
+ `NavigationModalPathInvalidError`, `NAVIGATE_EVENT`, `NAVIGATED_EVENT`, `NAVIGATION_ERROR_EVENT`.
490
+ The barrel bundles for the browser but its `sideEffects` keeps `errors.ts` — render's code table,
491
+ and core's and schema's titles tables behind it — in every chunk that reaches it; this entry's
492
+ graph is the navigation helpers plus `@ultimat3/core/page` (`client-bundle.test.ts`). `As of
493
+ 2026-10-08`, an island whose body is `refresh()`: 9,323 B minified from the barrel, 216 B from
494
+ `/client`. The barrel keeps the same names, for compatibility.
495
+
496
+ ```ts
497
+ import { navigate, refresh } from '@ultimat3/render/client';
498
+ ```
499
+
486
500
  ## Error classes
487
501
 
488
502
  Every error class `src/index.ts` exports, for `instanceof` inside one process. Across a wire or
@@ -495,7 +509,7 @@ a job boundary the class is gone and the `code` is what survives — match on th
495
509
  | `IslandInvalidError` | `X_ISLAND_INVALID` | `src/errors.ts` |
496
510
  | `IslandNotHydratedError` | `X_ISLAND_NOT_HYDRATED` | `src/errors.ts` |
497
511
  | `IslandPropsInvalidError` | `X_ISLAND_PROPS_INVALID` | `src/errors.ts` |
498
- | `NavigationModalPathInvalidError` | `X_NAVIGATION_MODAL_PATH_INVALID` | `src/errors.ts` |
512
+ | `NavigationModalPathInvalidError` | `X_NAVIGATION_MODAL_PATH_INVALID` | `src/navigation-errors.ts` (re-exported by `src/errors.ts`; also on `/client`) |
499
513
  | `PrerenderFailedError` | `X_PRERENDER_FAILED` | `src/errors.ts` |
500
514
  | `RouteDuplicateError` | `X_ROUTE_DUPLICATE` | `src/errors.ts` |
501
515
  | `RouteFileInvalidError` | `X_ROUTE_FILE_INVALID` | `src/errors.ts` |
@@ -509,7 +523,7 @@ a job boundary the class is gone and the `code` is what survives — match on th
509
523
 
510
524
  ## Public API
511
525
 
512
- `†` marks a name on `@ultimat3/render/server`.
526
+ `†` marks a name on `@ultimat3/render/server`; `‡` a name also on `@ultimat3/render/client`.
513
527
 
514
528
  | Export | Owns |
515
529
  |---|---|
@@ -533,8 +547,8 @@ a job boundary the class is gone and the `code` is what survives — match on th
533
547
  | `ISLAND_HOLD_ATTRIBUTE`, `ISLAND_HOLD_MS`, `ISLAND_HOLD_REVEAL` | a held island's marker, and the cap after which it shows its server markup regardless |
534
548
  | `parseByteBudget`, `defaultIslandBudget` | the `'40kb'` budget grammar, and the ceiling a declared island earns |
535
549
  | `mergeHead`, `renderHead`, `themeScript` | `<head>` merge + the one inlined script; it stamps `data-theme` and, beside it, the fallback itself as `data-theme-default` for `@ultimat3/ui`'s `clearTheme`/`watchOsTheme` |
536
- | `clientNavigationTags`, `linkVerdict`, `formVerdict`, `responseVerdict`, `reusable`, `mayPrefetch`, `NAVIGATION_*`, `NAVIGATE_EVENT`, `NAVIGATED_EVENT` | the client router's document tags and its pure rules; the router itself is `@ultimat3/render/navigation`, built and served by the CLI |
537
- | `navigate`, `refresh`, `openModal`, `closeModal`, `NavigateToOptions` | navigating from code: the router when the page has one, the browser's own load when not |
550
+ | `clientNavigationTags`, `linkVerdict`, `formVerdict`, `responseVerdict`, `reusable`, `mayPrefetch`, `NAVIGATION_*` (`NAVIGATION_ERROR_EVENT`‡), `NAVIGATE_EVENT`‡, `NAVIGATED_EVENT`‡ | the client router's document tags and its pure rules; the router itself is `@ultimat3/render/navigation`, built and served by the CLI |
551
+ | `navigate`‡, `refresh`‡, `openModal`‡, `closeModal`‡, `NavigateToOptions`‡, `NavigationModalPathInvalidError`‡ | navigating from code: the router when the page has one, the browser's own load when not. Import from `/client` in an island |
538
552
  | `modalAddress`, `modalLocation`, `addressOf`, `presentation`, `modalHistory`, `leaveModal`, `NAVIGATION_PRESENTATION_META`, `NAVIGATION_MODAL_ATTRIBUTE` | route-presented modals (`navigation: 'modal'`): the hash grammar, when an answer is a modal, and what leaving one does to history |
539
553
  | `clientPathStyleTags`, `CLIENT_PATH_STYLE_META` | `<meta name="ultimate-path-style">` — the action path style the server serves, for the browser's typed client. No tag for `'resource'`, the default |
540
554
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/render",
3
- "version": "26.1.0",
3
+ "version": "26.1.1",
4
4
  "description": "The route primitive and the five render modes: static, isr, ssr, stream, spa.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,6 +20,7 @@
20
20
  },
21
21
  "exports": {
22
22
  ".": "./src/index.ts",
23
+ "./client": "./src/client.ts",
23
24
  "./server": "./src/server.ts",
24
25
  "./navigation": "./src/navigation-entry.ts"
25
26
  },
@@ -39,11 +40,11 @@
39
40
  "test": "bun test"
40
41
  },
41
42
  "dependencies": {
42
- "@ultimat3/cache": "26.1.0",
43
- "@ultimat3/core": "26.1.0",
44
- "@ultimat3/http": "26.1.0",
45
- "@ultimat3/i18n": "26.1.0",
46
- "@ultimat3/seo": "26.1.0",
43
+ "@ultimat3/cache": "26.1.1",
44
+ "@ultimat3/core": "26.1.1",
45
+ "@ultimat3/http": "26.1.1",
46
+ "@ultimat3/i18n": "26.1.1",
47
+ "@ultimat3/seo": "26.1.1",
47
48
  "sass": "1.105.1"
48
49
  }
49
50
  }
package/src/client.ts ADDED
@@ -0,0 +1,14 @@
1
+ // `@ultimat3/render/client` — THE browser entry of this package: what an island or a page script
2
+ // may call, and nothing that drags the rest along. The `.` barrel bare-retains `errors.ts` (render's
3
+ // whole code table, registered at import, plus core's titles tables); this entry's graph is
4
+ // `navigation-api.ts`, `navigation-errors.ts`, the pure rules and `@ultimat3/core/page`, held there
5
+ // by `client-bundle.test.ts`.
6
+ //
7
+ // import { navigate, openModal, refresh } from '@ultimat3/render/client';
8
+ //
9
+ // The same names stay exported from `.` for compatibility; an island imports them from here.
10
+
11
+ export type { NavigateToOptions } from './navigation-api';
12
+ export { closeModal, navigate, openModal, refresh } from './navigation-api';
13
+ export { NavigationModalPathInvalidError } from './navigation-errors';
14
+ export { NAVIGATE_EVENT, NAVIGATED_EVENT, NAVIGATION_ERROR_EVENT } from './navigation-rules';
package/src/errors.ts CHANGED
@@ -222,17 +222,10 @@ export class RouteNavigationInvalidError extends UltimateError {
222
222
  }
223
223
  }
224
224
 
225
- /** `openModal(path)` with a path no hash can address on this origin. Thrown in the browser. */
226
- export class NavigationModalPathInvalidError extends UltimateError {
227
- static readonly code = 'X_NAVIGATION_MODAL_PATH_INVALID' as const;
228
- constructor(path: string) {
229
- super({
230
- code: NavigationModalPathInvalidError.code,
231
- cause: `openModal(${JSON.stringify(path)}): a modal is addressed by '#<path>', and this is not an absolute path on this origin`,
232
- fix: "openModal('/runs/new') — the modal route's own path, as its link carries it; never a full URL or a relative one",
233
- });
234
- }
235
- }
225
+ // `openModal(path)` with a path no hash can address on this origin. Re-exported, never re-declared:
226
+ // the class lives in `navigation-errors.ts` so `@ultimat3/render/client` constructs it without this
227
+ // module's table. One class, so `instanceof` holds from either entry.
228
+ export { NavigationModalPathInvalidError } from './navigation-errors';
236
229
 
237
230
  export class RouteLoadInvalidError extends UltimateError {
238
231
  static readonly code = 'X_ROUTE_LOAD_INVALID' as const;
package/src/index.ts CHANGED
@@ -107,7 +107,11 @@ export {
107
107
  defaultIslandBudget,
108
108
  MODE_SPECS,
109
109
  } from './modes';
110
- /** Navigating from code — through the router when the page has one, the browser's load when not. */
110
+ /**
111
+ * Navigating from code — through the router when the page has one, the browser's load when not.
112
+ * Kept here for compatibility; an island imports them from `@ultimat3/render/client` (`client.ts`),
113
+ * whose graph does not retain this barrel's `errors.ts` and the code tables behind it.
114
+ */
111
115
  export type { NavigateToOptions } from './navigation-api';
112
116
  export { closeModal, navigate, openModal, refresh } from './navigation-api';
113
117
  /** Client-side navigation over server-rendered documents — `navigation: { client }` surfaces. */
@@ -7,8 +7,8 @@
7
7
  * only: an island that navigates never ships the router.
8
8
  */
9
9
 
10
- import { NavigationModalPathInvalidError } from './errors';
11
10
  import type { NavigationRouter } from './navigation';
11
+ import { NavigationModalPathInvalidError } from './navigation-errors';
12
12
  import { modalAddress } from './navigation-modal-rules';
13
13
 
14
14
  export interface NavigateToOptions {
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The one refusal a BROWSER can reach in this package — `openModal`'s — apart from `errors.ts` for
3
+ * bytes: that module registers render's whole code table at import, and an island that calls
4
+ * `openModal` must not carry it. `errors.ts` re-exports this class, so it is ONE class wherever it is
5
+ * imported from and `instanceof` agrees across both entries. Without the table loaded, core titles
6
+ * the code from its name; the code, cause and fix are the same either way. Runs nothing at import.
7
+ */
8
+
9
+ import { UltimateError } from '@ultimat3/core/page';
10
+
11
+ /** `openModal` was handed something no `#<path>` hash can address. Rejected, never thrown. */
12
+ export class NavigationModalPathInvalidError extends UltimateError {
13
+ static readonly code = 'X_NAVIGATION_MODAL_PATH_INVALID' as const;
14
+ constructor(path: string) {
15
+ super({
16
+ code: NavigationModalPathInvalidError.code,
17
+ cause: `openModal(${JSON.stringify(path)}): a modal is addressed by '#<path>', and this is not an absolute path on this origin`,
18
+ fix: "openModal('/runs/new') — the modal route's own path, as its link carries it; never a full URL or a relative one",
19
+ });
20
+ }
21
+ }