@ultimat3/admin 6.0.0 → 8.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/CLAUDE.md CHANGED
@@ -34,6 +34,7 @@ Two products, one package, **two entry points**: `@ultimat3/admin/dev` (`src/dev
34
34
  - **One cursor codec.** `pagination.ts` is the only file calling core's `encodeCursor`/`decodeCursor`; it wraps them as `encodeAdminCursor`/`decodeAdminCursor`, scoped `admin:<resource>`. An invalid cursor is page one here, not an error page — but the signature is checked first, so a forged one cannot seek.
35
35
  - Labels are i18n keys derived in `resource.ts` (`admin.<entity>.field.<name>`); only `.tsx` calls `t()`. MCP tool descriptions are literal English (protocol payload, not UI copy).
36
36
  - Colours only via `ThemeTokenRef` (`--x-*`). Raw hex does not typecheck.
37
+ - **One owner of `globalThis.React`, and it is `@ultimat3/ui`'s.** `inert-jsx.ts` keeps the walkers (`nodesOf`, `shallowNodesOf`, `renderNodes`, `renderHtml`) and delegates install/restore to `probe`/`unprobe` from `@ultimat3/ui/jsx-probe` — tier 5 → tier 4, downward, no declared edge needed. It kept its own `depth`/`saved` pair until 2026-08-22 and two counters over one property restore in the wrong order: admin installs (saving the real binding), ui installs (saving ADMIN's factory), admin restores, ui restores admin's factory back over the top. `bun test` seats both packages in one process, so the interleave is reachable; `inert-jsx.test.ts` drives it in both orders.
37
38
  - Views are pure functions of props — no `createSignal`, no local state; the route owns it.
38
39
 
39
40
  ## Layout
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/admin",
3
- "version": "6.0.0",
3
+ "version": "8.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": "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"
35
+ "@ultimat3/action": "8.0.0",
36
+ "@ultimat3/ai": "8.0.0",
37
+ "@ultimat3/cache": "8.0.0",
38
+ "@ultimat3/core": "8.0.0",
39
+ "@ultimat3/db": "8.0.0",
40
+ "@ultimat3/entity": "8.0.0",
41
+ "@ultimat3/i18n": "8.0.0",
42
+ "@ultimat3/jobs": "8.0.0",
43
+ "@ultimat3/mcp": "8.0.0",
44
+ "@ultimat3/money": "8.0.0",
45
+ "@ultimat3/policy": "8.0.0",
46
+ "@ultimat3/query": "8.0.0",
47
+ "@ultimat3/render": "8.0.0",
48
+ "@ultimat3/schema": "8.0.0",
49
+ "@ultimat3/ui": "8.0.0"
50
50
  }
51
51
  }
package/src/inert-jsx.ts CHANGED
@@ -8,6 +8,10 @@
8
8
  // both and the run's file order stops deciding. Recognising neither is what falls through to
9
9
  // `String(value)` and asserts against `"[object Object]"`.
10
10
 
11
+ // The subpath, never the barrel: this is a test harness and the design system's `index.ts` is its
12
+ // semver'd contract (`packages/ui/CLAUDE.md`). It is imported for `globalThis.React`'s ONE counter.
13
+ import { probe, unprobe } from '@ultimat3/ui/jsx-probe';
14
+
11
15
  /** `@ultimat3/render`'s node brand, read off the GLOBAL symbol registry rather than imported. */
12
16
  const RENDER_NODE: symbol = Symbol.for('ultimate.render.jsx');
13
17
 
@@ -23,7 +27,11 @@ export function isInertNode(value: unknown): value is InertNode {
23
27
  return 'inert' in value || RENDER_NODE in value;
24
28
  }
25
29
 
26
- /** The classic factory these `.tsx` files fall back to under `jsx: 'preserve'`. */
30
+ /**
31
+ * Build a node by hand, the shape the installed factory builds. NOT the installed factory — that is
32
+ * `@ultimat3/ui`'s, so there is one owner of `globalThis.React` (see `installFactory` below). This
33
+ * is what a test uses to construct a tree it did not render.
34
+ */
27
35
  export function h(
28
36
  type: string | InertComponent,
29
37
  props: Record<string, unknown> | null,
@@ -35,37 +43,24 @@ export function h(
35
43
  }
36
44
 
37
45
  /**
38
- * How many installs are live, and what `globalThis.React` was before the first one. A harness that
39
- * DELETED the property on the way out destroys a binding it did not create, and a nested install
40
- * would tear the factory out from under the suite still using it — the counter is what makes the
41
- * last restore the only one that acts.
46
+ * Install the classic-factory global, through `@ultimat3/ui`'s ONE counter over `globalThis.React`.
47
+ *
48
+ * This package kept its own `depth`/`saved` pair until 2026-08-22, and two counters over one
49
+ * property restore in the wrong order: admin installs (saving the real binding), ui installs
50
+ * (saving ADMIN's factory), admin restores (its counter hits 0 → the real binding is back), ui
51
+ * restores (its counter hits 0 → admin's factory goes back over it). `bun test` is one process and
52
+ * `packages/ui` and `packages/admin` are one run, so the interleave is reachable, and the global
53
+ * was left holding a harness the run had already torn down. `admin` is tier 5 and `ui` is tier 4,
54
+ * so importing down is the fix; the two factories build the same `{ inert, type, props }` shape,
55
+ * which is what `isInertNode` recognises.
42
56
  */
43
- let depth = 0;
44
- let saved: PropertyDescriptor | undefined;
45
-
46
57
  export function installFactory(): void {
47
- if (depth === 0) {
48
- // The descriptor, not the value: the property may be a getter or non-writable, and `assign`
49
- // onto either throws or silently loses.
50
- saved = Object.getOwnPropertyDescriptor(globalThis, 'React');
51
- Object.defineProperty(globalThis, 'React', {
52
- value: { createElement: h },
53
- configurable: true,
54
- writable: true,
55
- enumerable: true,
56
- });
57
- }
58
- depth += 1;
58
+ probe();
59
59
  }
60
60
 
61
61
  /** Undo the matching `installFactory()`. Unbalanced calls are inert. */
62
62
  export function restoreFactory(): void {
63
- if (depth === 0) return;
64
- depth -= 1;
65
- if (depth > 0) return;
66
- if (saved === undefined) Reflect.deleteProperty(globalThis, 'React');
67
- else Object.defineProperty(globalThis, 'React', saved);
68
- saved = undefined;
63
+ unprobe();
69
64
  }
70
65
 
71
66
  /**
package/src/routes.ts CHANGED
@@ -50,9 +50,11 @@ export function adminRouteConfig(route: AdminRoute): AdminRouteConfig {
50
50
  // shell the browser was supposed to fill — until `spa` was deleted: nothing ever built the
51
51
  // client bundle it preloaded and `renderSpa` never read the route's component, so every
52
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.
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.
56
58
  render: 'ssr',
57
59
  offline: 'network-only',
58
60
  hydrate: 'never',