@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 +6 -0
- package/package.json +16 -16
- package/src/dev/panel-routes.ts +6 -1
- package/src/dev/server.ts +25 -13
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.
|
|
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.
|
|
36
|
-
"@ultimat3/ai": "19.
|
|
37
|
-
"@ultimat3/cache": "19.
|
|
38
|
-
"@ultimat3/core": "19.
|
|
39
|
-
"@ultimat3/db": "19.
|
|
40
|
-
"@ultimat3/entity": "19.
|
|
41
|
-
"@ultimat3/i18n": "19.
|
|
42
|
-
"@ultimat3/jobs": "19.
|
|
43
|
-
"@ultimat3/mcp": "19.
|
|
44
|
-
"@ultimat3/money": "19.
|
|
45
|
-
"@ultimat3/policy": "19.
|
|
46
|
-
"@ultimat3/query": "19.
|
|
47
|
-
"@ultimat3/render": "19.
|
|
48
|
-
"@ultimat3/schema": "19.
|
|
49
|
-
"@ultimat3/ui": "19.
|
|
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
|
}
|
package/src/dev/panel-routes.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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(
|