@jini-ai/cms 0.4.1 → 0.5.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 +23 -0
- package/dist/content-types/lifecycle.d.ts +1 -1
- package/dist/content-types/lifecycle.js +6 -2
- package/dist/content-types/types.d.ts +11 -0
- package/dist/content-types/write-service.d.ts +6 -0
- package/dist/content-types/write-service.js +7 -0
- package/dist/entries/errors.d.ts +7 -0
- package/dist/entries/errors.js +6 -0
- package/dist/entries/field-validation.d.ts +3 -0
- package/dist/entries/index.d.ts +2 -2
- package/dist/entries/index.js +1 -1
- package/dist/entries/repo.memory.d.ts +2 -2
- package/dist/entries/repo.memory.js +10 -1
- package/dist/entries/types.d.ts +2 -0
- package/dist/entries/write-service.d.ts +19 -8
- package/dist/entries/write-service.js +88 -54
- package/dist/media/blob-store.fs.d.ts +4 -0
- package/dist/media/blob-store.fs.js +27 -0
- package/dist/media/blob-store.memory.d.ts +3 -0
- package/dist/media/blob-store.memory.js +3 -0
- package/dist/media/created-by.d.ts +15 -0
- package/dist/media/created-by.js +20 -0
- package/dist/media/index.d.ts +1 -0
- package/dist/media/index.js +1 -0
- package/dist/media/media-service.d.ts +1 -1
- package/dist/media/media-service.js +1 -0
- package/dist/media/ports.d.ts +12 -2
- package/dist/media/repo.memory.js +2 -1
- package/dist/media/tool-registrations.js +1 -0
- package/dist/media/types.d.ts +4 -0
- package/dist/navigation/index.d.ts +2 -2
- package/dist/navigation/index.js +2 -2
- package/dist/navigation/menu-service.d.ts +28 -16
- package/dist/navigation/menu-service.js +90 -65
- package/dist/navigation/repo.memory.d.ts +46 -2
- package/dist/navigation/repo.memory.js +28 -1
- package/dist/navigation/types.d.ts +5 -0
- package/dist/taxonomy/write-service.d.ts +4 -2
- package/dist/taxonomy/write-service.js +8 -3
- package/dist/trash/write-service.js +19 -12
- package/package.json +2 -2
|
@@ -408,7 +408,7 @@ export async function assignTerms(required, _optional = {}) {
|
|
|
408
408
|
* authorize -> validateAssignmentTarget -> write -> stamp -> outbox chokepoint as `assignTerms`,
|
|
409
409
|
* and — like `assignTerms` — never produces a `taxonomy_revisions` row ( disclosed
|
|
410
410
|
* narrowing applies equally to removal). Idempotent: unassigning a row that isn't there is a no-op,
|
|
411
|
-
* not an error
|
|
411
|
+
* not an error. Only removed ids are returned, stamped, and emitted; an entirely absent set is a no-op. Chosen over
|
|
412
412
|
* a "set terms" replace call — see the taxonomy plan's "What the docs settle" #3 for why replace
|
|
413
413
|
* risks silently erasing a concurrent assignment.
|
|
414
414
|
* See docs/decisions/DR-005-ordered-taxonomy-validation.md.
|
|
@@ -417,19 +417,24 @@ export async function unassignTerms(required, _optional = {}) {
|
|
|
417
417
|
const { deps, principalId, contentType, contentId, termIds } = required;
|
|
418
418
|
await authorizeTaxonomyManage(deps, principalId);
|
|
419
419
|
await validateAssignmentTarget(deps, contentType, contentId, termIds);
|
|
420
|
+
const removedTermIds = [];
|
|
420
421
|
for (const termId of termIds) {
|
|
421
|
-
await deps.entryTerms.remove({ contentType, contentId, termId })
|
|
422
|
+
if (await deps.entryTerms.remove({ contentType, contentId, termId }) > 0)
|
|
423
|
+
removedTermIds.push(termId);
|
|
422
424
|
}
|
|
425
|
+
if (removedTermIds.length === 0)
|
|
426
|
+
return { removedTermIds };
|
|
423
427
|
const now = kernelNowIso({ clock: deps.clock });
|
|
424
428
|
await deps.stampWatermark({});
|
|
425
429
|
await deps.outbox.enqueue({ event: {
|
|
426
430
|
name: "taxonomy.terms_unassigned",
|
|
427
431
|
contentType,
|
|
428
432
|
contentId,
|
|
429
|
-
termIds,
|
|
433
|
+
termIds: removedTermIds,
|
|
430
434
|
actorId: principalId,
|
|
431
435
|
occurredAt: now,
|
|
432
436
|
} });
|
|
437
|
+
return { removedTermIds };
|
|
433
438
|
}
|
|
434
439
|
/** Content-deletion event subscriber. Best-effort (a missed event leaves an orphaned
|
|
435
440
|
* `entry_terms` row that is inert on read; a periodic/boot reconciliation sweep — modeled by
|
|
@@ -95,12 +95,16 @@ export function createTrashService(deps, optional = {}) {
|
|
|
95
95
|
priorMarker: marker.priorMarker ?? trashOptional.priorMarker ?? null,
|
|
96
96
|
};
|
|
97
97
|
await deps.repo.insert({ row });
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
// A successful noop may repair a missing index, but did not change the domain marker.
|
|
99
|
+
// Repeated removal must not emit another recovery watermark or outbox event (F1487).
|
|
100
|
+
if (!marker.noop) {
|
|
101
|
+
await notifyChanged(optional, {
|
|
102
|
+
workspaceId: required.workspaceId,
|
|
103
|
+
entityType: required.entityType,
|
|
104
|
+
entityId: required.entityId,
|
|
105
|
+
change: "trash",
|
|
106
|
+
});
|
|
107
|
+
}
|
|
104
108
|
return marker;
|
|
105
109
|
}
|
|
106
110
|
});
|
|
@@ -135,12 +139,15 @@ export function createTrashService(deps, optional = {}) {
|
|
|
135
139
|
if (!marker.ok)
|
|
136
140
|
return marker.reason === "not-found" ? "not-found" : "version-changed";
|
|
137
141
|
await deps.repo.deleteById({ workspaceId: required.workspaceId, id: row.id });
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
// An already-clear marker still needs index cleanup, without a duplicate notification.
|
|
143
|
+
if (!marker.noop) {
|
|
144
|
+
await notifyChanged(optional, {
|
|
145
|
+
workspaceId: required.workspaceId,
|
|
146
|
+
entityType: required.entityType,
|
|
147
|
+
entityId: required.entityId,
|
|
148
|
+
change: "restore",
|
|
149
|
+
});
|
|
150
|
+
}
|
|
144
151
|
return "restored";
|
|
145
152
|
}
|
|
146
153
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jini-ai/cms",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Content-model capability for Jini-hosted products: framework-free contracts, ports, and domain services in `/core` and per-domain subpaths; Node-bound adapters in domain-specific subpaths.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"@jini-ai/http-kit": "0.4.0"
|
|
133
133
|
},
|
|
134
134
|
"dependencies": {
|
|
135
|
-
"@jini-ai/core": "0.4.
|
|
135
|
+
"@jini-ai/core": "^0.4.1"
|
|
136
136
|
},
|
|
137
137
|
"peerDependencies": {
|
|
138
138
|
"sharp": "^0.35.3",
|