@orthacms/content-server 0.4.2 → 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 (246) hide show
  1. package/dist/index.d.ts +16 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +41 -1
  4. package/dist/lib/content.module.d.ts.map +1 -1
  5. package/dist/lib/content.module.js +31 -1
  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/http/controllers/create-entry.controller.d.ts.map +1 -1
  50. package/dist/lib/entries/http/controllers/create-entry.controller.js +1 -1
  51. package/dist/lib/entries/http/controllers/update-entry.controller.d.ts.map +1 -1
  52. package/dist/lib/entries/http/controllers/update-entry.controller.js +1 -1
  53. package/dist/lib/entries/http/dto/extension-bag.validator.d.ts +14 -0
  54. package/dist/lib/entries/http/dto/extension-bag.validator.d.ts.map +1 -0
  55. package/dist/lib/entries/http/dto/extension-bag.validator.js +42 -0
  56. package/dist/lib/entries/http/dto/save-entry.dto.d.ts +16 -0
  57. package/dist/lib/entries/http/dto/save-entry.dto.d.ts.map +1 -1
  58. package/dist/lib/entries/http/dto/save-entry.dto.js +30 -0
  59. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts +50 -8
  60. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts.map +1 -1
  61. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.js +183 -32
  62. package/dist/lib/entries/infrastructure/persistence/relation-link.service.d.ts +38 -5
  63. package/dist/lib/entries/infrastructure/persistence/relation-link.service.d.ts.map +1 -1
  64. package/dist/lib/entries/infrastructure/persistence/relation-link.service.js +38 -6
  65. package/dist/lib/entries/infrastructure/queries/entries.service.d.ts +3 -1
  66. package/dist/lib/entries/infrastructure/queries/entries.service.d.ts.map +1 -1
  67. package/dist/lib/entries/infrastructure/queries/entries.service.js +17 -5
  68. package/dist/lib/entries/infrastructure/queries/entry-match.query.d.ts +82 -0
  69. package/dist/lib/entries/infrastructure/queries/entry-match.query.d.ts.map +1 -0
  70. package/dist/lib/entries/infrastructure/queries/entry-match.query.js +152 -0
  71. package/dist/lib/extension/entry-filter-provider.d.ts +79 -0
  72. package/dist/lib/extension/entry-filter-provider.d.ts.map +1 -0
  73. package/dist/lib/extension/entry-filter-provider.js +149 -0
  74. package/dist/lib/extension/entry-write-extension.d.ts +185 -0
  75. package/dist/lib/extension/entry-write-extension.d.ts.map +1 -0
  76. package/dist/lib/extension/entry-write-extension.js +182 -0
  77. package/dist/lib/extension/read-scope.d.ts +107 -0
  78. package/dist/lib/extension/read-scope.d.ts.map +1 -0
  79. package/dist/lib/extension/read-scope.js +131 -0
  80. package/dist/lib/insights/docs/describe-content-insights-api.d.ts +23 -0
  81. package/dist/lib/insights/docs/describe-content-insights-api.d.ts.map +1 -0
  82. package/dist/lib/insights/docs/describe-content-insights-api.js +329 -0
  83. package/dist/lib/mcp/content-tools.provider.d.ts.map +1 -1
  84. package/dist/lib/mcp/content-tools.provider.js +10 -9
  85. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts +14 -13
  86. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts.map +1 -1
  87. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.js +62 -46
  88. package/dist/lib/public-api/http/guards/api-token-workspace.guard.d.ts.map +1 -1
  89. package/dist/lib/public-api/http/guards/api-token-workspace.guard.js +8 -0
  90. package/dist/lib/public-api/infrastructure/public-entries.query.d.ts +14 -1
  91. package/dist/lib/public-api/infrastructure/public-entries.query.d.ts.map +1 -1
  92. package/dist/lib/public-api/infrastructure/public-entries.query.js +20 -3
  93. package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts +10 -9
  94. package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts.map +1 -1
  95. package/dist/lib/public-api/infrastructure/public-entry-writes.service.js +23 -24
  96. package/dist/lib/public-api/infrastructure/public-expansion.query.d.ts +16 -4
  97. package/dist/lib/public-api/infrastructure/public-expansion.query.d.ts.map +1 -1
  98. package/dist/lib/public-api/infrastructure/public-expansion.query.js +29 -9
  99. package/dist/lib/public-api/infrastructure/token-actor.d.ts +37 -0
  100. package/dist/lib/public-api/infrastructure/token-actor.d.ts.map +1 -0
  101. package/dist/lib/public-api/infrastructure/token-actor.js +58 -0
  102. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.d.ts.map +1 -1
  103. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.js +23 -1
  104. package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.d.ts +7 -1
  105. package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.d.ts.map +1 -1
  106. package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.js +9 -2
  107. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.d.ts +28 -0
  108. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.d.ts.map +1 -0
  109. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.js +52 -0
  110. package/dist/lib/revisions/types/revision-view.d.ts +11 -0
  111. package/dist/lib/revisions/types/revision-view.d.ts.map +1 -1
  112. package/dist/lib/utils/content-plugin.d.ts.map +1 -1
  113. package/dist/lib/utils/content-plugin.js +10 -1
  114. package/dist/lib/utils/content-views-plugin.d.ts +28 -0
  115. package/dist/lib/utils/content-views-plugin.d.ts.map +1 -0
  116. package/dist/lib/utils/content-views-plugin.js +37 -0
  117. package/dist/lib/views/application/queries/saved-views.query.d.ts +16 -0
  118. package/dist/lib/views/application/queries/saved-views.query.d.ts.map +1 -0
  119. package/dist/lib/views/application/queries/saved-views.query.js +46 -0
  120. package/dist/lib/views/application/saved-view-access.service.d.ts +30 -0
  121. package/dist/lib/views/application/saved-view-access.service.d.ts.map +1 -0
  122. package/dist/lib/views/application/saved-view-access.service.js +55 -0
  123. package/dist/lib/views/application/use-cases/create-saved-view.use-case.d.ts +30 -0
  124. package/dist/lib/views/application/use-cases/create-saved-view.use-case.d.ts.map +1 -0
  125. package/dist/lib/views/application/use-cases/create-saved-view.use-case.js +81 -0
  126. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.d.ts +18 -0
  127. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.d.ts.map +1 -0
  128. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.js +56 -0
  129. package/dist/lib/views/application/use-cases/set-default-view.use-case.d.ts +23 -0
  130. package/dist/lib/views/application/use-cases/set-default-view.use-case.d.ts.map +1 -0
  131. package/dist/lib/views/application/use-cases/set-default-view.use-case.js +51 -0
  132. package/dist/lib/views/application/use-cases/update-saved-view.use-case.d.ts +24 -0
  133. package/dist/lib/views/application/use-cases/update-saved-view.use-case.d.ts.map +1 -0
  134. package/dist/lib/views/application/use-cases/update-saved-view.use-case.js +90 -0
  135. package/dist/lib/views/application/view-scope.service.d.ts +25 -0
  136. package/dist/lib/views/application/view-scope.service.d.ts.map +1 -0
  137. package/dist/lib/views/application/view-scope.service.js +45 -0
  138. package/dist/lib/views/content-views.module.d.ts +22 -0
  139. package/dist/lib/views/content-views.module.d.ts.map +1 -0
  140. package/dist/lib/views/content-views.module.js +63 -0
  141. package/dist/lib/views/domain/errors/index.d.ts +6 -0
  142. package/dist/lib/views/domain/errors/index.d.ts.map +1 -0
  143. package/dist/lib/views/domain/errors/index.js +12 -0
  144. package/dist/lib/views/domain/errors/saved-view-forbidden.error.d.ts +10 -0
  145. package/dist/lib/views/domain/errors/saved-view-forbidden.error.d.ts.map +1 -0
  146. package/dist/lib/views/domain/errors/saved-view-forbidden.error.js +16 -0
  147. package/dist/lib/views/domain/errors/saved-view-limit-error.d.ts +9 -0
  148. package/dist/lib/views/domain/errors/saved-view-limit-error.d.ts.map +1 -0
  149. package/dist/lib/views/domain/errors/saved-view-limit-error.js +16 -0
  150. package/dist/lib/views/domain/errors/saved-view-name-taken.error.d.ts +5 -0
  151. package/dist/lib/views/domain/errors/saved-view-name-taken.error.d.ts.map +1 -0
  152. package/dist/lib/views/domain/errors/saved-view-name-taken.error.js +11 -0
  153. package/dist/lib/views/domain/errors/saved-view-not-found.error.d.ts +9 -0
  154. package/dist/lib/views/domain/errors/saved-view-not-found.error.d.ts.map +1 -0
  155. package/dist/lib/views/domain/errors/saved-view-not-found.error.js +15 -0
  156. package/dist/lib/views/domain/events/saved-view-events.d.ts +28 -0
  157. package/dist/lib/views/domain/events/saved-view-events.d.ts.map +1 -0
  158. package/dist/lib/views/domain/events/saved-view-events.js +38 -0
  159. package/dist/lib/views/domain/saved-view.d.ts +66 -0
  160. package/dist/lib/views/domain/saved-view.d.ts.map +1 -0
  161. package/dist/lib/views/domain/saved-view.js +18 -0
  162. package/dist/lib/views/domain/saved-view.repository.d.ts +77 -0
  163. package/dist/lib/views/domain/saved-view.repository.d.ts.map +1 -0
  164. package/dist/lib/views/domain/saved-view.repository.js +5 -0
  165. package/dist/lib/views/http/controllers/saved-views.controller.d.ts +45 -0
  166. package/dist/lib/views/http/controllers/saved-views.controller.d.ts.map +1 -0
  167. package/dist/lib/views/http/controllers/saved-views.controller.js +216 -0
  168. package/dist/lib/views/http/controllers/to-http-error.d.ts +10 -0
  169. package/dist/lib/views/http/controllers/to-http-error.d.ts.map +1 -0
  170. package/dist/lib/views/http/controllers/to-http-error.js +26 -0
  171. package/dist/lib/views/http/dto/save-view.dto.d.ts +54 -0
  172. package/dist/lib/views/http/dto/save-view.dto.d.ts.map +1 -0
  173. package/dist/lib/views/http/dto/save-view.dto.js +230 -0
  174. package/dist/lib/views/http/dto/view-payload.validator.d.ts +20 -0
  175. package/dist/lib/views/http/dto/view-payload.validator.d.ts.map +1 -0
  176. package/dist/lib/views/http/dto/view-payload.validator.js +52 -0
  177. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.d.ts +26 -0
  178. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.d.ts.map +1 -0
  179. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.js +135 -0
  180. package/dist/lib/views/infrastructure/schema/external-refs.d.ts +68 -0
  181. package/dist/lib/views/infrastructure/schema/external-refs.d.ts.map +1 -0
  182. package/dist/lib/views/infrastructure/schema/external-refs.js +29 -0
  183. package/dist/lib/views/infrastructure/schema/index.d.ts +8 -0
  184. package/dist/lib/views/infrastructure/schema/index.d.ts.map +1 -0
  185. package/dist/lib/views/infrastructure/schema/index.js +13 -0
  186. package/dist/lib/views/infrastructure/schema/saved-views.d.ts +275 -0
  187. package/dist/lib/views/infrastructure/schema/saved-views.d.ts.map +1 -0
  188. package/dist/lib/views/infrastructure/schema/saved-views.js +87 -0
  189. package/dist/lib/views/views.constants.d.ts +26 -0
  190. package/dist/lib/views/views.constants.d.ts.map +1 -0
  191. package/dist/lib/views/views.constants.js +28 -0
  192. package/dist/lib/views/views.tokens.d.ts +17 -0
  193. package/dist/lib/views/views.tokens.d.ts.map +1 -0
  194. package/dist/lib/views/views.tokens.js +21 -0
  195. package/migrations/0000_saved_views.sql +29 -0
  196. package/migrations/meta/0000_snapshot.json +256 -0
  197. package/migrations/meta/_journal.json +13 -0
  198. package/package.json +13 -12
  199. package/dist/lib/entries/controllers/bulk-entries.controller.d.ts +0 -26
  200. package/dist/lib/entries/controllers/bulk-entries.controller.d.ts.map +0 -1
  201. package/dist/lib/entries/controllers/create-entry.controller.d.ts +0 -20
  202. package/dist/lib/entries/controllers/create-entry.controller.d.ts.map +0 -1
  203. package/dist/lib/entries/controllers/delete-entry.controller.d.ts +0 -24
  204. package/dist/lib/entries/controllers/delete-entry.controller.d.ts.map +0 -1
  205. package/dist/lib/entries/controllers/get-entry.controller.d.ts +0 -34
  206. package/dist/lib/entries/controllers/get-entry.controller.d.ts.map +0 -1
  207. package/dist/lib/entries/controllers/list-entries.controller.d.ts +0 -20
  208. package/dist/lib/entries/controllers/list-entries.controller.d.ts.map +0 -1
  209. package/dist/lib/entries/controllers/publish-entry.controller.d.ts +0 -19
  210. package/dist/lib/entries/controllers/publish-entry.controller.d.ts.map +0 -1
  211. package/dist/lib/entries/controllers/resolve-type.d.ts +0 -9
  212. package/dist/lib/entries/controllers/resolve-type.d.ts.map +0 -1
  213. package/dist/lib/entries/controllers/update-entry.controller.d.ts +0 -18
  214. package/dist/lib/entries/controllers/update-entry.controller.d.ts.map +0 -1
  215. package/dist/lib/entries/dto/bulk-ids.dto.d.ts +0 -11
  216. package/dist/lib/entries/dto/bulk-ids.dto.d.ts.map +0 -1
  217. package/dist/lib/entries/dto/list-entries-query.dto.d.ts +0 -46
  218. package/dist/lib/entries/dto/list-entries-query.dto.d.ts.map +0 -1
  219. package/dist/lib/entries/dto/relation-delta-map.validator.d.ts +0 -19
  220. package/dist/lib/entries/dto/relation-delta-map.validator.d.ts.map +0 -1
  221. package/dist/lib/entries/dto/save-entry.dto.d.ts +0 -46
  222. package/dist/lib/entries/dto/save-entry.dto.d.ts.map +0 -1
  223. package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts +0 -24
  224. package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts.map +0 -1
  225. package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts +0 -40
  226. package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts.map +0 -1
  227. package/dist/lib/entries/services/entries.service.d.ts +0 -59
  228. package/dist/lib/entries/services/entries.service.d.ts.map +0 -1
  229. package/dist/lib/entries/services/entry-counter.service.d.ts +0 -31
  230. package/dist/lib/entries/services/entry-counter.service.d.ts.map +0 -1
  231. package/dist/lib/entries/services/entry-filter-schema.d.ts +0 -32
  232. package/dist/lib/entries/services/entry-filter-schema.d.ts.map +0 -1
  233. package/dist/lib/entries/services/entry-row.d.ts +0 -56
  234. package/dist/lib/entries/services/entry-row.d.ts.map +0 -1
  235. package/dist/lib/entries/services/entry-writer.service.d.ts +0 -193
  236. package/dist/lib/entries/services/entry-writer.service.d.ts.map +0 -1
  237. package/dist/lib/entries/services/relation-link.service.d.ts +0 -115
  238. package/dist/lib/entries/services/relation-link.service.d.ts.map +0 -1
  239. package/dist/lib/extension/per-locale-relation.d.ts +0 -18
  240. package/dist/lib/extension/per-locale-relation.d.ts.map +0 -1
  241. package/dist/lib/public/controllers/get-public-entry.controller.d.ts +0 -26
  242. package/dist/lib/public/controllers/get-public-entry.controller.d.ts.map +0 -1
  243. package/dist/lib/public/controllers/list-public-entries.controller.d.ts +0 -24
  244. package/dist/lib/public/controllers/list-public-entries.controller.d.ts.map +0 -1
  245. package/dist/lib/public/controllers/public-schema.controller.d.ts +0 -18
  246. package/dist/lib/public/controllers/public-schema.controller.d.ts.map +0 -1
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SavedViewsController = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const swagger_1 = require("@nestjs/swagger");
7
+ const identity_server_1 = require("@orthacms/identity-server");
8
+ const workspaces_server_1 = require("@orthacms/workspaces-server");
9
+ const saved_view_1 = require("../../domain/saved-view");
10
+ const saved_views_query_1 = require("../../application/queries/saved-views.query");
11
+ const create_saved_view_use_case_1 = require("../../application/use-cases/create-saved-view.use-case");
12
+ const update_saved_view_use_case_1 = require("../../application/use-cases/update-saved-view.use-case");
13
+ const delete_saved_view_use_case_1 = require("../../application/use-cases/delete-saved-view.use-case");
14
+ const set_default_view_use_case_1 = require("../../application/use-cases/set-default-view.use-case");
15
+ const view_scope_service_1 = require("../../application/view-scope.service");
16
+ const save_view_dto_1 = require("../dto/save-view.dto");
17
+ const to_http_error_1 = require("./to-http-error");
18
+ /**
19
+ * `/api/views` — a member's saved list views for one content type.
20
+ *
21
+ * A genuine CRUD resource over one thing, so it stays a single controller
22
+ * rather than five. Every route is workspace-scoped (`WorkspaceGuard` reads
23
+ * `X-Workspace-Id` and 403s a non-member) and gated on `content:read`: a view
24
+ * is a saved way of reading content, so anyone who cannot read content has no
25
+ * use for one. Sharing needs `views:share` on top, checked per write because it
26
+ * depends on the *body*, not the route.
27
+ *
28
+ * The stored payload is **not** a grant. It is replayed through the ordinary
29
+ * list query with the reader's own permissions, workspace scope and content
30
+ * grants, so a shared view shows a narrower reader fewer rows — never more.
31
+ */
32
+ let SavedViewsController = class SavedViewsController {
33
+ views;
34
+ scopes;
35
+ createView;
36
+ updateView;
37
+ deleteView;
38
+ setDefault;
39
+ constructor(views, scopes, createView, updateView, deleteView, setDefault) {
40
+ this.views = views;
41
+ this.scopes = scopes;
42
+ this.createView = createView;
43
+ this.updateView = updateView;
44
+ this.deleteView = deleteView;
45
+ this.setDefault = setDefault;
46
+ }
47
+ /** Every view this member may see for a list: their own plus the shared ones. */
48
+ async list(query, workspaceId, user) {
49
+ const actor = requireUser(user);
50
+ await this.scopes.assertReachable(query.scope, workspaceId);
51
+ return this.views.list(workspaceId, query.scope, actor.id);
52
+ }
53
+ /** Saves the current slice as a new view. */
54
+ async create(body, workspaceId, user) {
55
+ const actor = requireUser(user);
56
+ await this.scopes.assertReachable(body.scope, workspaceId);
57
+ try {
58
+ return await this.createView.execute({
59
+ workspaceId,
60
+ scope: body.scope,
61
+ name: body.name,
62
+ visibility: body.visibility ?? saved_view_1.VIEW_VISIBILITY.Private,
63
+ payload: body.payload,
64
+ makeDefault: body.makeDefault
65
+ }, actor);
66
+ }
67
+ catch (error) {
68
+ (0, to_http_error_1.toHttpError)(error);
69
+ }
70
+ }
71
+ /** Renames, re-shares, or re-captures a view the caller owns. */
72
+ async update(id, body, workspaceId, user) {
73
+ const actor = requireUser(user);
74
+ try {
75
+ return await this.updateView.execute(id, workspaceId, body, actor);
76
+ }
77
+ catch (error) {
78
+ (0, to_http_error_1.toHttpError)(error);
79
+ }
80
+ }
81
+ /** Deletes a view the caller owns. */
82
+ async remove(id, workspaceId, user) {
83
+ const actor = requireUser(user);
84
+ try {
85
+ await this.deleteView.execute(id, workspaceId, actor);
86
+ }
87
+ catch (error) {
88
+ (0, to_http_error_1.toHttpError)(error);
89
+ }
90
+ }
91
+ /** Lands this member on the view when they open the list. */
92
+ async makeDefault(id, workspaceId, user) {
93
+ const actor = requireUser(user);
94
+ try {
95
+ await this.setDefault.execute(id, workspaceId, actor);
96
+ }
97
+ catch (error) {
98
+ (0, to_http_error_1.toHttpError)(error);
99
+ }
100
+ }
101
+ /** Clears the caller's default, so the list opens unfiltered again. */
102
+ async clearDefault(id, workspaceId, user) {
103
+ const actor = requireUser(user);
104
+ try {
105
+ await this.setDefault.executeClear(id, workspaceId, actor);
106
+ }
107
+ catch (error) {
108
+ (0, to_http_error_1.toHttpError)(error);
109
+ }
110
+ }
111
+ };
112
+ exports.SavedViewsController = SavedViewsController;
113
+ tslib_1.__decorate([
114
+ (0, swagger_1.ApiOperation)({
115
+ summary: 'List the saved views for one content type',
116
+ description: 'Returns the caller’s own views at any visibility plus every workspace-shared view for the scope, ordered for the switcher.'
117
+ }),
118
+ (0, common_1.Get)(),
119
+ tslib_1.__param(0, (0, common_1.Query)()),
120
+ tslib_1.__param(1, (0, workspaces_server_1.CurrentWorkspace)()),
121
+ tslib_1.__param(2, (0, identity_server_1.CurrentUser)()),
122
+ tslib_1.__metadata("design:type", Function),
123
+ tslib_1.__metadata("design:paramtypes", [save_view_dto_1.ListViewsQueryDto, String, Object]),
124
+ tslib_1.__metadata("design:returntype", Promise)
125
+ ], SavedViewsController.prototype, "list", null);
126
+ tslib_1.__decorate([
127
+ (0, swagger_1.ApiOperation)({
128
+ summary: 'Save a new view',
129
+ description: 'Stores the filter/sort/columns slice under a name. `visibility: workspace` additionally requires `views:share`.'
130
+ }),
131
+ (0, common_1.Post)(),
132
+ tslib_1.__param(0, (0, common_1.Body)()),
133
+ tslib_1.__param(1, (0, workspaces_server_1.CurrentWorkspace)()),
134
+ tslib_1.__param(2, (0, identity_server_1.CurrentUser)()),
135
+ tslib_1.__metadata("design:type", Function),
136
+ tslib_1.__metadata("design:paramtypes", [save_view_dto_1.CreateViewDto, String, Object]),
137
+ tslib_1.__metadata("design:returntype", Promise)
138
+ ], SavedViewsController.prototype, "create", null);
139
+ tslib_1.__decorate([
140
+ (0, swagger_1.ApiOperation)({
141
+ summary: 'Update a saved view',
142
+ description: 'Owner-only. Send just the fields that change — `payload` on Save, `name` on a rename, `visibility` on share/unshare.'
143
+ }),
144
+ (0, common_1.Patch)(':id'),
145
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
146
+ tslib_1.__param(1, (0, common_1.Body)()),
147
+ tslib_1.__param(2, (0, workspaces_server_1.CurrentWorkspace)()),
148
+ tslib_1.__param(3, (0, identity_server_1.CurrentUser)()),
149
+ tslib_1.__metadata("design:type", Function),
150
+ tslib_1.__metadata("design:paramtypes", [String, save_view_dto_1.UpdateViewDto, String, Object]),
151
+ tslib_1.__metadata("design:returntype", Promise)
152
+ ], SavedViewsController.prototype, "update", null);
153
+ tslib_1.__decorate([
154
+ (0, swagger_1.ApiOperation)({
155
+ summary: 'Delete a saved view',
156
+ description: 'Owner-only. Any member’s default pointing at it is cleared by the cascade.'
157
+ }),
158
+ (0, common_1.Delete)(':id'),
159
+ (0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
160
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
161
+ tslib_1.__param(1, (0, workspaces_server_1.CurrentWorkspace)()),
162
+ tslib_1.__param(2, (0, identity_server_1.CurrentUser)()),
163
+ tslib_1.__metadata("design:type", Function),
164
+ tslib_1.__metadata("design:paramtypes", [String, String, Object]),
165
+ tslib_1.__metadata("design:returntype", Promise)
166
+ ], SavedViewsController.prototype, "remove", null);
167
+ tslib_1.__decorate([
168
+ (0, swagger_1.ApiOperation)({
169
+ summary: 'Make a view the caller’s default',
170
+ description: 'Not owner-gated: a default is the reader’s own landing choice, so any view they can see may be one.'
171
+ }),
172
+ (0, common_1.Put)(':id/default'),
173
+ (0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
174
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
175
+ tslib_1.__param(1, (0, workspaces_server_1.CurrentWorkspace)()),
176
+ tslib_1.__param(2, (0, identity_server_1.CurrentUser)()),
177
+ tslib_1.__metadata("design:type", Function),
178
+ tslib_1.__metadata("design:paramtypes", [String, String, Object]),
179
+ tslib_1.__metadata("design:returntype", Promise)
180
+ ], SavedViewsController.prototype, "makeDefault", null);
181
+ tslib_1.__decorate([
182
+ (0, swagger_1.ApiOperation)({
183
+ summary: 'Clear the caller’s default view',
184
+ description: 'The list then opens with no filter. Idempotent — clearing an absent default succeeds.'
185
+ }),
186
+ (0, common_1.Delete)(':id/default'),
187
+ (0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
188
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
189
+ tslib_1.__param(1, (0, workspaces_server_1.CurrentWorkspace)()),
190
+ tslib_1.__param(2, (0, identity_server_1.CurrentUser)()),
191
+ tslib_1.__metadata("design:type", Function),
192
+ tslib_1.__metadata("design:paramtypes", [String, String, Object]),
193
+ tslib_1.__metadata("design:returntype", Promise)
194
+ ], SavedViewsController.prototype, "clearDefault", null);
195
+ exports.SavedViewsController = SavedViewsController = tslib_1.__decorate([
196
+ (0, swagger_1.ApiTags)('views'),
197
+ (0, common_1.UseGuards)(identity_server_1.PermissionsGuard, workspaces_server_1.WorkspaceGuard),
198
+ (0, identity_server_1.RequirePermissions)(identity_server_1.PERMISSIONS.CONTENT_READ),
199
+ (0, common_1.Controller)('views'),
200
+ tslib_1.__metadata("design:paramtypes", [saved_views_query_1.SavedViewsQuery,
201
+ view_scope_service_1.ViewScopeService,
202
+ create_saved_view_use_case_1.CreateSavedViewUseCase,
203
+ update_saved_view_use_case_1.UpdateSavedViewUseCase,
204
+ delete_saved_view_use_case_1.DeleteSavedViewUseCase,
205
+ set_default_view_use_case_1.SetDefaultViewUseCase])
206
+ ], SavedViewsController);
207
+ /**
208
+ * Narrows the optional `@CurrentUser()` to a present one. Every route here is
209
+ * behind the app-wide `AuthGuard`, so this cannot fire in practice — it exists
210
+ * so the use-cases take a `PublicUser` rather than an optional one.
211
+ */
212
+ function requireUser(user) {
213
+ if (!user)
214
+ throw new common_1.UnauthorizedException();
215
+ return user;
216
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Maps the saved-view domain errors onto HTTP. Domain errors stay
3
+ * transport-agnostic (ADR-0003), so every controller funnels through this one
4
+ * translation rather than each restating the status codes.
5
+ *
6
+ * Anything unrecognised is rethrown untouched — swallowing it here would turn a
7
+ * genuine fault into a misleading 4xx.
8
+ */
9
+ export declare function toHttpError(error: unknown): never;
10
+ //# sourceMappingURL=to-http-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"to-http-error.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/http/controllers/to-http-error.ts"],"names":[],"mappings":"AAYA;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAcjD"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toHttpError = toHttpError;
4
+ const common_1 = require("@nestjs/common");
5
+ const errors_1 = require("../../domain/errors");
6
+ /**
7
+ * Maps the saved-view domain errors onto HTTP. Domain errors stay
8
+ * transport-agnostic (ADR-0003), so every controller funnels through this one
9
+ * translation rather than each restating the status codes.
10
+ *
11
+ * Anything unrecognised is rethrown untouched — swallowing it here would turn a
12
+ * genuine fault into a misleading 4xx.
13
+ */
14
+ function toHttpError(error) {
15
+ if (error instanceof errors_1.SavedViewNotFoundError) {
16
+ throw new common_1.NotFoundException(error.message);
17
+ }
18
+ if (error instanceof errors_1.SavedViewForbiddenError) {
19
+ throw new common_1.ForbiddenException(error.message);
20
+ }
21
+ if (error instanceof errors_1.SavedViewNameTakenError ||
22
+ error instanceof errors_1.SavedViewLimitError) {
23
+ throw new common_1.ConflictException(error.message);
24
+ }
25
+ throw error;
26
+ }
@@ -0,0 +1,54 @@
1
+ import { type ViewVisibility } from '../../domain/saved-view';
2
+ /**
3
+ * The slice a view stores. Mirrors the records page's URL params rather than
4
+ * re-modelling them, so a saved view and a hand-edited link travel the same
5
+ * code path. `search` and `page` are absent by design — see
6
+ * {@link SavedViewPayload}.
7
+ */
8
+ export declare class ViewPayloadDto {
9
+ /** The `?filter=` JSON string. */
10
+ filter?: string;
11
+ /** The `?sort=` spec. */
12
+ sort?: string;
13
+ /** Rows per page. */
14
+ pageSize?: number;
15
+ /** Visible column ids, in display order. */
16
+ columns?: string[];
17
+ /** Slot-owned list params (e.g. the i18n plugin's `locale`). */
18
+ extra?: Record<string, string>;
19
+ }
20
+ /** Body of `POST /api/views`. */
21
+ export declare class CreateViewDto {
22
+ /**
23
+ * The list this view is over. v1 accepts content collections only, so a
24
+ * typo cannot quietly create a view nothing will ever list.
25
+ */
26
+ scope: string;
27
+ /** Display name. */
28
+ name: string;
29
+ /** Who may see it. Defaults to private. */
30
+ visibility?: ViewVisibility;
31
+ /** The slice it restores. */
32
+ payload: ViewPayloadDto;
33
+ /** Whether to land on this view when opening the list. */
34
+ makeDefault?: boolean;
35
+ }
36
+ /**
37
+ * Body of `PATCH /api/views/:id`. Every field optional — the switcher sends
38
+ * only `payload` on “Save”, only `name` on a rename, and only `visibility` on
39
+ * share/unshare.
40
+ */
41
+ export declare class UpdateViewDto {
42
+ /** New display name. */
43
+ name?: string;
44
+ /** New visibility. */
45
+ visibility?: ViewVisibility;
46
+ /** New slice. */
47
+ payload?: ViewPayloadDto;
48
+ }
49
+ /** Query of `GET /api/views`. */
50
+ export declare class ListViewsQueryDto {
51
+ /** The list to return views for. */
52
+ scope: string;
53
+ }
54
+ //# sourceMappingURL=save-view.dto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save-view.dto.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/http/dto/save-view.dto.ts"],"names":[],"mappings":"AAuBA,OAAO,EAGH,KAAK,cAAc,EACtB,MAAM,yBAAyB,CAAC;AAUjC;;;;;GAKG;AACH,qBAAa,cAAc;IACvB,kCAAkC;IAYlC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,yBAAyB;IAWzB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,qBAAqB;IAYrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,4CAA4C;IAa5C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,gEAAgE;IAWhE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,iCAAiC;AACjC,qBAAa,aAAa;IACtB;;;OAGG;IAaH,KAAK,EAAG,MAAM,CAAC;IAEf,oBAAoB;IAcpB,IAAI,EAAG,MAAM,CAAC;IAEd,2CAA2C;IAS3C,UAAU,CAAC,EAAE,cAAc,CAAC;IAE5B,6BAA6B;IAO7B,OAAO,EAAG,cAAc,CAAC;IAEzB,0DAA0D;IAQ1D,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,qBAAa,aAAa;IACtB,wBAAwB;IAcxB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,sBAAsB;IAItB,UAAU,CAAC,EAAE,cAAc,CAAC;IAE5B,iBAAiB;IAKjB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED,iCAAiC;AACjC,qBAAa,iBAAiB;IAC1B,oCAAoC;IAapC,KAAK,EAAG,MAAM,CAAC;CAClB"}
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ListViewsQueryDto = exports.UpdateViewDto = exports.CreateViewDto = exports.ViewPayloadDto = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const swagger_1 = require("@nestjs/swagger");
6
+ const class_transformer_1 = require("class-transformer");
7
+ const class_validator_1 = require("class-validator");
8
+ const class_transformer_2 = require("class-transformer");
9
+ const entries_constants_1 = require("../../../entries/entries.constants");
10
+ const saved_view_1 = require("../../domain/saved-view");
11
+ const views_constants_1 = require("../../views.constants");
12
+ const view_payload_validator_1 = require("./view-payload.validator");
13
+ /**
14
+ * The slice a view stores. Mirrors the records page's URL params rather than
15
+ * re-modelling them, so a saved view and a hand-edited link travel the same
16
+ * code path. `search` and `page` are absent by design — see
17
+ * {@link SavedViewPayload}.
18
+ */
19
+ class ViewPayloadDto {
20
+ /** The `?filter=` JSON string. */
21
+ filter;
22
+ /** The `?sort=` spec. */
23
+ sort;
24
+ /** Rows per page. */
25
+ pageSize;
26
+ /** Visible column ids, in display order. */
27
+ columns;
28
+ /** Slot-owned list params (e.g. the i18n plugin's `locale`). */
29
+ extra;
30
+ }
31
+ exports.ViewPayloadDto = ViewPayloadDto;
32
+ tslib_1.__decorate([
33
+ (0, swagger_1.ApiPropertyOptional)({
34
+ type: String,
35
+ maxLength: entries_constants_1.FILTER_MAX_LENGTH,
36
+ example: '{"op":"and","rules":[{"field":"status","op":"eq","value":"review"}]}',
37
+ description: 'The filter tree as a JSON string, byte-identical to the `?filter=` query param. Stored opaquely and re-validated against the type when replayed.'
38
+ }),
39
+ (0, class_validator_1.IsOptional)(),
40
+ (0, class_validator_1.IsString)(),
41
+ (0, class_validator_1.MaxLength)(entries_constants_1.FILTER_MAX_LENGTH),
42
+ tslib_1.__metadata("design:type", String)
43
+ ], ViewPayloadDto.prototype, "filter", void 0);
44
+ tslib_1.__decorate([
45
+ (0, swagger_1.ApiPropertyOptional)({
46
+ type: String,
47
+ maxLength: 255,
48
+ example: '-updatedAt',
49
+ description: 'Sort spec: a column id (ascending) or `-`-prefixed (descending).'
50
+ }),
51
+ (0, class_validator_1.IsOptional)(),
52
+ (0, class_validator_1.IsString)(),
53
+ (0, class_validator_1.MaxLength)(255),
54
+ tslib_1.__metadata("design:type", String)
55
+ ], ViewPayloadDto.prototype, "sort", void 0);
56
+ tslib_1.__decorate([
57
+ (0, swagger_1.ApiPropertyOptional)({
58
+ type: 'integer',
59
+ minimum: 1,
60
+ maximum: entries_constants_1.MAX_PAGE_SIZE,
61
+ example: 25,
62
+ description: 'Rows per page this view opens with.'
63
+ }),
64
+ (0, class_validator_1.IsOptional)(),
65
+ (0, class_validator_1.IsInt)(),
66
+ (0, class_validator_1.Min)(1),
67
+ (0, class_validator_1.Max)(entries_constants_1.MAX_PAGE_SIZE),
68
+ tslib_1.__metadata("design:type", Number)
69
+ ], ViewPayloadDto.prototype, "pageSize", void 0);
70
+ tslib_1.__decorate([
71
+ (0, swagger_1.ApiPropertyOptional)({
72
+ type: [String],
73
+ maxItems: views_constants_1.VIEW_MAX_COLUMNS,
74
+ example: ['title', 'status', 'updatedAt'],
75
+ description: 'Visible column ids **in display order**. Ids the type no longer has are dropped when the view is applied.'
76
+ }),
77
+ (0, class_validator_1.IsOptional)(),
78
+ (0, class_validator_1.IsArray)(),
79
+ (0, class_validator_1.ArrayMaxSize)(views_constants_1.VIEW_MAX_COLUMNS),
80
+ (0, class_validator_1.IsString)({ each: true }),
81
+ (0, class_validator_1.MaxLength)(views_constants_1.VIEW_COLUMN_MAX_LENGTH, { each: true }),
82
+ tslib_1.__metadata("design:type", Array)
83
+ ], ViewPayloadDto.prototype, "columns", void 0);
84
+ tslib_1.__decorate([
85
+ (0, swagger_1.ApiPropertyOptional)({
86
+ type: 'object',
87
+ additionalProperties: { type: 'string' },
88
+ example: { locale: 'en' },
89
+ description: 'Slot-contributed list params, as a flat string map. Opaque on purpose — the keys come from plugin-registered toolbar items at runtime.'
90
+ }),
91
+ (0, class_validator_1.IsOptional)(),
92
+ (0, class_validator_1.IsObject)(),
93
+ (0, view_payload_validator_1.IsViewExtraParams)(),
94
+ tslib_1.__metadata("design:type", Object)
95
+ ], ViewPayloadDto.prototype, "extra", void 0);
96
+ /** Body of `POST /api/views`. */
97
+ class CreateViewDto {
98
+ /**
99
+ * The list this view is over. v1 accepts content collections only, so a
100
+ * typo cannot quietly create a view nothing will ever list.
101
+ */
102
+ scope;
103
+ /** Display name. */
104
+ name;
105
+ /** Who may see it. Defaults to private. */
106
+ visibility;
107
+ /** The slice it restores. */
108
+ payload;
109
+ /** Whether to land on this view when opening the list. */
110
+ makeDefault;
111
+ }
112
+ exports.CreateViewDto = CreateViewDto;
113
+ tslib_1.__decorate([
114
+ (0, swagger_1.ApiProperty)({
115
+ type: String,
116
+ maxLength: views_constants_1.VIEW_SCOPE_MAX_LENGTH,
117
+ example: 'content:article',
118
+ description: 'The list this view belongs to. Must be `content:<typeName>`.'
119
+ }),
120
+ (0, class_validator_1.IsString)(),
121
+ (0, class_validator_1.MaxLength)(views_constants_1.VIEW_SCOPE_MAX_LENGTH),
122
+ (0, class_validator_1.Matches)(new RegExp(`^${views_constants_1.CONTENT_SCOPE_PREFIX}[A-Za-z0-9_-]+$`), {
123
+ message: `scope must be "${views_constants_1.CONTENT_SCOPE_PREFIX}<typeName>"`
124
+ }),
125
+ tslib_1.__metadata("design:type", String)
126
+ ], CreateViewDto.prototype, "scope", void 0);
127
+ tslib_1.__decorate([
128
+ (0, swagger_1.ApiProperty)({
129
+ type: String,
130
+ minLength: 1,
131
+ maxLength: views_constants_1.VIEW_NAME_MAX_LENGTH,
132
+ example: 'Needs review',
133
+ description: 'Display name, unique per person within one list.'
134
+ }),
135
+ (0, class_validator_1.IsString)(),
136
+ (0, class_transformer_2.Transform)(({ value }) => typeof value === 'string' ? value.trim() : value),
137
+ (0, class_validator_1.MinLength)(1),
138
+ (0, class_validator_1.MaxLength)(views_constants_1.VIEW_NAME_MAX_LENGTH),
139
+ tslib_1.__metadata("design:type", String)
140
+ ], CreateViewDto.prototype, "name", void 0);
141
+ tslib_1.__decorate([
142
+ (0, swagger_1.ApiPropertyOptional)({
143
+ enum: saved_view_1.VIEW_VISIBILITY_VALUES,
144
+ default: saved_view_1.VIEW_VISIBILITY.Private,
145
+ description: '`private` (only you) or `workspace` (every member). Sharing requires the `views:share` permission.'
146
+ }),
147
+ (0, class_validator_1.IsOptional)(),
148
+ (0, class_validator_1.IsIn)(saved_view_1.VIEW_VISIBILITY_VALUES),
149
+ tslib_1.__metadata("design:type", String)
150
+ ], CreateViewDto.prototype, "visibility", void 0);
151
+ tslib_1.__decorate([
152
+ (0, swagger_1.ApiProperty)({
153
+ type: () => ViewPayloadDto,
154
+ description: 'The filter/sort/columns/page-size slice this view stores.'
155
+ }),
156
+ (0, class_validator_1.ValidateNested)(),
157
+ (0, class_transformer_1.Type)(() => ViewPayloadDto),
158
+ tslib_1.__metadata("design:type", ViewPayloadDto)
159
+ ], CreateViewDto.prototype, "payload", void 0);
160
+ tslib_1.__decorate([
161
+ (0, swagger_1.ApiPropertyOptional)({
162
+ type: Boolean,
163
+ default: false,
164
+ description: 'Make this the caller’s default view for the list.'
165
+ }),
166
+ (0, class_validator_1.IsOptional)(),
167
+ (0, class_validator_1.IsBoolean)(),
168
+ tslib_1.__metadata("design:type", Boolean)
169
+ ], CreateViewDto.prototype, "makeDefault", void 0);
170
+ /**
171
+ * Body of `PATCH /api/views/:id`. Every field optional — the switcher sends
172
+ * only `payload` on “Save”, only `name` on a rename, and only `visibility` on
173
+ * share/unshare.
174
+ */
175
+ class UpdateViewDto {
176
+ /** New display name. */
177
+ name;
178
+ /** New visibility. */
179
+ visibility;
180
+ /** New slice. */
181
+ payload;
182
+ }
183
+ exports.UpdateViewDto = UpdateViewDto;
184
+ tslib_1.__decorate([
185
+ (0, swagger_1.ApiPropertyOptional)({
186
+ type: String,
187
+ minLength: 1,
188
+ maxLength: views_constants_1.VIEW_NAME_MAX_LENGTH,
189
+ example: 'Needs review'
190
+ }),
191
+ (0, class_validator_1.IsOptional)(),
192
+ (0, class_validator_1.IsString)(),
193
+ (0, class_transformer_2.Transform)(({ value }) => typeof value === 'string' ? value.trim() : value),
194
+ (0, class_validator_1.MinLength)(1),
195
+ (0, class_validator_1.MaxLength)(views_constants_1.VIEW_NAME_MAX_LENGTH),
196
+ tslib_1.__metadata("design:type", String)
197
+ ], UpdateViewDto.prototype, "name", void 0);
198
+ tslib_1.__decorate([
199
+ (0, swagger_1.ApiPropertyOptional)({ enum: saved_view_1.VIEW_VISIBILITY_VALUES }),
200
+ (0, class_validator_1.IsOptional)(),
201
+ (0, class_validator_1.IsIn)(saved_view_1.VIEW_VISIBILITY_VALUES),
202
+ tslib_1.__metadata("design:type", String)
203
+ ], UpdateViewDto.prototype, "visibility", void 0);
204
+ tslib_1.__decorate([
205
+ (0, swagger_1.ApiPropertyOptional)({ type: () => ViewPayloadDto }),
206
+ (0, class_validator_1.IsOptional)(),
207
+ (0, class_validator_1.ValidateNested)(),
208
+ (0, class_transformer_1.Type)(() => ViewPayloadDto),
209
+ tslib_1.__metadata("design:type", ViewPayloadDto)
210
+ ], UpdateViewDto.prototype, "payload", void 0);
211
+ /** Query of `GET /api/views`. */
212
+ class ListViewsQueryDto {
213
+ /** The list to return views for. */
214
+ scope;
215
+ }
216
+ exports.ListViewsQueryDto = ListViewsQueryDto;
217
+ tslib_1.__decorate([
218
+ (0, swagger_1.ApiProperty)({
219
+ type: String,
220
+ maxLength: views_constants_1.VIEW_SCOPE_MAX_LENGTH,
221
+ example: 'content:article',
222
+ description: 'The list to return saved views for (`content:<typeName>`).'
223
+ }),
224
+ (0, class_validator_1.IsString)(),
225
+ (0, class_validator_1.MaxLength)(views_constants_1.VIEW_SCOPE_MAX_LENGTH),
226
+ (0, class_validator_1.Matches)(new RegExp(`^${views_constants_1.CONTENT_SCOPE_PREFIX}[A-Za-z0-9_-]+$`), {
227
+ message: `scope must be "${views_constants_1.CONTENT_SCOPE_PREFIX}<typeName>"`
228
+ }),
229
+ tslib_1.__metadata("design:type", String)
230
+ ], ListViewsQueryDto.prototype, "scope", void 0);
@@ -0,0 +1,20 @@
1
+ import { type ValidationOptions, type ValidatorConstraintInterface } from 'class-validator';
2
+ /**
3
+ * Validates a payload's `extra` bag: the slot-owned list params (the i18n
4
+ * plugin's `?locale=`, and whatever a later plugin contributes) as a flat
5
+ * string map.
6
+ *
7
+ * class-validator cannot decorate a `Record`'s dynamic keys, and the keys here
8
+ * are genuinely dynamic — they come from `RECORDS_TOOLBAR_SLOT.listParamKeys`
9
+ * at runtime, so naming them in a DTO would silently break the next plugin's
10
+ * params. What we can still enforce is the shape and a bound: flat, strings on
11
+ * both sides, and small. That turns a malformed bag into a clean 400 instead of
12
+ * a jsonb column quietly swallowing a nested object nothing can replay.
13
+ */
14
+ export declare class ViewExtraParamsConstraint implements ValidatorConstraintInterface {
15
+ validate(value: unknown): boolean;
16
+ defaultMessage(): string;
17
+ }
18
+ /** Applies {@link ViewExtraParamsConstraint} to a property. */
19
+ export declare function IsViewExtraParams(options?: ValidationOptions): (object: object, propertyName: string) => void;
20
+ //# sourceMappingURL=view-payload.validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-payload.validator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/http/dto/view-payload.validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,iBAAiB,EACtB,KAAK,4BAA4B,EACpC,MAAM,iBAAiB,CAAC;AAMzB;;;;;;;;;;;GAWG;AACH,qBACa,yBAA0B,YAAW,4BAA4B;IAC1E,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAcjC,cAAc,IAAI,MAAM;CAG3B;AAED,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,iBAAiB,IACxC,QAAQ,MAAM,EAAE,cAAc,MAAM,KAAG,IAAI,CAQ/D"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ViewExtraParamsConstraint = void 0;
4
+ exports.IsViewExtraParams = IsViewExtraParams;
5
+ const tslib_1 = require("tslib");
6
+ const class_validator_1 = require("class-validator");
7
+ const views_constants_1 = require("../../views.constants");
8
+ /**
9
+ * Validates a payload's `extra` bag: the slot-owned list params (the i18n
10
+ * plugin's `?locale=`, and whatever a later plugin contributes) as a flat
11
+ * string map.
12
+ *
13
+ * class-validator cannot decorate a `Record`'s dynamic keys, and the keys here
14
+ * are genuinely dynamic — they come from `RECORDS_TOOLBAR_SLOT.listParamKeys`
15
+ * at runtime, so naming them in a DTO would silently break the next plugin's
16
+ * params. What we can still enforce is the shape and a bound: flat, strings on
17
+ * both sides, and small. That turns a malformed bag into a clean 400 instead of
18
+ * a jsonb column quietly swallowing a nested object nothing can replay.
19
+ */
20
+ let ViewExtraParamsConstraint = class ViewExtraParamsConstraint {
21
+ validate(value) {
22
+ if (value === null || typeof value !== 'object')
23
+ return false;
24
+ if (Array.isArray(value))
25
+ return false;
26
+ const entries = Object.entries(value);
27
+ if (entries.length > views_constants_1.VIEW_MAX_EXTRA_KEYS)
28
+ return false;
29
+ return entries.every(([key, param]) => key.length > 0 &&
30
+ key.length <= views_constants_1.VIEW_EXTRA_MAX_LENGTH &&
31
+ typeof param === 'string' &&
32
+ param.length <= views_constants_1.VIEW_EXTRA_MAX_LENGTH);
33
+ }
34
+ defaultMessage() {
35
+ return `extra must be a flat map of at most ${views_constants_1.VIEW_MAX_EXTRA_KEYS} string values, each at most ${views_constants_1.VIEW_EXTRA_MAX_LENGTH} characters`;
36
+ }
37
+ };
38
+ exports.ViewExtraParamsConstraint = ViewExtraParamsConstraint;
39
+ exports.ViewExtraParamsConstraint = ViewExtraParamsConstraint = tslib_1.__decorate([
40
+ (0, class_validator_1.ValidatorConstraint)({ name: 'viewExtraParams' })
41
+ ], ViewExtraParamsConstraint);
42
+ /** Applies {@link ViewExtraParamsConstraint} to a property. */
43
+ function IsViewExtraParams(options) {
44
+ return function (object, propertyName) {
45
+ (0, class_validator_1.registerDecorator)({
46
+ target: object.constructor,
47
+ propertyName,
48
+ options,
49
+ validator: ViewExtraParamsConstraint
50
+ });
51
+ };
52
+ }
@@ -0,0 +1,26 @@
1
+ import { UnitOfWork } from '@orthacms/database';
2
+ import type { NewSavedView, SavedViewPatch, SavedViewRecord, SavedViewRepository } from '../../domain/saved-view.repository';
3
+ /** Drizzle adapter for {@link SavedViewRepository}. */
4
+ export declare class DrizzleSavedViewRepository implements SavedViewRepository {
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();
16
+ listVisible(workspaceId: string, scope: string, readerId: string): Promise<SavedViewRecord[]>;
17
+ findById(id: string): Promise<SavedViewRecord | null>;
18
+ countForOwner(workspaceId: string, scope: string, ownerId: string): Promise<number>;
19
+ create(view: NewSavedView): Promise<SavedViewRecord>;
20
+ update(id: string, patch: SavedViewPatch): Promise<SavedViewRecord>;
21
+ delete(id: string): Promise<void>;
22
+ findDefaultId(userId: string, scope: string): Promise<string | null>;
23
+ setDefault(userId: string, scope: string, viewId: string): Promise<void>;
24
+ clearDefault(userId: string, scope: string): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=drizzle-saved-view.repository.d.ts.map
@@ -0,0 +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,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"}