@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,69 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @file The Taxonomy agent-tool catalog — this domain's instance of the per-domain
|
|
3
|
-
* `agent-tools.ts` convention `features/content-types/agent-tools.ts`,
|
|
4
|
-
* `features/database/agent-tools.ts`, and every other domain catalog already use.
|
|
5
|
-
*
|
|
6
|
-
* Purpose:
|
|
7
|
-
* A static, in-process catalog describing every agent-callable tool this domain exposes. Every
|
|
8
|
-
* WRITE entry maps 1:1 onto a real exported function of `features/taxonomy/write-service.ts`
|
|
9
|
-
* (`createTaxonomy`, `createTerm`, `renameTerm`, `assignTerms`); the one read maps onto
|
|
10
|
-
* `features/taxonomy/list.ts`'s `listTaxonomiesWithTerms`.
|
|
11
|
-
*
|
|
12
|
-
* `mergeTerm` (`merge-term.ts`) — read carefully, treated with the same scrutiny Database's
|
|
13
|
-
* `migrate-forward` and Recovery's `restore` ceremonies got:
|
|
14
|
-
* Merge is destructive and can silently lose pre-merge `entry_terms` assignment history for content
|
|
15
|
-
* already assigned to both terms (`merge-term.ts`'s own file header: "Destructive term
|
|
16
|
-
* merge" failure mode). That is why it alone, of every taxonomy mutation, gets a plan/confirm/
|
|
17
|
-
* execute ceremony through `core/gated-mutations` rather than an ordinary authorize-then-write.
|
|
18
|
-
* Reading `core/gated-mutations/gateway.ts` directly settles what is and is not safe to hand an
|
|
19
|
-
* agent:
|
|
20
|
-
* - `plan()` "Never invokes `hooks.executeMutation()` — a plan is read-only by construction
|
|
21
|
-
* (AC-10)" (`gateway.ts`'s own doc comment). It authorizes `admin.taxonomy.manage`, recomputes
|
|
22
|
-
* the live overlap-loss disclosure, and returns a plan. Persists nothing. Safe to wire as a
|
|
23
|
-
* READ, mirroring `features/database/agent-tools.ts`'s identical `database_plan_migrate_forward`
|
|
24
|
-
* precedent (same file's own comment: "the step that actually redeems a plan into a mutation
|
|
25
|
-
* (confirm()) can never be reached by an agent principal at all").
|
|
26
|
-
* - `confirm()` structurally refuses an agent: `gateway.ts`'s own body — "if (principalKind ===
|
|
27
|
-
* 'agent') throw new ForbiddenError('agent principals may not confirm a gated mutation', ...)"
|
|
28
|
-
* — before any permission check even runs. No `taxonomy_confirm_merge_term`-equivalent tool
|
|
29
|
-
* exists in this catalog.
|
|
30
|
-
* - `taxonomy_execute_merge_term` (2026-09-24) asks the human in chat before it runs: the host
|
|
31
|
-
* wires it with the kit's `humanConfirmedHandler`, which shows a confirm dialog and only on the
|
|
32
|
-
* human's own click confirms as that human (`kind='user'`) and executes as the agent acting for
|
|
33
|
-
* them — the `confirmer-must-equal-own-delegatedBy` rule. The model never sees or supplies a
|
|
34
|
-
* token. A merge deletes the source term's assignments with no Trash or undo, so it is gated.
|
|
35
|
-
*
|
|
36
|
-
* Naming: `taxonomy_*`, matching this package's own name — distinct from `features/content-types`'
|
|
37
|
-
* `collections_*` prefix (a different pairing) and from `features/entries`' own
|
|
38
|
-
* `collections_entry_*` prefix.
|
|
39
|
-
*
|
|
40
|
-
* How it relates to the project:
|
|
41
|
-
* `features/taxonomy/tool-registrations.ts` maps these entries into `@jini-ai/core`
|
|
42
|
-
* `ToolRegistration`s.
|
|
43
|
-
*
|
|
44
|
-
* Architectural role:
|
|
45
|
-
* `features/taxonomy` domain declaration. As of A2 (taxonomy plan) it imports nothing from its own
|
|
46
|
-
* `write-service.ts` — `contentType` is published as an open string (see `CONTENT_TYPE_SCHEMA`
|
|
47
|
-
* below), since Collections entries widened the set of legal values past the fixed `post`/`page`
|
|
48
|
-
* allow-list this file used to mirror as an `enum`.
|
|
49
|
-
*/
|
|
50
|
-
export type AgentToolSideEffect = "none" | "mutates-durable-state" | "mints-token";
|
|
51
|
-
export type AgentToolActorClassRule = "confirmer-must-equal-own-delegatedBy" | "user-only" | "none";
|
|
52
|
-
export interface AgentToolDefinition {
|
|
53
|
-
name: string;
|
|
54
|
-
description: string;
|
|
55
|
-
sideEffects: AgentToolSideEffect;
|
|
56
|
-
authorization: {
|
|
57
|
-
permission: string;
|
|
58
|
-
};
|
|
59
|
-
actorClassRule?: AgentToolActorClassRule;
|
|
60
|
-
/**
|
|
61
|
-
* JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
|
|
62
|
-
* (`assistant/tool-registration-kit.ts`'s `buildDomainRegistrations`, which refuses to wire any
|
|
63
|
-
* tool lacking one).
|
|
64
|
-
*/
|
|
65
|
-
inputSchema?: Readonly<Record<string, unknown>>;
|
|
66
|
-
}
|
|
1
|
+
import type { AgentToolDefinition } from "@jini-ai/core";
|
|
67
2
|
/** The Taxonomy domain's fixed agent-tool catalog: 7 wired (1 read, 5 ordinary writes, 1 gated-plan
|
|
68
3
|
* read) + 1 declared-but-never-wired destructive tool — see this file's header for the full
|
|
69
4
|
* `mergeTerm` safety analysis. */
|
|
@@ -17,21 +17,21 @@
|
|
|
17
17
|
* execute ceremony through `core/gated-mutations` rather than an ordinary authorize-then-write.
|
|
18
18
|
* Reading `core/gated-mutations/gateway.ts` directly settles what is and is not safe to hand an
|
|
19
19
|
* agent:
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
20
|
+
* - `plan` "Never invokes `hooks.executeMutation` — a plan is read-only by construction
|
|
21
|
+
* " (`gateway.ts`'s own doc comment). It authorizes `admin.taxonomy.manage`, recomputes
|
|
22
|
+
* the live overlap-loss disclosure, and returns a plan. Persists nothing. Safe to wire as a
|
|
23
|
+
* READ, mirroring `features/database/agent-tools.ts`'s identical `database_plan_migrate_forward`
|
|
24
|
+
* precedent (same file's own comment: "the step that actually redeems a plan into a mutation
|
|
25
|
+
* (confirm) can never be reached by an agent principal at all").
|
|
26
|
+
* - `confirm` structurally refuses an agent: `gateway.ts`'s own body — "if (principalKind ===
|
|
27
|
+
* 'agent') throw new ForbiddenError('agent principals may not confirm a gated mutation',...)"
|
|
28
|
+
* — before any permission check even runs. No `taxonomy_confirm_merge_term`-equivalent tool
|
|
29
|
+
* exists in this catalog.
|
|
30
|
+
* - `taxonomy_execute_merge_term` (2026-09-24) asks the human in chat before it runs: the host
|
|
31
|
+
* wires it with the kit's `humanConfirmedHandler`, which shows a confirm dialog and only on the
|
|
32
|
+
* human's own click confirms as that human (`kind='user'`) and executes as the agent acting for
|
|
33
|
+
* them — the `confirmer-must-equal-own-delegatedBy` rule. The model never sees or supplies a
|
|
34
|
+
* token. A merge deletes the source term's assignments with no Trash or undo, so it is gated.
|
|
35
35
|
*
|
|
36
36
|
* Naming: `taxonomy_*`, matching this package's own name — distinct from `features/content-types`'
|
|
37
37
|
* `collections_*` prefix (a different pairing) and from `features/entries`' own
|
|
@@ -46,7 +46,17 @@
|
|
|
46
46
|
* `write-service.ts` — `contentType` is published as an open string (see `CONTENT_TYPE_SCHEMA`
|
|
47
47
|
* below), since Collections entries widened the set of legal values past the fixed `post`/`page`
|
|
48
48
|
* allow-list this file used to mirror as an `enum`.
|
|
49
|
+
* See docs/decisions/DR-005-ordered-taxonomy-validation.md.
|
|
49
50
|
*/
|
|
51
|
+
// A2 (taxonomy plan) — no longer imported: `CONTENT_TYPE_SCHEMA` used to build its `enum` from
|
|
52
|
+
// this set, which would reject a Collection key (any `contentType` other than `post`/`page`) at
|
|
53
|
+
// the agent's own input-schema validation, before the write-service's `contentTypeTaxonomyPolicy`
|
|
54
|
+
// ever gets a chance to decide eligibility. See `CONTENT_TYPE_SCHEMA`'s doc comment below.
|
|
55
|
+
/**
|
|
56
|
+
* JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
|
|
57
|
+
* (`@jini-ai/core`'s `registration-kit.ts`'s `buildDomainRegistrations`, which refuses to wire any
|
|
58
|
+
* tool lacking one).
|
|
59
|
+
*/
|
|
50
60
|
const TAXONOMY_ID_SCHEMA = {
|
|
51
61
|
type: "string",
|
|
52
62
|
minLength: 1,
|
|
@@ -40,7 +40,7 @@ export function createContentLookup(deps) {
|
|
|
40
40
|
const entryLookup = createEntryBackedContentLookup({ entryRepo: deps.entryRepo, workspaceId: deps.workspaceId });
|
|
41
41
|
return {
|
|
42
42
|
async resolve(params) {
|
|
43
|
-
return isContentTypeOnAllowList(params.contentType) ? postLookup.resolve(params) : entryLookup.resolve(params);
|
|
43
|
+
return isContentTypeOnAllowList({ contentType: params.contentType }) ? postLookup.resolve(params) : entryLookup.resolve(params);
|
|
44
44
|
},
|
|
45
45
|
};
|
|
46
46
|
}
|
package/dist/taxonomy/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* has no imports at all: the ceremony is a parameter, not a dependency.
|
|
20
20
|
*/
|
|
21
21
|
export { TaxonomyNotApplicableError, WorkspaceMismatchError, ContentTypeMismatchError, TaxonomyNotHierarchicalError, ParentCrossTaxonomyError, TermNotFoundError, HierarchyCycleDetectedError, wouldCreateCycle, validateContentJoin, validateHierarchyAssignment, type TermTreeLookup, } from "./validation-chain.js";
|
|
22
|
-
export { TAXONOMY_ALLOWED_CONTENT_TYPES, isContentTypeOnAllowList, TaxonomyRecordNotFoundError, TermRecordNotFoundError, ContentRecordNotFoundError, TermHasAssignedContentError, TermHasChildTermsError, TaxonomyHasAssignedContentError, TaxonomyVersionConflictError, createTaxonomy, createTerm, renameTerm, assignTerms, unassignTerms, deleteTerm, deleteTaxonomy, onContentDeleted, importTaxonomy, importTerm, type AuthorizeFn, type Taxonomy, type Term, type TaxonomyRepoPort, type TermRepoPort, type EntryTermRepoPort, type ContentLookupPort, type ContentTypeTaxonomyPolicyPort, type UnassignableEntryTermRepoPort, type TaxonomyRevisionRow, type TaxonomyRevisionRepoPort, type
|
|
22
|
+
export { TAXONOMY_ALLOWED_CONTENT_TYPES, isContentTypeOnAllowList, TaxonomyRecordNotFoundError, TermRecordNotFoundError, ContentRecordNotFoundError, TermHasAssignedContentError, TermHasChildTermsError, TaxonomyHasAssignedContentError, TaxonomyVersionConflictError, createTaxonomy, createTerm, renameTerm, assignTerms, unassignTerms, deleteTerm, deleteTaxonomy, onContentDeleted, importTaxonomy, importTerm, type AuthorizeFn, type Taxonomy, type Term, type TaxonomyRepoPort, type TermRepoPort, type EntryTermRepoPort, type ContentLookupPort, type ContentTypeTaxonomyPolicyPort, type UnassignableEntryTermRepoPort, type TaxonomyRevisionRow, type TaxonomyRevisionRepoPort, type WriteServiceDeps, type CreateTaxonomyRequired, type CreateTermRequired, type CreateTermOptional, type RenameTermRequired, type AssignTermsRequired, type UnassignTermsRequired, type DeleteTermRequired, type DeleteTaxonomyRequired, type DeletableTaxonomyRepoPort, type DeletableTermRepoPort, type AssignmentCountEntryTermRepoPort, type TransactionalRepoPort, type EntryTermsCleanupPort, type OnContentDeletedRequired, type ImportableTaxonomyRepoPort, type ImportableTermRepoPort, type ImportTaxonomyRequired, type ImportTermRequired, type ImportTermOptional, } from "./write-service.js";
|
|
23
23
|
export { listTaxonomiesWithTerms, type TaxonomyListPort, type TermListPort, type TaxonomyWithTerms, } from "./list.js";
|
|
24
24
|
/**
|
|
25
25
|
* The domain half of the `mergeTerm` ceremony — see this file's header for why the gateway itself
|
|
@@ -34,5 +34,5 @@ export { InMemoryTaxonomyRepo, InMemoryTermRepo, InMemoryEntryTermRepo, InMemory
|
|
|
34
34
|
*/
|
|
35
35
|
export { createPostBackedContentLookup, createEntryBackedContentLookup, createContentLookup, type ContentRecordLookupPort, type EntryRecordLookupPort, } from "./content-lookup.js";
|
|
36
36
|
/** The agent-tool surface for this domain (see `agent-tools.ts` for what is deliberately omitted). */
|
|
37
|
-
export { taxonomyAgentToolCatalog,
|
|
37
|
+
export { taxonomyAgentToolCatalog, } from "./agent-tools.js";
|
|
38
38
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
* enforced by `merge-term.unit.test.ts`'s own export-surface inspection.
|
|
18
18
|
*/
|
|
19
19
|
export declare class SameTermMergeError extends Error {
|
|
20
|
-
constructor(
|
|
20
|
+
constructor(requiredArgs: {
|
|
21
|
+
message: string;
|
|
22
|
+
}, optionalArgs?: Record<string, never>);
|
|
21
23
|
}
|
|
22
24
|
export interface MergeTermPlanDetails {
|
|
23
25
|
fromTermId: string;
|
|
@@ -43,13 +45,14 @@ export interface PlanMergeTermRequired {
|
|
|
43
45
|
}>;
|
|
44
46
|
}
|
|
45
47
|
/**
|
|
46
|
-
*
|
|
47
|
-
* `computeOverlap
|
|
48
|
-
*
|
|
48
|
+
* — rejects `fromTermId === intoTermId` structurally BEFORE
|
|
49
|
+
* `computeOverlap` ever runs (no plan, therefore no token, can ever exist for a self-merge).
|
|
50
|
+
* — the returned plan discloses whether the merge would lose any pre-existing
|
|
49
51
|
* overlapping assignment (never a false "no loss" when `overlappingContentCount > 0`).
|
|
50
52
|
*
|
|
51
53
|
* @complexity O(1) plus the caller-supplied `computeOverlap`/`gatewayPlan` costs.
|
|
52
54
|
* @overallScore 100
|
|
55
|
+
* See docs/decisions/DR-005-ordered-taxonomy-validation.md.
|
|
53
56
|
*/
|
|
54
57
|
export declare function planMergeTerm(required: PlanMergeTermRequired, _optional?: Record<string, never>): Promise<{
|
|
55
58
|
planId: string;
|
|
@@ -17,24 +17,26 @@
|
|
|
17
17
|
* enforced by `merge-term.unit.test.ts`'s own export-surface inspection.
|
|
18
18
|
*/
|
|
19
19
|
export class SameTermMergeError extends Error {
|
|
20
|
-
constructor(
|
|
20
|
+
constructor(requiredArgs, optionalArgs = {}) {
|
|
21
|
+
const { message } = requiredArgs;
|
|
21
22
|
super(message);
|
|
22
23
|
this.name = "SameTermMergeError";
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
26
|
-
*
|
|
27
|
-
* `computeOverlap
|
|
28
|
-
*
|
|
27
|
+
* — rejects `fromTermId === intoTermId` structurally BEFORE
|
|
28
|
+
* `computeOverlap` ever runs (no plan, therefore no token, can ever exist for a self-merge).
|
|
29
|
+
* — the returned plan discloses whether the merge would lose any pre-existing
|
|
29
30
|
* overlapping assignment (never a false "no loss" when `overlappingContentCount > 0`).
|
|
30
31
|
*
|
|
31
32
|
* @complexity O(1) plus the caller-supplied `computeOverlap`/`gatewayPlan` costs.
|
|
32
33
|
* @overallScore 100
|
|
34
|
+
* See docs/decisions/DR-005-ordered-taxonomy-validation.md.
|
|
33
35
|
*/
|
|
34
36
|
export async function planMergeTerm(required, _optional = {}) {
|
|
35
37
|
const { fromTermId, intoTermId, computeOverlap, gatewayPlan } = required;
|
|
36
38
|
if (fromTermId === intoTermId) {
|
|
37
|
-
throw new SameTermMergeError(`cannot merge term '${fromTermId}' into itself`);
|
|
39
|
+
throw new SameTermMergeError({ message: `cannot merge term '${fromTermId}' into itself` });
|
|
38
40
|
}
|
|
39
41
|
const { overlappingContentCount } = await computeOverlap();
|
|
40
42
|
const details = {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Clock } from "@jini-ai/core/primitives";
|
|
1
2
|
import type { ContentLookupPort, EntryTermRepoPort, TaxonomyRepoPort, TaxonomyRevisionRepoPort, TaxonomyRevisionRow, Term, TermRepoPort, UnassignableEntryTermRepoPort } from "./write-service.js";
|
|
2
3
|
import type { Taxonomy } from "./write-service.js";
|
|
3
4
|
import type { TaxonomyListPort, TermListPort } from "./list.js";
|
|
@@ -8,20 +9,26 @@ import type { TaxonomyListPort, TermListPort } from "./list.js";
|
|
|
8
9
|
export declare class InMemoryTaxonomyRepo implements TaxonomyRepoPort, TaxonomyListPort {
|
|
9
10
|
private readonly rows;
|
|
10
11
|
insert(row: Taxonomy): Promise<unknown>;
|
|
11
|
-
findById(id
|
|
12
|
+
findById({ id }: {
|
|
13
|
+
id: string;
|
|
14
|
+
}): Promise<{
|
|
12
15
|
id: string;
|
|
13
16
|
hierarchical: boolean;
|
|
14
17
|
allowList?: string[] | undefined;
|
|
15
18
|
} | null>;
|
|
16
19
|
/** `ImportableTaxonomyRepoPort` — additive capability for `importTaxonomy`'s CAS check and
|
|
17
20
|
* update-in-place, see `write-service.ts`'s doc comment on that interface. */
|
|
18
|
-
findByIdFull(id
|
|
21
|
+
findByIdFull({ id }: {
|
|
22
|
+
id: string;
|
|
23
|
+
}): Promise<Taxonomy | null>;
|
|
19
24
|
/** `ImportableTaxonomyRepoPort` — writes an existing row back in place, preserving its id. */
|
|
20
25
|
update(row: Taxonomy): Promise<unknown>;
|
|
21
26
|
list(): Promise<Taxonomy[]>;
|
|
22
27
|
/** `DeletableTaxonomyRepoPort` — additive capability for `deleteTaxonomy`, see
|
|
23
28
|
* `write-service.ts`'s doc comment on that interface. */
|
|
24
|
-
delete(id
|
|
29
|
+
delete({ id }: {
|
|
30
|
+
id: string;
|
|
31
|
+
}): Promise<void>;
|
|
25
32
|
/**
|
|
26
33
|
* `TransactionalRepoPort` — disclosed narrowing, not a silently-wrong implementation of a real
|
|
27
34
|
* capability (same disclosure style as `noopStampWatermark` below): a plain in-process `Map` has
|
|
@@ -38,30 +45,40 @@ export declare class InMemoryTaxonomyRepo implements TaxonomyRepoPort, TaxonomyL
|
|
|
38
45
|
* app.ts`'s hermetic composition), never the host of a real workspace's real content, which is
|
|
39
46
|
* why this gap is accepted here rather than closed.
|
|
40
47
|
*/
|
|
41
|
-
transaction<T>(fn
|
|
48
|
+
transaction<T>({ fn }: {
|
|
49
|
+
fn: () => Promise<T>;
|
|
50
|
+
}): Promise<T>;
|
|
42
51
|
}
|
|
43
52
|
export declare class InMemoryTermRepo implements TermRepoPort, TermListPort {
|
|
44
53
|
private readonly rows;
|
|
45
54
|
insert(row: Term): Promise<unknown>;
|
|
46
55
|
update(row: Term): Promise<unknown>;
|
|
47
|
-
findById(id
|
|
56
|
+
findById({ id }: {
|
|
57
|
+
id: string;
|
|
58
|
+
}): Promise<{
|
|
48
59
|
id: string;
|
|
49
60
|
taxonomyId: string;
|
|
50
61
|
name?: string | undefined;
|
|
51
62
|
} | null>;
|
|
52
63
|
/** `ImportableTermRepoPort` — additive capability for `importTerm`'s CAS check, see
|
|
53
64
|
* `write-service.ts`'s doc comment on that interface. */
|
|
54
|
-
findByIdFull(id
|
|
65
|
+
findByIdFull({ id }: {
|
|
66
|
+
id: string;
|
|
67
|
+
}): Promise<Term | null>;
|
|
55
68
|
listByTaxonomy(params: {
|
|
56
69
|
taxonomyId: string;
|
|
57
70
|
}): Promise<Term[]>;
|
|
58
71
|
/** Ancestor-chain lookup for `validation-chain.ts`'s `wouldCreateCycle` — not required by any
|
|
59
72
|
* currently-wired route (reparent has no route this pass, design-spec.md §2.8), kept here so a
|
|
60
73
|
* future reparent route has a ready-made `TermTreeLookup` to inject. */
|
|
61
|
-
getParentId(termId
|
|
74
|
+
getParentId({ termId }: {
|
|
75
|
+
termId: string;
|
|
76
|
+
}): string | null;
|
|
62
77
|
/** `DeletableTermRepoPort` — additive capability for `deleteTerm`/`deleteTaxonomy`, see
|
|
63
78
|
* `write-service.ts`'s doc comment on that interface. */
|
|
64
|
-
delete(id
|
|
79
|
+
delete({ id }: {
|
|
80
|
+
id: string;
|
|
81
|
+
}): Promise<void>;
|
|
65
82
|
/** `DeletableTermRepoPort.countChildren` — direct children only (one level), matching
|
|
66
83
|
* `deleteTerm`'s guard (it does not recurse past the first level; a grandchild whose direct
|
|
67
84
|
* parent is itself already blocked from deletion is caught when that intermediate term's own
|
|
@@ -124,15 +141,21 @@ export declare class InMemoryTaxonomyRevisionRepo implements TaxonomyRevisionRep
|
|
|
124
141
|
*/
|
|
125
142
|
export declare class InMemoryContentLookup implements ContentLookupPort {
|
|
126
143
|
private readonly rows;
|
|
127
|
-
constructor(
|
|
144
|
+
constructor(requiredArgs: Record<string, never>, optionalArgs?: {
|
|
145
|
+
seed?: Array<{
|
|
146
|
+
contentType: string;
|
|
147
|
+
contentId: string;
|
|
148
|
+
workspaceId: string;
|
|
149
|
+
kind: string;
|
|
150
|
+
}>;
|
|
151
|
+
});
|
|
152
|
+
set({ contentType, contentId, value }: {
|
|
128
153
|
contentType: string;
|
|
129
154
|
contentId: string;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
workspaceId: string;
|
|
135
|
-
kind: string;
|
|
155
|
+
value: {
|
|
156
|
+
workspaceId: string;
|
|
157
|
+
kind: string;
|
|
158
|
+
};
|
|
136
159
|
}): void;
|
|
137
160
|
resolve(params: {
|
|
138
161
|
contentType: string;
|
|
@@ -161,9 +184,7 @@ export declare function toTaxonomyOutbox(deps: {
|
|
|
161
184
|
payload: Record<string, unknown>;
|
|
162
185
|
}): Promise<void>;
|
|
163
186
|
};
|
|
164
|
-
clock:
|
|
165
|
-
nowIso(): string;
|
|
166
|
-
};
|
|
187
|
+
clock: Clock;
|
|
167
188
|
idGen: {
|
|
168
189
|
newId(): string;
|
|
169
190
|
};
|
|
@@ -172,6 +193,8 @@ export declare function toTaxonomyOutbox(deps: {
|
|
|
172
193
|
* (`{name, taxonomyId, actorId, occurredAt}`) carry no `workspaceId` at all. */
|
|
173
194
|
workspaceId: string;
|
|
174
195
|
}): {
|
|
175
|
-
enqueue: (event:
|
|
196
|
+
enqueue: ({ event }: {
|
|
197
|
+
event: unknown;
|
|
198
|
+
}) => Promise<void>;
|
|
176
199
|
};
|
|
177
200
|
//# sourceMappingURL=repo.memory.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowIso as kernelNowIso } from "@jini-ai/core/primitives";
|
|
1
2
|
/**
|
|
2
3
|
* @file In-memory adapters for the `taxonomy` package's write/list ports — same disclosed
|
|
3
4
|
* rule-of-two-until-a-real-adapter-exists precedent as `features/content-types/repo.memory.ts`.
|
|
@@ -8,13 +9,13 @@ export class InMemoryTaxonomyRepo {
|
|
|
8
9
|
this.rows.set(row.id, { ...row });
|
|
9
10
|
return row;
|
|
10
11
|
}
|
|
11
|
-
async findById(id) {
|
|
12
|
+
async findById({ id }) {
|
|
12
13
|
const row = this.rows.get(id);
|
|
13
14
|
return row ? { id: row.id, hierarchical: row.hierarchical } : null;
|
|
14
15
|
}
|
|
15
16
|
/** `ImportableTaxonomyRepoPort` — additive capability for `importTaxonomy`'s CAS check and
|
|
16
17
|
* update-in-place, see `write-service.ts`'s doc comment on that interface. */
|
|
17
|
-
async findByIdFull(id) {
|
|
18
|
+
async findByIdFull({ id }) {
|
|
18
19
|
const row = this.rows.get(id);
|
|
19
20
|
return row ? { ...row } : null;
|
|
20
21
|
}
|
|
@@ -28,7 +29,7 @@ export class InMemoryTaxonomyRepo {
|
|
|
28
29
|
}
|
|
29
30
|
/** `DeletableTaxonomyRepoPort` — additive capability for `deleteTaxonomy`, see
|
|
30
31
|
* `write-service.ts`'s doc comment on that interface. */
|
|
31
|
-
async delete(id) {
|
|
32
|
+
async delete({ id }) {
|
|
32
33
|
this.rows.delete(id);
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
@@ -47,7 +48,7 @@ export class InMemoryTaxonomyRepo {
|
|
|
47
48
|
* app.ts`'s hermetic composition), never the host of a real workspace's real content, which is
|
|
48
49
|
* why this gap is accepted here rather than closed.
|
|
49
50
|
*/
|
|
50
|
-
async transaction(fn) {
|
|
51
|
+
async transaction({ fn }) {
|
|
51
52
|
return fn();
|
|
52
53
|
}
|
|
53
54
|
}
|
|
@@ -61,13 +62,13 @@ export class InMemoryTermRepo {
|
|
|
61
62
|
this.rows.set(row.id, { ...row });
|
|
62
63
|
return row;
|
|
63
64
|
}
|
|
64
|
-
async findById(id) {
|
|
65
|
+
async findById({ id }) {
|
|
65
66
|
const row = this.rows.get(id);
|
|
66
67
|
return row ? { id: row.id, taxonomyId: row.taxonomyId, name: row.name } : null;
|
|
67
68
|
}
|
|
68
69
|
/** `ImportableTermRepoPort` — additive capability for `importTerm`'s CAS check, see
|
|
69
70
|
* `write-service.ts`'s doc comment on that interface. */
|
|
70
|
-
async findByIdFull(id) {
|
|
71
|
+
async findByIdFull({ id }) {
|
|
71
72
|
const row = this.rows.get(id);
|
|
72
73
|
return row ? { ...row } : null;
|
|
73
74
|
}
|
|
@@ -77,12 +78,12 @@ export class InMemoryTermRepo {
|
|
|
77
78
|
/** Ancestor-chain lookup for `validation-chain.ts`'s `wouldCreateCycle` — not required by any
|
|
78
79
|
* currently-wired route (reparent has no route this pass, design-spec.md §2.8), kept here so a
|
|
79
80
|
* future reparent route has a ready-made `TermTreeLookup` to inject. */
|
|
80
|
-
getParentId(termId) {
|
|
81
|
+
getParentId({ termId }) {
|
|
81
82
|
return this.rows.get(termId)?.parentId ?? null;
|
|
82
83
|
}
|
|
83
84
|
/** `DeletableTermRepoPort` — additive capability for `deleteTerm`/`deleteTaxonomy`, see
|
|
84
85
|
* `write-service.ts`'s doc comment on that interface. */
|
|
85
|
-
async delete(id) {
|
|
86
|
+
async delete({ id }) {
|
|
86
87
|
this.rows.delete(id);
|
|
87
88
|
}
|
|
88
89
|
/** `DeletableTermRepoPort.countChildren` — direct children only (one level), matching
|
|
@@ -167,10 +168,11 @@ export class InMemoryTaxonomyRevisionRepo {
|
|
|
167
168
|
*/
|
|
168
169
|
export class InMemoryContentLookup {
|
|
169
170
|
rows;
|
|
170
|
-
constructor(
|
|
171
|
+
constructor(requiredArgs, optionalArgs = {}) {
|
|
172
|
+
const { seed = [] } = optionalArgs;
|
|
171
173
|
this.rows = new Map(seed.map((s) => [`${s.contentType}::${s.contentId}`, { workspaceId: s.workspaceId, kind: s.kind }]));
|
|
172
174
|
}
|
|
173
|
-
set(contentType, contentId, value) {
|
|
175
|
+
set({ contentType, contentId, value }) {
|
|
174
176
|
this.rows.set(`${contentType}::${contentId}`, value);
|
|
175
177
|
}
|
|
176
178
|
async resolve(params) {
|
|
@@ -188,10 +190,10 @@ export function noopStampWatermark() { }
|
|
|
188
190
|
* shape), so this wrapper forwards them as the full event payload rather than re-nesting. */
|
|
189
191
|
export function toTaxonomyOutbox(deps) {
|
|
190
192
|
return {
|
|
191
|
-
enqueue: async (event) => {
|
|
193
|
+
enqueue: async ({ event }) => {
|
|
192
194
|
const record = event;
|
|
193
195
|
const name = typeof record.name === "string" ? record.name : "taxonomy.event";
|
|
194
|
-
const occurredAt = typeof record.occurredAt === "string" ? record.occurredAt : deps.clock
|
|
196
|
+
const occurredAt = typeof record.occurredAt === "string" ? record.occurredAt : kernelNowIso({ clock: deps.clock });
|
|
195
197
|
await deps.outbox.enqueue({ id: deps.idGen.newId(), workspaceId: deps.workspaceId, name, occurredAt, payload: record });
|
|
196
198
|
},
|
|
197
199
|
};
|
|
@@ -25,35 +25,51 @@
|
|
|
25
25
|
* their own repo lookups, so the ordering guarantee holds regardless of how a caller wires them.
|
|
26
26
|
*/
|
|
27
27
|
export declare class TaxonomyNotApplicableError extends Error {
|
|
28
|
-
constructor(
|
|
28
|
+
constructor(requiredArgs: {
|
|
29
|
+
message: string;
|
|
30
|
+
}, optionalArgs?: Record<string, never>);
|
|
29
31
|
}
|
|
30
32
|
export declare class WorkspaceMismatchError extends Error {
|
|
31
|
-
constructor(
|
|
33
|
+
constructor(requiredArgs: {
|
|
34
|
+
message: string;
|
|
35
|
+
}, optionalArgs?: Record<string, never>);
|
|
32
36
|
}
|
|
33
37
|
export declare class ContentTypeMismatchError extends Error {
|
|
34
|
-
constructor(
|
|
38
|
+
constructor(requiredArgs: {
|
|
39
|
+
message: string;
|
|
40
|
+
}, optionalArgs?: Record<string, never>);
|
|
35
41
|
}
|
|
36
42
|
export declare class TaxonomyNotHierarchicalError extends Error {
|
|
37
|
-
constructor(
|
|
43
|
+
constructor(requiredArgs: {
|
|
44
|
+
message: string;
|
|
45
|
+
}, optionalArgs?: Record<string, never>);
|
|
38
46
|
}
|
|
39
47
|
export declare class ParentCrossTaxonomyError extends Error {
|
|
40
|
-
constructor(
|
|
48
|
+
constructor(requiredArgs: {
|
|
49
|
+
message: string;
|
|
50
|
+
}, optionalArgs?: Record<string, never>);
|
|
41
51
|
}
|
|
42
52
|
export declare class TermNotFoundError extends Error {
|
|
43
|
-
constructor(
|
|
53
|
+
constructor(requiredArgs: {
|
|
54
|
+
message: string;
|
|
55
|
+
}, optionalArgs?: Record<string, never>);
|
|
44
56
|
}
|
|
45
57
|
export declare class HierarchyCycleDetectedError extends Error {
|
|
46
|
-
constructor(
|
|
58
|
+
constructor(requiredArgs: {
|
|
59
|
+
message: string;
|
|
60
|
+
}, optionalArgs?: Record<string, never>);
|
|
47
61
|
}
|
|
48
62
|
/** Ancestor-chain lookup a cycle check walks. `null` marks a root (no parent). */
|
|
49
63
|
export interface TermTreeLookup {
|
|
50
|
-
getParentId(termId
|
|
64
|
+
getParentId({ termId }: {
|
|
65
|
+
termId: string;
|
|
66
|
+
}): string | null;
|
|
51
67
|
}
|
|
52
68
|
/**
|
|
53
|
-
*
|
|
69
|
+
* — true if assigning `candidateParentId` as `termId`'s parent would create a cycle:
|
|
54
70
|
* either immediate self-parenting, or `termId` appearing anywhere in `candidateParentId`'s own
|
|
55
71
|
* ancestor chain. A full recursive walk, not a fixed-depth or immediate-parent-only comparison
|
|
56
|
-
*
|
|
72
|
+
* — the exact shape a naive implementation gets wrong (a 3+-hop cycle is the
|
|
57
73
|
* regression case this exists to catch).
|
|
58
74
|
*
|
|
59
75
|
* A `visited` guard bounds the walk even against a pre-existing malformed tree (defensive; no
|
|
@@ -62,6 +78,7 @@ export interface TermTreeLookup {
|
|
|
62
78
|
*
|
|
63
79
|
* @complexity O(depth) — one `getParentId` call per ancestor hop, each hop visited at most once.
|
|
64
80
|
* @overallScore 100
|
|
81
|
+
* See docs/decisions/DR-005-ordered-taxonomy-validation.md.
|
|
65
82
|
*/
|
|
66
83
|
export declare function wouldCreateCycle(required: {
|
|
67
84
|
termId: string;
|
|
@@ -69,13 +86,14 @@ export declare function wouldCreateCycle(required: {
|
|
|
69
86
|
tree: TermTreeLookup;
|
|
70
87
|
}, _optional?: Record<string, never>): boolean;
|
|
71
88
|
/**
|
|
72
|
-
*
|
|
73
|
-
* fixed order. A combined-failure case always reports the first-in-order failure (
|
|
74
|
-
* not-on-allow-list always wins over a simultaneous workspace mismatch;
|
|
89
|
+
* /ORD1/ORD2 — the content-join chain: allow-list, THEN workspace, THEN lens, in that
|
|
90
|
+
* fixed order. A combined-failure case always reports the first-in-order failure (:
|
|
91
|
+
* not-on-allow-list always wins over a simultaneous workspace mismatch; : a workspace
|
|
75
92
|
* mismatch always wins over a simultaneous lens mismatch).
|
|
76
93
|
*
|
|
77
94
|
* @complexity O(1) — three independent comparisons, no loop.
|
|
78
95
|
* @overallScore 100
|
|
96
|
+
* See docs/decisions/DR-005-ordered-taxonomy-validation.md.
|
|
79
97
|
*/
|
|
80
98
|
export declare function validateContentJoin(required: {
|
|
81
99
|
taxonomyId: string;
|
|
@@ -87,18 +105,19 @@ export declare function validateContentJoin(required: {
|
|
|
87
105
|
resolvedContentKind: string;
|
|
88
106
|
}, _optional?: Record<string, never>): void;
|
|
89
107
|
/**
|
|
90
|
-
*
|
|
108
|
+
* /B3/ORD3 — the hierarchy chain: hierarchical-mode, THEN same-taxonomy (distinguishing
|
|
91
109
|
* not-found from wrong-taxonomy), THEN cycle, in that fixed order. `null` `candidateParentId`
|
|
92
|
-
* (no parent assignment attempted) always short-circuits to a pass regardless of mode (
|
|
110
|
+
* (no parent assignment attempted) always short-circuits to a pass regardless of mode (
|
|
93
111
|
* regression: a no-op parent write must never be rejected).
|
|
94
112
|
*
|
|
95
|
-
* The compound
|
|
113
|
+
* The compound regression this chain exists to prevent: a flat taxonomy's candidate parent
|
|
96
114
|
* that ALSO happens to exist in a different taxonomy must report `TAXONOMY_NOT_HIERARCHICAL`,
|
|
97
115
|
* never `PARENT_CROSS_TAXONOMY` — hierarchical-mode is checked first and is decisive on its own.
|
|
98
116
|
*
|
|
99
|
-
* @complexity O(1) plus the injected `wouldCreateCycle` closure's own cost (
|
|
117
|
+
* @complexity O(1) plus the injected `wouldCreateCycle` closure's own cost (only reached
|
|
100
118
|
* once hierarchical-mode and same-taxonomy both pass).
|
|
101
119
|
* @overallScore 100
|
|
120
|
+
* See docs/decisions/DR-005-ordered-taxonomy-validation.md.
|
|
102
121
|
*/
|
|
103
122
|
export declare function validateHierarchyAssignment(required: {
|
|
104
123
|
childTaxonomyId: string;
|
|
@@ -108,7 +127,9 @@ export declare function validateHierarchyAssignment(required: {
|
|
|
108
127
|
id: string;
|
|
109
128
|
taxonomyId: string;
|
|
110
129
|
} | null | "not-applicable";
|
|
111
|
-
wouldCreateCycle: (
|
|
130
|
+
wouldCreateCycle: (required: {
|
|
131
|
+
candidateParentId: string;
|
|
132
|
+
}) => boolean;
|
|
112
133
|
termId: string;
|
|
113
134
|
}, _optional?: Record<string, never>): void;
|
|
114
135
|
//# sourceMappingURL=validation-chain.d.ts.map
|