@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 +6 -1
- package/README.md +20 -6
- package/package.json +7 -6
- package/src/client.ts +14 -0
- package/src/errors.ts +4 -11
- package/src/index.ts +5 -1
- package/src/navigation-api.ts +1 -1
- package/src/navigation-errors.ts +21 -0
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
|
-
|
|
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_
|
|
537
|
-
| `navigate
|
|
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.
|
|
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.
|
|
43
|
-
"@ultimat3/core": "26.1.
|
|
44
|
-
"@ultimat3/http": "26.1.
|
|
45
|
-
"@ultimat3/i18n": "26.1.
|
|
46
|
-
"@ultimat3/seo": "26.1.
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
/**
|
|
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. */
|
package/src/navigation-api.ts
CHANGED
|
@@ -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
|
+
}
|