@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.
- package/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/define.d.ts +17 -0
- package/dist/define.d.ts.map +1 -0
- package/dist/define.js +28 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/lib/collection/define.d.ts +35 -0
- package/dist/lib/collection/define.d.ts.map +1 -0
- package/dist/lib/collection/define.js +217 -0
- package/dist/lib/collection/table-builder.d.ts +28 -0
- package/dist/lib/collection/table-builder.d.ts.map +1 -0
- package/dist/lib/collection/table-builder.js +306 -0
- package/dist/lib/content-types/controllers/get-content-schema.controller.d.ts +24 -0
- package/dist/lib/content-types/controllers/get-content-schema.controller.d.ts.map +1 -0
- package/dist/lib/content-types/controllers/get-content-schema.controller.js +58 -0
- package/dist/lib/content-types/controllers/get-filter-fields.controller.d.ts +35 -0
- package/dist/lib/content-types/controllers/get-filter-fields.controller.d.ts.map +1 -0
- package/dist/lib/content-types/controllers/get-filter-fields.controller.js +74 -0
- package/dist/lib/content-types/controllers/list-content-schema.controller.d.ts +15 -0
- package/dist/lib/content-types/controllers/list-content-schema.controller.d.ts.map +1 -0
- package/dist/lib/content-types/controllers/list-content-schema.controller.js +38 -0
- package/dist/lib/content-types/queries/workspace-grants.query.d.ts +25 -0
- package/dist/lib/content-types/queries/workspace-grants.query.d.ts.map +1 -0
- package/dist/lib/content-types/queries/workspace-grants.query.js +45 -0
- package/dist/lib/content.module.d.ts +21 -0
- package/dist/lib/content.module.d.ts.map +1 -0
- package/dist/lib/content.module.js +264 -0
- package/dist/lib/content.tokens.d.ts +5 -0
- package/dist/lib/content.tokens.d.ts.map +1 -0
- package/dist/lib/content.tokens.js +9 -0
- package/dist/lib/copilot/content-tool.provider.d.ts +64 -0
- package/dist/lib/copilot/content-tool.provider.d.ts.map +1 -0
- package/dist/lib/copilot/content-tool.provider.js +309 -0
- package/dist/lib/copilot/diff-snapshots.d.ts +42 -0
- package/dist/lib/copilot/diff-snapshots.d.ts.map +1 -0
- package/dist/lib/copilot/diff-snapshots.js +77 -0
- package/dist/lib/copilot/entry-proposal.applier.d.ts +89 -0
- package/dist/lib/copilot/entry-proposal.applier.d.ts.map +1 -0
- package/dist/lib/copilot/entry-proposal.applier.js +245 -0
- package/dist/lib/copilot/entry-proposal.provider.d.ts +157 -0
- package/dist/lib/copilot/entry-proposal.provider.d.ts.map +1 -0
- package/dist/lib/copilot/entry-proposal.provider.js +619 -0
- package/dist/lib/copilot/filter-schema.d.ts +61 -0
- package/dist/lib/copilot/filter-schema.d.ts.map +1 -0
- package/dist/lib/copilot/filter-schema.js +139 -0
- package/dist/lib/copilot/project-entry.d.ts +23 -0
- package/dist/lib/copilot/project-entry.d.ts.map +1 -0
- package/dist/lib/copilot/project-entry.js +36 -0
- package/dist/lib/copilot/proposal-kinds.d.ts +30 -0
- package/dist/lib/copilot/proposal-kinds.d.ts.map +1 -0
- package/dist/lib/copilot/proposal-kinds.js +32 -0
- package/dist/lib/copilot/revision-tool.provider.d.ts +56 -0
- package/dist/lib/copilot/revision-tool.provider.d.ts.map +1 -0
- package/dist/lib/copilot/revision-tool.provider.js +215 -0
- package/dist/lib/docs/content-schemas.d.ts +34 -0
- package/dist/lib/docs/content-schemas.d.ts.map +1 -0
- package/dist/lib/docs/content-schemas.js +617 -0
- package/dist/lib/docs/describe-content-api.d.ts +22 -0
- package/dist/lib/docs/describe-content-api.d.ts.map +1 -0
- package/dist/lib/docs/describe-content-api.js +173 -0
- package/dist/lib/docs/field-schema.d.ts +28 -0
- package/dist/lib/docs/field-schema.d.ts.map +1 -0
- package/dist/lib/docs/field-schema.js +214 -0
- package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.d.ts +23 -0
- package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.d.ts.map +1 -0
- package/dist/lib/entries/application/use-cases/bulk-publish-entries.use-case.js +77 -0
- package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.d.ts +23 -0
- package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.d.ts.map +1 -0
- package/dist/lib/entries/application/use-cases/bulk-unpublish-entries.use-case.js +66 -0
- package/dist/lib/entries/application/use-cases/publish-entry.use-case.d.ts +43 -0
- package/dist/lib/entries/application/use-cases/publish-entry.use-case.d.ts.map +1 -0
- package/dist/lib/entries/application/use-cases/publish-entry.use-case.js +106 -0
- package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.d.ts +30 -0
- package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.d.ts.map +1 -0
- package/dist/lib/entries/application/use-cases/unpublish-entry.use-case.js +70 -0
- package/dist/lib/entries/controllers/bulk-entries.controller.d.ts +26 -0
- package/dist/lib/entries/controllers/bulk-entries.controller.d.ts.map +1 -0
- package/dist/lib/entries/controllers/create-entry.controller.d.ts +20 -0
- package/dist/lib/entries/controllers/create-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/controllers/delete-entry.controller.d.ts +24 -0
- package/dist/lib/entries/controllers/delete-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/controllers/get-entry.controller.d.ts +34 -0
- package/dist/lib/entries/controllers/get-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/controllers/list-entries.controller.d.ts +20 -0
- package/dist/lib/entries/controllers/list-entries.controller.d.ts.map +1 -0
- package/dist/lib/entries/controllers/publish-entry.controller.d.ts +19 -0
- package/dist/lib/entries/controllers/publish-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/controllers/resolve-type.d.ts +9 -0
- package/dist/lib/entries/controllers/resolve-type.d.ts.map +1 -0
- package/dist/lib/entries/controllers/update-entry.controller.d.ts +18 -0
- package/dist/lib/entries/controllers/update-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/domain/entry-publish-blocked.error.d.ts +13 -0
- package/dist/lib/entries/domain/entry-publish-blocked.error.d.ts.map +1 -0
- package/dist/lib/entries/domain/entry-publish-blocked.error.js +19 -0
- package/dist/lib/entries/domain/entry.d.ts +71 -0
- package/dist/lib/entries/domain/entry.d.ts.map +1 -0
- package/dist/lib/entries/domain/entry.js +90 -0
- package/dist/lib/entries/domain/events/entry-events.d.ts +67 -0
- package/dist/lib/entries/domain/events/entry-events.d.ts.map +1 -0
- package/dist/lib/entries/domain/events/entry-events.js +100 -0
- package/dist/lib/entries/dto/bulk-ids.dto.d.ts +11 -0
- package/dist/lib/entries/dto/bulk-ids.dto.d.ts.map +1 -0
- package/dist/lib/entries/dto/list-entries-query.dto.d.ts +46 -0
- package/dist/lib/entries/dto/list-entries-query.dto.d.ts.map +1 -0
- package/dist/lib/entries/dto/relation-delta-map.validator.d.ts +19 -0
- package/dist/lib/entries/dto/relation-delta-map.validator.d.ts.map +1 -0
- package/dist/lib/entries/dto/save-entry.dto.d.ts +46 -0
- package/dist/lib/entries/dto/save-entry.dto.d.ts.map +1 -0
- package/dist/lib/entries/entries.constants.d.ts +19 -0
- package/dist/lib/entries/entries.constants.d.ts.map +1 -0
- package/dist/lib/entries/entries.constants.js +21 -0
- package/dist/lib/entries/http/controllers/bulk-entries.controller.d.ts +33 -0
- package/dist/lib/entries/http/controllers/bulk-entries.controller.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/bulk-entries.controller.js +143 -0
- package/dist/lib/entries/http/controllers/create-entry.controller.d.ts +21 -0
- package/dist/lib/entries/http/controllers/create-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/create-entry.controller.js +52 -0
- package/dist/lib/entries/http/controllers/delete-entry.controller.d.ts +25 -0
- package/dist/lib/entries/http/controllers/delete-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/delete-entry.controller.js +84 -0
- package/dist/lib/entries/http/controllers/get-entry.controller.d.ts +44 -0
- package/dist/lib/entries/http/controllers/get-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/get-entry.controller.js +124 -0
- package/dist/lib/entries/http/controllers/list-entries.controller.d.ts +20 -0
- package/dist/lib/entries/http/controllers/list-entries.controller.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/list-entries.controller.js +52 -0
- package/dist/lib/entries/http/controllers/publish-entry.controller.d.ts +22 -0
- package/dist/lib/entries/http/controllers/publish-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/publish-entry.controller.js +68 -0
- package/dist/lib/entries/http/controllers/resolve-type.d.ts +9 -0
- package/dist/lib/entries/http/controllers/resolve-type.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/resolve-type.js +16 -0
- package/dist/lib/entries/http/controllers/to-actor.d.ts +13 -0
- package/dist/lib/entries/http/controllers/to-actor.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/to-actor.js +15 -0
- package/dist/lib/entries/http/controllers/update-entry.controller.d.ts +19 -0
- package/dist/lib/entries/http/controllers/update-entry.controller.d.ts.map +1 -0
- package/dist/lib/entries/http/controllers/update-entry.controller.js +51 -0
- package/dist/lib/entries/http/dto/bulk-ids.dto.d.ts +11 -0
- package/dist/lib/entries/http/dto/bulk-ids.dto.d.ts.map +1 -0
- package/dist/lib/entries/http/dto/bulk-ids.dto.js +33 -0
- package/dist/lib/entries/http/dto/list-entries-query.dto.d.ts +66 -0
- package/dist/lib/entries/http/dto/list-entries-query.dto.d.ts.map +1 -0
- package/dist/lib/entries/http/dto/list-entries-query.dto.js +192 -0
- package/dist/lib/entries/http/dto/relation-delta-map.validator.d.ts +30 -0
- package/dist/lib/entries/http/dto/relation-delta-map.validator.d.ts.map +1 -0
- package/dist/lib/entries/http/dto/relation-delta-map.validator.js +102 -0
- package/dist/lib/entries/http/dto/save-entry.dto.d.ts +48 -0
- package/dist/lib/entries/http/dto/save-entry.dto.d.ts.map +1 -0
- package/dist/lib/entries/http/dto/save-entry.dto.js +120 -0
- package/dist/lib/entries/http/guards/content-grant.guard.d.ts +37 -0
- package/dist/lib/entries/http/guards/content-grant.guard.d.ts.map +1 -0
- package/dist/lib/entries/http/guards/content-grant.guard.js +67 -0
- package/dist/lib/entries/infrastructure/persistence/bulk-publish-verdicts.d.ts +22 -0
- package/dist/lib/entries/infrastructure/persistence/bulk-publish-verdicts.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/persistence/bulk-publish-verdicts.js +81 -0
- package/dist/lib/entries/infrastructure/persistence/entry-counter.service.d.ts +42 -0
- package/dist/lib/entries/infrastructure/persistence/entry-counter.service.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/persistence/entry-counter.service.js +73 -0
- package/dist/lib/entries/infrastructure/persistence/entry-row.d.ts +56 -0
- package/dist/lib/entries/infrastructure/persistence/entry-row.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/persistence/entry-row.js +185 -0
- package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts +392 -0
- package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/persistence/entry-writer.service.js +1223 -0
- package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts +24 -0
- package/dist/lib/entries/infrastructure/persistence/field-selection.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/persistence/media-accept.d.ts +23 -0
- package/dist/lib/entries/infrastructure/persistence/media-accept.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/persistence/media-accept.js +55 -0
- package/dist/lib/entries/infrastructure/persistence/relation-link.service.d.ts +327 -0
- package/dist/lib/entries/infrastructure/persistence/relation-link.service.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/persistence/relation-link.service.js +1008 -0
- package/dist/lib/entries/infrastructure/queries/bulk-publish-preview.query.d.ts +19 -0
- package/dist/lib/entries/infrastructure/queries/bulk-publish-preview.query.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/queries/bulk-publish-preview.query.js +39 -0
- package/dist/lib/entries/infrastructure/queries/entries.service.d.ts +64 -0
- package/dist/lib/entries/infrastructure/queries/entries.service.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/queries/entries.service.js +202 -0
- package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts +40 -0
- package/dist/lib/entries/infrastructure/queries/entry-filter-schema.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/queries/entry-filter-surface.d.ts +38 -0
- package/dist/lib/entries/infrastructure/queries/entry-filter-surface.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/queries/entry-filter-surface.js +310 -0
- package/dist/lib/entries/infrastructure/queries/entry-scalar-fields.d.ts +25 -0
- package/dist/lib/entries/infrastructure/queries/entry-scalar-fields.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/queries/entry-scalar-fields.js +51 -0
- package/dist/lib/entries/infrastructure/queries/entry-search.d.ts +19 -0
- package/dist/lib/entries/infrastructure/queries/entry-search.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/queries/entry-search.js +52 -0
- package/dist/lib/entries/infrastructure/queries/media-refs.query.d.ts +21 -0
- package/dist/lib/entries/infrastructure/queries/media-refs.query.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/queries/media-refs.query.js +117 -0
- package/dist/lib/entries/services/entries.service.d.ts +59 -0
- package/dist/lib/entries/services/entries.service.d.ts.map +1 -0
- package/dist/lib/entries/services/entry-counter.service.d.ts +31 -0
- package/dist/lib/entries/services/entry-counter.service.d.ts.map +1 -0
- package/dist/lib/entries/services/entry-filter-schema.d.ts +32 -0
- package/dist/lib/entries/services/entry-filter-schema.d.ts.map +1 -0
- package/dist/lib/entries/services/entry-row.d.ts +56 -0
- package/dist/lib/entries/services/entry-row.d.ts.map +1 -0
- package/dist/lib/entries/services/entry-writer.service.d.ts +193 -0
- package/dist/lib/entries/services/entry-writer.service.d.ts.map +1 -0
- package/dist/lib/entries/services/relation-link.service.d.ts +115 -0
- package/dist/lib/entries/services/relation-link.service.d.ts.map +1 -0
- package/dist/lib/entries/types/bulk-publish.d.ts +75 -0
- package/dist/lib/entries/types/bulk-publish.d.ts.map +1 -0
- package/dist/lib/entries/types/bulk-publish.js +22 -0
- package/dist/lib/entries/types/entry-list-view.d.ts +205 -0
- package/dist/lib/entries/types/entry-list-view.d.ts.map +1 -0
- package/dist/lib/entries/types/entry-list-view.js +5 -0
- package/dist/lib/entries/types/filter-surface.d.ts +35 -0
- package/dist/lib/entries/types/filter-surface.d.ts.map +1 -0
- package/dist/lib/entries/types/filter-surface.js +2 -0
- package/dist/lib/extension/entry-extension-boot-check.d.ts +16 -0
- package/dist/lib/extension/entry-extension-boot-check.d.ts.map +1 -0
- package/dist/lib/extension/entry-extension-boot-check.js +42 -0
- package/dist/lib/extension/entry-extension.d.ts +225 -0
- package/dist/lib/extension/entry-extension.d.ts.map +1 -0
- package/dist/lib/extension/entry-extension.js +27 -0
- package/dist/lib/extension/media-asset-resolver.d.ts +85 -0
- package/dist/lib/extension/media-asset-resolver.d.ts.map +1 -0
- package/dist/lib/extension/media-asset-resolver.js +26 -0
- package/dist/lib/extension/per-locale-relation.d.ts +18 -0
- package/dist/lib/extension/per-locale-relation.d.ts.map +1 -0
- package/dist/lib/extension/relation-locale-sync.d.ts +62 -0
- package/dist/lib/extension/relation-locale-sync.d.ts.map +1 -0
- package/dist/lib/extension/relation-locale-sync.js +88 -0
- package/dist/lib/fields/index.d.ts +94 -0
- package/dist/lib/fields/index.d.ts.map +1 -0
- package/dist/lib/fields/index.js +203 -0
- package/dist/lib/insights/http/controllers/content-pipeline.controller.d.ts +16 -0
- package/dist/lib/insights/http/controllers/content-pipeline.controller.d.ts.map +1 -0
- package/dist/lib/insights/http/controllers/content-pipeline.controller.js +39 -0
- package/dist/lib/insights/http/controllers/content-punchcard.controller.d.ts +18 -0
- package/dist/lib/insights/http/controllers/content-punchcard.controller.d.ts.map +1 -0
- package/dist/lib/insights/http/controllers/content-punchcard.controller.js +42 -0
- package/dist/lib/insights/http/controllers/content-stale.controller.d.ts +17 -0
- package/dist/lib/insights/http/controllers/content-stale.controller.d.ts.map +1 -0
- package/dist/lib/insights/http/controllers/content-stale.controller.js +40 -0
- package/dist/lib/insights/http/controllers/content-totals.controller.d.ts +18 -0
- package/dist/lib/insights/http/controllers/content-totals.controller.d.ts.map +1 -0
- package/dist/lib/insights/http/controllers/content-totals.controller.js +42 -0
- package/dist/lib/insights/http/controllers/content-unshipped.controller.d.ts +17 -0
- package/dist/lib/insights/http/controllers/content-unshipped.controller.d.ts.map +1 -0
- package/dist/lib/insights/http/controllers/content-unshipped.controller.js +40 -0
- package/dist/lib/insights/http/controllers/content-velocity.controller.d.ts +17 -0
- package/dist/lib/insights/http/controllers/content-velocity.controller.d.ts.map +1 -0
- package/dist/lib/insights/http/controllers/content-velocity.controller.js +41 -0
- package/dist/lib/insights/http/dto/insights-range-query.dto.d.ts +15 -0
- package/dist/lib/insights/http/dto/insights-range-query.dto.d.ts.map +1 -0
- package/dist/lib/insights/http/dto/insights-range-query.dto.js +38 -0
- package/dist/lib/insights/infrastructure/queries/content-insights.query.d.ts +77 -0
- package/dist/lib/insights/infrastructure/queries/content-insights.query.d.ts.map +1 -0
- package/dist/lib/insights/infrastructure/queries/content-insights.query.js +380 -0
- package/dist/lib/insights/types/content-insights-view.d.ts +134 -0
- package/dist/lib/insights/types/content-insights-view.d.ts.map +1 -0
- package/dist/lib/insights/types/content-insights-view.js +10 -0
- package/dist/lib/mcp/content-tools.provider.d.ts +83 -0
- package/dist/lib/mcp/content-tools.provider.d.ts.map +1 -0
- package/dist/lib/mcp/content-tools.provider.js +441 -0
- package/dist/lib/mcp/tool-input.d.ts +43 -0
- package/dist/lib/mcp/tool-input.d.ts.map +1 -0
- package/dist/lib/mcp/tool-input.js +117 -0
- package/dist/lib/mcp/tool-schemas.d.ts +34 -0
- package/dist/lib/mcp/tool-schemas.d.ts.map +1 -0
- package/dist/lib/mcp/tool-schemas.js +282 -0
- package/dist/lib/public/controllers/get-public-entry.controller.d.ts +26 -0
- package/dist/lib/public/controllers/get-public-entry.controller.d.ts.map +1 -0
- package/dist/lib/public/controllers/list-public-entries.controller.d.ts +24 -0
- package/dist/lib/public/controllers/list-public-entries.controller.d.ts.map +1 -0
- package/dist/lib/public/controllers/public-schema.controller.d.ts +18 -0
- package/dist/lib/public/controllers/public-schema.controller.d.ts.map +1 -0
- package/dist/lib/public-api/http/api-token-request.d.ts +41 -0
- package/dist/lib/public-api/http/api-token-request.d.ts.map +1 -0
- package/dist/lib/public-api/http/api-token-request.js +2 -0
- package/dist/lib/public-api/http/controllers/public-content-types.controller.d.ts +31 -0
- package/dist/lib/public-api/http/controllers/public-content-types.controller.d.ts.map +1 -0
- package/dist/lib/public-api/http/controllers/public-content-types.controller.js +93 -0
- package/dist/lib/public-api/http/controllers/public-entries.controller.d.ts +101 -0
- package/dist/lib/public-api/http/controllers/public-entries.controller.d.ts.map +1 -0
- package/dist/lib/public-api/http/controllers/public-entries.controller.js +307 -0
- package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts +76 -0
- package/dist/lib/public-api/http/controllers/public-entry-writes.controller.d.ts.map +1 -0
- package/dist/lib/public-api/http/controllers/public-entry-writes.controller.js +353 -0
- package/dist/lib/public-api/http/controllers/resolve-granted-type.d.ts +42 -0
- package/dist/lib/public-api/http/controllers/resolve-granted-type.d.ts.map +1 -0
- package/dist/lib/public-api/http/controllers/resolve-granted-type.js +25 -0
- package/dist/lib/public-api/http/decorators/current-api-token.decorator.d.ts +8 -0
- package/dist/lib/public-api/http/decorators/current-api-token.decorator.d.ts.map +1 -0
- package/dist/lib/public-api/http/decorators/current-api-token.decorator.js +17 -0
- package/dist/lib/public-api/http/dto/public-bulk.dto.d.ts +58 -0
- package/dist/lib/public-api/http/dto/public-bulk.dto.d.ts.map +1 -0
- package/dist/lib/public-api/http/dto/public-bulk.dto.js +118 -0
- package/dist/lib/public-api/http/dto/public-list-entries-query.dto.d.ts +106 -0
- package/dist/lib/public-api/http/dto/public-list-entries-query.dto.d.ts.map +1 -0
- package/dist/lib/public-api/http/dto/public-list-entries-query.dto.js +297 -0
- package/dist/lib/public-api/http/dto/public-save-entry.dto.d.ts +39 -0
- package/dist/lib/public-api/http/dto/public-save-entry.dto.d.ts.map +1 -0
- package/dist/lib/public-api/http/dto/public-save-entry.dto.js +112 -0
- package/dist/lib/public-api/http/guards/api-token-workspace.guard.d.ts +25 -0
- package/dist/lib/public-api/http/guards/api-token-workspace.guard.d.ts.map +1 -0
- package/dist/lib/public-api/http/guards/api-token-workspace.guard.js +58 -0
- package/dist/lib/public-api/http/guards/api-token.guard.d.ts +32 -0
- package/dist/lib/public-api/http/guards/api-token.guard.d.ts.map +1 -0
- package/dist/lib/public-api/http/guards/api-token.guard.js +92 -0
- package/dist/lib/public-api/http/guards/draft-visibility.guard.d.ts +25 -0
- package/dist/lib/public-api/http/guards/draft-visibility.guard.d.ts.map +1 -0
- package/dist/lib/public-api/http/guards/draft-visibility.guard.js +56 -0
- package/dist/lib/public-api/infrastructure/bulk-save-op.d.ts +55 -0
- package/dist/lib/public-api/infrastructure/bulk-save-op.d.ts.map +1 -0
- package/dist/lib/public-api/infrastructure/bulk-save-op.js +61 -0
- package/dist/lib/public-api/infrastructure/field-selection.d.ts +21 -0
- package/dist/lib/public-api/infrastructure/field-selection.d.ts.map +1 -0
- package/dist/lib/public-api/infrastructure/field-selection.js +72 -0
- package/dist/lib/public-api/infrastructure/public-entries.query.d.ts +248 -0
- package/dist/lib/public-api/infrastructure/public-entries.query.d.ts.map +1 -0
- package/dist/lib/public-api/infrastructure/public-entries.query.js +557 -0
- package/dist/lib/public-api/infrastructure/public-entry-row.d.ts +31 -0
- package/dist/lib/public-api/infrastructure/public-entry-row.d.ts.map +1 -0
- package/dist/lib/public-api/infrastructure/public-entry-row.js +76 -0
- package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts +188 -0
- package/dist/lib/public-api/infrastructure/public-entry-writes.service.d.ts.map +1 -0
- package/dist/lib/public-api/infrastructure/public-entry-writes.service.js +321 -0
- package/dist/lib/public-api/infrastructure/public-expansion.query.d.ts +98 -0
- package/dist/lib/public-api/infrastructure/public-expansion.query.d.ts.map +1 -0
- package/dist/lib/public-api/infrastructure/public-expansion.query.js +384 -0
- package/dist/lib/public-api/types/public-bulk.d.ts +77 -0
- package/dist/lib/public-api/types/public-bulk.d.ts.map +1 -0
- package/dist/lib/public-api/types/public-bulk.js +23 -0
- package/dist/lib/public-api/types/public-entry.d.ts +97 -0
- package/dist/lib/public-api/types/public-entry.d.ts.map +1 -0
- package/dist/lib/public-api/types/public-entry.js +8 -0
- package/dist/lib/public-api/types/public-expansion.d.ts +92 -0
- package/dist/lib/public-api/types/public-expansion.d.ts.map +1 -0
- package/dist/lib/public-api/types/public-expansion.js +2 -0
- package/dist/lib/registry/content-type-registry.d.ts +103 -0
- package/dist/lib/registry/content-type-registry.d.ts.map +1 -0
- package/dist/lib/registry/content-type-registry.js +155 -0
- package/dist/lib/revisions/application/ports/revision-store.d.ts +71 -0
- package/dist/lib/revisions/application/ports/revision-store.d.ts.map +1 -0
- package/dist/lib/revisions/application/ports/revision-store.js +9 -0
- package/dist/lib/revisions/application/use-cases/publish-revision.use-case.d.ts +40 -0
- package/dist/lib/revisions/application/use-cases/publish-revision.use-case.d.ts.map +1 -0
- package/dist/lib/revisions/application/use-cases/publish-revision.use-case.js +66 -0
- package/dist/lib/revisions/application/use-cases/restore-revision.use-case.d.ts +36 -0
- package/dist/lib/revisions/application/use-cases/restore-revision.use-case.d.ts.map +1 -0
- package/dist/lib/revisions/application/use-cases/restore-revision.use-case.js +57 -0
- package/dist/lib/revisions/domain/revision-status.d.ts +18 -0
- package/dist/lib/revisions/domain/revision-status.d.ts.map +1 -0
- package/dist/lib/revisions/domain/revision-status.js +18 -0
- package/dist/lib/revisions/domain/revision.d.ts +80 -0
- package/dist/lib/revisions/domain/revision.d.ts.map +1 -0
- package/dist/lib/revisions/domain/revision.js +84 -0
- package/dist/lib/revisions/http/controllers/publish-revision.controller.d.ts +19 -0
- package/dist/lib/revisions/http/controllers/publish-revision.controller.d.ts.map +1 -0
- package/dist/lib/revisions/http/controllers/publish-revision.controller.js +51 -0
- package/dist/lib/revisions/http/controllers/restore-revision.controller.d.ts +17 -0
- package/dist/lib/revisions/http/controllers/restore-revision.controller.d.ts.map +1 -0
- package/dist/lib/revisions/http/controllers/restore-revision.controller.js +49 -0
- package/dist/lib/revisions/http/controllers/revisions.controller.d.ts +20 -0
- package/dist/lib/revisions/http/controllers/revisions.controller.d.ts.map +1 -0
- package/dist/lib/revisions/http/controllers/revisions.controller.js +76 -0
- package/dist/lib/revisions/infrastructure/persistence/drizzle-revision.store.d.ts +33 -0
- package/dist/lib/revisions/infrastructure/persistence/drizzle-revision.store.d.ts.map +1 -0
- package/dist/lib/revisions/infrastructure/persistence/drizzle-revision.store.js +174 -0
- package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.d.ts +17 -0
- package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.d.ts.map +1 -0
- package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.js +20 -0
- package/dist/lib/revisions/infrastructure/persistence/revision-table.d.ts +228 -0
- package/dist/lib/revisions/infrastructure/persistence/revision-table.d.ts.map +1 -0
- package/dist/lib/revisions/infrastructure/persistence/revision-table.js +57 -0
- package/dist/lib/revisions/infrastructure/queries/revision-refs.query.d.ts +22 -0
- package/dist/lib/revisions/infrastructure/queries/revision-refs.query.d.ts.map +1 -0
- package/dist/lib/revisions/infrastructure/queries/revision-refs.query.js +66 -0
- package/dist/lib/revisions/revisions.constants.d.ts +10 -0
- package/dist/lib/revisions/revisions.constants.d.ts.map +1 -0
- package/dist/lib/revisions/revisions.constants.js +12 -0
- package/dist/lib/revisions/types/revision-view.d.ts +74 -0
- package/dist/lib/revisions/types/revision-view.d.ts.map +1 -0
- package/dist/lib/revisions/types/revision-view.js +2 -0
- package/dist/lib/types/content-type.d.ts +131 -0
- package/dist/lib/types/content-type.d.ts.map +1 -0
- package/dist/lib/types/content-type.js +28 -0
- package/dist/lib/types/fields.d.ts +303 -0
- package/dist/lib/types/fields.d.ts.map +1 -0
- package/dist/lib/types/fields.js +52 -0
- package/dist/lib/utils/content-plugin.d.ts +35 -0
- package/dist/lib/utils/content-plugin.d.ts.map +1 -0
- package/dist/lib/utils/content-plugin.js +35 -0
- package/dist/lib/validation/services/entry-validation.service.d.ts +24 -0
- package/dist/lib/validation/services/entry-validation.service.d.ts.map +1 -0
- package/dist/lib/validation/services/entry-validation.service.js +35 -0
- package/package.json +54 -0
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EntryProposalToolProvider = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const identity_server_1 = require("@orthacms/identity-server");
|
|
7
|
+
const tools_server_1 = require("@orthacms/tools-server");
|
|
8
|
+
const content_tokens_1 = require("../content.tokens");
|
|
9
|
+
const entry_writer_service_1 = require("../entries/infrastructure/persistence/entry-writer.service");
|
|
10
|
+
const workspace_grants_query_1 = require("../content-types/queries/workspace-grants.query");
|
|
11
|
+
const entries_constants_1 = require("../entries/entries.constants");
|
|
12
|
+
const entry_extension_1 = require("../extension/entry-extension");
|
|
13
|
+
const proposal_kinds_1 = require("./proposal-kinds");
|
|
14
|
+
/**
|
|
15
|
+
* The content plugin's **write** tools — `content_propose_create`,
|
|
16
|
+
* `content_propose_update`, and `content_propose_bulk_save` for the batch.
|
|
17
|
+
*
|
|
18
|
+
* All three are `effect: 'propose'`: they compute a change and hand it back, and the
|
|
19
|
+
* run engine persists it as a `copilot_proposals` row for a human to accept
|
|
20
|
+
* ([ADR-0005](../../../../../../docs/adr/0005-copilot-authority-model.md) §5).
|
|
21
|
+
* **Nothing here writes to the database.** That is the whole point of the split
|
|
22
|
+
* — the tool is a pure function of the model's arguments plus the current
|
|
23
|
+
* entry, so a prompt-injected instruction to "just save it" has nowhere to
|
|
24
|
+
* land, and the actual write happens later through the ordinary use-case with a
|
|
25
|
+
* person as actor.
|
|
26
|
+
*
|
|
27
|
+
* Two things they *do* touch the database for, both reads: resolving the
|
|
28
|
+
* workspace's content grants, and loading the entry an edit would change — the
|
|
29
|
+
* latter so the proposal carries a real before/after diff rather than a patch a
|
|
30
|
+
* reviewer has to mentally apply.
|
|
31
|
+
*
|
|
32
|
+
* **`content:publish` is not exposed at any role** (ADR-0005 §7). The copilot
|
|
33
|
+
* may prepare a publishable draft; a person presses publish. There is
|
|
34
|
+
* deliberately no `status` in any of their schemas — and no bulk publish or
|
|
35
|
+
* bulk delete either, however convenient: batching is a way of *asking*, not a
|
|
36
|
+
* route to authority a single-entry tool was not given.
|
|
37
|
+
*/
|
|
38
|
+
let EntryProposalToolProvider = class EntryProposalToolProvider {
|
|
39
|
+
registry;
|
|
40
|
+
writer;
|
|
41
|
+
grants;
|
|
42
|
+
toolRegistry;
|
|
43
|
+
extension;
|
|
44
|
+
constructor(registry, writer, grants, toolRegistry, extension) {
|
|
45
|
+
this.registry = registry;
|
|
46
|
+
this.writer = writer;
|
|
47
|
+
this.grants = grants;
|
|
48
|
+
this.toolRegistry = toolRegistry;
|
|
49
|
+
this.extension = extension;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Register with the shared tool registry once the DI graph is built —
|
|
53
|
+
* the same catalogue the MCP endpoint serves, narrowed to the `copilot`
|
|
54
|
+
* surface by each tool's `surfaces`. `@Optional()` because a deployment
|
|
55
|
+
* may run neither consumer, in which case these simply go unregistered.
|
|
56
|
+
*/
|
|
57
|
+
onModuleInit() {
|
|
58
|
+
this.toolRegistry?.register(this);
|
|
59
|
+
}
|
|
60
|
+
/** The three write tools, in the order the model sees them. */
|
|
61
|
+
tools() {
|
|
62
|
+
return [this.proposeEntry(), this.proposeEdit(), this.proposeBulk()];
|
|
63
|
+
}
|
|
64
|
+
/** Resolves a granted, registered type — the same uniform message as the reads. */
|
|
65
|
+
async resolveGranted(typeName, workspaceId) {
|
|
66
|
+
const type = this.registry.get(typeName);
|
|
67
|
+
const granted = await this.grants.grantedSlugs(workspaceId);
|
|
68
|
+
if (!type || !granted.has(type.name)) {
|
|
69
|
+
throw new Error(`Unknown content type "${typeName}" in this workspace.`);
|
|
70
|
+
}
|
|
71
|
+
return type;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The type's writable fields, keyed by name.
|
|
75
|
+
*
|
|
76
|
+
* **Back-references are excluded and owning many-relations are not.** The
|
|
77
|
+
* exclusion used to cover both, on the stated grounds that join-backed
|
|
78
|
+
* links "never travel in the `values` bag" — which is not true of the
|
|
79
|
+
* owning side: `RelationLinkService.writeLinks` performs a whole-set write
|
|
80
|
+
* for any owning many-relation submitted as an **array**, on create and on
|
|
81
|
+
* update alike, and the appliers already merge the patch straight into the
|
|
82
|
+
* values they hand the writer. So refusing `article.tags` refused something
|
|
83
|
+
* that works, which is how "Unknown or non-writable field(s): tags" came to
|
|
84
|
+
* be the answer to a perfectly ordinary request.
|
|
85
|
+
*
|
|
86
|
+
* An **inverse** relation genuinely cannot be written from this side —
|
|
87
|
+
* `writeLinks` skips it (`ownCol !== 'sourceId'`) — so a value for one
|
|
88
|
+
* really would be silently dropped, and a proposal that does nothing is
|
|
89
|
+
* worse than one refused up front.
|
|
90
|
+
*/
|
|
91
|
+
writableFields(typeName) {
|
|
92
|
+
const schema = this.registry.serialize(typeName);
|
|
93
|
+
const fields = new Map();
|
|
94
|
+
for (const field of schema?.fields ?? []) {
|
|
95
|
+
const backReference = field.type === 'relation' && !!field.relation?.inverse;
|
|
96
|
+
if (!backReference) {
|
|
97
|
+
fields.set(field.name, field);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return fields;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Whether a field is written as a **whole set** of target ids.
|
|
104
|
+
*
|
|
105
|
+
* These have no `before` in the diff: the current links are not part of the
|
|
106
|
+
* entry's `values` (`toRecord` drops join-backed fields), so the honest card
|
|
107
|
+
* shows what the set is being made into rather than a fabricated `null`
|
|
108
|
+
* before that reads as "it had no tags".
|
|
109
|
+
*/
|
|
110
|
+
isWholeSetRelation(field) {
|
|
111
|
+
return (field?.type === 'relation' &&
|
|
112
|
+
!!field.relation?.many &&
|
|
113
|
+
!field.relation.inverse);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Narrows model-supplied values to the type's writable fields, rejecting a
|
|
117
|
+
* name that isn't one.
|
|
118
|
+
*
|
|
119
|
+
* Unlike the read tools' `fields`, an unknown name here is an **error**.
|
|
120
|
+
* There the cost of a mis-remembered name is a missing column in a result
|
|
121
|
+
* the model can see; here it is a change a human approves believing it
|
|
122
|
+
* writes a field that does not exist.
|
|
123
|
+
*/
|
|
124
|
+
narrowValues(typeName, values) {
|
|
125
|
+
const fields = this.writableFields(typeName);
|
|
126
|
+
const unknown = Object.keys(values).filter((key) => !fields.has(key));
|
|
127
|
+
if (unknown.length > 0) {
|
|
128
|
+
throw new Error(`Unknown or non-writable field(s) on "${typeName}": ${unknown.join(', ')}. ` +
|
|
129
|
+
'Call admin_content_types for this type’s fields. Many-relations and ' +
|
|
130
|
+
'back-references cannot be set this way.');
|
|
131
|
+
}
|
|
132
|
+
return { values, fields };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Asks the bound entries extension what a write of `values` onto this entry
|
|
136
|
+
* would rewrite **besides** that row.
|
|
137
|
+
*
|
|
138
|
+
* A localized type stores one row per language, and a field the type does
|
|
139
|
+
* not mark `localized` is *shared* — so saving it propagates to every
|
|
140
|
+
* sibling in the translation group. That is the contract working, not a
|
|
141
|
+
* bug: "shared" means shared, and refusing the write would leave no way to
|
|
142
|
+
* edit a shared field at all. What was missing is that nobody was told.
|
|
143
|
+
* Under [ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)
|
|
144
|
+
* the change applies the moment it is drafted, so the proposal's own
|
|
145
|
+
* summary is the only place a person learns that one accepted edit moved
|
|
146
|
+
* their content in four languages — and it read as a single-entry edit.
|
|
147
|
+
*
|
|
148
|
+
* An error is deliberately **not** swallowed. This is a read against the
|
|
149
|
+
* same rows the write is about to take, so a failure here is a failure
|
|
150
|
+
* there; drafting the change anyway would drop the disclosure at exactly
|
|
151
|
+
* the moment something is wrong.
|
|
152
|
+
*/
|
|
153
|
+
async fanoutOf(type, entryId, values, workspaceId) {
|
|
154
|
+
return this.extension?.describeFanout?.(type, entryId, values, workspaceId);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Appends the blast radius to the model's own summary.
|
|
158
|
+
*
|
|
159
|
+
* The summary rather than a field of its own because of where a summary
|
|
160
|
+
* *goes*: it is the card's title, the audit row's `output_summary`, and —
|
|
161
|
+
* via the run engine's `Applied: …` receipt — the sentence the model reads
|
|
162
|
+
* back and reports to the user. One string reaches the person, the log and
|
|
163
|
+
* the model, and the model correcting itself ("that touched every
|
|
164
|
+
* language — for a translation I should use `i18n_propose_translation`") is
|
|
165
|
+
* worth as much here as the card is.
|
|
166
|
+
*/
|
|
167
|
+
discloseFanout(summary, fanout, records = 1) {
|
|
168
|
+
if (!fanout)
|
|
169
|
+
return summary;
|
|
170
|
+
// Plural on either axis: two locales of one record and one locale of
|
|
171
|
+
// two records are both several rows, and "the de row of 2 of these
|
|
172
|
+
// records" reads as a single row shared between them.
|
|
173
|
+
const rows = `${fanout.locales.join(', ')} ${fanout.locales.length === 1 && records === 1 ? 'row' : 'rows'}`;
|
|
174
|
+
// A batch names how many of its records fan out, because "some of
|
|
175
|
+
// them" is the part a reader needs and the count is the only honest
|
|
176
|
+
// way to say it — the card lists one diff row per item, and matching
|
|
177
|
+
// them up by hand is exactly the work the summary exists to save.
|
|
178
|
+
const scope = records === 1
|
|
179
|
+
? `this record’s ${rows}`
|
|
180
|
+
: `the ${rows} of ${records} of these records`;
|
|
181
|
+
const fields = fanout.fields.join(', ');
|
|
182
|
+
return (`${summary} — also changes ${scope}, because ${fields} ` +
|
|
183
|
+
`${fanout.fields.length === 1 ? 'is' : 'are'} shared across locales.`);
|
|
184
|
+
}
|
|
185
|
+
/** `content_propose_create` — a new draft entry, for a human to accept. */
|
|
186
|
+
proposeEntry() {
|
|
187
|
+
return {
|
|
188
|
+
name: 'content_propose_create',
|
|
189
|
+
title: 'Propose a new entry',
|
|
190
|
+
description: 'Propose creating a new entry. This does NOT create anything — it drafts the ' +
|
|
191
|
+
'change and asks the user to approve it, and the reply will say so. Call ' +
|
|
192
|
+
'admin_content_types for the type’s fields first; supply only fields you are ' +
|
|
193
|
+
'confident about, since the user reviews exactly what you send. On a ' +
|
|
194
|
+
'PUBLISHABLE type the entry lands as a draft, so a partial one saves fine and ' +
|
|
195
|
+
'you cannot publish it. On a type that is NOT publishable there is no draft — ' +
|
|
196
|
+
'the row is live immediately, so every field it marks `required` must be in ' +
|
|
197
|
+
'`values` or the save is refused; ask the user for a value you do not know.',
|
|
198
|
+
inputSchema: {
|
|
199
|
+
type: 'object',
|
|
200
|
+
properties: {
|
|
201
|
+
typeName: {
|
|
202
|
+
type: 'string',
|
|
203
|
+
description: 'The content type to create an entry of.'
|
|
204
|
+
},
|
|
205
|
+
values: {
|
|
206
|
+
type: 'object',
|
|
207
|
+
description: 'Field values keyed by field name, as admin_content_types describes ' +
|
|
208
|
+
'them. A many-relation (e.g. tags) takes an array of target entry ' +
|
|
209
|
+
'ids — find them with admin_content_search. Back-references cannot ' +
|
|
210
|
+
'be set here.'
|
|
211
|
+
},
|
|
212
|
+
locale: {
|
|
213
|
+
type: 'string',
|
|
214
|
+
maxLength: 35,
|
|
215
|
+
description: 'Locale to create in, on a localized type — for a NEW record ' +
|
|
216
|
+
'written in that language. Omitted, the default locale is used; ' +
|
|
217
|
+
'call i18n_locales_list if unsure. To add a language to an entry ' +
|
|
218
|
+
'that already exists, use i18n_propose_translation instead.'
|
|
219
|
+
},
|
|
220
|
+
summary: {
|
|
221
|
+
type: 'string',
|
|
222
|
+
maxLength: 200,
|
|
223
|
+
description: 'One line describing the change, shown to the user on the approval ' +
|
|
224
|
+
'card. Write it for a person, e.g. “New article: Spring launch”.'
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
required: ['typeName', 'values', 'summary'],
|
|
228
|
+
additionalProperties: false
|
|
229
|
+
},
|
|
230
|
+
requires: [identity_server_1.PERMISSIONS.CONTENT_CREATE],
|
|
231
|
+
readOnly: false,
|
|
232
|
+
effect: 'propose',
|
|
233
|
+
// Copilot-only: it reads the admin services (a viewer must see
|
|
234
|
+
// drafts) or writes through propose-then-apply with the human as
|
|
235
|
+
// actor. MCP's content tools are the public-API set.
|
|
236
|
+
surfaces: ['copilot'],
|
|
237
|
+
handler: async (input, ctx) => {
|
|
238
|
+
const args = (input ?? {});
|
|
239
|
+
const type = await this.resolveGranted(args.typeName, ctx.workspaceId);
|
|
240
|
+
const { values, fields } = this.narrowValues(type.name, args.values ?? {});
|
|
241
|
+
return {
|
|
242
|
+
kind: proposal_kinds_1.CONTENT_PROPOSAL_KINDS.createEntry,
|
|
243
|
+
// No `localeGroupId`: joining an existing translation group
|
|
244
|
+
// is not a content-save operation, however close the
|
|
245
|
+
// arguments look — see `proposeBulk` and
|
|
246
|
+
// `CreateEntryProposalApplier`.
|
|
247
|
+
target: {
|
|
248
|
+
typeName: type.name,
|
|
249
|
+
...(args.locale ? { locale: args.locale } : {})
|
|
250
|
+
},
|
|
251
|
+
patch: { values },
|
|
252
|
+
summary: args.summary,
|
|
253
|
+
// No `before` on a create — there is nothing to replace, and
|
|
254
|
+
// an explicit `undefined` reads better in the diff than a
|
|
255
|
+
// fabricated `null` that looks like a cleared field.
|
|
256
|
+
changes: Object.entries(values).map(([field, after]) => ({
|
|
257
|
+
field,
|
|
258
|
+
...labelOf(fields.get(field)),
|
|
259
|
+
after
|
|
260
|
+
}))
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/** `content_propose_update` — a change to an existing entry, with a real diff. */
|
|
266
|
+
proposeEdit() {
|
|
267
|
+
return {
|
|
268
|
+
name: 'content_propose_update',
|
|
269
|
+
title: 'Propose an entry edit',
|
|
270
|
+
description: 'Propose changing fields on an existing entry. This does NOT save anything — ' +
|
|
271
|
+
'it drafts the change and asks the user to approve it, and the reply will say ' +
|
|
272
|
+
'so. Send only the fields you are changing: everything else is left alone. ' +
|
|
273
|
+
'The user sees a before/after for each field, so read the entry first ' +
|
|
274
|
+
'(admin_content_get) and change what actually needs changing.',
|
|
275
|
+
inputSchema: {
|
|
276
|
+
type: 'object',
|
|
277
|
+
properties: {
|
|
278
|
+
typeName: {
|
|
279
|
+
type: 'string',
|
|
280
|
+
description: 'The entry’s content type.'
|
|
281
|
+
},
|
|
282
|
+
id: {
|
|
283
|
+
type: 'string',
|
|
284
|
+
description: 'The entry’s id, as returned by admin_content_search.'
|
|
285
|
+
},
|
|
286
|
+
values: {
|
|
287
|
+
type: 'object',
|
|
288
|
+
description: 'Only the fields to change, keyed by field name. Omitted fields ' +
|
|
289
|
+
'keep their current values. A many-relation (e.g. tags) takes an ' +
|
|
290
|
+
'array of target entry ids and REPLACES the whole set, so include ' +
|
|
291
|
+
'the ids it already has as well as the new ones — read them with ' +
|
|
292
|
+
'admin_content_get first, and find new ones with ' +
|
|
293
|
+
'admin_content_search.'
|
|
294
|
+
},
|
|
295
|
+
summary: {
|
|
296
|
+
type: 'string',
|
|
297
|
+
maxLength: 200,
|
|
298
|
+
description: 'One line describing the change, shown on the approval card. ' +
|
|
299
|
+
'Write it for a person, e.g. “Fix the typo in the headline”.'
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
required: ['typeName', 'id', 'values', 'summary'],
|
|
303
|
+
additionalProperties: false
|
|
304
|
+
},
|
|
305
|
+
requires: [identity_server_1.PERMISSIONS.CONTENT_UPDATE],
|
|
306
|
+
readOnly: false,
|
|
307
|
+
effect: 'propose',
|
|
308
|
+
// Copilot-only: it reads the admin services (a viewer must see
|
|
309
|
+
// drafts) or writes through propose-then-apply with the human as
|
|
310
|
+
// actor. MCP's content tools are the public-API set.
|
|
311
|
+
surfaces: ['copilot'],
|
|
312
|
+
handler: async (input, ctx) => {
|
|
313
|
+
const args = (input ?? {});
|
|
314
|
+
const type = await this.resolveGranted(args.typeName, ctx.workspaceId);
|
|
315
|
+
const { values, fields } = this.narrowValues(type.name, args.values ?? {});
|
|
316
|
+
if (Object.keys(values).length === 0) {
|
|
317
|
+
throw new Error('Nothing to change — `values` named no fields.');
|
|
318
|
+
}
|
|
319
|
+
// Read the live entry so the proposal carries a real diff. It
|
|
320
|
+
// also fails here, at propose time, if the entry is gone or
|
|
321
|
+
// outside the workspace — which is a far better moment for the
|
|
322
|
+
// model to find out than after a human has approved.
|
|
323
|
+
const current = await this.writer.getOne(type, args.id, ctx.workspaceId);
|
|
324
|
+
const before = current.values ?? {};
|
|
325
|
+
const changes = Object.entries(values)
|
|
326
|
+
.map(([field, after]) => {
|
|
327
|
+
// A whole-set relation has no readable `before` here —
|
|
328
|
+
// its links are not in the entry's values — so the card
|
|
329
|
+
// shows only what the set becomes.
|
|
330
|
+
if (this.isWholeSetRelation(fields.get(field))) {
|
|
331
|
+
return {
|
|
332
|
+
field,
|
|
333
|
+
...labelOf(fields.get(field)),
|
|
334
|
+
after
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
field,
|
|
339
|
+
...labelOf(fields.get(field)),
|
|
340
|
+
before: before[field] ?? null,
|
|
341
|
+
after
|
|
342
|
+
};
|
|
343
|
+
})
|
|
344
|
+
// A "change" that changes nothing is noise on the card and
|
|
345
|
+
// invites a reviewer to approve a no-op. The model gets the
|
|
346
|
+
// error above only when *every* field is unchanged. A
|
|
347
|
+
// whole-set relation has nothing to compare against, so it
|
|
348
|
+
// always counts as a change.
|
|
349
|
+
.filter((change) => !('before' in change) ||
|
|
350
|
+
JSON.stringify(change.before ?? null) !==
|
|
351
|
+
JSON.stringify(change.after ?? null));
|
|
352
|
+
if (changes.length === 0) {
|
|
353
|
+
throw new Error('That entry already has these values — nothing would change.');
|
|
354
|
+
}
|
|
355
|
+
// Only the genuinely-changed fields are carried, so an
|
|
356
|
+
// accepted proposal writes exactly what the reviewer saw — and
|
|
357
|
+
// so the fan-out below is described against what will actually
|
|
358
|
+
// be written, not against everything the model sent.
|
|
359
|
+
const patched = Object.fromEntries(changes.map((change) => [change.field, change.after]));
|
|
360
|
+
const fanout = await this.fanoutOf(type, args.id, patched, ctx.workspaceId);
|
|
361
|
+
return {
|
|
362
|
+
kind: proposal_kinds_1.CONTENT_PROPOSAL_KINDS.updateEntry,
|
|
363
|
+
target: {
|
|
364
|
+
typeName: type.name,
|
|
365
|
+
entryId: args.id,
|
|
366
|
+
// Structured alongside the prose, so the receipt is
|
|
367
|
+
// queryable: "which changes reached more than the row
|
|
368
|
+
// they named" is a question an audit asks of the table,
|
|
369
|
+
// not of a sentence.
|
|
370
|
+
...(fanout ? { fanout } : {})
|
|
371
|
+
},
|
|
372
|
+
patch: { values: patched },
|
|
373
|
+
summary: this.discloseFanout(args.summary, fanout),
|
|
374
|
+
changes
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* `content_propose_bulk_save` — many creates and edits as **one** change.
|
|
381
|
+
*
|
|
382
|
+
* It exists because the single-entry pair scales badly in the one direction
|
|
383
|
+
* users actually push it: "translate these eight posts", "retag everything
|
|
384
|
+
* from last month". Each entry was a tool call, so a run spent its step
|
|
385
|
+
* budget on round trips and the transcript grew a card per record — eight
|
|
386
|
+
* receipts for one instruction, none of which said what the other seven
|
|
387
|
+
* were.
|
|
388
|
+
*
|
|
389
|
+
* **Still `effect: 'propose'`, and still writes nothing here.** The batch is
|
|
390
|
+
* computed from the model's arguments plus the entries as they are now, and
|
|
391
|
+
* handed back for the engine to record and apply. One proposal row, one
|
|
392
|
+
* card, one diff listing every field of every entry — which is also what
|
|
393
|
+
* makes the batch reviewable after the fact instead of merely fast.
|
|
394
|
+
*
|
|
395
|
+
* The per-item addressing is the smaller half of the public API's: an `id`
|
|
396
|
+
* updates, no `id` creates. There is deliberately no group-addressed update
|
|
397
|
+
* (the ambiguity the REST `op` field resolves), because the admin tools hand
|
|
398
|
+
* the model entry ids and nothing here would produce a bare group id.
|
|
399
|
+
*
|
|
400
|
+
* **And deliberately no `localeGroupId`, which it used to take.** Joining a
|
|
401
|
+
* translation group is not a content save with two extra arguments: a
|
|
402
|
+
* create is a whole row, so every shared field the item did not name
|
|
403
|
+
* arrives as `null`, and the i18n extension then pushes those nulls onto
|
|
404
|
+
* every sibling in the group — blanking the record in every other language,
|
|
405
|
+
* silently where the siblings are drafts. Getting that right means
|
|
406
|
+
* inheriting the source row's shared values at apply time, which is
|
|
407
|
+
* knowledge the i18n plugin owns, so `i18n_propose_bulk_translation` is the
|
|
408
|
+
* route and this tool creates new records only.
|
|
409
|
+
*/
|
|
410
|
+
proposeBulk() {
|
|
411
|
+
return {
|
|
412
|
+
name: 'content_propose_bulk_save',
|
|
413
|
+
title: 'Propose several entry changes',
|
|
414
|
+
description: 'Propose creating and/or changing SEVERAL entries of one content type in a ' +
|
|
415
|
+
'single change. Use this instead of calling content_propose_create or ' +
|
|
416
|
+
'content_propose_update repeatedly — the user sees one approval card listing ' +
|
|
417
|
+
'every entry, and you spend one step instead of one per record. An item with ' +
|
|
418
|
+
'an `id` changes that entry (send only the fields you are changing); an item ' +
|
|
419
|
+
'without one creates a new draft. Read the entries first with ' +
|
|
420
|
+
'admin_content_search / admin_content_get so the diff is real. If any entry ' +
|
|
421
|
+
'fails to save, the change stops there and the reply says how many landed — ' +
|
|
422
|
+
'do not claim the whole batch saved without reading it. On a type that is ' +
|
|
423
|
+
'NOT publishable each created item is live at once, so it must carry every ' +
|
|
424
|
+
'`required` field; a partial item is refused and takes the rest of the batch ' +
|
|
425
|
+
'with it.',
|
|
426
|
+
inputSchema: {
|
|
427
|
+
type: 'object',
|
|
428
|
+
properties: {
|
|
429
|
+
typeName: {
|
|
430
|
+
type: 'string',
|
|
431
|
+
description: 'The content type every item belongs to.'
|
|
432
|
+
},
|
|
433
|
+
items: {
|
|
434
|
+
type: 'array',
|
|
435
|
+
minItems: 1,
|
|
436
|
+
maxItems: entries_constants_1.BULK_MAX_SAVE_ITEMS,
|
|
437
|
+
description: `The entries to save (1…${entries_constants_1.BULK_MAX_SAVE_ITEMS}), applied in order.`,
|
|
438
|
+
items: {
|
|
439
|
+
type: 'object',
|
|
440
|
+
properties: {
|
|
441
|
+
id: {
|
|
442
|
+
type: 'string',
|
|
443
|
+
description: 'The entry to change, as returned by admin_content_search. ' +
|
|
444
|
+
'Omit to create a new entry instead.'
|
|
445
|
+
},
|
|
446
|
+
values: {
|
|
447
|
+
type: 'object',
|
|
448
|
+
description: 'Field values keyed by field name. On an item with an `id`, ' +
|
|
449
|
+
'only the fields to change — omitted fields keep their current ' +
|
|
450
|
+
'values. A many-relation takes an array of target entry ids and ' +
|
|
451
|
+
'REPLACES the whole set.'
|
|
452
|
+
},
|
|
453
|
+
locale: {
|
|
454
|
+
type: 'string',
|
|
455
|
+
maxLength: 35,
|
|
456
|
+
description: 'Locale to create a NEW record in, on a localized type. ' +
|
|
457
|
+
'Create-only — an entry id already names its own locale. To ' +
|
|
458
|
+
'add languages to entries that already exist, use ' +
|
|
459
|
+
'i18n_propose_bulk_translation instead.'
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
required: ['values'],
|
|
463
|
+
additionalProperties: false
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
summary: {
|
|
467
|
+
type: 'string',
|
|
468
|
+
maxLength: 200,
|
|
469
|
+
description: 'One line describing the whole batch, shown to the user on the approval ' +
|
|
470
|
+
'card. Write it for a person, e.g. “Translate 8 posts into German”.'
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
required: ['typeName', 'items', 'summary'],
|
|
474
|
+
additionalProperties: false
|
|
475
|
+
},
|
|
476
|
+
requires: [identity_server_1.PERMISSIONS.CONTENT_CREATE, identity_server_1.PERMISSIONS.CONTENT_UPDATE],
|
|
477
|
+
readOnly: false,
|
|
478
|
+
effect: 'propose',
|
|
479
|
+
surfaces: ['copilot'],
|
|
480
|
+
handler: async (input, ctx) => {
|
|
481
|
+
const args = (input ?? {});
|
|
482
|
+
const type = await this.resolveGranted(args.typeName, ctx.workspaceId);
|
|
483
|
+
const items = args.items ?? [];
|
|
484
|
+
if (items.length === 0) {
|
|
485
|
+
throw new Error('Nothing to save — `items` was empty. Send at least one entry.');
|
|
486
|
+
}
|
|
487
|
+
if (items.length > entries_constants_1.BULK_MAX_SAVE_ITEMS) {
|
|
488
|
+
throw new Error(`Too many entries in one change: ${items.length}, and the limit is ` +
|
|
489
|
+
`${entries_constants_1.BULK_MAX_SAVE_ITEMS}. Split it into smaller batches.`);
|
|
490
|
+
}
|
|
491
|
+
const changes = [];
|
|
492
|
+
const patched = [];
|
|
493
|
+
for (const [index, item] of items.entries()) {
|
|
494
|
+
const { values, fields } = this.narrowValues(type.name, item.values ?? {});
|
|
495
|
+
if (Object.keys(values).length === 0) {
|
|
496
|
+
throw new Error(`Item ${index + 1} names no fields to write. Every item needs \`values\`.`);
|
|
497
|
+
}
|
|
498
|
+
// A create has no `before`; an edit reads the live entry so
|
|
499
|
+
// the card carries a real diff — and so a missing or
|
|
500
|
+
// out-of-workspace id fails HERE, before the user is told
|
|
501
|
+
// anything is happening, rather than halfway through the
|
|
502
|
+
// write.
|
|
503
|
+
const before = item.id
|
|
504
|
+
? ((await this.writer.getOne(type, item.id, ctx.workspaceId)).values ?? {})
|
|
505
|
+
: undefined;
|
|
506
|
+
// Fields that would not actually change are dropped, and
|
|
507
|
+
// an item left with none of them is dropped whole — the
|
|
508
|
+
// batch equivalent of `proposeEdit`'s no-op guard, and here
|
|
509
|
+
// it is more than card hygiene: writing an entry its own
|
|
510
|
+
// current values still appends a revision and, on a
|
|
511
|
+
// publishable type, takes a live entry back to draft. A
|
|
512
|
+
// model re-sending twenty unchanged records would
|
|
513
|
+
// unpublish twenty live pages.
|
|
514
|
+
const changed = {};
|
|
515
|
+
for (const [field, after] of Object.entries(values)) {
|
|
516
|
+
const wholeSet = this.isWholeSetRelation(fields.get(field));
|
|
517
|
+
// A whole-set relation has no readable `before` here,
|
|
518
|
+
// so it always counts as a change.
|
|
519
|
+
const hasBefore = before !== undefined && !wholeSet;
|
|
520
|
+
if (hasBefore &&
|
|
521
|
+
JSON.stringify(before[field] ?? null) ===
|
|
522
|
+
JSON.stringify(after ?? null)) {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
changed[field] = after;
|
|
526
|
+
changes.push({
|
|
527
|
+
// Prefixed by position, because the card keys its
|
|
528
|
+
// rows on `field` and eight entries editing `title`
|
|
529
|
+
// would otherwise collapse into one row.
|
|
530
|
+
field: `items[${index}].${field}`,
|
|
531
|
+
label: `#${index + 1} ${labelOf(fields.get(field)).label ?? field}`,
|
|
532
|
+
...(hasBefore
|
|
533
|
+
? { before: before[field] ?? null }
|
|
534
|
+
: {}),
|
|
535
|
+
after
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
if (Object.keys(changed).length === 0) {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
patched.push({
|
|
542
|
+
...(item.id ? { id: item.id } : {}),
|
|
543
|
+
values: changed,
|
|
544
|
+
...(item.locale ? { locale: item.locale } : {})
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
if (patched.length === 0) {
|
|
548
|
+
throw new Error('Those entries already have these values — nothing would change.');
|
|
549
|
+
}
|
|
550
|
+
// The batch is where this matters most. "Translate these eight
|
|
551
|
+
// posts" is the instruction this tool was built for, and it is
|
|
552
|
+
// also the one most likely to reach for a shared field — so a
|
|
553
|
+
// single accepted card could rewrite eight records in every
|
|
554
|
+
// language they have. Described per item, then merged: the
|
|
555
|
+
// card carries one summary, not eight.
|
|
556
|
+
const fanouts = [];
|
|
557
|
+
for (const item of patched) {
|
|
558
|
+
if (!item.id)
|
|
559
|
+
continue;
|
|
560
|
+
const fanout = await this.fanoutOf(type, item.id, item.values, ctx.workspaceId);
|
|
561
|
+
if (fanout)
|
|
562
|
+
fanouts.push(fanout);
|
|
563
|
+
}
|
|
564
|
+
const merged = mergeFanouts(fanouts);
|
|
565
|
+
return {
|
|
566
|
+
kind: proposal_kinds_1.CONTENT_PROPOSAL_KINDS.bulkSaveEntries,
|
|
567
|
+
target: {
|
|
568
|
+
typeName: type.name,
|
|
569
|
+
...(merged ? { fanout: merged } : {})
|
|
570
|
+
},
|
|
571
|
+
patch: { items: patched },
|
|
572
|
+
summary: this.discloseFanout(args.summary, merged, fanouts.length),
|
|
573
|
+
changes
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
exports.EntryProposalToolProvider = EntryProposalToolProvider;
|
|
580
|
+
exports.EntryProposalToolProvider = EntryProposalToolProvider = tslib_1.__decorate([
|
|
581
|
+
(0, common_1.Injectable)(),
|
|
582
|
+
tslib_1.__param(0, (0, content_tokens_1.InjectContentRegistry)()),
|
|
583
|
+
tslib_1.__param(3, (0, common_1.Optional)()),
|
|
584
|
+
tslib_1.__param(4, (0, common_1.Optional)()),
|
|
585
|
+
tslib_1.__param(4, (0, common_1.Inject)(entry_extension_1.CONTENT_ENTRY_EXTENSION)),
|
|
586
|
+
tslib_1.__metadata("design:paramtypes", [Function, entry_writer_service_1.EntryWriterService,
|
|
587
|
+
workspace_grants_query_1.WorkspaceGrantsQuery,
|
|
588
|
+
tools_server_1.ToolRegistry, Object])
|
|
589
|
+
], EntryProposalToolProvider);
|
|
590
|
+
/**
|
|
591
|
+
* Folds one fan-out description per batch item into the single one a card
|
|
592
|
+
* carries — the union of the fields that travel and of the rows they reach.
|
|
593
|
+
*
|
|
594
|
+
* A union rather than a per-item list because the reader's question is "what
|
|
595
|
+
* else did this touch", not "which item touched what". Both lists are sorted so
|
|
596
|
+
* two batches describing the same spread read identically, and `locales`
|
|
597
|
+
* arrives already sorted from the extension.
|
|
598
|
+
*/
|
|
599
|
+
function mergeFanouts(fanouts) {
|
|
600
|
+
if (!fanouts.length)
|
|
601
|
+
return undefined;
|
|
602
|
+
const fields = new Set();
|
|
603
|
+
const locales = new Set();
|
|
604
|
+
for (const fanout of fanouts) {
|
|
605
|
+
for (const field of fanout.fields)
|
|
606
|
+
fields.add(field);
|
|
607
|
+
for (const locale of fanout.locales)
|
|
608
|
+
locales.add(locale);
|
|
609
|
+
}
|
|
610
|
+
return {
|
|
611
|
+
fields: [...fields].sort(),
|
|
612
|
+
locales: [...locales].sort()
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
/** The field's admin label, when it has one — for the diff's row heading. */
|
|
616
|
+
function labelOf(field) {
|
|
617
|
+
const label = field?.admin?.['label'];
|
|
618
|
+
return typeof label === 'string' ? { label } : {};
|
|
619
|
+
}
|