@orthacms/content-server 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4 -1
  4. package/dist/lib/content.module.d.ts.map +1 -1
  5. package/dist/lib/content.module.js +8 -0
  6. package/dist/lib/copilot/entry-proposal.applier.d.ts.map +1 -1
  7. package/dist/lib/copilot/entry-proposal.applier.js +5 -4
  8. package/dist/lib/docs/describe-content-api.d.ts +7 -0
  9. package/dist/lib/docs/describe-content-api.d.ts.map +1 -1
  10. package/dist/lib/docs/describe-content-api.js +177 -53
  11. package/dist/lib/docs/describe-views-api.d.ts +19 -0
  12. package/dist/lib/docs/describe-views-api.d.ts.map +1 -0
  13. package/dist/lib/docs/describe-views-api.js +76 -0
  14. package/dist/lib/docs/field-schema.d.ts.map +1 -1
  15. package/dist/lib/docs/field-schema.js +36 -2
  16. package/dist/lib/docs/openapi-writer.d.ts +49 -0
  17. package/dist/lib/docs/openapi-writer.d.ts.map +1 -0
  18. package/dist/lib/docs/openapi-writer.js +76 -0
  19. package/dist/lib/docs/public-api-schemas.d.ts +45 -0
  20. package/dist/lib/docs/public-api-schemas.d.ts.map +1 -0
  21. package/dist/lib/docs/public-api-schemas.js +377 -0
  22. package/dist/lib/docs/views-schemas.d.ts +22 -0
  23. package/dist/lib/docs/views-schemas.d.ts.map +1 -0
  24. package/dist/lib/docs/views-schemas.js +156 -0
  25. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.d.ts +8 -2
  26. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.d.ts.map +1 -1
  27. package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.js +19 -4
  28. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.d.ts +2 -2
  29. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.d.ts.map +1 -1
  30. package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.js +14 -4
  31. package/dist/lib/entries/application/use-cases/publish-entry.use-case.d.ts +6 -8
  32. package/dist/lib/entries/application/use-cases/publish-entry.use-case.d.ts.map +1 -1
  33. package/dist/lib/entries/application/use-cases/publish-entry.use-case.js +10 -4
  34. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.d.ts +2 -5
  35. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.d.ts.map +1 -1
  36. package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.js +6 -1
  37. package/dist/lib/entries/domain/entry.d.ts +8 -1
  38. package/dist/lib/entries/domain/entry.d.ts.map +1 -1
  39. package/dist/lib/entries/domain/entry.js +12 -12
  40. package/dist/lib/entries/domain/events/entry-events.d.ts +47 -5
  41. package/dist/lib/entries/domain/events/entry-events.d.ts.map +1 -1
  42. package/dist/lib/entries/domain/events/entry-events.js +26 -10
  43. package/dist/lib/entries/entries.constants.d.ts +10 -2
  44. package/dist/lib/entries/entries.constants.d.ts.map +1 -1
  45. package/dist/lib/entries/entries.constants.js +11 -2
  46. package/dist/lib/entries/http/controllers/bulk-entries.controller.d.ts +2 -2
  47. package/dist/lib/entries/http/controllers/bulk-entries.controller.d.ts.map +1 -1
  48. package/dist/lib/entries/http/controllers/bulk-entries.controller.js +8 -6
  49. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts +22 -6
  50. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts.map +1 -1
  51. package/dist/lib/entries/infrastructure/persistence/entry-writer.service.js +71 -17
  52. package/dist/lib/insights/docs/describe-content-insights-api.d.ts +23 -0
  53. package/dist/lib/insights/docs/describe-content-insights-api.d.ts.map +1 -0
  54. package/dist/lib/insights/docs/describe-content-insights-api.js +329 -0
  55. package/dist/lib/mcp/content-tools.provider.d.ts.map +1 -1
  56. package/dist/lib/mcp/content-tools.provider.js +10 -9
  57. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts +14 -13
  58. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts.map +1 -1
  59. package/dist/lib/public-api/http/controllers/public-entry-writes.controller.js +62 -46
  60. package/dist/lib/public-api/http/guards/api-token-workspace.guard.d.ts.map +1 -1
  61. package/dist/lib/public-api/http/guards/api-token-workspace.guard.js +8 -0
  62. package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts +10 -9
  63. package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts.map +1 -1
  64. package/dist/lib/public-api/infrastructure/public-entry-writes.service.js +23 -24
  65. package/dist/lib/public-api/infrastructure/token-actor.d.ts +37 -0
  66. package/dist/lib/public-api/infrastructure/token-actor.d.ts.map +1 -0
  67. package/dist/lib/public-api/infrastructure/token-actor.js +58 -0
  68. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.d.ts.map +1 -1
  69. package/dist/lib/revisions/application/use-cases/restore-revision.use-case.js +12 -1
  70. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.d.ts +28 -0
  71. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.d.ts.map +1 -0
  72. package/dist/lib/revisions/infrastructure/purge/revisions-workspace.purger.js +52 -0
  73. package/dist/lib/utils/content-plugin.d.ts.map +1 -1
  74. package/dist/lib/utils/content-plugin.js +10 -1
  75. package/dist/lib/utils/content-views-plugin.d.ts.map +1 -1
  76. package/dist/lib/utils/content-views-plugin.js +8 -0
  77. package/dist/lib/views/application/use-cases/create-saved-view.use-case.d.ts +4 -1
  78. package/dist/lib/views/application/use-cases/create-saved-view.use-case.d.ts.map +1 -1
  79. package/dist/lib/views/application/use-cases/create-saved-view.use-case.js +33 -9
  80. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.d.ts +4 -1
  81. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.d.ts.map +1 -1
  82. package/dist/lib/views/application/use-cases/delete-saved-view.use-case.js +24 -3
  83. package/dist/lib/views/application/use-cases/update-saved-view.use-case.d.ts +4 -1
  84. package/dist/lib/views/application/use-cases/update-saved-view.use-case.d.ts.map +1 -1
  85. package/dist/lib/views/application/use-cases/update-saved-view.use-case.js +32 -3
  86. package/dist/lib/views/domain/events/saved-view-events.d.ts +28 -0
  87. package/dist/lib/views/domain/events/saved-view-events.d.ts.map +1 -0
  88. package/dist/lib/views/domain/events/saved-view-events.js +38 -0
  89. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.d.ts +12 -3
  90. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.d.ts.map +1 -1
  91. package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.js +15 -5
  92. package/package.json +11 -11
  93. package/dist/lib/entries/controllers/bulk-entries.controller.d.ts +0 -26
  94. package/dist/lib/entries/controllers/bulk-entries.controller.d.ts.map +0 -1
  95. package/dist/lib/entries/controllers/create-entry.controller.d.ts +0 -20
  96. package/dist/lib/entries/controllers/create-entry.controller.d.ts.map +0 -1
  97. package/dist/lib/entries/controllers/delete-entry.controller.d.ts +0 -24
  98. package/dist/lib/entries/controllers/delete-entry.controller.d.ts.map +0 -1
  99. package/dist/lib/entries/controllers/get-entry.controller.d.ts +0 -34
  100. package/dist/lib/entries/controllers/get-entry.controller.d.ts.map +0 -1
  101. package/dist/lib/entries/controllers/list-entries.controller.d.ts +0 -20
  102. package/dist/lib/entries/controllers/list-entries.controller.d.ts.map +0 -1
  103. package/dist/lib/entries/controllers/publish-entry.controller.d.ts +0 -19
  104. package/dist/lib/entries/controllers/publish-entry.controller.d.ts.map +0 -1
  105. package/dist/lib/entries/controllers/resolve-type.d.ts +0 -9
  106. package/dist/lib/entries/controllers/resolve-type.d.ts.map +0 -1
  107. package/dist/lib/entries/controllers/update-entry.controller.d.ts +0 -18
  108. package/dist/lib/entries/controllers/update-entry.controller.d.ts.map +0 -1
  109. package/dist/lib/entries/dto/bulk-ids.dto.d.ts +0 -11
  110. package/dist/lib/entries/dto/bulk-ids.dto.d.ts.map +0 -1
  111. package/dist/lib/entries/dto/list-entries-query.dto.d.ts +0 -46
  112. package/dist/lib/entries/dto/list-entries-query.dto.d.ts.map +0 -1
  113. package/dist/lib/entries/dto/relation-delta-map.validator.d.ts +0 -19
  114. package/dist/lib/entries/dto/relation-delta-map.validator.d.ts.map +0 -1
  115. package/dist/lib/entries/dto/save-entry.dto.d.ts +0 -46
  116. package/dist/lib/entries/dto/save-entry.dto.d.ts.map +0 -1
  117. package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts +0 -24
  118. package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts.map +0 -1
  119. package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts +0 -40
  120. package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts.map +0 -1
  121. package/dist/lib/entries/services/entries.service.d.ts +0 -59
  122. package/dist/lib/entries/services/entries.service.d.ts.map +0 -1
  123. package/dist/lib/entries/services/entry-counter.service.d.ts +0 -31
  124. package/dist/lib/entries/services/entry-counter.service.d.ts.map +0 -1
  125. package/dist/lib/entries/services/entry-filter-schema.d.ts +0 -32
  126. package/dist/lib/entries/services/entry-filter-schema.d.ts.map +0 -1
  127. package/dist/lib/entries/services/entry-row.d.ts +0 -56
  128. package/dist/lib/entries/services/entry-row.d.ts.map +0 -1
  129. package/dist/lib/entries/services/entry-writer.service.d.ts +0 -193
  130. package/dist/lib/entries/services/entry-writer.service.d.ts.map +0 -1
  131. package/dist/lib/entries/services/relation-link.service.d.ts +0 -115
  132. package/dist/lib/entries/services/relation-link.service.d.ts.map +0 -1
  133. package/dist/lib/extension/entry-access-source.d.ts +0 -112
  134. package/dist/lib/extension/entry-access-source.d.ts.map +0 -1
  135. package/dist/lib/extension/entry-write-hook.d.ts +0 -98
  136. package/dist/lib/extension/entry-write-hook.d.ts.map +0 -1
  137. package/dist/lib/extension/per-locale-relation.d.ts +0 -18
  138. package/dist/lib/extension/per-locale-relation.d.ts.map +0 -1
  139. package/dist/lib/public/controllers/get-public-entry.controller.d.ts +0 -26
  140. package/dist/lib/public/controllers/get-public-entry.controller.d.ts.map +0 -1
  141. package/dist/lib/public/controllers/list-public-entries.controller.d.ts +0 -24
  142. package/dist/lib/public/controllers/list-public-entries.controller.d.ts.map +0 -1
  143. package/dist/lib/public/controllers/public-schema.controller.d.ts +0 -18
  144. package/dist/lib/public/controllers/public-schema.controller.d.ts.map +0 -1
