@ultimat3/admin
Advanced tools
+16
-16
| { | ||
| "name": "@ultimat3/admin", | ||
| "version": "16.0.0", | ||
| "version": "17.0.0", | ||
| "description": "Two dashboards: the /_x framework dev panels and the generated, AI-first app admin", | ||
@@ -35,18 +35,18 @@ "license": "MIT", | ||
| "dependencies": { | ||
| "@ultimat3/action": "16.0.0", | ||
| "@ultimat3/ai": "16.0.0", | ||
| "@ultimat3/cache": "16.0.0", | ||
| "@ultimat3/core": "16.0.0", | ||
| "@ultimat3/db": "16.0.0", | ||
| "@ultimat3/entity": "16.0.0", | ||
| "@ultimat3/i18n": "16.0.0", | ||
| "@ultimat3/jobs": "16.0.0", | ||
| "@ultimat3/mcp": "16.0.0", | ||
| "@ultimat3/money": "16.0.0", | ||
| "@ultimat3/policy": "16.0.0", | ||
| "@ultimat3/query": "16.0.0", | ||
| "@ultimat3/render": "16.0.0", | ||
| "@ultimat3/schema": "16.0.0", | ||
| "@ultimat3/ui": "16.0.0" | ||
| "@ultimat3/action": "17.0.0", | ||
| "@ultimat3/ai": "17.0.0", | ||
| "@ultimat3/cache": "17.0.0", | ||
| "@ultimat3/core": "17.0.0", | ||
| "@ultimat3/db": "17.0.0", | ||
| "@ultimat3/entity": "17.0.0", | ||
| "@ultimat3/i18n": "17.0.0", | ||
| "@ultimat3/jobs": "17.0.0", | ||
| "@ultimat3/mcp": "17.0.0", | ||
| "@ultimat3/money": "17.0.0", | ||
| "@ultimat3/policy": "17.0.0", | ||
| "@ultimat3/query": "17.0.0", | ||
| "@ultimat3/render": "17.0.0", | ||
| "@ultimat3/schema": "17.0.0", | ||
| "@ultimat3/ui": "17.0.0" | ||
| } | ||
| } |
+14
-3
@@ -5,3 +5,3 @@ // Append-only audit log: actor, operation, entity, before/after diff, requestId, timestamp. | ||
| import { canonicalJson } from '@ultimat3/core'; | ||
| import { canonicalJson, finiteCount } from '@ultimat3/core'; | ||
| import type { AdminActor, AdminDecision } from './authz'; | ||
@@ -12,2 +12,5 @@ import type { AdminRow } from './registry'; | ||
| /** Named once, so both refusals below say the same thing about the same call. */ | ||
| const SUBJECT = 'memoryAuditLog'; | ||
| export interface AuditFieldDiff { | ||
@@ -96,3 +99,6 @@ readonly field: string; | ||
| const nextId = opts.nextId ?? ((): string => crypto.randomUUID()); | ||
| const capacity = opts.capacity ?? 1000; | ||
| // `log.length > NaN` is false for every length, so a capacity that is not a number does not make | ||
| // the ring bigger — it removes the ring, and this buffer then grows for the life of the process. | ||
| // At least 1, because a ring that keeps nothing is an audit log that records nothing. | ||
| const capacity = finiteCount(SUBJECT, 'capacity', opts.capacity ?? 1000, 1); | ||
| const sinks = opts.sinks ?? []; | ||
@@ -119,3 +125,8 @@ const log: AuditEntry[] = []; | ||
| const newestFirst = [...filtered].reverse(); | ||
| return query.limit === undefined ? newestFirst : newestFirst.slice(0, query.limit); | ||
| // The opposite failure to `capacity`, from the same missing check: `slice(0, NaN)` is `[]`, | ||
| // so an unreadable limit answers "nothing was ever logged" and reads as a successful read. | ||
| // 0 stays legal — asking for none is a coherent request. | ||
| return query.limit === undefined | ||
| ? newestFirst | ||
| : newestFirst.slice(0, finiteCount(SUBJECT, 'entries limit', query.limit)); | ||
| }, | ||
@@ -122,0 +133,0 @@ }; |
+6
-1
@@ -6,2 +6,3 @@ // Entity registry → a working CRUD resource, with nothing configured. Columns become | ||
| import { finiteCount } from '@ultimat3/core'; | ||
| import { type AdminColumnFacts, adminColumnsOf } from './entity-columns'; | ||
@@ -282,3 +283,7 @@ import { | ||
| defaultSort: opts.defaultSort ?? defaultSortOf(fields, idField), | ||
| pageSize: opts.pageSize ?? DEFAULT_PAGE_SIZE, | ||
| // Refused here rather than at the first listing, because `pagination.ts` clamps with | ||
| // `Math.max(1, Math.min(x, 200))` and neither of those validates: a `NaN` survives both, so | ||
| // `fetched.length > NaN` is false, the page is never trimmed, `hasMore` is false and the repo | ||
| // is asked for `limit: NaN`. At least 1 — a page with no rows on it is not a page. | ||
| pageSize: finiteCount('adminResource', 'pageSize', opts.pageSize ?? DEFAULT_PAGE_SIZE, 1), | ||
| operations: opts.operations ?? ADMIN_OPERATIONS, | ||
@@ -285,0 +290,0 @@ actions, |
+11
-1
@@ -5,2 +5,3 @@ // Cross-entity search, derived: every resource's text fields are the index. No separate | ||
| import { finiteCount } from '@ultimat3/core'; | ||
| import { expectedQueryLoop } from '@ultimat3/db'; | ||
@@ -108,3 +109,12 @@ import { type AuditEntry, deniedDraft } from './audit'; | ||
| const term = input.term.trim(); | ||
| const limit = input.limitPerResource ?? DEFAULT_LIMIT_PER_RESOURCE; | ||
| // Both consumers of this number fail silently on a `NaN`, in opposite directions: | ||
| // `hits.length >= NaN` is false, so the early return never fires and every field of every | ||
| // resource is queried, and `repo.list({ limit: NaN })` hands the repo a limit no `LIMIT` clause | ||
| // carries. At least 1 — a cap of zero is a search that is guaranteed to find nothing. | ||
| const limit = finiteCount( | ||
| 'adminSearch', | ||
| 'limitPerResource', | ||
| input.limitPerResource ?? DEFAULT_LIMIT_PER_RESOURCE, | ||
| 1, | ||
| ); | ||
| const searched: string[] = []; | ||
@@ -111,0 +121,0 @@ const skipped: { entity: string; reason: string }[] = []; |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
317304
0.55%6581
0.38%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated