@orthacms/content-server 0.4.3 → 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.
Files changed (144) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4 -1
  4. package/dist/lib/content.module.d.ts.map +1 -1
  5. package/dist/lib/content.module.js +8 -0
  6. package/dist/lib/copilot/entry-proposal.applier.d.ts.map +1 -1
  7. package/dist/lib/copilot/entry-proposal.applier.js +5 -4
  8. package/dist/lib/docs/describe-content-api.d.ts +7 -0
  9. package/dist/lib/docs/describe-content-api.d.ts.map +1 -1
  10. package/dist/lib/docs/describe-content-api.js +177 -53
  11. package/dist/lib/docs/describe-views-api.d.ts +19 -0
  12. package/dist/lib/docs/describe-views-api.d.ts.map +1 -0
  13. package/dist/lib/docs/describe-views-api.js +76 -0
  14. package/dist/lib/docs/field-schema.d.ts.map +1 -1
  15. package/dist/lib/docs/field-schema.js +36 -2
  16. package/dist/lib/docs/openapi-writer.d.ts +49 -0
  17. package/dist/lib/docs/openapi-writer.d.ts.map +1 -0
  18. package/dist/lib/docs/openapi-writer.js +76 -0
  19. package/dist/lib/docs/public-api-schemas.d.ts +45 -0
  20. package/dist/lib/docs/public-api-schemas.d.ts.map +1 -0
  21. package/dist/lib/docs/public-api-schemas.js +377 -0
  22. package/dist/lib/docs/views-schemas.d.ts +22 -0
  23. package/dist/lib/docs/views-schemas.d.ts.map +1 -0
  24. package/dist/lib/docs/views-schemas.js +156 -0
  25. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.d.ts +8 -2
  26. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.d.ts.map +1 -1
  27. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.js +19 -4
  28. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.d.ts +2 -2
  29. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.d.ts.map +1 -1
  30. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.js +14 -4
  31. package/dist/lib/entries/application/use-cases/publish-entry.use-case.d.ts +6 -8
  32. package/dist/lib/entries/application/use-cases/publish-entry.use-case.d.ts.map +1 -1
  33. package/dist/lib/entries/application/use-cases/publish-entry.use-case.js +10 -4
  34. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.d.ts +2 -5
  35. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.d.ts.map +1 -1
  36. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.js +6 -1
  37. package/dist/lib/entries/domain/entry.d.ts +8 -1
  38. package/dist/lib/entries/domain/entry.d.ts.map +1 -1
  39. package/dist/lib/entries/domain/entry.js +12 -12
  40. package/dist/lib/entries/domain/events/entry-events.d.ts +47 -5
  41. package/dist/lib/entries/domain/events/entry-events.d.ts.map +1 -1
  42. package/dist/lib/entries/domain/events/entry-events.js +26 -10
  43. package/dist/lib/entries/entries.constants.d.ts +10 -2
  44. package/dist/lib/entries/entries.constants.d.ts.map +1 -1
  45. package/dist/lib/entries/entries.constants.js +11 -2
  46. package/dist/lib/entries/http/controllers/bulk-entries.controller.d.ts +2 -2
  47. package/dist/lib/entries/http/controllers/bulk-entries.controller.d.ts.map +1 -1
  48. package/dist/lib/entries/http/controllers/bulk-entries.controller.js +8 -6
  49. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts +22 -6
  50. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts.map +1 -1
  51. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.js +71 -17
  52. package/dist/lib/insights/docs/describe-content-insights-api.d.ts +23 -0
  53. package/dist/lib/insights/docs/describe-content-insights-api.d.ts.map +1 -0
  54. package/dist/lib/insights/docs/describe-content-insights-api.js +329 -0
  55. package/dist/lib/mcp/content-tools.provider.d.ts.map +1 -1
  56. package/dist/lib/mcp/content-tools.provider.js +10 -9
  57. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts +14 -13
  58. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts.map +1 -1
  59. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.js +62 -46
  60. package/dist/lib/public-api/http/guards/api-token-workspace.guard.d.ts.map +1 -1
  61. package/dist/lib/public-api/http/guards/api-token-workspace.guard.js +8 -0
  62. package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts +10 -9
  63. package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts.map +1 -1
  64. package/dist/lib/public-api/infrastructure/public-entry-writes.service.js +23 -24
  65. package/dist/lib/public-api/infrastructure/token-actor.d.ts +37 -0
  66. package/dist/lib/public-api/infrastructure/token-actor.d.ts.map +1 -0
  67. package/dist/lib/public-api/infrastructure/token-actor.js +58 -0
  68. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.d.ts.map +1 -1
  69. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.js +12 -1
  70. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.d.ts +28 -0
  71. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.d.ts.map +1 -0
  72. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.js +52 -0
  73. package/dist/lib/utils/content-plugin.d.ts.map +1 -1
  74. package/dist/lib/utils/content-plugin.js +10 -1
  75. package/dist/lib/utils/content-views-plugin.d.ts.map +1 -1
  76. package/dist/lib/utils/content-views-plugin.js +8 -0
  77. package/dist/lib/views/application/use-cases/create-saved-view.use-case.d.ts +4 -1
  78. package/dist/lib/views/application/use-cases/create-saved-view.use-case.d.ts.map +1 -1
  79. package/dist/lib/views/application/use-cases/create-saved-view.use-case.js +33 -9
  80. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.d.ts +4 -1
  81. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.d.ts.map +1 -1
  82. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.js +24 -3
  83. package/dist/lib/views/application/use-cases/update-saved-view.use-case.d.ts +4 -1
  84. package/dist/lib/views/application/use-cases/update-saved-view.use-case.d.ts.map +1 -1
  85. package/dist/lib/views/application/use-cases/update-saved-view.use-case.js +32 -3
  86. package/dist/lib/views/domain/events/saved-view-events.d.ts +28 -0
  87. package/dist/lib/views/domain/events/saved-view-events.d.ts.map +1 -0
  88. package/dist/lib/views/domain/events/saved-view-events.js +38 -0
  89. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.d.ts +12 -3
  90. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.d.ts.map +1 -1
  91. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.js +15 -5
  92. package/package.json +11 -11
  93. package/dist/lib/entries/controllers/bulk-entries.controller.d.ts +0 -26
  94. package/dist/lib/entries/controllers/bulk-entries.controller.d.ts.map +0 -1
  95. package/dist/lib/entries/controllers/create-entry.controller.d.ts +0 -20
  96. package/dist/lib/entries/controllers/create-entry.controller.d.ts.map +0 -1
  97. package/dist/lib/entries/controllers/delete-entry.controller.d.ts +0 -24
  98. package/dist/lib/entries/controllers/delete-entry.controller.d.ts.map +0 -1
  99. package/dist/lib/entries/controllers/get-entry.controller.d.ts +0 -34
  100. package/dist/lib/entries/controllers/get-entry.controller.d.ts.map +0 -1
  101. package/dist/lib/entries/controllers/list-entries.controller.d.ts +0 -20
  102. package/dist/lib/entries/controllers/list-entries.controller.d.ts.map +0 -1
  103. package/dist/lib/entries/controllers/publish-entry.controller.d.ts +0 -19
  104. package/dist/lib/entries/controllers/publish-entry.controller.d.ts.map +0 -1
  105. package/dist/lib/entries/controllers/resolve-type.d.ts +0 -9
  106. package/dist/lib/entries/controllers/resolve-type.d.ts.map +0 -1
  107. package/dist/lib/entries/controllers/update-entry.controller.d.ts +0 -18
  108. package/dist/lib/entries/controllers/update-entry.controller.d.ts.map +0 -1
  109. package/dist/lib/entries/dto/bulk-ids.dto.d.ts +0 -11
  110. package/dist/lib/entries/dto/bulk-ids.dto.d.ts.map +0 -1
  111. package/dist/lib/entries/dto/list-entries-query.dto.d.ts +0 -46
  112. package/dist/lib/entries/dto/list-entries-query.dto.d.ts.map +0 -1
  113. package/dist/lib/entries/dto/relation-delta-map.validator.d.ts +0 -19
  114. package/dist/lib/entries/dto/relation-delta-map.validator.d.ts.map +0 -1
  115. package/dist/lib/entries/dto/save-entry.dto.d.ts +0 -46
  116. package/dist/lib/entries/dto/save-entry.dto.d.ts.map +0 -1
  117. package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts +0 -24
  118. package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts.map +0 -1
  119. package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts +0 -40
  120. package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts.map +0 -1
  121. package/dist/lib/entries/services/entries.service.d.ts +0 -59
  122. package/dist/lib/entries/services/entries.service.d.ts.map +0 -1
  123. package/dist/lib/entries/services/entry-counter.service.d.ts +0 -31
  124. package/dist/lib/entries/services/entry-counter.service.d.ts.map +0 -1
  125. package/dist/lib/entries/services/entry-filter-schema.d.ts +0 -32
  126. package/dist/lib/entries/services/entry-filter-schema.d.ts.map +0 -1
  127. package/dist/lib/entries/services/entry-row.d.ts +0 -56
  128. package/dist/lib/entries/services/entry-row.d.ts.map +0 -1
  129. package/dist/lib/entries/services/entry-writer.service.d.ts +0 -193
  130. package/dist/lib/entries/services/entry-writer.service.d.ts.map +0 -1
  131. package/dist/lib/entries/services/relation-link.service.d.ts +0 -115
  132. package/dist/lib/entries/services/relation-link.service.d.ts.map +0 -1
  133. package/dist/lib/extension/entry-access-source.d.ts +0 -112
  134. package/dist/lib/extension/entry-access-source.d.ts.map +0 -1
  135. package/dist/lib/extension/entry-write-hook.d.ts +0 -98
  136. package/dist/lib/extension/entry-write-hook.d.ts.map +0 -1
  137. package/dist/lib/extension/per-locale-relation.d.ts +0 -18
  138. package/dist/lib/extension/per-locale-relation.d.ts.map +0 -1
  139. package/dist/lib/public/controllers/get-public-entry.controller.d.ts +0 -26
  140. package/dist/lib/public/controllers/get-public-entry.controller.d.ts.map +0 -1
  141. package/dist/lib/public/controllers/list-public-entries.controller.d.ts +0 -24
  142. package/dist/lib/public/controllers/list-public-entries.controller.d.ts.map +0 -1
  143. package/dist/lib/public/controllers/public-schema.controller.d.ts +0 -18
  144. package/dist/lib/public/controllers/public-schema.controller.d.ts.map +0 -1