package/dist/index.d.ts CHANGED
@@ -61,4 +61,5 @@ export type { PublicMediaFieldView, PublicMediaRef, PublicRelationFieldView } fr
61
61
  export { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE, BULK_MAX_SAVE_ITEMS } from './lib/entries/entries.constants';
62
62
  export { RELATION_DELTA_ADDRESSING } from './lib/entries/types/entry-list-view';
63
63
  export type { RelationDelta, RelationDeltaAddressing } from './lib/entries/types/entry-list-view';
64
+ export { toTokenActor, toToolEventActor } from './lib/public-api/infrastructure/token-actor';
64
65
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  /** Public API of @orthacms/content-server. */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.ENTRY_VISIBILITY = exports.PublicListEntriesQueryDto = exports.PublicEntryQueryDto = exports.resolveGrantedType = exports.PublicEntryWritesService = exports.PublicEntriesQuery = exports.CurrentApiToken = exports.ApiTokenWorkspaceGuard = exports.ApiTokenGuard = exports.MEDIA_KIND_VALUES = exports.CONTENT_FIELD_TYPE = exports.ENTRY_STATUS = exports.CONTENT_TYPE_KIND = exports.EntryValidationService = exports.EntryMatchQuery = exports.ContentTypeRegistry = exports.toRecord = exports.toColumns = exports.InjectMediaAssetResolver = exports.MEDIA_ASSET_RESOLVER = exports.entryFilterProviderRegistrar = exports.EntryFilterProviderRegistry = exports.entryWriteExtensionRegistrar = exports.EntryWriteExtensionRegistry = exports.contentReadScopeRegistrar = exports.ContentReadScopeRegistry = exports.isJoinBackedRelation = exports.isPerLocaleField = exports.relationLocaleSync = exports.RELATION_LOCALE_SYNC = exports.CONTENT_ENTRY_EXTENSION = exports.ContentGrantGuard = exports.RelationLinkService = exports.EntryWriterService = exports.WorkspaceGrantsQuery = exports.InjectContentRegistry = exports.CONTENT_REGISTRY = exports.ContentModule = exports.field = exports.joinTableOf = exports.single = exports.collection = exports.VIEW_VISIBILITY_VALUES = exports.VIEW_VISIBILITY = exports.viewVisibility = exports.savedViewDefaults = exports.savedViews = exports.ContentViewsModule = exports.ContentViewsPlugin = exports.ContentPlugin = void 0;
5
- exports.RELATION_DELTA_ADDRESSING = exports.BULK_MAX_SAVE_ITEMS = exports.MAX_PAGE_SIZE = exports.DEFAULT_PAGE_SIZE = exports.BULK_SAVE_OP = exports.PublicBulkSaveItemDto = exports.PublicBulkSaveDto = exports.PublicBulkIdsDto = exports.PublicSaveEntryDto = exports.DEFAULT_EXPANSION_LIMIT = exports.PREVIEW = void 0;
5
+ exports.toToolEventActor = exports.toTokenActor = exports.RELATION_DELTA_ADDRESSING = exports.BULK_MAX_SAVE_ITEMS = exports.MAX_PAGE_SIZE = exports.DEFAULT_PAGE_SIZE = exports.BULK_SAVE_OP = exports.PublicBulkSaveItemDto = exports.PublicBulkSaveDto = exports.PublicBulkIdsDto = exports.PublicSaveEntryDto = exports.DEFAULT_EXPANSION_LIMIT = exports.PREVIEW = void 0;
6
6
  var content_plugin_1 = require("./lib/utils/content-plugin");
