@ultimat3/admin 19.2.0 → 19.3.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
@@ -77,6 +77,12 @@ Two products, one package, **two entry points**: `@ultimat3/admin/dev` (`src/dev
77
77
  into plain objects, where `__proto__` reads a prototype (so `?? 0` never fires) and WRITES through
78
78
  the setter, dropping the row: the policy matrix reported a permission unreachable while an actor
79
79
  held it. `Map` + `Object.fromEntries`, which DEFINES each key.
80
+ - **A `/_x` panel orders by CODE UNIT, never `localeCompare`.** `dev/panel-routes.ts` sorted its
81
+ rows with it, and with no locale argument `localeCompare` answers from the runtime's ICU default
82
+ locale and collation version — so the same route table reads in a different order on a
83
+ developer's machine than in the container the same build runs in, and a screenshot of one does
84
+ not match the other. `(a < b ? -1 : a > b ? 1 : 0)`, inlined: `@ultimat3/render`'s `byCodeUnit`
85
+ is package-internal, and a comparator is not worth widening a barrel for.
80
86
  - **The locale picker reads `registeredLocales()`, not a bundled list.** It was
81
87
  `['en','es','de','fr','pt','ja']`, one line under a comment forbidding exactly that for IANA
82
88
  zones: an app registering `it` could not pick it, and an app with only `en` was offered five
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/admin",
3
- "version": "19.2.0",
3
+ "version": "19.3.1",
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": "19.2.0",
36
- "@ultimat3/ai": "19.2.0",
37
- "@ultimat3/cache": "19.2.0",
38
- "@ultimat3/core": "19.2.0",
39
- "@ultimat3/db": "19.2.0",
40
- "@ultimat3/entity": "19.2.0",
41
- "@ultimat3/i18n": "19.2.0",
42
- "@ultimat3/jobs": "19.2.0",
43
- "@ultimat3/mcp": "19.2.0",
44
- "@ultimat3/money": "19.2.0",
45
- "@ultimat3/policy": "19.2.0",
46
- "@ultimat3/query": "19.2.0",
47
- "@ultimat3/render": "19.2.0",
48
- "@ultimat3/schema": "19.2.0",
49
- "@ultimat3/ui": "19.2.0"
35
+ "@ultimat3/action": "19.3.1",
36
+ "@ultimat3/ai": "19.3.1",
37
+ "@ultimat3/cache": "19.3.1",
38
+ "@ultimat3/core": "19.3.1",
39
+ "@ultimat3/db": "19.3.1",
40
+ "@ultimat3/entity": "19.3.1",
41
+ "@ultimat3/i18n": "19.3.1",
42
+ "@ultimat3/jobs": "19.3.1",
43
+ "@ultimat3/mcp": "19.3.1",
44
+ "@ultimat3/money": "19.3.1",
45
+ "@ultimat3/policy": "19.3.1",
46
+ "@ultimat3/query": "19.3.1",
47
+ "@ultimat3/render": "19.3.1",
48
+ "@ultimat3/schema": "19.3.1",
49
+ "@ultimat3/ui": "19.3.1"
50
50
  }
51
51
  }
@@ -36,7 +36,12 @@ export const routesPanel: DevPanel<RoutesPanelData> = {
36
36
  for (const route of routes) counts.set(route.render, (counts.get(route.render) ?? 0) + 1);
37
37
  const byRenderMode = Object.fromEntries(counts);
38
38
  return {
39
- routes: [...routes].sort((a, b) => a.path.localeCompare(b.path)),
39
+ // Code units, never `localeCompare`: with no locale argument it answers from the runtime's
40
+ // ICU default locale and collation version, so the same route table reads in a different
41
+ // order on a developer's machine than in the container the same build runs in. The
42
+ // comparator is inlined rather than imported — `@ultimat3/render`'s `byCodeUnit` is
43
+ // package-internal, and a comparator is not public API worth widening a barrel for.
44
+ routes: [...routes].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)),
40
45
  byRenderMode,
41
46
  overBudget: routes
42
47
  .filter((route) => kb(route.budget.js) > BUDGET_LIMIT_KB)
package/src/dev/server.ts CHANGED
@@ -125,24 +125,36 @@ let stylePromise: Promise<string> | undefined;
125
125
  * served under, and the `style-src` hash it needs is of THIS text — a host that hashed its own
126
126
  * copy would send a policy that blocks the document this function actually writes.
127
127
  */
128
- export async function devShellStyle(): Promise<string> {
129
- stylePromise ??= import('@ultimat3/ui').then(({ colorTokens }) => {
130
- const block = (theme: 'light' | 'dark'): string =>
131
- SHELL_ROLES.map((role) => `--x-color-${role}: ${colorTokens[theme][role]};`).join(' ');
132
- return `
128
+ export function devShellStyle(): Promise<string> {
129
+ // One memo, and the clearing catch is attached where the promise is CREATED — the shape
130
+ // `packages/db/src/pglite.ts`'s `connect()` uses. Re-wrapping on every call
131
+ // (`stylePromise = stylePromise.catch(…)`, which is what this did) publishes a new promise per
132
+ // call, each one retaining the last: `/_x` grew that chain by a link per request for the life of
133
+ // the dev server, and no caller could rely on the memo's identity.
134
+ if (stylePromise === undefined) {
135
+ const attempt: Promise<string> = loadShellStyle().catch((error: unknown) => {
136
+ // A rejected import (a transient resolution failure) must not be memoised, or `/_x` is
137
+ // unstyled for the life of the process — the `jwks.ts` inflight pattern. Guarded on
138
+ // identity: a late rejection clears its OWN attempt, never a newer one that has replaced it.
139
+ if (stylePromise === attempt) stylePromise = undefined;
140
+ throw error;
141
+ });
142
+ stylePromise = attempt;
143
+ }
144
+ return stylePromise;
145
+ }
146
+
147
+ /** The read itself. Dynamic, so the 46-component barrel stays out of the production graph. */
148
+ async function loadShellStyle(): Promise<string> {
149
+ const { colorTokens } = await import('@ultimat3/ui');
150
+ const block = (theme: 'light' | 'dark'): string =>
151
+ SHELL_ROLES.map((role) => `--x-color-${role}: ${colorTokens[theme][role]};`).join(' ');
152
+ return `
133
153
  :root { ${block('light')} }
134
154
  @media (prefers-color-scheme: dark) { :root { ${block('dark')} } }
135
155
  html[data-theme="light"] { ${block('light')} }
136
156
  html[data-theme="dark"] { ${block('dark')} }
137
157
  ${SHELL_LAYOUT}`;
138
- });
139
- // A rejected import (a transient resolution failure) must not be memoised, or `/_x` is
140
- // unstyled for the life of the process — the `jwks.ts` inflight pattern.
141
- stylePromise = stylePromise.catch((error: unknown) => {
142
- stylePromise = undefined;
143
- throw error;
144
- });
145
- return stylePromise;
146
158
  }
147
159
 
148
160
  function shell(