@ultimat3/admin 5.0.1 → 6.0.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.
- package/README.md +1 -1
- package/package.json +16 -16
- package/src/dev/facts.ts +1 -1
- package/src/routes.ts +13 -9
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ export const admin = defineAdmin({
|
|
|
58
58
|
audit: memoryAuditLog({ sinks: [auditTable] }),
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
export const routes = adminRoutes(admin); //
|
|
61
|
+
export const routes = adminRoutes(admin); // every view `ssr`, gated — an admin screen is per-actor
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
### The views are TSX, and the pieces come apart
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimat3/admin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Two dashboards: the /_x framework dev panels and the generated, AI-first app admin",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -32,20 +32,20 @@
|
|
|
32
32
|
"test": "bun test"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@ultimat3/action": "
|
|
36
|
-
"@ultimat3/ai": "
|
|
37
|
-
"@ultimat3/cache": "
|
|
38
|
-
"@ultimat3/core": "
|
|
39
|
-
"@ultimat3/db": "
|
|
40
|
-
"@ultimat3/entity": "
|
|
41
|
-
"@ultimat3/i18n": "
|
|
42
|
-
"@ultimat3/jobs": "
|
|
43
|
-
"@ultimat3/mcp": "
|
|
44
|
-
"@ultimat3/money": "
|
|
45
|
-
"@ultimat3/policy": "
|
|
46
|
-
"@ultimat3/query": "
|
|
47
|
-
"@ultimat3/render": "
|
|
48
|
-
"@ultimat3/schema": "
|
|
49
|
-
"@ultimat3/ui": "
|
|
35
|
+
"@ultimat3/action": "6.0.0",
|
|
36
|
+
"@ultimat3/ai": "6.0.0",
|
|
37
|
+
"@ultimat3/cache": "6.0.0",
|
|
38
|
+
"@ultimat3/core": "6.0.0",
|
|
39
|
+
"@ultimat3/db": "6.0.0",
|
|
40
|
+
"@ultimat3/entity": "6.0.0",
|
|
41
|
+
"@ultimat3/i18n": "6.0.0",
|
|
42
|
+
"@ultimat3/jobs": "6.0.0",
|
|
43
|
+
"@ultimat3/mcp": "6.0.0",
|
|
44
|
+
"@ultimat3/money": "6.0.0",
|
|
45
|
+
"@ultimat3/policy": "6.0.0",
|
|
46
|
+
"@ultimat3/query": "6.0.0",
|
|
47
|
+
"@ultimat3/render": "6.0.0",
|
|
48
|
+
"@ultimat3/schema": "6.0.0",
|
|
49
|
+
"@ultimat3/ui": "6.0.0"
|
|
50
50
|
}
|
|
51
51
|
}
|
package/src/dev/facts.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export interface RouteFact {
|
|
16
16
|
readonly path: string;
|
|
17
|
-
/** `RouteDescriptor.mode` — `
|
|
17
|
+
/** `RouteDescriptor.mode` — `static`, `isr`, `ssr`, `stream`. */
|
|
18
18
|
readonly render: string;
|
|
19
19
|
readonly offline: string;
|
|
20
20
|
readonly hydrate: string;
|
package/src/routes.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The one bridge from the admin's route table to @ultimat3/render, and the one place a policy
|
|
2
|
-
// is composed onto an admin page.
|
|
3
|
-
// nothing to prerender and nothing a CDN may hold — and `network-only`
|
|
4
|
-
// out of a service worker cache.
|
|
2
|
+
// is composed onto an admin page. Every admin route is `ssr`: it is behind auth, so its guard runs
|
|
3
|
+
// on the server, there is nothing to prerender and nothing a CDN may hold — and `network-only`
|
|
4
|
+
// keeps a stale org's rows out of a service worker cache.
|
|
5
5
|
|
|
6
6
|
import { t } from '@ultimat3/i18n';
|
|
7
7
|
import { defineRoute, type RouteGuard } from '@ultimat3/render';
|
|
@@ -31,12 +31,11 @@ export interface AdminRouteConfig {
|
|
|
31
31
|
* which is the whole mechanism. The coarse gate is `permissions[0]` (always `admin:read`, put
|
|
32
32
|
* there by `permissionsForOperation`/`pagePermissions`); the rest of the pair is decided per
|
|
33
33
|
* request by `decideAll`, in `crud.ts` for a generated view and in `page-guard.tsx` for a page.
|
|
34
|
-
* An empty list is refused here too: `render: '
|
|
34
|
+
* An empty list is refused here too: `render: 'ssr'` with no policy is a public dashboard.
|
|
35
35
|
*/
|
|
36
36
|
export function adminRouteConfig(route: AdminRoute): AdminRouteConfig {
|
|
37
37
|
const permission = route.permissions[0];
|
|
38
38
|
if (permission === undefined) throw new AdminPageUnguardedError({ path: route.path });
|
|
39
|
-
const custom = route.component !== undefined;
|
|
40
39
|
const policy: RouteGuard = { permission };
|
|
41
40
|
|
|
42
41
|
return {
|
|
@@ -47,11 +46,16 @@ export function adminRouteConfig(route: AdminRoute): AdminRouteConfig {
|
|
|
47
46
|
component: route.component === undefined ? null : guardedPage(route, route.component),
|
|
48
47
|
policy,
|
|
49
48
|
config: defineRoute({
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
49
|
+
// One mode for every admin route, never an author's choice. A generated view was `spa` — a
|
|
50
|
+
// shell the browser was supposed to fill — until `spa` was deleted: nothing ever built the
|
|
51
|
+
// client bundle it preloaded and `renderSpa` never read the route's component, so every
|
|
52
|
+
// generated view served an empty `<div id="x-root">`. `ssr` renders the same rows behind the
|
|
53
|
+
// same guard, and the interactive part of a screen arrives as an `island({ src })`, budgeted
|
|
54
|
+
// in real bytes. `hydrate: 'never'` follows from that: an admin view is a pure function of
|
|
55
|
+
// its props (no `createSignal`, no local state), so the page level has nothing to hydrate.
|
|
56
|
+
render: 'ssr',
|
|
53
57
|
offline: 'network-only',
|
|
54
|
-
hydrate:
|
|
58
|
+
hydrate: 'never',
|
|
55
59
|
policy,
|
|
56
60
|
meta: () => ({ title: t(route.titleKey) }),
|
|
57
61
|
}),
|