7
7
  Object.defineProperty(exports, "ContentPlugin", { enumerable: true, get: function () { return content_plugin_1.ContentPlugin; } });
8
8
  // Saved list views. A second `ServerPlugin` entry from this package because
@@ -151,3 +151,6 @@ Object.defineProperty(exports, "MAX_PAGE_SIZE", { enumerable: true, get: functio
151
151
  Object.defineProperty(exports, "BULK_MAX_SAVE_ITEMS", { enumerable: true, get: function () { return entries_constants_1.BULK_MAX_SAVE_ITEMS; } });
152
152
  var entry_list_view_1 = require("./lib/entries/types/entry-list-view");
153
153
  Object.defineProperty(exports, "RELATION_DELTA_ADDRESSING", { enumerable: true, get: function () { return entry_list_view_1.RELATION_DELTA_ADDRESSING; } });
154
+ var token_actor_1 = require("./lib/public-api/infrastructure/token-actor");
155
+ Object.defineProperty(exports, "toTokenActor", { enumerable: true, get: function () { return token_actor_1.toTokenActor; } });
156
+ Object.defineProperty(exports, "toToolEventActor", { enumerable: true, get: function () { return token_actor_1.toToolEventActor; } });
@@ -1 +1 @@
1
- {"version":3,"file":"content.module.d.ts","sourceRoot":"","sources":["../../src/lib/content.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAOvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAgE5E;;;;;;;;;;;;;GAaG;AACH,qBACa,aAAa;IACtB,qEAAqE;IACrE,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,mBAAmB,GAAG,aAAa;CA4M/D"}
1
+ {"version":3,"file":"content.module.d.ts","sourceRoot":"","sources":["../../src/lib/content.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAOvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAiE5E;;;;;;;;;;;;;GAaG;AACH,qBACa,aAAa;IACtB,qEAAqE;IACrE,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,mBAAmB,GAAG,aAAa;CAmN/D"}
@@ -44,6 +44,7 @@ const drizzle_revision_store_1 = require("./revisions/infrastructure/persistence
44
44
  const restore_revision_use_case_1 = require("./revisions/application/use-cases/restore-revision.use-case");
45
45
  const publish_revision_use_case_1 = require("./revisions/application/use-cases/publish-revision.use-case");
46
46
  const revision_refs_query_1 = require("./revisions/infrastructure/queries/revision-refs.query");
47
+ const revisions_workspace_purger_1 = require("./revisions/infrastructure/purge/revisions-workspace.purger");
47
48
  const revisions_controller_1 = require("./revisions/http/controllers/revisions.controller");
48
49
  const restore_revision_controller_1 = require("./revisions/http/controllers/restore-revision.controller");
49
50
  const publish_revision_controller_1 = require("./revisions/http/controllers/publish-revision.controller");
@@ -184,6 +185,13 @@ let ContentModule = ContentModule_1 = class ContentModule {
184
185
  // Resolves a previewed revision's relation ids to display refs
185
186
  // (the "exact linked records" the diff shows).
186
187
  revision_refs_query_1.RevisionRefsQuery,
188
+ // Removes a deleted workspace's revision history. Content
189
+ // otherwise refuses rather than purges, but revisions escape
190
+ // that protection in both directions: no FK to `workspaces`,
191
+ // and `countWorkspaceEntries` sums live entry tables only — so
192
+ // a workspace whose entries were all deleted counts as empty,
193
+ // deletes cleanly, and strands its whole version timeline.
194
+ revisions_workspace_purger_1.RevisionsWorkspacePurger,
187
195
  entry_writer_service_1.EntryWriterService,
188
196
  relation_link_service_1.RelationLinkService,
189
197
  // Entries feature, layered per ADR-0003: the publish-lifecycle
@@ -1 +1 @@
1
- {"version":3,"file":"entry-proposal.applier.d.ts","sourceRoot":"","sources":["../../../src/lib/copilot/entry-proposal.applier.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACR,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,cAAc,EACjB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAChG,OAAO,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AA8CvF;;;;;;;;;;;;;;;GAeG;AACH,qBACa,0BAA2B,YAAW,eAAe;IAK1D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAN3B,QAAQ,CAAC,IAAI,yBAAsC;gBAI9B,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,oBAAoB;IAG3C,KAAK,CACP,KAAK,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EACjE,KAAK,EAAE,aAAa,GACrB,OAAO,CAAC,mBAAmB,CAAC;CAiClC;AAED;;;;;;;;;;;;;;GAcG;AACH,qBACa,0BAA2B,YAAW,eAAe;IAK1D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAN3B,QAAQ,CAAC,IAAI,yBAAsC;gBAI9B,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,oBAAoB;IAG3C,KAAK,CACP,KAAK,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EACjE,KAAK,EAAE,aAAa,GACrB,OAAO,CAAC,mBAAmB,CAAC;CAwClC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,8BAA+B,YAAW,eAAe;IAK9D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAN3B,QAAQ,CAAC,IAAI,4BAA0C;gBAIlC,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,oBAAoB;IAG3C,KAAK,CACP,KAAK,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EACjE,KAAK,EAAE,aAAa,GACrB,OAAO,CAAC,mBAAmB,CAAC;CAqFlC"}
1
+ {"version":3,"file":"entry-proposal.applier.d.ts","sourceRoot":"","sources":["../../../src/lib/copilot/entry-proposal.applier.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,cAAc,EACjB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAChG,OAAO,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AA8CvF;;;;;;;;;;;;;;;GAeG;AACH,qBACa,0BAA2B,YAAW,eAAe;IAK1D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAN3B,QAAQ,CAAC,IAAI,yBAAsC;gBAI9B,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,oBAAoB;IAG3C,KAAK,CACP,KAAK,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EACjE,KAAK,EAAE,aAAa,GACrB,OAAO,CAAC,mBAAmB,CAAC;CAiClC;AAED;;;;;;;;;;;;;;GAcG;AACH,qBACa,0BAA2B,YAAW,eAAe;IAK1D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAN3B,QAAQ,CAAC,IAAI,yBAAsC;gBAI9B,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,oBAAoB;IAG3C,KAAK,CACP,KAAK,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EACjE,KAAK,EAAE,aAAa,GACrB,OAAO,CAAC,mBAAmB,CAAC;CAwClC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,8BAA+B,YAAW,eAAe;IAK9D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAN3B,QAAQ,CAAC,IAAI,4BAA0C;gBAIlC,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,oBAAoB;IAG3C,KAAK,CACP,KAAK,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EACjE,KAAK,EAAE,aAAa,GACrB,OAAO,CAAC,mBAAmB,CAAC;CAqFlC"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BulkSaveEntriesProposalApplier = exports.UpdateEntryProposalApplier = exports.CreateEntryProposalApplier = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const copilot_server_1 = require("@orthacms/copilot-server");
5
6
  const common_1 = require("@nestjs/common");
6
7
  const content_tokens_1 = require("../content.tokens");
7
8
  const entry_writer_service_1 = require("../entries/infrastructure/persistence/entry-writer.service");
@@ -83,7 +84,7 @@ let CreateEntryProposalApplier = class CreateEntryProposalApplier {
83
84
  // The human who accepted is the actor on the write, on its revision
84
85
  // and on the domain event it raises — never a copilot identity,
85
86
  // which does not exist.
86
- { id: actor.userId, email: actor.actorEmail });
87
+ (0, copilot_server_1.proposalEventActor)(actor));
87
88
  return {
88
89
  entityId: entry.id,
89
90
  detail: { typeName: type.name, status: entry.status ?? 'draft' }
@@ -134,7 +135,7 @@ let UpdateEntryProposalApplier = class UpdateEntryProposalApplier {
134
135
  const current = await this.writer.getOne(type, entryId, actor.workspaceId);
135
136
  const patch = (input.patch['values'] ?? {});
136
137
  const merged = { ...(current.values ?? {}), ...patch };
137
- const entry = await this.writer.update(type, entryId, merged, actor.workspaceId, undefined, { id: actor.userId, email: actor.actorEmail });
138
+ const entry = await this.writer.update(type, entryId, merged, actor.workspaceId, undefined, (0, copilot_server_1.proposalEventActor)(actor));
138
139
  return {
139
140
  entityId: entry.id,
140
141
  detail: {
@@ -201,7 +202,7 @@ let BulkSaveEntriesProposalApplier = class BulkSaveEntriesProposalApplier {
201
202
  // become — the same merge rule the single-entry applier
202
203
  // states at length.
203
204
  const current = await this.writer.getOne(type, id, actor.workspaceId);
204
- const entry = await this.writer.update(type, id, { ...(current.values ?? {}), ...values }, actor.workspaceId, undefined, { id: actor.userId, email: actor.actorEmail });
205
+ const entry = await this.writer.update(type, id, { ...(current.values ?? {}), ...values }, actor.workspaceId, undefined, (0, copilot_server_1.proposalEventActor)(actor));
205
206
  updated.push(entry.id);
206
207
  }
207
208
  else {
@@ -210,7 +211,7 @@ let BulkSaveEntriesProposalApplier = class BulkSaveEntriesProposalApplier {
210
211
  ? item.locale
211
212
  : undefined,
212
213
  // No group to join — see `assertStartsItsOwnGroup`.
213
- undefined, { id: actor.userId, email: actor.actorEmail });
214
+ undefined, (0, copilot_server_1.proposalEventActor)(actor));
214
215
  created.push(entry.id);
215
216
  }
216
217
  }
@@ -11,6 +11,13 @@
11
11
  *
12
12
  * Pure: it takes the document and the serialized types, and mutates only the
13
13
  * paths this plugin owns.
14
+ *
15
+ * Two surfaces, described separately. `/api/content/...` is the admin's and
16
+ * `/api/v1/content/...` is the published one, and they answer in different
17
+ * shapes where their spellings agree — a public relation preview carries whole
18
+ * entries, the admin's carries refs. Describing both from one table is not a
19
+ * shortcut but a bug, and was one: the public routes were reported with the
20
+ * admin's schemas until {@link PUBLIC_ENTRY_ROUTES} existed.
14
21
  */
15
22
  import type { OpenApiDocument } from '@orthacms/bootstrap-server';
16
23
  import type { SerializedContentType } from '../registry/content-type-registry';
@@ -1 +1 @@
1
- {"version":3,"file":"describe-content-api.d.ts","sourceRoot":"","sources":["../../../src/lib/docs/describe-content-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAuJ/E;;;GAGG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,SAAS,qBAAqB,EAAE,GACxC,IAAI,CA2EN"}
1
+ {"version":3,"file":"describe-content-api.d.ts","sourceRoot":"","sources":["../../../src/lib/docs/describe-content-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAqP/E;;;GAGG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,SAAS,qBAAqB,EAAE,GACxC,IAAI,CAgIN"}
@@ -12,10 +12,19 @@
12
12
  *
13
13
  * Pure: it takes the document and the serialized types, and mutates only the
14
14
  * paths this plugin owns.
15
+ *
16
+ * Two surfaces, described separately. `/api/content/...` is the admin's and
17
+ * `/api/v1/content/...` is the published one, and they answer in different
18
+ * shapes where their spellings agree — a public relation preview carries whole
19
+ * entries, the admin's carries refs. Describing both from one table is not a
20
+ * shortcut but a bug, and was one: the public routes were reported with the
21
+ * admin's schemas until {@link PUBLIC_ENTRY_ROUTES} existed.
15
22
  */
16
23
  Object.defineProperty(exports, "__esModule", { value: true });
17
24
  exports.describeContentApi = describeContentApi;
18
25
  const content_schemas_1 = require("./content-schemas");
26
+ const public_api_schemas_1 = require("./public-api-schemas");
27
+ const openapi_writer_1 = require("./openapi-writer");
19
28
  /** The entry read/write shorthands, since most operations return one. */
20
29
  const ENTRY = { response: { kind: 'entry' } };
21
30
  const VALIDATED_ENTRY = {
@@ -23,6 +32,25 @@ const VALIDATED_ENTRY = {
23
32
  validated: true
24
33
  };
25
34
  const EMPTY = { response: { kind: 'empty' } };
35
+ /**
36
+ * A route another plugin mounts under one of this plugin's `{typeName}`
37
+ * prefixes — transfer's export/import, segments' `/access`.
38
+ *
39
+ * Listed so the `typeName` parameter still gets the registered-name enum: which
40
+ * names are valid there is *this* plugin's contract, and the registry is the
41
+ * only thing that knows them, so leaving the parameter an opaque string would
42
+ * be leaving a gap nothing else can fill.
43
+ *
44
+ * Nothing else is touched. The response body and the failure codes belong to
45
+ * whichever plugin serves the route, and they genuinely differ — transfer 404s
46
+ * an unknown type, the public `/access` route answers 400 — so writing this
47
+ * plugin's usual 404 onto them from here would publish something the API does
48
+ * not do.
49
+ */
50
+ const FOREIGN = {
51
+ response: { kind: 'empty' },
52
+ ownedElsewhere: true
53
+ };
26
54
  /** An operation returning one of the fixed shared schemas. */
27
55
  function shared(name) {
28
56
  return { response: { kind: 'schema', name } };
@@ -50,7 +78,14 @@ const ENTRY_ROUTES = {
50
78
  '/bulk/unpublish': { post: shared('BulkActionResult') },
51
79
  '/bulk/delete': { post: shared('BulkActionResult') },
52
80
  '/bulk/restore': { post: shared('BulkActionResult') },
53
- '/bulk/purge': { post: shared('BulkActionResult') }
81
+ '/bulk/purge': { post: shared('BulkActionResult') },
82
+ // Mounted here by `@orthacms/transfer-server`, which describes their
83
+ // bodies; see {@link FOREIGN}.
84
+ '/export': { post: FOREIGN },
85
+ '/export/preview': { post: FOREIGN },
86
+ '/import': { post: FOREIGN },
87
+ '/import/preview': { post: FOREIGN },
88
+ '/import/template': { get: FOREIGN }
54
89
  };
55
90
  /** Schema routes, keyed by what follows `/content-schema`. */
56
91
  const SCHEMA_ROUTES = {
@@ -58,58 +93,107 @@ const SCHEMA_ROUTES = {
58
93
  '/{name}': { get: shared('ContentTypeSchema') },
59
94
  '/{name}/filter-fields': { get: shared('FilterFields') }
60
95
  };
61
- /** Matches `<prefix>/content/{typeName}<rest>`. */
96
+ /**
97
+ * Public entry routes, keyed by what follows `/v1/content/{typeName}`.
98
+ *
99
+ * A separate table from {@link ENTRY_ROUTES} rather than an extension of it,
100
+ * because the two surfaces answer in **different shapes** on the paths they
101
+ * spell the same way: a public relation page carries whole entries where the
102
+ * admin's carries `RelationRef`s, and a public media read is keyed to
103
+ * `{ items, total }` where the admin's is keyed to a bare array. One table
104
+ * matching both spellings is what put the admin's answer on the public routes
105
+ * in the first place.
106
+ *
107
+ * Every read exists twice — once under `/{id}`, once under
108
+ * `/group/{localeGroupId}` — because a localized front-end carries the stable
109
+ * group id and a `?locale=`, not a per-locale id map. The two spellings funnel
110
+ * into one handler, so they are listed with one shape apiece and cannot drift.
111
+ */
112
+ const PUBLIC_ENTRY_ROUTES = {
113
+ '': { get: { response: { kind: 'listPage' } }, post: VALIDATED_ENTRY },
114
+ '/{id}': { get: ENTRY, patch: VALIDATED_ENTRY, delete: EMPTY },
115
+ '/{id}/media': { get: shared('PublicEntryMedia') },
116
+ '/{id}/relations/{field}': { get: shared('PublicRelationFieldPage') },
117
+ '/{id}/translations': { get: shared('PublicEntryTranslations') },
118
+ '/{id}/publish': { post: VALIDATED_ENTRY },
119
+ '/{id}/unpublish': { post: ENTRY },
120
+ '/group/{localeGroupId}': {
121
+ get: ENTRY,
122
+ patch: VALIDATED_ENTRY,
123
+ delete: EMPTY
124
+ },
125
+ '/group/{localeGroupId}/media': { get: shared('PublicEntryMedia') },
126
+ '/group/{localeGroupId}/relations/{field}': {
127
+ get: shared('PublicRelationFieldPage')
128
+ },
129
+ '/group/{localeGroupId}/translations': {
130
+ get: shared('PublicEntryTranslations')
131
+ },
132
+ '/group/{localeGroupId}/publish': { post: VALIDATED_ENTRY },
133
+ '/group/{localeGroupId}/unpublish': { post: ENTRY },
134
+ '/bulk': { post: shared('PublicBulkSaveResult') },
135
+ // The batch publish/unpublish/delete run the very same use-cases the
136
+ // admin's do, so they answer in the admin's shapes — deliberately, and
137
+ // documented as such in `types/public-bulk.ts`.
138
+ '/bulk/publish': { post: shared('BulkPublishResult') },
139
+ '/bulk/unpublish': { post: shared('BulkActionResult') },
140
+ '/bulk/delete': { post: shared('BulkActionResult') },
141
+ // Mounted here by `@orthacms/segments-server`, which describes its bodies;
142
+ // see {@link FOREIGN}.
143
+ '/{id}/access': { get: FOREIGN, put: FOREIGN }
144
+ };
145
+ /** Public discovery routes, keyed by what follows `/v1/content-types`. */
146
+ const PUBLIC_TYPES_ROUTES = {
147
+ '': { get: shared('PublicContentTypeList') },
148
+ '/{name}': { get: shared('ContentTypeSchema') }
149
+ };
150
+ /** Matches `<prefix>/v1/content/{typeName}<rest>`. */
151
+ const PUBLIC_ENTRY_ROUTE_RE = /\/v1\/content\/\{typeName\}(.*)$/;
152
+ /** Matches `<prefix>/v1/content-types<rest>`. */
153
+ const PUBLIC_TYPES_ROUTE_RE = /\/v1\/content-types(.*)$/;
154
+ /**
155
+ * Matches `<prefix>/content/{typeName}<rest>`.
156
+ *
157
+ * It matches the `/v1/` spelling too, which is why the public patterns are
158
+ * tried **first** and win: this pattern silently claiming the public routes is
159
+ * exactly how the admin's schemas ended up on the published contract.
160
+ */
62
161
  const ENTRY_ROUTE_RE = /\/content\/\{typeName\}(.*)$/;
63
162
  /** Matches `<prefix>/content-schema<rest>`. */
64
163
  const SCHEMA_ROUTE_RE = /\/content-schema(.*)$/;
65
164
  /**
66
- * Writes a success response's schema onto whichever 2xx key the scanner already
67
- * emitted (Nest's default is 201 for `@Post`, 200 elsewhere, and a `@HttpCode`
68
- * moves it), so this never invents a status code the API doesn't return.
165
+ * Constrains the `typeName` path param to the registered type names.
166
+ *
167
+ * The note about what an unknown name answers is only added for this plugin's
168
+ * own routes: on a {@link FOREIGN} one the owning plugin decides, and two of
169
+ * them do not agree with each other, let alone with this one.
69
170
  */
70
- function setSuccessResponse(operation, schema, description) {
71
- const responses = operation.responses ?? {};
72
- const key = Object.keys(responses).find((code) => /^2\d\d$/.test(code));
73
- if (!key || key === '204') {
74
- return;
75
- }
76
- responses[key] = {
77
- description,
78
- content: { 'application/json': { schema } }
79
- };
80
- operation.responses = responses;
81
- }
82
- /** Adds a documented failure response, leaving any existing one alone. */
83
- function addErrorResponse(operation, code, description, schema) {
84
- const responses = operation.responses ?? {};
85
- if (responses[code]) {
86
- return;
87
- }
88
- responses[code] = {
89
- description,
90
- ...(schema ? { content: { 'application/json': { schema } } } : {})
91
- };
92
- operation.responses = responses;
93
- }
94
- /** Constrains the `typeName` path param to the registered type names. */
95
- function describeTypeNameParam(operation, typeNames) {
171
+ function describeTypeNameParam(operation, typeNames, ownedElsewhere = false) {
96
172
  const parameter = operation.parameters?.find((candidate) => candidate.name === 'typeName' && candidate.in === 'path');
97
173
  if (!parameter) {
98
174
  return;
99
175
  }
100
176
  parameter.schema = { type: 'string', enum: typeNames };
101
- parameter.description =
102
- 'Machine name of the content type. Unknown (or not granted to the workspace) is a 404.';
177
+ parameter.description = ownedElsewhere
178
+ ? 'Machine name of the content type, resolved through the same registry the content routes use.'
179
+ : 'Machine name of the content type. Unknown (or not granted to the workspace) is a 404.';
103
180
  }
104
181
  /**
105
- * `oneOf` the per-type schemas — the response shape depends on `typeName`,
106
- * which OpenAPI can't express as a dependency, so the alternatives are listed.
182
+ * The per-type schemas as alternatives — the response shape depends on
183
+ * `typeName`, which OpenAPI cannot express as a dependency, so they are listed.
107
184
  * A single registered type needs no union.
185
+ *
186
+ * `anyOf`, **not** `oneOf`: the alternatives are not mutually exclusive. Two
187
+ * content types with compatible envelopes both validate the same page (an empty
188
+ * `items` array matches every list schema there is), and `oneOf` means *exactly
189
+ * one*, so the honest-looking operator turns a correct response into a
190
+ * validation failure. Measured: `GET /api/v1/content/home_page` matched two
191
+ * branches and was therefore rejected by its own document.
108
192
  */
109
193
  function unionOf(names) {
110
194
  return names.length === 1
111
195
  ? (0, content_schemas_1.ref)(names[0])
112
- : { oneOf: names.map((name) => (0, content_schemas_1.ref)(name)) };
196
+ : { anyOf: names.map((name) => (0, content_schemas_1.ref)(name)) };
113
197
  }
114
198
  /**
115
199
  * Adds this plugin's schemas to `document` and describes its own operations:
@@ -119,18 +203,49 @@ function describeContentApi(document, types) {
119
203
  document.components ??= {};
120
204
  document.components.schemas ??= {};
121
205
  Object.assign(document.components.schemas, (0, content_schemas_1.buildContentSchemas)(types));
206
+ Object.assign(document.components.schemas, (0, public_api_schemas_1.buildPublicApiSchemas)(types));
122
207
  const typeNames = types.map((type) => type.name);
123
- const entryUnion = unionOf(types.map((type) => (0, content_schemas_1.schemaNamesOf)(type).entry));
124
- const listUnion = unionOf(types.map((type) => (0, content_schemas_1.schemaNamesOf)(type).listPage));
208
+ /** The admin surface's per-type unions. */
209
+ const admin = {
210
+ routes: ENTRY_ROUTES,
211
+ entryUnion: unionOf(types.map((type) => (0, content_schemas_1.schemaNamesOf)(type).entry)),
212
+ listUnion: unionOf(types.map((type) => (0, content_schemas_1.schemaNamesOf)(type).listPage)),
213
+ typed: true
214
+ };
215
+ /** The public surface's, which are a different set of schemas entirely. */
216
+ const publicEntries = {
217
+ routes: PUBLIC_ENTRY_ROUTES,
218
+ entryUnion: (0, public_api_schemas_1.publicUnionOf)(types.map((type) => (0, public_api_schemas_1.publicSchemaNamesOf)(type).entry)),
219
+ listUnion: (0, public_api_schemas_1.publicUnionOf)(types.map((type) => (0, public_api_schemas_1.publicSchemaNamesOf)(type).listPage)),
220
+ typed: true
221
+ };
222
+ const adminSchema = { routes: SCHEMA_ROUTES, typed: false };
223
+ const publicSchema = { routes: PUBLIC_TYPES_ROUTES, typed: false };
224
+ // Order matters: the public patterns are tried first because
225
+ // `ENTRY_ROUTE_RE` also matches the `/v1/` spelling, and letting it win
226
+ // there is what used to write the admin's relation and media shapes onto
227
+ // the published contract.
228
+ const surfaces = [
229
+ [PUBLIC_ENTRY_ROUTE_RE, publicEntries],
230
+ [PUBLIC_TYPES_ROUTE_RE, publicSchema],
231
+ [ENTRY_ROUTE_RE, admin],
232
+ [SCHEMA_ROUTE_RE, adminSchema]
233
+ ];
125
234
  for (const [route, item] of Object.entries(document.paths)) {
126
- const entryMatch = ENTRY_ROUTE_RE.exec(route);
127
- const schemaMatch = SCHEMA_ROUTE_RE.exec(route);
128
- const rest = (entryMatch ?? schemaMatch)?.[1];
129
- if (rest === undefined) {
235
+ let rest;
236
+ let surface;
237
+ for (const [pattern, candidate] of surfaces) {
238
+ const match = pattern.exec(route);
239
+ if (match) {
240
+ rest = match[1];
241
+ surface = candidate;
242
+ break;
243
+ }
244
+ }
245
+ if (rest === undefined || !surface) {
130
246
  continue;
131
247
  }
132
- const routes = entryMatch ? ENTRY_ROUTES : SCHEMA_ROUTES;
133
- const byMethod = routes[rest];
248
+ const byMethod = surface.routes[rest];
134
249
  if (!byMethod) {
135
250
  continue;
136
251
  }
@@ -139,11 +254,16 @@ function describeContentApi(document, types) {
139
254
  if (!spec || !operation || typeof operation !== 'object') {
140
255
  continue;
141
256
  }
142
- if (entryMatch) {
143
- describeTypeNameParam(operation, typeNames);
144
- addErrorResponse(operation, '404', 'Unknown content type, or no entry with this id in the workspace.');
257
+ if (surface.typed) {
258
+ describeTypeNameParam(operation, typeNames, spec.ownedElsewhere);
259
+ }
260
+ if (spec.ownedElsewhere) {
261
+ continue;
262
+ }
263
+ if (surface.typed) {
264
+ (0, openapi_writer_1.addErrorResponse)(operation, '404', 'Unknown content type, or no entry with this id in the workspace.');
145
265
  if (spec.validated) {
146
- addErrorResponse(operation, '422', 'The values failed the content type’s field validation.', {
266
+ (0, openapi_writer_1.addErrorResponse)(operation, '422', 'The values failed the content type’s field validation.', {
147
267
  type: 'object',
148
268
  properties: {
149
269
  message: { type: 'string' },
@@ -159,14 +279,18 @@ function describeContentApi(document, types) {
159
279
  // With no registered types there is no entry shape to describe —
160
280
  // and every one of these routes 404s anyway.
161
281
  const { response } = spec;
162
- if (response.kind === 'entry' && typeNames.length) {
163
- setSuccessResponse(operation, entryUnion, 'The entry.');
282
+ if (response.kind === 'entry' &&
283
+ typeNames.length &&
284
+ surface.entryUnion) {
285
+ (0, openapi_writer_1.setSuccessResponse)(operation, surface.entryUnion, 'The entry.');
164
286
  }
165
- else if (response.kind === 'listPage' && typeNames.length) {
166
- setSuccessResponse(operation, listUnion, 'One page of entries.');
287
+ else if (response.kind === 'listPage' &&
288
+ typeNames.length &&
289
+ surface.listUnion) {
290
+ (0, openapi_writer_1.setSuccessResponse)(operation, surface.listUnion, 'One page of entries.');
167
291
  }
168
292
  else if (response.kind === 'schema') {
169
- setSuccessResponse(operation, (0, content_schemas_1.ref)(response.name), 'OK.');
293
+ (0, openapi_writer_1.setSuccessResponse)(operation, (0, content_schemas_1.ref)(response.name), 'OK.');
170
294
  }
171
295
  }
172
296
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The saved-views plugin's pass over the host's OpenAPI document.
3
+ *
4
+ * A second `decorate` from the same package as {@link describeContentApi},
5
+ * because saved views ship as a second `ServerPlugin` entry
6
+ * (`ContentViewsPlugin`) and a plugin describes what it registers. Keeping them
7
+ * apart also keeps the route tables honest: nothing here can accidentally claim
8
+ * a `/content/...` path, and nothing there can claim a `/views` one.
9
+ *
10
+ * Pure: takes the document and the serialized types, mutates only `/views`.
11
+ */
12
+ import type { OpenApiDocument } from '@orthacms/bootstrap-server';
13
+ import type { SerializedContentType } from '../registry/content-type-registry';
14
+ /**
15
+ * Adds the saved-view schemas to `document` and points the `/views` operations
16
+ * at them.
17
+ */
18
+ export declare function describeViewsApi(document: OpenApiDocument, types: readonly SerializedContentType[]): void;
19
+ //# sourceMappingURL=describe-views-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe-views-api.d.ts","sourceRoot":"","sources":["../../../src/lib/docs/describe-views-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAmC/E;;;GAGG;AACH,wBAAgB,gBAAgB,CAC5B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,SAAS,qBAAqB,EAAE,GACxC,IAAI,CAqCN"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * The saved-views plugin's pass over the host's OpenAPI document.
4
+ *
5
+ * A second `decorate` from the same package as {@link describeContentApi},
6
+ * because saved views ship as a second `ServerPlugin` entry
7
+ * (`ContentViewsPlugin`) and a plugin describes what it registers. Keeping them
8
+ * apart also keeps the route tables honest: nothing here can accidentally claim
9
+ * a `/content/...` path, and nothing there can claim a `/views` one.
10
+ *
11
+ * Pure: takes the document and the serialized types, mutates only `/views`.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.describeViewsApi = describeViewsApi;
15
+ const content_schemas_1 = require("./content-schemas");
16
+ const views_schemas_1 = require("./views-schemas");
17
+ const openapi_writer_1 = require("./openapi-writer");
18
+ /**
19
+ * Matches `<prefix>/views<rest>` — anchored at both ends.
20
+ *
21
+ * The tail is one of the three shapes the controller actually serves. The head
22
+ * is `^/<one segment>/`, so `/api/insights/views` — another plugin's route,
23
+ * ending in the same word — is not caught: a suffix match claimed it and gave
24
+ * it this plugin's schemas, which is the same failure that once published
25
+ * thirteen public content operations with the admin's shapes.
26
+ *
27
+ * It assumes the host's global prefix is a single segment, which the default
28
+ * (`api`) is. A longer one leaves these three operations with no response
29
+ * schema rather than the wrong one — the direction to fail in, and the same
30
+ * one an unmatched route already takes.
31
+ */
32
+ const VIEWS_ROUTE_RE = /^\/[^/]+\/views((?:\/\{id\})?(?:\/default)?)$/;
33
+ /**
34
+ * What each `/views` operation answers, keyed by what follows `/views`.
35
+ *
36
+ * The three `204`s (`DELETE /views/{id}`, `PUT|DELETE /views/{id}/default`) are
37
+ * listed as `null` rather than omitted: they are described — they simply have
38
+ * no body, and saying so here is what keeps a later reader from "fixing" the
39
+ * gap by inventing one.
40
+ */
41
+ const VIEW_ROUTES = {
42
+ '': { get: 'list', post: 'one' },
43
+ '/{id}': { patch: 'one', delete: null },
44
+ '/{id}/default': { put: null, delete: null }
45
+ };
46
+ /**
47
+ * Adds the saved-view schemas to `document` and points the `/views` operations
48
+ * at them.
49
+ */
50
+ function describeViewsApi(document, types) {
51
+ document.components ??= {};
52
+ document.components.schemas ??= {};
53
+ Object.assign(document.components.schemas, (0, views_schemas_1.buildViewsSchemas)(types));
54
+ for (const [route, item] of Object.entries(document.paths)) {
55
+ const match = VIEWS_ROUTE_RE.exec(route);
56
+ if (!match) {
57
+ continue;
58
+ }
59
+ const byMethod = VIEW_ROUTES[match[1]];
60
+ if (!byMethod) {
61
+ continue;
62
+ }
63
+ for (const [method, operation] of Object.entries(item)) {
64
+ const kind = byMethod[method];
65
+ if (kind == null || !operation || typeof operation !== 'object') {
66
+ continue;
67
+ }
68
+ if (kind === 'list') {
69
+ (0, openapi_writer_1.setSuccessResponse)(operation, { type: 'array', items: (0, content_schemas_1.ref)(views_schemas_1.SAVED_VIEW_SCHEMA) }, 'The caller’s own views for this scope at any visibility, plus every workspace-shared one, ordered for the switcher.');
70
+ }
71
+ else {
72
+ (0, openapi_writer_1.setSuccessResponse)(operation, (0, content_schemas_1.ref)(views_schemas_1.SAVED_VIEW_SCHEMA), 'The saved view.');
73
+ }
74
+ }
75
+ }
76
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"field-schema.d.ts","sourceRoot":"","sources":["../../../src/lib/docs/field-schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAEzE,qEAAqE;AACrE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAyJpD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAK5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,eAAe,GAAG,aAAa,CA0DjE"}
1
+ {"version":3,"file":"field-schema.d.ts","sourceRoot":"","sources":["../../../src/lib/docs/field-schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAEzE,qEAAqE;AACrE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAyJpD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAK5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,eAAe,GAAG,aAAa,CAyDjE"}
@@ -206,9 +206,43 @@ function fieldSchema(field) {
206
206
  ? field.admin['label']
207
207
  : undefined;
208
208
  return {
209
- ...valueSchema(field),
210
- nullable: true,
209
+ ...nullable(valueSchema(field)),
211
210
  ...(label ? { title: label } : {}),
212
211
  ...(notes.length ? { description: notes.join(' ') } : {})
213
212
  };
214
213
  }
214
+ /**
215
+ * Marks a value schema nullable — and does the two things `nullable: true`
216
+ * alone does **not** do.
217
+ *
218
+ * OpenAPI 3.0's `nullable` is a modifier on the schema's `type`, so it is inert
219
+ * wherever there is no single type to modify, and it does not widen an
220
+ * enumeration. Both cases occur here and both produced a document that rejected
221
+ * responses the API really returns:
222
+ *
223
+ * - a `select` read back as `{ type: 'string', enum: [...], nullable: true }`,
224
+ * which every validator refuses `null` against, because OAS 3.0 requires a
225
+ * nullable enum to list `null` among its values;
226
+ * - a `richtext` read back as a bare `oneOf` (document or legacy HTML string)
227
+ * with `nullable` attached to nothing at all.
228
+ *
229
+ * Measured against a live server: an `article` with an unset `layout` did not
230
+ * validate against its own `ArticleValues` schema until this existed.
231
+ */
232
+ function nullable(schema) {
233
+ if (Array.isArray(schema['oneOf'])) {
234
+ return {
235
+ ...schema,
236
+ oneOf: [...schema['oneOf'], { type: 'null' }],
237
+ nullable: true
238
+ };
239
+ }
240
+ if (Array.isArray(schema['enum'])) {
241
+ return {
242
+ ...schema,
243
+ enum: [...schema['enum'], null],
244
+ nullable: true
245
+ };
246
+ }
247
+ return { ...schema, nullable: true };
248
+ }