@orthacms/content-server 0.0.0-reserve.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 (396) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -0
  3. package/dist/define.d.ts +17 -0
  4. package/dist/define.d.ts.map +1 -0
  5. package/dist/define.js +28 -0
  6. package/dist/index.d.ts +48 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +109 -0
  9. package/dist/lib/collection/define.d.ts +35 -0
  10. package/dist/lib/collection/define.d.ts.map +1 -0
  11. package/dist/lib/collection/define.js +217 -0
  12. package/dist/lib/collection/table-builder.d.ts +28 -0
  13. package/dist/lib/collection/table-builder.d.ts.map +1 -0
  14. package/dist/lib/collection/table-builder.js +306 -0
  15. package/dist/lib/content-types/controllers/get-content-schema.controller.d.ts +24 -0
  16. package/dist/lib/content-types/controllers/get-content-schema.controller.d.ts.map +1 -0
  17. package/dist/lib/content-types/controllers/get-content-schema.controller.js +58 -0
  18. package/dist/lib/content-types/controllers/get-filter-fields.controller.d.ts +35 -0
  19. package/dist/lib/content-types/controllers/get-filter-fields.controller.d.ts.map +1 -0
  20. package/dist/lib/content-types/controllers/get-filter-fields.controller.js +74 -0
  21. package/dist/lib/content-types/controllers/list-content-schema.controller.d.ts +15 -0
  22. package/dist/lib/content-types/controllers/list-content-schema.controller.d.ts.map +1 -0
  23. package/dist/lib/content-types/controllers/list-content-schema.controller.js +38 -0
  24. package/dist/lib/content-types/queries/workspace-grants.query.d.ts +25 -0
  25. package/dist/lib/content-types/queries/workspace-grants.query.d.ts.map +1 -0
  26. package/dist/lib/content-types/queries/workspace-grants.query.js +45 -0
  27. package/dist/lib/content.module.d.ts +21 -0
  28. package/dist/lib/content.module.d.ts.map +1 -0
  29. package/dist/lib/content.module.js +264 -0
  30. package/dist/lib/content.tokens.d.ts +5 -0
  31. package/dist/lib/content.tokens.d.ts.map +1 -0
  32. package/dist/lib/content.tokens.js +9 -0
  33. package/dist/lib/copilot/content-tool.provider.d.ts +64 -0
  34. package/dist/lib/copilot/content-tool.provider.d.ts.map +1 -0
  35. package/dist/lib/copilot/content-tool.provider.js +309 -0
  36. package/dist/lib/copilot/diff-snapshots.d.ts +42 -0
  37. package/dist/lib/copilot/diff-snapshots.d.ts.map +1 -0
  38. package/dist/lib/copilot/diff-snapshots.js +77 -0
  39. package/dist/lib/copilot/entry-proposal.applier.d.ts +89 -0
  40. package/dist/lib/copilot/entry-proposal.applier.d.ts.map +1 -0
  41. package/dist/lib/copilot/entry-proposal.applier.js +245 -0
  42. package/dist/lib/copilot/entry-proposal.provider.d.ts +157 -0
  43. package/dist/lib/copilot/entry-proposal.provider.d.ts.map +1 -0
  44. package/dist/lib/copilot/entry-proposal.provider.js +619 -0
  45. package/dist/lib/copilot/filter-schema.d.ts +61 -0
  46. package/dist/lib/copilot/filter-schema.d.ts.map +1 -0
  47. package/dist/lib/copilot/filter-schema.js +139 -0
  48. package/dist/lib/copilot/project-entry.d.ts +23 -0
  49. package/dist/lib/copilot/project-entry.d.ts.map +1 -0
  50. package/dist/lib/copilot/project-entry.js +36 -0
  51. package/dist/lib/copilot/proposal-kinds.d.ts +30 -0
  52. package/dist/lib/copilot/proposal-kinds.d.ts.map +1 -0
  53. package/dist/lib/copilot/proposal-kinds.js +32 -0
  54. package/dist/lib/copilot/revision-tool.provider.d.ts +56 -0
  55. package/dist/lib/copilot/revision-tool.provider.d.ts.map +1 -0
  56. package/dist/lib/copilot/revision-tool.provider.js +215 -0
  57. package/dist/lib/docs/content-schemas.d.ts +34 -0
  58. package/dist/lib/docs/content-schemas.d.ts.map +1 -0
  59. package/dist/lib/docs/content-schemas.js +617 -0
  60. package/dist/lib/docs/describe-content-api.d.ts +22 -0
  61. package/dist/lib/docs/describe-content-api.d.ts.map +1 -0
  62. package/dist/lib/docs/describe-content-api.js +173 -0
  63. package/dist/lib/docs/field-schema.d.ts +28 -0
  64. package/dist/lib/docs/field-schema.d.ts.map +1 -0
  65. package/dist/lib/docs/field-schema.js +214 -0
  66. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.d.ts +23 -0
  67. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.d.ts.map +1 -0
  68. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.js +77 -0
  69. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.d.ts +23 -0
  70. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.d.ts.map +1 -0
  71. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.js +66 -0
  72. package/dist/lib/entries/application/use-cases/publish-entry.use-case.d.ts +43 -0
  73. package/dist/lib/entries/application/use-cases/publish-entry.use-case.d.ts.map +1 -0
  74. package/dist/lib/entries/application/use-cases/publish-entry.use-case.js +106 -0
  75. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.d.ts +30 -0
  76. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.d.ts.map +1 -0
  77. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.js +70 -0
  78. package/dist/lib/entries/controllers/bulk-entries.controller.d.ts +26 -0
  79. package/dist/lib/entries/controllers/bulk-entries.controller.d.ts.map +1 -0
  80. package/dist/lib/entries/controllers/create-entry.controller.d.ts +20 -0
  81. package/dist/lib/entries/controllers/create-entry.controller.d.ts.map +1 -0
  82. package/dist/lib/entries/controllers/delete-entry.controller.d.ts +24 -0
  83. package/dist/lib/entries/controllers/delete-entry.controller.d.ts.map +1 -0
  84. package/dist/lib/entries/controllers/get-entry.controller.d.ts +34 -0
  85. package/dist/lib/entries/controllers/get-entry.controller.d.ts.map +1 -0
  86. package/dist/lib/entries/controllers/list-entries.controller.d.ts +20 -0
  87. package/dist/lib/entries/controllers/list-entries.controller.d.ts.map +1 -0
  88. package/dist/lib/entries/controllers/publish-entry.controller.d.ts +19 -0
  89. package/dist/lib/entries/controllers/publish-entry.controller.d.ts.map +1 -0
  90. package/dist/lib/entries/controllers/resolve-type.d.ts +9 -0
  91. package/dist/lib/entries/controllers/resolve-type.d.ts.map +1 -0
  92. package/dist/lib/entries/controllers/update-entry.controller.d.ts +18 -0
  93. package/dist/lib/entries/controllers/update-entry.controller.d.ts.map +1 -0
  94. package/dist/lib/entries/domain/entry-publish-blocked.error.d.ts +13 -0
  95. package/dist/lib/entries/domain/entry-publish-blocked.error.d.ts.map +1 -0
  96. package/dist/lib/entries/domain/entry-publish-blocked.error.js +19 -0
  97. package/dist/lib/entries/domain/entry.d.ts +71 -0
  98. package/dist/lib/entries/domain/entry.d.ts.map +1 -0
  99. package/dist/lib/entries/domain/entry.js +90 -0
  100. package/dist/lib/entries/domain/events/entry-events.d.ts +67 -0
  101. package/dist/lib/entries/domain/events/entry-events.d.ts.map +1 -0
  102. package/dist/lib/entries/domain/events/entry-events.js +100 -0
  103. package/dist/lib/entries/dto/bulk-ids.dto.d.ts +11 -0
  104. package/dist/lib/entries/dto/bulk-ids.dto.d.ts.map +1 -0
  105. package/dist/lib/entries/dto/list-entries-query.dto.d.ts +46 -0
  106. package/dist/lib/entries/dto/list-entries-query.dto.d.ts.map +1 -0
  107. package/dist/lib/entries/dto/relation-delta-map.validator.d.ts +19 -0
  108. package/dist/lib/entries/dto/relation-delta-map.validator.d.ts.map +1 -0
  109. package/dist/lib/entries/dto/save-entry.dto.d.ts +46 -0
  110. package/dist/lib/entries/dto/save-entry.dto.d.ts.map +1 -0
  111. package/dist/lib/entries/entries.constants.d.ts +19 -0
  112. package/dist/lib/entries/entries.constants.d.ts.map +1 -0
  113. package/dist/lib/entries/entries.constants.js +21 -0
  114. package/dist/lib/entries/http/controllers/bulk-entries.controller.d.ts +33 -0
  115. package/dist/lib/entries/http/controllers/bulk-entries.controller.d.ts.map +1 -0
  116. package/dist/lib/entries/http/controllers/bulk-entries.controller.js +143 -0
  117. package/dist/lib/entries/http/controllers/create-entry.controller.d.ts +21 -0
  118. package/dist/lib/entries/http/controllers/create-entry.controller.d.ts.map +1 -0
  119. package/dist/lib/entries/http/controllers/create-entry.controller.js +52 -0
  120. package/dist/lib/entries/http/controllers/delete-entry.controller.d.ts +25 -0
  121. package/dist/lib/entries/http/controllers/delete-entry.controller.d.ts.map +1 -0
  122. package/dist/lib/entries/http/controllers/delete-entry.controller.js +84 -0
  123. package/dist/lib/entries/http/controllers/get-entry.controller.d.ts +44 -0
  124. package/dist/lib/entries/http/controllers/get-entry.controller.d.ts.map +1 -0
  125. package/dist/lib/entries/http/controllers/get-entry.controller.js +124 -0
  126. package/dist/lib/entries/http/controllers/list-entries.controller.d.ts +20 -0
  127. package/dist/lib/entries/http/controllers/list-entries.controller.d.ts.map +1 -0
  128. package/dist/lib/entries/http/controllers/list-entries.controller.js +52 -0
  129. package/dist/lib/entries/http/controllers/publish-entry.controller.d.ts +22 -0
  130. package/dist/lib/entries/http/controllers/publish-entry.controller.d.ts.map +1 -0
  131. package/dist/lib/entries/http/controllers/publish-entry.controller.js +68 -0
  132. package/dist/lib/entries/http/controllers/resolve-type.d.ts +9 -0
  133. package/dist/lib/entries/http/controllers/resolve-type.d.ts.map +1 -0
  134. package/dist/lib/entries/http/controllers/resolve-type.js +16 -0
  135. package/dist/lib/entries/http/controllers/to-actor.d.ts +13 -0
  136. package/dist/lib/entries/http/controllers/to-actor.d.ts.map +1 -0
  137. package/dist/lib/entries/http/controllers/to-actor.js +15 -0
  138. package/dist/lib/entries/http/controllers/update-entry.controller.d.ts +19 -0
  139. package/dist/lib/entries/http/controllers/update-entry.controller.d.ts.map +1 -0
  140. package/dist/lib/entries/http/controllers/update-entry.controller.js +51 -0
  141. package/dist/lib/entries/http/dto/bulk-ids.dto.d.ts +11 -0
  142. package/dist/lib/entries/http/dto/bulk-ids.dto.d.ts.map +1 -0
  143. package/dist/lib/entries/http/dto/bulk-ids.dto.js +33 -0
  144. package/dist/lib/entries/http/dto/list-entries-query.dto.d.ts +66 -0
  145. package/dist/lib/entries/http/dto/list-entries-query.dto.d.ts.map +1 -0
  146. package/dist/lib/entries/http/dto/list-entries-query.dto.js +192 -0
  147. package/dist/lib/entries/http/dto/relation-delta-map.validator.d.ts +30 -0
  148. package/dist/lib/entries/http/dto/relation-delta-map.validator.d.ts.map +1 -0
  149. package/dist/lib/entries/http/dto/relation-delta-map.validator.js +102 -0
  150. package/dist/lib/entries/http/dto/save-entry.dto.d.ts +48 -0
  151. package/dist/lib/entries/http/dto/save-entry.dto.d.ts.map +1 -0
  152. package/dist/lib/entries/http/dto/save-entry.dto.js +120 -0
  153. package/dist/lib/entries/http/guards/content-grant.guard.d.ts +37 -0
  154. package/dist/lib/entries/http/guards/content-grant.guard.d.ts.map +1 -0
  155. package/dist/lib/entries/http/guards/content-grant.guard.js +67 -0
  156. package/dist/lib/entries/infrastructure/persistence/bulk-publish-verdicts.d.ts +22 -0
  157. package/dist/lib/entries/infrastructure/persistence/bulk-publish-verdicts.d.ts.map +1 -0
  158. package/dist/lib/entries/infrastructure/persistence/bulk-publish-verdicts.js +81 -0
  159. package/dist/lib/entries/infrastructure/persistence/entry-counter.service.d.ts +42 -0
  160. package/dist/lib/entries/infrastructure/persistence/entry-counter.service.d.ts.map +1 -0
  161. package/dist/lib/entries/infrastructure/persistence/entry-counter.service.js +73 -0
  162. package/dist/lib/entries/infrastructure/persistence/entry-row.d.ts +56 -0
  163. package/dist/lib/entries/infrastructure/persistence/entry-row.d.ts.map +1 -0
  164. package/dist/lib/entries/infrastructure/persistence/entry-row.js +185 -0
  165. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts +392 -0
  166. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts.map +1 -0
  167. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.js +1223 -0
  168. package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts +24 -0
  169. package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts.map +1 -0
  170. package/dist/lib/entries/infrastructure/persistence/media-accept.d.ts +23 -0
  171. package/dist/lib/entries/infrastructure/persistence/media-accept.d.ts.map +1 -0
  172. package/dist/lib/entries/infrastructure/persistence/media-accept.js +55 -0
  173. package/dist/lib/entries/infrastructure/persistence/relation-link.service.d.ts +327 -0
  174. package/dist/lib/entries/infrastructure/persistence/relation-link.service.d.ts.map +1 -0
  175. package/dist/lib/entries/infrastructure/persistence/relation-link.service.js +1008 -0
  176. package/dist/lib/entries/infrastructure/queries/bulk-publish-preview.query.d.ts +19 -0
  177. package/dist/lib/entries/infrastructure/queries/bulk-publish-preview.query.d.ts.map +1 -0
  178. package/dist/lib/entries/infrastructure/queries/bulk-publish-preview.query.js +39 -0
  179. package/dist/lib/entries/infrastructure/queries/entries.service.d.ts +64 -0
  180. package/dist/lib/entries/infrastructure/queries/entries.service.d.ts.map +1 -0
  181. package/dist/lib/entries/infrastructure/queries/entries.service.js +202 -0
  182. package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts +40 -0
  183. package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts.map +1 -0
  184. package/dist/lib/entries/infrastructure/queries/entry-filter-surface.d.ts +38 -0
  185. package/dist/lib/entries/infrastructure/queries/entry-filter-surface.d.ts.map +1 -0
  186. package/dist/lib/entries/infrastructure/queries/entry-filter-surface.js +310 -0
  187. package/dist/lib/entries/infrastructure/queries/entry-scalar-fields.d.ts +25 -0
  188. package/dist/lib/entries/infrastructure/queries/entry-scalar-fields.d.ts.map +1 -0
  189. package/dist/lib/entries/infrastructure/queries/entry-scalar-fields.js +51 -0
  190. package/dist/lib/entries/infrastructure/queries/entry-search.d.ts +19 -0
  191. package/dist/lib/entries/infrastructure/queries/entry-search.d.ts.map +1 -0
  192. package/dist/lib/entries/infrastructure/queries/entry-search.js +52 -0
  193. package/dist/lib/entries/infrastructure/queries/media-refs.query.d.ts +21 -0
  194. package/dist/lib/entries/infrastructure/queries/media-refs.query.d.ts.map +1 -0
  195. package/dist/lib/entries/infrastructure/queries/media-refs.query.js +117 -0
  196. package/dist/lib/entries/services/entries.service.d.ts +59 -0
  197. package/dist/lib/entries/services/entries.service.d.ts.map +1 -0
  198. package/dist/lib/entries/services/entry-counter.service.d.ts +31 -0
  199. package/dist/lib/entries/services/entry-counter.service.d.ts.map +1 -0
  200. package/dist/lib/entries/services/entry-filter-schema.d.ts +32 -0
  201. package/dist/lib/entries/services/entry-filter-schema.d.ts.map +1 -0
  202. package/dist/lib/entries/services/entry-row.d.ts +56 -0
  203. package/dist/lib/entries/services/entry-row.d.ts.map +1 -0
  204. package/dist/lib/entries/services/entry-writer.service.d.ts +193 -0
  205. package/dist/lib/entries/services/entry-writer.service.d.ts.map +1 -0
  206. package/dist/lib/entries/services/relation-link.service.d.ts +115 -0
  207. package/dist/lib/entries/services/relation-link.service.d.ts.map +1 -0
  208. package/dist/lib/entries/types/bulk-publish.d.ts +75 -0
  209. package/dist/lib/entries/types/bulk-publish.d.ts.map +1 -0
  210. package/dist/lib/entries/types/bulk-publish.js +22 -0
  211. package/dist/lib/entries/types/entry-list-view.d.ts +205 -0
  212. package/dist/lib/entries/types/entry-list-view.d.ts.map +1 -0
  213. package/dist/lib/entries/types/entry-list-view.js +5 -0
  214. package/dist/lib/entries/types/filter-surface.d.ts +35 -0
  215. package/dist/lib/entries/types/filter-surface.d.ts.map +1 -0
  216. package/dist/lib/entries/types/filter-surface.js +2 -0
  217. package/dist/lib/extension/entry-extension-boot-check.d.ts +16 -0
  218. package/dist/lib/extension/entry-extension-boot-check.d.ts.map +1 -0
  219. package/dist/lib/extension/entry-extension-boot-check.js +42 -0
  220. package/dist/lib/extension/entry-extension.d.ts +225 -0
  221. package/dist/lib/extension/entry-extension.d.ts.map +1 -0
  222. package/dist/lib/extension/entry-extension.js +27 -0
  223. package/dist/lib/extension/media-asset-resolver.d.ts +85 -0
  224. package/dist/lib/extension/media-asset-resolver.d.ts.map +1 -0
  225. package/dist/lib/extension/media-asset-resolver.js +26 -0
  226. package/dist/lib/extension/per-locale-relation.d.ts +18 -0
  227. package/dist/lib/extension/per-locale-relation.d.ts.map +1 -0
  228. package/dist/lib/extension/relation-locale-sync.d.ts +62 -0
  229. package/dist/lib/extension/relation-locale-sync.d.ts.map +1 -0
  230. package/dist/lib/extension/relation-locale-sync.js +88 -0
  231. package/dist/lib/fields/index.d.ts +94 -0
  232. package/dist/lib/fields/index.d.ts.map +1 -0
  233. package/dist/lib/fields/index.js +203 -0
  234. package/dist/lib/insights/http/controllers/content-pipeline.controller.d.ts +16 -0
  235. package/dist/lib/insights/http/controllers/content-pipeline.controller.d.ts.map +1 -0
  236. package/dist/lib/insights/http/controllers/content-pipeline.controller.js +39 -0
  237. package/dist/lib/insights/http/controllers/content-punchcard.controller.d.ts +18 -0
  238. package/dist/lib/insights/http/controllers/content-punchcard.controller.d.ts.map +1 -0
  239. package/dist/lib/insights/http/controllers/content-punchcard.controller.js +42 -0
  240. package/dist/lib/insights/http/controllers/content-stale.controller.d.ts +17 -0
  241. package/dist/lib/insights/http/controllers/content-stale.controller.d.ts.map +1 -0
  242. package/dist/lib/insights/http/controllers/content-stale.controller.js +40 -0
  243. package/dist/lib/insights/http/controllers/content-totals.controller.d.ts +18 -0
  244. package/dist/lib/insights/http/controllers/content-totals.controller.d.ts.map +1 -0
  245. package/dist/lib/insights/http/controllers/content-totals.controller.js +42 -0
  246. package/dist/lib/insights/http/controllers/content-unshipped.controller.d.ts +17 -0
  247. package/dist/lib/insights/http/controllers/content-unshipped.controller.d.ts.map +1 -0
  248. package/dist/lib/insights/http/controllers/content-unshipped.controller.js +40 -0
  249. package/dist/lib/insights/http/controllers/content-velocity.controller.d.ts +17 -0
  250. package/dist/lib/insights/http/controllers/content-velocity.controller.d.ts.map +1 -0
  251. package/dist/lib/insights/http/controllers/content-velocity.controller.js +41 -0
  252. package/dist/lib/insights/http/dto/insights-range-query.dto.d.ts +15 -0
  253. package/dist/lib/insights/http/dto/insights-range-query.dto.d.ts.map +1 -0
  254. package/dist/lib/insights/http/dto/insights-range-query.dto.js +38 -0
  255. package/dist/lib/insights/infrastructure/queries/content-insights.query.d.ts +77 -0
  256. package/dist/lib/insights/infrastructure/queries/content-insights.query.d.ts.map +1 -0
  257. package/dist/lib/insights/infrastructure/queries/content-insights.query.js +380 -0
  258. package/dist/lib/insights/types/content-insights-view.d.ts +134 -0
  259. package/dist/lib/insights/types/content-insights-view.d.ts.map +1 -0
  260. package/dist/lib/insights/types/content-insights-view.js +10 -0
  261. package/dist/lib/mcp/content-tools.provider.d.ts +83 -0
  262. package/dist/lib/mcp/content-tools.provider.d.ts.map +1 -0
  263. package/dist/lib/mcp/content-tools.provider.js +441 -0
  264. package/dist/lib/mcp/tool-input.d.ts +43 -0
  265. package/dist/lib/mcp/tool-input.d.ts.map +1 -0
  266. package/dist/lib/mcp/tool-input.js +117 -0
  267. package/dist/lib/mcp/tool-schemas.d.ts +34 -0
  268. package/dist/lib/mcp/tool-schemas.d.ts.map +1 -0
  269. package/dist/lib/mcp/tool-schemas.js +282 -0
  270. package/dist/lib/public/controllers/get-public-entry.controller.d.ts +26 -0
  271. package/dist/lib/public/controllers/get-public-entry.controller.d.ts.map +1 -0
  272. package/dist/lib/public/controllers/list-public-entries.controller.d.ts +24 -0
  273. package/dist/lib/public/controllers/list-public-entries.controller.d.ts.map +1 -0
  274. package/dist/lib/public/controllers/public-schema.controller.d.ts +18 -0
  275. package/dist/lib/public/controllers/public-schema.controller.d.ts.map +1 -0
  276. package/dist/lib/public-api/http/api-token-request.d.ts +41 -0
  277. package/dist/lib/public-api/http/api-token-request.d.ts.map +1 -0
  278. package/dist/lib/public-api/http/api-token-request.js +2 -0
  279. package/dist/lib/public-api/http/controllers/public-content-types.controller.d.ts +31 -0
  280. package/dist/lib/public-api/http/controllers/public-content-types.controller.d.ts.map +1 -0
  281. package/dist/lib/public-api/http/controllers/public-content-types.controller.js +93 -0
  282. package/dist/lib/public-api/http/controllers/public-entries.controller.d.ts +101 -0
  283. package/dist/lib/public-api/http/controllers/public-entries.controller.d.ts.map +1 -0
  284. package/dist/lib/public-api/http/controllers/public-entries.controller.js +307 -0
  285. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts +76 -0
  286. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts.map +1 -0
  287. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.js +353 -0
  288. package/dist/lib/public-api/http/controllers/resolve-granted-type.d.ts +42 -0
  289. package/dist/lib/public-api/http/controllers/resolve-granted-type.d.ts.map +1 -0
  290. package/dist/lib/public-api/http/controllers/resolve-granted-type.js +25 -0
  291. package/dist/lib/public-api/http/decorators/current-api-token.decorator.d.ts +8 -0
  292. package/dist/lib/public-api/http/decorators/current-api-token.decorator.d.ts.map +1 -0
  293. package/dist/lib/public-api/http/decorators/current-api-token.decorator.js +17 -0
  294. package/dist/lib/public-api/http/dto/public-bulk.dto.d.ts +58 -0
  295. package/dist/lib/public-api/http/dto/public-bulk.dto.d.ts.map +1 -0
  296. package/dist/lib/public-api/http/dto/public-bulk.dto.js +118 -0
  297. package/dist/lib/public-api/http/dto/public-list-entries-query.dto.d.ts +106 -0
  298. package/dist/lib/public-api/http/dto/public-list-entries-query.dto.d.ts.map +1 -0
  299. package/dist/lib/public-api/http/dto/public-list-entries-query.dto.js +297 -0
  300. package/dist/lib/public-api/http/dto/public-save-entry.dto.d.ts +39 -0
  301. package/dist/lib/public-api/http/dto/public-save-entry.dto.d.ts.map +1 -0
  302. package/dist/lib/public-api/http/dto/public-save-entry.dto.js +112 -0
  303. package/dist/lib/public-api/http/guards/api-token-workspace.guard.d.ts +25 -0
  304. package/dist/lib/public-api/http/guards/api-token-workspace.guard.d.ts.map +1 -0
  305. package/dist/lib/public-api/http/guards/api-token-workspace.guard.js +58 -0
  306. package/dist/lib/public-api/http/guards/api-token.guard.d.ts +32 -0
  307. package/dist/lib/public-api/http/guards/api-token.guard.d.ts.map +1 -0
  308. package/dist/lib/public-api/http/guards/api-token.guard.js +92 -0
  309. package/dist/lib/public-api/http/guards/draft-visibility.guard.d.ts +25 -0
  310. package/dist/lib/public-api/http/guards/draft-visibility.guard.d.ts.map +1 -0
  311. package/dist/lib/public-api/http/guards/draft-visibility.guard.js +56 -0
  312. package/dist/lib/public-api/infrastructure/bulk-save-op.d.ts +55 -0
  313. package/dist/lib/public-api/infrastructure/bulk-save-op.d.ts.map +1 -0
  314. package/dist/lib/public-api/infrastructure/bulk-save-op.js +61 -0
  315. package/dist/lib/public-api/infrastructure/field-selection.d.ts +21 -0
  316. package/dist/lib/public-api/infrastructure/field-selection.d.ts.map +1 -0
  317. package/dist/lib/public-api/infrastructure/field-selection.js +72 -0
  318. package/dist/lib/public-api/infrastructure/public-entries.query.d.ts +248 -0
  319. package/dist/lib/public-api/infrastructure/public-entries.query.d.ts.map +1 -0
  320. package/dist/lib/public-api/infrastructure/public-entries.query.js +557 -0
  321. package/dist/lib/public-api/infrastructure/public-entry-row.d.ts +31 -0
  322. package/dist/lib/public-api/infrastructure/public-entry-row.d.ts.map +1 -0
  323. package/dist/lib/public-api/infrastructure/public-entry-row.js +76 -0
  324. package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts +188 -0
  325. package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts.map +1 -0
  326. package/dist/lib/public-api/infrastructure/public-entry-writes.service.js +321 -0
  327. package/dist/lib/public-api/infrastructure/public-expansion.query.d.ts +98 -0
  328. package/dist/lib/public-api/infrastructure/public-expansion.query.d.ts.map +1 -0
  329. package/dist/lib/public-api/infrastructure/public-expansion.query.js +384 -0
  330. package/dist/lib/public-api/types/public-bulk.d.ts +77 -0
  331. package/dist/lib/public-api/types/public-bulk.d.ts.map +1 -0
  332. package/dist/lib/public-api/types/public-bulk.js +23 -0
  333. package/dist/lib/public-api/types/public-entry.d.ts +97 -0
  334. package/dist/lib/public-api/types/public-entry.d.ts.map +1 -0
  335. package/dist/lib/public-api/types/public-entry.js +8 -0
  336. package/dist/lib/public-api/types/public-expansion.d.ts +92 -0
  337. package/dist/lib/public-api/types/public-expansion.d.ts.map +1 -0
  338. package/dist/lib/public-api/types/public-expansion.js +2 -0
  339. package/dist/lib/registry/content-type-registry.d.ts +103 -0
  340. package/dist/lib/registry/content-type-registry.d.ts.map +1 -0
  341. package/dist/lib/registry/content-type-registry.js +155 -0
  342. package/dist/lib/revisions/application/ports/revision-store.d.ts +71 -0
  343. package/dist/lib/revisions/application/ports/revision-store.d.ts.map +1 -0
  344. package/dist/lib/revisions/application/ports/revision-store.js +9 -0
  345. package/dist/lib/revisions/application/use-cases/publish-revision.use-case.d.ts +40 -0
  346. package/dist/lib/revisions/application/use-cases/publish-revision.use-case.d.ts.map +1 -0
  347. package/dist/lib/revisions/application/use-cases/publish-revision.use-case.js +66 -0
  348. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.d.ts +36 -0
  349. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.d.ts.map +1 -0
  350. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.js +57 -0
  351. package/dist/lib/revisions/domain/revision-status.d.ts +18 -0
  352. package/dist/lib/revisions/domain/revision-status.d.ts.map +1 -0
  353. package/dist/lib/revisions/domain/revision-status.js +18 -0
  354. package/dist/lib/revisions/domain/revision.d.ts +80 -0
  355. package/dist/lib/revisions/domain/revision.d.ts.map +1 -0
  356. package/dist/lib/revisions/domain/revision.js +84 -0
  357. package/dist/lib/revisions/http/controllers/publish-revision.controller.d.ts +19 -0
  358. package/dist/lib/revisions/http/controllers/publish-revision.controller.d.ts.map +1 -0
  359. package/dist/lib/revisions/http/controllers/publish-revision.controller.js +51 -0
  360. package/dist/lib/revisions/http/controllers/restore-revision.controller.d.ts +17 -0
  361. package/dist/lib/revisions/http/controllers/restore-revision.controller.d.ts.map +1 -0
  362. package/dist/lib/revisions/http/controllers/restore-revision.controller.js +49 -0
  363. package/dist/lib/revisions/http/controllers/revisions.controller.d.ts +20 -0
  364. package/dist/lib/revisions/http/controllers/revisions.controller.d.ts.map +1 -0
  365. package/dist/lib/revisions/http/controllers/revisions.controller.js +76 -0
  366. package/dist/lib/revisions/infrastructure/persistence/drizzle-revision.store.d.ts +33 -0
  367. package/dist/lib/revisions/infrastructure/persistence/drizzle-revision.store.d.ts.map +1 -0
  368. package/dist/lib/revisions/infrastructure/persistence/drizzle-revision.store.js +174 -0
  369. package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.d.ts +17 -0
  370. package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.d.ts.map +1 -0
  371. package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.js +20 -0
  372. package/dist/lib/revisions/infrastructure/persistence/revision-table.d.ts +228 -0
  373. package/dist/lib/revisions/infrastructure/persistence/revision-table.d.ts.map +1 -0
  374. package/dist/lib/revisions/infrastructure/persistence/revision-table.js +57 -0
  375. package/dist/lib/revisions/infrastructure/queries/revision-refs.query.d.ts +22 -0
  376. package/dist/lib/revisions/infrastructure/queries/revision-refs.query.d.ts.map +1 -0
  377. package/dist/lib/revisions/infrastructure/queries/revision-refs.query.js +66 -0
  378. package/dist/lib/revisions/revisions.constants.d.ts +10 -0
  379. package/dist/lib/revisions/revisions.constants.d.ts.map +1 -0
  380. package/dist/lib/revisions/revisions.constants.js +12 -0
  381. package/dist/lib/revisions/types/revision-view.d.ts +74 -0
  382. package/dist/lib/revisions/types/revision-view.d.ts.map +1 -0
  383. package/dist/lib/revisions/types/revision-view.js +2 -0
  384. package/dist/lib/types/content-type.d.ts +131 -0
  385. package/dist/lib/types/content-type.d.ts.map +1 -0
  386. package/dist/lib/types/content-type.js +28 -0
  387. package/dist/lib/types/fields.d.ts +303 -0
  388. package/dist/lib/types/fields.d.ts.map +1 -0
  389. package/dist/lib/types/fields.js +52 -0
  390. package/dist/lib/utils/content-plugin.d.ts +35 -0
  391. package/dist/lib/utils/content-plugin.d.ts.map +1 -0
  392. package/dist/lib/utils/content-plugin.js +35 -0
  393. package/dist/lib/validation/services/entry-validation.service.d.ts +24 -0
  394. package/dist/lib/validation/services/entry-validation.service.d.ts.map +1 -0
  395. package/dist/lib/validation/services/entry-validation.service.js +35 -0
  396. package/package.json +54 -0