@@ -46,7 +46,18 @@ let RestoreRevisionUseCase = class RestoreRevisionUseCase {
46
46
  values[field] = ids;
47
47
  }
48
48
  }
49
- return this.writer.update(type, id, values, workspaceId, undefined, actor, {
49
+ return this.writer.update(type, id, values, workspaceId, undefined,
50
+ // Restoring reaches the log as the `entry.updated` its save raises,
51
+ // naming the fields it put back — which is right, and used to be
52
+ // the whole story: nothing said the edit *was* a restore, or of
53
+ // which version. `via` carries that without inventing a kind, the
54
+ // same seam a copilot-applied change uses.
55
+ actor
56
+ ? {
57
+ ...actor,
58
+ via: { kind: 'revision_restore', revisionNumber: number }
59
+ }
60
+ : actor, {
50
61
  ...options,
51
62
  // Put back whatever the bound extensions held when this version was
52
63
  // captured — segments' audiences, today. Without it "go back to
@@ -0,0 +1,28 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { UnitOfWork } from '@orthacms/database';
3
+ import { WorkspacePurgeRegistry, type WorkspacePurger, type WorkspacePurgeOutcome } from '@orthacms/workspaces-server';
4
+ /**
5
+ * Removes a deleted workspace's entry revisions.
6
+ *
7
+ * Content is otherwise the plugin that does **not** purge: a workspace holding
8
+ * entries is refused (409), because entries are authored records someone must
9
+ * delete deliberately. Revisions fall outside that protection in both
10
+ * directions. They carry a plain `workspace_id` with no foreign key, and
11
+ * `countWorkspaceEntries` sums the live `content_<name>` tables only — so a
12
+ * workspace whose entries have all been deleted counts as empty, deletes
13
+ * cleanly, and leaves its whole revision history behind pointing at nothing.
14
+ *
15
+ * That history is not an authored record in its own right: it is the version
16
+ * timeline of rows that are already gone, unreachable once the workspace it was
17
+ * scoped to no longer opens. Purging it is the same call the folder tree and the
18
+ * token bucket get — scoping rows with no independent meaning left.
19
+ */
20
+ export declare class RevisionsWorkspacePurger implements WorkspacePurger, OnModuleInit {
21
+ private readonly uow;
22
+ private readonly registry?;
23
+ readonly purgeName = "content:entry-revisions";
24
+ constructor(uow: UnitOfWork, registry?: WorkspacePurgeRegistry | undefined);
25
+ onModuleInit(): void;
26
+ purge(workspaceId: string): Promise<WorkspacePurgeOutcome>;
27
+ }
28
+ //# sourceMappingURL=revisions-workspace.purger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revisions-workspace.purger.d.ts","sourceRoot":"","sources":["../../../../../src/lib/revisions/infrastructure/purge/revisions-workspace.purger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,YAAY,EAAY,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACH,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC7B,MAAM,6BAA6B,CAAC;AAGrC;;;;;;;;;;;;;;;GAeG;AACH,qBACa,wBAAyB,YAAW,eAAe,EAAE,YAAY;IAItE,OAAO,CAAC,QAAQ,CAAC,GAAG;IACR,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAJ1C,QAAQ,CAAC,SAAS,6BAA6B;gBAG1B,GAAG,EAAE,UAAU,EACH,QAAQ,CAAC,EAAE,sBAAsB,YAAA;IAGlE,YAAY,IAAI,IAAI;IAId,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;CASnE"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RevisionsWorkspacePurger = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const drizzle_orm_1 = require("drizzle-orm");
7
+ const database_1 = require("@orthacms/database");
8
+ const workspaces_server_1 = require("@orthacms/workspaces-server");
9
+ const revision_table_1 = require("../persistence/revision-table");
10
+ /**
11
+ * Removes a deleted workspace's entry revisions.
12
+ *
13
+ * Content is otherwise the plugin that does **not** purge: a workspace holding
14
+ * entries is refused (409), because entries are authored records someone must
15
+ * delete deliberately. Revisions fall outside that protection in both
16
+ * directions. They carry a plain `workspace_id` with no foreign key, and
17
+ * `countWorkspaceEntries` sums the live `content_<name>` tables only — so a
18
+ * workspace whose entries have all been deleted counts as empty, deletes
19
+ * cleanly, and leaves its whole revision history behind pointing at nothing.
20
+ *
21
+ * That history is not an authored record in its own right: it is the version
22
+ * timeline of rows that are already gone, unreachable once the workspace it was
23
+ * scoped to no longer opens. Purging it is the same call the folder tree and the
24
+ * token bucket get — scoping rows with no independent meaning left.
25
+ */
26
+ let RevisionsWorkspacePurger = class RevisionsWorkspacePurger {
27
+ uow;
28
+ registry;
29
+ purgeName = 'content:entry-revisions';
30
+ constructor(uow, registry) {
31
+ this.uow = uow;
32
+ this.registry = registry;
33
+ }
34
+ onModuleInit() {
35
+ this.registry?.register(this);
36
+ }
37
+ async purge(workspaceId) {
38
+ const removed = await this.uow
39
+ .current()
40
+ .delete(revision_table_1.contentEntryRevisions)
41
+ .where((0, drizzle_orm_1.eq)(revision_table_1.contentEntryRevisions.workspaceId, workspaceId))
42
+ .returning({ id: revision_table_1.contentEntryRevisions.id });
43
+ return { rows: removed.length };
44
+ }
45
+ };
46
+ exports.RevisionsWorkspacePurger = RevisionsWorkspacePurger;
47
+ exports.RevisionsWorkspacePurger = RevisionsWorkspacePurger = tslib_1.__decorate([
48
+ (0, common_1.Injectable)(),
49
+ tslib_1.__param(1, (0, common_1.Optional)()),
50
+ tslib_1.__metadata("design:paramtypes", [database_1.UnitOfWork,
51
+ workspaces_server_1.WorkspacePurgeRegistry])
52
+ ], RevisionsWorkspacePurger);
@@ -1 +1 @@
1
- {"version":3,"file":"content-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/content-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACjC,iEAAiE;IACjE,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IACjC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;CAC3C;AAED,kEAAkE;AAClE,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACrD,QAAQ,EAAE,mBAAmB,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CACzB,OAAO,EAAE,oBAAoB,GAC9B,mBAAmB,CAerB"}
1
+ {"version":3,"file":"content-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/content-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACjC,iEAAiE;IACjE,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IACjC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;CAC3C;AAED,kEAAkE;AAClE,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACrD,QAAQ,EAAE,mBAAmB,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CACzB,OAAO,EAAE,oBAAoB,GAC9B,mBAAmB,CAsBrB"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ContentPlugin = ContentPlugin;
4
4
  const content_module_1 = require("../content.module");
5
5
  const describe_content_api_1 = require("../docs/describe-content-api");
6
+ const describe_content_insights_api_1 = require("../insights/docs/describe-content-insights-api");
6
7
  const content_type_registry_1 = require("../registry/content-type-registry");
7
8
  /**
8
9
  * Content plugin factory. Builds the registry eagerly — duplicate names
@@ -29,7 +30,15 @@ function ContentPlugin(options) {
29
30
  // can see; the registry is what knows `article` from `home_page`. This
30
31
  // hook is where the code-defined types become OpenAPI schemas.
31
32
  docs: {
32
- decorate: (document) => (0, describe_content_api_1.describeContentApi)(document, registry.serializeAll())
33
+ decorate: (document) => {
34
+ (0, describe_content_api_1.describeContentApi)(document, registry.serializeAll());
35
+ // The Insights widgets are a second surface with a fixed
36
+ // contract — six unlike payloads whose views are `interface`s,
37
+ // so the scanner emits an empty 200 for each. Described from
38
+ // their own module rather than folded into the pass above:
39
+ // they are grouped under the `insights` tag, not `content`.
40
+ (0, describe_content_insights_api_1.describeContentInsightsApi)(document);
41
+ }
33
42
  }
34
43
  };
35
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"content-views-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/content-views-plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,8CAA8C;AAC9C,MAAM,WAAW,yBAAyB;IACtC;;;;;;OAMG;IACH,OAAO,EAAE,mBAAmB,CAAC;CAChC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,yBAAyB,GACnC,YAAY,CAUd"}
1
+ {"version":3,"file":"content-views-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/content-views-plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,8CAA8C;AAC9C,MAAM,WAAW,yBAAyB;IACtC;;;;;;OAMG;IACH,OAAO,EAAE,mBAAmB,CAAC;CAChC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,yBAAyB,GACnC,YAAY,CAqBd"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ContentViewsPlugin = ContentViewsPlugin;
4
4
  const node_path_1 = require("node:path");
5
5
  const content_views_module_1 = require("../views/content-views.module");
6
+ const describe_views_api_1 = require("../docs/describe-views-api");
6
7
  /**
7
8
  * Saved list views — the named filter/sort/column slices an editor returns to.
8
9
  *
@@ -24,6 +25,13 @@ function ContentViewsPlugin(options) {
24
25
  migrations: {
25
26
  dir: () => (0, node_path_1.join)(__dirname, '../../../migrations'),
26
27
  table: '__drizzle_migrations_content_views'
28
+ },
29
+ // `SavedView` is a framework-free `interface` (ADR-0003 forbids
30
+ // decorating it) and its `scope` is `content:<typeName>`, which only
31
+ // the registry knows — so the swagger scanner sees neither the shape
32
+ // nor the values, and this hook is where both become visible.
33
+ docs: {
34
+ decorate: (document) => (0, describe_views_api_1.describeViewsApi)(document, options.content.registry.serializeAll())
27
35
  }
28
36
  };
29
37
  }
@@ -1,4 +1,5 @@
1
1
  import type { PublicUser } from '@orthacms/identity-server';
2
+ import { OutboxWriter, UnitOfWork } from '@orthacms/database';
2
3
  import type { SavedView, SavedViewPayload, ViewVisibility } from '../../domain/saved-view';
3
4
  import { type SavedViewRepository } from '../../domain/saved-view.repository';
4
5
  import { SavedViewAccessService } from '../saved-view-access.service';
@@ -21,7 +22,9 @@ export interface CreateSavedViewInput {
21
22
  export declare class CreateSavedViewUseCase {
22
23
  private readonly repository;
23
24
  private readonly access;
24
- constructor(repository: SavedViewRepository, access: SavedViewAccessService);
25
+ private readonly uow;
26
+ private readonly outbox;
27
+ constructor(repository: SavedViewRepository, access: SavedViewAccessService, uow: UnitOfWork, outbox: OutboxWriter);
25
28
  execute(input: CreateSavedViewInput, user: PublicUser): Promise<SavedView>;
26
29
  }
27
30
  //# sourceMappingURL=create-saved-view.use-case.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/create-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,KAAK,EACR,SAAS,EACT,gBAAgB,EAChB,cAAc,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAM5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACjC,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,UAAU,EAAE,cAAc,CAAC;IAC3B,6BAA6B;IAC7B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,6CAA6C;AAC7C,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB;IAG7C,OAAO,CACT,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC;CAwCxB"}
1
+ {"version":3,"file":"create-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/create-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAEH,YAAY,EACZ,UAAU,EACb,MAAM,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EACR,SAAS,EACT,gBAAgB,EAChB,cAAc,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAM5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACjC,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,UAAU,EAAE,cAAc,CAAC;IAC3B,6BAA6B;IAC7B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,6CAA6C;AAC7C,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAHN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,YAAY;IAGnC,OAAO,CACT,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC;CAiExB"}
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CreateSavedViewUseCase = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const common_1 = require("@nestjs/common");
6
+ const database_1 = require("@orthacms/database");
7
+ const saved_view_events_1 = require("../../domain/events/saved-view-events");
6
8
  const utils_server_1 = require("@orthacms/utils-server");
7
9
  const saved_view_repository_1 = require("../../domain/saved-view.repository");
8
10
  const errors_1 = require("../../domain/errors");
@@ -13,9 +15,13 @@ const saved_views_query_1 = require("../queries/saved-views.query");
13
15
  let CreateSavedViewUseCase = class CreateSavedViewUseCase {
14
16
  repository;
15
17
  access;
16
- constructor(repository, access) {
18
+ uow;
19
+ outbox;
20
+ constructor(repository, access, uow, outbox) {
17
21
  this.repository = repository;
18
22
  this.access = access;
23
+ this.uow = uow;
24
+ this.outbox = outbox;
19
25
  }
20
26
  async execute(input, user) {
21
27
  await this.access.assertCanUseVisibility(input.visibility, user);
@@ -28,13 +34,27 @@ let CreateSavedViewUseCase = class CreateSavedViewUseCase {
28
34
  // 409 a sequential duplicate gets.
29
35
  let created;
30
36
  try {
31
- created = await this.repository.create({
32
- workspaceId: input.workspaceId,
33
- scope: input.scope,
34
- ownerId: user.id,
35
- visibility: input.visibility,
36
- name: input.name,
37
- payload: input.payload
37
+ created = await this.uow.run(async () => {
38
+ const row = await this.repository.create({
39
+ workspaceId: input.workspaceId,
40
+ scope: input.scope,
41
+ ownerId: user.id,
42
+ visibility: input.visibility,
43
+ name: input.name,
44
+ payload: input.payload
45
+ });
46
+ await this.outbox.append((0, database_1.attachActor)([
47
+ (0, saved_view_events_1.savedViewEvent)(saved_view_events_1.SAVED_VIEW_EVENT_KINDS.CREATED, row.id, {
48
+ workspaceId: input.workspaceId,
49
+ scope: input.scope,
50
+ name: input.name,
51
+ // The half that makes the row worth
52
+ // keeping: a `workspace` view is shared
53
+ // state everyone in the switcher sees.
54
+ visibility: input.visibility
55
+ })
56
+ ], { id: user.id, email: user.email ?? null }));
57
+ return row;
38
58
  });
39
59
  }
40
60
  catch (error) {
@@ -44,6 +64,8 @@ let CreateSavedViewUseCase = class CreateSavedViewUseCase {
44
64
  throw error;
45
65
  }
46
66
  if (input.makeDefault) {
67
+ // Outside the run on purpose: a personal default raises no event
68
+ // (see `saved-view-events.ts`), so it has nothing to commit with.
47
69
  await this.repository.setDefault(user.id, input.scope, created.id);
48
70
  }
49
71
  return (0, saved_views_query_1.toSavedView)(created, user.id, input.makeDefault ? created.id : null);
@@ -53,5 +75,7 @@ exports.CreateSavedViewUseCase = CreateSavedViewUseCase;
53
75
  exports.CreateSavedViewUseCase = CreateSavedViewUseCase = tslib_1.__decorate([
54
76
  (0, common_1.Injectable)(),
55
77
  tslib_1.__param(0, (0, common_1.Inject)(saved_view_repository_1.SAVED_VIEW_REPOSITORY)),
56
- tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService])
78
+ tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService,
79
+ database_1.UnitOfWork,
80
+ database_1.OutboxWriter])
57
81
  ], CreateSavedViewUseCase);
@@ -1,4 +1,5 @@
1
1
  import type { PublicUser } from '@orthacms/identity-server';
2
+ import { OutboxWriter, UnitOfWork } from '@orthacms/database';
2
3
  import { type SavedViewRepository } from '../../domain/saved-view.repository';
3
4
  import { SavedViewAccessService } from '../saved-view-access.service';
4
5
  /**
@@ -9,7 +10,9 @@ import { SavedViewAccessService } from '../saved-view-access.service';
9
10
  export declare class DeleteSavedViewUseCase {
10
11
  private readonly repository;
11
12
  private readonly access;
12
- constructor(repository: SavedViewRepository, access: SavedViewAccessService);
13
+ private readonly uow;
14
+ private readonly outbox;
15
+ constructor(repository: SavedViewRepository, access: SavedViewAccessService, uow: UnitOfWork, outbox: OutboxWriter);
13
16
  execute(id: string, workspaceId: string, user: PublicUser): Promise<void>;
14
17
  }
15
18
  //# sourceMappingURL=delete-saved-view.use-case.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"delete-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/delete-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;;;GAIG;AACH,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB;IAG7C,OAAO,CACT,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC;CAQnB"}
1
+ {"version":3,"file":"delete-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/delete-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAEH,YAAY,EACZ,UAAU,EACb,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;;;GAIG;AACH,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAHN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,YAAY;IAGnC,OAAO,CACT,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC;CA0BnB"}
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DeleteSavedViewUseCase = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const common_1 = require("@nestjs/common");
6
+ const database_1 = require("@orthacms/database");
7
+ const saved_view_events_1 = require("../../domain/events/saved-view-events");
6
8
  const saved_view_repository_1 = require("../../domain/saved-view.repository");
7
9
  const errors_1 = require("../../domain/errors");
8
10
  const saved_view_access_service_1 = require("../saved-view-access.service");
@@ -14,9 +16,13 @@ const saved_view_access_service_1 = require("../saved-view-access.service");
14
16
  let DeleteSavedViewUseCase = class DeleteSavedViewUseCase {
15
17
  repository;
16
18
  access;
17
- constructor(repository, access) {
19
+ uow;
20
+ outbox;
21
+ constructor(repository, access, uow, outbox) {
18
22
  this.repository = repository;
19
23
  this.access = access;
24
+ this.uow = uow;
25
+ this.outbox = outbox;
20
26
  }
21
27
  async execute(id, workspaceId, user) {
22
28
  const existing = await this.repository.findById(id);
@@ -24,12 +30,27 @@ let DeleteSavedViewUseCase = class DeleteSavedViewUseCase {
24
30
  throw new errors_1.SavedViewNotFoundError(id);
25
31
  }
26
32
  this.access.assertOwned(existing, user);
27
- await this.repository.delete(id);
33
+ await this.uow.run(async () => {
34
+ await this.repository.delete(id);
35
+ // The view's own details, because this is the last place they
36
+ // exist — and a shared view leaving everyone's switcher is a
37
+ // change to what a team can see, not just to one person's list.
38
+ await this.outbox.append((0, database_1.attachActor)([
39
+ (0, saved_view_events_1.savedViewEvent)(saved_view_events_1.SAVED_VIEW_EVENT_KINDS.DELETED, id, {
40
+ workspaceId,
41
+ scope: existing.scope,
42
+ name: existing.name,
43
+ visibility: existing.visibility
44
+ })
45
+ ], { id: user.id, email: user.email ?? null }));
46
+ });
28
47
  }
29
48
  };
30
49
  exports.DeleteSavedViewUseCase = DeleteSavedViewUseCase;
31
50
  exports.DeleteSavedViewUseCase = DeleteSavedViewUseCase = tslib_1.__decorate([
32
51
  (0, common_1.Injectable)(),
33
52
  tslib_1.__param(0, (0, common_1.Inject)(saved_view_repository_1.SAVED_VIEW_REPOSITORY)),
34
- tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService])
53
+ tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService,
54
+ database_1.UnitOfWork,
55
+ database_1.OutboxWriter])
35
56
  ], DeleteSavedViewUseCase);
@@ -1,4 +1,5 @@
1
1
  import type { PublicUser } from '@orthacms/identity-server';
2
+ import { OutboxWriter, UnitOfWork } from '@orthacms/database';
2
3
  import type { SavedView, SavedViewPayload, ViewVisibility } from '../../domain/saved-view';
3
4
  import { type SavedViewRepository } from '../../domain/saved-view.repository';
4
5
  import { SavedViewAccessService } from '../saved-view-access.service';
@@ -15,7 +16,9 @@ export interface UpdateSavedViewInput {
15
16
  export declare class UpdateSavedViewUseCase {
16
17
  private readonly repository;
17
18
  private readonly access;
18
- constructor(repository: SavedViewRepository, access: SavedViewAccessService);
19
+ private readonly uow;
20
+ private readonly outbox;
21
+ constructor(repository: SavedViewRepository, access: SavedViewAccessService, uow: UnitOfWork, outbox: OutboxWriter);
19
22
  execute(id: string, workspaceId: string, input: UpdateSavedViewInput, user: PublicUser): Promise<SavedView>;
20
23
  }
21
24
  //# sourceMappingURL=update-saved-view.use-case.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/update-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,KAAK,EACR,SAAS,EACT,gBAAgB,EAChB,cAAc,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAK5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACjC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,iBAAiB;IACjB,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,2DAA2D;AAC3D,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB;IAG7C,OAAO,CACT,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC;CA4CxB"}
1
+ {"version":3,"file":"update-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/update-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAEH,YAAY,EACZ,UAAU,EACb,MAAM,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EACR,SAAS,EACT,gBAAgB,EAChB,cAAc,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAK5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACjC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,iBAAiB;IACjB,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,2DAA2D;AAC3D,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAHN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,YAAY;IAGnC,OAAO,CACT,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC;CA0ExB"}
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UpdateSavedViewUseCase = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const common_1 = require("@nestjs/common");
6
+ const database_1 = require("@orthacms/database");
7
+ const saved_view_events_1 = require("../../domain/events/saved-view-events");
6
8
  const utils_server_1 = require("@orthacms/utils-server");
7
9
  const saved_view_repository_1 = require("../../domain/saved-view.repository");
8
10
  const errors_1 = require("../../domain/errors");
@@ -12,9 +14,13 @@ const saved_views_query_1 = require("../queries/saved-views.query");
12
14
  let UpdateSavedViewUseCase = class UpdateSavedViewUseCase {
13
15
  repository;
14
16
  access;
15
- constructor(repository, access) {
17
+ uow;
18
+ outbox;
19
+ constructor(repository, access, uow, outbox) {
16
20
  this.repository = repository;
17
21
  this.access = access;
22
+ this.uow = uow;
23
+ this.outbox = outbox;
18
24
  }
19
25
  async execute(id, workspaceId, input, user) {
20
26
  const existing = await this.repository.findById(id);
@@ -41,7 +47,28 @@ let UpdateSavedViewUseCase = class UpdateSavedViewUseCase {
41
47
  }
42
48
  let updated;
43
49
  try {
44
- updated = await this.repository.update(id, input);
50
+ updated = await this.uow.run(async () => {
51
+ const row = await this.repository.update(id, input);
52
+ await this.outbox.append((0, database_1.attachActor)([
53
+ (0, saved_view_events_1.savedViewEvent)(saved_view_events_1.SAVED_VIEW_EVENT_KINDS.UPDATED, id, {
54
+ workspaceId,
55
+ scope: existing.scope,
56
+ name: row.name,
57
+ // The keys the caller actually sent — a
58
+ // patch, so "what changed" is the request.
59
+ fields: Object.keys(input),
60
+ // Called out on its own: sharing is a
61
+ // permission of its own, and unsharing
62
+ // takes a view out of every member's
63
+ // switcher without telling them.
64
+ visibility: {
65
+ from: existing.visibility,
66
+ to: row.visibility
67
+ }
68
+ })
69
+ ], { id: user.id, email: user.email ?? null }));
70
+ return row;
71
+ });
45
72
  }
46
73
  catch (error) {
47
74
  if ((0, utils_server_1.isUniqueViolation)(error)) {
@@ -57,5 +84,7 @@ exports.UpdateSavedViewUseCase = UpdateSavedViewUseCase;
57
84
  exports.UpdateSavedViewUseCase = UpdateSavedViewUseCase = tslib_1.__decorate([
58
85
  (0, common_1.Injectable)(),
59
86
  tslib_1.__param(0, (0, common_1.Inject)(saved_view_repository_1.SAVED_VIEW_REPOSITORY)),
60
- tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService])
87
+ tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService,
88
+ database_1.UnitOfWork,
89
+ database_1.OutboxWriter])
61
90
  ], UpdateSavedViewUseCase);
@@ -0,0 +1,28 @@
1
+ import { type DomainEvent } from '@orthacms/database';
2
+ /**
3
+ * The domain events a saved view raises.
4
+ *
5
+ * A view is a bookmark rather than a grant — it is replayed through the
6
+ * ordinary list query with the reader's own permissions, so it can never show
7
+ * anyone a row they could not already reach. That is why only three of the five
8
+ * write routes raise anything:
9
+ *
10
+ * - **Create, update and delete are recorded.** A `workspace`-visible view is
11
+ * shared state: it appears in every member's switcher, it is the thing a team
12
+ * agrees "the review queue" means, and deleting one takes it away from
13
+ * everybody. Sharing is even its own permission (`views:share`), which is the
14
+ * product saying this is not purely personal.
15
+ * - **Setting a personal default raises nothing, deliberately.** It is the
16
+ * reader's own landing choice — the same class of thing as `PUT
17
+ * /preferences` — and it is set by clicking a view. A row per click would be
18
+ * a usage metric wearing an audit row's clothes, and it would bury the three
19
+ * kinds above in a log that has no way to filter by "interesting".
20
+ */
21
+ export declare const SAVED_VIEW_EVENT_KINDS: {
22
+ readonly CREATED: "saved_view.created";
23
+ readonly UPDATED: "saved_view.updated";
24
+ readonly DELETED: "saved_view.deleted";
25
+ };
26
+ /** Builds a saved-view {@link DomainEvent}, stamping the aggregate type + id. */
27
+ export declare function savedViewEvent(kind: string, viewId: string, payload: Record<string, unknown>): DomainEvent;
28
+ //# sourceMappingURL=saved-view-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saved-view-events.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/domain/events/saved-view-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEzE;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,sBAAsB;;;;CAIzB,CAAC;AAEX,iFAAiF;AACjF,wBAAgB,cAAc,CAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,WAAW,CAOb"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SAVED_VIEW_EVENT_KINDS = void 0;
4
+ exports.savedViewEvent = savedViewEvent;
5
+ const database_1 = require("@orthacms/database");
6
+ /**
7
+ * The domain events a saved view raises.
8
+ *
9
+ * A view is a bookmark rather than a grant — it is replayed through the
10
+ * ordinary list query with the reader's own permissions, so it can never show
11
+ * anyone a row they could not already reach. That is why only three of the five
12
+ * write routes raise anything:
13
+ *
14
+ * - **Create, update and delete are recorded.** A `workspace`-visible view is
15
+ * shared state: it appears in every member's switcher, it is the thing a team
16
+ * agrees "the review queue" means, and deleting one takes it away from
17
+ * everybody. Sharing is even its own permission (`views:share`), which is the
18
+ * product saying this is not purely personal.
19
+ * - **Setting a personal default raises nothing, deliberately.** It is the
20
+ * reader's own landing choice — the same class of thing as `PUT
21
+ * /preferences` — and it is set by clicking a view. A row per click would be
22
+ * a usage metric wearing an audit row's clothes, and it would bury the three
23
+ * kinds above in a log that has no way to filter by "interesting".
24
+ */
25
+ exports.SAVED_VIEW_EVENT_KINDS = {
26
+ CREATED: 'saved_view.created',
27
+ UPDATED: 'saved_view.updated',
28
+ DELETED: 'saved_view.deleted'
29
+ };
30
+ /** Builds a saved-view {@link DomainEvent}, stamping the aggregate type + id. */
31
+ function savedViewEvent(kind, viewId, payload) {
32
+ return (0, database_1.createDomainEvent)({
33
+ kind,
34
+ aggregateType: 'saved_view',
35
+ aggregateId: viewId,
36
+ payload
37
+ });
38
+ }
@@ -1,9 +1,18 @@
1
- import { type Database } from '@orthacms/database';
1
+ import { UnitOfWork } from '@orthacms/database';
2
2
  import type { NewSavedView, SavedViewPatch, SavedViewRecord, SavedViewRepository } from '../../domain/saved-view.repository';
3
3
  /** Drizzle adapter for {@link SavedViewRepository}. */
4
4
  export declare class DrizzleSavedViewRepository implements SavedViewRepository {
5
- private readonly db;
6
- constructor(db: Database);
5
+ private readonly uow;
6
+ constructor(uow: UnitOfWork);
7
+ /**
8
+ * The executor to run against: the ambient transaction when a caller opened
9
+ * one, the base connection otherwise.
10
+ *
11
+ * It exists so a view write and the `saved_view.*` event describing it
12
+ * commit together. Outside a unit of work this is the old behaviour
13
+ * exactly — `UnitOfWork.current()` falls back to the pool.
14
+ */
15
+ private get db();
7
16
  listVisible(workspaceId: string, scope: string, readerId: string): Promise<SavedViewRecord[]>;
8
17
  findById(id: string): Promise<SavedViewRecord | null>;
9
18
  countForOwner(workspaceId: string, scope: string, ownerId: string): Promise<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"drizzle-saved-view.repository.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/infrastructure/persistence/drizzle-saved-view.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnE,OAAO,KAAK,EACR,YAAY,EACZ,cAAc,EACd,eAAe,EACf,mBAAmB,EACtB,MAAM,oCAAoC,CAAC;AAiC5C,uDAAuD;AACvD,qBACa,0BAA2B,YAAW,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAErD,WAAW,CACb,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,EAAE,CAAC;IAuBvB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IASrD,aAAa,CACf,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC;IAcZ,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAepD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAoBnE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAcpE,UAAU,CACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAYV,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUnE"}
1
+ {"version":3,"file":"drizzle-saved-view.repository.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/infrastructure/persistence/drizzle-saved-view.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAiB,MAAM,oBAAoB,CAAC;AAG/D,OAAO,KAAK,EACR,YAAY,EACZ,cAAc,EACd,eAAe,EACf,mBAAmB,EACtB,MAAM,oCAAoC,CAAC;AAiC5C,uDAAuD;AACvD,qBACa,0BAA2B,YAAW,mBAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,UAAU;IAE5C;;;;;;;OAOG;IACH,OAAO,KAAK,EAAE,GAEb;IAEK,WAAW,CACb,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,EAAE,CAAC;IAuBvB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IASrD,aAAa,CACf,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC;IAcZ,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAepD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAoBnE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAcpE,UAAU,CACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAYV,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUnE"}
@@ -26,9 +26,20 @@ function toRecord(row) {
26
26
  }
27
27
  /** Drizzle adapter for {@link SavedViewRepository}. */
28
28
  let DrizzleSavedViewRepository = class DrizzleSavedViewRepository {
29
- db;
30
- constructor(db) {
31
- this.db = db;
29
+ uow;
30
+ constructor(uow) {
31
+ this.uow = uow;
32
+ }
33
+ /**
34
+ * The executor to run against: the ambient transaction when a caller opened
35
+ * one, the base connection otherwise.
36
+ *
37
+ * It exists so a view write and the `saved_view.*` event describing it
38
+ * commit together. Outside a unit of work this is the old behaviour
39
+ * exactly — `UnitOfWork.current()` falls back to the pool.
40
+ */
41
+ get db() {
42
+ return this.uow.current();
32
43
  }
33
44
  async listVisible(workspaceId, scope, readerId) {
34
45
  const rows = await this.db
@@ -120,6 +131,5 @@ let DrizzleSavedViewRepository = class DrizzleSavedViewRepository {
120
131
  exports.DrizzleSavedViewRepository = DrizzleSavedViewRepository;
121
132
  exports.DrizzleSavedViewRepository = DrizzleSavedViewRepository = tslib_1.__decorate([
122
133
  (0, common_1.Injectable)(),
123
- tslib_1.__param(0, (0, database_1.InjectDatabase)()),
124
- tslib_1.__metadata("design:paramtypes", [Object])
134
+ tslib_1.__metadata("design:paramtypes", [database_1.UnitOfWork])
125
135
  ], DrizzleSavedViewRepository);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orthacms/content-server",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "@orthacms/content-server — part of Ortha CMS.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/ortha-source/ortha-cms/tree/main/packages/content/server",
@@ -33,16 +33,16 @@
33
33
  "@nestjs/common": "^11.0.0",
34
34
  "@nestjs/core": "^11.0.0",
35
35
  "@nestjs/swagger": "^11.4.6",
36
- "@orthacms/bootstrap-server": "^0.4.3",
37
- "@orthacms/content-domain": "^0.4.3",
38
- "@orthacms/copilot-domain": "^0.4.3",
39
- "@orthacms/copilot-server": "^0.4.3",
40
- "@orthacms/database": "^0.4.3",
41
- "@orthacms/identity-server": "^0.4.3",
42
- "@orthacms/mcp-server": "^0.4.3",
43
- "@orthacms/tools-server": "^0.4.3",
44
- "@orthacms/utils-server": "^0.4.3",
45
- "@orthacms/workspaces-server": "^0.4.3",
36
+ "@orthacms/bootstrap-server": "^0.5.0",
37
+ "@orthacms/content-domain": "^0.5.0",
38
+ "@orthacms/copilot-domain": "^0.5.0",
39
+ "@orthacms/copilot-server": "^0.5.0",
40
+ "@orthacms/database": "^0.5.0",
41
+ "@orthacms/identity-server": "^0.5.0",
42
+ "@orthacms/mcp-server": "^0.5.0",
43
+ "@orthacms/tools-server": "^0.5.0",
44
+ "@orthacms/utils-server": "^0.5.0",
45
+ "@orthacms/workspaces-server": "^0.5.0",
46
46
  "class-transformer": "^0.5.1",
47
47
  "class-validator": "^0.15.1",
48
48
  "drizzle-orm": "^0.45.0",