@jini-ai/cms 0.3.11 → 0.4.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/CHANGELOG.md +59 -0
- package/README.md +47 -19
- package/dist/content-types/agent-tools.d.ts +3 -56
- package/dist/content-types/agent-tools.js +22 -6
- package/dist/content-types/cleanup.d.ts +18 -13
- package/dist/content-types/cleanup.js +16 -11
- package/dist/content-types/errors.d.ts +57 -24
- package/dist/content-types/errors.js +56 -39
- package/dist/content-types/field-defs.d.ts +8 -4
- package/dist/content-types/field-defs.js +19 -14
- package/dist/content-types/index-provisioning.d.ts +61 -47
- package/dist/content-types/index-provisioning.js +90 -66
- package/dist/content-types/index.d.ts +4 -3
- package/dist/content-types/lifecycle-dispatch.d.ts +11 -5
- package/dist/content-types/lifecycle-dispatch.js +5 -4
- package/dist/content-types/lifecycle.d.ts +23 -18
- package/dist/content-types/lifecycle.js +71 -64
- package/dist/content-types/repo.memory.d.ts +5 -4
- package/dist/content-types/repo.memory.js +3 -2
- package/dist/content-types/tool-registrations.d.ts +6 -8
- package/dist/content-types/tool-registrations.js +24 -28
- package/dist/content-types/types.d.ts +17 -13
- package/dist/content-types/types.js +11 -5
- package/dist/content-types/write-service.d.ts +20 -22
- package/dist/content-types/write-service.js +78 -75
- package/dist/core/authorization.d.ts +15 -0
- package/dist/core/authorization.js +2 -0
- package/dist/core/commands/change-set.d.ts +15 -7
- package/dist/core/commands/command.d.ts +45 -26
- package/dist/core/commands/command.js +73 -63
- package/dist/core/entity-liveness.d.ts +11 -7
- package/dist/core/entity-liveness.js +5 -4
- package/dist/core/index.d.ts +12 -5
- package/dist/core/index.js +10 -4
- package/dist/core/ports.d.ts +25 -24
- package/dist/core/ports.js +1 -0
- package/dist/core/tools/args.d.ts +49 -0
- package/dist/core/tools/args.js +46 -0
- package/dist/core/tools/index.d.ts +3 -0
- package/dist/core/tools/index.js +3 -0
- package/dist/entries/agent-tools.d.ts +1 -73
- package/dist/entries/agent-tools.js +19 -13
- package/dist/entries/errors.d.ts +28 -14
- package/dist/entries/errors.js +17 -11
- package/dist/entries/field-validation.d.ts +5 -3
- package/dist/entries/field-validation.js +7 -5
- package/dist/entries/index.d.ts +2 -2
- package/dist/entries/lifecycle-dispatch.d.ts +5 -2
- package/dist/entries/lifecycle-dispatch.js +2 -1
- package/dist/entries/list.d.ts +4 -2
- package/dist/entries/list.js +4 -3
- package/dist/entries/repo.memory.d.ts +12 -10
- package/dist/entries/repo.memory.js +11 -10
- package/dist/entries/tool-registrations.d.ts +6 -8
- package/dist/entries/tool-registrations.js +42 -41
- package/dist/entries/types.d.ts +0 -7
- package/dist/entries/write-service.d.ts +28 -29
- package/dist/entries/write-service.js +114 -105
- package/dist/http/settings/cms-adapter.d.ts +20 -0
- package/dist/http/settings/cms-adapter.js +124 -0
- package/dist/http/settings/contracts.d.ts +135 -0
- package/dist/http/settings/contracts.js +2 -0
- package/dist/http/settings/http.d.ts +10 -0
- package/dist/http/settings/http.js +211 -0
- package/dist/http/settings/index.d.ts +5 -0
- package/dist/http/settings/index.js +4 -0
- package/dist/http/settings/shared.d.ts +68 -0
- package/dist/http/settings/shared.js +54 -0
- package/dist/http/settings/stream.d.ts +24 -0
- package/dist/http/settings/stream.js +147 -0
- package/dist/media/agent-tools.d.ts +1 -66
- package/dist/media/agent-tools.js +5 -1
- package/dist/media/blob-gc-lock.d.ts +6 -2
- package/dist/media/blob-gc-lock.js +4 -2
- package/dist/media/blob-gc.d.ts +64 -51
- package/dist/media/blob-gc.js +62 -52
- package/dist/media/blob-key.d.ts +1 -1
- package/dist/media/content-type-sniffer.d.ts +3 -1
- package/dist/media/content-type-sniffer.js +1 -1
- package/dist/media/html-attributes.d.ts +9 -5
- package/dist/media/html-attributes.js +8 -6
- package/dist/media/image-transformer.js +1 -1
- package/dist/media/image-transformer.sharp.d.ts +6 -0
- package/dist/media/image-transformer.sharp.js +12 -6
- package/dist/media/import/fetch-image.d.ts +24 -0
- package/dist/media/import/fetch-image.js +137 -0
- package/dist/media/import/index.d.ts +3 -0
- package/dist/media/import/index.js +3 -0
- package/dist/media/import/ports.d.ts +38 -0
- package/dist/media/index.d.ts +7 -1
- package/dist/media/index.js +1 -0
- package/dist/media/media-service.d.ts +14 -10
- package/dist/media/media-service.js +57 -52
- package/dist/media/ports.d.ts +3 -2
- package/dist/media/rendition-service.d.ts +3 -3
- package/dist/media/rendition-service.js +38 -37
- package/dist/media/repo.memory.d.ts +18 -7
- package/dist/media/repo.memory.js +12 -6
- package/dist/media/tool-registrations.d.ts +16 -15
- package/dist/media/tool-registrations.js +84 -72
- package/dist/media/transform-lock.d.ts +22 -12
- package/dist/media/transform-lock.js +14 -13
- package/dist/media/transform-registry.d.ts +3 -3
- package/dist/media/transform-registry.js +19 -18
- package/dist/media/transform-types.d.ts +8 -3
- package/dist/media/transform-types.js +10 -5
- package/dist/media/types.d.ts +21 -4
- package/dist/media/types.js +15 -2
- package/dist/navigation/agent-tools.d.ts +1 -80
- package/dist/navigation/agent-tools.js +15 -3
- package/dist/navigation/contracts.d.ts +1 -1
- package/dist/navigation/index.d.ts +2 -2
- package/dist/navigation/menu-service.d.ts +57 -40
- package/dist/navigation/menu-service.js +80 -69
- package/dist/navigation/ports.d.ts +1 -1
- package/dist/navigation/read-model.d.ts +3 -1
- package/dist/navigation/read-model.js +2 -2
- package/dist/navigation/reconcile.d.ts +2 -2
- package/dist/navigation/reconcile.js +2 -1
- package/dist/navigation/repo.memory.d.ts +7 -3
- package/dist/navigation/repo.memory.js +4 -2
- package/dist/navigation/resolver.d.ts +4 -1
- package/dist/navigation/resolver.js +1 -1
- package/dist/navigation/tool-registrations.d.ts +6 -8
- package/dist/navigation/tool-registrations.js +44 -42
- package/dist/navigation/types.d.ts +1 -1
- package/dist/presentation/presentation.d.ts +11 -3
- package/dist/presentation/presentation.js +13 -6
- package/dist/presentation/repo.memory.d.ts +6 -2
- package/dist/presentation/repo.memory.js +3 -2
- package/dist/settings/agent-tools.d.ts +2 -75
- package/dist/settings/agent-tools.js +49 -45
- package/dist/settings/agent-value-write-tools.d.ts +22 -0
- package/dist/settings/agent-value-write-tools.js +154 -0
- package/dist/settings/agent-writable-preferences.js +8 -20
- package/dist/settings/agent-write-denylist.d.ts +19 -0
- package/dist/settings/agent-write-denylist.js +15 -0
- package/dist/settings/change-feed.d.ts +11 -2
- package/dist/settings/change-feed.js +4 -4
- package/dist/settings/definitions-dispatch.d.ts +8 -3
- package/dist/settings/definitions-dispatch.js +5 -5
- package/dist/settings/dictionaries/index.d.ts +5 -2
- package/dist/settings/dictionaries/index.js +2 -2
- package/dist/settings/dictionaries/settings-dialog.ar.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.bn.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.de.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.es.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.fa.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.fr.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.hi.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.hu.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.id.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.it.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.ja.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.ko.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.pl.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.pt-BR.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.ru.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.th.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.tr.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.uk.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.ur.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.zh-CN.js +0 -1
- package/dist/settings/dictionaries/settings-dialog.zh-TW.js +0 -1
- package/dist/settings/ensure-definitions.d.ts +5 -5
- package/dist/settings/errors.d.ts +7 -1
- package/dist/settings/errors.js +7 -1
- package/dist/settings/index.d.ts +4 -1
- package/dist/settings/index.js +1 -0
- package/dist/settings/ports.d.ts +6 -5
- package/dist/settings/principal-lookup.d.ts +9 -0
- package/dist/settings/principal-lookup.js +2 -0
- package/dist/settings/purge-service.d.ts +5 -4
- package/dist/settings/purge-service.js +3 -2
- package/dist/settings/settings.d.ts +22 -7
- package/dist/settings/settings.js +47 -26
- package/dist/settings/tool-registrations.d.ts +25 -32
- package/dist/settings/tool-registrations.js +66 -56
- package/dist/settings/types.d.ts +1 -1
- package/dist/settings/ui-tab-definitions.d.ts +1 -1
- package/dist/settings/write-service.d.ts +32 -26
- package/dist/settings/write-service.js +26 -20
- package/dist/taxonomy/agent-tools.d.ts +1 -66
- package/dist/taxonomy/agent-tools.js +25 -15
- package/dist/taxonomy/content-lookup.js +1 -1
- package/dist/taxonomy/index.d.ts +2 -2
- package/dist/taxonomy/merge-term.d.ts +7 -4
- package/dist/taxonomy/merge-term.js +7 -5
- package/dist/taxonomy/repo.memory.d.ts +42 -19
- package/dist/taxonomy/repo.memory.js +14 -12
- package/dist/taxonomy/validation-chain.d.ts +39 -18
- package/dist/taxonomy/validation-chain.js +35 -25
- package/dist/taxonomy/write-service.d.ts +103 -44
- package/dist/taxonomy/write-service.js +221 -179
- package/dist/trash/adapters/record-store.d.ts +52 -0
- package/dist/trash/adapters/record-store.js +36 -0
- package/dist/trash/cursor.d.ts +20 -0
- package/dist/trash/cursor.js +36 -0
- package/dist/trash/follow-ups.d.ts +76 -0
- package/dist/trash/follow-ups.js +46 -0
- package/dist/trash/index.d.ts +8 -0
- package/dist/trash/index.js +8 -0
- package/dist/trash/ports.d.ts +308 -0
- package/dist/trash/ports.js +2 -0
- package/dist/trash/repo.memory.d.ts +50 -0
- package/dist/trash/repo.memory.js +114 -0
- package/dist/trash/sweeper.d.ts +77 -0
- package/dist/trash/sweeper.js +127 -0
- package/dist/trash/write-service.d.ts +100 -0
- package/dist/trash/write-service.js +242 -0
- package/dist/workspace/agent-tools.d.ts +1 -59
- package/dist/workspace/agent-tools.js +27 -12
- package/dist/workspace/create.d.ts +31 -6
- package/dist/workspace/create.js +18 -5
- package/dist/workspace/delete.d.ts +18 -13
- package/dist/workspace/delete.js +20 -12
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/repo.memory.d.ts +19 -4
- package/dist/workspace/repo.memory.js +26 -4
- package/dist/workspace/tool-registrations.d.ts +2 -2
- package/dist/workspace/tool-registrations.js +13 -13
- package/dist/workspace/update.d.ts +6 -5
- package/dist/workspace/update.js +9 -8
- package/package.json +44 -38
- package/dist/identity/admin-crud-service.d.ts +0 -280
- package/dist/identity/admin-crud-service.js +0 -468
- package/dist/identity/agent-tool-input.d.ts +0 -58
- package/dist/identity/agent-tool-input.js +0 -126
- package/dist/identity/agent-tools.d.ts +0 -101
- package/dist/identity/agent-tools.js +0 -290
- package/dist/identity/auth-service.d.ts +0 -118
- package/dist/identity/auth-service.js +0 -170
- package/dist/identity/authorize.d.ts +0 -90
- package/dist/identity/authorize.js +0 -94
- package/dist/identity/grant-service.d.ts +0 -198
- package/dist/identity/grant-service.js +0 -361
- package/dist/identity/hasher.d.ts +0 -39
- package/dist/identity/hasher.js +0 -39
- package/dist/identity/index.d.ts +0 -62
- package/dist/identity/index.js +0 -54
- package/dist/identity/password-policy.d.ts +0 -57
- package/dist/identity/password-policy.js +0 -66
- package/dist/identity/permission-migrations.d.ts +0 -86
- package/dist/identity/permission-migrations.js +0 -67
- package/dist/identity/permissions.d.ts +0 -35
- package/dist/identity/permissions.js +0 -603
- package/dist/identity/ports.d.ts +0 -201
- package/dist/identity/repo.memory.d.ts +0 -164
- package/dist/identity/repo.memory.js +0 -224
- package/dist/identity/seed.d.ts +0 -54
- package/dist/identity/seed.js +0 -429
- package/dist/identity/tool-registrations.d.ts +0 -50
- package/dist/identity/tool-registrations.js +0 -419
- package/dist/identity/types.d.ts +0 -185
- package/dist/identity/types.js +0 -64
- package/dist/identity/username.d.ts +0 -12
- package/dist/identity/username.js +0 -14
- /package/dist/{identity → media/import}/ports.js +0 -0
|
@@ -1,83 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @file The Navigation (Menus) agent-tool catalog — this domain's instance of the
|
|
3
|
-
* per-domain `agent-tools.ts` convention `forms/agent-tools.ts` and `identity/agent-tools.ts`
|
|
4
|
-
* already use.
|
|
5
|
-
*
|
|
6
|
-
* Purpose:
|
|
7
|
-
* A static, in-process catalog describing every agent-callable tool this domain exposes and the
|
|
8
|
-
* permission each carries. Every entry maps 1:1 onto a real exported function of
|
|
9
|
-
* `navigation/menu-service.ts` (plus two pure reads over `MenuRepoPort`) — this catalog never names
|
|
10
|
-
* an operation the domain cannot perform.
|
|
11
|
-
*
|
|
12
|
-
* Precedent already in this library: `navigation/contracts.ts` declares `NAVIGATION_AI_TOOLS` — a
|
|
13
|
-
* design-note list of an intended future AI tool surface (`navigation.search`/`.get`/`.where_used`/
|
|
14
|
-
* `.update`/`.assign`) for a DIFFERENT, not-yet-built delivery mechanism (a "change-set review
|
|
15
|
-
* layer" HITL gateway; the list itself is unused anywhere in this build today). Two of its five
|
|
16
|
-
* names do not correspond to any real, callable capability in this build: `navigation.search` has
|
|
17
|
-
* no implementation beyond `MenuRepoPort.list` (folded into `menus_list_menus` below — there is no
|
|
18
|
-
* separate text-search capability, matching how `identity_user_list`/`identity_role_list` are
|
|
19
|
-
* likewise this library's "search" for their own domains), and `navigation.where_used` has no
|
|
20
|
-
* implementation anywhere (`NavWhereUsedResult` is declared in `contracts.ts` but no function in
|
|
21
|
-
* `navigation/` computes it — `entry_refs`-backed where-used, unlike `widgets`/`media`, was never
|
|
22
|
-
* built for menus). Wrapping either literally would invent backend capability this catalog's own
|
|
23
|
-
* discipline forbids; `menus_list_menus` + `menus_get_menu` are this build's honest equivalents of
|
|
24
|
-
* "search"/"get".
|
|
25
|
-
*
|
|
26
|
-
* Deliberate absence (the point of a catalog, not an oversight):
|
|
27
|
-
* - There is NO `menus_delete_menu` (nor a separate trash-only tool). `deleteMenu` is ONE function
|
|
28
|
-
* that performs BOTH steps of the deletion ladder, keyed off the menu's CURRENT status:
|
|
29
|
-
* a first call trashes (safe, unconditional), but a second call against an already-trashed menu
|
|
30
|
-
* PURGES it — a hard, irreversible delete, blocked only by a still-bound-location guard that
|
|
31
|
-
* itself can be bypassed with `force` (gated behind the separate `admin.menus.delete.force`
|
|
32
|
-
* permission). Unlike `widgets`/`media` (which expose trash and purge as two SEPARATE domain
|
|
33
|
-
* functions, letting a catalog safely wire trash alone), navigation has no decomposed trash-only
|
|
34
|
-
* entrypoint to call — the very same tool call, made twice, silently escalates from a reversible
|
|
35
|
-
* soft-delete into a permanent one. That is exactly the shape of risk `identity/agent-tools.ts`
|
|
36
|
-
* excludes `resetUserPassword` for: a single lever whose second pull does something categorically
|
|
37
|
-
* more dangerous than its first, reachable by an agent re-invoking a tool it already called once
|
|
38
|
-
* (e.g. after losing track of a prior call, or via prompt injection through ordinary operator
|
|
39
|
-
* content). Left human-UI-only.
|
|
40
|
-
*
|
|
41
|
-
* How it relates to the project:
|
|
42
|
-
* A host's own tool-registration layer maps these entries into `ToolRegistration`s (see
|
|
43
|
-
* `tool-registrations.ts`). Unlike Forms/Identity/Widgets, `menu-service.ts`'s functions perform NO
|
|
44
|
-
* internal `authorize()` call of their own (confirmed: `CreateMenuDeps`/`UpdateMenuTreeDeps`/
|
|
45
|
-
* `AssignLocationDeps` carry no `authorize` field) — every admin HTTP route a host builds is expected
|
|
46
|
-
* to check `deps.authorize(...)` inline, before calling the service function (mirrors `media`'s
|
|
47
|
-
* identical gap, see `media/agent-tools.ts`'s header). `tool-registrations.ts` therefore performs
|
|
48
|
-
* that SAME inline `authorize()` call itself (the identical permission string and `entityType:
|
|
49
|
-
* "menu"` the HTTP route uses) rather than relying on a domain-layer gate that does not exist for
|
|
50
|
-
* this library.
|
|
51
|
-
*
|
|
52
|
-
* Architectural role:
|
|
53
|
-
* `navigation` domain declaration. Imports only `VALID_TARGET_KINDS`-equivalent constants are not
|
|
54
|
-
* exported from `menu-service.ts` as public data (the target-kind allowlist is enforced, not
|
|
55
|
-
* published, there), so the target schema below is hand-authored against `types.ts`'s `NavTarget`
|
|
56
|
-
* union and cross-checked by this catalog's own contract test rather than imported.
|
|
57
|
-
*/
|
|
58
|
-
export type AgentToolSideEffect = "none" | "mutates-durable-state" | "mints-token";
|
|
59
|
-
export type AgentToolActorClassRule = "confirmer-must-equal-own-delegatedBy" | "user-only" | "none";
|
|
60
|
-
export interface AgentToolDefinition {
|
|
61
|
-
name: string;
|
|
62
|
-
description: string;
|
|
63
|
-
sideEffects: AgentToolSideEffect;
|
|
64
|
-
authorization: {
|
|
65
|
-
permission: string;
|
|
66
|
-
};
|
|
67
|
-
actorClassRule?: AgentToolActorClassRule;
|
|
68
|
-
/**
|
|
69
|
-
* JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
|
|
70
|
-
* (a host's own tool-registration layer, which refuses to wire any tool lacking one).
|
|
71
|
-
*
|
|
72
|
-
* Deliberately not widened to `| undefined` (unlike most optional fields in this port) — this
|
|
73
|
-
* type flows into `core/tools/registration-kit.ts`'s `WirableToolDefinition`, which declares both
|
|
74
|
-
* this field and `actorClassRule` below without `| undefined`. Widening only this catalog's copy
|
|
75
|
-
* would make it structurally incompatible with that shared interface under
|
|
76
|
-
* `exactOptionalPropertyTypes`, which is exactly what identity's own `agent-tools.ts` avoids for
|
|
77
|
-
* the same reason.
|
|
78
|
-
*/
|
|
79
|
-
inputSchema?: Readonly<Record<string, unknown>>;
|
|
80
|
-
}
|
|
1
|
+
import type { AgentToolDefinition } from "@jini-ai/core";
|
|
81
2
|
/**
|
|
82
3
|
* The Navigation domain's fixed agent-tool catalog — the 5 operations a host's admin HTTP surface
|
|
83
4
|
* (`server/routes/admin/menus/*.ts`) exposes that are safe to wrap, out of its 6 total (see file
|
|
@@ -56,6 +56,17 @@
|
|
|
56
56
|
* union and cross-checked by this catalog's own contract test rather than imported.
|
|
57
57
|
*/
|
|
58
58
|
import { ALLOWED_HREF_SHAPES_DESCRIPTION } from "./menu-service.js";
|
|
59
|
+
/**
|
|
60
|
+
* JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
|
|
61
|
+
* (a host's own tool-registration layer, which refuses to wire any tool lacking one).
|
|
62
|
+
*
|
|
63
|
+
* Deliberately not widened to `| undefined` (unlike most optional fields in this port) — this
|
|
64
|
+
* type flows into `@jini-ai/core`'s `registration-kit.ts`'s `AgentToolDefinition`, which declares both
|
|
65
|
+
* this field and `actorClassRule` below without `| undefined`. Widening only this catalog's copy
|
|
66
|
+
* would make it structurally incompatible with that shared interface under
|
|
67
|
+
* `exactOptionalPropertyTypes`, which is exactly what identity's own `agent-tools.ts` avoids for
|
|
68
|
+
* the same reason.
|
|
69
|
+
*/
|
|
59
70
|
const MENU_ID_SCHEMA = {
|
|
60
71
|
type: "string",
|
|
61
72
|
description: "The menu's id, as returned by menus_list_menus, menus_get_menu, or menus_create_menu.",
|
|
@@ -152,7 +163,7 @@ const ITEMS_TREE_SCHEMA = {
|
|
|
152
163
|
export const menusAgentToolCatalog = [
|
|
153
164
|
{
|
|
154
165
|
name: "menus_list_menus",
|
|
155
|
-
description: "Lists every menu in the workspace (id, slug, title, status, item tree, locations, version). Read-only.",
|
|
166
|
+
description: "Lists every menu in the workspace (id, slug, title, status, item tree, locations, version). Read-only. To delete a menu, use trash_item with entityType 'menu' (it moves to the Trash and can be restored).",
|
|
156
167
|
sideEffects: "none",
|
|
157
168
|
authorization: { permission: "admin.menus.read" },
|
|
158
169
|
inputSchema: {
|
|
@@ -177,7 +188,8 @@ export const menusAgentToolCatalog = [
|
|
|
177
188
|
{
|
|
178
189
|
name: "menus_create_menu",
|
|
179
190
|
description: "Creates a new menu in 'draft' status with no location assigned yet — it has no effect on the live site until " +
|
|
180
|
-
"menus_assign_location binds it somewhere. Rejects a duplicate slug within the workspace."
|
|
191
|
+
"menus_assign_location binds it somewhere. Rejects a duplicate slug within the workspace. " +
|
|
192
|
+
"To delete a menu, use trash_item with entityType 'menu' (it moves to the Trash and can be restored).",
|
|
181
193
|
sideEffects: "mutates-durable-state",
|
|
182
194
|
authorization: { permission: "admin.menus.create" },
|
|
183
195
|
inputSchema: {
|
|
@@ -195,7 +207,7 @@ export const menusAgentToolCatalog = [
|
|
|
195
207
|
name: "menus_update_menu_tree",
|
|
196
208
|
description: "Replaces an existing menu's whole item tree (and optionally its title/slug) in one version-guarded write. " +
|
|
197
209
|
"Always a whole-tree replace — there is no per-item patch operation, so the submitted tree must include every " +
|
|
198
|
-
"item the menu keeps.",
|
|
210
|
+
"item the menu keeps. To delete a menu, use trash_item with entityType 'menu' (it moves to the Trash and can be restored).",
|
|
199
211
|
sideEffects: "mutates-durable-state",
|
|
200
212
|
authorization: { permission: "admin.menus.update" },
|
|
201
213
|
inputSchema: {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* INTERFACES + DATA CATALOGS ONLY. No feature logic.
|
|
12
12
|
*/
|
|
13
|
-
import type { UUID } from "
|
|
13
|
+
import type { UUID } from "@jini-ai/core/primitives";
|
|
14
14
|
import type { NavItemNode, NavLocationKey, NavMenuEntry } from "./types.js";
|
|
15
15
|
/**
|
|
16
16
|
* The `admin.menus.*` permission strings (renamed
|
|
@@ -9,7 +9,7 @@ export { NAV_MENU_CONTENT_TYPE, NAV_FIELD_NAMESPACE, NAV_DOC_TYPE } from "./type
|
|
|
9
9
|
export type { NavLocationBindingRepoPort, NavResolveContext, NavTargetResolver, NavMenuReadModel, NavLocationRegistry, } from "./ports.js";
|
|
10
10
|
export type { NavigationPermission, CreateMenuInput, UpdateMenuInput, AssignLocationInput, UnassignLocationInput, DeleteMenuInput, NavigationEventName, NavMenuChangedPayload, NavLocationChangedPayload, NavigationHookName, NavigationAiTool, NavWhereUsedResult, } from "./contracts.js";
|
|
11
11
|
export { NAVIGATION_PERMISSIONS, NAVIGATION_EVENTS, NAVIGATION_HOOKS, NAVIGATION_AI_TOOLS, } from "./contracts.js";
|
|
12
|
-
export { createNavMenuReadModel, type NavMenuReadModelDeps } from "./read-model.js";
|
|
12
|
+
export { createNavMenuReadModel, type NavMenuReadModelDeps, type NavMenuReadModelOptions } from "./read-model.js";
|
|
13
13
|
/**
|
|
14
14
|
* `MenuRepoPort` is navigation-owned (not part of the frozen `ports.ts` ADR surface — see
|
|
15
15
|
* `repo.memory.ts`'s file header for why) but is a real public contract: a host's own SQLite
|
|
@@ -29,7 +29,7 @@ export { createMenu, updateMenuTree, assignLocation, deleteMenu, validateAndClon
|
|
|
29
29
|
export { resolveForLocation, resolveMenuDoc, type ResolveTargetHrefFn, type ResolvedTargetHref, type ResolveForLocationDeps, type ResolveForLocationServiceInput, type ResolveForLocationRequired, type ResolveForLocationOptional, } from "./resolver.js";
|
|
30
30
|
export { rebuildNavLocationBindings, type RebuildNavLocationBindingsDeps, type RebuildNavLocationBindingsResult, } from "./reconcile.js";
|
|
31
31
|
/** The agent-tool surface for this domain (see `agent-tools.ts` for what is deliberately omitted). */
|
|
32
|
-
export { menusAgentToolCatalog,
|
|
32
|
+
export { menusAgentToolCatalog, } from "./agent-tools.js";
|
|
33
33
|
/**
|
|
34
34
|
* The agent-tool wiring for this domain.
|
|
35
35
|
*
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Clock, IdGenerator, UUID } from "@jini-ai/core/primitives";
|
|
2
|
+
import type { OutboxPort } from "../core/ports.js";
|
|
2
3
|
import type { MenuRepoPort } from "./repo.memory.js";
|
|
3
4
|
import type { NavLocationBindingRepoPort } from "./ports.js";
|
|
4
5
|
import { type NavItemNode, type NavLocationBindingRow, type NavLocationKey, type NavMenuEntry } from "./types.js";
|
|
5
6
|
export declare class MenuNotFoundError extends Error {
|
|
7
|
+
constructor({ message }: {
|
|
8
|
+
message: string;
|
|
9
|
+
}, optionalArgs?: ErrorOptions);
|
|
6
10
|
}
|
|
7
11
|
export declare class MenuValidationError extends Error {
|
|
12
|
+
constructor({ message }: {
|
|
13
|
+
message: string;
|
|
14
|
+
}, optionalArgs?: ErrorOptions);
|
|
8
15
|
}
|
|
9
16
|
export declare class MenuConflictError extends Error {
|
|
17
|
+
constructor({ message }: {
|
|
18
|
+
message: string;
|
|
19
|
+
}, optionalArgs?: ErrorOptions);
|
|
10
20
|
}
|
|
11
21
|
/**
|
|
12
22
|
* The 409-style purge rejection: hard delete is blocked while the menu is
|
|
@@ -16,7 +26,10 @@ export declare class MenuConflictError extends Error {
|
|
|
16
26
|
*/
|
|
17
27
|
export declare class MenuLocationBoundError extends MenuConflictError {
|
|
18
28
|
readonly boundLocations: readonly NavLocationKey[];
|
|
19
|
-
constructor(
|
|
29
|
+
constructor(requiredArgs: {
|
|
30
|
+
message: string;
|
|
31
|
+
boundLocations: readonly NavLocationKey[];
|
|
32
|
+
}, optionalArgs?: Record<string, never>);
|
|
20
33
|
}
|
|
21
34
|
/** Default max nesting depth (root = depth 1). Configurable. */
|
|
22
35
|
export declare const DEFAULT_MAX_TREE_DEPTH = 5;
|
|
@@ -25,7 +38,7 @@ export declare const DEFAULT_MAX_ITEM_COUNT = 500;
|
|
|
25
38
|
/**
|
|
26
39
|
* The CANONICAL href allowlist for an author-authored link — same accepted shapes (`#…`, same-origin
|
|
27
40
|
* `/…`, `http(s)://`, `mailto:`) as the host's render-time `safeHref` in `render.ts` and its
|
|
28
|
-
* `features/theme/static-render.ts` duplicate. **This is now the single source of truth
|
|
41
|
+
* `features/theme/static-render.ts` duplicate. **This is now the single source of truth** exported
|
|
29
42
|
* from this package's public surface (`navigation/index.ts` -> `@jini-ai/cms/navigation`) so the
|
|
30
43
|
* dependency runs the direction that is actually legal — the host already depends on `@jini-ai/cms`, not
|
|
31
44
|
* the reverse — rather than each consumer hand-copying the predicate.
|
|
@@ -36,14 +49,14 @@ export declare const DEFAULT_MAX_ITEM_COUNT = 500;
|
|
|
36
49
|
* `check:boundaries` no-deep-import concern is NOT what blocks it: `render.ts` already imports
|
|
37
50
|
* `@jini-ai/cms/core` today, and `features/theme` already imports `@jini-ai/cms/core` too, so both
|
|
38
51
|
* call sites may legally import `@jini-ai/cms/navigation` directly — verified by grep, not assumed).
|
|
39
|
-
* Until that follow-up lands,
|
|
52
|
+
* Until that follow-up lands, the host's menu href allowlist sync check
|
|
40
53
|
* behaviorally gates the three copies against the same adversarial table so a divergence fails CI
|
|
41
54
|
* instead of drifting silently.
|
|
42
55
|
*
|
|
43
|
-
* Replaced (this change) a `URL_SCHEME_DENYLIST` (`startsWith` on a lowercased, `.trim
|
|
56
|
+
* Replaced (this change) a `URL_SCHEME_DENYLIST` (`startsWith` on a lowercased, `.trim`ed string)
|
|
44
57
|
* that failed open: the WHATWG `URL` parser strips TAB/LF/CR from ANYWHERE in the input and folds a
|
|
45
|
-
* leading backslash to `/` for `http(s)`, so `"java\tscript:alert
|
|
46
|
-
* `"file
|
|
58
|
+
* leading backslash to `/` for `http(s)`, so `"java\tscript:alert"`, `" javascript:alert"`,
|
|
59
|
+
* `"file:// etc/passwd"`, `"blob:…"`, `"about:blank"`, `"//evil.example"` (protocol-relative), and
|
|
47
60
|
* `"/\evil.example"` all resolved to a dangerous or off-origin target while never matching any
|
|
48
61
|
* `startsWith` prefix in the old list. An allowlist closes the whole bypass class at once (case,
|
|
49
62
|
* embedded control characters, and scheme are all irrelevant to an allowlist the same way) rather
|
|
@@ -58,11 +71,13 @@ export declare const DEFAULT_MAX_ITEM_COUNT = 500;
|
|
|
58
71
|
* hrefs written through the host's admin editor.
|
|
59
72
|
*
|
|
60
73
|
* @param rawHref - The href to check, already confirmed non-empty by `validateTarget`. Any string is
|
|
61
|
-
*
|
|
74
|
+
* otherwise a valid input — this function performs no other precondition checks.
|
|
62
75
|
* @returns `true` when `rawHref` passes the allowlist, `false` otherwise.
|
|
63
|
-
* @complexity O
|
|
76
|
+
* @complexity O — a handful of string checks plus one `URL` construction on the `/…` branch.
|
|
64
77
|
*/
|
|
65
|
-
export declare function isAllowedHref(rawHref
|
|
78
|
+
export declare function isAllowedHref({ rawHref }: {
|
|
79
|
+
rawHref: string;
|
|
80
|
+
}, _optional?: Record<string, never>): boolean;
|
|
66
81
|
/**
|
|
67
82
|
* Human-readable description of {@link isAllowedHref}'s accepted shapes — the single source of truth
|
|
68
83
|
* for both `validateTarget`'s rejection message below and `agent-tools.ts`'s published JSON Schema
|
|
@@ -80,31 +95,33 @@ export interface TreeValidationLimits {
|
|
|
80
95
|
*
|
|
81
96
|
* Checks (total/bounded validation + target integrity):
|
|
82
97
|
* - `items` (and every `children` array) is actually an array, and every node
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
98
|
+
* in it is a non-null object — untrusted JSON bodies can carry `null`
|
|
99
|
+
* entries or a non-array `items`/`children`, which must reject as a
|
|
100
|
+
* `MenuValidationError`, not throw an uncaught `TypeError`;
|
|
86
101
|
* - every node has a non-empty `id`, unique across the whole tree (id
|
|
87
|
-
*
|
|
88
|
-
*
|
|
102
|
+
* stability is a caller responsibility — see `updateMenuTree` doc for the
|
|
103
|
+
* simplification this build accepts);
|
|
89
104
|
* - nesting depth stays within `maxDepth`;
|
|
90
105
|
* - total item count stays within `maxItemCount`;
|
|
91
106
|
* - every node has a `target` object (a missing/`null` `target` rejects
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
107
|
+
* rather than crashing) whose `kind` is one of the four v1 kinds — reserved
|
|
108
|
+
* kinds (`dynamicQuery`, `content`) are rejected with a clear "not yet"
|
|
109
|
+
* error rather than silently accepted;
|
|
95
110
|
* - `url` targets require a non-empty string `href` and pass an origin/scheme
|
|
96
|
-
*
|
|
97
|
-
*
|
|
111
|
+
* ALLOWLIST (`#…`, same-origin `/…`, `http(s)://`, `mailto:` — see
|
|
112
|
+
* {@link isAllowedHref}), not a scheme denylist.
|
|
98
113
|
*
|
|
99
114
|
* @complexity O(n) over total node count for one full walk; no per-node
|
|
100
115
|
* backtracking. Space is O(n) for the cloned tree plus O(n) for the id set.
|
|
101
116
|
* @overallScore 100
|
|
102
117
|
*/
|
|
103
|
-
export declare function validateAndCloneTree(items
|
|
118
|
+
export declare function validateAndCloneTree({ items }: {
|
|
119
|
+
items: readonly NavItemNode[];
|
|
120
|
+
}, limits?: TreeValidationLimits): NavItemNode[];
|
|
104
121
|
export interface CreateMenuDeps {
|
|
105
122
|
repo: MenuRepoPort;
|
|
106
|
-
clock:
|
|
107
|
-
idGen:
|
|
123
|
+
clock: Clock;
|
|
124
|
+
idGen: IdGenerator;
|
|
108
125
|
/** Enqueues `navigation.menu.created` after a successful save. */
|
|
109
126
|
outbox: OutboxPort;
|
|
110
127
|
}
|
|
@@ -142,9 +159,9 @@ export declare function createMenu(required: CreateMenuRequired, optional?: Crea
|
|
|
142
159
|
}>;
|
|
143
160
|
export interface UpdateMenuTreeDeps {
|
|
144
161
|
repo: MenuRepoPort;
|
|
145
|
-
clock:
|
|
162
|
+
clock: Clock;
|
|
146
163
|
/** Not previously present on this deps bag — needed to mint the outbox event's id. */
|
|
147
|
-
idGen:
|
|
164
|
+
idGen: IdGenerator;
|
|
148
165
|
/** Enqueues `navigation.menu.updated` after a successful save. */
|
|
149
166
|
outbox: OutboxPort;
|
|
150
167
|
}
|
|
@@ -176,7 +193,7 @@ export interface UpdateMenuTreeOptional {
|
|
|
176
193
|
* previous tree and is deferred — a caller-discipline requirement for now,
|
|
177
194
|
* not a runtime-enforced invariant.
|
|
178
195
|
*
|
|
179
|
-
* @complexity O(n) in the new tree size for validation; O
|
|
196
|
+
* @complexity O(n) in the new tree size for validation; O additional repo
|
|
180
197
|
* calls (one read, at most one slug-uniqueness read, one write).
|
|
181
198
|
* @overallScore 90
|
|
182
199
|
* @findings Medium: id-stability across edits (ids not renumbered on survive)
|
|
@@ -191,9 +208,9 @@ export declare function updateMenuTree(required: UpdateMenuTreeRequired, optiona
|
|
|
191
208
|
export interface AssignLocationDeps {
|
|
192
209
|
repo: MenuRepoPort;
|
|
193
210
|
bindingRepo: NavLocationBindingRepoPort;
|
|
194
|
-
clock:
|
|
211
|
+
clock: Clock;
|
|
195
212
|
/** Not previously present on this deps bag — needed to mint outbox event ids. */
|
|
196
|
-
idGen:
|
|
213
|
+
idGen: IdGenerator;
|
|
197
214
|
/** Enqueues `navigation.location.assigned` (+ `.unassigned` on reassignment). */
|
|
198
215
|
outbox: OutboxPort;
|
|
199
216
|
}
|
|
@@ -229,7 +246,7 @@ export interface AssignLocationOptional {
|
|
|
229
246
|
* transaction machinery — do not copy this sequencing pattern into code that
|
|
230
247
|
* has real transactions available.
|
|
231
248
|
*
|
|
232
|
-
* @complexity O
|
|
249
|
+
* @complexity O repo calls (bounded: at most two menu reads/writes plus one
|
|
233
250
|
* binding upsert), independent of workspace size.
|
|
234
251
|
* @overallScore 90
|
|
235
252
|
* @findings Medium: no rollback across the two writes (menu save, then
|
|
@@ -246,9 +263,9 @@ export declare function assignLocation(required: AssignLocationRequired, _option
|
|
|
246
263
|
export interface DeleteMenuDeps {
|
|
247
264
|
repo: MenuRepoPort;
|
|
248
265
|
bindingRepo: NavLocationBindingRepoPort;
|
|
249
|
-
clock:
|
|
266
|
+
clock: Clock;
|
|
250
267
|
/** Not previously present on this deps bag — needed to mint outbox event ids. */
|
|
251
|
-
idGen:
|
|
268
|
+
idGen: IdGenerator;
|
|
252
269
|
/** Enqueues `navigation.menu.updated` (trash) or `navigation.menu.deleted` (purge); nothing on a blocked purge. */
|
|
253
270
|
outbox: OutboxPort;
|
|
254
271
|
}
|
|
@@ -267,17 +284,17 @@ export interface DeleteMenuOptional {
|
|
|
267
284
|
/**
|
|
268
285
|
* Deletion ladder (mirrors the media library's):
|
|
269
286
|
* 1. First call on a non-trashed menu **soft-deletes** it (`status: 'trash'`,
|
|
270
|
-
*
|
|
271
|
-
* 2. A second call on an already-trashed menu attempts the **hard purge
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
287
|
+
* revisioned) and returns — no purge yet.
|
|
288
|
+
* 2. A second call on an already-trashed menu attempts the **hard purge** If
|
|
289
|
+
* the menu is still bound to any location, purge is rejected with
|
|
290
|
+
* `MenuLocationBoundError` (409-style) listing the bound keys, unless
|
|
291
|
+
* `force` is set — permission-gating that error behind
|
|
292
|
+
* `navigation.delete.force` is the caller's (gateway's) job, not this
|
|
293
|
+
* function's; this function only enforces the *shape* of the guard.
|
|
277
294
|
* 3. On a successful purge, the menu row and all of its location bindings are
|
|
278
|
-
*
|
|
295
|
+
* removed.
|
|
279
296
|
*
|
|
280
|
-
* @complexity O
|
|
297
|
+
* @complexity O repo calls; O(k) bindings scanned where k = locations this
|
|
281
298
|
* menu holds (small, bounded by registered locations).
|
|
282
299
|
* @overallScore 100
|
|
283
300
|
*/
|