@ultimat3/admin 5.0.1 → 7.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 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); // generated views `spa`, custom pages `ssr`, all gated
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": "5.0.1",
3
+ "version": "7.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": "5.0.1",
36
- "@ultimat3/ai": "5.0.1",
37
- "@ultimat3/cache": "5.0.1",
38
- "@ultimat3/core": "5.0.1",
39
- "@ultimat3/db": "5.0.1",
40
- "@ultimat3/entity": "5.0.1",
41
- "@ultimat3/i18n": "5.0.1",
42
- "@ultimat3/jobs": "5.0.1",
43
- "@ultimat3/mcp": "5.0.1",
44
- "@ultimat3/money": "5.0.1",
45
- "@ultimat3/policy": "5.0.1",
46
- "@ultimat3/query": "5.0.1",
47
- "@ultimat3/render": "5.0.1",
48
- "@ultimat3/schema": "5.0.1",
49
- "@ultimat3/ui": "5.0.1"
35
+ "@ultimat3/action": "7.0.0",
36
+ "@ultimat3/ai": "7.0.0",
37
+ "@ultimat3/cache": "7.0.0",
38
+ "@ultimat3/core": "7.0.0",
39
+ "@ultimat3/db": "7.0.0",
40
+ "@ultimat3/entity": "7.0.0",
41
+ "@ultimat3/i18n": "7.0.0",
42
+ "@ultimat3/jobs": "7.0.0",
43
+ "@ultimat3/mcp": "7.0.0",
44
+ "@ultimat3/money": "7.0.0",
45
+ "@ultimat3/policy": "7.0.0",
46
+ "@ultimat3/query": "7.0.0",
47
+ "@ultimat3/render": "7.0.0",
48
+ "@ultimat3/schema": "7.0.0",
49
+ "@ultimat3/ui": "7.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` — `ssr`, `isr`, `static`, `stream`, `spa`. */
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. A generated view is `spa`: it is behind auth, so there is
3
- // nothing to prerender and nothing a CDN may hold — and `network-only` keeps a stale org's rows
4
- // out of a service worker cache. A custom page is `ssr`, because its guard runs on the server.
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: 'spa'` and `'ssr'` would both ship a public shell.
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,18 @@ 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
- // A custom page renders server data behind the guard; a generated view is a shell that
51
- // fetches through the admin's own gated calls. One mode each, never an author's choice.
52
- render: custom ? 'ssr' : 'spa',
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, once per request, and `hydrate: 'never'` means the screen ships no JS at all:
54
+ // an admin view is a pure function of its props (no `createSignal`, no local state), so
55
+ // there is nothing to hydrate. `never` is a REFUSAL and not just a default — an `island()`
56
+ // rendered on this route throws `X_ISLAND_NOT_HYDRATED` (`@ultimat3/render`'s
57
+ // `island-collector.ts`), and no admin module declares one.
58
+ render: 'ssr',
53
59
  offline: 'network-only',
54
- hydrate: custom ? 'never' : 'idle',
60
+ hydrate: 'never',
55
61
  policy,
56
62
  meta: () => ({ title: t(route.titleKey) }),
57
63
  }),