@jini-ai/cms 0.5.9 → 0.5.10

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 CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.5.10 — 2026-10-13
2
+
3
+ - `./entries`: `InMemoryEntryRepo.hardDelete({ workspaceId, id })` removes one workspace-scoped entry and its revisions (memory-only purge seam, not part of the port).
4
+ - `./forms`: `InMemoryFormSubmissionRepo.listAllForDefinition({ workspaceId, formDefinitionId })` lists a form's submissions, trashed ones included, so a host can drop their Trash rows before the purge cascade (memory-only, not part of the port).
5
+
1
6
  ## 0.5.9 — 2026-10-13
2
7
 
3
8
  - `./widgets`: write, embed and region services take an optional `entryLocks` dependency, threaded into every `withEntryLock` call. New `getEntryLockState({ owner })` returns one lock state per store object, so a host that rebuilds dependency bags per request still shares one queue per store. Omitting `entryLocks` keeps the previous module-wide state.
@@ -9,7 +9,7 @@ import type { EntryRecord, EntryStatus } from "./types.js";
9
9
  */
10
10
  export declare class InMemoryEntryRepo implements EntryRepoPort, EntryListPort {
11
11
  private readonly byId;
12
- private readonly revisions;
12
+ private revisions;
13
13
  private static slugKey;
14
14
  findBySlug(params: {
15
15
  workspaceId: string;
@@ -22,6 +22,12 @@ export declare class InMemoryEntryRepo implements EntryRepoPort, EntryListPort {
22
22
  }): Promise<EntryRecord | null>;
23
23
  save(row: EntryRecord, options?: EntrySaveOptions): Promise<void>;
24
24
  appendRevision(revision: EntryRevisionInput): Promise<void>;
25
+ /** Memory-only purge seam: removes the scoped entry and its revision history. Missing or foreign
26
+ * entries are unchanged. @complexity O(r) time and space over stored revisions. */
27
+ hardDelete(required: {
28
+ workspaceId: string;
29
+ id: string;
30
+ }, _optional?: Record<string, never>): Promise<void>;
25
31
  transaction<T>({ fn }: {
26
32
  fn: () => Promise<T>;
27
33
  }): Promise<T>;
@@ -37,6 +37,15 @@ export class InMemoryEntryRepo {
37
37
  async appendRevision(revision) {
38
38
  this.revisions.push(revision);
39
39
  }
40
+ /** Memory-only purge seam: removes the scoped entry and its revision history. Missing or foreign
41
+ * entries are unchanged. @complexity O(r) time and space over stored revisions. */
42
+ async hardDelete(required, _optional = {}) {
43
+ const row = this.byId.get(required.id);
44
+ if (!row || row.workspaceId !== required.workspaceId)
45
+ return;
46
+ this.byId.delete(required.id);
47
+ this.revisions = this.revisions.filter(revision => revision.workspaceId !== required.workspaceId || revision.entryId !== required.id);
48
+ }
40
49
  async transaction({ fn }) {
41
50
  return fn();
42
51
  }
@@ -115,6 +115,12 @@ export declare class InMemoryFormSubmissionRepo implements FormSubmissionRepoPor
115
115
  workspaceId: UUID;
116
116
  formDefinitionId: UUID;
117
117
  }): Promise<void>;
118
+ /** Trash-blind memory seam: enumerate a form's submissions before its purge cascade, so the host
119
+ * can forget their Trash index rows too. @complexity O(n) time and space over stored submissions. */
120
+ listAllForDefinition(required: {
121
+ workspaceId: UUID;
122
+ formDefinitionId: UUID;
123
+ }, _optional?: Record<string, never>): Promise<StoredFormSubmission[]>;
118
124
  }
119
125
  export {};
120
126
  //# sourceMappingURL=repo.memory.d.ts.map
@@ -184,5 +184,12 @@ export class InMemoryFormSubmissionRepo {
184
184
  }
185
185
  }
186
186
  }
187
+ /** Trash-blind memory seam: enumerate a form's submissions before its purge cascade, so the host
188
+ * can forget their Trash index rows too. @complexity O(n) time and space over stored submissions. */
189
+ async listAllForDefinition(required, _optional = {}) {
190
+ return [...this.rows.values()]
191
+ .filter(row => row.workspaceId === required.workspaceId && row.formDefinitionId === required.formDefinitionId)
192
+ .map(cloneSubmission);
193
+ }
187
194
  }
188
195
  //# sourceMappingURL=repo.memory.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/cms",
3
- "version": "0.5.9",
3
+ "version": "0.5.10",
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": {
@@ -418,8 +418,8 @@
418
418
  "@types/better-sqlite3": "^7.6.13",
419
419
  "@electric-sql/pglite": "0.5.8",
420
420
  "jsdom": "^25.0.1",
421
- "@jini-ai/db": "0.3.3",
422
421
  "@jini-ai/core": "0.4.4",
422
+ "@jini-ai/db": "0.3.3",
423
423
  "@jini-ai/http-kit": "0.4.1"
424
424
  },
425
425
  "dependencies": {