@@ -0,0 +1,310 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildEntryFilterSurface = buildEntryFilterSurface;
4
+ const drizzle_orm_1 = require("drizzle-orm");
5
+ const utils_server_1 = require("@orthacms/utils-server");
6
+ const content_type_1 = require("../../../types/content-type");
7
+ const fields_1 = require("../../../types/fields");
8
+ // `scalarTypeFor` is the single scalar-coercion mapping — shared with the
9
+ // sort whitelist (`isScalarField`), so "filterable" and "sortable" can't
10
+ // disagree on which field types are backed by a comparable column.
11
+ const entry_scalar_fields_1 = require("./entry-scalar-fields");
12
+ /**
13
+ * Relation hops offered by default. 2 hops means `author.company.name` is
14
+ * reachable and `…company.country.name` is not. Each hop is an EXISTS
15
+ * subquery, so this directly bounds worst-case query cost. The engine's
16
+ * `maxDepth` counts path SEGMENTS (hops + 1), so it is derived as
17
+ * `hops + 1` below — raising one without the other would let the picker
18
+ * offer paths the parser rejects with a 400.
19
+ */
20
+ const DEFAULT_RELATION_HOPS = 2;
21
+ /** Humanize a field name — mirrors the admin's `fieldLabel` fallback. */
22
+ function humanize(name) {
23
+ return name
24
+ .replace(/[_-]+/g, ' ')
25
+ .replace(/([a-z\d])([A-Z])/g, '$1 $2')
26
+ .replace(/^\w/, (c) => c.toUpperCase());
27
+ }
28
+ /** A field's display label — its admin label, else a humanized name. */
29
+ function fieldLabel(name, spec) {
30
+ const label = spec.admin?.label;
31
+ return typeof label === 'string' && label.length > 0
32
+ ? label
33
+ : humanize(name);
34
+ }
35
+ /**
36
+ * Resolve a column on a generated table by its JS property name.
37
+ *
38
+ * `Object.hasOwn`-guarded, and it throws rather than returning `undefined`.
39
+ * Every caller today passes a literal or a name off `Object.entries(type.fields)`,
40
+ * so nothing request-supplied reaches it — but drizzle's column map is a plain
41
+ * object, an unguarded lookup resolves `constructor`/`valueOf`/`toString` to
42
+ * truthy non-columns, and handing one of those to drizzle as a `Column` emits a
43
+ * broken fragment (a 500) rather than failing here. Its `utils-server`
44
+ * counterpart (`columnOf`) is guarded the same way, so the two helpers can't
45
+ * disagree about what a name means.
46
+ */
47
+ function col(table, name) {
48
+ const cols = (0, drizzle_orm_1.getTableColumns)(table);
49
+ const column = Object.hasOwn(cols, name) ? cols[name] : undefined;
50
+ if (!column) {
51
+ throw new utils_server_1.FilterSchemaException(`column "${name}" does not exist on the generated table`);
52
+ }
53
+ return column;
54
+ }
55
+ /**
56
+ * The scope predicate for one target type: the workspace boundary plus the
57
+ * soft-delete guard, resolved against whatever table the translator queries
58
+ * (the physical target, or an alias for a self-relation). Without this a
59
+ * relation filter matches rows the root list itself excludes — a
60
+ * soft-deleted author would still match `author.name`.
61
+ *
62
+ * Publish status is deliberately NOT filtered here: an editor filtering
63
+ * articles by author expects to match a draft author, and hiding
64
+ * unpublished targets would silently drop rows. A published-only traversal
65
+ * is expressible as an explicit `author.status` rule instead.
66
+ */
67
+ function scopeFor(target, workspaceId) {
68
+ return (tbl) => {
69
+ const cols = (0, drizzle_orm_1.getTableColumns)(tbl);
70
+ return (0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(cols['workspaceId'], workspaceId), target.paranoid ? (0, drizzle_orm_1.isNull)(cols['deletedAt']) : undefined);
71
+ };
72
+ }
73
+ /** The scalar (envelope + field) whitelist for one type at one level. */
74
+ function scalarFieldsOf(type) {
75
+ const fields = {
76
+ // `id` so a relation's record picker (`author.id in (…)`) resolves,
77
+ // and the envelope timestamps so they stay API-filterable.
78
+ id: { type: utils_server_1.ScalarFieldType.Uuid },
79
+ createdAt: { type: utils_server_1.ScalarFieldType.Date },
80
+ updatedAt: { type: utils_server_1.ScalarFieldType.Date }
81
+ };
82
+ if (type.publishable) {
83
+ fields['status'] = {
84
+ type: utils_server_1.ScalarFieldType.Enum,
85
+ enumValues: [content_type_1.ENTRY_STATUS.Draft, content_type_1.ENTRY_STATUS.Published]
86
+ };
87
+ fields['publishedAt'] = { type: utils_server_1.ScalarFieldType.Date };
88
+ }
89
+ if (type.i18n) {
90
+ fields['locale'] = { type: utils_server_1.ScalarFieldType.String };
91
+ // The translation-group key, so a caller holding one row's group can
92
+ // ask for the group's row in another locale (`localeGroupId eq X` +
93
+ // `?locale=de`). Whitelisted for SQL only — `scalarWireOf` below builds
94
+ // the admin's filter *picker*, and this envelope column stays out of
95
+ // it, so the UI is unchanged.
96
+ fields['localeGroupId'] = { type: utils_server_1.ScalarFieldType.Uuid };
97
+ }
98
+ for (const [name, spec] of Object.entries(type.fields)) {
99
+ const scalar = (0, entry_scalar_fields_1.scalarTypeFor)(spec);
100
+ if (scalar)
101
+ fields[name] = scalar;
102
+ }
103
+ return fields;
104
+ }
105
+ /** The wire fields the picker shows at one level: user scalars + status. */
106
+ function scalarWireOf(type, path, group, wire) {
107
+ if (type.publishable) {
108
+ wire.push({
109
+ path: [...path, 'status'].join('.'),
110
+ label: 'Status',
111
+ type: utils_server_1.ScalarFieldType.Enum,
112
+ enumValues: [content_type_1.ENTRY_STATUS.Draft, content_type_1.ENTRY_STATUS.Published],
113
+ group
114
+ });
115
+ }
116
+ for (const [name, spec] of Object.entries(type.fields)) {
117
+ const scalar = (0, entry_scalar_fields_1.scalarTypeFor)(spec);
118
+ if (!scalar)
119
+ continue;
120
+ wire.push({
121
+ path: [...path, name].join('.'),
122
+ label: fieldLabel(name, spec),
123
+ type: scalar.type,
124
+ enumValues: scalar.enumValues,
125
+ group
126
+ });
127
+ }
128
+ }
129
+ /**
130
+ * Build one relation's `RelationSchema`, recursing into the target's own
131
+ * relations while hops remain, and pushing the wire fields for the target
132
+ * level as it goes. Returns `null` to omit the relation entirely (ungranted
133
+ * target, a cycle back to an ancestor, or a self-referential shape not yet
134
+ * supported).
135
+ */
136
+ function relationFor(name, spec, owner, path, group, hopsLeft, visited, ctx) {
137
+ const rel = spec.relation;
138
+ if (!rel)
139
+ return null;
140
+ // `to()` is the target for an owning side, the OWNER of the storage for
141
+ // an inverse — either way, the type this hop traverses to.
142
+ const target = rel.to();
143
+ if (ctx.grantedTypes && !ctx.grantedTypes.has(target.name))
144
+ return null;
145
+ const selfRef = target.name === owner.name;
146
+ // A cycle back to an ANCESTOR is never a filter a user wants. A
147
+ // self-reference is allowed (page trees) and bounded by hops instead.
148
+ if (!selfRef && visited.has(target.name))
149
+ return null;
150
+ const relLabel = fieldLabel(name, spec);
151
+ const nextPath = [...path, name];
152
+ const nextGroup = [...group, relLabel];
153
+ // The relation's record-picker entry: `author.id`, rendered as a picker
154
+ // over `target` rather than a raw uuid input.
155
+ ctx.wire.push({
156
+ path: [...nextPath, 'id'].join('.'),
157
+ label: relLabel,
158
+ type: utils_server_1.ScalarFieldType.Uuid,
159
+ group: nextGroup,
160
+ relationTarget: target.name
161
+ });
162
+ // The target's own scalar fields + (if hops remain) its relations. This
163
+ // is the SAME walk that emits the wire fields, so the SQL whitelist and
164
+ // the picker's field list are one traversal and cannot drift.
165
+ const nested = walk(target, nextPath, nextGroup, hopsLeft - 1, visited, ctx);
166
+ const common = {
167
+ fields: nested.fields,
168
+ relations: nested.relations,
169
+ scope: scopeFor(target, ctx.workspaceId)
170
+ };
171
+ const ownerT = owner.table;
172
+ const targetT = target.table;
173
+ // ---- inverse: storage lives on the owning side, reused swapped ----
174
+ if (rel.inverse) {
175
+ const ownerField = rel.inverse.field;
176
+ const ownerSpec = target.fields[ownerField];
177
+ if (!ownerSpec?.relation)
178
+ return null;
179
+ if (ownerSpec.relation.many) {
180
+ // Inverse of a many-to-many: OUR rows are the join's targets.
181
+ if (selfRef)
182
+ return null; // self many-to-many — not supported yet
183
+ const join = target.joinTables[ownerField];
184
+ if (!join)
185
+ return null;
186
+ return {
187
+ kind: utils_server_1.RelationKind.ManyToMany,
188
+ through: join,
189
+ fk: col(join, 'targetId'),
190
+ targetFk: col(join, 'sourceId'),
191
+ table: target.table,
192
+ parentKey: col(ownerT, 'id'),
193
+ targetKey: col(targetT, 'id'),
194
+ ...common
195
+ };
196
+ }
197
+ // Inverse of a single = one-to-many: the owner's FK points at us.
198
+ return {
199
+ kind: utils_server_1.RelationKind.OneToMany,
200
+ table: target.table,
201
+ fk: col(targetT, ownerField),
202
+ parentKey: col(ownerT, 'id'),
203
+ ...common
204
+ };
205
+ }
206
+ // ---- owning many-to-many ----
207
+ if (rel.many) {
208
+ if (selfRef)
209
+ return null; // self many-to-many — not supported yet
210
+ const join = owner.joinTables[name];
211
+ if (!join)
212
+ return null;
213
+ return {
214
+ kind: utils_server_1.RelationKind.ManyToMany,
215
+ through: join,
216
+ fk: col(join, 'sourceId'),
217
+ targetFk: col(join, 'targetId'),
218
+ table: target.table,
219
+ parentKey: col(ownerT, 'id'),
220
+ targetKey: col(targetT, 'id'),
221
+ ...common
222
+ };
223
+ }
224
+ // ---- owning single ----
225
+ if (selfRef) {
226
+ return {
227
+ kind: utils_server_1.RelationKind.SelfReferential,
228
+ table: target.table,
229
+ fk: col(ownerT, name),
230
+ // Unique per OCCURRENCE, not per relation: two rules on the same
231
+ // self-relation must not share a correlation name.
232
+ alias: `qb_${nextPath.join('__')}`,
233
+ ...common
234
+ };
235
+ }
236
+ return {
237
+ kind: utils_server_1.RelationKind.ManyToOne,
238
+ table: target.table,
239
+ fk: col(ownerT, name),
240
+ targetKey: col(targetT, 'id'),
241
+ ...common
242
+ };
243
+ }
244
+ /**
245
+ * One node of the surface: the scalar fields filterable at this level and
246
+ * the relations traversable from it. Emits the wire fields for this level
247
+ * as a side effect on `ctx.wire`, so the SQL whitelist (the return value)
248
+ * and the picker's field list (the accumulator) are produced by a single
249
+ * traversal.
250
+ */
251
+ function walk(type, path, group, hopsLeft, visited, ctx) {
252
+ const fields = scalarFieldsOf(type);
253
+ scalarWireOf(type, path, group, ctx.wire);
254
+ if (hopsLeft <= 0)
255
+ return { fields };
256
+ const nextVisited = new Set([...visited, type.name]);
257
+ const relations = {};
258
+ for (const [name, spec] of Object.entries(type.fields)) {
259
+ if (spec.type !== fields_1.CONTENT_FIELD_TYPE.Relation)
260
+ continue;
261
+ const r = relationFor(name, spec, type, path, group, hopsLeft, nextVisited, ctx);
262
+ if (r)
263
+ relations[name] = r;
264
+ }
265
+ return {
266
+ fields,
267
+ relations: Object.keys(relations).length ? relations : undefined
268
+ };
269
+ }
270
+ /**
271
+ * The filterable surface for one content type: the Drizzle `FilterSchema`
272
+ * (the security boundary — only listed paths reach SQL) AND the flat
273
+ * `WireFilterField[]` the admin's query builder renders, produced by a
274
+ * single traversal so they cannot drift.
275
+ *
276
+ * `extensionFields` are virtual fields contributed by the bound
277
+ * `CONTENT_ENTRY_EXTENSION` (locale aggregates, …): they merge into the
278
+ * root `fields` (so the parser can coerce their values) and their names are
279
+ * registered on `extensionFields` (so the translator routes them to the
280
+ * extension's own SQL resolver). A real column always wins a name clash.
281
+ * They are NOT surfaced as wire fields here — a contributing plugin adds
282
+ * those via the admin's `RECORDS_FILTER_FIELDS_SLOT`, as today.
283
+ */
284
+ function buildEntryFilterSurface(type, opts) {
285
+ const hops = opts.maxRelationHops ?? DEFAULT_RELATION_HOPS;
286
+ const ctx = {
287
+ workspaceId: opts.workspaceId,
288
+ grantedTypes: opts.grantedTypes,
289
+ wire: []
290
+ };
291
+ const root = walk(type, [], [], hops, new Set(), ctx);
292
+ const schema = {
293
+ fields: root.fields,
294
+ relations: root.relations,
295
+ // Path SEGMENTS = hops + 1 (`author.company.name` is 3 at 2 hops),
296
+ // so the engine cap must track the traversal cap or it silently
297
+ // rejects paths the picker offers.
298
+ maxDepth: hops + 1
299
+ };
300
+ if (opts.extensionFields) {
301
+ const merged = schema.fields ?? {};
302
+ const extra = Object.keys(opts.extensionFields).filter((n) => !(n in merged));
303
+ for (const n of extra)
304
+ merged[n] = opts.extensionFields[n];
305
+ schema.fields = merged;
306
+ if (extra.length)
307
+ schema.extensionFields = new Set(extra);
308
+ }
309
+ return { schema, fields: ctx.wire };
310
+ }
@@ -0,0 +1,25 @@
1
+ import { type ScalarFieldSchema } from '@orthacms/utils-server';
2
+ import { type AnyFieldSpec } from '../../../types/fields';
3
+ /**
4
+ * The filter scalar type for one content field, or `null` to leave it
5
+ * unfilterable. Mirrors the admin's `filterFieldsFromSchema`: text fields
6
+ * filter as strings, `select` as an enum of its options, numerics as numbers,
7
+ * dates as dates. `json`/`multiselect`/`media` have no scalar editor, and
8
+ * `relation` filtering (by raw FK uuid) has no UI yet — all skipped.
9
+ *
10
+ * `richtext` is skipped too, and deliberately: a body is a **document**, so
11
+ * `equals`/`starts with` over it would be comparing one serialization of a
12
+ * node tree against another rather than comparing prose. Free-text `?search=`
13
+ * still reaches it — see `isTextLike` — which is the question a reader
14
+ * actually asks of a body.
15
+ */
16
+ export declare function scalarTypeFor(spec: AnyFieldSpec): ScalarFieldSchema | null;
17
+ /**
18
+ * Whether a field is backed by a comparable scalar column — the single source of
19
+ * truth for "can this field be filtered or sorted". `richtext`/`json`/
20
+ * `multiselect` (jsonb) and `relation` (FK uuid / join table) are not: they have
21
+ * no scalar editor and ordering them is meaningless. The sort whitelist and the filter schema both
22
+ * derive from this, so the two can't drift apart.
23
+ */
24
+ export declare function isScalarField(spec: AnyFieldSpec): boolean;
25
+ //# sourceMappingURL=entry-scalar-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-scalar-fields.d.ts","sourceRoot":"","sources":["../../../../../src/lib/entries/infrastructure/queries/entry-scalar-fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,KAAK,iBAAiB,EACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,iBAAiB,GAAG,IAAI,CAqB1E;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAEzD"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scalarTypeFor = scalarTypeFor;
4
+ exports.isScalarField = isScalarField;
5
+ const utils_server_1 = require("@orthacms/utils-server");
6
+ const fields_1 = require("../../../types/fields");
7
+ /**
8
+ * The filter scalar type for one content field, or `null` to leave it
9
+ * unfilterable. Mirrors the admin's `filterFieldsFromSchema`: text fields
10
+ * filter as strings, `select` as an enum of its options, numerics as numbers,
11
+ * dates as dates. `json`/`multiselect`/`media` have no scalar editor, and
12
+ * `relation` filtering (by raw FK uuid) has no UI yet — all skipped.
13
+ *
14
+ * `richtext` is skipped too, and deliberately: a body is a **document**, so
15
+ * `equals`/`starts with` over it would be comparing one serialization of a
16
+ * node tree against another rather than comparing prose. Free-text `?search=`
17
+ * still reaches it — see `isTextLike` — which is the question a reader
18
+ * actually asks of a body.
19
+ */
20
+ function scalarTypeFor(spec) {
21
+ switch (spec.type) {
22
+ case fields_1.CONTENT_FIELD_TYPE.Text:
23
+ return { type: utils_server_1.ScalarFieldType.String };
24
+ case fields_1.CONTENT_FIELD_TYPE.Select:
25
+ return {
26
+ type: utils_server_1.ScalarFieldType.Enum,
27
+ enumValues: spec.options ?? []
28
+ };
29
+ case fields_1.CONTENT_FIELD_TYPE.Number:
30
+ case fields_1.CONTENT_FIELD_TYPE.Money:
31
+ return { type: utils_server_1.ScalarFieldType.Number };
32
+ case fields_1.CONTENT_FIELD_TYPE.Boolean:
33
+ return { type: utils_server_1.ScalarFieldType.Boolean };
34
+ case fields_1.CONTENT_FIELD_TYPE.Date:
35
+ case fields_1.CONTENT_FIELD_TYPE.Datetime:
36
+ return { type: utils_server_1.ScalarFieldType.Date };
37
+ default:
38
+ // richtext / json / multiselect / media / relation
39
+ return null;
40
+ }
41
+ }
42
+ /**
43
+ * Whether a field is backed by a comparable scalar column — the single source of
44
+ * truth for "can this field be filtered or sorted". `richtext`/`json`/
45
+ * `multiselect` (jsonb) and `relation` (FK uuid / join table) are not: they have
46
+ * no scalar editor and ordering them is meaningless. The sort whitelist and the filter schema both
47
+ * derive from this, so the two can't drift apart.
48
+ */
49
+ function isScalarField(spec) {
50
+ return scalarTypeFor(spec) !== null;
51
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The free-text `?search=` predicate, shared by the admin entries list and the
3
+ * public content API so the two can't drift on which columns are searched or —
4
+ * more importantly — on how the needle is escaped.
5
+ */
6
+ import { type SQL } from 'drizzle-orm';
7
+ import type { AnyContentType } from '../../../types/content-type';
8
+ import { type AnyFieldSpec } from '../../../types/fields';
9
+ /** Columns the free-text search scans (they hold searchable textual content). */
10
+ export declare function isTextLike(spec: AnyFieldSpec): boolean;
11
+ /**
12
+ * Case-insensitive `ILIKE` across the type's text-like columns, OR-ed together;
13
+ * `undefined` when there is no search term (so it collapses out of an `and()`).
14
+ *
15
+ * The needle's LIKE metacharacters are escaped, so a literal `%` or `_`
16
+ * searches literally instead of turning the query into a wildcard scan.
17
+ */
18
+ export declare function buildSearchPredicate(type: AnyContentType, search: string | undefined): SQL | undefined;
19
+ //# sourceMappingURL=entry-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-search.d.ts","sourceRoot":"","sources":["../../../../../src/lib/entries/infrastructure/queries/entry-search.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAkC,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAK9E,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAMtD;AAmBD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAChC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,MAAM,GAAG,SAAS,GAC3B,GAAG,GAAG,SAAS,CAWjB"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * The free-text `?search=` predicate, shared by the admin entries list and the
4
+ * public content API so the two can't drift on which columns are searched or —
5
+ * more importantly — on how the needle is escaped.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.isTextLike = isTextLike;
9
+ exports.buildSearchPredicate = buildSearchPredicate;
10
+ const drizzle_orm_1 = require("drizzle-orm");
11
+ const fields_1 = require("../../../types/fields");
12
+ /** Columns the free-text search scans (they hold searchable textual content). */
13
+ function isTextLike(spec) {
14
+ return (spec.type === fields_1.CONTENT_FIELD_TYPE.Text ||
15
+ spec.type === fields_1.CONTENT_FIELD_TYPE.RichText ||
16
+ spec.type === fields_1.CONTENT_FIELD_TYPE.Select);
17
+ }
18
+ /**
19
+ * The expression a text-like column is matched against.
20
+ *
21
+ * A `richtext` body is a **document** in a `jsonb` column, and `ILIKE` has no
22
+ * meaning against `jsonb` — so it is cast to text and the search runs over the
23
+ * serialized tree. That reaches the words, which is what a reader is looking
24
+ * for; the cost is that a needle spelling one of the tree's own key names
25
+ * (`paragraph`, `heading`) can match a body that never says it. Searching the
26
+ * *text* properly wants a stored, indexed projection of it — worth doing when
27
+ * search is next revisited, and much more than a cast.
28
+ */
29
+ function searchable(spec, column) {
30
+ return spec.type === fields_1.CONTENT_FIELD_TYPE.RichText
31
+ ? (0, drizzle_orm_1.sql) `${column}::text`
32
+ : column;
33
+ }
34
+ /**
35
+ * Case-insensitive `ILIKE` across the type's text-like columns, OR-ed together;
36
+ * `undefined` when there is no search term (so it collapses out of an `and()`).
37
+ *
38
+ * The needle's LIKE metacharacters are escaped, so a literal `%` or `_`
39
+ * searches literally instead of turning the query into a wildcard scan.
40
+ */
41
+ function buildSearchPredicate(type, search) {
42
+ const needle = search?.trim();
43
+ if (!needle) {
44
+ return undefined;
45
+ }
46
+ const table = type.table;
47
+ const pattern = `%${needle.replace(/[\\%_]/g, '\\$&')}%`;
48
+ const clauses = Object.entries(type.fields)
49
+ .filter(([, spec]) => isTextLike(spec))
50
+ .map(([name, spec]) => (0, drizzle_orm_1.ilike)(searchable(spec, table[name]), pattern));
51
+ return clauses.length ? (0, drizzle_orm_1.or)(...clauses) : undefined;
52
+ }
@@ -0,0 +1,21 @@
1
+ import type { AnyContentType } from '../../../types/content-type';
2
+ import { type MediaAssetResolver } from '../../../extension/media-asset-resolver';
3
+ import type { MediaRef } from '../../types/entry-list-view';
4
+ /**
5
+ * Resolves the media fields of a `values` bag to display refs — the assets the
6
+ * admin renders (name / thumbnail url / kind) instead of raw uuids. One batched
7
+ * resolver lookup across every media id; an asset that can't be resolved
8
+ * (deleted / cross-workspace) is kept **in order** as an id-only `missing` ref,
9
+ * so a `multiple` field's list never runs shorter than what was stored.
10
+ *
11
+ * Shared by the entry-editor read (`GET …/:id/media`, against the live row's
12
+ * values) and the revision preview (against a snapshot's values), so the two
13
+ * can't drift. A no-op returning `{}` when no media resolver is bound.
14
+ */
15
+ export declare class MediaRefsQuery {
16
+ private readonly resolver?;
17
+ constructor(resolver?: MediaAssetResolver | undefined);
18
+ /** Resolve every media field's ids in `values` to ordered {@link MediaRef}s. */
19
+ forValues(type: AnyContentType, values: Record<string, unknown>, workspaceId: string): Promise<Record<string, MediaRef[]>>;
20
+ }
21
+ //# sourceMappingURL=media-refs.query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-refs.query.d.ts","sourceRoot":"","sources":["../../../../../src/lib/entries/infrastructure/queries/media-refs.query.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,EAEH,KAAK,kBAAkB,EAC1B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,qBACa,cAAc;IAInB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAT,QAAQ,CAAC,EAAE,kBAAkB,YAAA;IAGlD,gFAAgF;IAC1E,SAAS,CACX,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;CAkEzC"}
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MediaRefsQuery = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const content_domain_1 = require("@orthacms/content-domain");
7
+ const fields_1 = require("../../../types/fields");
8
+ const media_asset_resolver_1 = require("../../../extension/media-asset-resolver");
9
+ /**
10
+ * Resolves the media fields of a `values` bag to display refs — the assets the
11
+ * admin renders (name / thumbnail url / kind) instead of raw uuids. One batched
12
+ * resolver lookup across every media id; an asset that can't be resolved
13
+ * (deleted / cross-workspace) is kept **in order** as an id-only `missing` ref,
14
+ * so a `multiple` field's list never runs shorter than what was stored.
15
+ *
16
+ * Shared by the entry-editor read (`GET …/:id/media`, against the live row's
17
+ * values) and the revision preview (against a snapshot's values), so the two
18
+ * can't drift. A no-op returning `{}` when no media resolver is bound.
19
+ */
20
+ let MediaRefsQuery = class MediaRefsQuery {
21
+ resolver;
22
+ constructor(resolver) {
23
+ this.resolver = resolver;
24
+ }
25
+ /** Resolve every media field's ids in `values` to ordered {@link MediaRef}s. */
26
+ async forValues(type, values, workspaceId) {
27
+ const out = {};
28
+ if (!this.resolver)
29
+ return out;
30
+ // The **refs**, not just the ids: a media value has carried a
31
+ // per-usage `alt` and a `decorative` flag since `ORT-83`, and the whole
32
+ // point of putting them on the value is that they override the asset
33
+ // row's own description for *this* usage.
34
+ const byField = {};
35
+ const all = new Set();
36
+ for (const [name, spec] of Object.entries(type.fields)) {
37
+ if (spec.type !== fields_1.CONTENT_FIELD_TYPE.Media)
38
+ continue;
39
+ const value = values[name];
40
+ const refs = (Array.isArray(value) ? value : [value])
41
+ .map(content_domain_1.toMediaValueRef)
42
+ .filter((ref) => ref !== null && !!ref.id);
43
+ if (!refs.length)
44
+ continue;
45
+ byField[name] = refs;
46
+ for (const ref of refs)
47
+ all.add(ref.id);
48
+ }
49
+ if (!all.size)
50
+ return out;
51
+ const resolved = await this.resolver.resolve([...all], workspaceId);
52
+ for (const [name, refs] of Object.entries(byField)) {
53
+ out[name] = refs.map((ref) => {
54
+ const id = ref.id;
55
+ const asset = resolved.get(id);
56
+ return asset
57
+ ? {
58
+ id: asset.id,
59
+ name: asset.name,
60
+ url: asset.url,
61
+ // Only when the resolver has them — an asset with no
62
+ // derivative keeps the ref clean rather than carrying
63
+ // an undefined the admin has to test twice.
64
+ ...(asset.thumbUrl
65
+ ? { thumbUrl: asset.thumbUrl }
66
+ : {}),
67
+ ...(asset.previewUrl
68
+ ? { previewUrl: asset.previewUrl }
69
+ : {}),
70
+ kind: asset.kind,
71
+ mimeType: asset.mimeType,
72
+ // Per-usage wins over the asset's default, and
73
+ // `decorative` beats both: an image the author marked
74
+ // presentational *here* publishes with an empty `alt`
75
+ // however it is described in the library.
76
+ alt: usageAlt(ref, asset.alt),
77
+ ...(ref.decorative === true
78
+ ? { decorative: true }
79
+ : {})
80
+ }
81
+ : {
82
+ id,
83
+ name: id,
84
+ url: '',
85
+ kind: '',
86
+ mimeType: '',
87
+ missing: true
88
+ };
89
+ });
90
+ }
91
+ return out;
92
+ }
93
+ };
94
+ exports.MediaRefsQuery = MediaRefsQuery;
95
+ exports.MediaRefsQuery = MediaRefsQuery = tslib_1.__decorate([
96
+ (0, common_1.Injectable)(),
97
+ tslib_1.__param(0, (0, common_1.Optional)()),
98
+ tslib_1.__param(0, (0, media_asset_resolver_1.InjectMediaAssetResolver)()),
99
+ tslib_1.__metadata("design:paramtypes", [Object])
100
+ ], MediaRefsQuery);
101
+ /**
102
+ * The alt text this usage should publish with.
103
+ *
104
+ * `decorative` wins outright and resolves to an empty string — the value an
105
+ * `<img alt="">` needs to be skipped by a screen reader, which is a different
106
+ * claim from having no `alt` attribute at all. Otherwise a per-usage `alt`
107
+ * overrides the asset row's default, and a usage that said nothing falls back to
108
+ * it. Alt text is per usage, not per asset: the same logo is "Acme logo" in a
109
+ * header and decorative in a footer strip (`ORT-83`).
110
+ */
111
+ function usageAlt(ref, assetAlt) {
112
+ if (ref.decorative === true)
113
+ return '';
114
+ if (typeof ref.alt === 'string' && ref.alt.trim() !== '')
115
+ return ref.alt;
116
+ return assetAlt;
117
+ }
@@ -0,0 +1,59 @@
1
+ import { type Database } from '@ortha-cms/database';
2
+ import { type ContentEntryExtension } from '../../extension/entry-extension';
3
+ import type { AnyContentType } from '../../types/content-type';
4
+ import { type ListEntriesQueryDto } from '../dto/list-entries-query.dto';
5
+ import type { EntryListView } from '../types/entry-list-view';
6
+ /**
7
+ * Reads a collection's entries. Generic over the content type: the physical
8
+ * table, the filterable columns, the searchable columns, and the sort whitelist
9
+ * are all derived from `type` at request time, so one service backs every
10
+ * collection. Owns no schema of its own — it queries the HOST-owned generated
11
+ * `content_<name>` tables through the shared Drizzle client.
12
+ */
13
+ export declare class EntriesService {
14
+ private readonly db;
15
+ private readonly extension?;
16
+ constructor(db: Database, extension?: ContentEntryExtension | undefined);
17
+ /**
18
+ * One page of a collection's entries: search → filter → sort → paginate, run
19
+ * in SQL against the type's generated table, returned as the
20
+ * `{ items, total, page, pageSize }` envelope the admin records table renders.
21
+ * Scoped to `workspaceId` — only the calling workspace's entries are counted
22
+ * or listed.
23
+ */
24
+ list(type: AnyContentType, query: ListEntriesQueryDto, workspaceId: string): Promise<EntryListView>;
25
+ /**
26
+ * The full WHERE: the workspace scope AND free-text search AND the
27
+ * query-builder `?filter=` tree AND (for paranoid types) the not-deleted
28
+ * guard. `and(undefined, …)` collapses empties, so an unfiltered list still
29
+ * scans the workspace's whole table. The workspace predicate is always
30
+ * present, so an entry never leaks across workspaces. A malformed filter
31
+ * throws a `FilterException` (HTTP 400).
32
+ */
33
+ private listWhere;
34
+ /**
35
+ * The soft-delete guard for paranoid types: the default list excludes
36
+ * tombstoned rows (`deleted_at IS NULL`); `?deleted=only` flips to the trash
37
+ * view (`deleted_at IS NOT NULL`). A non-paranoid type has no `deleted_at`,
38
+ * so the predicate collapses to `undefined`.
39
+ */
40
+ private deletedPredicate;
41
+ /**
42
+ * Case-insensitive `ILIKE` across the type's text-like columns, OR-ed
43
+ * together; `undefined` when there's no search term. The needle's LIKE
44
+ * metacharacters are escaped so a literal `%`/`_` searches literally.
45
+ */
46
+ private searchPredicate;
47
+ /**
48
+ * Translate the `?sort=` spec (`col` asc, `-col` desc) into an ORDER BY,
49
+ * always with an `id` tiebreaker so pagination is stable across requests.
50
+ * Sortable = the always-present envelope columns + `status` (publishable
51
+ * only) + the type's **scalar** fields. Non-scalar fields (`json`/
52
+ * `multiselect`, single/many `relation`) are excluded — a many-relation has
53
+ * no column on the main table at all, so ordering by it would pass
54
+ * `undefined` to `asc`/`desc`; the others have no meaningful order. An
55
+ * unknown or excluded column falls back to `updatedAt` desc.
56
+ */
57
+ private orderBy;
58
+ }
59
+ //# sourceMappingURL=entries.service.d.ts.map