@happyvertical/smrt-content 0.49.2 → 0.49.4
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/dist/chunks/content-query-JaCGj01O.js +4092 -0
- package/dist/chunks/{content-query-CraB4BJx.js.map → content-query-JaCGj01O.js.map} +1 -1
- package/dist/chunks/{content-versions-JXn7MXeM.js → content-versions-qIuk5bbv.js} +2 -2
- package/dist/chunks/{content-versions-JXn7MXeM.js.map → content-versions-qIuk5bbv.js.map} +1 -1
- package/dist/chunks/{contents-C048Z_8g.js → contents-DZaQwoRH.js} +2 -2
- package/dist/chunks/{contents-C048Z_8g.js.map → contents-DZaQwoRH.js.map} +1 -1
- package/dist/index.js +4 -4
- package/dist/manifest.json +1324 -116
- package/dist/server/content-list-actions.d.ts +4 -2
- package/dist/server/content-list-actions.d.ts.map +1 -1
- package/dist/server/content-list-lifecycle.d.ts +1 -1
- package/dist/server/content-list-lifecycle.d.ts.map +1 -1
- package/dist/server.js +6 -2
- package/dist/server.js.map +1 -1
- package/dist/smrt-knowledge.json +8 -8
- package/package.json +18 -17
- package/dist/chunks/content-query-CraB4BJx.js +0 -4092
|
@@ -1,4092 +0,0 @@
|
|
|
1
|
-
import { isContentBodyFormat } from "../body-format.js";
|
|
2
|
-
import { DataQueryValidationError, ObjectRegistry, SmrtJunction, SmrtObject, ValidationError, createDataQueryFingerprint, crossPackageRef, field, foreignKey, normalizeDataQueryRequest, normalizeDataQueryResult, normalizeDataQuerySchema, smrt } from "@happyvertical/smrt-core";
|
|
3
|
-
import { AssetCollection } from "@happyvertical/smrt-assets";
|
|
4
|
-
import { ImageCollection } from "@happyvertical/smrt-images";
|
|
5
|
-
import { definePrompt, resolvePrompt } from "@happyvertical/smrt-prompts";
|
|
6
|
-
import { TenantScoped, getCurrentTenant, isSuperAdminBypass, isSystemContext, isTenancyEnabled, tenantId } from "@happyvertical/smrt-tenancy";
|
|
7
|
-
import { fetchStaticMap } from "@happyvertical/geo";
|
|
8
|
-
import { generateHeadlineCard } from "@happyvertical/images";
|
|
9
|
-
//#region src/__smrt-register__.ts
|
|
10
|
-
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-content\",\"packageVersion\":\"0.49.2\",\"objects\":{\"@happyvertical/smrt-content:ContentAsset\":{\"name\":\"contentasset\",\"className\":\"ContentAsset\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentAsset\",\"collection\":\"contentassets\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-asset.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"contentId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Content\",\"_meta\":{\"required\":true}},\"assetId\":{\"type\":\"crossPackageRef\",\"required\":true,\"related\":\"@happyvertical/smrt-assets:Asset\"},\"relationship\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"sortOrder\":{\"type\":\"integer\",\"required\":true,\"default\":0}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"content_assets\",\"conflictColumns\":[\"content_id\",\"asset_id\",\"relationship\"],\"api\":false,\"mcp\":false,\"cli\":false,\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentAsset\",\"collectionExportName\":\"ContentAssetCollection\",\"validationRules\":[{\"field\":\"contentId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"assetId\",\"rule\":\"required\",\"fieldType\":\"crossPackageRef\"},{\"field\":\"relationship\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"sortOrder\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"content_assets\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_assets\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"content_id\\\" UUID NOT NULL,\\n \\\"asset_id\\\" UUID NOT NULL,\\n \\\"relationship\\\" TEXT NOT NULL,\\n \\\"sort_order\\\" INTEGER NOT NULL DEFAULT 0\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"content_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"contents\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"relationship\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"sort_order\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0}},\"indexes\":[{\"name\":\"content_assets_content_id_asset_id_idx\",\"columns\":[\"content_id\",\"asset_id\",\"relationship\"],\"unique\":true},{\"name\":\"content_assets_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_assets_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"content_assets_asset_id_idx\",\"columns\":[\"asset_id\"]}],\"version\":\"472d718d\"}},\"@happyvertical/smrt-content:ContentAssetCollection\":{\"name\":\"contentassetcollection\",\"className\":\"ContentAssetCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentAssetCollection\",\"collection\":\"contentassets\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-assets.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"byLeft\":{\"name\":\"byLeft\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<TItem[]>\",\"isStatic\":false,\"isPublic\":true},\"byRight\":{\"name\":\"byRight\",\"async\":true,\"parameters\":[{\"name\":\"rightId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<TItem[]>\",\"isStatic\":false,\"isPublic\":true},\"attach\":{\"name\":\"attach\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"rightId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionAttachOptions\",\"optional\":true}],\"returnType\":\"Promise<TItem>\",\"isStatic\":false,\"isPublic\":true},\"detach\":{\"name\":\"detach\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"rightId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"setLinks\":{\"name\":\"setLinks\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"rightIds\",\"type\":\"string[]\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionAttachOptions\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":false,\"mcp\":false,\"cli\":false,\"tableName\":\"content_assets\"},\"extends\":\"SmrtJunction\",\"extendsTypeArg\":\"ContentAsset\",\"exportName\":\"ContentAssetCollection\",\"collectionExportName\":\"ContentAssetCollectionCollection\",\"schema\":{\"tableName\":\"content_assets\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_assets\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_assets_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_assets_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"35bf42e8\"}},\"@happyvertical/smrt-content:ContentContributionAttachment\":{\"name\":\"contentcontributionattachment\",\"className\":\"ContentContributionAttachment\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributionAttachment\",\"collection\":\"contentcontributionattachments\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contribution-attachment.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"contributionId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ContentContribution\",\"_meta\":{\"required\":true}},\"revisionId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ContentContributionRevision\"},\"filename\":{\"type\":\"text\",\"required\":false},\"mimeType\":{\"type\":\"text\",\"required\":false},\"size\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"fileKey\":{\"type\":\"text\",\"required\":false},\"sourceUri\":{\"type\":\"text\",\"required\":false},\"channel\":{\"type\":\"text\",\"required\":false,\"default\":\"web\"},\"promotedAssetId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-assets:Asset\"},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contribution_attachments\",\"conflictColumns\":[\"id\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentContributionAttachment\",\"collectionExportName\":\"ContentContributionAttachmentCollection\",\"validationRules\":[{\"field\":\"contributionId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"size\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"content_contribution_attachments\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contribution_attachments\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"contribution_id\\\" UUID NOT NULL,\\n \\\"revision_id\\\" UUID,\\n \\\"filename\\\" TEXT,\\n \\\"mime_type\\\" TEXT,\\n \\\"size\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"file_key\\\" TEXT,\\n \\\"source_uri\\\" TEXT,\\n \\\"channel\\\" TEXT DEFAULT 'web',\\n \\\"promoted_asset_id\\\" UUID,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"contribution_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"content_contributions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"revision_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"content_contribution_revisions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"filename\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"mime_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"size\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"file_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_uri\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"channel\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"web\"},\"promoted_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_contribution_attachments_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_contribution_attachments_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"content_contribution_attachments_contribution_id_idx\",\"columns\":[\"contribution_id\"]},{\"name\":\"content_contribution_attachments_revision_id_idx\",\"columns\":[\"revision_id\"]},{\"name\":\"content_contribution_attachments_promoted_asset_id_idx\",\"columns\":[\"promoted_asset_id\"]}],\"version\":\"83e64a1b\"}},\"@happyvertical/smrt-content:ContentContributionAttachmentCollection\":{\"name\":\"contentcontributionattachmentcollection\",\"className\":\"ContentContributionAttachmentCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributionAttachmentCollection\",\"collection\":\"contentcontributionattachments\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contribution-attachments.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"listForContribution\":{\"name\":\"listForContribution\",\"async\":true,\"parameters\":[{\"name\":\"contributionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentContributionAttachment[]>\",\"isStatic\":false,\"isPublic\":true},\"listForRevision\":{\"name\":\"listForRevision\",\"async\":true,\"parameters\":[{\"name\":\"revisionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentContributionAttachment[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contribution_attachments\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentContributionAttachment\",\"exportName\":\"ContentContributionAttachmentCollection\",\"collectionExportName\":\"ContentContributionAttachmentCollectionCollection\",\"schema\":{\"tableName\":\"content_contribution_attachments\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contribution_attachments\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_contribution_attachments_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_contribution_attachments_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"d0c8b33f\"}},\"@happyvertical/smrt-content:ContentContributionRevision\":{\"name\":\"contentcontributionrevision\",\"className\":\"ContentContributionRevision\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributionRevision\",\"collection\":\"contentcontributionrevisions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contribution-revision.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"contributionId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ContentContribution\",\"_meta\":{\"required\":true}},\"revisionNumber\":{\"type\":\"integer\",\"required\":true,\"default\":1},\"channel\":{\"type\":\"text\",\"required\":false,\"default\":\"web\"},\"title\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"body\":{\"type\":\"text\",\"required\":false},\"sourceMessageId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-messages:Message\"},\"sourceThreadKey\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contribution_revisions\",\"conflictColumns\":[\"contribution_id\",\"revision_number\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentContributionRevision\",\"collectionExportName\":\"ContentContributionRevisionCollection\",\"validationRules\":[{\"field\":\"contributionId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"revisionNumber\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"content_contribution_revisions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contribution_revisions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"contribution_id\\\" UUID NOT NULL,\\n \\\"revision_number\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"channel\\\" TEXT DEFAULT 'web',\\n \\\"title\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"body\\\" TEXT,\\n \\\"source_message_id\\\" UUID,\\n \\\"source_thread_key\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"contribution_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"content_contributions\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"revision_number\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"channel\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"web\"},\"title\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"body\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_message_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"source_thread_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_contribution_revisions_contribution_id_r_af43e6d599_idx\",\"columns\":[\"contribution_id\",\"revision_number\"],\"unique\":true},{\"name\":\"content_contribution_revisions_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_contribution_revisions_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"content_contribution_revisions_source_message_id_idx\",\"columns\":[\"source_message_id\"]}],\"version\":\"5051727c\"}},\"@happyvertical/smrt-content:ContentContributionRevisionCollection\":{\"name\":\"contentcontributionrevisioncollection\",\"className\":\"ContentContributionRevisionCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributionRevisionCollection\",\"collection\":\"contentcontributionrevisions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contribution-revisions.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"listForContribution\":{\"name\":\"listForContribution\",\"async\":true,\"parameters\":[{\"name\":\"contributionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentContributionRevision[]>\",\"isStatic\":false,\"isPublic\":true},\"getLatestForContribution\":{\"name\":\"getLatestForContribution\",\"async\":true,\"parameters\":[{\"name\":\"contributionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentContributionRevision | null>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contribution_revisions\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentContributionRevision\",\"exportName\":\"ContentContributionRevisionCollection\",\"collectionExportName\":\"ContentContributionRevisionCollectionCollection\",\"schema\":{\"tableName\":\"content_contribution_revisions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contribution_revisions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_contribution_revisions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_contribution_revisions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"cc3e0dfa\"}},\"@happyvertical/smrt-content:ContentContributionType\":{\"name\":\"contentcontributiontype\",\"className\":\"ContentContributionType\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributionType\",\"collection\":\"contentcontributiontypes\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contribution-type.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"key\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"label\":{\"type\":\"text\",\"required\":false},\"enabled\":{\"type\":\"boolean\",\"required\":true,\"default\":true},\"allowedChannels\":{\"type\":\"text\",\"required\":false},\"allowText\":{\"type\":\"boolean\",\"required\":true,\"default\":true},\"allowFiles\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"allowEmptyText\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"intakeRules\":{\"type\":\"text\",\"required\":false},\"promotion\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getAllowedChannels\":{\"name\":\"getAllowedChannels\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentContributionChannel[]\",\"isStatic\":false,\"isPublic\":true},\"setAllowedChannels\":{\"name\":\"setAllowedChannels\",\"async\":false,\"parameters\":[{\"name\":\"channels\",\"type\":\"ContentContributionChannel[]\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getIntakeRules\":{\"name\":\"getIntakeRules\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentContributionIntakeRules\",\"isStatic\":false,\"isPublic\":true},\"setIntakeRules\":{\"name\":\"setIntakeRules\",\"async\":false,\"parameters\":[{\"name\":\"rules\",\"type\":\"ContentContributionIntakeRules\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getPromotion\":{\"name\":\"getPromotion\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentContributionPromotionMapping\",\"isStatic\":false,\"isPublic\":true},\"setPromotion\":{\"name\":\"setPromotion\",\"async\":false,\"parameters\":[{\"name\":\"promotion\",\"type\":\"ContentContributionPromotionMapping\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"toDefinition\":{\"name\":\"toDefinition\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentContributionTypeDefinition\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contribution_types\",\"conflictColumns\":[\"key\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentContributionType\",\"collectionExportName\":\"ContentContributionTypeCollection\",\"validationRules\":[{\"field\":\"key\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"enabled\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"allowText\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"allowFiles\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"allowEmptyText\",\"rule\":\"required\",\"fieldType\":\"boolean\"}],\"schema\":{\"tableName\":\"content_contribution_types\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contribution_types\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"key\\\" TEXT NOT NULL,\\n \\\"label\\\" TEXT,\\n \\\"enabled\\\" BOOLEAN NOT NULL DEFAULT TRUE,\\n \\\"allowed_channels\\\" TEXT,\\n \\\"allow_text\\\" BOOLEAN NOT NULL DEFAULT TRUE,\\n \\\"allow_files\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"allow_empty_text\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"intake_rules\\\" TEXT,\\n \\\"promotion\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"label\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"enabled\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":true},\"allowed_channels\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"allow_text\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":true},\"allow_files\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"allow_empty_text\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"intake_rules\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"promotion\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_contribution_types_key_idx\",\"columns\":[\"key\"],\"unique\":true},{\"name\":\"content_contribution_types_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_contribution_types_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"35552300\"}},\"@happyvertical/smrt-content:ContentContributionTypeCollection\":{\"name\":\"contentcontributiontypecollection\",\"className\":\"ContentContributionTypeCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributionTypeCollection\",\"collection\":\"contentcontributiontypes\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contribution-types.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"getByKey\":{\"name\":\"getByKey\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentContributionType | null>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contribution_types\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentContributionType\",\"exportName\":\"ContentContributionTypeCollection\",\"collectionExportName\":\"ContentContributionTypeCollectionCollection\",\"schema\":{\"tableName\":\"content_contribution_types\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contribution_types\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_contribution_types_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_contribution_types_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"9c9a0367\"}},\"@happyvertical/smrt-content:ContentContribution\":{\"name\":\"contentcontribution\",\"className\":\"ContentContribution\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContribution\",\"collection\":\"contentcontributions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contribution.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"contributorId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ContentContributor\",\"_meta\":{\"required\":true}},\"contributionTypeKey\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"submitted\"},\"intakeDecision\":{\"type\":\"text\",\"required\":false,\"default\":\"accepted\"},\"channel\":{\"type\":\"text\",\"required\":false,\"default\":\"web\"},\"title\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"body\":{\"type\":\"text\",\"required\":false},\"contributorEmail\":{\"type\":\"text\",\"required\":false},\"contributorName\":{\"type\":\"text\",\"required\":false},\"threadKey\":{\"type\":\"text\",\"required\":false},\"sourceMessageId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-messages:Message\"},\"editorNotes\":{\"type\":\"text\",\"required\":false},\"promotedContentId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Content\",\"_meta\":{\"nullable\":true}},\"revisionCount\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"approvedAt\":{\"type\":\"datetime\",\"required\":false},\"promotedAt\":{\"type\":\"datetime\",\"required\":false},\"rejectedAt\":{\"type\":\"datetime\",\"required\":false},\"withdrawnAt\":{\"type\":\"datetime\",\"required\":false},\"requestedChangesAt\":{\"type\":\"datetime\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getContributor\":{\"name\":\"getContributor\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentContributor | null>\",\"isStatic\":false,\"isPublic\":true},\"getRevisions\":{\"name\":\"getRevisions\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentContributionRevision[]>\",\"isStatic\":false,\"isPublic\":true},\"getLatestRevision\":{\"name\":\"getLatestRevision\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentContributionRevision | null>\",\"isStatic\":false,\"isPublic\":true},\"getAttachments\":{\"name\":\"getAttachments\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentContributionAttachment[]>\",\"isStatic\":false,\"isPublic\":true},\"resolveContributionType\":{\"name\":\"resolveContributionType\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentContributionTypeDefinition | null>\",\"isStatic\":false,\"isPublic\":true},\"appendRevisionAction\":{\"name\":\"appendRevisionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"AppendContentContributionRevisionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"requestChangesAction\":{\"name\":\"requestChangesAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RequestChangesContentContributionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"rejectAction\":{\"name\":\"rejectAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RejectContentContributionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"withdrawAction\":{\"name\":\"withdrawAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"WithdrawContentContributionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"approveAction\":{\"name\":\"approveAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"ApproveContentContributionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"promoteAction\":{\"name\":\"promoteAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"PromoteContentContributionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contributions\",\"conflictColumns\":[\"id\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\",\"appendRevisionAction\",\"requestChangesAction\",\"approveAction\",\"rejectAction\",\"withdrawAction\",\"promoteAction\"],\"routes\":{\"appendRevisionAction\":{\"method\":\"POST\",\"path\":\"revisions\"},\"requestChangesAction\":{\"method\":\"POST\",\"path\":\"request-changes\"},\"approveAction\":{\"method\":\"POST\",\"path\":\"approve\"},\"rejectAction\":{\"method\":\"POST\",\"path\":\"reject\"},\"withdrawAction\":{\"method\":\"POST\",\"path\":\"withdraw\"},\"promoteAction\":{\"method\":\"POST\",\"path\":\"promote\"}}},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentContribution\",\"collectionExportName\":\"ContentContributionCollection\",\"validationRules\":[{\"field\":\"contributorId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"contributionTypeKey\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"revisionCount\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"content_contributions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contributions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"contributor_id\\\" UUID NOT NULL,\\n \\\"contribution_type_key\\\" TEXT NOT NULL,\\n \\\"status\\\" TEXT DEFAULT 'submitted',\\n \\\"intake_decision\\\" TEXT DEFAULT 'accepted',\\n \\\"channel\\\" TEXT DEFAULT 'web',\\n \\\"title\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"body\\\" TEXT,\\n \\\"contributor_email\\\" TEXT,\\n \\\"contributor_name\\\" TEXT,\\n \\\"thread_key\\\" TEXT,\\n \\\"source_message_id\\\" UUID,\\n \\\"editor_notes\\\" TEXT,\\n \\\"promoted_content_id\\\" UUID,\\n \\\"revision_count\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"approved_at\\\" TIMESTAMP,\\n \\\"promoted_at\\\" TIMESTAMP,\\n \\\"rejected_at\\\" TIMESTAMP,\\n \\\"withdrawn_at\\\" TIMESTAMP,\\n \\\"requested_changes_at\\\" TIMESTAMP,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"contributor_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"content_contributors\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"contribution_type_key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"submitted\"},\"intake_decision\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"accepted\"},\"channel\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"web\"},\"title\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"body\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"contributor_email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"contributor_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"thread_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_message_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"editor_notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"promoted_content_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"contents\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"revision_count\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"approved_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"promoted_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"rejected_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"withdrawn_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"requested_changes_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_contributions_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_contributions_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"content_contributions_contributor_id_idx\",\"columns\":[\"contributor_id\"]},{\"name\":\"content_contributions_source_message_id_idx\",\"columns\":[\"source_message_id\"]},{\"name\":\"content_contributions_promoted_content_id_idx\",\"columns\":[\"promoted_content_id\"]}],\"version\":\"ef8fd792\"}},\"@happyvertical/smrt-content:ContentContributions\":{\"name\":\"contentcontributions\",\"className\":\"ContentContributions\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributions\",\"collection\":\"contentcontributions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contributions.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"getContributionTypesAction\":{\"name\":\"getContributionTypesAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listForContributor\":{\"name\":\"listForContributor\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\",\"string | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listInboxAction\":{\"name\":\"listInboxAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string | string[]\",\"string | null\"]}],\"returnType\":\"Promise<ContentContribution[]>\",\"isStatic\":false,\"isPublic\":true},\"submitWebContribution\":{\"name\":\"submitWebContribution\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"SubmitWebContentContributionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"ingestEmailContribution\":{\"name\":\"ingestEmailContribution\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IngestEmailContentContributionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"submitWebContribution\",\"ingestEmailContribution\",\"listForContributor\",\"listInboxAction\",\"getContributionTypesAction\"],\"routes\":{\"submitWebContribution\":{\"scope\":\"collection\",\"method\":\"POST\",\"path\":\"submit\"},\"ingestEmailContribution\":{\"scope\":\"collection\",\"method\":\"POST\",\"path\":\"ingest-email\"},\"listForContributor\":{\"scope\":\"collection\",\"method\":\"GET\",\"path\":\"by-contributor\"},\"listInboxAction\":{\"scope\":\"collection\",\"method\":\"GET\",\"path\":\"inbox\"},\"getContributionTypesAction\":{\"scope\":\"collection\",\"method\":\"GET\",\"path\":\"types\"}}},\"mcp\":false,\"cli\":false,\"tableName\":\"content_contributions\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentContribution\",\"exportName\":\"ContentContributions\",\"collectionExportName\":\"ContentContributionsCollection\",\"schema\":{\"tableName\":\"content_contributions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contributions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_contributions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_contributions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"641c0cc8\"}},\"@happyvertical/smrt-content:ContentContributor\":{\"name\":\"contentcontributor\",\"className\":\"ContentContributor\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributor\",\"collection\":\"contentcontributors\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contributor.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"profileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\"},\"email\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"name\":{\"type\":\"text\",\"required\":false},\"trustLevel\":{\"type\":\"text\",\"required\":false,\"default\":\"standard\"},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contributors\",\"conflictColumns\":[\"email\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentContributor\",\"collectionExportName\":\"ContentContributorCollection\",\"validationRules\":[{\"field\":\"email\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"content_contributors\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contributors\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID,\\n \\\"email\\\" TEXT NOT NULL,\\n \\\"name\\\" TEXT,\\n \\\"trust_level\\\" TEXT DEFAULT 'standard',\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"email\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"trust_level\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"standard\"},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_contributors_email_idx\",\"columns\":[\"email\"],\"unique\":true},{\"name\":\"content_contributors_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_contributors_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"content_contributors_profile_id_idx\",\"columns\":[\"profile_id\"]}],\"version\":\"7eb9c661\"}},\"@happyvertical/smrt-content:ContentContributorCollection\":{\"name\":\"contentcontributorcollection\",\"className\":\"ContentContributorCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentContributorCollection\",\"collection\":\"contentcontributors\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-contributors.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"getByEmail\":{\"name\":\"getByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentContributor | null>\",\"isStatic\":false,\"isPublic\":true},\"getByProfileId\":{\"name\":\"getByProfileId\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentContributor | null>\",\"isStatic\":false,\"isPublic\":true},\"findOrCreateByEmail\":{\"name\":\"findOrCreateByEmail\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"string | null\"]}],\"returnType\":\"Promise<ContentContributor>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_contributors\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentContributor\",\"exportName\":\"ContentContributorCollection\",\"collectionExportName\":\"ContentContributorCollectionCollection\",\"schema\":{\"tableName\":\"content_contributors\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_contributors\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_contributors_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_contributors_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"b457e60b\"}},\"@happyvertical/smrt-content:ContentCorrection\":{\"name\":\"contentcorrection\",\"className\":\"ContentCorrection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentCorrection\",\"collection\":\"contentcorrections\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-correction.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"contentId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Content\",\"_meta\":{\"required\":true}},\"contentVersionId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ContentVersion\"},\"factId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-facts:Fact\"},\"replacementFactId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-facts:Fact\"},\"correctionType\":{\"type\":\"text\",\"required\":false,\"default\":\"fact\"},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"draft\"},\"summary\":{\"type\":\"text\",\"required\":false},\"incorrectText\":{\"type\":\"text\",\"required\":false},\"correctedText\":{\"type\":\"text\",\"required\":false},\"publicNote\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"publishedAt\":{\"type\":\"datetime\",\"required\":false},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_corrections\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ContentCorrection\",\"collectionExportName\":\"ContentCorrectionCollection\",\"validationRules\":[{\"field\":\"contentId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"content_corrections\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_corrections\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"content_id\\\" UUID NOT NULL,\\n \\\"content_version_id\\\" UUID,\\n \\\"fact_id\\\" UUID,\\n \\\"replacement_fact_id\\\" UUID,\\n \\\"correction_type\\\" TEXT DEFAULT 'fact',\\n \\\"status\\\" TEXT DEFAULT 'draft',\\n \\\"summary\\\" TEXT,\\n \\\"incorrect_text\\\" TEXT,\\n \\\"corrected_text\\\" TEXT,\\n \\\"public_note\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID,\\n \\\"published_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"content_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"contents\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"content_version_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"content_versions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"fact_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"replacement_fact_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"correction_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"fact\"},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"draft\"},\"summary\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"incorrect_text\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"corrected_text\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"public_note\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"published_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_corrections_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_corrections_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"content_corrections_content_id_idx\",\"columns\":[\"content_id\"]},{\"name\":\"content_corrections_content_version_id_idx\",\"columns\":[\"content_version_id\"]},{\"name\":\"content_corrections_fact_id_idx\",\"columns\":[\"fact_id\"]},{\"name\":\"content_corrections_replacement_fact_id_idx\",\"columns\":[\"replacement_fact_id\"]}],\"version\":\"bf2808c7\"}},\"@happyvertical/smrt-content:ContentCorrectionCollection\":{\"name\":\"contentcorrectioncollection\",\"className\":\"ContentCorrectionCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentCorrectionCollection\",\"collection\":\"contentcorrections\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-corrections.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"listForContent\":{\"name\":\"listForContent\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentCorrection[]>\",\"isStatic\":false,\"isPublic\":true},\"getPublishedForContent\":{\"name\":\"getPublishedForContent\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentCorrection[]>\",\"isStatic\":false,\"isPublic\":true},\"issue\":{\"name\":\"issue\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"any\",\"optional\":false,\"typeUnresolved\":true}],\"returnType\":\"Promise<ContentCorrection>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_corrections\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentCorrection\",\"exportName\":\"ContentCorrectionCollection\",\"collectionExportName\":\"ContentCorrectionCollectionCollection\",\"schema\":{\"tableName\":\"content_corrections\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_corrections\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_corrections_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_corrections_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"6ebe142d\"}},\"@happyvertical/smrt-content:ContentFeedSource\":{\"name\":\"contentfeedsource\",\"className\":\"ContentFeedSource\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentFeedSource\",\"collection\":\"contentfeedsources\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-feed-source.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"name\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"feedUrl\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"homepageUrl\":{\"type\":\"text\",\"required\":false},\"format\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":true,\"default\":\"active\",\"_meta\":{\"required\":true,\"default\":\"active\"}},\"defaultCategory\":{\"type\":\"text\",\"required\":false},\"sourceGroup\":{\"type\":\"text\",\"required\":false},\"pollIntervalMinutes\":{\"type\":\"integer\",\"required\":true,\"default\":15},\"etag\":{\"type\":\"text\",\"required\":false},\"lastModified\":{\"type\":\"text\",\"required\":false},\"lastFetchedAt\":{\"type\":\"datetime\",\"required\":false},\"lastSuccessAt\":{\"type\":\"datetime\",\"required\":false},\"lastError\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"markFetchStarted\":{\"name\":\"markFetchStarted\",\"async\":false,\"parameters\":[{\"name\":\"at\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"markFetchSucceeded\":{\"name\":\"markFetchSucceeded\",\"async\":false,\"parameters\":[{\"name\":\"at\",\"type\":\"any\",\"optional\":true},{\"name\":\"headers\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string | null\"]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"markFetchFailed\":{\"name\":\"markFetchFailed\",\"async\":false,\"parameters\":[{\"name\":\"error\",\"type\":\"unknown\",\"optional\":false},{\"name\":\"at\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_feed_sources\",\"conflictColumns\":[\"tenant_id\",\"feed_url\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentFeedSource\",\"collectionExportName\":\"ContentFeedSourceCollection\",\"validationRules\":[{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"feedUrl\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"status\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"pollIntervalMinutes\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"content_feed_sources\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_feed_sources\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT NOT NULL,\\n \\\"feed_url\\\" TEXT NOT NULL,\\n \\\"homepage_url\\\" TEXT,\\n \\\"format\\\" TEXT,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'active',\\n \\\"default_category\\\" TEXT,\\n \\\"source_group\\\" TEXT,\\n \\\"poll_interval_minutes\\\" INTEGER NOT NULL DEFAULT 15,\\n \\\"etag\\\" TEXT,\\n \\\"last_modified\\\" TEXT,\\n \\\"last_fetched_at\\\" TIMESTAMP,\\n \\\"last_success_at\\\" TIMESTAMP,\\n \\\"last_error\\\" TEXT,\\n \\\"metadata\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"feed_url\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"homepage_url\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"format\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"active\"},\"default_category\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_group\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"poll_interval_minutes\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":15},\"etag\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"last_modified\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"last_fetched_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"last_success_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"last_error\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"content_feed_sources_tenant_id_feed_url_idx\",\"columns\":[\"tenant_id\",\"feed_url\"],\"unique\":true},{\"name\":\"content_feed_sources_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_feed_sources_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"bbcb36e5\"}},\"@happyvertical/smrt-content:ContentFeedSourceCollection\":{\"name\":\"contentfeedsourcecollection\",\"className\":\"ContentFeedSourceCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentFeedSourceCollection\",\"collection\":\"contentfeedsources\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-feed-sources.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"findActive\":{\"name\":\"findActive\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string | null\",\"optional\":true,\"unionBranches\":[{\"type\":\"string\"},{\"type\":\"null\"}]}],\"returnType\":\"Promise<ContentFeedSource[]>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"ContentFeedSourceStatus\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string | null\",\"optional\":true,\"unionBranches\":[{\"type\":\"string\"},{\"type\":\"null\"}]}],\"returnType\":\"Promise<ContentFeedSource[]>\",\"isStatic\":false,\"isPublic\":true},\"findByFeedUrl\":{\"name\":\"findByFeedUrl\",\"async\":true,\"parameters\":[{\"name\":\"feedUrl\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string | null\",\"optional\":true,\"unionBranches\":[{\"type\":\"string\"},{\"type\":\"null\"}]}],\"returnType\":\"Promise<ContentFeedSource | null>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_feed_sources\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentFeedSource\",\"exportName\":\"ContentFeedSourceCollection\",\"collectionExportName\":\"ContentFeedSourceCollectionCollection\",\"schema\":{\"tableName\":\"content_feed_sources\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_feed_sources\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_feed_sources_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_feed_sources_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"bb0cca9e\"}},\"@happyvertical/smrt-content:ContentGovernanceAssignment\":{\"name\":\"contentgovernanceassignment\",\"className\":\"ContentGovernanceAssignment\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentGovernanceAssignment\",\"collection\":\"contentgovernanceassignments\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-governance-assignment.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"key\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"label\":{\"type\":\"text\",\"required\":false},\"contentType\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"contentVariant\":{\"type\":\"text\",\"required\":false},\"enabled\":{\"type\":\"boolean\",\"required\":true,\"default\":true},\"factLinkingEnabled\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"transparencyEnabled\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"publicationProfileKey\":{\"type\":\"text\",\"required\":false},\"correctionProfileKey\":{\"type\":\"text\",\"required\":false},\"enforcePublishReadiness\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"defaultFactRelationship\":{\"type\":\"text\",\"required\":false,\"default\":\"supports\"},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"toDefinition\":{\"name\":\"toDefinition\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentGovernanceAssignmentDefinition\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_governance_assignments\",\"conflictColumns\":[\"key\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentGovernanceAssignment\",\"collectionExportName\":\"ContentGovernanceAssignmentCollection\",\"validationRules\":[{\"field\":\"key\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"contentType\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"enabled\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"factLinkingEnabled\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"transparencyEnabled\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"enforcePublishReadiness\",\"rule\":\"required\",\"fieldType\":\"boolean\"}],\"schema\":{\"tableName\":\"content_governance_assignments\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_governance_assignments\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"key\\\" TEXT NOT NULL,\\n \\\"label\\\" TEXT,\\n \\\"content_type\\\" TEXT NOT NULL,\\n \\\"content_variant\\\" TEXT,\\n \\\"enabled\\\" BOOLEAN NOT NULL DEFAULT TRUE,\\n \\\"fact_linking_enabled\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"transparency_enabled\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"publication_profile_key\\\" TEXT,\\n \\\"correction_profile_key\\\" TEXT,\\n \\\"enforce_publish_readiness\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"default_fact_relationship\\\" TEXT DEFAULT 'supports',\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"label\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"content_type\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"content_variant\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"enabled\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":true},\"fact_linking_enabled\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"transparency_enabled\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"publication_profile_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"correction_profile_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"enforce_publish_readiness\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"default_fact_relationship\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"supports\"},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_governance_assignments_key_idx\",\"columns\":[\"key\"],\"unique\":true},{\"name\":\"content_governance_assignments_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_governance_assignments_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"00a2c610\"}},\"@happyvertical/smrt-content:ContentGovernanceAssignmentCollection\":{\"name\":\"contentgovernanceassignmentcollection\",\"className\":\"ContentGovernanceAssignmentCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentGovernanceAssignmentCollection\",\"collection\":\"contentgovernanceassignments\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-governance-assignments.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"getByKey\":{\"name\":\"getByKey\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentGovernanceAssignment | null>\",\"isStatic\":false,\"isPublic\":true},\"resolveForContent\":{\"name\":\"resolveForContent\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"string | null\"]}],\"returnType\":\"Promise<ContentGovernanceAssignment | null>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_governance_assignments\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentGovernanceAssignment\",\"exportName\":\"ContentGovernanceAssignmentCollection\",\"collectionExportName\":\"ContentGovernanceAssignmentCollectionCollection\",\"schema\":{\"tableName\":\"content_governance_assignments\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_governance_assignments\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_governance_assignments_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_governance_assignments_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"21471529\"}},\"@happyvertical/smrt-content:ContentGovernancePolicyCollection\":{\"name\":\"contentgovernancepolicycollection\",\"className\":\"ContentGovernancePolicyCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentGovernancePolicyCollection\",\"collection\":\"contentgovernancepolicies\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-governance-policies.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"getByKey\":{\"name\":\"getByKey\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentGovernancePolicy | null>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_governance_policies\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentGovernancePolicy\",\"exportName\":\"ContentGovernancePolicyCollection\",\"collectionExportName\":\"ContentGovernancePolicyCollectionCollection\",\"schema\":{\"tableName\":\"content_governance_policies\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_governance_policies\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_governance_policies_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_governance_policies_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"e2da0e5b\"}},\"@happyvertical/smrt-content:ContentGovernancePolicy\":{\"name\":\"contentgovernancepolicy\",\"className\":\"ContentGovernancePolicy\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentGovernancePolicy\",\"collection\":\"contentgovernancepolicies\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-governance-policy.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"key\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"label\":{\"type\":\"text\",\"required\":false},\"kind\":{\"type\":\"text\",\"required\":false,\"default\":\"custom\"},\"instructions\":{\"type\":\"text\",\"required\":false},\"enabled\":{\"type\":\"boolean\",\"required\":true,\"default\":true},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"toDefinition\":{\"name\":\"toDefinition\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentReviewPolicyDefinition\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_governance_policies\",\"conflictColumns\":[\"key\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentGovernancePolicy\",\"collectionExportName\":\"ContentGovernancePolicyCollection\",\"validationRules\":[{\"field\":\"key\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"enabled\",\"rule\":\"required\",\"fieldType\":\"boolean\"}],\"schema\":{\"tableName\":\"content_governance_policies\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_governance_policies\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"key\\\" TEXT NOT NULL,\\n \\\"label\\\" TEXT,\\n \\\"kind\\\" TEXT DEFAULT 'custom',\\n \\\"instructions\\\" TEXT,\\n \\\"enabled\\\" BOOLEAN NOT NULL DEFAULT TRUE,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"label\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"kind\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"custom\"},\"instructions\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"enabled\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":true},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_governance_policies_key_idx\",\"columns\":[\"key\"],\"unique\":true},{\"name\":\"content_governance_policies_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_governance_policies_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"3cc24f80\"}},\"@happyvertical/smrt-content:ContentGovernanceProfile\":{\"name\":\"contentgovernanceprofile\",\"className\":\"ContentGovernanceProfile\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentGovernanceProfile\",\"collection\":\"contentgovernanceprofiles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-governance-profile.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"key\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"label\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"enabled\":{\"type\":\"boolean\",\"required\":true,\"default\":true},\"requirements\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getRequirements\":{\"name\":\"getRequirements\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentReviewRequirement[]\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"toDefinition\":{\"name\":\"toDefinition\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentGovernanceProfileDefinition\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_governance_profiles\",\"conflictColumns\":[\"key\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentGovernanceProfile\",\"collectionExportName\":\"ContentGovernanceProfileCollection\",\"validationRules\":[{\"field\":\"key\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"enabled\",\"rule\":\"required\",\"fieldType\":\"boolean\"}],\"schema\":{\"tableName\":\"content_governance_profiles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_governance_profiles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"key\\\" TEXT NOT NULL,\\n \\\"label\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"enabled\\\" BOOLEAN NOT NULL DEFAULT TRUE,\\n \\\"requirements\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"label\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"enabled\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":true},\"requirements\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_governance_profiles_key_idx\",\"columns\":[\"key\"],\"unique\":true},{\"name\":\"content_governance_profiles_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_governance_profiles_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"4bfc2afc\"}},\"@happyvertical/smrt-content:ContentGovernanceProfileCollection\":{\"name\":\"contentgovernanceprofilecollection\",\"className\":\"ContentGovernanceProfileCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentGovernanceProfileCollection\",\"collection\":\"contentgovernanceprofiles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-governance-profiles.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"getByKey\":{\"name\":\"getByKey\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentGovernanceProfile | null>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_governance_profiles\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentGovernanceProfile\",\"exportName\":\"ContentGovernanceProfileCollection\",\"collectionExportName\":\"ContentGovernanceProfileCollectionCollection\",\"schema\":{\"tableName\":\"content_governance_profiles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_governance_profiles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_governance_profiles_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_governance_profiles_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"496f0f56\"}},\"@happyvertical/smrt-content:ContentReference\":{\"name\":\"contentreference\",\"className\":\"ContentReference\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentReference\",\"collection\":\"contentreferences\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-reference.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"sourceId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Content\",\"_meta\":{\"required\":true}},\"targetId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Content\",\"_meta\":{\"required\":true}},\"targetVersion\":{\"type\":\"integer\",\"required\":false,\"_meta\":{\"nullable\":true}},\"createdAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"content_references\",\"conflictColumns\":[\"source_id\",\"target_id\"],\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentReference\",\"collectionExportName\":\"ContentReferenceCollection\",\"validationRules\":[{\"field\":\"sourceId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"targetId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"content_references\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_references\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"source_id\\\" UUID NOT NULL,\\n \\\"target_id\\\" UUID NOT NULL,\\n \\\"target_version\\\" INTEGER\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"source_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"contents\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"target_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"contents\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"target_version\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_references_source_id_target_id_idx\",\"columns\":[\"source_id\",\"target_id\"],\"unique\":true},{\"name\":\"content_references_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_references_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"content_references_target_id_idx\",\"columns\":[\"target_id\"]}],\"version\":\"3347ea2a\"}},\"@happyvertical/smrt-content:ContentReferences\":{\"name\":\"contentreferences\",\"className\":\"ContentReferences\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentReferences\",\"collection\":\"contentreferences\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-references.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"byLeft\":{\"name\":\"byLeft\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<TItem[]>\",\"isStatic\":false,\"isPublic\":true},\"byRight\":{\"name\":\"byRight\",\"async\":true,\"parameters\":[{\"name\":\"rightId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<TItem[]>\",\"isStatic\":false,\"isPublic\":true},\"attach\":{\"name\":\"attach\",\"async\":true,\"parameters\":[{\"name\":\"sourceId\",\"type\":\"string\",\"optional\":false},{\"name\":\"targetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionAttachOptions\",\"optional\":true}],\"returnType\":\"Promise<ContentReference>\",\"isStatic\":false,\"isPublic\":true},\"detach\":{\"name\":\"detach\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"rightId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"setLinks\":{\"name\":\"setLinks\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"rightIds\",\"type\":\"string[]\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionAttachOptions\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getForSource\":{\"name\":\"getForSource\",\"async\":true,\"parameters\":[{\"name\":\"sourceId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentReference[]>\",\"isStatic\":false,\"isPublic\":true},\"getForTarget\":{\"name\":\"getForTarget\",\"async\":true,\"parameters\":[{\"name\":\"targetId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentReference[]>\",\"isStatic\":false,\"isPublic\":true},\"unlink\":{\"name\":\"unlink\",\"async\":true,\"parameters\":[{\"name\":\"sourceId\",\"type\":\"string\",\"optional\":false},{\"name\":\"targetId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_references\"},\"extends\":\"SmrtJunction\",\"extendsTypeArg\":\"ContentReference\",\"exportName\":\"ContentReferences\",\"collectionExportName\":\"ContentReferencesCollection\",\"schema\":{\"tableName\":\"content_references\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_references\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_references_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_references_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"e9ad3cf0\"}},\"@happyvertical/smrt-content:ContentReview\":{\"name\":\"contentreview\",\"className\":\"ContentReview\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentReview\",\"collection\":\"contentreviews\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-review.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"contentId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Content\",\"_meta\":{\"required\":true}},\"contentVersionId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ContentVersion\"},\"kind\":{\"type\":\"text\",\"required\":false,\"default\":\"custom\"},\"policyKey\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"pending\"},\"summary\":{\"type\":\"text\",\"required\":false},\"findings\":{\"type\":\"text\",\"required\":false},\"reviewer\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getFindings\":{\"name\":\"getFindings\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentReviewFinding[]\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_reviews\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ContentReview\",\"collectionExportName\":\"ContentReviewCollection\",\"validationRules\":[{\"field\":\"contentId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"content_reviews\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_reviews\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"content_id\\\" UUID NOT NULL,\\n \\\"content_version_id\\\" UUID,\\n \\\"kind\\\" TEXT DEFAULT 'custom',\\n \\\"policy_key\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'pending',\\n \\\"summary\\\" TEXT,\\n \\\"findings\\\" TEXT,\\n \\\"reviewer\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"content_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"contents\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"content_version_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"content_versions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"kind\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"custom\"},\"policy_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"pending\"},\"summary\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"findings\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"reviewer\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_reviews_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_reviews_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"content_reviews_content_id_idx\",\"columns\":[\"content_id\"]},{\"name\":\"content_reviews_content_version_id_idx\",\"columns\":[\"content_version_id\"]}],\"version\":\"7b2c0ad7\"}},\"@happyvertical/smrt-content:ContentReviewCollection\":{\"name\":\"contentreviewcollection\",\"className\":\"ContentReviewCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentReviewCollection\",\"collection\":\"contentreviews\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-reviews.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"listForContent\":{\"name\":\"listForContent\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false},{\"name\":\"kind\",\"type\":\"ContentReviewKind\",\"optional\":true}],\"returnType\":\"Promise<ContentReview[]>\",\"isStatic\":false,\"isPublic\":true},\"getLatestForContent\":{\"name\":\"getLatestForContent\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false},{\"name\":\"kind\",\"type\":\"ContentReviewKind\",\"optional\":true}],\"returnType\":\"Promise<ContentReview | null>\",\"isStatic\":false,\"isPublic\":true},\"listForContentByPolicyKey\":{\"name\":\"listForContentByPolicyKey\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false},{\"name\":\"policyKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentReview[]>\",\"isStatic\":false,\"isPublic\":true},\"getLatestForPolicyKey\":{\"name\":\"getLatestForPolicyKey\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false},{\"name\":\"policyKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentReview | null>\",\"isStatic\":false,\"isPublic\":true},\"createFromResult\":{\"name\":\"createFromResult\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"string | null\",\"ContentReviewKind\",\"ContentReviewResult\",\"Record<string, unknown>\"]}],\"returnType\":\"Promise<ContentReview>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_reviews\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentReview\",\"exportName\":\"ContentReviewCollection\",\"collectionExportName\":\"ContentReviewCollectionCollection\",\"schema\":{\"tableName\":\"content_reviews\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_reviews\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_reviews_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_reviews_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"03b7d1d3\"}},\"@happyvertical/smrt-content:Article\":{\"name\":\"article\",\"className\":\"Article\",\"qualifiedName\":\"@happyvertical/smrt-content:Article\",\"collection\":\"contents\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-types.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true}}},\"type\":{\"type\":\"text\",\"required\":false},\"variant\":{\"type\":\"text\",\"required\":false},\"fileKey\":{\"type\":\"text\",\"required\":false},\"author\":{\"type\":\"text\",\"required\":false},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"title\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"body\":{\"type\":\"text\",\"required\":false},\"bodyFormat\":{\"type\":\"text\",\"required\":false},\"publish_date\":{\"type\":\"datetime\",\"required\":false},\"url\":{\"type\":\"text\",\"required\":false},\"source\":{\"type\":\"text\",\"required\":false},\"original_url\":{\"type\":\"text\",\"required\":false},\"language\":{\"type\":\"text\",\"required\":false},\"tags\":{\"type\":\"json\",\"required\":false,\"default\":[]},\"category\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"draft\"},\"state\":{\"type\":\"text\",\"required\":false,\"default\":\"active\"},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}},\"thumbnailAssetId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-assets:Asset\"}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"SmrtSaveOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"resolveGovernance\":{\"name\":\"resolveGovernance\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ResolvedContentGovernance>\",\"isStatic\":false,\"isPublic\":true},\"loadReferences\":{\"name\":\"loadReferences\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"addReference\":{\"name\":\"addReference\",\"async\":true,\"parameters\":[{\"name\":\"content\",\"type\":\"Content | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Content\"},{\"type\":\"string\"}]},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"removeReference\":{\"name\":\"removeReference\",\"async\":true,\"parameters\":[{\"name\":\"targetId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReferences\":{\"name\":\"getReferences\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReferenceEdges\":{\"name\":\"getReferenceEdges\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"getReferenceDrift\":{\"name\":\"getReferenceDrift\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"isGoverned\":{\"name\":\"isGoverned\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getFactLinks\":{\"name\":\"getFactLinks\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFacts\":{\"name\":\"getFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\",\"boolean\"]}],\"returnType\":\"Promise<Fact[]>\",\"isStatic\":false,\"isPublic\":true},\"addFact\":{\"name\":\"addFact\",\"async\":true,\"parameters\":[{\"name\":\"fact\",\"type\":\"Fact | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Fact\"},{\"type\":\"string\"}]},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true},{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"removeFact\":{\"name\":\"removeFact\",\"async\":true,\"parameters\":[{\"name\":\"factId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"syncFacts\":{\"name\":\"syncFacts\",\"async\":true,\"parameters\":[{\"name\":\"factIds\",\"type\":\"string[]\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true},\"browseFacts\":{\"name\":\"browseFacts\",\"async\":true,\"parameters\":[{\"name\":\"query\",\"type\":\"any\",\"optional\":true,\"default\":\"\"},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"boolean\"]}],\"returnType\":\"Promise<Fact[]>\",\"isStatic\":false,\"isPublic\":true},\"repairFactAudit\":{\"name\":\"repairFactAudit\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactAuditAction\":{\"name\":\"repairFactAuditAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactEvidence\":{\"name\":\"repairFactEvidence\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditResourceRepairOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactEvidenceAction\":{\"name\":\"repairFactEvidenceAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditResourceRepairOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"recheckFactClaims\":{\"name\":\"recheckFactClaims\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditClaimRecheckOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"recheckFactClaimsAction\":{\"name\":\"recheckFactClaimsAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditClaimRecheckOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"updateFactEvidenceStatus\":{\"name\":\"updateFactEvidenceStatus\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactEvidenceStatusUpdateOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"updateFactEvidenceStatusAction\":{\"name\":\"updateFactEvidenceStatusAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactEvidenceStatusUpdateOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFactAuditState\":{\"name\":\"getFactAuditState\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<FactAuditState>\",\"isStatic\":false,\"isPublic\":true},\"getFactAuditStateAction\":{\"name\":\"getFactAuditStateAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFactsState\":{\"name\":\"getFactsState\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"syncFactsState\":{\"name\":\"syncFactsState\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string[]\",\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"createVersion\":{\"name\":\"createVersion\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"CreateContentVersionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getVersions\":{\"name\":\"getVersions\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"restoreFromVersion\":{\"name\":\"restoreFromVersion\",\"async\":true,\"parameters\":[{\"name\":\"versionNumber\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReviews\":{\"name\":\"getReviews\",\"async\":true,\"parameters\":[{\"name\":\"kind\",\"type\":\"any\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listReviews\":{\"name\":\"listReviews\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReviewRequirements\":{\"name\":\"getReviewRequirements\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"governance\",\"type\":\"ResolvedContentGovernance\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceState\":{\"name\":\"getGovernanceState\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentGovernanceState>\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceStateAction\":{\"name\":\"getGovernanceStateAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listReviewProfilesAction\":{\"name\":\"listReviewProfilesAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"evaluateReviewProfile\":{\"name\":\"evaluateReviewProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentReviewProfileEvaluation>\",\"isStatic\":false,\"isPublic\":true},\"evaluateReviewProfileAction\":{\"name\":\"evaluateReviewProfileAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"isReadyForReviewProfile\":{\"name\":\"isReadyForReviewProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getPublishedTransparency\":{\"name\":\"getPublishedTransparency\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getPublishedTransparencyAction\":{\"name\":\"getPublishedTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"previewTransparency\":{\"name\":\"previewTransparency\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"previewTransparencyAction\":{\"name\":\"previewTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"runReview\":{\"name\":\"runReview\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RunContentReviewOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"runReviewAction\":{\"name\":\"runReviewAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RunContentReviewOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"reviewFacts\":{\"name\":\"reviewFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<RunContentReviewOptions, 'kind'>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"reviewSafety\":{\"name\":\"reviewSafety\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<RunContentReviewOptions, 'kind'>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getCorrections\":{\"name\":\"getCorrections\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listCorrections\":{\"name\":\"listCorrections\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"issueCorrection\":{\"name\":\"issueCorrection\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IssueContentCorrectionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"issueCorrectionAction\":{\"name\":\"issueCorrectionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IssueContentCorrectionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listVersions\":{\"name\":\"listVersions\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"mutateVersionAction\":{\"name\":\"mutateVersionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"any\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getCategorySegments\":{\"name\":\"getCategorySegments\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"getParentCategory\":{\"name\":\"getParentCategory\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"getRootCategory\":{\"name\":\"getRootCategory\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"getAncestorPaths\":{\"name\":\"getAncestorPaths\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"isInCategory\":{\"name\":\"isInCategory\",\"async\":false,\"parameters\":[{\"name\":\"categoryPath\",\"type\":\"string\",\"optional\":false},{\"name\":\"includeChildren\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown> | null | undefined\",\"optional\":false,\"unionBranches\":[{\"type\":\"Record<string, unknown>\"},{\"type\":\"null\"},{\"type\":\"undefined\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":false,\"parameters\":[{\"name\":\"patch\",\"type\":\"Partial<Record<string, unknown>>\",\"optional\":false}],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"getThumbnail\":{\"name\":\"getThumbnail\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image | null>\",\"isStatic\":false,\"isPublic\":true},\"setThumbnail\":{\"name\":\"setThumbnail\",\"async\":true,\"parameters\":[{\"name\":\"image\",\"type\":\"Image\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"generateThumbnail\":{\"name\":\"generateThumbnail\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"ThumbnailOptions\",\"optional\":false}],\"returnType\":\"Promise<Image>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":false,\"mcp\":false,\"cli\":false,\"tableName\":\"contents\"},\"extends\":\"Content\",\"exportName\":\"Article\",\"collectionExportName\":\"ArticleCollection\",\"validationRules\":[{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"contents\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"contents\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type\\\" TEXT,\\n \\\"variant\\\" TEXT,\\n \\\"file_key\\\" TEXT,\\n \\\"author\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"title\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"body\\\" TEXT,\\n \\\"body_format\\\" TEXT,\\n \\\"publish_date\\\" TIMESTAMP,\\n \\\"url\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"original_url\\\" TEXT,\\n \\\"language\\\" TEXT,\\n \\\"tags\\\" JSON DEFAULT '[]',\\n \\\"category\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'draft',\\n \\\"state\\\" TEXT DEFAULT 'active',\\n \\\"metadata\\\" JSON DEFAULT '{}',\\n \\\"thumbnail_asset_id\\\" UUID,\\n \\\"feed_source_id\\\" UUID,\\n \\\"source_guid\\\" TEXT,\\n \\\"source_name\\\" TEXT,\\n \\\"source_homepage_url\\\" TEXT,\\n \\\"external_url\\\" TEXT,\\n \\\"original_published_at\\\" TIMESTAMP,\\n \\\"dedupe_key\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type\":{\"type\":\"TEXT\",\"notNull\":false},\"variant\":{\"type\":\"TEXT\",\"notNull\":false},\"file_key\":{\"type\":\"TEXT\",\"notNull\":false},\"author\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"title\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"body\":{\"type\":\"TEXT\",\"notNull\":false},\"body_format\":{\"type\":\"TEXT\",\"notNull\":false},\"publish_date\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"url\":{\"type\":\"TEXT\",\"notNull\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false},\"original_url\":{\"type\":\"TEXT\",\"notNull\":false},\"language\":{\"type\":\"TEXT\",\"notNull\":false},\"tags\":{\"type\":\"JSON\",\"notNull\":false,\"default\":[]},\"category\":{\"type\":\"TEXT\",\"notNull\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"draft\"},\"state\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"active\"},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"default\":{}},\"thumbnail_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false},\"feed_source_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"content_feed_sources\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"source_guid\":{\"type\":\"TEXT\",\"notNull\":false},\"source_name\":{\"type\":\"TEXT\",\"notNull\":false},\"source_homepage_url\":{\"type\":\"TEXT\",\"notNull\":false},\"external_url\":{\"type\":\"TEXT\",\"notNull\":false},\"original_published_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"dedupe_key\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"contents_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"contents_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"contents_tenant_id_publish_date_idx\",\"columns\":[\"tenant_id\",\"publish_date\"]},{\"name\":\"contents_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"contents_thumbnail_asset_id_idx\",\"columns\":[\"thumbnail_asset_id\"]},{\"name\":\"contents_feed_source_id_idx\",\"columns\":[\"feed_source_id\"]}],\"version\":\"ad51267b\"}},\"@happyvertical/smrt-content:ContentDocument\":{\"name\":\"contentdocument\",\"className\":\"ContentDocument\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentDocument\",\"collection\":\"contents\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-types.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true}}},\"type\":{\"type\":\"text\",\"required\":false},\"variant\":{\"type\":\"text\",\"required\":false},\"fileKey\":{\"type\":\"text\",\"required\":false},\"author\":{\"type\":\"text\",\"required\":false},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"title\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"body\":{\"type\":\"text\",\"required\":false},\"bodyFormat\":{\"type\":\"text\",\"required\":false},\"publish_date\":{\"type\":\"datetime\",\"required\":false},\"url\":{\"type\":\"text\",\"required\":false},\"source\":{\"type\":\"text\",\"required\":false},\"original_url\":{\"type\":\"text\",\"required\":false},\"language\":{\"type\":\"text\",\"required\":false},\"tags\":{\"type\":\"json\",\"required\":false,\"default\":[]},\"category\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"draft\"},\"state\":{\"type\":\"text\",\"required\":false,\"default\":\"active\"},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}},\"thumbnailAssetId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-assets:Asset\"}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"SmrtSaveOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"resolveGovernance\":{\"name\":\"resolveGovernance\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ResolvedContentGovernance>\",\"isStatic\":false,\"isPublic\":true},\"loadReferences\":{\"name\":\"loadReferences\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"addReference\":{\"name\":\"addReference\",\"async\":true,\"parameters\":[{\"name\":\"content\",\"type\":\"Content | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Content\"},{\"type\":\"string\"}]},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"removeReference\":{\"name\":\"removeReference\",\"async\":true,\"parameters\":[{\"name\":\"targetId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReferences\":{\"name\":\"getReferences\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReferenceEdges\":{\"name\":\"getReferenceEdges\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"getReferenceDrift\":{\"name\":\"getReferenceDrift\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"isGoverned\":{\"name\":\"isGoverned\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getFactLinks\":{\"name\":\"getFactLinks\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFacts\":{\"name\":\"getFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\",\"boolean\"]}],\"returnType\":\"Promise<Fact[]>\",\"isStatic\":false,\"isPublic\":true},\"addFact\":{\"name\":\"addFact\",\"async\":true,\"parameters\":[{\"name\":\"fact\",\"type\":\"Fact | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Fact\"},{\"type\":\"string\"}]},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true},{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"removeFact\":{\"name\":\"removeFact\",\"async\":true,\"parameters\":[{\"name\":\"factId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"syncFacts\":{\"name\":\"syncFacts\",\"async\":true,\"parameters\":[{\"name\":\"factIds\",\"type\":\"string[]\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true},\"browseFacts\":{\"name\":\"browseFacts\",\"async\":true,\"parameters\":[{\"name\":\"query\",\"type\":\"any\",\"optional\":true,\"default\":\"\"},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"boolean\"]}],\"returnType\":\"Promise<Fact[]>\",\"isStatic\":false,\"isPublic\":true},\"repairFactAudit\":{\"name\":\"repairFactAudit\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactAuditAction\":{\"name\":\"repairFactAuditAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactEvidence\":{\"name\":\"repairFactEvidence\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditResourceRepairOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactEvidenceAction\":{\"name\":\"repairFactEvidenceAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditResourceRepairOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"recheckFactClaims\":{\"name\":\"recheckFactClaims\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditClaimRecheckOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"recheckFactClaimsAction\":{\"name\":\"recheckFactClaimsAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditClaimRecheckOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"updateFactEvidenceStatus\":{\"name\":\"updateFactEvidenceStatus\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactEvidenceStatusUpdateOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"updateFactEvidenceStatusAction\":{\"name\":\"updateFactEvidenceStatusAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactEvidenceStatusUpdateOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFactAuditState\":{\"name\":\"getFactAuditState\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<FactAuditState>\",\"isStatic\":false,\"isPublic\":true},\"getFactAuditStateAction\":{\"name\":\"getFactAuditStateAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFactsState\":{\"name\":\"getFactsState\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"syncFactsState\":{\"name\":\"syncFactsState\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string[]\",\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"createVersion\":{\"name\":\"createVersion\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"CreateContentVersionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getVersions\":{\"name\":\"getVersions\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"restoreFromVersion\":{\"name\":\"restoreFromVersion\",\"async\":true,\"parameters\":[{\"name\":\"versionNumber\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReviews\":{\"name\":\"getReviews\",\"async\":true,\"parameters\":[{\"name\":\"kind\",\"type\":\"any\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listReviews\":{\"name\":\"listReviews\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReviewRequirements\":{\"name\":\"getReviewRequirements\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"governance\",\"type\":\"ResolvedContentGovernance\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceState\":{\"name\":\"getGovernanceState\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentGovernanceState>\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceStateAction\":{\"name\":\"getGovernanceStateAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listReviewProfilesAction\":{\"name\":\"listReviewProfilesAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"evaluateReviewProfile\":{\"name\":\"evaluateReviewProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentReviewProfileEvaluation>\",\"isStatic\":false,\"isPublic\":true},\"evaluateReviewProfileAction\":{\"name\":\"evaluateReviewProfileAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"isReadyForReviewProfile\":{\"name\":\"isReadyForReviewProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getPublishedTransparency\":{\"name\":\"getPublishedTransparency\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getPublishedTransparencyAction\":{\"name\":\"getPublishedTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"previewTransparency\":{\"name\":\"previewTransparency\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"previewTransparencyAction\":{\"name\":\"previewTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"runReview\":{\"name\":\"runReview\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RunContentReviewOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"runReviewAction\":{\"name\":\"runReviewAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RunContentReviewOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"reviewFacts\":{\"name\":\"reviewFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<RunContentReviewOptions, 'kind'>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"reviewSafety\":{\"name\":\"reviewSafety\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<RunContentReviewOptions, 'kind'>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getCorrections\":{\"name\":\"getCorrections\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listCorrections\":{\"name\":\"listCorrections\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"issueCorrection\":{\"name\":\"issueCorrection\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IssueContentCorrectionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"issueCorrectionAction\":{\"name\":\"issueCorrectionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IssueContentCorrectionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listVersions\":{\"name\":\"listVersions\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"mutateVersionAction\":{\"name\":\"mutateVersionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"any\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getCategorySegments\":{\"name\":\"getCategorySegments\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"getParentCategory\":{\"name\":\"getParentCategory\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"getRootCategory\":{\"name\":\"getRootCategory\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"getAncestorPaths\":{\"name\":\"getAncestorPaths\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"isInCategory\":{\"name\":\"isInCategory\",\"async\":false,\"parameters\":[{\"name\":\"categoryPath\",\"type\":\"string\",\"optional\":false},{\"name\":\"includeChildren\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown> | null | undefined\",\"optional\":false,\"unionBranches\":[{\"type\":\"Record<string, unknown>\"},{\"type\":\"null\"},{\"type\":\"undefined\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":false,\"parameters\":[{\"name\":\"patch\",\"type\":\"Partial<Record<string, unknown>>\",\"optional\":false}],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"getThumbnail\":{\"name\":\"getThumbnail\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image | null>\",\"isStatic\":false,\"isPublic\":true},\"setThumbnail\":{\"name\":\"setThumbnail\",\"async\":true,\"parameters\":[{\"name\":\"image\",\"type\":\"Image\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"generateThumbnail\":{\"name\":\"generateThumbnail\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"ThumbnailOptions\",\"optional\":false}],\"returnType\":\"Promise<Image>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":false,\"mcp\":false,\"cli\":false,\"tableName\":\"contents\"},\"extends\":\"Content\",\"exportName\":\"ContentDocument\",\"collectionExportName\":\"ContentDocumentCollection\",\"validationRules\":[{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"contents\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"contents\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type\\\" TEXT,\\n \\\"variant\\\" TEXT,\\n \\\"file_key\\\" TEXT,\\n \\\"author\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"title\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"body\\\" TEXT,\\n \\\"body_format\\\" TEXT,\\n \\\"publish_date\\\" TIMESTAMP,\\n \\\"url\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"original_url\\\" TEXT,\\n \\\"language\\\" TEXT,\\n \\\"tags\\\" JSON DEFAULT '[]',\\n \\\"category\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'draft',\\n \\\"state\\\" TEXT DEFAULT 'active',\\n \\\"metadata\\\" JSON DEFAULT '{}',\\n \\\"thumbnail_asset_id\\\" UUID,\\n \\\"feed_source_id\\\" UUID,\\n \\\"source_guid\\\" TEXT,\\n \\\"source_name\\\" TEXT,\\n \\\"source_homepage_url\\\" TEXT,\\n \\\"external_url\\\" TEXT,\\n \\\"original_published_at\\\" TIMESTAMP,\\n \\\"dedupe_key\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type\":{\"type\":\"TEXT\",\"notNull\":false},\"variant\":{\"type\":\"TEXT\",\"notNull\":false},\"file_key\":{\"type\":\"TEXT\",\"notNull\":false},\"author\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"title\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"body\":{\"type\":\"TEXT\",\"notNull\":false},\"body_format\":{\"type\":\"TEXT\",\"notNull\":false},\"publish_date\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"url\":{\"type\":\"TEXT\",\"notNull\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false},\"original_url\":{\"type\":\"TEXT\",\"notNull\":false},\"language\":{\"type\":\"TEXT\",\"notNull\":false},\"tags\":{\"type\":\"JSON\",\"notNull\":false,\"default\":[]},\"category\":{\"type\":\"TEXT\",\"notNull\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"draft\"},\"state\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"active\"},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"default\":{}},\"thumbnail_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false},\"feed_source_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"content_feed_sources\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"source_guid\":{\"type\":\"TEXT\",\"notNull\":false},\"source_name\":{\"type\":\"TEXT\",\"notNull\":false},\"source_homepage_url\":{\"type\":\"TEXT\",\"notNull\":false},\"external_url\":{\"type\":\"TEXT\",\"notNull\":false},\"original_published_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"dedupe_key\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"contents_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"contents_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"contents_tenant_id_publish_date_idx\",\"columns\":[\"tenant_id\",\"publish_date\"]},{\"name\":\"contents_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"contents_thumbnail_asset_id_idx\",\"columns\":[\"thumbnail_asset_id\"]},{\"name\":\"contents_feed_source_id_idx\",\"columns\":[\"feed_source_id\"]}],\"version\":\"8107d801\"}},\"@happyvertical/smrt-content:Mirror\":{\"name\":\"mirror\",\"className\":\"Mirror\",\"qualifiedName\":\"@happyvertical/smrt-content:Mirror\",\"collection\":\"contents\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-types.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true}}},\"type\":{\"type\":\"text\",\"required\":false},\"variant\":{\"type\":\"text\",\"required\":false},\"fileKey\":{\"type\":\"text\",\"required\":false},\"author\":{\"type\":\"text\",\"required\":false},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"title\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"body\":{\"type\":\"text\",\"required\":false},\"bodyFormat\":{\"type\":\"text\",\"required\":false},\"publish_date\":{\"type\":\"datetime\",\"required\":false},\"url\":{\"type\":\"text\",\"required\":false},\"source\":{\"type\":\"text\",\"required\":false},\"original_url\":{\"type\":\"text\",\"required\":false},\"language\":{\"type\":\"text\",\"required\":false},\"tags\":{\"type\":\"json\",\"required\":false,\"default\":[]},\"category\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"draft\"},\"state\":{\"type\":\"text\",\"required\":false,\"default\":\"active\"},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}},\"thumbnailAssetId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-assets:Asset\"},\"feedSourceId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ContentFeedSource\"},\"sourceGuid\":{\"type\":\"text\",\"required\":false},\"sourceName\":{\"type\":\"text\",\"required\":false},\"sourceHomepageUrl\":{\"type\":\"text\",\"required\":false},\"externalUrl\":{\"type\":\"text\",\"required\":false},\"originalPublishedAt\":{\"type\":\"datetime\",\"required\":false},\"dedupeKey\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"SmrtSaveOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"resolveGovernance\":{\"name\":\"resolveGovernance\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ResolvedContentGovernance>\",\"isStatic\":false,\"isPublic\":true},\"loadReferences\":{\"name\":\"loadReferences\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"addReference\":{\"name\":\"addReference\",\"async\":true,\"parameters\":[{\"name\":\"content\",\"type\":\"Content | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Content\"},{\"type\":\"string\"}]},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"removeReference\":{\"name\":\"removeReference\",\"async\":true,\"parameters\":[{\"name\":\"targetId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReferences\":{\"name\":\"getReferences\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReferenceEdges\":{\"name\":\"getReferenceEdges\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"getReferenceDrift\":{\"name\":\"getReferenceDrift\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"isGoverned\":{\"name\":\"isGoverned\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getFactLinks\":{\"name\":\"getFactLinks\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFacts\":{\"name\":\"getFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\",\"boolean\"]}],\"returnType\":\"Promise<Fact[]>\",\"isStatic\":false,\"isPublic\":true},\"addFact\":{\"name\":\"addFact\",\"async\":true,\"parameters\":[{\"name\":\"fact\",\"type\":\"Fact | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Fact\"},{\"type\":\"string\"}]},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true},{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"removeFact\":{\"name\":\"removeFact\",\"async\":true,\"parameters\":[{\"name\":\"factId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"syncFacts\":{\"name\":\"syncFacts\",\"async\":true,\"parameters\":[{\"name\":\"factIds\",\"type\":\"string[]\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true},\"browseFacts\":{\"name\":\"browseFacts\",\"async\":true,\"parameters\":[{\"name\":\"query\",\"type\":\"any\",\"optional\":true,\"default\":\"\"},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"boolean\"]}],\"returnType\":\"Promise<Fact[]>\",\"isStatic\":false,\"isPublic\":true},\"repairFactAudit\":{\"name\":\"repairFactAudit\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactAuditAction\":{\"name\":\"repairFactAuditAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactEvidence\":{\"name\":\"repairFactEvidence\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditResourceRepairOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactEvidenceAction\":{\"name\":\"repairFactEvidenceAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditResourceRepairOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"recheckFactClaims\":{\"name\":\"recheckFactClaims\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditClaimRecheckOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"recheckFactClaimsAction\":{\"name\":\"recheckFactClaimsAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditClaimRecheckOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"updateFactEvidenceStatus\":{\"name\":\"updateFactEvidenceStatus\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactEvidenceStatusUpdateOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"updateFactEvidenceStatusAction\":{\"name\":\"updateFactEvidenceStatusAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactEvidenceStatusUpdateOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFactAuditState\":{\"name\":\"getFactAuditState\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<FactAuditState>\",\"isStatic\":false,\"isPublic\":true},\"getFactAuditStateAction\":{\"name\":\"getFactAuditStateAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFactsState\":{\"name\":\"getFactsState\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"syncFactsState\":{\"name\":\"syncFactsState\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string[]\",\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"createVersion\":{\"name\":\"createVersion\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"CreateContentVersionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getVersions\":{\"name\":\"getVersions\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"restoreFromVersion\":{\"name\":\"restoreFromVersion\",\"async\":true,\"parameters\":[{\"name\":\"versionNumber\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReviews\":{\"name\":\"getReviews\",\"async\":true,\"parameters\":[{\"name\":\"kind\",\"type\":\"any\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listReviews\":{\"name\":\"listReviews\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReviewRequirements\":{\"name\":\"getReviewRequirements\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"governance\",\"type\":\"ResolvedContentGovernance\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceState\":{\"name\":\"getGovernanceState\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentGovernanceState>\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceStateAction\":{\"name\":\"getGovernanceStateAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listReviewProfilesAction\":{\"name\":\"listReviewProfilesAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"evaluateReviewProfile\":{\"name\":\"evaluateReviewProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentReviewProfileEvaluation>\",\"isStatic\":false,\"isPublic\":true},\"evaluateReviewProfileAction\":{\"name\":\"evaluateReviewProfileAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"isReadyForReviewProfile\":{\"name\":\"isReadyForReviewProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getPublishedTransparency\":{\"name\":\"getPublishedTransparency\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getPublishedTransparencyAction\":{\"name\":\"getPublishedTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"previewTransparency\":{\"name\":\"previewTransparency\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"previewTransparencyAction\":{\"name\":\"previewTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"runReview\":{\"name\":\"runReview\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RunContentReviewOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"runReviewAction\":{\"name\":\"runReviewAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RunContentReviewOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"reviewFacts\":{\"name\":\"reviewFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<RunContentReviewOptions, 'kind'>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"reviewSafety\":{\"name\":\"reviewSafety\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<RunContentReviewOptions, 'kind'>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getCorrections\":{\"name\":\"getCorrections\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listCorrections\":{\"name\":\"listCorrections\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"issueCorrection\":{\"name\":\"issueCorrection\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IssueContentCorrectionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"issueCorrectionAction\":{\"name\":\"issueCorrectionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IssueContentCorrectionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listVersions\":{\"name\":\"listVersions\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"mutateVersionAction\":{\"name\":\"mutateVersionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"any\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getCategorySegments\":{\"name\":\"getCategorySegments\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"getParentCategory\":{\"name\":\"getParentCategory\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"getRootCategory\":{\"name\":\"getRootCategory\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"getAncestorPaths\":{\"name\":\"getAncestorPaths\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"isInCategory\":{\"name\":\"isInCategory\",\"async\":false,\"parameters\":[{\"name\":\"categoryPath\",\"type\":\"string\",\"optional\":false},{\"name\":\"includeChildren\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown> | null | undefined\",\"optional\":false,\"unionBranches\":[{\"type\":\"Record<string, unknown>\"},{\"type\":\"null\"},{\"type\":\"undefined\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":false,\"parameters\":[{\"name\":\"patch\",\"type\":\"Partial<Record<string, unknown>>\",\"optional\":false}],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"getThumbnail\":{\"name\":\"getThumbnail\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image | null>\",\"isStatic\":false,\"isPublic\":true},\"setThumbnail\":{\"name\":\"setThumbnail\",\"async\":true,\"parameters\":[{\"name\":\"image\",\"type\":\"Image\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"generateThumbnail\":{\"name\":\"generateThumbnail\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"ThumbnailOptions\",\"optional\":false}],\"returnType\":\"Promise<Image>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":false,\"mcp\":false,\"cli\":false,\"tableName\":\"contents\"},\"extends\":\"Content\",\"exportName\":\"Mirror\",\"collectionExportName\":\"MirrorCollection\",\"validationRules\":[{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"contents\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"contents\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type\\\" TEXT,\\n \\\"variant\\\" TEXT,\\n \\\"file_key\\\" TEXT,\\n \\\"author\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"title\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"body\\\" TEXT,\\n \\\"body_format\\\" TEXT,\\n \\\"publish_date\\\" TIMESTAMP,\\n \\\"url\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"original_url\\\" TEXT,\\n \\\"language\\\" TEXT,\\n \\\"tags\\\" JSON DEFAULT '[]',\\n \\\"category\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'draft',\\n \\\"state\\\" TEXT DEFAULT 'active',\\n \\\"metadata\\\" JSON DEFAULT '{}',\\n \\\"thumbnail_asset_id\\\" UUID,\\n \\\"feed_source_id\\\" UUID,\\n \\\"source_guid\\\" TEXT,\\n \\\"source_name\\\" TEXT,\\n \\\"source_homepage_url\\\" TEXT,\\n \\\"external_url\\\" TEXT,\\n \\\"original_published_at\\\" TIMESTAMP,\\n \\\"dedupe_key\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type\":{\"type\":\"TEXT\",\"notNull\":false},\"variant\":{\"type\":\"TEXT\",\"notNull\":false},\"file_key\":{\"type\":\"TEXT\",\"notNull\":false},\"author\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"title\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"body\":{\"type\":\"TEXT\",\"notNull\":false},\"body_format\":{\"type\":\"TEXT\",\"notNull\":false},\"publish_date\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"url\":{\"type\":\"TEXT\",\"notNull\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false},\"original_url\":{\"type\":\"TEXT\",\"notNull\":false},\"language\":{\"type\":\"TEXT\",\"notNull\":false},\"tags\":{\"type\":\"JSON\",\"notNull\":false,\"default\":[]},\"category\":{\"type\":\"TEXT\",\"notNull\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"draft\"},\"state\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"active\"},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"default\":{}},\"thumbnail_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false},\"feed_source_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"content_feed_sources\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"source_guid\":{\"type\":\"TEXT\",\"notNull\":false},\"source_name\":{\"type\":\"TEXT\",\"notNull\":false},\"source_homepage_url\":{\"type\":\"TEXT\",\"notNull\":false},\"external_url\":{\"type\":\"TEXT\",\"notNull\":false},\"original_published_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"dedupe_key\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"contents_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"contents_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"contents_tenant_id_publish_date_idx\",\"columns\":[\"tenant_id\",\"publish_date\"]},{\"name\":\"contents_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"contents_thumbnail_asset_id_idx\",\"columns\":[\"thumbnail_asset_id\"]},{\"name\":\"contents_feed_source_id_idx\",\"columns\":[\"feed_source_id\"]}],\"version\":\"088da7e4\"}},\"@happyvertical/smrt-content:ContentVersion\":{\"name\":\"contentversion\",\"className\":\"ContentVersion\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentVersion\",\"collection\":\"contentversions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-version.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"contentId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Content\",\"_meta\":{\"required\":true}},\"version\":{\"type\":\"integer\",\"required\":true,\"default\":1},\"kind\":{\"type\":\"text\",\"required\":false,\"default\":\"manual\"},\"title\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"body\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":false},\"summary\":{\"type\":\"text\",\"required\":false},\"snapshot\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getSnapshot\":{\"name\":\"getSnapshot\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"ContentVersionMetadata\",\"isStatic\":false,\"isPublic\":true},\"getTransparency\":{\"name\":\"getTransparency\",\"async\":false,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getTransparencyAction\":{\"name\":\"getTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_versions\",\"conflictColumns\":[\"content_id\",\"version\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"getTransparencyAction\"],\"routes\":{\"getTransparencyAction\":{\"method\":\"GET\",\"path\":\"transparency\"}}},\"mcp\":{\"include\":[\"list\",\"get\",\"create\"]},\"cli\":true,\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ContentVersion\",\"collectionExportName\":\"ContentVersionCollection\",\"validationRules\":[{\"field\":\"contentId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"version\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"content_versions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_versions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"content_id\\\" UUID NOT NULL,\\n \\\"version\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"kind\\\" TEXT DEFAULT 'manual',\\n \\\"title\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"body\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"summary\\\" TEXT,\\n \\\"snapshot\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"tenant_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"content_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"contents\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"version\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"kind\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"manual\"},\"title\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"body\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"summary\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"content_versions_content_id_version_idx\",\"columns\":[\"content_id\",\"version\"],\"unique\":true},{\"name\":\"content_versions_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"content_versions_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"66cda211\"}},\"@happyvertical/smrt-content:ContentVersionCollection\":{\"name\":\"contentversioncollection\",\"className\":\"ContentVersionCollection\",\"qualifiedName\":\"@happyvertical/smrt-content:ContentVersionCollection\",\"collection\":\"contentversions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content-versions.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{},\"methods\":{\"listForContent\":{\"name\":\"listForContent\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentVersion[]>\",\"isStatic\":false,\"isPublic\":true},\"getLatestForContent\":{\"name\":\"getLatestForContent\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentVersion | null>\",\"isStatic\":false,\"isPublic\":true},\"getLatestPublishedForContent\":{\"name\":\"getLatestPublishedForContent\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentVersion | null>\",\"isStatic\":false,\"isPublic\":true},\"getVersion\":{\"name\":\"getVersion\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false},{\"name\":\"versionNumber\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<ContentVersion | null>\",\"isStatic\":false,\"isPublic\":true},\"getNextVersionNumber\":{\"name\":\"getNextVersionNumber\",\"async\":true,\"parameters\":[{\"name\":\"contentId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"createSnapshot\":{\"name\":\"createSnapshot\",\"async\":true,\"parameters\":[{\"name\":\"content\",\"type\":\"Content\",\"optional\":false},{\"name\":\"options\",\"type\":\"CreateContentVersionOptions\",\"optional\":true}],\"returnType\":\"Promise<ContentVersion>\",\"isStatic\":false,\"isPublic\":true},\"restoreIntoContent\":{\"name\":\"restoreIntoContent\",\"async\":true,\"parameters\":[{\"name\":\"content\",\"type\":\"Content\",\"optional\":false},{\"name\":\"versionNumber\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<Content>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"content_versions\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ContentVersion\",\"exportName\":\"ContentVersionCollection\",\"collectionExportName\":\"ContentVersionCollectionCollection\",\"schema\":{\"tableName\":\"content_versions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"content_versions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"content_versions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"content_versions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"56acd806\"}},\"@happyvertical/smrt-content:Content\":{\"name\":\"content\",\"className\":\"Content\",\"qualifiedName\":\"@happyvertical/smrt-content:Content\",\"collection\":\"contents\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/content.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"type\":{\"type\":\"text\",\"required\":false},\"variant\":{\"type\":\"text\",\"required\":false},\"fileKey\":{\"type\":\"text\",\"required\":false},\"author\":{\"type\":\"text\",\"required\":false},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"title\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"body\":{\"type\":\"text\",\"required\":false},\"bodyFormat\":{\"type\":\"text\",\"required\":false},\"publish_date\":{\"type\":\"datetime\",\"required\":false},\"url\":{\"type\":\"text\",\"required\":false},\"source\":{\"type\":\"text\",\"required\":false},\"original_url\":{\"type\":\"text\",\"required\":false},\"language\":{\"type\":\"text\",\"required\":false},\"tags\":{\"type\":\"json\",\"required\":false,\"default\":[]},\"category\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"draft\"},\"state\":{\"type\":\"text\",\"required\":false,\"default\":\"active\"},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}},\"thumbnailAssetId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-assets:Asset\"}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"SmrtSaveOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"resolveGovernance\":{\"name\":\"resolveGovernance\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ResolvedContentGovernance>\",\"isStatic\":false,\"isPublic\":true},\"loadReferences\":{\"name\":\"loadReferences\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"addReference\":{\"name\":\"addReference\",\"async\":true,\"parameters\":[{\"name\":\"content\",\"type\":\"Content | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Content\"},{\"type\":\"string\"}]},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"removeReference\":{\"name\":\"removeReference\",\"async\":true,\"parameters\":[{\"name\":\"targetId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReferences\":{\"name\":\"getReferences\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReferenceEdges\":{\"name\":\"getReferenceEdges\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"getReferenceDrift\":{\"name\":\"getReferenceDrift\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"isGoverned\":{\"name\":\"isGoverned\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getFactLinks\":{\"name\":\"getFactLinks\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFacts\":{\"name\":\"getFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\",\"boolean\"]}],\"returnType\":\"Promise<Fact[]>\",\"isStatic\":false,\"isPublic\":true},\"addFact\":{\"name\":\"addFact\",\"async\":true,\"parameters\":[{\"name\":\"fact\",\"type\":\"Fact | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Fact\"},{\"type\":\"string\"}]},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true},{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"removeFact\":{\"name\":\"removeFact\",\"async\":true,\"parameters\":[{\"name\":\"factId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"syncFacts\":{\"name\":\"syncFacts\",\"async\":true,\"parameters\":[{\"name\":\"factIds\",\"type\":\"string[]\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"FactContentRelationship\",\"optional\":true}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true},\"browseFacts\":{\"name\":\"browseFacts\",\"async\":true,\"parameters\":[{\"name\":\"query\",\"type\":\"any\",\"optional\":true,\"default\":\"\"},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"boolean\"]}],\"returnType\":\"Promise<Fact[]>\",\"isStatic\":false,\"isPublic\":true},\"repairFactAudit\":{\"name\":\"repairFactAudit\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactAuditAction\":{\"name\":\"repairFactAuditAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactEvidence\":{\"name\":\"repairFactEvidence\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditResourceRepairOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"repairFactEvidenceAction\":{\"name\":\"repairFactEvidenceAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditResourceRepairOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"recheckFactClaims\":{\"name\":\"recheckFactClaims\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditClaimRecheckOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"recheckFactClaimsAction\":{\"name\":\"recheckFactClaimsAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactAuditClaimRecheckOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"updateFactEvidenceStatus\":{\"name\":\"updateFactEvidenceStatus\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactEvidenceStatusUpdateOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"updateFactEvidenceStatusAction\":{\"name\":\"updateFactEvidenceStatusAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"FactEvidenceStatusUpdateOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFactAuditState\":{\"name\":\"getFactAuditState\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<FactAuditState>\",\"isStatic\":false,\"isPublic\":true},\"getFactAuditStateAction\":{\"name\":\"getFactAuditStateAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getFactsState\":{\"name\":\"getFactsState\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"syncFactsState\":{\"name\":\"syncFactsState\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string[]\",\"FactContentRelationship\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"createVersion\":{\"name\":\"createVersion\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"CreateContentVersionOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getVersions\":{\"name\":\"getVersions\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"restoreFromVersion\":{\"name\":\"restoreFromVersion\",\"async\":true,\"parameters\":[{\"name\":\"versionNumber\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReviews\":{\"name\":\"getReviews\",\"async\":true,\"parameters\":[{\"name\":\"kind\",\"type\":\"any\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listReviews\":{\"name\":\"listReviews\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getReviewRequirements\":{\"name\":\"getReviewRequirements\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"governance\",\"type\":\"ResolvedContentGovernance\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceState\":{\"name\":\"getGovernanceState\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ContentGovernanceState>\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceStateAction\":{\"name\":\"getGovernanceStateAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listReviewProfilesAction\":{\"name\":\"listReviewProfilesAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"evaluateReviewProfile\":{\"name\":\"evaluateReviewProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ContentReviewProfileEvaluation>\",\"isStatic\":false,\"isPublic\":true},\"evaluateReviewProfileAction\":{\"name\":\"evaluateReviewProfileAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"isReadyForReviewProfile\":{\"name\":\"isReadyForReviewProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getPublishedTransparency\":{\"name\":\"getPublishedTransparency\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getPublishedTransparencyAction\":{\"name\":\"getPublishedTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"previewTransparency\":{\"name\":\"previewTransparency\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"previewTransparencyAction\":{\"name\":\"previewTransparencyAction\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"runReview\":{\"name\":\"runReview\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RunContentReviewOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"runReviewAction\":{\"name\":\"runReviewAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"RunContentReviewOptions\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"reviewFacts\":{\"name\":\"reviewFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<RunContentReviewOptions, 'kind'>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"reviewSafety\":{\"name\":\"reviewSafety\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<RunContentReviewOptions, 'kind'>\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getCorrections\":{\"name\":\"getCorrections\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listCorrections\":{\"name\":\"listCorrections\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"issueCorrection\":{\"name\":\"issueCorrection\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IssueContentCorrectionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"issueCorrectionAction\":{\"name\":\"issueCorrectionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"IssueContentCorrectionOptions\",\"optional\":false}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"listVersions\":{\"name\":\"listVersions\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"mutateVersionAction\":{\"name\":\"mutateVersionAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"any\",\"optional\":true,\"typeUnresolved\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getCategorySegments\":{\"name\":\"getCategorySegments\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"getParentCategory\":{\"name\":\"getParentCategory\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"getRootCategory\":{\"name\":\"getRootCategory\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"getAncestorPaths\":{\"name\":\"getAncestorPaths\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"isInCategory\":{\"name\":\"isInCategory\",\"async\":false,\"parameters\":[{\"name\":\"categoryPath\",\"type\":\"string\",\"optional\":false},{\"name\":\"includeChildren\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown> | null | undefined\",\"optional\":false,\"unionBranches\":[{\"type\":\"Record<string, unknown>\"},{\"type\":\"null\"},{\"type\":\"undefined\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":false,\"parameters\":[{\"name\":\"patch\",\"type\":\"Partial<Record<string, unknown>>\",\"optional\":false}],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"getThumbnail\":{\"name\":\"getThumbnail\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image | null>\",\"isStatic\":false,\"isPublic\":true},\"setThumbnail\":{\"name\":\"setThumbnail\",\"async\":true,\"parameters\":[{\"name\":\"image\",\"type\":\"Image\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"generateThumbnail\":{\"name\":\"generateThumbnail\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"ThumbnailOptions\",\"optional\":false}],\"returnType\":\"Promise<Image>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\",\"getFactsState\",\"syncFactsState\",\"getFactAuditStateAction\",\"repairFactAuditAction\",\"repairFactEvidenceAction\",\"recheckFactClaimsAction\",\"updateFactEvidenceStatusAction\",\"getGovernanceStateAction\",\"listReviews\",\"runReviewAction\",\"listReviewProfilesAction\",\"evaluateReviewProfileAction\",\"getPublishedTransparencyAction\",\"previewTransparencyAction\",\"listCorrections\",\"issueCorrectionAction\",\"listVersions\",\"mutateVersionAction\"],\"routes\":{\"getFactsState\":{\"method\":\"GET\",\"path\":\"facts\"},\"syncFactsState\":{\"method\":\"PUT\",\"path\":\"facts\"},\"getFactAuditStateAction\":{\"method\":\"GET\",\"path\":\"fact-audit\"},\"repairFactAuditAction\":{\"method\":\"POST\",\"path\":\"fact-audit/repair\"},\"repairFactEvidenceAction\":{\"method\":\"POST\",\"path\":\"fact-audit/evidence/repair\"},\"recheckFactClaimsAction\":{\"method\":\"POST\",\"path\":\"fact-audit/claims/recheck\"},\"updateFactEvidenceStatusAction\":{\"method\":\"PUT\",\"path\":\"fact-audit/evidence/status\"},\"getGovernanceStateAction\":{\"method\":\"GET\",\"path\":\"governance\"},\"listReviews\":{\"method\":\"GET\",\"path\":\"reviews\"},\"runReviewAction\":{\"method\":\"POST\",\"path\":\"reviews\"},\"listReviewProfilesAction\":{\"method\":\"GET\",\"path\":\"review-profiles\"},\"evaluateReviewProfileAction\":{\"method\":\"GET\",\"path\":\"review-profiles/[profileKey]\"},\"getPublishedTransparencyAction\":{\"method\":\"GET\",\"path\":\"transparency\"},\"previewTransparencyAction\":{\"method\":\"GET\",\"path\":\"transparency/preview\"},\"listCorrections\":{\"method\":\"GET\",\"path\":\"corrections\"},\"issueCorrectionAction\":{\"method\":\"POST\",\"path\":\"corrections\"},\"listVersions\":{\"method\":\"GET\",\"path\":\"versions\"},\"mutateVersionAction\":{\"method\":\"POST\",\"path\":\"versions\"}},\"serializers\":{\"item\":{\"importPath\":\"$lib/server/content-api-serializers\",\"exportName\":\"serializeContent\"}}},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"cli\":true,\"indexes\":[{\"name\":\"contents_tenant_id_publish_date_idx\",\"columns\":[\"tenantId\",\"publish_date\"]}],\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"]},\"extends\":\"SmrtObject\",\"exportName\":\"Content\",\"collectionExportName\":\"ContentCollection\",\"validationRules\":[{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"contents\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"contents\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type\\\" TEXT,\\n \\\"variant\\\" TEXT,\\n \\\"file_key\\\" TEXT,\\n \\\"author\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"title\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"body\\\" TEXT,\\n \\\"body_format\\\" TEXT,\\n \\\"publish_date\\\" TIMESTAMP,\\n \\\"url\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"original_url\\\" TEXT,\\n \\\"language\\\" TEXT,\\n \\\"tags\\\" JSON DEFAULT '[]',\\n \\\"category\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'draft',\\n \\\"state\\\" TEXT DEFAULT 'active',\\n \\\"metadata\\\" JSON DEFAULT '{}',\\n \\\"thumbnail_asset_id\\\" UUID,\\n \\\"feed_source_id\\\" UUID,\\n \\\"source_guid\\\" TEXT,\\n \\\"source_name\\\" TEXT,\\n \\\"source_homepage_url\\\" TEXT,\\n \\\"external_url\\\" TEXT,\\n \\\"original_published_at\\\" TIMESTAMP,\\n \\\"dedupe_key\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type\":{\"type\":\"TEXT\",\"notNull\":false},\"variant\":{\"type\":\"TEXT\",\"notNull\":false},\"file_key\":{\"type\":\"TEXT\",\"notNull\":false},\"author\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"title\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"body\":{\"type\":\"TEXT\",\"notNull\":false},\"body_format\":{\"type\":\"TEXT\",\"notNull\":false},\"publish_date\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"url\":{\"type\":\"TEXT\",\"notNull\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false},\"original_url\":{\"type\":\"TEXT\",\"notNull\":false},\"language\":{\"type\":\"TEXT\",\"notNull\":false},\"tags\":{\"type\":\"JSON\",\"notNull\":false,\"default\":[]},\"category\":{\"type\":\"TEXT\",\"notNull\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"draft\"},\"state\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"active\"},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"default\":{}},\"thumbnail_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false},\"feed_source_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"content_feed_sources\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"source_guid\":{\"type\":\"TEXT\",\"notNull\":false},\"source_name\":{\"type\":\"TEXT\",\"notNull\":false},\"source_homepage_url\":{\"type\":\"TEXT\",\"notNull\":false},\"external_url\":{\"type\":\"TEXT\",\"notNull\":false},\"original_published_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"dedupe_key\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"contents_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"contents_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"contents_tenant_id_publish_date_idx\",\"columns\":[\"tenant_id\",\"publish_date\"]},{\"name\":\"contents_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"contents_thumbnail_asset_id_idx\",\"columns\":[\"thumbnail_asset_id\"]},{\"name\":\"contents_feed_source_id_idx\",\"columns\":[\"feed_source_id\"]}],\"version\":\"40e4ddf4\"}},\"@happyvertical/smrt-content:Contents\":{\"name\":\"contents\",\"className\":\"Contents\",\"qualifiedName\":\"@happyvertical/smrt-content:Contents\",\"collection\":\"contents\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/content/src/contents.ts\",\"packageName\":\"@happyvertical/smrt-content\",\"fields\":{\"contentDir\":{\"type\":\"text\",\"required\":false},\"loaded\":{\"type\":\"json\",\"required\":true}},\"methods\":{\"getDb\":{\"name\":\"getDb\",\"async\":false,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"queryAction\":{\"name\":\"queryAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<DataQueryResult>\",\"isStatic\":false,\"isPublic\":true},\"browseFacts\":{\"name\":\"browseFacts\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\",\"number | string\",\"boolean | string\",\"string | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\",\"string | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getGovernanceDefinitionsAction\":{\"name\":\"getGovernanceDefinitionsAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"resolveGovernanceAction\":{\"name\":\"resolveGovernanceAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\",\"string | null\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"mirror\":{\"name\":\"mirror\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"typeUnresolved\":true,\"memberTypes\":[\"string\",\"boolean\",\"ResolveHostname\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"writeContentFile\":{\"name\":\"writeContentFile\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"Content\",\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"syncContentDir\":{\"name\":\"syncContentDir\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"generateMissingThumbnails\":{\"name\":\"generateMissingThumbnails\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"GenerateMissingThumbnailsOptions\",\"optional\":false}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true},\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Content[]>\",\"isStatic\":false,\"isPublic\":true},\"findGlobal\":{\"name\":\"findGlobal\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Content[]>\",\"isStatic\":false,\"isPublic\":true},\"findWithGlobals\":{\"name\":\"findWithGlobals\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Content[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"browseFacts\",\"getBySlug\",\"getGovernanceDefinitionsAction\",\"resolveGovernanceAction\",\"queryAction\"],\"routes\":{\"queryAction\":{\"scope\":\"collection\",\"method\":\"POST\",\"path\":\"query\"},\"browseFacts\":{\"scope\":\"collection\",\"method\":\"GET\",\"path\":\"facts\"},\"getBySlug\":{\"scope\":\"collection\",\"method\":\"GET\",\"path\":\"by-slug\"},\"getGovernanceDefinitionsAction\":{\"scope\":\"collection\",\"method\":\"GET\",\"path\":\"governance\"},\"resolveGovernanceAction\":{\"scope\":\"collection\",\"method\":\"GET\",\"path\":\"governance/resolve\"}}},\"mcp\":false,\"cli\":false},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Content\",\"exportName\":\"Contents\",\"collectionExportName\":\"ContentsCollection\",\"validationRules\":[{\"field\":\"loaded\",\"rule\":\"required\",\"fieldType\":\"json\"}],\"schema\":{\"tableName\":\"contents\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"contents\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"content_dir\\\" TEXT,\\n \\\"loaded\\\" JSON NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"content_dir\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"loaded\":{\"type\":\"JSON\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"contents_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"contents_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"c11f9ec0\"}}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-agents\",\"@happyvertical/smrt-assets\",\"@happyvertical/smrt-chat\",\"@happyvertical/smrt-core\",\"@happyvertical/smrt-facts\",\"@happyvertical/smrt-images\",\"@happyvertical/smrt-messages\",\"@happyvertical/smrt-profiles\",\"@happyvertical/smrt-prompts\",\"@happyvertical/smrt-tenancy\"]}"));
|
|
11
|
-
//#endregion
|
|
12
|
-
//#region src/asset-associable.ts
|
|
13
|
-
function isAssetAssociable(value) {
|
|
14
|
-
if (!value || typeof value !== "object") return false;
|
|
15
|
-
const candidate = value;
|
|
16
|
-
return typeof candidate.getAssets === "function" && typeof candidate.addAsset === "function" && typeof candidate.removeAsset === "function";
|
|
17
|
-
}
|
|
18
|
-
function isMetadataAccessor(value) {
|
|
19
|
-
if (!value || typeof value !== "object") return false;
|
|
20
|
-
const candidate = value;
|
|
21
|
-
return typeof candidate.getMetadata === "function" && typeof candidate.setMetadata === "function" && typeof candidate.updateMetadata === "function";
|
|
22
|
-
}
|
|
23
|
-
function isPlainMetadataRecord(value) {
|
|
24
|
-
if (!value || typeof value !== "object") return false;
|
|
25
|
-
if (Array.isArray(value)) return false;
|
|
26
|
-
const proto = Object.getPrototypeOf(value);
|
|
27
|
-
return proto === null || proto === Object.prototype;
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region src/content-asset.ts
|
|
31
|
-
var __defProp$4 = Object.defineProperty;
|
|
32
|
-
var __getOwnPropDesc$4 = Object.getOwnPropertyDescriptor;
|
|
33
|
-
var __decorateClass$4 = (decorators, target, key, kind) => {
|
|
34
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$4(target, key) : target;
|
|
35
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
36
|
-
if (kind && result) __defProp$4(target, key, result);
|
|
37
|
-
return result;
|
|
38
|
-
};
|
|
39
|
-
var ContentAsset = class extends SmrtObject {
|
|
40
|
-
tenantId = null;
|
|
41
|
-
contentId = "";
|
|
42
|
-
assetId = "";
|
|
43
|
-
relationship = "attachment";
|
|
44
|
-
sortOrder = 0;
|
|
45
|
-
constructor(options = {}) {
|
|
46
|
-
super(options);
|
|
47
|
-
if (options.contentId) this.contentId = options.contentId;
|
|
48
|
-
if (options.assetId) this.assetId = options.assetId;
|
|
49
|
-
if (options.relationship) this.relationship = options.relationship;
|
|
50
|
-
if (options.sortOrder !== void 0) this.sortOrder = options.sortOrder;
|
|
51
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
__decorateClass$4([tenantId({ nullable: true })], ContentAsset.prototype, "tenantId", 2);
|
|
55
|
-
__decorateClass$4([foreignKey("Content", { required: true })], ContentAsset.prototype, "contentId", 2);
|
|
56
|
-
__decorateClass$4([crossPackageRef("@happyvertical/smrt-assets:Asset", { required: true })], ContentAsset.prototype, "assetId", 2);
|
|
57
|
-
__decorateClass$4([field({ required: true })], ContentAsset.prototype, "relationship", 2);
|
|
58
|
-
__decorateClass$4([field()], ContentAsset.prototype, "sortOrder", 2);
|
|
59
|
-
ContentAsset = __decorateClass$4([TenantScoped({ mode: "optional" }), smrt({
|
|
60
|
-
tableName: "content_assets",
|
|
61
|
-
conflictColumns: [
|
|
62
|
-
"content_id",
|
|
63
|
-
"asset_id",
|
|
64
|
-
"relationship"
|
|
65
|
-
],
|
|
66
|
-
api: false,
|
|
67
|
-
mcp: false,
|
|
68
|
-
cli: false
|
|
69
|
-
})], ContentAsset);
|
|
70
|
-
//#endregion
|
|
71
|
-
//#region src/content-assets.ts
|
|
72
|
-
var __defProp$3 = Object.defineProperty;
|
|
73
|
-
var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
|
|
74
|
-
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$3(obj, key, {
|
|
75
|
-
enumerable: true,
|
|
76
|
-
configurable: true,
|
|
77
|
-
writable: true,
|
|
78
|
-
value
|
|
79
|
-
}) : obj[key] = value;
|
|
80
|
-
var __decorateClass$3 = (decorators, target, key, kind) => {
|
|
81
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
|
|
82
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
83
|
-
if (kind && result) __defProp$3(target, key, result);
|
|
84
|
-
return result;
|
|
85
|
-
};
|
|
86
|
-
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
87
|
-
var ContentAssetCollection = class extends SmrtJunction {
|
|
88
|
-
leftField = "contentId";
|
|
89
|
-
rightField = "assetId";
|
|
90
|
-
};
|
|
91
|
-
__publicField$1(ContentAssetCollection, "_itemClass", ContentAsset);
|
|
92
|
-
ContentAssetCollection = __decorateClass$3([smrt({
|
|
93
|
-
api: false,
|
|
94
|
-
mcp: false,
|
|
95
|
-
cli: false
|
|
96
|
-
})], ContentAssetCollection);
|
|
97
|
-
//#endregion
|
|
98
|
-
//#region src/content-governance.ts
|
|
99
|
-
var DEFAULT_FACT_RELATIONSHIP = "supports";
|
|
100
|
-
var DEFAULT_CONTENT_GOVERNANCE_CONFIG = {
|
|
101
|
-
policies: [{
|
|
102
|
-
key: "facts",
|
|
103
|
-
label: "Facts Review",
|
|
104
|
-
kind: "facts",
|
|
105
|
-
instructions: [
|
|
106
|
-
"Compare the draft copy against the supplied facts only.",
|
|
107
|
-
"Flag contradictions, unsupported claims, stale claims, and places where the copy should cite or qualify a statement.",
|
|
108
|
-
"Do not invent missing facts. If the draft makes a claim that is not supported by the provided facts, flag it clearly."
|
|
109
|
-
].join(" "),
|
|
110
|
-
enabled: true
|
|
111
|
-
}, {
|
|
112
|
-
key: "safety",
|
|
113
|
-
label: "Safety Review",
|
|
114
|
-
kind: "safety",
|
|
115
|
-
instructions: [
|
|
116
|
-
"Review the content for legal, reputational, and user-safety risks.",
|
|
117
|
-
"At minimum, check for defamation risk, privacy leaks, unverified allegations, unsafe instructions, and medical, legal, or financial claims that need qualification.",
|
|
118
|
-
"Flag content that should be softened, attributed, removed, or escalated for human review."
|
|
119
|
-
].join(" "),
|
|
120
|
-
enabled: true
|
|
121
|
-
}].map(clonePolicyDefinition),
|
|
122
|
-
profiles: [{
|
|
123
|
-
key: "publication",
|
|
124
|
-
label: "Publication",
|
|
125
|
-
description: "Default publication-time editorial checks.",
|
|
126
|
-
enabled: true,
|
|
127
|
-
requirements: [{
|
|
128
|
-
policyKey: "safety",
|
|
129
|
-
label: "Safety Review",
|
|
130
|
-
blocking: false
|
|
131
|
-
}, {
|
|
132
|
-
policyKey: "facts",
|
|
133
|
-
label: "Facts Review",
|
|
134
|
-
blocking: false
|
|
135
|
-
}]
|
|
136
|
-
}, {
|
|
137
|
-
key: "correction",
|
|
138
|
-
label: "Correction",
|
|
139
|
-
description: "Default correction-time editorial checks.",
|
|
140
|
-
enabled: true,
|
|
141
|
-
requirements: [{
|
|
142
|
-
policyKey: "safety",
|
|
143
|
-
label: "Safety Review",
|
|
144
|
-
blocking: false
|
|
145
|
-
}]
|
|
146
|
-
}].map(cloneProfileDefinition),
|
|
147
|
-
assignments: []
|
|
148
|
-
};
|
|
149
|
-
var governanceConfig = cloneGovernanceConfig(DEFAULT_CONTENT_GOVERNANCE_CONFIG);
|
|
150
|
-
function cloneReviewRequirement(requirement) {
|
|
151
|
-
return {
|
|
152
|
-
...requirement,
|
|
153
|
-
acceptedStatuses: requirement.acceptedStatuses ? [...requirement.acceptedStatuses] : void 0
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
function normalizePolicyDefinition(policy) {
|
|
157
|
-
return {
|
|
158
|
-
key: policy.key,
|
|
159
|
-
label: policy.label || policy.key,
|
|
160
|
-
kind: policy.kind || getFallbackPolicyKind(policy.key),
|
|
161
|
-
instructions: policy.instructions || "",
|
|
162
|
-
enabled: policy.enabled !== false,
|
|
163
|
-
metadata: policy.metadata ? { ...policy.metadata } : void 0
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
function clonePolicyDefinition(policy) {
|
|
167
|
-
return normalizePolicyDefinition(policy);
|
|
168
|
-
}
|
|
169
|
-
function normalizeProfileDefinition(profile) {
|
|
170
|
-
return {
|
|
171
|
-
key: profile.key,
|
|
172
|
-
label: profile.label || profile.key,
|
|
173
|
-
description: profile.description || "",
|
|
174
|
-
enabled: profile.enabled !== false,
|
|
175
|
-
requirements: Array.isArray(profile.requirements) ? profile.requirements.map(cloneReviewRequirement) : [],
|
|
176
|
-
metadata: profile.metadata ? { ...profile.metadata } : void 0
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
function cloneProfileDefinition(profile) {
|
|
180
|
-
return normalizeProfileDefinition(profile);
|
|
181
|
-
}
|
|
182
|
-
function buildContentGovernanceAssignmentKey(contentType, contentVariant) {
|
|
183
|
-
return `${contentType || ""}::${contentVariant || ""}`;
|
|
184
|
-
}
|
|
185
|
-
function normalizeAssignmentDefinition(assignment) {
|
|
186
|
-
return {
|
|
187
|
-
key: assignment.key || buildContentGovernanceAssignmentKey(assignment.contentType, assignment.contentVariant),
|
|
188
|
-
label: assignment.label || "",
|
|
189
|
-
contentType: assignment.contentType,
|
|
190
|
-
contentVariant: assignment.contentVariant || "",
|
|
191
|
-
enabled: assignment.enabled !== false,
|
|
192
|
-
factLinkingEnabled: assignment.factLinkingEnabled === true,
|
|
193
|
-
transparencyEnabled: assignment.transparencyEnabled === true,
|
|
194
|
-
publicationProfileKey: assignment.publicationProfileKey || null,
|
|
195
|
-
correctionProfileKey: assignment.correctionProfileKey || null,
|
|
196
|
-
enforcePublishReadiness: assignment.enforcePublishReadiness === true,
|
|
197
|
-
defaultFactRelationship: assignment.defaultFactRelationship || DEFAULT_FACT_RELATIONSHIP,
|
|
198
|
-
metadata: assignment.metadata ? { ...assignment.metadata } : void 0
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
function cloneAssignmentDefinition(assignment) {
|
|
202
|
-
return normalizeAssignmentDefinition(assignment);
|
|
203
|
-
}
|
|
204
|
-
function cloneGovernanceConfig(config) {
|
|
205
|
-
return {
|
|
206
|
-
policies: config.policies.map(clonePolicyDefinition),
|
|
207
|
-
profiles: config.profiles.map(cloneProfileDefinition),
|
|
208
|
-
assignments: config.assignments.map(cloneAssignmentDefinition)
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
function mergeByKey(previous, next, normalize) {
|
|
212
|
-
const merged = /* @__PURE__ */ new Map();
|
|
213
|
-
for (const value of previous) {
|
|
214
|
-
const normalized = normalize(value);
|
|
215
|
-
if (normalized.key) merged.set(normalized.key, normalized);
|
|
216
|
-
}
|
|
217
|
-
for (const value of next) {
|
|
218
|
-
const normalized = normalize(value);
|
|
219
|
-
if (normalized.key) merged.set(normalized.key, normalized);
|
|
220
|
-
}
|
|
221
|
-
return [...merged.values()];
|
|
222
|
-
}
|
|
223
|
-
function getFallbackPolicyKind(key) {
|
|
224
|
-
if (key === "facts") return "facts";
|
|
225
|
-
if (key === "safety") return "safety";
|
|
226
|
-
return "custom";
|
|
227
|
-
}
|
|
228
|
-
function getPolicyMap(policies) {
|
|
229
|
-
return new Map(policies.map((policy) => {
|
|
230
|
-
const normalized = normalizePolicyDefinition(policy);
|
|
231
|
-
return [normalized.key, normalized];
|
|
232
|
-
}));
|
|
233
|
-
}
|
|
234
|
-
function getProfileMap(profiles) {
|
|
235
|
-
return new Map(profiles.map((profile) => {
|
|
236
|
-
const normalized = normalizeProfileDefinition(profile);
|
|
237
|
-
return [normalized.key, normalized];
|
|
238
|
-
}));
|
|
239
|
-
}
|
|
240
|
-
function isMissingGovernanceTableError(error) {
|
|
241
|
-
const message = error instanceof Error ? error.message : String(error || "Unknown error");
|
|
242
|
-
return message.includes("Run 'smrt db:migrate'") || /no such table/i.test(message) || /does not exist/i.test(message);
|
|
243
|
-
}
|
|
244
|
-
function getRowTimestamp(row, primaryKey) {
|
|
245
|
-
const snakeCaseKey = primaryKey === "createdAt" ? "created_at" : "updated_at";
|
|
246
|
-
const value = row[primaryKey] ?? row[snakeCaseKey];
|
|
247
|
-
return typeof value === "string" && value.length > 0 ? value : null;
|
|
248
|
-
}
|
|
249
|
-
function getRowTenantId(row) {
|
|
250
|
-
const value = row.tenantId ?? row.tenant_id ?? null;
|
|
251
|
-
return typeof value === "string" && value.length > 0 ? value : null;
|
|
252
|
-
}
|
|
253
|
-
function getRowString(row, ...keys) {
|
|
254
|
-
for (const key of keys) {
|
|
255
|
-
const value = row[key];
|
|
256
|
-
if (typeof value === "string" && value.length > 0) return value;
|
|
257
|
-
}
|
|
258
|
-
return null;
|
|
259
|
-
}
|
|
260
|
-
function safeParseJSONObject(value) {
|
|
261
|
-
if (!value) return {};
|
|
262
|
-
if (typeof value === "object" && !Array.isArray(value)) return { ...value };
|
|
263
|
-
try {
|
|
264
|
-
const parsed = JSON.parse(String(value));
|
|
265
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? { ...parsed } : {};
|
|
266
|
-
} catch {
|
|
267
|
-
return {};
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
function safeParseJSONArray(value, mapEntry) {
|
|
271
|
-
if (!value) return [];
|
|
272
|
-
if (Array.isArray(value)) return value.map((entry) => mapEntry(entry));
|
|
273
|
-
try {
|
|
274
|
-
const parsed = JSON.parse(String(value));
|
|
275
|
-
return Array.isArray(parsed) ? parsed.map((entry) => mapEntry(entry)) : [];
|
|
276
|
-
} catch {
|
|
277
|
-
return [];
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
function resolveGovernanceTenantFilter(tenantId) {
|
|
281
|
-
if (tenantId !== void 0) return tenantId;
|
|
282
|
-
if (isSystemContext() || isSuperAdminBypass()) return;
|
|
283
|
-
const currentTenant = getCurrentTenant();
|
|
284
|
-
if (currentTenant?.tenantId) return currentTenant.tenantId;
|
|
285
|
-
return isTenancyEnabled() ? null : void 0;
|
|
286
|
-
}
|
|
287
|
-
function mapPersistedPolicyRow(row) {
|
|
288
|
-
return {
|
|
289
|
-
id: typeof row.id === "string" ? row.id : void 0,
|
|
290
|
-
tenantId: getRowTenantId(row),
|
|
291
|
-
createdAt: getRowTimestamp(row, "createdAt"),
|
|
292
|
-
updatedAt: getRowTimestamp(row, "updatedAt"),
|
|
293
|
-
...normalizePolicyDefinition({
|
|
294
|
-
key: String(row.key || ""),
|
|
295
|
-
label: String(row.label || row.key || ""),
|
|
296
|
-
kind: row.kind || getFallbackPolicyKind(String(row.key || "")),
|
|
297
|
-
instructions: String(row.instructions || ""),
|
|
298
|
-
enabled: row.enabled !== false && row.enabled !== 0,
|
|
299
|
-
metadata: safeParseJSONObject(row.metadata)
|
|
300
|
-
})
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
function mapPersistedProfileRow(row) {
|
|
304
|
-
return {
|
|
305
|
-
id: typeof row.id === "string" ? row.id : void 0,
|
|
306
|
-
tenantId: getRowTenantId(row),
|
|
307
|
-
createdAt: getRowTimestamp(row, "createdAt"),
|
|
308
|
-
updatedAt: getRowTimestamp(row, "updatedAt"),
|
|
309
|
-
...normalizeProfileDefinition({
|
|
310
|
-
key: String(row.key || ""),
|
|
311
|
-
label: String(row.label || row.key || ""),
|
|
312
|
-
description: String(row.description || ""),
|
|
313
|
-
enabled: row.enabled !== false && row.enabled !== 0,
|
|
314
|
-
requirements: safeParseJSONArray(row.requirements, cloneReviewRequirement),
|
|
315
|
-
metadata: safeParseJSONObject(row.metadata)
|
|
316
|
-
})
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
function mapPersistedAssignmentRow(row) {
|
|
320
|
-
return {
|
|
321
|
-
id: typeof row.id === "string" ? row.id : void 0,
|
|
322
|
-
tenantId: getRowTenantId(row),
|
|
323
|
-
createdAt: getRowTimestamp(row, "createdAt"),
|
|
324
|
-
updatedAt: getRowTimestamp(row, "updatedAt"),
|
|
325
|
-
...normalizeAssignmentDefinition({
|
|
326
|
-
key: String(row.key || ""),
|
|
327
|
-
label: String(row.label || ""),
|
|
328
|
-
contentType: String(row.contentType || row.content_type || ""),
|
|
329
|
-
contentVariant: String(row.contentVariant || row.content_variant || ""),
|
|
330
|
-
enabled: row.enabled !== false && row.enabled !== 0,
|
|
331
|
-
factLinkingEnabled: row.factLinkingEnabled === true || row.fact_linking_enabled === true || row.fact_linking_enabled === 1,
|
|
332
|
-
transparencyEnabled: row.transparencyEnabled === true || row.transparency_enabled === true || row.transparency_enabled === 1,
|
|
333
|
-
publicationProfileKey: getRowString(row, "publicationProfileKey", "publication_profile_key"),
|
|
334
|
-
correctionProfileKey: getRowString(row, "correctionProfileKey", "correction_profile_key"),
|
|
335
|
-
enforcePublishReadiness: row.enforcePublishReadiness === true || row.enforce_publish_readiness === true || row.enforce_publish_readiness === 1,
|
|
336
|
-
defaultFactRelationship: getRowString(row, "defaultFactRelationship", "default_fact_relationship") || DEFAULT_FACT_RELATIONSHIP,
|
|
337
|
-
metadata: safeParseJSONObject(row.metadata)
|
|
338
|
-
})
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
async function loadPersistedContentGovernanceDefinitions(options = {}) {
|
|
342
|
-
const { db } = options;
|
|
343
|
-
if (!db) return {
|
|
344
|
-
policies: [],
|
|
345
|
-
profiles: [],
|
|
346
|
-
assignments: []
|
|
347
|
-
};
|
|
348
|
-
try {
|
|
349
|
-
const tenantId = resolveGovernanceTenantFilter(options.tenantId);
|
|
350
|
-
const listGovernanceRows = async (tableName) => {
|
|
351
|
-
const byCreatedAt = (a, b) => String(a.created_at || a.createdAt || "").localeCompare(String(b.created_at || b.createdAt || ""));
|
|
352
|
-
const sortRows = (rows) => rows.sort(byCreatedAt);
|
|
353
|
-
if (tenantId === void 0) return sortRows(await db.list(tableName, {}));
|
|
354
|
-
if (tenantId === null) return sortRows(await db.list(tableName, { tenant_id: null }));
|
|
355
|
-
const [globalRows, tenantRows] = await Promise.all([db.list(tableName, { tenant_id: null }), db.list(tableName, { tenant_id: tenantId })]);
|
|
356
|
-
return [...sortRows(globalRows), ...sortRows(tenantRows)];
|
|
357
|
-
};
|
|
358
|
-
const [policyRows, profileRows, assignmentRows] = await Promise.all([
|
|
359
|
-
listGovernanceRows("content_governance_policies"),
|
|
360
|
-
listGovernanceRows("content_governance_profiles"),
|
|
361
|
-
listGovernanceRows("content_governance_assignments")
|
|
362
|
-
]);
|
|
363
|
-
return {
|
|
364
|
-
policies: policyRows.map((row) => mapPersistedPolicyRow(row)),
|
|
365
|
-
profiles: profileRows.map((row) => mapPersistedProfileRow(row)),
|
|
366
|
-
assignments: assignmentRows.map((row) => mapPersistedAssignmentRow(row))
|
|
367
|
-
};
|
|
368
|
-
} catch (error) {
|
|
369
|
-
if (isMissingGovernanceTableError(error)) return {
|
|
370
|
-
policies: [],
|
|
371
|
-
profiles: [],
|
|
372
|
-
assignments: []
|
|
373
|
-
};
|
|
374
|
-
throw error;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
function resolveAssignmentDefinition(assignments, options) {
|
|
378
|
-
if (!options.contentType) return null;
|
|
379
|
-
const exactMatch = assignments.find((assignment) => assignment.contentType === options.contentType && (assignment.contentVariant || "") === (options.contentVariant || "")) || null;
|
|
380
|
-
if (exactMatch) return cloneAssignmentDefinition(exactMatch);
|
|
381
|
-
const typeOnlyMatch = assignments.find((assignment) => assignment.contentType === options.contentType && !assignment.contentVariant) || null;
|
|
382
|
-
return typeOnlyMatch ? cloneAssignmentDefinition(typeOnlyMatch) : null;
|
|
383
|
-
}
|
|
384
|
-
function buildResolvedGovernance(config, assignment) {
|
|
385
|
-
const normalizedAssignment = assignment ? normalizeAssignmentDefinition(assignment) : null;
|
|
386
|
-
if (normalizedAssignment?.enabled !== true) return {
|
|
387
|
-
isGoverned: false,
|
|
388
|
-
factLinkingEnabled: false,
|
|
389
|
-
transparencyEnabled: false,
|
|
390
|
-
publicationProfileKey: null,
|
|
391
|
-
correctionProfileKey: null,
|
|
392
|
-
enforcePublishReadiness: false,
|
|
393
|
-
defaultFactRelationship: DEFAULT_FACT_RELATIONSHIP,
|
|
394
|
-
reviewPolicies: config.policies.map(clonePolicyDefinition).filter((policy) => policy.enabled !== false),
|
|
395
|
-
availableProfiles: config.profiles.map(cloneProfileDefinition).filter((profile) => profile.enabled !== false),
|
|
396
|
-
assignment: normalizedAssignment
|
|
397
|
-
};
|
|
398
|
-
return {
|
|
399
|
-
isGoverned: true,
|
|
400
|
-
factLinkingEnabled: normalizedAssignment.factLinkingEnabled === true,
|
|
401
|
-
transparencyEnabled: normalizedAssignment.transparencyEnabled === true,
|
|
402
|
-
publicationProfileKey: normalizedAssignment.publicationProfileKey || null,
|
|
403
|
-
correctionProfileKey: normalizedAssignment.correctionProfileKey || null,
|
|
404
|
-
enforcePublishReadiness: normalizedAssignment.enforcePublishReadiness === true,
|
|
405
|
-
defaultFactRelationship: normalizedAssignment.defaultFactRelationship || DEFAULT_FACT_RELATIONSHIP,
|
|
406
|
-
reviewPolicies: config.policies.map(clonePolicyDefinition).filter((policy) => policy.enabled !== false),
|
|
407
|
-
availableProfiles: config.profiles.map(cloneProfileDefinition).filter((profile) => profile.enabled !== false),
|
|
408
|
-
assignment: normalizedAssignment
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
function normalizeStatus(status) {
|
|
412
|
-
switch (status) {
|
|
413
|
-
case "pending":
|
|
414
|
-
case "passed":
|
|
415
|
-
case "flagged":
|
|
416
|
-
case "failed":
|
|
417
|
-
case "waived": return status;
|
|
418
|
-
default: return "flagged";
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
function normalizeSeverity(severity) {
|
|
422
|
-
switch (severity) {
|
|
423
|
-
case "info":
|
|
424
|
-
case "warning":
|
|
425
|
-
case "error": return severity;
|
|
426
|
-
default: return "warning";
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
function extractJSONObject(raw) {
|
|
430
|
-
const start = raw.indexOf("{");
|
|
431
|
-
const end = raw.lastIndexOf("}");
|
|
432
|
-
if (start === -1 || end === -1 || end <= start) return null;
|
|
433
|
-
return raw.slice(start, end + 1);
|
|
434
|
-
}
|
|
435
|
-
function getContentGovernanceConfig() {
|
|
436
|
-
return cloneGovernanceConfig(governanceConfig);
|
|
437
|
-
}
|
|
438
|
-
function configureContentGovernance(config) {
|
|
439
|
-
governanceConfig = {
|
|
440
|
-
policies: config.policies ? mergeByKey(governanceConfig.policies, config.policies, normalizePolicyDefinition) : governanceConfig.policies.map(clonePolicyDefinition),
|
|
441
|
-
profiles: config.profiles ? mergeByKey(governanceConfig.profiles, config.profiles, normalizeProfileDefinition) : governanceConfig.profiles.map(cloneProfileDefinition),
|
|
442
|
-
assignments: config.assignments ? mergeByKey(governanceConfig.assignments, config.assignments, normalizeAssignmentDefinition) : governanceConfig.assignments.map(cloneAssignmentDefinition)
|
|
443
|
-
};
|
|
444
|
-
return getContentGovernanceConfig();
|
|
445
|
-
}
|
|
446
|
-
function resetContentGovernanceConfig() {
|
|
447
|
-
governanceConfig = cloneGovernanceConfig(DEFAULT_CONTENT_GOVERNANCE_CONFIG);
|
|
448
|
-
return getContentGovernanceConfig();
|
|
449
|
-
}
|
|
450
|
-
async function getEffectiveContentGovernanceConfig(options = {}) {
|
|
451
|
-
const persisted = await loadPersistedContentGovernanceDefinitions({
|
|
452
|
-
db: options.db,
|
|
453
|
-
tenantId: options.tenantId
|
|
454
|
-
});
|
|
455
|
-
return {
|
|
456
|
-
policies: mergeByKey(governanceConfig.policies, persisted.policies, normalizePolicyDefinition),
|
|
457
|
-
profiles: mergeByKey(governanceConfig.profiles, persisted.profiles, normalizeProfileDefinition),
|
|
458
|
-
assignments: mergeByKey(governanceConfig.assignments, persisted.assignments, normalizeAssignmentDefinition)
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
function hasStaticContentGovernancePolicy(key) {
|
|
462
|
-
return getPolicyMap(governanceConfig.policies).has(key);
|
|
463
|
-
}
|
|
464
|
-
function hasStaticContentGovernanceProfile(key) {
|
|
465
|
-
return getProfileMap(governanceConfig.profiles).has(key);
|
|
466
|
-
}
|
|
467
|
-
function getContentReviewPolicy(policyKey, policies = governanceConfig.policies) {
|
|
468
|
-
return getPolicyMap(policies).get(policyKey) || null;
|
|
469
|
-
}
|
|
470
|
-
function getContentReviewKind(policyKey, policies = governanceConfig.policies) {
|
|
471
|
-
return getPolicyMap(policies).get(policyKey)?.kind || getFallbackPolicyKind(policyKey);
|
|
472
|
-
}
|
|
473
|
-
function getContentReviewProfile(profileKey, profiles = governanceConfig.profiles) {
|
|
474
|
-
return getProfileMap(profiles).get(profileKey) || null;
|
|
475
|
-
}
|
|
476
|
-
function getContentReviewProfileKeys(profiles = governanceConfig.profiles) {
|
|
477
|
-
return profiles.map(cloneProfileDefinition).filter((profile) => profile.enabled !== false).map((profile) => profile.key);
|
|
478
|
-
}
|
|
479
|
-
function getContentReviewPolicies(policies = governanceConfig.policies) {
|
|
480
|
-
return policies.map(clonePolicyDefinition).filter((policy) => policy.enabled !== false);
|
|
481
|
-
}
|
|
482
|
-
function getContentReviewRequirements(profileKey, profiles = governanceConfig.profiles) {
|
|
483
|
-
return getContentReviewProfile(profileKey, profiles)?.requirements.map(cloneReviewRequirement) || [];
|
|
484
|
-
}
|
|
485
|
-
function getAcceptedContentReviewStatuses(requirement) {
|
|
486
|
-
return requirement.acceptedStatuses && requirement.acceptedStatuses.length > 0 ? [...requirement.acceptedStatuses] : ["passed", "waived"];
|
|
487
|
-
}
|
|
488
|
-
function resolveConfiguredContentGovernance(options) {
|
|
489
|
-
const assignment = resolveAssignmentDefinition(governanceConfig.assignments, {
|
|
490
|
-
contentType: options.contentType,
|
|
491
|
-
contentVariant: options.contentVariant
|
|
492
|
-
});
|
|
493
|
-
return buildResolvedGovernance(governanceConfig, assignment);
|
|
494
|
-
}
|
|
495
|
-
async function resolveEffectiveContentGovernance(options) {
|
|
496
|
-
const effectiveConfig = await getEffectiveContentGovernanceConfig({
|
|
497
|
-
db: options.db,
|
|
498
|
-
tenantId: options.tenantId
|
|
499
|
-
});
|
|
500
|
-
return buildResolvedGovernance(effectiveConfig, resolveAssignmentDefinition(effectiveConfig.assignments, {
|
|
501
|
-
contentType: options.contentType,
|
|
502
|
-
contentVariant: options.contentVariant
|
|
503
|
-
}));
|
|
504
|
-
}
|
|
505
|
-
function buildContentReviewPrompt(options) {
|
|
506
|
-
const { kind, content, facts = [], policy, customInstructions } = options;
|
|
507
|
-
const factLines = facts.length > 0 ? facts.map((fact) => `- [${fact.id}] status=${fact.status}; confidence=${fact.confidence}; sources=${fact.sourceCount}; text=${fact.textRefined}`).join("\n") : "No facts were supplied for this review.";
|
|
508
|
-
const policyText = customInstructions?.trim() || policy?.instructions || getContentReviewPolicy(kind)?.instructions || "";
|
|
509
|
-
return `You are a structured editorial reviewer.
|
|
510
|
-
|
|
511
|
-
Return ONLY valid JSON with this shape:
|
|
512
|
-
{
|
|
513
|
-
"status": "passed" | "flagged" | "failed" | "waived",
|
|
514
|
-
"summary": "short summary",
|
|
515
|
-
"findings": [
|
|
516
|
-
{
|
|
517
|
-
"severity": "info" | "warning" | "error",
|
|
518
|
-
"title": "short title",
|
|
519
|
-
"detail": "what is wrong and why",
|
|
520
|
-
"factId": "optional fact id",
|
|
521
|
-
"quote": "optional quoted text from the draft",
|
|
522
|
-
"suggestedChange": "optional suggested fix",
|
|
523
|
-
"ruleId": "optional policy or rule id"
|
|
524
|
-
}
|
|
525
|
-
]
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
Review kind: ${kind}
|
|
529
|
-
Policy key: ${policy?.key || kind}
|
|
530
|
-
Review instructions:
|
|
531
|
-
${policyText}
|
|
532
|
-
|
|
533
|
-
Draft content:
|
|
534
|
-
- id: ${content.id ?? ""}
|
|
535
|
-
- type: ${content.type ?? ""}
|
|
536
|
-
- status: ${content.status}
|
|
537
|
-
- state: ${content.state}
|
|
538
|
-
- author: ${content.author ?? ""}
|
|
539
|
-
- publish_date: ${content.publish_date?.toISOString?.() ?? ""}
|
|
540
|
-
|
|
541
|
-
Title:
|
|
542
|
-
${content.title}
|
|
543
|
-
|
|
544
|
-
Description:
|
|
545
|
-
${content.description ?? ""}
|
|
546
|
-
|
|
547
|
-
Body:
|
|
548
|
-
${content.body}
|
|
549
|
-
|
|
550
|
-
Relevant facts:
|
|
551
|
-
${factLines}`;
|
|
552
|
-
}
|
|
553
|
-
function parseContentReviewResponse(raw) {
|
|
554
|
-
const normalizedRaw = raw.trim();
|
|
555
|
-
const jsonCandidate = extractJSONObject(normalizedRaw);
|
|
556
|
-
if (jsonCandidate) try {
|
|
557
|
-
const parsed = JSON.parse(jsonCandidate);
|
|
558
|
-
const findings = Array.isArray(parsed.findings) ? parsed.findings.map((rawFinding) => {
|
|
559
|
-
const finding = rawFinding && typeof rawFinding === "object" ? rawFinding : {};
|
|
560
|
-
return {
|
|
561
|
-
severity: normalizeSeverity(finding.severity),
|
|
562
|
-
title: String(finding.title || "Review finding"),
|
|
563
|
-
detail: String(finding.detail || ""),
|
|
564
|
-
factId: typeof finding.factId === "string" ? finding.factId : void 0,
|
|
565
|
-
quote: typeof finding.quote === "string" ? finding.quote : void 0,
|
|
566
|
-
suggestedChange: typeof finding.suggestedChange === "string" ? finding.suggestedChange : void 0,
|
|
567
|
-
ruleId: typeof finding.ruleId === "string" ? finding.ruleId : void 0
|
|
568
|
-
};
|
|
569
|
-
}) : [];
|
|
570
|
-
return {
|
|
571
|
-
status: normalizeStatus(parsed.status),
|
|
572
|
-
summary: String(parsed.summary || normalizedRaw || "Review completed"),
|
|
573
|
-
findings
|
|
574
|
-
};
|
|
575
|
-
} catch {}
|
|
576
|
-
return {
|
|
577
|
-
status: "flagged",
|
|
578
|
-
summary: normalizedRaw || "Review completed without structured output.",
|
|
579
|
-
findings: normalizedRaw ? [{
|
|
580
|
-
severity: "warning",
|
|
581
|
-
title: "Unstructured review output",
|
|
582
|
-
detail: normalizedRaw
|
|
583
|
-
}] : []
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
//#endregion
|
|
587
|
-
//#region src/content-prompts.ts
|
|
588
|
-
var smrtContentReviewPrompt = definePrompt({
|
|
589
|
-
key: "smrtContent.review",
|
|
590
|
-
template: `Content review request
|
|
591
|
-
|
|
592
|
-
Content ID: {contentId}
|
|
593
|
-
Review kind: {kind}
|
|
594
|
-
Policy key: {policyKey}
|
|
595
|
-
Title: {contentTitle}
|
|
596
|
-
Description: {contentDescription}
|
|
597
|
-
|
|
598
|
-
Body:
|
|
599
|
-
{contentBody}
|
|
600
|
-
|
|
601
|
-
{reviewPrompt}`,
|
|
602
|
-
editable: {
|
|
603
|
-
template: true,
|
|
604
|
-
profile: true,
|
|
605
|
-
model: true,
|
|
606
|
-
params: true
|
|
607
|
-
}
|
|
608
|
-
});
|
|
609
|
-
var smrtContentApplyCorrectionPrompt = definePrompt({
|
|
610
|
-
key: "smrtContent.applyCorrection",
|
|
611
|
-
template: `You are revising an article draft to apply a factual correction.
|
|
612
|
-
|
|
613
|
-
Return only the fully revised body text, with no commentary.
|
|
614
|
-
|
|
615
|
-
Current body:
|
|
616
|
-
{body}
|
|
617
|
-
|
|
618
|
-
Correction summary:
|
|
619
|
-
{summary}
|
|
620
|
-
|
|
621
|
-
Incorrect text to fix:
|
|
622
|
-
{incorrectText}
|
|
623
|
-
|
|
624
|
-
Corrected text to incorporate:
|
|
625
|
-
{correctedText}`,
|
|
626
|
-
editable: {
|
|
627
|
-
template: true,
|
|
628
|
-
profile: true,
|
|
629
|
-
model: true,
|
|
630
|
-
params: true
|
|
631
|
-
}
|
|
632
|
-
});
|
|
633
|
-
var smrtContentThumbnailAIGeneratePrompt = definePrompt({
|
|
634
|
-
key: "smrtContent.thumbnail.aiGenerate",
|
|
635
|
-
template: `Create a {style} thumbnail image for an article titled "{title}". {descriptionClause}Style: {styleHint}. The image should be suitable for a news article or blog post thumbnail.`,
|
|
636
|
-
editable: {
|
|
637
|
-
template: true,
|
|
638
|
-
profile: true,
|
|
639
|
-
model: true,
|
|
640
|
-
params: true
|
|
641
|
-
}
|
|
642
|
-
});
|
|
643
|
-
function promptMessageOptions(ai) {
|
|
644
|
-
return {
|
|
645
|
-
...ai.params || {},
|
|
646
|
-
...ai.model ? { model: ai.model } : {},
|
|
647
|
-
...typeof ai.temperature === "number" ? { temperature: ai.temperature } : {},
|
|
648
|
-
...typeof ai.maxTokens === "number" ? { maxTokens: ai.maxTokens } : {}
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
//#endregion
|
|
652
|
-
//#region src/content-reference.ts
|
|
653
|
-
var __defProp$2 = Object.defineProperty;
|
|
654
|
-
var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
|
|
655
|
-
var __decorateClass$2 = (decorators, target, key, kind) => {
|
|
656
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
|
|
657
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
658
|
-
if (kind && result) __defProp$2(target, key, result);
|
|
659
|
-
return result;
|
|
660
|
-
};
|
|
661
|
-
var ContentReference = class extends SmrtObject {
|
|
662
|
-
tenantId = null;
|
|
663
|
-
sourceId = "";
|
|
664
|
-
targetId = "";
|
|
665
|
-
targetVersion = null;
|
|
666
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
667
|
-
constructor(options = {}) {
|
|
668
|
-
super(options);
|
|
669
|
-
if (options.sourceId) this.sourceId = options.sourceId;
|
|
670
|
-
if (options.targetId) this.targetId = options.targetId;
|
|
671
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
672
|
-
if (options.targetVersion !== void 0) this.targetVersion = options.targetVersion;
|
|
673
|
-
if (options.createdAt) this.createdAt = options.createdAt;
|
|
674
|
-
}
|
|
675
|
-
};
|
|
676
|
-
__decorateClass$2([tenantId({ nullable: true })], ContentReference.prototype, "tenantId", 2);
|
|
677
|
-
__decorateClass$2([foreignKey("Content", { required: true })], ContentReference.prototype, "sourceId", 2);
|
|
678
|
-
__decorateClass$2([foreignKey("Content", { required: true })], ContentReference.prototype, "targetId", 2);
|
|
679
|
-
__decorateClass$2([field({
|
|
680
|
-
type: "integer",
|
|
681
|
-
nullable: true
|
|
682
|
-
})], ContentReference.prototype, "targetVersion", 2);
|
|
683
|
-
__decorateClass$2([field()], ContentReference.prototype, "createdAt", 2);
|
|
684
|
-
ContentReference = __decorateClass$2([TenantScoped({ mode: "optional" }), smrt({
|
|
685
|
-
tableName: "content_references",
|
|
686
|
-
conflictColumns: ["source_id", "target_id"]
|
|
687
|
-
})], ContentReference);
|
|
688
|
-
//#endregion
|
|
689
|
-
//#region src/content-references.ts
|
|
690
|
-
var __defProp$1 = Object.defineProperty;
|
|
691
|
-
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
692
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp$1(obj, key, {
|
|
693
|
-
enumerable: true,
|
|
694
|
-
configurable: true,
|
|
695
|
-
writable: true,
|
|
696
|
-
value
|
|
697
|
-
}) : obj[key] = value;
|
|
698
|
-
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
699
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
|
|
700
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
701
|
-
if (kind && result) __defProp$1(target, key, result);
|
|
702
|
-
return result;
|
|
703
|
-
};
|
|
704
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
705
|
-
var ContentReferences = class extends SmrtJunction {
|
|
706
|
-
leftField = "sourceId";
|
|
707
|
-
rightField = "targetId";
|
|
708
|
-
sortField = "createdAt";
|
|
709
|
-
positionField = null;
|
|
710
|
-
async getForSource(sourceId) {
|
|
711
|
-
return await this.list({
|
|
712
|
-
where: { sourceId },
|
|
713
|
-
orderBy: "created_at ASC"
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
async getForTarget(targetId) {
|
|
717
|
-
return await this.list({
|
|
718
|
-
where: { targetId },
|
|
719
|
-
orderBy: "created_at ASC"
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
/**
|
|
723
|
-
* Find-or-create idempotency: if a reference already exists for
|
|
724
|
-
* (sourceId, targetId), return the existing row unchanged instead of
|
|
725
|
-
* upserting a new row. This preserves the existing row's `id` and
|
|
726
|
-
* `createdAt`, which is important because reference rows are
|
|
727
|
-
* externally addressable via `/api/v1/contentreferences/[id]`.
|
|
728
|
-
*
|
|
729
|
-
* The base `SmrtJunction.attach` flow (this.create → db.upsert) would
|
|
730
|
-
* overwrite both columns on every duplicate call.
|
|
731
|
-
*
|
|
732
|
-
* Reference pinning (main): `opts.targetVersion` pins the citation to a
|
|
733
|
-
* specific `ContentVersion.version` for drift detection. Re-attaching an
|
|
734
|
-
* existing edge with a different `targetVersion` updates the pin in place;
|
|
735
|
-
* `undefined` leaves an existing pin untouched, while a brand-new row
|
|
736
|
-
* defaults the pin to `null` (unpinned).
|
|
737
|
-
*/
|
|
738
|
-
async attach(sourceId, targetId, opts = {}) {
|
|
739
|
-
const targetVersion = opts.targetVersion;
|
|
740
|
-
const existing = await this.get({
|
|
741
|
-
sourceId,
|
|
742
|
-
targetId
|
|
743
|
-
});
|
|
744
|
-
if (existing) {
|
|
745
|
-
if (targetVersion !== void 0 && existing.targetVersion !== targetVersion) {
|
|
746
|
-
existing.targetVersion = targetVersion;
|
|
747
|
-
await existing.save();
|
|
748
|
-
}
|
|
749
|
-
return existing;
|
|
750
|
-
}
|
|
751
|
-
return super.attach(sourceId, targetId, {
|
|
752
|
-
...opts,
|
|
753
|
-
targetVersion: targetVersion ?? null
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
async unlink(sourceId, targetId) {
|
|
757
|
-
await this.detach(sourceId, targetId);
|
|
758
|
-
}
|
|
759
|
-
};
|
|
760
|
-
__publicField(ContentReferences, "_itemClass", ContentReference);
|
|
761
|
-
ContentReferences = __decorateClass$1([smrt()], ContentReferences);
|
|
762
|
-
//#endregion
|
|
763
|
-
//#region src/content-transparency.ts
|
|
764
|
-
function asObject(value, fallback = {}) {
|
|
765
|
-
return value && typeof value === "object" ? { ...value } : fallback;
|
|
766
|
-
}
|
|
767
|
-
function asString(value) {
|
|
768
|
-
return typeof value === "string" && value.length > 0 ? value : null;
|
|
769
|
-
}
|
|
770
|
-
function asNumber(value) {
|
|
771
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
772
|
-
}
|
|
773
|
-
function asArray(value) {
|
|
774
|
-
return Array.isArray(value) ? value : [];
|
|
775
|
-
}
|
|
776
|
-
function normalizeGeneration(value) {
|
|
777
|
-
const generation = asObject(value);
|
|
778
|
-
return {
|
|
779
|
-
aiAssisted: Boolean(generation.aiAssisted),
|
|
780
|
-
publicPrompt: asString(generation.publicPrompt),
|
|
781
|
-
model: asString(generation.model)
|
|
782
|
-
};
|
|
783
|
-
}
|
|
784
|
-
function normalizeFact(value) {
|
|
785
|
-
const fact = asObject(value);
|
|
786
|
-
return {
|
|
787
|
-
...fact,
|
|
788
|
-
id: asString(fact.id),
|
|
789
|
-
relationship: asString(fact.relationship),
|
|
790
|
-
linkMetadata: asObject(fact.linkMetadata),
|
|
791
|
-
usedInArticle: Boolean(fact.usedInArticle),
|
|
792
|
-
sources: asArray(fact.sources).map(normalizeSource)
|
|
793
|
-
};
|
|
794
|
-
}
|
|
795
|
-
function normalizeSource(value) {
|
|
796
|
-
const source = asObject(value);
|
|
797
|
-
return {
|
|
798
|
-
id: asString(source.id),
|
|
799
|
-
sourceType: asString(source.sourceType),
|
|
800
|
-
sourceUrl: asString(source.sourceUrl),
|
|
801
|
-
sourceTitle: asString(source.sourceTitle),
|
|
802
|
-
credibility: asNumber(source.credibility),
|
|
803
|
-
extractedAt: asString(source.extractedAt),
|
|
804
|
-
metadata: asObject(source.metadata)
|
|
805
|
-
};
|
|
806
|
-
}
|
|
807
|
-
function normalizeReference(value) {
|
|
808
|
-
const reference = asObject(value);
|
|
809
|
-
return {
|
|
810
|
-
id: asString(reference.id),
|
|
811
|
-
title: asString(reference.title),
|
|
812
|
-
url: asString(reference.url),
|
|
813
|
-
originalUrl: asString(reference.originalUrl),
|
|
814
|
-
type: asString(reference.type),
|
|
815
|
-
source: asString(reference.source),
|
|
816
|
-
usedFactIds: asArray(reference.usedFactIds).filter(Boolean),
|
|
817
|
-
extractedFacts: asArray(reference.extractedFacts).map(normalizeFact)
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
function normalizePublicationVersion(value) {
|
|
821
|
-
const publicationVersion = asObject(value);
|
|
822
|
-
if (!publicationVersion.id && publicationVersion.version === void 0) return null;
|
|
823
|
-
return {
|
|
824
|
-
id: asString(publicationVersion.id),
|
|
825
|
-
version: asNumber(publicationVersion.version),
|
|
826
|
-
kind: asString(publicationVersion.kind),
|
|
827
|
-
summary: typeof publicationVersion.summary === "string" ? publicationVersion.summary : "",
|
|
828
|
-
createdAt: asString(publicationVersion.createdAt)
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
function normalizeVersionHistoryItem(value) {
|
|
832
|
-
const version = asObject(value);
|
|
833
|
-
return {
|
|
834
|
-
id: asString(version.id),
|
|
835
|
-
version: asNumber(version.version),
|
|
836
|
-
kind: asString(version.kind),
|
|
837
|
-
summary: typeof version.summary === "string" ? version.summary : "",
|
|
838
|
-
createdAt: asString(version.createdAt),
|
|
839
|
-
provenance: asObject(version.provenance)
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
function dedupeFacts(facts) {
|
|
843
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
844
|
-
for (const fact of facts) {
|
|
845
|
-
const key = fact.id || fact.textRefined || fact.textRaw || JSON.stringify(fact.metadata || {});
|
|
846
|
-
if (!key) continue;
|
|
847
|
-
byKey.set(key, fact);
|
|
848
|
-
}
|
|
849
|
-
return [...byKey.values()];
|
|
850
|
-
}
|
|
851
|
-
function normalizeContentTransparency(value, defaults = {}) {
|
|
852
|
-
const snapshot = asObject(value);
|
|
853
|
-
const references = asArray(snapshot.references).map(normalizeReference);
|
|
854
|
-
const linkedFacts = asArray(snapshot.linkedFacts).map(normalizeFact);
|
|
855
|
-
const factsUsed = asArray(snapshot.factsUsed).length > 0 ? asArray(snapshot.factsUsed).map(normalizeFact) : linkedFacts.filter((fact) => fact.usedInArticle);
|
|
856
|
-
const otherExtractedFacts = asArray(snapshot.otherExtractedFacts).length > 0 ? asArray(snapshot.otherExtractedFacts).map(normalizeFact) : dedupeFacts(references.flatMap((reference) => reference.extractedFacts.filter((fact) => !fact.usedInArticle)));
|
|
857
|
-
return {
|
|
858
|
-
generatedAt: asString(snapshot.generatedAt) ?? defaults.generatedAt ?? null,
|
|
859
|
-
snapshotKind: snapshot.snapshotKind === "published" ? "published" : defaults.snapshotKind || "preview",
|
|
860
|
-
contentId: asString(snapshot.contentId) ?? defaults.contentId ?? null,
|
|
861
|
-
currentContentStatus: asString(snapshot.currentContentStatus) ?? defaults.currentContentStatus ?? null,
|
|
862
|
-
publicationProfileKey: asString(snapshot.publicationProfileKey) ?? asString(snapshot.publicationReviewProfileKey) ?? defaults.publicationProfileKey ?? "publication",
|
|
863
|
-
publicationVersion: normalizePublicationVersion(snapshot.publicationVersion) ?? defaults.publicationVersion ?? null,
|
|
864
|
-
generation: normalizeGeneration(snapshot.generation ?? defaults.generation ?? {}),
|
|
865
|
-
factsUsed,
|
|
866
|
-
linkedFacts,
|
|
867
|
-
otherExtractedFacts,
|
|
868
|
-
references,
|
|
869
|
-
reviews: asArray(snapshot.reviews),
|
|
870
|
-
reviewProfiles: asArray(snapshot.reviewProfiles),
|
|
871
|
-
corrections: asArray(snapshot.corrections),
|
|
872
|
-
versionHistory: asArray(snapshot.versionHistory).map(normalizeVersionHistoryItem)
|
|
873
|
-
};
|
|
874
|
-
}
|
|
875
|
-
//#endregion
|
|
876
|
-
//#region src/database-utils.ts
|
|
877
|
-
function isMissingTableError(error, tableName) {
|
|
878
|
-
const message = String(error?.message || error || "").toLowerCase();
|
|
879
|
-
return message.includes(tableName.toLowerCase()) && (message.includes("no such table") || message.includes("does not exist") || message.includes("relation"));
|
|
880
|
-
}
|
|
881
|
-
function getQueryRows(result) {
|
|
882
|
-
return Array.isArray(result) ? result : Array.isArray(result?.rows) ? result.rows ?? [] : [];
|
|
883
|
-
}
|
|
884
|
-
//#endregion
|
|
885
|
-
//#region src/serialization.ts
|
|
886
|
-
function asModel(value) {
|
|
887
|
-
return value && typeof value === "object" ? value : {};
|
|
888
|
-
}
|
|
889
|
-
function toJSON(value) {
|
|
890
|
-
const model = asModel(value);
|
|
891
|
-
if (typeof model.toJSON === "function") {
|
|
892
|
-
const serialized = model.toJSON();
|
|
893
|
-
return serialized && typeof serialized === "object" ? serialized : {};
|
|
894
|
-
}
|
|
895
|
-
return value && typeof value === "object" ? value : {};
|
|
896
|
-
}
|
|
897
|
-
function serializeFact(fact) {
|
|
898
|
-
const model = asModel(fact);
|
|
899
|
-
const data = toJSON(fact);
|
|
900
|
-
return {
|
|
901
|
-
...data,
|
|
902
|
-
metadata: typeof model.getMetadata === "function" ? model.getMetadata() : data.metadata || {}
|
|
903
|
-
};
|
|
904
|
-
}
|
|
905
|
-
function serializeFactLink(link) {
|
|
906
|
-
const model = asModel(link);
|
|
907
|
-
const data = toJSON(link);
|
|
908
|
-
return {
|
|
909
|
-
...data,
|
|
910
|
-
metadata: typeof model.getMetadata === "function" ? model.getMetadata() : data.metadata || {}
|
|
911
|
-
};
|
|
912
|
-
}
|
|
913
|
-
function serializeContentVersion(version) {
|
|
914
|
-
const model = asModel(version);
|
|
915
|
-
const data = toJSON(version);
|
|
916
|
-
return {
|
|
917
|
-
...data,
|
|
918
|
-
snapshot: typeof model.getSnapshot === "function" ? model.getSnapshot() : data.snapshot || {},
|
|
919
|
-
metadata: typeof model.getMetadata === "function" ? model.getMetadata() : data.metadata || {}
|
|
920
|
-
};
|
|
921
|
-
}
|
|
922
|
-
function serializeContentReview(review) {
|
|
923
|
-
const model = asModel(review);
|
|
924
|
-
const data = toJSON(review);
|
|
925
|
-
return {
|
|
926
|
-
...data,
|
|
927
|
-
findings: typeof model.getFindings === "function" ? model.getFindings() : data.findings || [],
|
|
928
|
-
metadata: typeof model.getMetadata === "function" ? model.getMetadata() : data.metadata || {}
|
|
929
|
-
};
|
|
930
|
-
}
|
|
931
|
-
function serializeContentCorrection(correction) {
|
|
932
|
-
const model = asModel(correction);
|
|
933
|
-
const data = toJSON(correction);
|
|
934
|
-
return {
|
|
935
|
-
...data,
|
|
936
|
-
metadata: typeof model.getMetadata === "function" ? model.getMetadata() : data.metadata || {}
|
|
937
|
-
};
|
|
938
|
-
}
|
|
939
|
-
async function serializeContent(content) {
|
|
940
|
-
const model = asModel(content);
|
|
941
|
-
const [references, assets] = await Promise.all([typeof model.getReferences === "function" ? model.getReferences() : [], typeof model.getAssets === "function" ? model.getAssets() : []]);
|
|
942
|
-
const drift = references.length > 0 && typeof model.getReferenceDrift === "function" ? await model.getReferenceDrift() : [];
|
|
943
|
-
const driftByTargetId = new Map(Array.isArray(drift) ? drift.map((entry) => asModel(entry)).filter((entry) => typeof entry.targetId === "string").map((entry) => {
|
|
944
|
-
const edge = entry;
|
|
945
|
-
return [edge.targetId, {
|
|
946
|
-
citedVersion: edge.citedVersion ?? null,
|
|
947
|
-
currentVersion: edge.currentVersion ?? null,
|
|
948
|
-
isDrifted: Boolean(edge.isDrifted)
|
|
949
|
-
}];
|
|
950
|
-
}) : []);
|
|
951
|
-
return {
|
|
952
|
-
...toJSON(content),
|
|
953
|
-
referenceIds: references.map((reference) => asModel(reference)).map((reference) => reference.id).filter(Boolean),
|
|
954
|
-
references: references.map((reference) => {
|
|
955
|
-
const base = toJSON(reference);
|
|
956
|
-
const edge = typeof base.id === "string" ? driftByTargetId.get(base.id) : null;
|
|
957
|
-
return edge ? {
|
|
958
|
-
...base,
|
|
959
|
-
citedVersion: edge.citedVersion,
|
|
960
|
-
currentVersion: edge.currentVersion,
|
|
961
|
-
isDrifted: edge.isDrifted
|
|
962
|
-
} : base;
|
|
963
|
-
}),
|
|
964
|
-
assetIds: assets.map((asset) => asModel(asset).id).filter(Boolean),
|
|
965
|
-
assets: assets.map((asset) => toJSON(asset))
|
|
966
|
-
};
|
|
967
|
-
}
|
|
968
|
-
//#endregion
|
|
969
|
-
//#region src/thumbnail-generator.ts
|
|
970
|
-
function isImageGenerationClient(value) {
|
|
971
|
-
return !!value && typeof value === "object" && typeof value.generateImage === "function";
|
|
972
|
-
}
|
|
973
|
-
function isAIClientOptions(value) {
|
|
974
|
-
return !!value && typeof value === "object" && !isImageGenerationClient(value);
|
|
975
|
-
}
|
|
976
|
-
var ThumbnailGenerator = class {
|
|
977
|
-
constructor(content, options = {}) {
|
|
978
|
-
this.content = content;
|
|
979
|
-
this.options = options;
|
|
980
|
-
if (!this.options.db && this.options.persistence) this.options.db = this.options.persistence;
|
|
981
|
-
}
|
|
982
|
-
content;
|
|
983
|
-
options;
|
|
984
|
-
/**
|
|
985
|
-
* Generate a thumbnail using the specified strategy
|
|
986
|
-
*/
|
|
987
|
-
async generate(options) {
|
|
988
|
-
switch (options.strategy) {
|
|
989
|
-
case "headline-card": return this.generateHeadlineCard(options);
|
|
990
|
-
case "static-map": return this.generateStaticMap(options);
|
|
991
|
-
case "ai-generate": return this.generateWithAI(options);
|
|
992
|
-
default: throw new Error(`Unknown thumbnail strategy: ${options.strategy}`);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
/**
|
|
996
|
-
* Generate a headline card thumbnail
|
|
997
|
-
*/
|
|
998
|
-
async generateHeadlineCard(options) {
|
|
999
|
-
const result = await generateHeadlineCard(this.content.title || this.content.name || "Untitled", {
|
|
1000
|
-
width: options.width ?? 1200,
|
|
1001
|
-
height: options.height ?? 630,
|
|
1002
|
-
brandColor: options.brandColor,
|
|
1003
|
-
backgroundColor: options.backgroundColor,
|
|
1004
|
-
subtitle: options.subtitle ?? this.content.category ?? void 0,
|
|
1005
|
-
logoUrl: options.logoUrl,
|
|
1006
|
-
template: options.template
|
|
1007
|
-
});
|
|
1008
|
-
return this.createImageFromBuffer(result.buffer, {
|
|
1009
|
-
width: result.width,
|
|
1010
|
-
height: result.height,
|
|
1011
|
-
mimeType: result.mimeType,
|
|
1012
|
-
name: `${this.content.id}-headline.png`
|
|
1013
|
-
});
|
|
1014
|
-
}
|
|
1015
|
-
/**
|
|
1016
|
-
* Generate a static map thumbnail
|
|
1017
|
-
*/
|
|
1018
|
-
async generateStaticMap(options) {
|
|
1019
|
-
const coordinateMetadata = this.content.metadata;
|
|
1020
|
-
const rawLatitude = coordinateMetadata?.latitude ?? coordinateMetadata?.lat;
|
|
1021
|
-
const rawLongitude = coordinateMetadata?.longitude ?? coordinateMetadata?.lng ?? coordinateMetadata?.lon;
|
|
1022
|
-
if (rawLatitude == null || rawLongitude == null) throw new Error("Content metadata must contain latitude and longitude for static-map strategy");
|
|
1023
|
-
const latitude = typeof rawLatitude === "string" ? +rawLatitude : rawLatitude;
|
|
1024
|
-
const longitude = typeof rawLongitude === "string" ? +rawLongitude : rawLongitude;
|
|
1025
|
-
if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90) throw new Error(`Invalid latitude value "${rawLatitude}" in content metadata; expected a number between -90 and 90.`);
|
|
1026
|
-
if (!Number.isFinite(longitude) || longitude < -180 || longitude > 180) throw new Error(`Invalid longitude value "${rawLongitude}" in content metadata; expected a number between -180 and 180.`);
|
|
1027
|
-
const mapboxStyle = options.mapboxStyle;
|
|
1028
|
-
const result = await fetchStaticMap(latitude, longitude, {
|
|
1029
|
-
provider: options.mapProvider ?? "mapbox",
|
|
1030
|
-
width: options.width ?? 1200,
|
|
1031
|
-
height: options.height ?? 630,
|
|
1032
|
-
zoom: options.zoom ?? 14,
|
|
1033
|
-
markerColor: options.markerColor,
|
|
1034
|
-
mapboxStyle,
|
|
1035
|
-
googleMapType: options.googleMapType
|
|
1036
|
-
});
|
|
1037
|
-
return this.createImageFromBuffer(result.buffer, {
|
|
1038
|
-
width: result.width,
|
|
1039
|
-
height: result.height,
|
|
1040
|
-
mimeType: result.mimeType,
|
|
1041
|
-
name: `${this.content.id}-map.png`
|
|
1042
|
-
});
|
|
1043
|
-
}
|
|
1044
|
-
/**
|
|
1045
|
-
* Generate a thumbnail using AI image generation
|
|
1046
|
-
*/
|
|
1047
|
-
async generateWithAI(options) {
|
|
1048
|
-
const { getAI } = await import("@happyvertical/ai");
|
|
1049
|
-
const aiInput = options.ai ?? this.options.ai;
|
|
1050
|
-
if (!aiInput) throw new Error("AI configuration required for ai-generate strategy. Provide via options.ai or constructor options.");
|
|
1051
|
-
const ai = isImageGenerationClient(aiInput) ? aiInput : isAIClientOptions(aiInput) ? await getAI(aiInput) : (() => {
|
|
1052
|
-
throw new Error("AI client does not support image generation for ai-generate thumbnails.");
|
|
1053
|
-
})();
|
|
1054
|
-
const width = options.width ?? 1200;
|
|
1055
|
-
const height = options.height ?? 630;
|
|
1056
|
-
let prompt;
|
|
1057
|
-
let aiOverrideOptions = {};
|
|
1058
|
-
if (options.prompt) prompt = options.prompt;
|
|
1059
|
-
else {
|
|
1060
|
-
const built = await this.buildAIPrompt(options.style ?? "photorealistic");
|
|
1061
|
-
prompt = built.text;
|
|
1062
|
-
aiOverrideOptions = promptMessageOptions(built.ai);
|
|
1063
|
-
}
|
|
1064
|
-
const result = await ai.generateImage(prompt, {
|
|
1065
|
-
...aiOverrideOptions,
|
|
1066
|
-
size: `${width}x${height}`,
|
|
1067
|
-
outputFormat: "buffer"
|
|
1068
|
-
});
|
|
1069
|
-
if (!result.images || result.images.length === 0) throw new Error("AI image generation returned no results");
|
|
1070
|
-
let buffer;
|
|
1071
|
-
const imageData = result.images[0].data;
|
|
1072
|
-
if (Buffer.isBuffer(imageData)) buffer = imageData;
|
|
1073
|
-
else if (typeof imageData === "string") if (imageData.startsWith("http")) {
|
|
1074
|
-
const response = await fetch(imageData);
|
|
1075
|
-
if (!response.ok) throw new Error(`AI image generation URL fetch failed: ${response.status} ${response.statusText}`);
|
|
1076
|
-
buffer = Buffer.from(await response.arrayBuffer());
|
|
1077
|
-
} else buffer = Buffer.from(imageData, "base64");
|
|
1078
|
-
else throw new Error("AI image generation returned unexpected format");
|
|
1079
|
-
return this.createImageFromBuffer(buffer, {
|
|
1080
|
-
width: options.width ?? 1200,
|
|
1081
|
-
height: options.height ?? 630,
|
|
1082
|
-
mimeType: "image/png",
|
|
1083
|
-
name: `${this.content.id}-ai.png`
|
|
1084
|
-
});
|
|
1085
|
-
}
|
|
1086
|
-
/**
|
|
1087
|
-
* Build a prompt for AI image generation based on content.
|
|
1088
|
-
*
|
|
1089
|
-
* Resolves via `@happyvertical/smrt-prompts` so tenants can override the
|
|
1090
|
-
* template/profile/model/params at runtime. Only non-PII content fields
|
|
1091
|
-
* (title, description) and the caller-supplied style hint are passed.
|
|
1092
|
-
* Internal IDs and the freeform `metadata` blob are intentionally excluded.
|
|
1093
|
-
*
|
|
1094
|
-
* Returns the full ResolvedPrompt (text + ai config) so the caller can
|
|
1095
|
-
* forward `model`/`params` overrides to `ai.generateImage()`. Returning
|
|
1096
|
-
* only the text would silently drop the editable model/params overrides.
|
|
1097
|
-
*/
|
|
1098
|
-
async buildAIPrompt(style) {
|
|
1099
|
-
const title = this.content.title || "Untitled";
|
|
1100
|
-
const description = this.content.description || "";
|
|
1101
|
-
const stylePrompts = {
|
|
1102
|
-
photorealistic: "photorealistic, high quality, professional photography, 8k resolution",
|
|
1103
|
-
illustration: "digital illustration, clean vector art, modern design, vibrant colors",
|
|
1104
|
-
abstract: "abstract art, geometric shapes, modern minimalist, artistic interpretation",
|
|
1105
|
-
minimal: "minimalist design, simple shapes, clean composition, subtle colors"
|
|
1106
|
-
};
|
|
1107
|
-
const styleHint = stylePrompts[style] || stylePrompts.photorealistic;
|
|
1108
|
-
return resolvePrompt(smrtContentThumbnailAIGeneratePrompt.key, {
|
|
1109
|
-
db: this.options.db,
|
|
1110
|
-
tenantId: this.content.tenantId,
|
|
1111
|
-
variables: {
|
|
1112
|
-
style,
|
|
1113
|
-
title,
|
|
1114
|
-
styleHint,
|
|
1115
|
-
descriptionClause: description ? `The article is about: ${description}. ` : ""
|
|
1116
|
-
}
|
|
1117
|
-
});
|
|
1118
|
-
}
|
|
1119
|
-
/**
|
|
1120
|
-
* Create an Image object from a buffer
|
|
1121
|
-
*/
|
|
1122
|
-
async createImageFromBuffer(buffer, metadata) {
|
|
1123
|
-
return await (await ImageCollection.create({ db: this.options.db })).create({
|
|
1124
|
-
name: metadata.name,
|
|
1125
|
-
mimeType: metadata.mimeType,
|
|
1126
|
-
width: metadata.width,
|
|
1127
|
-
height: metadata.height,
|
|
1128
|
-
sourceUri: `data:${metadata.mimeType};base64,${buffer.toString("base64")}`
|
|
1129
|
-
});
|
|
1130
|
-
}
|
|
1131
|
-
};
|
|
1132
|
-
//#endregion
|
|
1133
|
-
//#region src/content.ts
|
|
1134
|
-
var __defProp = Object.defineProperty;
|
|
1135
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
1136
|
-
var __decorateClass = (decorators, target, key, kind) => {
|
|
1137
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
1138
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1139
|
-
if (kind && result) __defProp(target, key, result);
|
|
1140
|
-
return result;
|
|
1141
|
-
};
|
|
1142
|
-
var USED_FACT_RELATIONSHIPS = /* @__PURE__ */ new Set([
|
|
1143
|
-
"supports",
|
|
1144
|
-
"referenced_in",
|
|
1145
|
-
"contradicts"
|
|
1146
|
-
]);
|
|
1147
|
-
var FACT_AUDIT_GENERATED_BY = "content.factAudit";
|
|
1148
|
-
var FACT_AUDIT_DOMAIN = "content-audit";
|
|
1149
|
-
function normalizeFingerprintValue(value) {
|
|
1150
|
-
if (value instanceof Date) return value.toISOString();
|
|
1151
|
-
if (Array.isArray(value)) return value.map((entry) => normalizeFingerprintValue(entry));
|
|
1152
|
-
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entryValue]) => [key, normalizeFingerprintValue(entryValue)]));
|
|
1153
|
-
return value ?? null;
|
|
1154
|
-
}
|
|
1155
|
-
function hashFingerprint(input) {
|
|
1156
|
-
let hash = 5381;
|
|
1157
|
-
for (let index = 0; index < input.length; index += 1) hash = hash * 33 ^ input.charCodeAt(index);
|
|
1158
|
-
return `fp-${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
1159
|
-
}
|
|
1160
|
-
function createFingerprint(value) {
|
|
1161
|
-
return hashFingerprint(JSON.stringify(normalizeFingerprintValue(value)));
|
|
1162
|
-
}
|
|
1163
|
-
function normalizeAuditText(value) {
|
|
1164
|
-
return String(value ?? "").trim().replace(/\s+/g, " ");
|
|
1165
|
-
}
|
|
1166
|
-
function errorMessage(error) {
|
|
1167
|
-
if (error instanceof Error) return error.message;
|
|
1168
|
-
if (error && typeof error === "object" && "message" in error && typeof error.message === "string") return error.message;
|
|
1169
|
-
return String(error);
|
|
1170
|
-
}
|
|
1171
|
-
function createFactAuditRunId(contentId) {
|
|
1172
|
-
return `fact-audit-${hashFingerprint(`${contentId}:${(/* @__PURE__ */ new Date()).toISOString()}:${Math.random()}`)}`;
|
|
1173
|
-
}
|
|
1174
|
-
function parseAuditMetadata(value) {
|
|
1175
|
-
if (!value) return {};
|
|
1176
|
-
if (typeof value === "object") return value;
|
|
1177
|
-
try {
|
|
1178
|
-
return JSON.parse(String(value));
|
|
1179
|
-
} catch {
|
|
1180
|
-
return {};
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
function getLinkMetadata(link) {
|
|
1184
|
-
return typeof link?.getMetadata === "function" ? link.getMetadata() : {};
|
|
1185
|
-
}
|
|
1186
|
-
function getFactMetadata(fact) {
|
|
1187
|
-
return typeof fact?.getMetadata === "function" ? fact.getMetadata() : parseAuditMetadata(fact?.metadata);
|
|
1188
|
-
}
|
|
1189
|
-
function getGeneratedFactAuditMetadata(link) {
|
|
1190
|
-
const metadata = getLinkMetadata(link);
|
|
1191
|
-
if (metadata.generatedBy === FACT_AUDIT_GENERATED_BY) return metadata;
|
|
1192
|
-
const nested = metadata.factAudit;
|
|
1193
|
-
if (nested && typeof nested === "object" && nested.generatedBy === FACT_AUDIT_GENERATED_BY) return nested;
|
|
1194
|
-
return null;
|
|
1195
|
-
}
|
|
1196
|
-
function getEvidenceMetadata(evidence) {
|
|
1197
|
-
return typeof evidence?.getMetadata === "function" ? evidence.getMetadata() : parseAuditMetadata(evidence?.metadata);
|
|
1198
|
-
}
|
|
1199
|
-
function isGeneratedFactAuditEvidence(evidence, contentId) {
|
|
1200
|
-
const metadata = getEvidenceMetadata(evidence);
|
|
1201
|
-
return metadata.generatedBy === FACT_AUDIT_GENERATED_BY && metadata.contentId === contentId;
|
|
1202
|
-
}
|
|
1203
|
-
function isGeneratedArticleClaimFact(fact, contentId) {
|
|
1204
|
-
const metadata = getFactMetadata(fact);
|
|
1205
|
-
if (metadata.generatedBy !== FACT_AUDIT_GENERATED_BY) return false;
|
|
1206
|
-
return ((metadata.auditFactRole || metadata.factAuditRole) === "article-claim" || metadata.claimOnly === true) && metadata.contentId === contentId;
|
|
1207
|
-
}
|
|
1208
|
-
function normalizeFactEvidenceStatus(value) {
|
|
1209
|
-
return [
|
|
1210
|
-
"supports",
|
|
1211
|
-
"contradicts",
|
|
1212
|
-
"unclear",
|
|
1213
|
-
"irrelevant",
|
|
1214
|
-
"invalid"
|
|
1215
|
-
].includes(value) ? value : null;
|
|
1216
|
-
}
|
|
1217
|
-
function sourceMatchesSelector(source, selector) {
|
|
1218
|
-
return source.sourceKind === selector.sourceKind && source.sourceId === selector.sourceId;
|
|
1219
|
-
}
|
|
1220
|
-
function filterAuditSources(sources, selectors) {
|
|
1221
|
-
if (!selectors || selectors.length === 0) return sources;
|
|
1222
|
-
return sources.filter((source) => selectors.some((selector) => sourceMatchesSelector(source, selector)));
|
|
1223
|
-
}
|
|
1224
|
-
function getContentText(content) {
|
|
1225
|
-
return [
|
|
1226
|
-
content.title,
|
|
1227
|
-
content.description,
|
|
1228
|
-
content.body
|
|
1229
|
-
].map(normalizeAuditText).filter(Boolean).join("\n\n");
|
|
1230
|
-
}
|
|
1231
|
-
function readNestedString(source, path) {
|
|
1232
|
-
let current = source;
|
|
1233
|
-
for (const key of path) {
|
|
1234
|
-
if (!current || typeof current !== "object") return null;
|
|
1235
|
-
current = current[key];
|
|
1236
|
-
}
|
|
1237
|
-
return typeof current === "string" && current ? current : null;
|
|
1238
|
-
}
|
|
1239
|
-
function asRecord(value) {
|
|
1240
|
-
if (value && typeof value === "object" && !Array.isArray(value)) return value;
|
|
1241
|
-
if (typeof value === "string") try {
|
|
1242
|
-
const parsed = JSON.parse(value);
|
|
1243
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
1244
|
-
} catch {
|
|
1245
|
-
return {};
|
|
1246
|
-
}
|
|
1247
|
-
return {};
|
|
1248
|
-
}
|
|
1249
|
-
function readNestedRecord(source, path) {
|
|
1250
|
-
let current = source;
|
|
1251
|
-
for (const key of path) {
|
|
1252
|
-
if (!current || typeof current !== "object") return {};
|
|
1253
|
-
current = current[key];
|
|
1254
|
-
}
|
|
1255
|
-
return asRecord(current);
|
|
1256
|
-
}
|
|
1257
|
-
function getPublicPrompt(metadata) {
|
|
1258
|
-
return readNestedString(metadata, [
|
|
1259
|
-
"transparency",
|
|
1260
|
-
"generation",
|
|
1261
|
-
"publicPrompt"
|
|
1262
|
-
]) || readNestedString(metadata, ["generation", "publicPrompt"]) || readNestedString(metadata, ["publicPrompt"]) || null;
|
|
1263
|
-
}
|
|
1264
|
-
var Content = class extends SmrtObject {
|
|
1265
|
-
tenantId = null;
|
|
1266
|
-
/**
|
|
1267
|
-
* Array of referenced content objects
|
|
1268
|
-
*/
|
|
1269
|
-
references = [];
|
|
1270
|
-
/**
|
|
1271
|
-
* Content type classification
|
|
1272
|
-
*/
|
|
1273
|
-
type = null;
|
|
1274
|
-
/**
|
|
1275
|
-
* Content variant for namespaced classification within types
|
|
1276
|
-
* Format: generator:domain:specific-type
|
|
1277
|
-
* Example: "praeco:meeting:upcoming"
|
|
1278
|
-
*/
|
|
1279
|
-
variant = null;
|
|
1280
|
-
/**
|
|
1281
|
-
* Reference to file storage key
|
|
1282
|
-
*/
|
|
1283
|
-
fileKey = null;
|
|
1284
|
-
/**
|
|
1285
|
-
* Author of the content
|
|
1286
|
-
*/
|
|
1287
|
-
author = null;
|
|
1288
|
-
name = "";
|
|
1289
|
-
/**
|
|
1290
|
-
* Content title
|
|
1291
|
-
*/
|
|
1292
|
-
title = "";
|
|
1293
|
-
/**
|
|
1294
|
-
* Short description or summary
|
|
1295
|
-
*/
|
|
1296
|
-
description = null;
|
|
1297
|
-
/**
|
|
1298
|
-
* Main content body text
|
|
1299
|
-
*/
|
|
1300
|
-
body = "";
|
|
1301
|
-
/**
|
|
1302
|
-
* Format used to persist the body field.
|
|
1303
|
-
*/
|
|
1304
|
-
bodyFormat = null;
|
|
1305
|
-
/**
|
|
1306
|
-
* Date when content was published
|
|
1307
|
-
*/
|
|
1308
|
-
publish_date = null;
|
|
1309
|
-
/**
|
|
1310
|
-
* URL source of the content
|
|
1311
|
-
*/
|
|
1312
|
-
url = null;
|
|
1313
|
-
/**
|
|
1314
|
-
* Original source identifier
|
|
1315
|
-
*/
|
|
1316
|
-
source = null;
|
|
1317
|
-
/**
|
|
1318
|
-
* Original URL of the content
|
|
1319
|
-
*/
|
|
1320
|
-
original_url = null;
|
|
1321
|
-
/**
|
|
1322
|
-
* Content language
|
|
1323
|
-
*/
|
|
1324
|
-
language = null;
|
|
1325
|
-
/**
|
|
1326
|
-
* Content tags
|
|
1327
|
-
*/
|
|
1328
|
-
tags = [];
|
|
1329
|
-
/**
|
|
1330
|
-
* Hierarchical category path for URL routing
|
|
1331
|
-
* Format: 'parent/child' (e.g., 'politics/local')
|
|
1332
|
-
* Each content belongs to exactly ONE category
|
|
1333
|
-
*/
|
|
1334
|
-
category = null;
|
|
1335
|
-
/**
|
|
1336
|
-
* Publication status
|
|
1337
|
-
*/
|
|
1338
|
-
status = "draft";
|
|
1339
|
-
/**
|
|
1340
|
-
* Content state flag
|
|
1341
|
-
*/
|
|
1342
|
-
state = "active";
|
|
1343
|
-
/**
|
|
1344
|
-
* Additional JSON metadata for flexible schema extension
|
|
1345
|
-
*/
|
|
1346
|
-
metadata = {};
|
|
1347
|
-
thumbnailAssetId = null;
|
|
1348
|
-
/**
|
|
1349
|
-
* Creates a new Content instance
|
|
1350
|
-
*/
|
|
1351
|
-
constructor(options = {}) {
|
|
1352
|
-
super(options);
|
|
1353
|
-
this.type = options.type || null;
|
|
1354
|
-
this.variant = options.variant || null;
|
|
1355
|
-
this.fileKey = options.fileKey || null;
|
|
1356
|
-
this.author = options.author || null;
|
|
1357
|
-
if (options.name) this.name = options.name;
|
|
1358
|
-
this.title = options.title || "";
|
|
1359
|
-
this.description = options.description || null;
|
|
1360
|
-
this.body = options.body || "";
|
|
1361
|
-
this.bodyFormat = isContentBodyFormat(options.bodyFormat) ? options.bodyFormat : null;
|
|
1362
|
-
this.publish_date = options.publish_date || null;
|
|
1363
|
-
this.source = options.source || null;
|
|
1364
|
-
this.original_url = options.original_url || null;
|
|
1365
|
-
this.language = options.language || null;
|
|
1366
|
-
this.status = options.status || "draft";
|
|
1367
|
-
this.tags = options.tags || [];
|
|
1368
|
-
this.category = options.category || null;
|
|
1369
|
-
this.state = options.state || "active";
|
|
1370
|
-
this.metadata = options.metadata || {};
|
|
1371
|
-
this.thumbnailAssetId = options.thumbnailAssetId ?? null;
|
|
1372
|
-
const transient = this;
|
|
1373
|
-
if (Array.isArray(options.referenceIds)) transient.referenceIds = [...options.referenceIds];
|
|
1374
|
-
if (Array.isArray(options.assetIds)) transient.assetIds = [...options.assetIds];
|
|
1375
|
-
}
|
|
1376
|
-
/**
|
|
1377
|
-
* Initializes this content object
|
|
1378
|
-
*
|
|
1379
|
-
* @returns Promise that resolves to this instance
|
|
1380
|
-
*/
|
|
1381
|
-
async initialize() {
|
|
1382
|
-
await super.initialize();
|
|
1383
|
-
return this;
|
|
1384
|
-
}
|
|
1385
|
-
async validateBeforeSave() {
|
|
1386
|
-
if (!this.name && this.title) this.name = this.title;
|
|
1387
|
-
if (!this.title && this.name) this.title = this.name;
|
|
1388
|
-
await super.validateBeforeSave();
|
|
1389
|
-
if (this.status !== "published") return;
|
|
1390
|
-
const governance = await this.resolvePublicationGovernance();
|
|
1391
|
-
const profileKey = governance?.publicationProfileKey;
|
|
1392
|
-
if (!governance?.isGoverned || !governance.enforcePublishReadiness || !profileKey) return;
|
|
1393
|
-
const blockingRequirements = (await this.evaluateReviewProfile(profileKey)).requirements.filter((requirement) => requirement.blocking && !requirement.satisfied);
|
|
1394
|
-
if (blockingRequirements.length === 0) return;
|
|
1395
|
-
throw new ValidationError(`Cannot publish content until the "${profileKey}" review profile is satisfied. ${blockingRequirements.map((requirement) => {
|
|
1396
|
-
if (requirement.missing) return `${requirement.label} has not been run yet`;
|
|
1397
|
-
if (requirement.stale) return `${requirement.label} is stale and must be rerun`;
|
|
1398
|
-
if (requirement.latestStatus) return `${requirement.label} returned ${requirement.latestStatus}`;
|
|
1399
|
-
return `${requirement.label} is not satisfied`;
|
|
1400
|
-
}).join("; ")}`, "VALIDATION_PUBLISH_READINESS", {
|
|
1401
|
-
profileKey,
|
|
1402
|
-
blockingRequirements: blockingRequirements.map((requirement) => ({
|
|
1403
|
-
policyKey: requirement.policyKey,
|
|
1404
|
-
label: requirement.label,
|
|
1405
|
-
missing: requirement.missing,
|
|
1406
|
-
stale: requirement.stale,
|
|
1407
|
-
latestStatus: requirement.latestStatus
|
|
1408
|
-
}))
|
|
1409
|
-
});
|
|
1410
|
-
}
|
|
1411
|
-
async save(options = {}) {
|
|
1412
|
-
const shouldConsiderPublicationSnapshot = this.status === "published";
|
|
1413
|
-
let governance = null;
|
|
1414
|
-
let previous = null;
|
|
1415
|
-
let previousPublicationFingerprint = null;
|
|
1416
|
-
if (shouldConsiderPublicationSnapshot) {
|
|
1417
|
-
governance = await this.resolvePublicationGovernance();
|
|
1418
|
-
if (governance?.isGoverned && governance.transparencyEnabled) {
|
|
1419
|
-
previous = await this.getPersistedContent();
|
|
1420
|
-
previousPublicationFingerprint = await this.getLatestPublicationSnapshotFingerprint();
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
await super.save(options);
|
|
1424
|
-
await this.syncPendingReferenceIds();
|
|
1425
|
-
await this.syncPendingAssetIds();
|
|
1426
|
-
if (!shouldConsiderPublicationSnapshot || !governance?.isGoverned || !governance.transparencyEnabled) return this;
|
|
1427
|
-
const nextPublicationFingerprint = await this.buildPublicationSnapshotFingerprint(governance);
|
|
1428
|
-
if (nextPublicationFingerprint && nextPublicationFingerprint !== previousPublicationFingerprint) await this.createVersion({
|
|
1429
|
-
kind: "publication",
|
|
1430
|
-
summary: previous?.status === "published" ? "Published content updated." : "Content published.",
|
|
1431
|
-
metadata: {
|
|
1432
|
-
publicationSnapshotFingerprint: nextPublicationFingerprint,
|
|
1433
|
-
publicationProfileKey: governance.publicationProfileKey,
|
|
1434
|
-
transparency: await this.buildTransparencySnapshot({
|
|
1435
|
-
snapshotKind: "published",
|
|
1436
|
-
governance
|
|
1437
|
-
})
|
|
1438
|
-
}
|
|
1439
|
-
});
|
|
1440
|
-
return this;
|
|
1441
|
-
}
|
|
1442
|
-
async getReferenceCollection() {
|
|
1443
|
-
return ContentReferences.create({ db: this.db });
|
|
1444
|
-
}
|
|
1445
|
-
async getFactCollection() {
|
|
1446
|
-
const { FactCollection } = await import("@happyvertical/smrt-facts");
|
|
1447
|
-
return FactCollection.create(this.options);
|
|
1448
|
-
}
|
|
1449
|
-
async getFactContentCollection() {
|
|
1450
|
-
const { FactContentCollection } = await import("@happyvertical/smrt-facts");
|
|
1451
|
-
return FactContentCollection.create(this.options);
|
|
1452
|
-
}
|
|
1453
|
-
async getFactSourceCollection() {
|
|
1454
|
-
const { FactSourceCollection } = await import("@happyvertical/smrt-facts");
|
|
1455
|
-
return FactSourceCollection.create(this.options);
|
|
1456
|
-
}
|
|
1457
|
-
async getFactEvidenceCollection() {
|
|
1458
|
-
const { FactEvidenceCollection } = await import("@happyvertical/smrt-facts");
|
|
1459
|
-
return FactEvidenceCollection.create(this.options);
|
|
1460
|
-
}
|
|
1461
|
-
async getContentVersionCollection() {
|
|
1462
|
-
const { ContentVersionCollection } = await import("./content-versions-JXn7MXeM.js").then((n) => n.n);
|
|
1463
|
-
return ContentVersionCollection.create(this.options);
|
|
1464
|
-
}
|
|
1465
|
-
async getContentReviewCollection() {
|
|
1466
|
-
const { ContentReviewCollection } = await import("./content-reviews-D6o0zK8s.js").then((n) => n.n);
|
|
1467
|
-
return ContentReviewCollection.create(this.options);
|
|
1468
|
-
}
|
|
1469
|
-
async getContentCorrectionCollection() {
|
|
1470
|
-
const { ContentCorrectionCollection } = await import("./content-corrections-CKuY-MSv.js").then((n) => n.n);
|
|
1471
|
-
return ContentCorrectionCollection.create(this.options);
|
|
1472
|
-
}
|
|
1473
|
-
async getContentsCollection() {
|
|
1474
|
-
const { Contents } = await import("./contents-C048Z_8g.js").then((n) => n.n);
|
|
1475
|
-
return Contents.create({ db: this.db });
|
|
1476
|
-
}
|
|
1477
|
-
getConfiguredGovernance() {
|
|
1478
|
-
return resolveConfiguredContentGovernance({
|
|
1479
|
-
contentType: this.type,
|
|
1480
|
-
contentVariant: this.variant
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
async resolveGovernance() {
|
|
1484
|
-
return resolveEffectiveContentGovernance({
|
|
1485
|
-
contentType: this.type,
|
|
1486
|
-
contentVariant: this.variant,
|
|
1487
|
-
db: this.db,
|
|
1488
|
-
tenantId: this.tenantId ?? null
|
|
1489
|
-
});
|
|
1490
|
-
}
|
|
1491
|
-
async hasPersistedGovernanceAssignments() {
|
|
1492
|
-
if (!this.db || typeof this.db.query !== "function") return false;
|
|
1493
|
-
try {
|
|
1494
|
-
const exactKey = buildContentGovernanceAssignmentKey(this.type || "", this.variant || "");
|
|
1495
|
-
const typeOnlyKey = buildContentGovernanceAssignmentKey(this.type || "");
|
|
1496
|
-
const keys = exactKey === typeOnlyKey ? [exactKey] : [exactKey, typeOnlyKey];
|
|
1497
|
-
const placeholders = keys.map(() => "?").join(", ");
|
|
1498
|
-
const result = await this.db.query(`SELECT 1 AS matched FROM content_governance_assignments WHERE key IN (${placeholders}) LIMIT 1`, keys);
|
|
1499
|
-
return (Array.isArray(result) ? result : result?.rows ?? []).length > 0;
|
|
1500
|
-
} catch {
|
|
1501
|
-
return false;
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
async resolvePublicationGovernance() {
|
|
1505
|
-
if (this.getConfiguredGovernance().isGoverned) return this.resolveGovernance();
|
|
1506
|
-
if (!await this.hasPersistedGovernanceAssignments()) return null;
|
|
1507
|
-
const governance = await this.resolveGovernance();
|
|
1508
|
-
return governance.isGoverned ? governance : null;
|
|
1509
|
-
}
|
|
1510
|
-
async requireGovernance(feature = "governance workflow") {
|
|
1511
|
-
const governance = await this.resolveGovernance();
|
|
1512
|
-
if (!governance.isGoverned) throw new Error(`Governance is not enabled for content type "${this.type || "content"}"${this.variant ? ` variant "${this.variant}"` : ""}, so ${feature} is unavailable.`);
|
|
1513
|
-
return governance;
|
|
1514
|
-
}
|
|
1515
|
-
async requireFactLinking(feature = "fact linking") {
|
|
1516
|
-
const governance = await this.requireGovernance(feature);
|
|
1517
|
-
if (!governance.factLinkingEnabled) throw new Error(`Fact linking is not enabled for content type "${this.type || "content"}"${this.variant ? ` variant "${this.variant}"` : ""}.`);
|
|
1518
|
-
return governance;
|
|
1519
|
-
}
|
|
1520
|
-
async getPersistedContent() {
|
|
1521
|
-
if (!this.id) return null;
|
|
1522
|
-
return await (await this.getContentsCollection()).get({ id: this.id });
|
|
1523
|
-
}
|
|
1524
|
-
async buildReviewFingerprint(policyKey) {
|
|
1525
|
-
const governance = await this.resolveGovernance();
|
|
1526
|
-
const kind = getContentReviewKind(policyKey, governance.reviewPolicies);
|
|
1527
|
-
const policy = getContentReviewPolicy(policyKey, governance.reviewPolicies);
|
|
1528
|
-
const [references, facts, factLinks] = await Promise.all([
|
|
1529
|
-
this.getReferences(),
|
|
1530
|
-
kind === "facts" && governance.factLinkingEnabled ? this.getFacts({
|
|
1531
|
-
latestOnly: true,
|
|
1532
|
-
includeSuperseded: false
|
|
1533
|
-
}) : Promise.resolve([]),
|
|
1534
|
-
kind === "facts" && governance.factLinkingEnabled ? this.getFactLinks() : Promise.resolve([])
|
|
1535
|
-
]);
|
|
1536
|
-
return createFingerprint({
|
|
1537
|
-
scope: "content-review",
|
|
1538
|
-
policyKey,
|
|
1539
|
-
kind,
|
|
1540
|
-
policyInstructions: policy?.instructions || "",
|
|
1541
|
-
content: {
|
|
1542
|
-
id: this.id || null,
|
|
1543
|
-
type: this.type,
|
|
1544
|
-
variant: this.variant,
|
|
1545
|
-
title: this.title,
|
|
1546
|
-
description: this.description,
|
|
1547
|
-
body: this.body,
|
|
1548
|
-
author: this.author,
|
|
1549
|
-
state: this.state,
|
|
1550
|
-
publishDate: this.publish_date,
|
|
1551
|
-
language: this.language,
|
|
1552
|
-
category: this.category,
|
|
1553
|
-
tags: this.tags,
|
|
1554
|
-
metadata: this.metadata
|
|
1555
|
-
},
|
|
1556
|
-
referenceIds: references.map((reference) => reference.id).filter(Boolean).sort(),
|
|
1557
|
-
facts: facts.map((fact) => ({
|
|
1558
|
-
id: fact.id || null,
|
|
1559
|
-
previousFactId: fact.previousFactId || null,
|
|
1560
|
-
status: fact.status || null,
|
|
1561
|
-
textRefined: fact.textRefined || "",
|
|
1562
|
-
sourceCount: fact.sourceCount ?? 0,
|
|
1563
|
-
confidence: fact.confidence ?? null,
|
|
1564
|
-
metadata: typeof fact?.getMetadata === "function" ? fact.getMetadata() : {}
|
|
1565
|
-
})),
|
|
1566
|
-
factLinks: factLinks.map((link) => ({
|
|
1567
|
-
factId: link.factId || null,
|
|
1568
|
-
relationship: link.relationship || null,
|
|
1569
|
-
metadata: typeof link?.getMetadata === "function" ? link.getMetadata() : {}
|
|
1570
|
-
}))
|
|
1571
|
-
});
|
|
1572
|
-
}
|
|
1573
|
-
async buildTransparencySnapshot(options = {}) {
|
|
1574
|
-
const snapshotKind = options.snapshotKind || "preview";
|
|
1575
|
-
const governance = options.governance || await this.resolveGovernance();
|
|
1576
|
-
if (!governance.isGoverned || !governance.transparencyEnabled) return null;
|
|
1577
|
-
const [references, facts, factLinks, reviews, corrections, versions, reviewProfiles] = await Promise.all([
|
|
1578
|
-
this.getReferences(),
|
|
1579
|
-
governance.factLinkingEnabled ? this.getFacts({
|
|
1580
|
-
latestOnly: true,
|
|
1581
|
-
includeSuperseded: false
|
|
1582
|
-
}) : Promise.resolve([]),
|
|
1583
|
-
governance.factLinkingEnabled ? this.getFactLinks() : Promise.resolve([]),
|
|
1584
|
-
this.listReviews(),
|
|
1585
|
-
this.listCorrections(),
|
|
1586
|
-
this.listVersions(),
|
|
1587
|
-
this.listReviewProfilesAction()
|
|
1588
|
-
]);
|
|
1589
|
-
const factSources = await this.getFactSourceCollection();
|
|
1590
|
-
const factSourcesByFactId = /* @__PURE__ */ new Map();
|
|
1591
|
-
for (const fact of facts) {
|
|
1592
|
-
const factId = fact.id;
|
|
1593
|
-
if (!factId) continue;
|
|
1594
|
-
const sources = await factSources.getForFact(factId);
|
|
1595
|
-
factSourcesByFactId.set(factId, sources);
|
|
1596
|
-
}
|
|
1597
|
-
const usedFactIds = new Set(factLinks.filter((link) => USED_FACT_RELATIONSHIPS.has(link.relationship || "related")).map((link) => link.factId).filter(Boolean));
|
|
1598
|
-
const linkedFacts = facts.map((fact) => {
|
|
1599
|
-
const factId = fact.id;
|
|
1600
|
-
const link = factLinks.find((entry) => entry.factId === factId);
|
|
1601
|
-
const sources = (factId ? factSourcesByFactId.get(factId) : []) || [];
|
|
1602
|
-
return {
|
|
1603
|
-
...serializeFact(fact),
|
|
1604
|
-
relationship: link?.relationship || null,
|
|
1605
|
-
linkMetadata: typeof link?.getMetadata === "function" ? link.getMetadata() : {},
|
|
1606
|
-
usedInArticle: factId ? usedFactIds.has(factId) : false,
|
|
1607
|
-
sources: sources.map((source) => ({
|
|
1608
|
-
id: source.id || null,
|
|
1609
|
-
sourceType: source.sourceType || null,
|
|
1610
|
-
sourceUrl: source.sourceUrl || null,
|
|
1611
|
-
sourceTitle: source.sourceTitle || null,
|
|
1612
|
-
credibility: source.credibility ?? null,
|
|
1613
|
-
extractedAt: source.extractedAt || null,
|
|
1614
|
-
metadata: typeof source?.getMetadata === "function" ? source.getMetadata() : {}
|
|
1615
|
-
}))
|
|
1616
|
-
};
|
|
1617
|
-
});
|
|
1618
|
-
const referenceGroups = await Promise.all(references.map(async (reference) => {
|
|
1619
|
-
const sourceUrls = [
|
|
1620
|
-
reference.url,
|
|
1621
|
-
reference.original_url,
|
|
1622
|
-
reference.source
|
|
1623
|
-
].filter(Boolean);
|
|
1624
|
-
const extractedFacts = /* @__PURE__ */ new Map();
|
|
1625
|
-
for (const sourceUrl of sourceUrls) {
|
|
1626
|
-
const matches = await factSources.list({
|
|
1627
|
-
where: { sourceUrl },
|
|
1628
|
-
orderBy: "created_at ASC"
|
|
1629
|
-
});
|
|
1630
|
-
for (const match of matches) {
|
|
1631
|
-
if (!match.factId || extractedFacts.has(match.factId)) continue;
|
|
1632
|
-
const fact = await match.getFact();
|
|
1633
|
-
if (fact?.id) extractedFacts.set(fact.id, fact);
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
const extractedFactRecords = [...extractedFacts.values()].map((fact) => {
|
|
1637
|
-
const factId = fact.id;
|
|
1638
|
-
return {
|
|
1639
|
-
...serializeFact(fact),
|
|
1640
|
-
usedInArticle: factId ? usedFactIds.has(factId) : false
|
|
1641
|
-
};
|
|
1642
|
-
});
|
|
1643
|
-
return {
|
|
1644
|
-
id: reference.id || null,
|
|
1645
|
-
title: reference.title || reference.name || reference.url || null,
|
|
1646
|
-
url: reference.url || null,
|
|
1647
|
-
originalUrl: reference.original_url || null,
|
|
1648
|
-
type: reference.type || null,
|
|
1649
|
-
source: reference.source || null,
|
|
1650
|
-
usedFactIds: extractedFactRecords.filter((fact) => fact.id && usedFactIds.has(fact.id)).map((fact) => fact.id),
|
|
1651
|
-
extractedFacts: extractedFactRecords
|
|
1652
|
-
};
|
|
1653
|
-
}));
|
|
1654
|
-
const publicGeneration = readNestedRecord(this.metadata, ["transparency", "generation"]);
|
|
1655
|
-
const generationMetadata = readNestedRecord(this.metadata, ["generation"]);
|
|
1656
|
-
const serializedCorrections = corrections.filter((correction) => correction.status === "published").map((correction) => {
|
|
1657
|
-
const correctionMetadata = asRecord(correction.metadata);
|
|
1658
|
-
return {
|
|
1659
|
-
...serializeContentCorrection(correction),
|
|
1660
|
-
provenance: {
|
|
1661
|
-
autoGeneratedDraft: Boolean(correctionMetadata.autoGeneratedDraft),
|
|
1662
|
-
draftVersionId: correctionMetadata.draftVersionId || null,
|
|
1663
|
-
draftVersionNumber: correctionMetadata.draftVersionNumber || null,
|
|
1664
|
-
sourceCorrectionVersionId: correctionMetadata.sourceCorrectionVersionId || null,
|
|
1665
|
-
sourceCorrectionVersionNumber: correctionMetadata.sourceCorrectionVersionNumber || null
|
|
1666
|
-
}
|
|
1667
|
-
};
|
|
1668
|
-
});
|
|
1669
|
-
const serializedVersionHistory = versions.map((version) => {
|
|
1670
|
-
const versionMetadata = asRecord(version.metadata);
|
|
1671
|
-
return {
|
|
1672
|
-
id: version.id || null,
|
|
1673
|
-
version: version.version ?? null,
|
|
1674
|
-
kind: version.kind || null,
|
|
1675
|
-
summary: version.summary || "",
|
|
1676
|
-
createdAt: version.createdAt || null,
|
|
1677
|
-
provenance: {
|
|
1678
|
-
policyKey: versionMetadata.policyKey || null,
|
|
1679
|
-
reviewFingerprint: versionMetadata.reviewFingerprint || versionMetadata.contentFingerprint || null,
|
|
1680
|
-
factId: versionMetadata.factId || null,
|
|
1681
|
-
replacementFactId: versionMetadata.replacementFactId || null,
|
|
1682
|
-
sourceCorrectionVersionId: versionMetadata.sourceCorrectionVersionId || null,
|
|
1683
|
-
sourceCorrectionVersionNumber: versionMetadata.sourceCorrectionVersionNumber || null,
|
|
1684
|
-
correctionDraft: versionMetadata.correctionDraft || null,
|
|
1685
|
-
publicationSnapshotFingerprint: versionMetadata.publicationSnapshotFingerprint || null
|
|
1686
|
-
}
|
|
1687
|
-
};
|
|
1688
|
-
});
|
|
1689
|
-
return normalizeContentTransparency({
|
|
1690
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1691
|
-
snapshotKind,
|
|
1692
|
-
contentId: this.id || null,
|
|
1693
|
-
currentContentStatus: this.status || null,
|
|
1694
|
-
publicationProfileKey: governance.publicationProfileKey || void 0,
|
|
1695
|
-
generation: {
|
|
1696
|
-
aiAssisted: publicGeneration.aiAssisted ?? generationMetadata.aiAssisted ?? Boolean(getPublicPrompt(this.metadata)),
|
|
1697
|
-
publicPrompt: getPublicPrompt(this.metadata),
|
|
1698
|
-
model: publicGeneration.model || generationMetadata.model || null
|
|
1699
|
-
},
|
|
1700
|
-
factsUsed: linkedFacts.filter((fact) => fact.usedInArticle),
|
|
1701
|
-
linkedFacts,
|
|
1702
|
-
otherExtractedFacts: referenceGroups.flatMap((reference) => reference.extractedFacts.filter((fact) => !fact.usedInArticle)),
|
|
1703
|
-
references: referenceGroups,
|
|
1704
|
-
reviews,
|
|
1705
|
-
reviewProfiles,
|
|
1706
|
-
corrections: serializedCorrections,
|
|
1707
|
-
versionHistory: serializedVersionHistory
|
|
1708
|
-
}, {
|
|
1709
|
-
snapshotKind,
|
|
1710
|
-
contentId: this.id || null,
|
|
1711
|
-
currentContentStatus: this.status || null,
|
|
1712
|
-
publicationProfileKey: governance.publicationProfileKey || void 0
|
|
1713
|
-
});
|
|
1714
|
-
}
|
|
1715
|
-
/**
|
|
1716
|
-
* Fingerprint of the *content-bearing* publication surface only.
|
|
1717
|
-
*
|
|
1718
|
-
* This must converge: two byte-identical `save()`s of published content
|
|
1719
|
-
* have to produce the same fingerprint so the publication-version writer
|
|
1720
|
-
* (`save()`) does not append a redundant `ContentVersion` on every save.
|
|
1721
|
-
*
|
|
1722
|
-
* It therefore deliberately excludes everything that grows or carries a
|
|
1723
|
-
* timestamp/ordering with each save — `versionHistory`, `reviews`,
|
|
1724
|
-
* `corrections`, and any `generatedAt`/`createdAt`/`id` fields. The earlier
|
|
1725
|
-
* implementation fingerprinted the full transparency snapshot (which embeds
|
|
1726
|
-
* the growing `versionHistory`), so the stored fingerprint of vN predated vN
|
|
1727
|
-
* and the next save's recomputed fingerprint always differed → unbounded
|
|
1728
|
-
* redundant publication versions (#1387 blocker).
|
|
1729
|
-
*
|
|
1730
|
-
* The surface mirrors `buildReviewFingerprint`'s content block, plus the
|
|
1731
|
-
* pinned reference edges (`{ targetId, targetVersion }`) — a pin change is a
|
|
1732
|
-
* meaningful republication — and the publication profile key.
|
|
1733
|
-
*/
|
|
1734
|
-
async buildPublicationSnapshotFingerprint(governance) {
|
|
1735
|
-
if (!governance.isGoverned || !governance.transparencyEnabled) return null;
|
|
1736
|
-
const referenceCollection = await this.getReferenceCollection();
|
|
1737
|
-
const [referenceEdges, facts, factLinks] = await Promise.all([
|
|
1738
|
-
this.id ? referenceCollection.getForSource(this.id) : Promise.resolve([]),
|
|
1739
|
-
governance.factLinkingEnabled ? this.getFacts({
|
|
1740
|
-
latestOnly: true,
|
|
1741
|
-
includeSuperseded: false
|
|
1742
|
-
}) : Promise.resolve([]),
|
|
1743
|
-
governance.factLinkingEnabled ? this.getFactLinks() : Promise.resolve([])
|
|
1744
|
-
]);
|
|
1745
|
-
return createFingerprint({
|
|
1746
|
-
scope: "content-publication",
|
|
1747
|
-
publicationProfileKey: governance.publicationProfileKey || null,
|
|
1748
|
-
content: {
|
|
1749
|
-
id: this.id || null,
|
|
1750
|
-
type: this.type,
|
|
1751
|
-
variant: this.variant,
|
|
1752
|
-
title: this.title,
|
|
1753
|
-
description: this.description,
|
|
1754
|
-
body: this.body,
|
|
1755
|
-
author: this.author,
|
|
1756
|
-
state: this.state,
|
|
1757
|
-
publishDate: this.publish_date,
|
|
1758
|
-
language: this.language,
|
|
1759
|
-
category: this.category,
|
|
1760
|
-
tags: this.tags,
|
|
1761
|
-
metadata: this.metadata
|
|
1762
|
-
},
|
|
1763
|
-
references: referenceEdges.map((edge) => ({
|
|
1764
|
-
targetId: edge.targetId || null,
|
|
1765
|
-
targetVersion: edge.targetVersion ?? null
|
|
1766
|
-
})).sort((a, b) => String(a.targetId).localeCompare(String(b.targetId))),
|
|
1767
|
-
facts: facts.map((fact) => ({
|
|
1768
|
-
id: fact.id || null,
|
|
1769
|
-
previousFactId: fact.previousFactId || null,
|
|
1770
|
-
status: fact.status || null,
|
|
1771
|
-
textRefined: fact.textRefined || "",
|
|
1772
|
-
sourceCount: fact.sourceCount ?? 0,
|
|
1773
|
-
confidence: fact.confidence ?? null,
|
|
1774
|
-
metadata: typeof fact?.getMetadata === "function" ? fact.getMetadata() : {}
|
|
1775
|
-
})).sort((a, b) => String(a.id).localeCompare(String(b.id))),
|
|
1776
|
-
factLinks: factLinks.map((link) => ({
|
|
1777
|
-
factId: link.factId || null,
|
|
1778
|
-
relationship: link.relationship || null,
|
|
1779
|
-
metadata: typeof link?.getMetadata === "function" ? link.getMetadata() : {}
|
|
1780
|
-
})).sort((a, b) => String(a.factId).localeCompare(String(b.factId)))
|
|
1781
|
-
});
|
|
1782
|
-
}
|
|
1783
|
-
async getLatestPublicationSnapshotFingerprint() {
|
|
1784
|
-
const latestPublicationVersion = [...await this.getVersions()].reverse().find((version) => version.kind === "publication");
|
|
1785
|
-
if (!latestPublicationVersion) return null;
|
|
1786
|
-
return latestPublicationVersion.getMetadata().publicationSnapshotFingerprint || null;
|
|
1787
|
-
}
|
|
1788
|
-
async buildCorrectionDraftSnapshot(options, replacementFactId) {
|
|
1789
|
-
const correctedText = options.correctedText || options.correctedFactText || "";
|
|
1790
|
-
const incorrectText = options.incorrectText || "";
|
|
1791
|
-
let body = this.body;
|
|
1792
|
-
let generationMethod = "metadata";
|
|
1793
|
-
if (incorrectText && correctedText && body.includes(incorrectText)) {
|
|
1794
|
-
body = body.replace(incorrectText, correctedText);
|
|
1795
|
-
generationMethod = "replace";
|
|
1796
|
-
} else if (correctedText) {
|
|
1797
|
-
const ai = this.ai;
|
|
1798
|
-
if (ai?.message) {
|
|
1799
|
-
const resolvedPrompt = await resolvePrompt(smrtContentApplyCorrectionPrompt.key, {
|
|
1800
|
-
db: this.options.db,
|
|
1801
|
-
tenantId: this.tenantId,
|
|
1802
|
-
variables: {
|
|
1803
|
-
body: this.body,
|
|
1804
|
-
correctedText,
|
|
1805
|
-
incorrectText: incorrectText || "Not provided",
|
|
1806
|
-
summary: options.summary || ""
|
|
1807
|
-
}
|
|
1808
|
-
});
|
|
1809
|
-
try {
|
|
1810
|
-
const proposedBody = (await ai.message(resolvedPrompt.text, promptMessageOptions(resolvedPrompt.ai))).trim();
|
|
1811
|
-
if (proposedBody) {
|
|
1812
|
-
body = proposedBody;
|
|
1813
|
-
generationMethod = "ai";
|
|
1814
|
-
}
|
|
1815
|
-
} catch {
|
|
1816
|
-
generationMethod = "metadata";
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1819
|
-
}
|
|
1820
|
-
return {
|
|
1821
|
-
snapshot: {
|
|
1822
|
-
title: this.title,
|
|
1823
|
-
description: this.description,
|
|
1824
|
-
body,
|
|
1825
|
-
status: "draft",
|
|
1826
|
-
metadata: {
|
|
1827
|
-
...this.metadata || {},
|
|
1828
|
-
governance: {
|
|
1829
|
-
...asRecord(this.metadata.governance),
|
|
1830
|
-
correctionDraft: {
|
|
1831
|
-
summary: options.summary,
|
|
1832
|
-
incorrectText,
|
|
1833
|
-
correctedText,
|
|
1834
|
-
factId: options.factId || null,
|
|
1835
|
-
replacementFactId: replacementFactId || null,
|
|
1836
|
-
autoGenerated: true,
|
|
1837
|
-
generationMethod
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
},
|
|
1842
|
-
metadata: {
|
|
1843
|
-
summary: options.summary,
|
|
1844
|
-
incorrectText,
|
|
1845
|
-
correctedText,
|
|
1846
|
-
factId: options.factId || null,
|
|
1847
|
-
replacementFactId: replacementFactId || null,
|
|
1848
|
-
autoGenerated: true,
|
|
1849
|
-
generationMethod
|
|
1850
|
-
}
|
|
1851
|
-
};
|
|
1852
|
-
}
|
|
1853
|
-
async getAssetCollection() {
|
|
1854
|
-
return AssetCollection.create({ db: this.db });
|
|
1855
|
-
}
|
|
1856
|
-
async getContentAssetCollection() {
|
|
1857
|
-
return ContentAssetCollection.create({ db: this.db });
|
|
1858
|
-
}
|
|
1859
|
-
async getContentAssetLinks(relationship) {
|
|
1860
|
-
if (!this.id) return [];
|
|
1861
|
-
try {
|
|
1862
|
-
return (await (await this.getContentAssetCollection()).byLeft(this.id, relationship ? { relationship } : {})).filter((link) => link.assetId).map((link) => ({
|
|
1863
|
-
assetId: link.assetId,
|
|
1864
|
-
sortOrder: link.sortOrder ?? 0
|
|
1865
|
-
}));
|
|
1866
|
-
} catch (error) {
|
|
1867
|
-
if (isMissingTableError(error, "content_assets")) return [];
|
|
1868
|
-
throw error;
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
async resolveAssetsForLinks(links) {
|
|
1872
|
-
if (links.length === 0) return [];
|
|
1873
|
-
const assetIds = [...new Set(links.map((link) => link.assetId))];
|
|
1874
|
-
const resolved = await (await this.getAssetCollection()).listByIds(assetIds);
|
|
1875
|
-
const assetsById = new Map(resolved.filter((asset) => asset.id).map((asset) => [asset.id, asset]));
|
|
1876
|
-
return links.map((link) => assetsById.get(link.assetId)).filter(Boolean);
|
|
1877
|
-
}
|
|
1878
|
-
async resolveReferenceTarget(content) {
|
|
1879
|
-
if (typeof content !== "string") return content;
|
|
1880
|
-
return await (await this.getContentsCollection()).getOrUpsert({
|
|
1881
|
-
url: content,
|
|
1882
|
-
tenantId: this.tenantId
|
|
1883
|
-
}, {
|
|
1884
|
-
name: content,
|
|
1885
|
-
title: content,
|
|
1886
|
-
type: "reference",
|
|
1887
|
-
tenantId: this.tenantId
|
|
1888
|
-
});
|
|
1889
|
-
}
|
|
1890
|
-
/**
|
|
1891
|
-
* Loads referenced content objects
|
|
1892
|
-
*
|
|
1893
|
-
* @returns Promise that resolves when references are loaded
|
|
1894
|
-
*/
|
|
1895
|
-
async loadReferences() {
|
|
1896
|
-
this.references = await this.getReferences();
|
|
1897
|
-
}
|
|
1898
|
-
getPendingReferenceIds() {
|
|
1899
|
-
const pendingReferenceIds = this.referenceIds;
|
|
1900
|
-
if (!Array.isArray(pendingReferenceIds)) return null;
|
|
1901
|
-
return [...new Set(pendingReferenceIds.filter((referenceId) => typeof referenceId === "string" && referenceId.length > 0 && referenceId !== this.id))];
|
|
1902
|
-
}
|
|
1903
|
-
getPendingAssetIds() {
|
|
1904
|
-
const pendingAssetIds = this.assetIds;
|
|
1905
|
-
if (!Array.isArray(pendingAssetIds)) return null;
|
|
1906
|
-
return [...new Set(pendingAssetIds.filter((assetId) => typeof assetId === "string" && assetId.length > 0))];
|
|
1907
|
-
}
|
|
1908
|
-
async syncPendingReferenceIds() {
|
|
1909
|
-
if (!this.id) return;
|
|
1910
|
-
const pendingReferenceIds = this.getPendingReferenceIds();
|
|
1911
|
-
if (pendingReferenceIds === null) return;
|
|
1912
|
-
const currentReferenceIds = (await this.getReferences()).map((reference) => reference.id).filter((referenceId) => Boolean(referenceId));
|
|
1913
|
-
const currentReferenceIdSet = new Set(currentReferenceIds);
|
|
1914
|
-
const pendingReferenceIdSet = new Set(pendingReferenceIds);
|
|
1915
|
-
for (const referenceId of currentReferenceIds) if (!pendingReferenceIdSet.has(referenceId)) await this.removeReference(referenceId);
|
|
1916
|
-
const referenceIdsToAdd = pendingReferenceIds.filter((referenceId) => !currentReferenceIdSet.has(referenceId));
|
|
1917
|
-
if (referenceIdsToAdd.length === 0) {
|
|
1918
|
-
this.references = await this.getReferences();
|
|
1919
|
-
return;
|
|
1920
|
-
}
|
|
1921
|
-
const resolvedReferences = await (await this.getContentsCollection()).listByIds(referenceIdsToAdd);
|
|
1922
|
-
const referencesById = new Map(resolvedReferences.filter((reference) => reference.id).map((reference) => [reference.id, reference]));
|
|
1923
|
-
for (const referenceId of referenceIdsToAdd) {
|
|
1924
|
-
const reference = referencesById.get(referenceId);
|
|
1925
|
-
if (reference) await this.addReference(reference);
|
|
1926
|
-
}
|
|
1927
|
-
this.references = await this.getReferences();
|
|
1928
|
-
}
|
|
1929
|
-
async syncPendingAssetIds() {
|
|
1930
|
-
if (!this.id) return;
|
|
1931
|
-
const pendingAssetIds = this.getPendingAssetIds();
|
|
1932
|
-
if (pendingAssetIds === null) return;
|
|
1933
|
-
const currentAssetIds = (await this.getAssets()).map((asset) => asset.id).filter((assetId) => Boolean(assetId));
|
|
1934
|
-
const currentAssetIdSet = new Set(currentAssetIds);
|
|
1935
|
-
const pendingAssetIdSet = new Set(pendingAssetIds);
|
|
1936
|
-
for (const assetId of currentAssetIds) if (!pendingAssetIdSet.has(assetId)) await this.removeAsset(assetId);
|
|
1937
|
-
const assetIdsToAdd = pendingAssetIds.filter((assetId) => !currentAssetIdSet.has(assetId));
|
|
1938
|
-
if (assetIdsToAdd.length === 0) return;
|
|
1939
|
-
const resolvedAssets = await (await this.getAssetCollection()).listByIds(assetIdsToAdd);
|
|
1940
|
-
const assetsById = new Map(resolvedAssets.filter((asset) => asset.id).map((asset) => [asset.id, asset]));
|
|
1941
|
-
for (const assetId of assetIdsToAdd) {
|
|
1942
|
-
const asset = assetsById.get(assetId);
|
|
1943
|
-
if (asset) await this.addAsset(asset);
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
/**
|
|
1947
|
-
* Adds a reference to another content object.
|
|
1948
|
-
*
|
|
1949
|
-
* @param content - Content object or URL to reference
|
|
1950
|
-
* @param options.targetVersion - Optional ContentVersion.version to pin the
|
|
1951
|
-
* citation to. Pass the target's current version (typically the latest
|
|
1952
|
-
* publication) to enable drift detection later. Pass `null` or omit to
|
|
1953
|
-
* leave the reference untracked.
|
|
1954
|
-
* @returns Promise that resolves when the reference is added
|
|
1955
|
-
*/
|
|
1956
|
-
async addReference(content, options = {}) {
|
|
1957
|
-
if (!this.id) throw new Error("Cannot add reference to unsaved content");
|
|
1958
|
-
const target = await this.resolveReferenceTarget(content);
|
|
1959
|
-
if (!target.id) throw new Error("Cannot add reference to unsaved content");
|
|
1960
|
-
if (this.id === target.id) return;
|
|
1961
|
-
await (await this.getReferenceCollection()).attach(this.id, target.id, {
|
|
1962
|
-
tenantId: this.tenantId,
|
|
1963
|
-
targetVersion: options.targetVersion
|
|
1964
|
-
});
|
|
1965
|
-
this.references = await this.getReferences();
|
|
1966
|
-
}
|
|
1967
|
-
/**
|
|
1968
|
-
* Removes a reference to another content object
|
|
1969
|
-
*
|
|
1970
|
-
* @param targetId - ID of the referenced content to remove
|
|
1971
|
-
*/
|
|
1972
|
-
async removeReference(targetId) {
|
|
1973
|
-
if (!this.id) return;
|
|
1974
|
-
await (await this.getReferenceCollection()).detach(this.id, targetId);
|
|
1975
|
-
this.references = this.references.filter((reference) => reference.id !== targetId);
|
|
1976
|
-
}
|
|
1977
|
-
/**
|
|
1978
|
-
* Gets all referenced content objects
|
|
1979
|
-
*
|
|
1980
|
-
* @returns Promise resolving to an array of referenced Content objects
|
|
1981
|
-
*/
|
|
1982
|
-
async getReferences() {
|
|
1983
|
-
if (!this.id) return [];
|
|
1984
|
-
const targetIds = (await (await this.getReferenceCollection()).byLeft(this.id)).map((reference) => reference.targetId);
|
|
1985
|
-
if (targetIds.length === 0) {
|
|
1986
|
-
this.references = [];
|
|
1987
|
-
return this.references;
|
|
1988
|
-
}
|
|
1989
|
-
const resolved = await (await this.getContentsCollection()).listByIds(targetIds);
|
|
1990
|
-
const referencesById = new Map(resolved.filter((content) => content.id).map((content) => [content.id, content]));
|
|
1991
|
-
this.references = targetIds.map((targetId) => referencesById.get(targetId)).filter(Boolean);
|
|
1992
|
-
return this.references;
|
|
1993
|
-
}
|
|
1994
|
-
/**
|
|
1995
|
-
* Returns the raw reference edges with their citation pins
|
|
1996
|
-
* (`{ targetId, targetVersion }`). Unlike `getReferences()` (which resolves
|
|
1997
|
-
* to `Content` objects and loses the per-edge `targetVersion`), this keeps
|
|
1998
|
-
* the pin so callers — notably version snapshots — can reconstruct pinned
|
|
1999
|
-
* citations on restore. See `ContentVersionCollection.restoreIntoContent`.
|
|
2000
|
-
*/
|
|
2001
|
-
async getReferenceEdges() {
|
|
2002
|
-
if (!this.id) return [];
|
|
2003
|
-
return (await (await this.getReferenceCollection()).getForSource(this.id)).filter((edge) => Boolean(edge.targetId)).map((edge) => ({
|
|
2004
|
-
targetId: edge.targetId,
|
|
2005
|
-
targetVersion: edge.targetVersion ?? null
|
|
2006
|
-
}));
|
|
2007
|
-
}
|
|
2008
|
-
/**
|
|
2009
|
-
* Returns one entry per reference edge with the pinned `targetVersion` and
|
|
2010
|
-
* the target's latest version. Drift exists when both are present and
|
|
2011
|
-
* differ — callers can use this to surface "the source you cited has been
|
|
2012
|
-
* updated" affordances in editors or review tools.
|
|
2013
|
-
*
|
|
2014
|
-
* `currentVersion` is the target's latest **publication** `ContentVersion`,
|
|
2015
|
-
* because pins are taken against the latest publication (see `addReference`).
|
|
2016
|
-
* Auto-created `correction`/`draft`/`manual` versions bump the shared
|
|
2017
|
-
* `(content_id, version)` counter but do NOT republish, so comparing against
|
|
2018
|
-
* the max version of *any* kind produced false drift positives (#1387 #4).
|
|
2019
|
-
*
|
|
2020
|
-
* Unpinned references (`citedVersion === null`) are included with
|
|
2021
|
-
* `currentVersion` populated when available so callers can choose to
|
|
2022
|
-
* surface them as "pinnable" suggestions.
|
|
2023
|
-
*/
|
|
2024
|
-
async getReferenceDrift() {
|
|
2025
|
-
if (!this.id) return [];
|
|
2026
|
-
const linkedReferences = await (await this.getReferenceCollection()).getForSource(this.id);
|
|
2027
|
-
if (linkedReferences.length === 0) return [];
|
|
2028
|
-
const versions = await this.getContentVersionCollection();
|
|
2029
|
-
const targetIds = linkedReferences.map((reference) => reference.targetId);
|
|
2030
|
-
const allVersions = await versions.list({
|
|
2031
|
-
where: {
|
|
2032
|
-
contentId: targetIds,
|
|
2033
|
-
kind: "publication"
|
|
2034
|
-
},
|
|
2035
|
-
orderBy: "version DESC"
|
|
2036
|
-
});
|
|
2037
|
-
const latestByContentId = /* @__PURE__ */ new Map();
|
|
2038
|
-
for (const version of allVersions) if (!latestByContentId.has(version.contentId)) latestByContentId.set(version.contentId, version.version);
|
|
2039
|
-
return linkedReferences.map((reference) => {
|
|
2040
|
-
const currentVersion = latestByContentId.get(reference.targetId) ?? null;
|
|
2041
|
-
const citedVersion = reference.targetVersion ?? null;
|
|
2042
|
-
return {
|
|
2043
|
-
targetId: reference.targetId,
|
|
2044
|
-
citedVersion,
|
|
2045
|
-
currentVersion,
|
|
2046
|
-
isDrifted: citedVersion !== null && currentVersion !== null && citedVersion !== currentVersion
|
|
2047
|
-
};
|
|
2048
|
-
});
|
|
2049
|
-
}
|
|
2050
|
-
isGoverned() {
|
|
2051
|
-
return this.getConfiguredGovernance().isGoverned;
|
|
2052
|
-
}
|
|
2053
|
-
async getFactLinks(options = {}) {
|
|
2054
|
-
const governance = await this.resolveGovernance();
|
|
2055
|
-
if (!governance.isGoverned || !governance.factLinkingEnabled || !this.id) return [];
|
|
2056
|
-
if (!this.id) return [];
|
|
2057
|
-
const links = await this.getFactContentCollection();
|
|
2058
|
-
return options.relationship ? links.byRight(this.id, { relationship: options.relationship }) : links.byRight(this.id);
|
|
2059
|
-
}
|
|
2060
|
-
async getFacts(options = {}) {
|
|
2061
|
-
const governance = await this.resolveGovernance();
|
|
2062
|
-
if (!governance.isGoverned || !governance.factLinkingEnabled || !this.id) return [];
|
|
2063
|
-
if (!this.id) return [];
|
|
2064
|
-
return (await this.getFactCollection()).getForContent(this.id, options);
|
|
2065
|
-
}
|
|
2066
|
-
async addFact(fact, relationship, metadata) {
|
|
2067
|
-
const governance = await this.requireFactLinking("fact association");
|
|
2068
|
-
if (!this.id) throw new Error("Cannot associate an unsaved content item with a fact");
|
|
2069
|
-
const factId = typeof fact === "string" ? fact : fact.id;
|
|
2070
|
-
if (!factId) throw new Error("Fact ID is required to create a content-fact link");
|
|
2071
|
-
return (await this.getFactContentCollection()).attach(factId, this.id, {
|
|
2072
|
-
relationship: relationship || governance.defaultFactRelationship,
|
|
2073
|
-
metadata
|
|
2074
|
-
});
|
|
2075
|
-
}
|
|
2076
|
-
async removeFact(factId, relationship) {
|
|
2077
|
-
const governance = await this.resolveGovernance();
|
|
2078
|
-
if (!governance.isGoverned || !governance.factLinkingEnabled) return;
|
|
2079
|
-
if (!this.id) return;
|
|
2080
|
-
const links = await this.getFactContentCollection();
|
|
2081
|
-
if (relationship) {
|
|
2082
|
-
await links.detach(factId, this.id, { relationship });
|
|
2083
|
-
return;
|
|
2084
|
-
}
|
|
2085
|
-
await links.detach(factId, this.id);
|
|
2086
|
-
}
|
|
2087
|
-
async syncFacts(factIds, relationship) {
|
|
2088
|
-
const governance = await this.requireFactLinking("fact sync");
|
|
2089
|
-
if (!this.id) throw new Error("Cannot sync facts for unsaved content");
|
|
2090
|
-
const uniqueFactIds = [...new Set(factIds.filter(Boolean))];
|
|
2091
|
-
const links = await this.getFactContentCollection();
|
|
2092
|
-
const resolvedRelationship = relationship || governance.defaultFactRelationship;
|
|
2093
|
-
const existing = await links.byRight(this.id, { relationship: resolvedRelationship });
|
|
2094
|
-
const existingIds = new Set(existing.map((link) => link.factId));
|
|
2095
|
-
const desiredIds = new Set(uniqueFactIds);
|
|
2096
|
-
const kept = uniqueFactIds.filter((factId) => existingIds.has(factId));
|
|
2097
|
-
const added = uniqueFactIds.filter((factId) => !existingIds.has(factId));
|
|
2098
|
-
const removed = existing.map((link) => link.factId).filter((factId) => !desiredIds.has(factId));
|
|
2099
|
-
for (const factId of added) await links.attach(factId, this.id, { relationship: resolvedRelationship });
|
|
2100
|
-
for (const factId of removed) await links.detach(factId, this.id, { relationship: resolvedRelationship });
|
|
2101
|
-
return {
|
|
2102
|
-
added,
|
|
2103
|
-
kept,
|
|
2104
|
-
removed
|
|
2105
|
-
};
|
|
2106
|
-
}
|
|
2107
|
-
async browseFacts(query = "", options = {}) {
|
|
2108
|
-
await this.requireFactLinking("fact catalog browsing");
|
|
2109
|
-
return (await this.getFactCollection()).browseCatalog(query, {
|
|
2110
|
-
...options,
|
|
2111
|
-
tenantId: this.tenantId
|
|
2112
|
-
});
|
|
2113
|
-
}
|
|
2114
|
-
async getFactAuditSourceMaterials() {
|
|
2115
|
-
const warnings = [];
|
|
2116
|
-
const sources = [];
|
|
2117
|
-
const references = await this.getReferences();
|
|
2118
|
-
const assets = await this.getAssets();
|
|
2119
|
-
for (const reference of references) {
|
|
2120
|
-
const referenceId = reference.id || "";
|
|
2121
|
-
const text = getContentText(reference);
|
|
2122
|
-
const referenceSourceUrl = reference.sourceUrl;
|
|
2123
|
-
const sourceUrl = normalizeAuditText(reference.url) || normalizeAuditText(referenceSourceUrl) || normalizeAuditText(reference.fileKey);
|
|
2124
|
-
const sourceTitle = normalizeAuditText(reference.title) || normalizeAuditText(reference.name) || sourceUrl || referenceId;
|
|
2125
|
-
if (!text) {
|
|
2126
|
-
warnings.push(`Reference ${sourceTitle || referenceId} has no extracted text.`);
|
|
2127
|
-
continue;
|
|
2128
|
-
}
|
|
2129
|
-
sources.push({
|
|
2130
|
-
sourceKind: "content-reference",
|
|
2131
|
-
sourceId: referenceId,
|
|
2132
|
-
sourceUrl,
|
|
2133
|
-
sourceTitle,
|
|
2134
|
-
locator: sourceTitle,
|
|
2135
|
-
text
|
|
2136
|
-
});
|
|
2137
|
-
}
|
|
2138
|
-
for (const asset of assets) {
|
|
2139
|
-
const metadata = typeof asset?.getMetadata === "function" ? asset.getMetadata() : parseAuditMetadata(asset?.metadata);
|
|
2140
|
-
const text = [
|
|
2141
|
-
metadata.extractedText,
|
|
2142
|
-
metadata.text,
|
|
2143
|
-
metadata.ocrText,
|
|
2144
|
-
asset?.text,
|
|
2145
|
-
asset?.body,
|
|
2146
|
-
asset?.description
|
|
2147
|
-
].map(normalizeAuditText).filter(Boolean).join("\n\n");
|
|
2148
|
-
const assetId = normalizeAuditText(asset?.id);
|
|
2149
|
-
const sourceTitle = normalizeAuditText(asset?.title) || normalizeAuditText(asset?.name) || normalizeAuditText(asset?.filename) || assetId;
|
|
2150
|
-
const sourceUrl = normalizeAuditText(asset?.url) || normalizeAuditText(asset?.sourceUrl) || normalizeAuditText(asset?.fileKey);
|
|
2151
|
-
if (!text) {
|
|
2152
|
-
warnings.push(`Asset ${sourceTitle || assetId} has no extracted text.`);
|
|
2153
|
-
continue;
|
|
2154
|
-
}
|
|
2155
|
-
sources.push({
|
|
2156
|
-
sourceKind: "asset",
|
|
2157
|
-
sourceId: assetId,
|
|
2158
|
-
sourceUrl,
|
|
2159
|
-
sourceTitle,
|
|
2160
|
-
locator: sourceTitle,
|
|
2161
|
-
text
|
|
2162
|
-
});
|
|
2163
|
-
}
|
|
2164
|
-
return {
|
|
2165
|
-
sources,
|
|
2166
|
-
warnings
|
|
2167
|
-
};
|
|
2168
|
-
}
|
|
2169
|
-
factMatchesTenant(fact) {
|
|
2170
|
-
return fact.tenantId === this.tenantId || fact.tenant_id === this.tenantId || !fact.tenantId && !fact.tenant_id && !this.tenantId;
|
|
2171
|
-
}
|
|
2172
|
-
async findExactArticleClaimFact(statement) {
|
|
2173
|
-
const normalizedStatement = normalizeAuditText(statement);
|
|
2174
|
-
const facts = await this.getFactCollection();
|
|
2175
|
-
const linkedMatch = (await Promise.all((await this.getFactLinks({ relationship: "referenced_in" })).map((link) => facts.get({ id: link.factId })))).find((fact) => Boolean(fact) && this.factMatchesTenant(fact) && normalizeAuditText(fact.textRefined) === normalizedStatement);
|
|
2176
|
-
if (linkedMatch) return linkedMatch;
|
|
2177
|
-
return (await facts.list({
|
|
2178
|
-
where: { textRefined: normalizedStatement },
|
|
2179
|
-
orderBy: "updated_at DESC"
|
|
2180
|
-
})).find((fact) => this.factMatchesTenant(fact) && this.id && isGeneratedArticleClaimFact(fact, this.id)) || null;
|
|
2181
|
-
}
|
|
2182
|
-
async safeAuditLink(factId, relationship, metadata) {
|
|
2183
|
-
const links = await this.getFactContentCollection();
|
|
2184
|
-
const existing = (await links.byRight(this.id, { relationship })).find((link) => link.factId === factId);
|
|
2185
|
-
if (existing) {
|
|
2186
|
-
const existingMetadata = getLinkMetadata(existing);
|
|
2187
|
-
if (existingMetadata.generatedBy === FACT_AUDIT_GENERATED_BY) existing.setMetadata?.({
|
|
2188
|
-
...existingMetadata,
|
|
2189
|
-
...metadata
|
|
2190
|
-
});
|
|
2191
|
-
else existing.setMetadata?.({
|
|
2192
|
-
...existingMetadata,
|
|
2193
|
-
factAudit: {
|
|
2194
|
-
...asRecord(existingMetadata.factAudit),
|
|
2195
|
-
...metadata
|
|
2196
|
-
}
|
|
2197
|
-
});
|
|
2198
|
-
await existing.save();
|
|
2199
|
-
return existing;
|
|
2200
|
-
}
|
|
2201
|
-
return links.attach(factId, this.id, {
|
|
2202
|
-
relationship,
|
|
2203
|
-
metadata
|
|
2204
|
-
});
|
|
2205
|
-
}
|
|
2206
|
-
async clearGeneratedFactAudit() {
|
|
2207
|
-
if (!this.id) return;
|
|
2208
|
-
const [links, evidences] = await Promise.all([this.getFactLinks(), this.getFactEvidenceCollection()]);
|
|
2209
|
-
for (const link of links) {
|
|
2210
|
-
const metadata = getLinkMetadata(link);
|
|
2211
|
-
const nestedFactAudit = asRecord(metadata.factAudit);
|
|
2212
|
-
if (metadata.generatedBy === FACT_AUDIT_GENERATED_BY) await link.delete();
|
|
2213
|
-
else if (metadata.factAudit && typeof metadata.factAudit === "object" && nestedFactAudit.generatedBy === FACT_AUDIT_GENERATED_BY) {
|
|
2214
|
-
const { factAudit: _removed, ...preservedMetadata } = metadata;
|
|
2215
|
-
link.setMetadata?.(preservedMetadata);
|
|
2216
|
-
await link.save();
|
|
2217
|
-
}
|
|
2218
|
-
}
|
|
2219
|
-
const generatedEvidence = await evidences.list({ where: { tenantId: this.tenantId ?? null } });
|
|
2220
|
-
for (const evidence of generatedEvidence) {
|
|
2221
|
-
const metadata = typeof evidence.getMetadata === "function" ? evidence.getMetadata() : {};
|
|
2222
|
-
if (metadata.generatedBy === FACT_AUDIT_GENERATED_BY && metadata.contentId === this.id) await evidence.delete();
|
|
2223
|
-
}
|
|
2224
|
-
}
|
|
2225
|
-
async clearGeneratedFactSourcesForSources(sources) {
|
|
2226
|
-
if (!this.id || sources.length === 0) return [];
|
|
2227
|
-
const sourceKeys = new Set(sources.map((source) => `${source.sourceKind}:${source.sourceId}`));
|
|
2228
|
-
const generatedSources = await (await this.getFactSourceCollection()).list({ where: { tenantId: this.tenantId ?? null } });
|
|
2229
|
-
const deletedSourceIds = [];
|
|
2230
|
-
for (const source of generatedSources) {
|
|
2231
|
-
const metadata = typeof source.getMetadata === "function" ? source.getMetadata() : {};
|
|
2232
|
-
const sourceKey = `${source.sourceType || ""}:${metadata.sourceId || ""}`;
|
|
2233
|
-
if (sourceKeys.has(sourceKey) && metadata.generatedBy === FACT_AUDIT_GENERATED_BY && metadata.contentId === this.id) {
|
|
2234
|
-
if (typeof source.id === "string") deletedSourceIds.push(source.id);
|
|
2235
|
-
await source.delete();
|
|
2236
|
-
}
|
|
2237
|
-
}
|
|
2238
|
-
return deletedSourceIds;
|
|
2239
|
-
}
|
|
2240
|
-
async extractReferenceFactsForAudit(sources, options) {
|
|
2241
|
-
const facts = await this.getFactCollection();
|
|
2242
|
-
const evidences = await this.getFactEvidenceCollection();
|
|
2243
|
-
const warnings = [];
|
|
2244
|
-
const referenceFacts = /* @__PURE__ */ new Map();
|
|
2245
|
-
let deletedEvidenceIds = [];
|
|
2246
|
-
let deletedSourceIds = [];
|
|
2247
|
-
if (options.replaceGenerated && sources.length > 0) {
|
|
2248
|
-
deletedEvidenceIds = (await evidences.replaceGeneratedForSources(sources.map((source) => ({
|
|
2249
|
-
sourceKind: source.sourceKind,
|
|
2250
|
-
sourceId: source.sourceId
|
|
2251
|
-
})), {
|
|
2252
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2253
|
-
contentId: this.id,
|
|
2254
|
-
tenantId: this.tenantId ?? null
|
|
2255
|
-
})).deletedEvidenceIds;
|
|
2256
|
-
deletedSourceIds = await this.clearGeneratedFactSourcesForSources(sources);
|
|
2257
|
-
}
|
|
2258
|
-
for (const source of sources) {
|
|
2259
|
-
let candidates = [];
|
|
2260
|
-
try {
|
|
2261
|
-
candidates = await facts.extractCandidatesFromText(source.text, {
|
|
2262
|
-
domain: FACT_AUDIT_DOMAIN,
|
|
2263
|
-
sourceType: source.sourceKind,
|
|
2264
|
-
context: options.context || source.sourceTitle,
|
|
2265
|
-
maxFacts: options.maxFactsPerSource ?? 24,
|
|
2266
|
-
tenantId: this.tenantId
|
|
2267
|
-
});
|
|
2268
|
-
} catch (error) {
|
|
2269
|
-
warnings.push(`Failed to extract facts from ${source.sourceTitle}: ${errorMessage(error)}`);
|
|
2270
|
-
continue;
|
|
2271
|
-
}
|
|
2272
|
-
for (const candidate of candidates) {
|
|
2273
|
-
const result = await facts.reconcile({
|
|
2274
|
-
rawInput: candidate.statement,
|
|
2275
|
-
type: candidate.type || "assertion",
|
|
2276
|
-
domain: FACT_AUDIT_DOMAIN,
|
|
2277
|
-
tenantId: this.tenantId,
|
|
2278
|
-
source: {
|
|
2279
|
-
sourceType: source.sourceKind,
|
|
2280
|
-
sourceUrl: source.sourceUrl,
|
|
2281
|
-
sourceTitle: source.sourceTitle,
|
|
2282
|
-
credibility: candidate.confidence ?? .75,
|
|
2283
|
-
metadata: {
|
|
2284
|
-
auditRunId: options.auditRunId,
|
|
2285
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2286
|
-
contentId: this.id,
|
|
2287
|
-
sourceId: source.sourceId,
|
|
2288
|
-
quote: candidate.sourceExcerpt || null,
|
|
2289
|
-
locator: source.locator || null
|
|
2290
|
-
}
|
|
2291
|
-
}
|
|
2292
|
-
});
|
|
2293
|
-
referenceFacts.set(result.fact.id, result.fact);
|
|
2294
|
-
await evidences.upsertEvidence({
|
|
2295
|
-
factId: result.fact.id,
|
|
2296
|
-
status: "supports",
|
|
2297
|
-
sourceKind: source.sourceKind,
|
|
2298
|
-
sourceId: source.sourceId,
|
|
2299
|
-
sourceUrl: source.sourceUrl,
|
|
2300
|
-
sourceTitle: source.sourceTitle,
|
|
2301
|
-
quote: candidate.sourceExcerpt || candidate.statement,
|
|
2302
|
-
locator: source.locator,
|
|
2303
|
-
extractionMethod: "ai-reference-fact",
|
|
2304
|
-
confidence: candidate.confidence ?? .75,
|
|
2305
|
-
tenantId: this.tenantId,
|
|
2306
|
-
metadata: {
|
|
2307
|
-
auditRunId: options.auditRunId,
|
|
2308
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2309
|
-
contentId: this.id,
|
|
2310
|
-
candidateMetadata: candidate.metadata || {}
|
|
2311
|
-
}
|
|
2312
|
-
});
|
|
2313
|
-
}
|
|
2314
|
-
}
|
|
2315
|
-
return {
|
|
2316
|
-
referenceFacts,
|
|
2317
|
-
warnings,
|
|
2318
|
-
referenceFactsExtracted: referenceFacts.size,
|
|
2319
|
-
deletedEvidenceIds,
|
|
2320
|
-
deletedSourceIds,
|
|
2321
|
-
repairedSources: sources.map((source) => ({
|
|
2322
|
-
sourceKind: source.sourceKind,
|
|
2323
|
-
sourceId: source.sourceId,
|
|
2324
|
-
sourceTitle: source.sourceTitle
|
|
2325
|
-
}))
|
|
2326
|
-
};
|
|
2327
|
-
}
|
|
2328
|
-
async getCurrentFactAuditSupportCandidates(options = {}) {
|
|
2329
|
-
const evidences = await this.getFactEvidenceCollection();
|
|
2330
|
-
const allFacts = await this.getFactCollection();
|
|
2331
|
-
const candidateFacts = /* @__PURE__ */ new Map();
|
|
2332
|
-
const candidateEvidence = /* @__PURE__ */ new Map();
|
|
2333
|
-
const sourceKeys = new Set((options.sources || []).map((source) => `${source.sourceKind}:${source.sourceId}`));
|
|
2334
|
-
const sourceIds = new Set(options.sourceIds || []);
|
|
2335
|
-
const maxCandidateEvidence = Math.max(1, options.maxCandidateEvidence ?? 120);
|
|
2336
|
-
const evidenceEntries = options.referenceFacts ? (await Promise.all([...options.referenceFacts.keys()].map((factId) => evidences.getForFact(factId)))).flat() : await evidences.list({ where: { tenantId: this.tenantId ?? null } });
|
|
2337
|
-
for (const entry of evidenceEntries) {
|
|
2338
|
-
if (!isGeneratedFactAuditEvidence(entry, this.id)) continue;
|
|
2339
|
-
if (entry.sourceKind === "content") continue;
|
|
2340
|
-
if (entry.status === "irrelevant" || entry.status === "invalid") continue;
|
|
2341
|
-
if (sourceKeys.size > 0 && !sourceKeys.has(`${entry.sourceKind}:${entry.sourceId}`)) continue;
|
|
2342
|
-
if (sourceIds.size > 0 && !sourceIds.has(entry.sourceId)) continue;
|
|
2343
|
-
if (candidateEvidence.size >= maxCandidateEvidence) break;
|
|
2344
|
-
const fact = options.referenceFacts?.get(entry.factId) || await allFacts.get({ id: entry.factId });
|
|
2345
|
-
if (!fact) continue;
|
|
2346
|
-
const factId = fact.id;
|
|
2347
|
-
const existing = candidateFacts.get(factId) || {
|
|
2348
|
-
id: factId,
|
|
2349
|
-
statement: fact.textRefined || fact.textRaw || "",
|
|
2350
|
-
evidence: []
|
|
2351
|
-
};
|
|
2352
|
-
const serializedEvidence = {
|
|
2353
|
-
id: entry.id || null,
|
|
2354
|
-
status: entry.status || "supports",
|
|
2355
|
-
quote: entry.quote || null,
|
|
2356
|
-
sourceTitle: entry.sourceTitle || null,
|
|
2357
|
-
sourceUrl: entry.sourceUrl || null,
|
|
2358
|
-
locator: entry.locator || null
|
|
2359
|
-
};
|
|
2360
|
-
existing.evidence.push(serializedEvidence);
|
|
2361
|
-
candidateFacts.set(factId, existing);
|
|
2362
|
-
if (typeof entry.id === "string") candidateEvidence.set(entry.id, entry);
|
|
2363
|
-
}
|
|
2364
|
-
return {
|
|
2365
|
-
supportCandidates: [...candidateFacts.values()],
|
|
2366
|
-
candidateFactIds: new Set(candidateFacts.keys()),
|
|
2367
|
-
candidateEvidence
|
|
2368
|
-
};
|
|
2369
|
-
}
|
|
2370
|
-
async repairFactAudit(options = {}) {
|
|
2371
|
-
await this.requireFactLinking("fact audit repair");
|
|
2372
|
-
if (!this.id) throw new Error("Cannot repair fact audit for unsaved content");
|
|
2373
|
-
const auditRunId = createFactAuditRunId(this.id);
|
|
2374
|
-
const facts = await this.getFactCollection();
|
|
2375
|
-
const evidences = await this.getFactEvidenceCollection();
|
|
2376
|
-
const warnings = [];
|
|
2377
|
-
const articleText = getContentText(this);
|
|
2378
|
-
const sourceMaterials = await this.getFactAuditSourceMaterials();
|
|
2379
|
-
warnings.push(...sourceMaterials.warnings);
|
|
2380
|
-
await this.clearGeneratedFactAudit();
|
|
2381
|
-
const referenceRepair = await this.extractReferenceFactsForAudit(sourceMaterials.sources, {
|
|
2382
|
-
auditRunId,
|
|
2383
|
-
maxFactsPerSource: options.maxReferenceFactsPerSource,
|
|
2384
|
-
context: options.context
|
|
2385
|
-
});
|
|
2386
|
-
warnings.push(...referenceRepair.warnings);
|
|
2387
|
-
const referenceFacts = referenceRepair.referenceFacts;
|
|
2388
|
-
let claims = [];
|
|
2389
|
-
if (!articleText) warnings.push("Article has no text to audit.");
|
|
2390
|
-
else try {
|
|
2391
|
-
claims = await facts.extractArticleClaims(articleText, {
|
|
2392
|
-
domain: FACT_AUDIT_DOMAIN,
|
|
2393
|
-
sourceType: "article",
|
|
2394
|
-
context: options.context || this.title || this.slug || "",
|
|
2395
|
-
maxFacts: options.maxArticleClaims ?? 32,
|
|
2396
|
-
tenantId: this.tenantId
|
|
2397
|
-
});
|
|
2398
|
-
} catch (error) {
|
|
2399
|
-
warnings.push(`Failed to extract article claims: ${errorMessage(error)}`);
|
|
2400
|
-
}
|
|
2401
|
-
const { supportCandidates, candidateFactIds, candidateEvidence } = await this.getCurrentFactAuditSupportCandidates({ referenceFacts });
|
|
2402
|
-
const findings = [];
|
|
2403
|
-
for (const claim of claims) {
|
|
2404
|
-
let assessment;
|
|
2405
|
-
try {
|
|
2406
|
-
assessment = await facts.assessClaimSupport(claim.statement, supportCandidates, { tenantId: this.tenantId });
|
|
2407
|
-
} catch (error) {
|
|
2408
|
-
warnings.push(`Failed to assess claim "${claim.statement}": ${errorMessage(error)}`);
|
|
2409
|
-
assessment = {
|
|
2410
|
-
status: "needs_review",
|
|
2411
|
-
matchedFactIds: [],
|
|
2412
|
-
matchedEvidenceIds: [],
|
|
2413
|
-
rationale: "Support assessment failed.",
|
|
2414
|
-
confidence: void 0
|
|
2415
|
-
};
|
|
2416
|
-
}
|
|
2417
|
-
const matchedFactIds = assessment.matchedFactIds.filter((factId) => candidateFactIds.has(factId));
|
|
2418
|
-
let claimFact = await this.findExactArticleClaimFact(claim.statement);
|
|
2419
|
-
if (!claimFact) claimFact = await facts.create({
|
|
2420
|
-
textRefined: claim.statement,
|
|
2421
|
-
textRaw: claim.statement,
|
|
2422
|
-
type: claim.type || "assertion",
|
|
2423
|
-
domain: FACT_AUDIT_DOMAIN,
|
|
2424
|
-
status: assessment.status === "unsupported" || assessment.status === "needs_review" ? "pending" : "active",
|
|
2425
|
-
sourceCount: 0,
|
|
2426
|
-
confidence: claim.confidence ?? assessment.confidence ?? .5,
|
|
2427
|
-
tenantId: this.tenantId,
|
|
2428
|
-
metadata: JSON.stringify({
|
|
2429
|
-
auditRunId,
|
|
2430
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2431
|
-
contentId: this.id,
|
|
2432
|
-
auditFactRole: "article-claim",
|
|
2433
|
-
claimOnly: matchedFactIds.length === 0
|
|
2434
|
-
})
|
|
2435
|
-
});
|
|
2436
|
-
else if (this.id && isGeneratedArticleClaimFact(claimFact, this.id)) {
|
|
2437
|
-
claimFact.status = assessment.status === "unsupported" || assessment.status === "needs_review" ? "pending" : "active";
|
|
2438
|
-
claimFact.confidence = claim.confidence ?? assessment.confidence ?? claimFact.confidence;
|
|
2439
|
-
claimFact.updateMetadata?.({
|
|
2440
|
-
auditRunId,
|
|
2441
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2442
|
-
contentId: this.id,
|
|
2443
|
-
auditFactRole: "article-claim",
|
|
2444
|
-
claimOnly: matchedFactIds.length === 0
|
|
2445
|
-
});
|
|
2446
|
-
await claimFact.save();
|
|
2447
|
-
}
|
|
2448
|
-
const articleEvidence = await evidences.upsertEvidence({
|
|
2449
|
-
factId: claimFact.id,
|
|
2450
|
-
status: "supports",
|
|
2451
|
-
sourceKind: "content",
|
|
2452
|
-
sourceId: this.id,
|
|
2453
|
-
sourceTitle: this.title || this.slug || this.id,
|
|
2454
|
-
quote: claim.sourceExcerpt || claim.statement,
|
|
2455
|
-
locator: this.title || this.slug || "",
|
|
2456
|
-
extractionMethod: "ai-article-claim",
|
|
2457
|
-
confidence: claim.confidence ?? assessment.confidence ?? .5,
|
|
2458
|
-
tenantId: this.tenantId,
|
|
2459
|
-
metadata: {
|
|
2460
|
-
auditRunId,
|
|
2461
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2462
|
-
contentId: this.id,
|
|
2463
|
-
supportStatus: assessment.status
|
|
2464
|
-
}
|
|
2465
|
-
});
|
|
2466
|
-
let supportingEvidenceIds = assessment.matchedEvidenceIds.filter((evidenceId) => candidateEvidence.has(evidenceId));
|
|
2467
|
-
for (const matchedFactId of matchedFactIds) {
|
|
2468
|
-
if (supportingEvidenceIds.length > 0) continue;
|
|
2469
|
-
const candidate = supportCandidates.find((entry) => entry.id === matchedFactId);
|
|
2470
|
-
supportingEvidenceIds = [...supportingEvidenceIds, ...(candidate?.evidence || []).map((entry) => entry.id).filter((id) => typeof id === "string")];
|
|
2471
|
-
}
|
|
2472
|
-
supportingEvidenceIds = [...new Set(supportingEvidenceIds)];
|
|
2473
|
-
const linkMetadata = {
|
|
2474
|
-
auditRunId,
|
|
2475
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2476
|
-
supportStatus: assessment.status,
|
|
2477
|
-
claimQuote: claim.sourceExcerpt || claim.statement,
|
|
2478
|
-
claimFactId: claimFact.id,
|
|
2479
|
-
articleEvidenceId: articleEvidence.id || null,
|
|
2480
|
-
supportingFactIds: matchedFactIds,
|
|
2481
|
-
supportingEvidenceIds,
|
|
2482
|
-
rationale: assessment.rationale,
|
|
2483
|
-
confidence: assessment.confidence ?? claim.confidence ?? null
|
|
2484
|
-
};
|
|
2485
|
-
await this.safeAuditLink(claimFact.id, "referenced_in", linkMetadata);
|
|
2486
|
-
for (const matchedFactId of matchedFactIds) await this.safeAuditLink(matchedFactId, assessment.status === "contradicted" ? "contradicts" : "supports", {
|
|
2487
|
-
...linkMetadata,
|
|
2488
|
-
supportingEvidenceIds
|
|
2489
|
-
});
|
|
2490
|
-
if (assessment.status !== "supported") findings.push({
|
|
2491
|
-
severity: assessment.status === "contradicted" ? "error" : "warning",
|
|
2492
|
-
title: assessment.status === "contradicted" ? "Contradicted article claim" : "Unsupported article claim",
|
|
2493
|
-
detail: assessment.rationale || "The claim needs editorial review.",
|
|
2494
|
-
factId: claimFact.id,
|
|
2495
|
-
quote: claim.sourceExcerpt || claim.statement,
|
|
2496
|
-
ruleId: "fact-audit"
|
|
2497
|
-
});
|
|
2498
|
-
}
|
|
2499
|
-
await (await this.getContentReviewCollection()).createFromResult({
|
|
2500
|
-
contentId: this.id,
|
|
2501
|
-
kind: "facts",
|
|
2502
|
-
policyKey: "facts",
|
|
2503
|
-
reviewer: "system",
|
|
2504
|
-
result: {
|
|
2505
|
-
status: findings.length > 0 ? "flagged" : "passed",
|
|
2506
|
-
summary: findings.length > 0 ? `${findings.length} article claim(s) need review.` : "Article claims are supported by available evidence.",
|
|
2507
|
-
findings
|
|
2508
|
-
},
|
|
2509
|
-
metadata: {
|
|
2510
|
-
auditRunId,
|
|
2511
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2512
|
-
warnings
|
|
2513
|
-
},
|
|
2514
|
-
tenantId: this.tenantId
|
|
2515
|
-
});
|
|
2516
|
-
return {
|
|
2517
|
-
...await this.getFactAuditState(),
|
|
2518
|
-
repair: {
|
|
2519
|
-
auditRunId,
|
|
2520
|
-
claimsExtracted: claims.length,
|
|
2521
|
-
referenceFactsExtracted: referenceRepair.referenceFactsExtracted,
|
|
2522
|
-
warnings
|
|
2523
|
-
}
|
|
2524
|
-
};
|
|
2525
|
-
}
|
|
2526
|
-
async repairFactAuditAction(options = {}) {
|
|
2527
|
-
return this.repairFactAudit(options);
|
|
2528
|
-
}
|
|
2529
|
-
async repairFactEvidence(options = {}) {
|
|
2530
|
-
await this.requireFactLinking("fact evidence repair");
|
|
2531
|
-
if (!this.id) throw new Error("Cannot repair fact evidence for unsaved content");
|
|
2532
|
-
const auditRunId = createFactAuditRunId(this.id);
|
|
2533
|
-
const sources = filterAuditSources((await this.getFactAuditSourceMaterials()).sources, options.sources);
|
|
2534
|
-
const warnings = [];
|
|
2535
|
-
if (options.sources?.length && sources.length === 0) warnings.push("No matching resource text was available for repair.");
|
|
2536
|
-
const repair = await this.extractReferenceFactsForAudit(sources, {
|
|
2537
|
-
auditRunId,
|
|
2538
|
-
maxFactsPerSource: options.maxFactsPerSource,
|
|
2539
|
-
context: options.context,
|
|
2540
|
-
replaceGenerated: true
|
|
2541
|
-
});
|
|
2542
|
-
warnings.push(...repair.warnings);
|
|
2543
|
-
return {
|
|
2544
|
-
...await this.getFactAuditState(),
|
|
2545
|
-
evidenceRepair: {
|
|
2546
|
-
auditRunId,
|
|
2547
|
-
referenceFactsExtracted: repair.referenceFactsExtracted,
|
|
2548
|
-
repairedSources: repair.repairedSources,
|
|
2549
|
-
deletedEvidenceIds: repair.deletedEvidenceIds,
|
|
2550
|
-
deletedSourceIds: repair.deletedSourceIds,
|
|
2551
|
-
warnings
|
|
2552
|
-
}
|
|
2553
|
-
};
|
|
2554
|
-
}
|
|
2555
|
-
async repairFactEvidenceAction(options = {}) {
|
|
2556
|
-
return this.repairFactEvidence(options);
|
|
2557
|
-
}
|
|
2558
|
-
async clearGeneratedSupportLinksForClaim(claimFactId, articleEvidenceId) {
|
|
2559
|
-
const links = await this.getFactLinks();
|
|
2560
|
-
for (const link of links) {
|
|
2561
|
-
if (link.relationship !== "supports" && link.relationship !== "contradicts") continue;
|
|
2562
|
-
const metadata = getGeneratedFactAuditMetadata(link);
|
|
2563
|
-
if (!metadata) continue;
|
|
2564
|
-
const matchesEvidence = articleEvidenceId && typeof metadata.articleEvidenceId === "string" && metadata.articleEvidenceId === articleEvidenceId;
|
|
2565
|
-
const matchesClaim = typeof metadata.claimFactId === "string" && metadata.claimFactId === claimFactId;
|
|
2566
|
-
if (matchesEvidence || matchesClaim) await link.delete();
|
|
2567
|
-
}
|
|
2568
|
-
}
|
|
2569
|
-
async recheckFactClaims(options = {}) {
|
|
2570
|
-
await this.requireFactLinking("claim support recheck");
|
|
2571
|
-
if (!this.id) throw new Error("Cannot recheck fact claims for unsaved content");
|
|
2572
|
-
const auditRunId = createFactAuditRunId(this.id);
|
|
2573
|
-
const facts = await this.getFactCollection();
|
|
2574
|
-
const evidences = await this.getFactEvidenceCollection();
|
|
2575
|
-
const links = await this.getFactContentCollection();
|
|
2576
|
-
const claimIdFilter = new Set(options.claimFactIds || []);
|
|
2577
|
-
const { supportCandidates, candidateFactIds, candidateEvidence } = await this.getCurrentFactAuditSupportCandidates({
|
|
2578
|
-
sources: options.sources,
|
|
2579
|
-
sourceIds: options.sourceIds,
|
|
2580
|
-
maxCandidateEvidence: options.maxCandidateEvidence
|
|
2581
|
-
});
|
|
2582
|
-
const claimLinks = (await links.byRight(this.id, { relationship: "referenced_in" })).map((link) => ({
|
|
2583
|
-
link,
|
|
2584
|
-
metadata: getGeneratedFactAuditMetadata(link)
|
|
2585
|
-
})).filter((entry) => entry.metadata !== null && (claimIdFilter.size === 0 || claimIdFilter.has(entry.link.factId)));
|
|
2586
|
-
const warnings = [];
|
|
2587
|
-
let recheckedClaims = 0;
|
|
2588
|
-
for (const { link, metadata } of claimLinks) {
|
|
2589
|
-
const claimFact = await facts.get({ id: link.factId });
|
|
2590
|
-
if (!claimFact) continue;
|
|
2591
|
-
const claimText = normalizeAuditText(metadata.claimQuote) || normalizeAuditText(claimFact.textRefined) || normalizeAuditText(claimFact.textRaw);
|
|
2592
|
-
if (!claimText) continue;
|
|
2593
|
-
let assessment;
|
|
2594
|
-
try {
|
|
2595
|
-
assessment = await facts.assessClaimSupport(claimText, supportCandidates, { tenantId: this.tenantId });
|
|
2596
|
-
} catch (error) {
|
|
2597
|
-
warnings.push(`Failed to recheck claim "${claimText}": ${errorMessage(error)}`);
|
|
2598
|
-
assessment = {
|
|
2599
|
-
status: "needs_review",
|
|
2600
|
-
matchedFactIds: [],
|
|
2601
|
-
matchedEvidenceIds: [],
|
|
2602
|
-
rationale: "Support assessment failed.",
|
|
2603
|
-
confidence: void 0
|
|
2604
|
-
};
|
|
2605
|
-
}
|
|
2606
|
-
const matchedFactIds = assessment.matchedFactIds.filter((factId) => candidateFactIds.has(factId));
|
|
2607
|
-
let supportStatus = assessment.status;
|
|
2608
|
-
if ((supportStatus === "supported" || supportStatus === "contradicted") && matchedFactIds.length === 0) supportStatus = "needs_review";
|
|
2609
|
-
let supportingEvidenceIds = assessment.matchedEvidenceIds.filter((evidenceId) => candidateEvidence.has(evidenceId));
|
|
2610
|
-
if (supportingEvidenceIds.length === 0) for (const matchedFactId of matchedFactIds) {
|
|
2611
|
-
const candidate = supportCandidates.find((entry) => entry.id === matchedFactId);
|
|
2612
|
-
supportingEvidenceIds.push(...(candidate?.evidence || []).map((entry) => entry.id).filter((id) => typeof id === "string"));
|
|
2613
|
-
}
|
|
2614
|
-
supportingEvidenceIds = [...new Set(supportingEvidenceIds)];
|
|
2615
|
-
const articleEvidenceId = typeof metadata.articleEvidenceId === "string" ? metadata.articleEvidenceId : null;
|
|
2616
|
-
const nextMetadata = {
|
|
2617
|
-
...metadata,
|
|
2618
|
-
auditRunId,
|
|
2619
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2620
|
-
supportStatus,
|
|
2621
|
-
supportingFactIds: matchedFactIds,
|
|
2622
|
-
supportingEvidenceIds,
|
|
2623
|
-
rationale: assessment.rationale,
|
|
2624
|
-
confidence: assessment.confidence ?? metadata.confidence ?? null,
|
|
2625
|
-
claimFactId: link.factId
|
|
2626
|
-
};
|
|
2627
|
-
const existingMetadata = getLinkMetadata(link);
|
|
2628
|
-
if (existingMetadata.generatedBy === FACT_AUDIT_GENERATED_BY) link.setMetadata?.(nextMetadata);
|
|
2629
|
-
else link.setMetadata?.({
|
|
2630
|
-
...existingMetadata,
|
|
2631
|
-
factAudit: nextMetadata
|
|
2632
|
-
});
|
|
2633
|
-
await link.save();
|
|
2634
|
-
if (articleEvidenceId) {
|
|
2635
|
-
const articleEvidence = await evidences.get({ id: articleEvidenceId });
|
|
2636
|
-
if (articleEvidence) {
|
|
2637
|
-
articleEvidence.updateMetadata({
|
|
2638
|
-
auditRunId,
|
|
2639
|
-
supportStatus
|
|
2640
|
-
});
|
|
2641
|
-
await articleEvidence.save();
|
|
2642
|
-
}
|
|
2643
|
-
}
|
|
2644
|
-
await this.clearGeneratedSupportLinksForClaim(link.factId, articleEvidenceId);
|
|
2645
|
-
for (const matchedFactId of matchedFactIds) await this.safeAuditLink(matchedFactId, supportStatus === "contradicted" ? "contradicts" : "supports", {
|
|
2646
|
-
...nextMetadata,
|
|
2647
|
-
articleEvidenceId
|
|
2648
|
-
});
|
|
2649
|
-
recheckedClaims += 1;
|
|
2650
|
-
}
|
|
2651
|
-
return {
|
|
2652
|
-
...await this.getFactAuditState(),
|
|
2653
|
-
claimRecheck: {
|
|
2654
|
-
auditRunId,
|
|
2655
|
-
recheckedClaims,
|
|
2656
|
-
candidateFacts: supportCandidates.length,
|
|
2657
|
-
candidateEvidence: candidateEvidence.size,
|
|
2658
|
-
warnings
|
|
2659
|
-
}
|
|
2660
|
-
};
|
|
2661
|
-
}
|
|
2662
|
-
async recheckFactClaimsAction(options = {}) {
|
|
2663
|
-
return this.recheckFactClaims(options);
|
|
2664
|
-
}
|
|
2665
|
-
async updateFactEvidenceStatus(options = {}) {
|
|
2666
|
-
await this.requireFactLinking("evidence status update");
|
|
2667
|
-
if (!this.id) throw new Error("Cannot update fact evidence for unsaved content");
|
|
2668
|
-
const status = normalizeFactEvidenceStatus(options.status);
|
|
2669
|
-
if (!status) throw new Error("A valid evidence status is required");
|
|
2670
|
-
const requestedEvidenceIds = [...new Set((options.evidenceIds || []).filter((id) => typeof id === "string" && id.length > 0))];
|
|
2671
|
-
const evidences = await this.getFactEvidenceCollection();
|
|
2672
|
-
const sourceMaterials = await this.getFactAuditSourceMaterials();
|
|
2673
|
-
const allowedSourceKeys = new Set(sourceMaterials.sources.map((source) => `${source.sourceKind}:${source.sourceId}`));
|
|
2674
|
-
const allowedEvidenceIds = [];
|
|
2675
|
-
for (const evidenceId of requestedEvidenceIds) {
|
|
2676
|
-
const evidence = await evidences.get({ id: evidenceId });
|
|
2677
|
-
if (!evidence) continue;
|
|
2678
|
-
if (this.tenantId && evidence.tenantId && evidence.tenantId !== this.tenantId) continue;
|
|
2679
|
-
const metadata = getEvidenceMetadata(evidence);
|
|
2680
|
-
const sourceKey = `${evidence.sourceKind || ""}:${evidence.sourceId || ""}`;
|
|
2681
|
-
if (metadata.contentId === this.id || evidence.sourceKind === "content" && evidence.sourceId === this.id || allowedSourceKeys.has(sourceKey)) allowedEvidenceIds.push(evidenceId);
|
|
2682
|
-
}
|
|
2683
|
-
const updated = await evidences.bulkUpdateStatus(allowedEvidenceIds, status, { reason: options.reason });
|
|
2684
|
-
return {
|
|
2685
|
-
...await this.getFactAuditState(),
|
|
2686
|
-
evidenceStatusUpdate: {
|
|
2687
|
-
status,
|
|
2688
|
-
requestedEvidenceIds,
|
|
2689
|
-
updatedEvidenceIds: updated.map((entry) => entry.id).filter((id) => typeof id === "string"),
|
|
2690
|
-
skippedEvidenceIds: requestedEvidenceIds.filter((id) => !allowedEvidenceIds.includes(id))
|
|
2691
|
-
}
|
|
2692
|
-
};
|
|
2693
|
-
}
|
|
2694
|
-
async updateFactEvidenceStatusAction(options = {}) {
|
|
2695
|
-
return this.updateFactEvidenceStatus(options);
|
|
2696
|
-
}
|
|
2697
|
-
async getFactAuditState() {
|
|
2698
|
-
if (!this.id) return {
|
|
2699
|
-
counts: {
|
|
2700
|
-
total: 0,
|
|
2701
|
-
supported: 0,
|
|
2702
|
-
unsupported: 0,
|
|
2703
|
-
contradicted: 0,
|
|
2704
|
-
needs_review: 0
|
|
2705
|
-
},
|
|
2706
|
-
claims: [],
|
|
2707
|
-
resourceClaims: [],
|
|
2708
|
-
warnings: [],
|
|
2709
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2710
|
-
latestAuditRunId: null
|
|
2711
|
-
};
|
|
2712
|
-
const [facts, factLinks] = await Promise.all([this.getFacts({
|
|
2713
|
-
relationship: "referenced_in",
|
|
2714
|
-
latestOnly: false,
|
|
2715
|
-
includeSuperseded: false
|
|
2716
|
-
}), this.getFactLinks({ relationship: "referenced_in" })]);
|
|
2717
|
-
const factMap = new Map(facts.filter((fact) => fact.id).map((fact) => [fact.id, fact]));
|
|
2718
|
-
const evidences = await this.getFactEvidenceCollection();
|
|
2719
|
-
const allFacts = await this.getFactCollection();
|
|
2720
|
-
const generatedLinks = factLinks.map((link) => ({
|
|
2721
|
-
link,
|
|
2722
|
-
metadata: getGeneratedFactAuditMetadata(link)
|
|
2723
|
-
})).filter((entry) => entry.metadata !== null);
|
|
2724
|
-
const claims = [];
|
|
2725
|
-
const resourceClaimsByKey = /* @__PURE__ */ new Map();
|
|
2726
|
-
const warnings = [];
|
|
2727
|
-
let latestAuditRunId = null;
|
|
2728
|
-
for (const { link, metadata } of generatedLinks) {
|
|
2729
|
-
const fact = factMap.get(link.factId);
|
|
2730
|
-
if (!fact) continue;
|
|
2731
|
-
latestAuditRunId = metadata.auditRunId || latestAuditRunId;
|
|
2732
|
-
const status = metadata.supportStatus || "needs_review";
|
|
2733
|
-
const matchedFactIds = Array.isArray(metadata.supportingFactIds) ? metadata.supportingFactIds : [];
|
|
2734
|
-
const articleEvidenceId = typeof metadata.articleEvidenceId === "string" ? metadata.articleEvidenceId : null;
|
|
2735
|
-
const supportingEvidenceIds = new Set(Array.isArray(metadata.supportingEvidenceIds) ? metadata.supportingEvidenceIds.filter((id) => typeof id === "string") : []);
|
|
2736
|
-
const [allClaimEvidence, matchedFacts] = await Promise.all([evidences.getForFact(fact.id), Promise.all(matchedFactIds.map(async (factId) => {
|
|
2737
|
-
const matchedFact = await allFacts.get({ id: factId });
|
|
2738
|
-
const matchedEvidence = (await evidences.getForFact(factId)).filter((entry) => supportingEvidenceIds.size === 0 ? entry.sourceKind !== "content" || entry.sourceId !== this.id : supportingEvidenceIds.has(entry.id));
|
|
2739
|
-
return matchedFact ? {
|
|
2740
|
-
fact: serializeFact(matchedFact),
|
|
2741
|
-
evidence: matchedEvidence.map((entry) => ({
|
|
2742
|
-
...serializeFact(entry),
|
|
2743
|
-
metadata: typeof entry.getMetadata === "function" ? entry.getMetadata() : {}
|
|
2744
|
-
}))
|
|
2745
|
-
} : null;
|
|
2746
|
-
}))]);
|
|
2747
|
-
const claimEvidence = allClaimEvidence.filter((entry) => articleEvidenceId ? entry.id === articleEvidenceId : entry.sourceKind === "content" && entry.sourceId === this.id);
|
|
2748
|
-
claims.push({
|
|
2749
|
-
id: fact.id,
|
|
2750
|
-
fact: serializeFact(fact),
|
|
2751
|
-
supportStatus: status,
|
|
2752
|
-
claimQuote: metadata.claimQuote || null,
|
|
2753
|
-
rationale: metadata.rationale || null,
|
|
2754
|
-
confidence: metadata.confidence ?? null,
|
|
2755
|
-
relationship: link.relationship || null,
|
|
2756
|
-
linkMetadata: metadata,
|
|
2757
|
-
evidence: claimEvidence.map((entry) => ({
|
|
2758
|
-
...serializeFact(entry),
|
|
2759
|
-
metadata: typeof entry.getMetadata === "function" ? entry.getMetadata() : {}
|
|
2760
|
-
})),
|
|
2761
|
-
matchedFacts: matchedFacts.filter(Boolean)
|
|
2762
|
-
});
|
|
2763
|
-
}
|
|
2764
|
-
const generatedEvidence = await evidences.list({ where: { tenantId: this.tenantId ?? null } });
|
|
2765
|
-
for (const evidence of generatedEvidence) {
|
|
2766
|
-
const metadata = typeof evidence.getMetadata === "function" ? evidence.getMetadata() : {};
|
|
2767
|
-
if (metadata.generatedBy !== FACT_AUDIT_GENERATED_BY || metadata.contentId !== this.id || evidence.sourceKind === "content") continue;
|
|
2768
|
-
const fact = await allFacts.get({ id: evidence.factId });
|
|
2769
|
-
if (!fact) continue;
|
|
2770
|
-
const key = [
|
|
2771
|
-
evidence.factId,
|
|
2772
|
-
evidence.sourceKind,
|
|
2773
|
-
evidence.sourceId,
|
|
2774
|
-
evidence.evidenceKey
|
|
2775
|
-
].join(":");
|
|
2776
|
-
const serializedEvidence = {
|
|
2777
|
-
...serializeFact(evidence),
|
|
2778
|
-
metadata
|
|
2779
|
-
};
|
|
2780
|
-
const existing = resourceClaimsByKey.get(key);
|
|
2781
|
-
if (existing) {
|
|
2782
|
-
existing.evidence.push(serializedEvidence);
|
|
2783
|
-
continue;
|
|
2784
|
-
}
|
|
2785
|
-
resourceClaimsByKey.set(key, {
|
|
2786
|
-
id: fact.id,
|
|
2787
|
-
fact: serializeFact(fact),
|
|
2788
|
-
sourceKind: evidence.sourceKind || null,
|
|
2789
|
-
sourceId: evidence.sourceId || null,
|
|
2790
|
-
sourceUrl: evidence.sourceUrl || null,
|
|
2791
|
-
sourceTitle: evidence.sourceTitle || null,
|
|
2792
|
-
locator: evidence.locator || null,
|
|
2793
|
-
quote: evidence.quote || null,
|
|
2794
|
-
status: evidence.status || "supports",
|
|
2795
|
-
confidence: evidence.confidence ?? null,
|
|
2796
|
-
evidence: [serializedEvidence]
|
|
2797
|
-
});
|
|
2798
|
-
}
|
|
2799
|
-
const review = await (await this.getContentReviewCollection()).getLatestForPolicyKey(this.id, "facts");
|
|
2800
|
-
const reviewMetadata = review && typeof review.getMetadata === "function" ? review.getMetadata() : {};
|
|
2801
|
-
if (reviewMetadata.generatedBy === FACT_AUDIT_GENERATED_BY && Array.isArray(reviewMetadata.warnings)) warnings.push(...reviewMetadata.warnings);
|
|
2802
|
-
const counts = {
|
|
2803
|
-
total: claims.length,
|
|
2804
|
-
supported: 0,
|
|
2805
|
-
unsupported: 0,
|
|
2806
|
-
contradicted: 0,
|
|
2807
|
-
needs_review: 0
|
|
2808
|
-
};
|
|
2809
|
-
for (const claim of claims) counts[claim.supportStatus] += 1;
|
|
2810
|
-
return {
|
|
2811
|
-
counts,
|
|
2812
|
-
claims,
|
|
2813
|
-
resourceClaims: [...resourceClaimsByKey.values()],
|
|
2814
|
-
warnings,
|
|
2815
|
-
generatedBy: FACT_AUDIT_GENERATED_BY,
|
|
2816
|
-
latestAuditRunId
|
|
2817
|
-
};
|
|
2818
|
-
}
|
|
2819
|
-
async getFactAuditStateAction() {
|
|
2820
|
-
return this.getFactAuditState();
|
|
2821
|
-
}
|
|
2822
|
-
async getFactsState(options = {}) {
|
|
2823
|
-
const governance = await this.resolveGovernance();
|
|
2824
|
-
if (!governance.isGoverned || !governance.factLinkingEnabled) return {
|
|
2825
|
-
factIds: [],
|
|
2826
|
-
facts: [],
|
|
2827
|
-
factLinks: []
|
|
2828
|
-
};
|
|
2829
|
-
const relationship = options.relationship;
|
|
2830
|
-
const [facts, factLinks] = await Promise.all([this.getFacts({
|
|
2831
|
-
relationship,
|
|
2832
|
-
latestOnly: true,
|
|
2833
|
-
includeSuperseded: false
|
|
2834
|
-
}), this.getFactLinks(relationship ? { relationship } : {})]);
|
|
2835
|
-
return {
|
|
2836
|
-
factIds: facts.map((fact) => fact.id).filter(Boolean),
|
|
2837
|
-
facts: facts.map(serializeFact),
|
|
2838
|
-
factLinks: factLinks.map(serializeFactLink)
|
|
2839
|
-
};
|
|
2840
|
-
}
|
|
2841
|
-
async syncFactsState(options = {}) {
|
|
2842
|
-
const governance = await this.requireFactLinking("fact sync");
|
|
2843
|
-
const relationship = options.relationship || governance.defaultFactRelationship;
|
|
2844
|
-
const sync = await this.syncFacts(options.factIds || [], relationship);
|
|
2845
|
-
return {
|
|
2846
|
-
...await this.getFactsState({ relationship }),
|
|
2847
|
-
sync
|
|
2848
|
-
};
|
|
2849
|
-
}
|
|
2850
|
-
async createVersion(options = {}) {
|
|
2851
|
-
return (await this.getContentVersionCollection()).createSnapshot(this, options);
|
|
2852
|
-
}
|
|
2853
|
-
async getVersions() {
|
|
2854
|
-
if (!this.id) return [];
|
|
2855
|
-
return (await this.getContentVersionCollection()).listForContent(this.id);
|
|
2856
|
-
}
|
|
2857
|
-
async restoreFromVersion(versionNumber) {
|
|
2858
|
-
return (await this.getContentVersionCollection()).restoreIntoContent(this, versionNumber);
|
|
2859
|
-
}
|
|
2860
|
-
async getReviews(kind) {
|
|
2861
|
-
if (!this.id) return [];
|
|
2862
|
-
return (await this.getContentReviewCollection()).listForContent(this.id, kind);
|
|
2863
|
-
}
|
|
2864
|
-
async listReviews(options = {}) {
|
|
2865
|
-
return (await this.getReviews(options.kind)).map(serializeContentReview);
|
|
2866
|
-
}
|
|
2867
|
-
async getReviewRequirements(profileKey, governance) {
|
|
2868
|
-
return getContentReviewRequirements(profileKey, (governance || await this.resolveGovernance()).availableProfiles);
|
|
2869
|
-
}
|
|
2870
|
-
async getGovernanceState() {
|
|
2871
|
-
const governance = await this.resolveGovernance();
|
|
2872
|
-
if (!governance.isGoverned) return {
|
|
2873
|
-
...governance,
|
|
2874
|
-
reviewProfiles: []
|
|
2875
|
-
};
|
|
2876
|
-
return {
|
|
2877
|
-
...governance,
|
|
2878
|
-
reviewProfiles: await this.listReviewProfilesAction()
|
|
2879
|
-
};
|
|
2880
|
-
}
|
|
2881
|
-
async getGovernanceStateAction() {
|
|
2882
|
-
return this.getGovernanceState();
|
|
2883
|
-
}
|
|
2884
|
-
async listReviewProfilesAction() {
|
|
2885
|
-
const governance = await this.resolveGovernance();
|
|
2886
|
-
if (!governance.isGoverned) return [];
|
|
2887
|
-
return Promise.all(getContentReviewProfileKeys(governance.availableProfiles).map((profileKey) => this.evaluateReviewProfile(profileKey)));
|
|
2888
|
-
}
|
|
2889
|
-
async evaluateReviewProfile(profileKey) {
|
|
2890
|
-
const governance = await this.resolveGovernance();
|
|
2891
|
-
const requirements = await this.getReviewRequirements(profileKey, governance);
|
|
2892
|
-
if (requirements.length === 0) return {
|
|
2893
|
-
profileKey,
|
|
2894
|
-
ready: true,
|
|
2895
|
-
complete: true,
|
|
2896
|
-
requirements: []
|
|
2897
|
-
};
|
|
2898
|
-
const reviews = await this.getContentReviewCollection();
|
|
2899
|
-
const reviewFingerprintCache = /* @__PURE__ */ new Map();
|
|
2900
|
-
const evaluatedRequirements = await Promise.all(requirements.map(async (requirement) => {
|
|
2901
|
-
if (!reviewFingerprintCache.has(requirement.policyKey)) reviewFingerprintCache.set(requirement.policyKey, await this.buildReviewFingerprint(requirement.policyKey));
|
|
2902
|
-
const latestReview = this.id && requirement.policyKey ? await reviews.getLatestForPolicyKey(this.id, requirement.policyKey) : null;
|
|
2903
|
-
const acceptedStatuses = getAcceptedContentReviewStatuses(requirement);
|
|
2904
|
-
const latestStatus = latestReview?.status ?? null;
|
|
2905
|
-
const latestMetadata = typeof latestReview?.getMetadata === "function" ? latestReview.getMetadata() : {};
|
|
2906
|
-
const currentFingerprint = reviewFingerprintCache.get(requirement.policyKey) || null;
|
|
2907
|
-
const reviewedFingerprint = latestMetadata?.reviewFingerprint || latestMetadata?.contentFingerprint || null;
|
|
2908
|
-
const missing = !latestReview;
|
|
2909
|
-
const stale = !missing && !!reviewedFingerprint && reviewedFingerprint !== currentFingerprint;
|
|
2910
|
-
const executed = latestStatus !== null && latestStatus !== "pending" && !stale;
|
|
2911
|
-
const satisfied = !stale && latestStatus !== null && acceptedStatuses.includes(latestStatus);
|
|
2912
|
-
return {
|
|
2913
|
-
kind: getContentReviewKind(requirement.policyKey, governance.reviewPolicies),
|
|
2914
|
-
policyKey: requirement.policyKey,
|
|
2915
|
-
label: requirement.label || getContentReviewPolicy(requirement.policyKey, governance.reviewPolicies)?.label || requirement.policyKey,
|
|
2916
|
-
blocking: requirement.blocking === true,
|
|
2917
|
-
acceptedStatuses,
|
|
2918
|
-
missing,
|
|
2919
|
-
stale,
|
|
2920
|
-
executed,
|
|
2921
|
-
satisfied,
|
|
2922
|
-
latestReviewId: latestReview?.id || null,
|
|
2923
|
-
latestStatus,
|
|
2924
|
-
latestSummary: latestReview?.summary || null
|
|
2925
|
-
};
|
|
2926
|
-
}));
|
|
2927
|
-
return {
|
|
2928
|
-
profileKey,
|
|
2929
|
-
ready: evaluatedRequirements.filter((requirement) => requirement.blocking).every((requirement) => requirement.satisfied),
|
|
2930
|
-
complete: evaluatedRequirements.every((requirement) => requirement.executed),
|
|
2931
|
-
requirements: evaluatedRequirements
|
|
2932
|
-
};
|
|
2933
|
-
}
|
|
2934
|
-
async evaluateReviewProfileAction(options = {}) {
|
|
2935
|
-
if (!options.profileKey) throw new Error("profileKey is required");
|
|
2936
|
-
return this.evaluateReviewProfile(options.profileKey);
|
|
2937
|
-
}
|
|
2938
|
-
async isReadyForReviewProfile(profileKey) {
|
|
2939
|
-
return (await this.evaluateReviewProfile(profileKey)).ready;
|
|
2940
|
-
}
|
|
2941
|
-
async getPublishedTransparency() {
|
|
2942
|
-
if (!this.id) return null;
|
|
2943
|
-
return (await (await this.getContentVersionCollection()).getLatestPublishedForContent(this.id))?.getTransparency() || null;
|
|
2944
|
-
}
|
|
2945
|
-
async getPublishedTransparencyAction() {
|
|
2946
|
-
return this.getPublishedTransparency();
|
|
2947
|
-
}
|
|
2948
|
-
async previewTransparency() {
|
|
2949
|
-
const governance = await this.resolveGovernance();
|
|
2950
|
-
if (!governance.isGoverned || !governance.transparencyEnabled) return null;
|
|
2951
|
-
return this.buildTransparencySnapshot({
|
|
2952
|
-
snapshotKind: "preview",
|
|
2953
|
-
governance
|
|
2954
|
-
});
|
|
2955
|
-
}
|
|
2956
|
-
async previewTransparencyAction() {
|
|
2957
|
-
return this.previewTransparency();
|
|
2958
|
-
}
|
|
2959
|
-
async runReview(options = {}) {
|
|
2960
|
-
const governance = await this.requireGovernance("review execution");
|
|
2961
|
-
if (!this.id) throw new Error("Cannot review unsaved content");
|
|
2962
|
-
const policyKey = options.policyKey || options.kind || "custom";
|
|
2963
|
-
const policy = getContentReviewPolicy(policyKey, governance.reviewPolicies);
|
|
2964
|
-
const kind = options.kind || getContentReviewKind(policyKey, governance.reviewPolicies);
|
|
2965
|
-
const facts = options.facts !== void 0 ? options.facts : governance.factLinkingEnabled && (kind === "facts" || Boolean(options.factIds?.length)) ? await this.getFacts({
|
|
2966
|
-
latestOnly: true,
|
|
2967
|
-
includeSuperseded: false
|
|
2968
|
-
}) : [];
|
|
2969
|
-
const filteredFacts = options.factIds && options.factIds.length > 0 ? facts.filter((fact) => options.factIds?.includes(fact.id)) : facts;
|
|
2970
|
-
const reviewPrompt = buildContentReviewPrompt({
|
|
2971
|
-
kind,
|
|
2972
|
-
content: this,
|
|
2973
|
-
facts: filteredFacts,
|
|
2974
|
-
policy,
|
|
2975
|
-
customInstructions: options.instructions
|
|
2976
|
-
});
|
|
2977
|
-
const resolvedPrompt = await resolvePrompt(smrtContentReviewPrompt.key, {
|
|
2978
|
-
db: this.options.db,
|
|
2979
|
-
tenantId: this.tenantId,
|
|
2980
|
-
variables: {
|
|
2981
|
-
contentBody: this.body,
|
|
2982
|
-
contentDescription: this.description ?? "",
|
|
2983
|
-
contentId: this.id ?? "",
|
|
2984
|
-
contentTitle: this.title,
|
|
2985
|
-
kind,
|
|
2986
|
-
policyKey: policy?.key || kind,
|
|
2987
|
-
reviewPrompt
|
|
2988
|
-
}
|
|
2989
|
-
});
|
|
2990
|
-
const reviewFingerprint = await this.buildReviewFingerprint(policyKey);
|
|
2991
|
-
const ai = this.ai;
|
|
2992
|
-
if (!ai?.message) throw new Error("AI client is not configured for content reviews");
|
|
2993
|
-
const rawResponse = await ai.message(resolvedPrompt.text, promptMessageOptions(resolvedPrompt.ai));
|
|
2994
|
-
const result = parseContentReviewResponse(rawResponse);
|
|
2995
|
-
const persistReview = async (content) => {
|
|
2996
|
-
if (options.expectedUpdatedAt !== void 0) await content.claimRevision(options.expectedUpdatedAt);
|
|
2997
|
-
const version = options.createVersion === false ? null : await content.createVersion({
|
|
2998
|
-
kind: "review",
|
|
2999
|
-
summary: result.summary,
|
|
3000
|
-
metadata: {
|
|
3001
|
-
kind,
|
|
3002
|
-
policyKey,
|
|
3003
|
-
reviewFingerprint
|
|
3004
|
-
}
|
|
3005
|
-
});
|
|
3006
|
-
return (await content.getContentReviewCollection()).createFromResult({
|
|
3007
|
-
contentId: content.id,
|
|
3008
|
-
contentVersionId: version?.id,
|
|
3009
|
-
kind,
|
|
3010
|
-
policyKey,
|
|
3011
|
-
reviewer: options.reviewer || "system",
|
|
3012
|
-
result,
|
|
3013
|
-
metadata: {
|
|
3014
|
-
...options.metadata || {},
|
|
3015
|
-
prompt: resolvedPrompt.text,
|
|
3016
|
-
rawResponse,
|
|
3017
|
-
reviewFingerprint,
|
|
3018
|
-
factIds: filteredFacts.map((fact) => fact.id)
|
|
3019
|
-
},
|
|
3020
|
-
tenantId: content.tenantId
|
|
3021
|
-
});
|
|
3022
|
-
};
|
|
3023
|
-
if (options.expectedUpdatedAt !== void 0) {
|
|
3024
|
-
if (!this.db.transaction) throw new Error("Atomic content review persistence requires transaction support");
|
|
3025
|
-
return this.withTransaction(persistReview);
|
|
3026
|
-
}
|
|
3027
|
-
return persistReview(this);
|
|
3028
|
-
}
|
|
3029
|
-
async runReviewAction(options = {}) {
|
|
3030
|
-
let review;
|
|
3031
|
-
if (options.kind === "facts") review = await this.reviewFacts(options);
|
|
3032
|
-
else if (options.kind === "safety") review = await this.reviewSafety(options);
|
|
3033
|
-
else review = await this.runReview(options);
|
|
3034
|
-
return serializeContentReview(review);
|
|
3035
|
-
}
|
|
3036
|
-
async reviewFacts(options = {}) {
|
|
3037
|
-
return this.runReview({
|
|
3038
|
-
...options,
|
|
3039
|
-
kind: "facts",
|
|
3040
|
-
policyKey: options.policyKey || "facts"
|
|
3041
|
-
});
|
|
3042
|
-
}
|
|
3043
|
-
async reviewSafety(options = {}) {
|
|
3044
|
-
const governance = await this.requireGovernance("safety review");
|
|
3045
|
-
const baseInstructions = getContentReviewPolicy(options.policyKey || "safety", governance.reviewPolicies)?.instructions || "";
|
|
3046
|
-
return this.runReview({
|
|
3047
|
-
...options,
|
|
3048
|
-
kind: "safety",
|
|
3049
|
-
policyKey: options.policyKey || "safety",
|
|
3050
|
-
instructions: options.instructions && baseInstructions ? `${baseInstructions}
|
|
3051
|
-
|
|
3052
|
-
Additional app-level guidance:
|
|
3053
|
-
${options.instructions}` : options.instructions || baseInstructions
|
|
3054
|
-
});
|
|
3055
|
-
}
|
|
3056
|
-
async getCorrections() {
|
|
3057
|
-
if (!this.id) return [];
|
|
3058
|
-
return (await this.getContentCorrectionCollection()).listForContent(this.id);
|
|
3059
|
-
}
|
|
3060
|
-
async listCorrections() {
|
|
3061
|
-
return (await this.getCorrections()).map(serializeContentCorrection);
|
|
3062
|
-
}
|
|
3063
|
-
async issueCorrection(options) {
|
|
3064
|
-
const governance = await this.requireGovernance("corrections");
|
|
3065
|
-
if (!this.id) throw new Error("Cannot issue a correction for unsaved content");
|
|
3066
|
-
let replacementFactId = "";
|
|
3067
|
-
if (governance.factLinkingEnabled && options.factId && options.correctedFactText) {
|
|
3068
|
-
const facts = await this.getFactCollection();
|
|
3069
|
-
const existing = await facts.get({ id: options.factId });
|
|
3070
|
-
if (!existing) throw new Error(`Fact not found for correction: ${options.factId}`);
|
|
3071
|
-
const replacement = await facts.create({
|
|
3072
|
-
textRefined: options.correctedFactText,
|
|
3073
|
-
textRaw: options.correctedFactText,
|
|
3074
|
-
type: existing.getType(),
|
|
3075
|
-
domain: existing.domain,
|
|
3076
|
-
status: "active",
|
|
3077
|
-
tenantId: existing.tenantId ?? this.tenantId ?? null,
|
|
3078
|
-
previousFactId: options.factId,
|
|
3079
|
-
evolutionType: "correction"
|
|
3080
|
-
});
|
|
3081
|
-
existing.status = "superseded";
|
|
3082
|
-
await existing.save();
|
|
3083
|
-
replacementFactId = replacement.id;
|
|
3084
|
-
await this.addFact(replacementFactId);
|
|
3085
|
-
}
|
|
3086
|
-
const version = options.createVersion === false ? null : await this.createVersion({
|
|
3087
|
-
kind: "correction",
|
|
3088
|
-
summary: options.summary,
|
|
3089
|
-
metadata: {
|
|
3090
|
-
factId: options.factId || null,
|
|
3091
|
-
replacementFactId: replacementFactId || null
|
|
3092
|
-
}
|
|
3093
|
-
});
|
|
3094
|
-
const correctionDraft = options.createVersion === false ? null : await this.buildCorrectionDraftSnapshot(options, replacementFactId);
|
|
3095
|
-
const draftVersion = options.createVersion === false || !correctionDraft ? null : await this.createVersion({
|
|
3096
|
-
kind: "draft",
|
|
3097
|
-
summary: `Auto-created correction draft: ${options.summary}`,
|
|
3098
|
-
snapshot: correctionDraft.snapshot,
|
|
3099
|
-
metadata: {
|
|
3100
|
-
...correctionDraft.metadata,
|
|
3101
|
-
sourceCorrectionVersionId: version?.id || null,
|
|
3102
|
-
sourceCorrectionVersionNumber: version?.version ?? null
|
|
3103
|
-
}
|
|
3104
|
-
});
|
|
3105
|
-
const corrections = await this.getContentCorrectionCollection();
|
|
3106
|
-
const shouldPublish = options.publish ?? this.status === "published";
|
|
3107
|
-
return corrections.issue({
|
|
3108
|
-
contentId: this.id,
|
|
3109
|
-
contentVersionId: version?.id || "",
|
|
3110
|
-
factId: options.factId || "",
|
|
3111
|
-
replacementFactId,
|
|
3112
|
-
correctionType: options.correctionType || "fact",
|
|
3113
|
-
status: shouldPublish ? "published" : "draft",
|
|
3114
|
-
summary: options.summary,
|
|
3115
|
-
incorrectText: options.incorrectText || "",
|
|
3116
|
-
correctedText: options.correctedText || options.correctedFactText || "",
|
|
3117
|
-
publicNote: options.publicNote || "",
|
|
3118
|
-
metadata: {
|
|
3119
|
-
...options.metadata || {},
|
|
3120
|
-
autoGeneratedDraft: Boolean(draftVersion),
|
|
3121
|
-
draftVersionId: draftVersion?.id || null,
|
|
3122
|
-
draftVersionNumber: draftVersion?.version ?? null,
|
|
3123
|
-
sourceCorrectionVersionId: version?.id || null,
|
|
3124
|
-
sourceCorrectionVersionNumber: version?.version ?? null,
|
|
3125
|
-
correctionProfileKey: governance.correctionProfileKey || null
|
|
3126
|
-
},
|
|
3127
|
-
tenantId: this.tenantId,
|
|
3128
|
-
publishedAt: shouldPublish ? /* @__PURE__ */ new Date() : null
|
|
3129
|
-
});
|
|
3130
|
-
}
|
|
3131
|
-
async issueCorrectionAction(options) {
|
|
3132
|
-
return serializeContentCorrection(await this.issueCorrection(options));
|
|
3133
|
-
}
|
|
3134
|
-
async listVersions() {
|
|
3135
|
-
return (await this.getVersions()).map(serializeContentVersion);
|
|
3136
|
-
}
|
|
3137
|
-
async mutateVersionAction(options = {}) {
|
|
3138
|
-
if (options.action === "restore") {
|
|
3139
|
-
const versionNumber = Number(options.versionNumber);
|
|
3140
|
-
if (!Number.isFinite(versionNumber)) throw new Error("versionNumber is required to restore a version");
|
|
3141
|
-
return serializeContent(await this.restoreFromVersion(versionNumber));
|
|
3142
|
-
}
|
|
3143
|
-
return serializeContentVersion(await this.createVersion(options));
|
|
3144
|
-
}
|
|
3145
|
-
/**
|
|
3146
|
-
* Note: toJSON() is inherited from SmrtObject
|
|
3147
|
-
*
|
|
3148
|
-
* The parent implementation handles:
|
|
3149
|
-
* - STI discriminator (_meta_type) for polymorphic queries
|
|
3150
|
-
* - Meta field extraction (_meta_data) for child-specific fields
|
|
3151
|
-
* - Automatic serialization of all fields from manifest
|
|
3152
|
-
*
|
|
3153
|
-
* DO NOT override toJSON() unless you call super.toJSON() first.
|
|
3154
|
-
* See issue #377 for details on why this override was removed.
|
|
3155
|
-
*/
|
|
3156
|
-
/**
|
|
3157
|
-
* Get category segments as array
|
|
3158
|
-
* @example 'politics/local' -> ['politics', 'local']
|
|
3159
|
-
*/
|
|
3160
|
-
getCategorySegments() {
|
|
3161
|
-
if (!this.category) return [];
|
|
3162
|
-
return this.category.split("/").filter(Boolean);
|
|
3163
|
-
}
|
|
3164
|
-
/**
|
|
3165
|
-
* Get parent category path
|
|
3166
|
-
* @example 'politics/local/town' -> 'politics/local'
|
|
3167
|
-
* @example 'politics' -> null
|
|
3168
|
-
*/
|
|
3169
|
-
getParentCategory() {
|
|
3170
|
-
const segments = this.getCategorySegments();
|
|
3171
|
-
if (segments.length <= 1) return null;
|
|
3172
|
-
return segments.slice(0, -1).join("/");
|
|
3173
|
-
}
|
|
3174
|
-
/**
|
|
3175
|
-
* Get root (top-level) category
|
|
3176
|
-
* @example 'politics/local/town' -> 'politics'
|
|
3177
|
-
*/
|
|
3178
|
-
getRootCategory() {
|
|
3179
|
-
return this.getCategorySegments()[0] || null;
|
|
3180
|
-
}
|
|
3181
|
-
/**
|
|
3182
|
-
* Get all ancestor category paths (for breadcrumbs)
|
|
3183
|
-
* @example 'politics/local' -> ['politics', 'politics/local']
|
|
3184
|
-
*/
|
|
3185
|
-
getAncestorPaths() {
|
|
3186
|
-
const segments = this.getCategorySegments();
|
|
3187
|
-
return segments.map((_, i) => segments.slice(0, i + 1).join("/"));
|
|
3188
|
-
}
|
|
3189
|
-
/**
|
|
3190
|
-
* Check if content belongs to a category (optionally including subcategories)
|
|
3191
|
-
* @param categoryPath - Category to check
|
|
3192
|
-
* @param includeChildren - If true, matches 'politics' for content in 'politics/local'
|
|
3193
|
-
*/
|
|
3194
|
-
isInCategory(categoryPath, includeChildren = true) {
|
|
3195
|
-
if (!this.category) return false;
|
|
3196
|
-
if (includeChildren) return this.category === categoryPath || this.category.startsWith(`${categoryPath}/`);
|
|
3197
|
-
return this.category === categoryPath;
|
|
3198
|
-
}
|
|
3199
|
-
/**
|
|
3200
|
-
* Get all assets associated with this content
|
|
3201
|
-
* @param relationship - Optional filter by relationship type (e.g., 'thumbnail', 'attachment')
|
|
3202
|
-
* @returns Promise resolving to array of assets
|
|
3203
|
-
*/
|
|
3204
|
-
async getAssets(relationship) {
|
|
3205
|
-
if (!this.id) return [];
|
|
3206
|
-
return this.resolveAssetsForLinks(await this.getContentAssetLinks(relationship));
|
|
3207
|
-
}
|
|
3208
|
-
/**
|
|
3209
|
-
* Add an asset to this content with a relationship type
|
|
3210
|
-
* @param asset - The asset to associate
|
|
3211
|
-
* @param relationship - Relationship type (e.g., 'thumbnail', 'attachment', 'inline')
|
|
3212
|
-
* @param sortOrder - Optional sort order for display
|
|
3213
|
-
*/
|
|
3214
|
-
async addAsset(asset, relationship = "attachment", sortOrder = 0) {
|
|
3215
|
-
if (!this.id || !asset.id) throw new Error("Cannot associate unsaved content or asset");
|
|
3216
|
-
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(relationship)) throw new Error(`Invalid relationship type "${relationship}"; must start with a letter or underscore and contain only letters, digits, and underscores`);
|
|
3217
|
-
if (!Number.isInteger(sortOrder) || sortOrder < 0 || sortOrder > 2147483647) throw new Error(`Invalid sortOrder "${sortOrder}"; must be a non-negative integer`);
|
|
3218
|
-
await (await this.getContentAssetCollection()).attach(this.id, asset.id, {
|
|
3219
|
-
relationship,
|
|
3220
|
-
sortOrder,
|
|
3221
|
-
tenantId: this.tenantId
|
|
3222
|
-
});
|
|
3223
|
-
}
|
|
3224
|
-
/**
|
|
3225
|
-
* Remove an asset from this content
|
|
3226
|
-
* @param assetId - ID of the asset to remove
|
|
3227
|
-
* @param relationship - Optional specific relationship to remove (removes all if not specified)
|
|
3228
|
-
*/
|
|
3229
|
-
async removeAsset(assetId, relationship) {
|
|
3230
|
-
if (!this.id) return;
|
|
3231
|
-
try {
|
|
3232
|
-
await (await this.getContentAssetCollection()).detach(this.id, assetId, relationship ? { relationship } : {});
|
|
3233
|
-
} catch (error) {
|
|
3234
|
-
if (!isMissingTableError(error, "content_assets")) throw error;
|
|
3235
|
-
}
|
|
3236
|
-
}
|
|
3237
|
-
/**
|
|
3238
|
-
* Get the full metadata record. Always returns a plain object — never
|
|
3239
|
-
* `null`, never an array — so callers can safely read nested keys without
|
|
3240
|
-
* defensive checks.
|
|
3241
|
-
*
|
|
3242
|
-
* Pure read with no side-effect on `this.metadata`: if the field is
|
|
3243
|
-
* currently `null` (e.g. fresh from the DB) or non-record-shaped, an
|
|
3244
|
-
* empty object is returned but the field is **not** mutated. This avoids
|
|
3245
|
-
* accidentally marking the object dirty during a read, which would
|
|
3246
|
-
* otherwise cause SmrtObject's save lifecycle to write `{}` back over a
|
|
3247
|
-
* NULL column on the next save. Callers that want to normalise the
|
|
3248
|
-
* stored field should use {@link Content.setMetadata}.
|
|
3249
|
-
*/
|
|
3250
|
-
getMetadata() {
|
|
3251
|
-
return isPlainMetadataRecord(this.metadata) ? this.metadata : {};
|
|
3252
|
-
}
|
|
3253
|
-
/**
|
|
3254
|
-
* Replace the full metadata record. Passing `null`/`undefined` (or any
|
|
3255
|
-
* non-record value such as an array) clears it to an empty object so
|
|
3256
|
-
* downstream readers can rely on the field always being a plain object.
|
|
3257
|
-
*/
|
|
3258
|
-
setMetadata(metadata) {
|
|
3259
|
-
this.metadata = isPlainMetadataRecord(metadata) ? { ...metadata } : {};
|
|
3260
|
-
}
|
|
3261
|
-
/**
|
|
3262
|
-
* Shallow-merge a patch over the current metadata. Returns the resulting
|
|
3263
|
-
* record so callers can chain reads without re-reading the field. Unlike
|
|
3264
|
-
* {@link Content.getMetadata}, this method does intentionally write back
|
|
3265
|
-
* to `this.metadata` because the merge is a write.
|
|
3266
|
-
*/
|
|
3267
|
-
updateMetadata(patch) {
|
|
3268
|
-
const next = {
|
|
3269
|
-
...this.getMetadata(),
|
|
3270
|
-
...patch ?? {}
|
|
3271
|
-
};
|
|
3272
|
-
this.metadata = next;
|
|
3273
|
-
return next;
|
|
3274
|
-
}
|
|
3275
|
-
/**
|
|
3276
|
-
* Get the thumbnail image for this content
|
|
3277
|
-
* @returns Promise resolving to the thumbnail Image or null
|
|
3278
|
-
*/
|
|
3279
|
-
async getThumbnail() {
|
|
3280
|
-
if (!this.thumbnailAssetId) return null;
|
|
3281
|
-
return (await ImageCollection.create({ db: this.options?.db })).get({ id: this.thumbnailAssetId });
|
|
3282
|
-
}
|
|
3283
|
-
/**
|
|
3284
|
-
* Set the thumbnail image for this content
|
|
3285
|
-
* @param image - The image to set as thumbnail
|
|
3286
|
-
*/
|
|
3287
|
-
async setThumbnail(image) {
|
|
3288
|
-
await this.addAsset(image, "thumbnail", 0);
|
|
3289
|
-
this.thumbnailAssetId = image.id ?? null;
|
|
3290
|
-
await this.save();
|
|
3291
|
-
}
|
|
3292
|
-
/**
|
|
3293
|
-
* Generate a thumbnail for this content using the specified strategy
|
|
3294
|
-
*
|
|
3295
|
-
* @param options - Thumbnail generation options including strategy
|
|
3296
|
-
* @returns Promise resolving to the generated Image
|
|
3297
|
-
*
|
|
3298
|
-
* @example Headline card thumbnail
|
|
3299
|
-
* ```typescript
|
|
3300
|
-
* const thumbnail = await content.generateThumbnail({
|
|
3301
|
-
* strategy: 'headline-card',
|
|
3302
|
-
* brandColor: '#1a56db',
|
|
3303
|
-
* logoUrl: 'https://example.com/logo.png'
|
|
3304
|
-
* });
|
|
3305
|
-
* ```
|
|
3306
|
-
*
|
|
3307
|
-
* @example Static map thumbnail (requires metadata.latitude/longitude)
|
|
3308
|
-
* ```typescript
|
|
3309
|
-
* const thumbnail = await content.generateThumbnail({
|
|
3310
|
-
* strategy: 'static-map',
|
|
3311
|
-
* mapProvider: 'mapbox'
|
|
3312
|
-
* });
|
|
3313
|
-
* ```
|
|
3314
|
-
*
|
|
3315
|
-
* @example AI-generated thumbnail
|
|
3316
|
-
* ```typescript
|
|
3317
|
-
* const thumbnail = await content.generateThumbnail({
|
|
3318
|
-
* strategy: 'ai-generate'
|
|
3319
|
-
* });
|
|
3320
|
-
* ```
|
|
3321
|
-
*/
|
|
3322
|
-
async generateThumbnail(options) {
|
|
3323
|
-
const image = await new ThumbnailGenerator(this, this.options).generate(options);
|
|
3324
|
-
await this.setThumbnail(image);
|
|
3325
|
-
return image;
|
|
3326
|
-
}
|
|
3327
|
-
};
|
|
3328
|
-
__decorateClass([tenantId({ nullable: true })], Content.prototype, "tenantId", 2);
|
|
3329
|
-
__decorateClass([field({ required: true })], Content.prototype, "name", 2);
|
|
3330
|
-
__decorateClass([crossPackageRef("@happyvertical/smrt-assets:Asset")], Content.prototype, "thumbnailAssetId", 2);
|
|
3331
|
-
Content = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
|
|
3332
|
-
tableStrategy: "sti",
|
|
3333
|
-
api: {
|
|
3334
|
-
include: [
|
|
3335
|
-
"list",
|
|
3336
|
-
"get",
|
|
3337
|
-
"create",
|
|
3338
|
-
"update",
|
|
3339
|
-
"delete",
|
|
3340
|
-
"getFactsState",
|
|
3341
|
-
"syncFactsState",
|
|
3342
|
-
"getFactAuditStateAction",
|
|
3343
|
-
"repairFactAuditAction",
|
|
3344
|
-
"repairFactEvidenceAction",
|
|
3345
|
-
"recheckFactClaimsAction",
|
|
3346
|
-
"updateFactEvidenceStatusAction",
|
|
3347
|
-
"getGovernanceStateAction",
|
|
3348
|
-
"listReviews",
|
|
3349
|
-
"runReviewAction",
|
|
3350
|
-
"listReviewProfilesAction",
|
|
3351
|
-
"evaluateReviewProfileAction",
|
|
3352
|
-
"getPublishedTransparencyAction",
|
|
3353
|
-
"previewTransparencyAction",
|
|
3354
|
-
"listCorrections",
|
|
3355
|
-
"issueCorrectionAction",
|
|
3356
|
-
"listVersions",
|
|
3357
|
-
"mutateVersionAction"
|
|
3358
|
-
],
|
|
3359
|
-
routes: {
|
|
3360
|
-
getFactsState: {
|
|
3361
|
-
method: "GET",
|
|
3362
|
-
path: "facts"
|
|
3363
|
-
},
|
|
3364
|
-
syncFactsState: {
|
|
3365
|
-
method: "PUT",
|
|
3366
|
-
path: "facts"
|
|
3367
|
-
},
|
|
3368
|
-
getFactAuditStateAction: {
|
|
3369
|
-
method: "GET",
|
|
3370
|
-
path: "fact-audit"
|
|
3371
|
-
},
|
|
3372
|
-
repairFactAuditAction: {
|
|
3373
|
-
method: "POST",
|
|
3374
|
-
path: "fact-audit/repair"
|
|
3375
|
-
},
|
|
3376
|
-
repairFactEvidenceAction: {
|
|
3377
|
-
method: "POST",
|
|
3378
|
-
path: "fact-audit/evidence/repair"
|
|
3379
|
-
},
|
|
3380
|
-
recheckFactClaimsAction: {
|
|
3381
|
-
method: "POST",
|
|
3382
|
-
path: "fact-audit/claims/recheck"
|
|
3383
|
-
},
|
|
3384
|
-
updateFactEvidenceStatusAction: {
|
|
3385
|
-
method: "PUT",
|
|
3386
|
-
path: "fact-audit/evidence/status"
|
|
3387
|
-
},
|
|
3388
|
-
getGovernanceStateAction: {
|
|
3389
|
-
method: "GET",
|
|
3390
|
-
path: "governance"
|
|
3391
|
-
},
|
|
3392
|
-
listReviews: {
|
|
3393
|
-
method: "GET",
|
|
3394
|
-
path: "reviews"
|
|
3395
|
-
},
|
|
3396
|
-
runReviewAction: {
|
|
3397
|
-
method: "POST",
|
|
3398
|
-
path: "reviews"
|
|
3399
|
-
},
|
|
3400
|
-
listReviewProfilesAction: {
|
|
3401
|
-
method: "GET",
|
|
3402
|
-
path: "review-profiles"
|
|
3403
|
-
},
|
|
3404
|
-
evaluateReviewProfileAction: {
|
|
3405
|
-
method: "GET",
|
|
3406
|
-
path: "review-profiles/[profileKey]"
|
|
3407
|
-
},
|
|
3408
|
-
getPublishedTransparencyAction: {
|
|
3409
|
-
method: "GET",
|
|
3410
|
-
path: "transparency"
|
|
3411
|
-
},
|
|
3412
|
-
previewTransparencyAction: {
|
|
3413
|
-
method: "GET",
|
|
3414
|
-
path: "transparency/preview"
|
|
3415
|
-
},
|
|
3416
|
-
listCorrections: {
|
|
3417
|
-
method: "GET",
|
|
3418
|
-
path: "corrections"
|
|
3419
|
-
},
|
|
3420
|
-
issueCorrectionAction: {
|
|
3421
|
-
method: "POST",
|
|
3422
|
-
path: "corrections"
|
|
3423
|
-
},
|
|
3424
|
-
listVersions: {
|
|
3425
|
-
method: "GET",
|
|
3426
|
-
path: "versions"
|
|
3427
|
-
},
|
|
3428
|
-
mutateVersionAction: {
|
|
3429
|
-
method: "POST",
|
|
3430
|
-
path: "versions"
|
|
3431
|
-
}
|
|
3432
|
-
},
|
|
3433
|
-
serializers: { item: {
|
|
3434
|
-
importPath: "$lib/server/content-api-serializers",
|
|
3435
|
-
exportName: "serializeContent"
|
|
3436
|
-
} }
|
|
3437
|
-
},
|
|
3438
|
-
mcp: { include: [
|
|
3439
|
-
"list",
|
|
3440
|
-
"get",
|
|
3441
|
-
"create",
|
|
3442
|
-
"update"
|
|
3443
|
-
] },
|
|
3444
|
-
cli: true,
|
|
3445
|
-
indexes: [{
|
|
3446
|
-
name: "contents_tenant_id_publish_date_idx",
|
|
3447
|
-
columns: ["tenantId", "publish_date"]
|
|
3448
|
-
}]
|
|
3449
|
-
})], Content);
|
|
3450
|
-
//#endregion
|
|
3451
|
-
//#region src/content-query.ts
|
|
3452
|
-
var CONTENT_QUERY_CLASS_NAME = "@happyvertical/smrt-content:Content";
|
|
3453
|
-
var CONTENT_QUERY_IDENTITY_FIELD = "id";
|
|
3454
|
-
var CONTENT_QUERY_DEFAULT_SORT = [{
|
|
3455
|
-
field: "updated_at",
|
|
3456
|
-
direction: "desc"
|
|
3457
|
-
}, {
|
|
3458
|
-
field: "id",
|
|
3459
|
-
direction: "asc"
|
|
3460
|
-
}];
|
|
3461
|
-
var CONTENT_QUERY_DEFAULT_PAGE_LIMIT = 50;
|
|
3462
|
-
var CONTENT_QUERY_MAX_PAGE_LIMIT = 200;
|
|
3463
|
-
var CONTENT_QUERY_MAX_RESULT_BYTES = 1e6;
|
|
3464
|
-
var CONTENT_QUERY_EXCLUDED_FIELD_IDS = ["body"];
|
|
3465
|
-
var DATA_QUERY_MAX_STRING_LENGTH = 4096;
|
|
3466
|
-
var DATA_QUERY_MAX_JSON_STRING_LENGTH = 65536;
|
|
3467
|
-
var DATA_QUERY_MAX_JSON_CONTAINER_ITEMS = 1e3;
|
|
3468
|
-
var DATA_QUERY_MAX_JSON_DEPTH = 16;
|
|
3469
|
-
var DATA_QUERY_FORBIDDEN_JSON_KEYS = /* @__PURE__ */ new Set([
|
|
3470
|
-
"__proto__",
|
|
3471
|
-
"constructor",
|
|
3472
|
-
"prototype"
|
|
3473
|
-
]);
|
|
3474
|
-
var RESULT_ENVELOPE_RESERVE_BYTES = 4096;
|
|
3475
|
-
var MIN_RESULT_ROW_BYTES = 512;
|
|
3476
|
-
var CONTENT_QUERY_MIN_RESULT_BYTES = 4608;
|
|
3477
|
-
function assertUsableResultBudget(schema) {
|
|
3478
|
-
const budget = schema.maxResultBytes ?? 1e6;
|
|
3479
|
-
if (budget >= 4608) return;
|
|
3480
|
-
throw new Error(`Content query schema maxResultBytes must be at least ${CONTENT_QUERY_MIN_RESULT_BYTES} (${RESULT_ENVELOPE_RESERVE_BYTES} reserved for the result envelope, ${MIN_RESULT_ROW_BYTES} for rows); received ${budget}.`);
|
|
3481
|
-
}
|
|
3482
|
-
var MAX_CONTENT_QUERY_OR_BRANCHES = 128;
|
|
3483
|
-
var encoder = new TextEncoder();
|
|
3484
|
-
function assertContentQuerySchema(schema) {
|
|
3485
|
-
normalizeDataQuerySchema(schema);
|
|
3486
|
-
assertUsableResultBudget(schema);
|
|
3487
|
-
}
|
|
3488
|
-
function resolveContentTenantReadScope() {
|
|
3489
|
-
if (!isTenancyEnabled()) return void 0;
|
|
3490
|
-
if (isSuperAdminBypass() || isSystemContext()) return void 0;
|
|
3491
|
-
return { tenantId: getCurrentTenant()?.tenantId ?? null };
|
|
3492
|
-
}
|
|
3493
|
-
function queryFail(message, code = "INVALID_DATA_QUERY") {
|
|
3494
|
-
throw new DataQueryValidationError(message, code);
|
|
3495
|
-
}
|
|
3496
|
-
function isPlainRecord(value) {
|
|
3497
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
3498
|
-
const prototype = Object.getPrototypeOf(value);
|
|
3499
|
-
return prototype === Object.prototype || prototype === null;
|
|
3500
|
-
}
|
|
3501
|
-
function queryFieldType(type) {
|
|
3502
|
-
switch (type) {
|
|
3503
|
-
case "text":
|
|
3504
|
-
case "foreignKey":
|
|
3505
|
-
case "crossPackageRef": return "string";
|
|
3506
|
-
case "integer":
|
|
3507
|
-
case "decimal": return "number";
|
|
3508
|
-
case "boolean": return "boolean";
|
|
3509
|
-
case "datetime": return "datetime";
|
|
3510
|
-
case "json": return "json";
|
|
3511
|
-
default: return;
|
|
3512
|
-
}
|
|
3513
|
-
}
|
|
3514
|
-
function filterOperatorsFor(type) {
|
|
3515
|
-
switch (type) {
|
|
3516
|
-
case "string": return [
|
|
3517
|
-
"eq",
|
|
3518
|
-
"ne",
|
|
3519
|
-
"gt",
|
|
3520
|
-
"gte",
|
|
3521
|
-
"lt",
|
|
3522
|
-
"lte",
|
|
3523
|
-
"in",
|
|
3524
|
-
"notIn",
|
|
3525
|
-
"like"
|
|
3526
|
-
];
|
|
3527
|
-
case "number":
|
|
3528
|
-
case "datetime": return [
|
|
3529
|
-
"eq",
|
|
3530
|
-
"ne",
|
|
3531
|
-
"gt",
|
|
3532
|
-
"gte",
|
|
3533
|
-
"lt",
|
|
3534
|
-
"lte",
|
|
3535
|
-
"in",
|
|
3536
|
-
"notIn"
|
|
3537
|
-
];
|
|
3538
|
-
case "boolean": return [
|
|
3539
|
-
"eq",
|
|
3540
|
-
"ne",
|
|
3541
|
-
"in",
|
|
3542
|
-
"notIn"
|
|
3543
|
-
];
|
|
3544
|
-
case "json": return;
|
|
3545
|
-
}
|
|
3546
|
-
}
|
|
3547
|
-
function meta(field) {
|
|
3548
|
-
return isPlainRecord(field._meta) ? field._meta : {};
|
|
3549
|
-
}
|
|
3550
|
-
function isRestrictedField(field) {
|
|
3551
|
-
const fieldMeta = meta(field);
|
|
3552
|
-
return field.sensitive === true || fieldMeta.sensitive === true || typeof field.readPermission === "string" || typeof fieldMeta.readPermission === "string";
|
|
3553
|
-
}
|
|
3554
|
-
function isTransientField(field) {
|
|
3555
|
-
return field.transient === true || meta(field).transient === true;
|
|
3556
|
-
}
|
|
3557
|
-
function isTenantField(name, field) {
|
|
3558
|
-
const fieldMeta = meta(field);
|
|
3559
|
-
return (isPlainRecord(field.__tenancy) ? field.__tenancy : isPlainRecord(fieldMeta.__tenancy) ? fieldMeta.__tenancy : void 0)?.isTenantIdField === true || name === "tenantId" || name === "tenant_id";
|
|
3560
|
-
}
|
|
3561
|
-
async function buildQuerySchemaForClass(qualifiedName, excluded) {
|
|
3562
|
-
const registered = await ObjectRegistry.getAllFields(qualifiedName);
|
|
3563
|
-
const fields = [];
|
|
3564
|
-
for (const [name, field] of registered) {
|
|
3565
|
-
if (name.startsWith("_")) continue;
|
|
3566
|
-
if (excluded.has(name)) continue;
|
|
3567
|
-
if (isRestrictedField(field)) continue;
|
|
3568
|
-
if (isTransientField(field)) continue;
|
|
3569
|
-
if (isTenantField(name, field)) continue;
|
|
3570
|
-
const type = queryFieldType(field.type);
|
|
3571
|
-
if (!type) continue;
|
|
3572
|
-
const filterOperators = filterOperatorsFor(type);
|
|
3573
|
-
fields.push({
|
|
3574
|
-
id: name,
|
|
3575
|
-
type,
|
|
3576
|
-
projectable: true,
|
|
3577
|
-
sortable: type !== "json",
|
|
3578
|
-
facetable: name !== "id" && (type === "string" || type === "boolean" || type === "number"),
|
|
3579
|
-
...filterOperators ? { filterOperators } : {}
|
|
3580
|
-
});
|
|
3581
|
-
}
|
|
3582
|
-
if (!fields.find((field) => field.id === "id")) throw new Error(`${qualifiedName} does not declare a queryable 'id' field`);
|
|
3583
|
-
const declared = new Set(fields.map((field) => field.id));
|
|
3584
|
-
const defaultSort = CONTENT_QUERY_DEFAULT_SORT.filter((term) => declared.has(term.field));
|
|
3585
|
-
return {
|
|
3586
|
-
version: 1,
|
|
3587
|
-
identityField: "id",
|
|
3588
|
-
fields,
|
|
3589
|
-
defaultPageLimit: 50,
|
|
3590
|
-
maxPageLimit: 200,
|
|
3591
|
-
maxResultBytes: CONTENT_QUERY_MAX_RESULT_BYTES,
|
|
3592
|
-
...defaultSort.length > 0 ? { defaultSort } : {},
|
|
3593
|
-
supports: {
|
|
3594
|
-
cursorPagination: false,
|
|
3595
|
-
consistency: false,
|
|
3596
|
-
facets: true
|
|
3597
|
-
}
|
|
3598
|
-
};
|
|
3599
|
-
}
|
|
3600
|
-
var schemaCache = /* @__PURE__ */ new Map();
|
|
3601
|
-
function buildDataQuerySchemaForClass(qualifiedName, options = {}) {
|
|
3602
|
-
const excluded = [...new Set(options.exclude ?? [])].sort();
|
|
3603
|
-
const key = `${qualifiedName}::${excluded.join(",")}`;
|
|
3604
|
-
const cached = schemaCache.get(key);
|
|
3605
|
-
if (cached) return cached;
|
|
3606
|
-
const pending = buildQuerySchemaForClass(qualifiedName, new Set(excluded)).catch((cause) => {
|
|
3607
|
-
schemaCache.delete(key);
|
|
3608
|
-
throw cause;
|
|
3609
|
-
});
|
|
3610
|
-
schemaCache.set(key, pending);
|
|
3611
|
-
return pending;
|
|
3612
|
-
}
|
|
3613
|
-
function buildContentQuerySchema() {
|
|
3614
|
-
return buildDataQuerySchemaForClass(CONTENT_QUERY_CLASS_NAME, { exclude: CONTENT_QUERY_EXCLUDED_FIELD_IDS });
|
|
3615
|
-
}
|
|
3616
|
-
function clearContentQuerySchemaCache() {
|
|
3617
|
-
schemaCache.clear();
|
|
3618
|
-
}
|
|
3619
|
-
function inverseOperator(operator) {
|
|
3620
|
-
switch (operator) {
|
|
3621
|
-
case "eq": return "ne";
|
|
3622
|
-
case "ne": return "eq";
|
|
3623
|
-
case "gt": return "lte";
|
|
3624
|
-
case "gte": return "lt";
|
|
3625
|
-
case "lt": return "gte";
|
|
3626
|
-
case "lte": return "gt";
|
|
3627
|
-
case "in": return "notIn";
|
|
3628
|
-
case "notIn": return "in";
|
|
3629
|
-
case "like": return queryFail("Content queries cannot negate a like predicate", "DATA_QUERY_UNSUPPORTED");
|
|
3630
|
-
}
|
|
3631
|
-
}
|
|
3632
|
-
function conditionToDnf(field, operator, value, negated = false) {
|
|
3633
|
-
const key = (suffix) => suffix ? `${field} ${suffix}` : field;
|
|
3634
|
-
const single = (whereKey, whereValue) => [[{ [whereKey]: whereValue }]];
|
|
3635
|
-
if (operator === "in") {
|
|
3636
|
-
const values = value ?? [];
|
|
3637
|
-
const nonNull = values.filter((entry) => entry !== null);
|
|
3638
|
-
if (nonNull.length === 0) return single(field, null);
|
|
3639
|
-
if (nonNull.length === values.length) return single(key("in"), nonNull);
|
|
3640
|
-
return [[{ [field]: null }], [{ [key("in")]: nonNull }]];
|
|
3641
|
-
}
|
|
3642
|
-
if (operator === "notIn") {
|
|
3643
|
-
const values = value ?? [];
|
|
3644
|
-
if (values.length === 0) return queryFail("Content query notIn requires at least one value", "DATA_QUERY_UNSUPPORTED");
|
|
3645
|
-
const inequalities = values.filter((entry) => entry !== null).map((entry) => ({ [key("!=")]: entry }));
|
|
3646
|
-
if (values.some((entry) => entry === null)) return [[...inequalities, { [key("!=")]: null }]];
|
|
3647
|
-
return [[{ [field]: null }], inequalities];
|
|
3648
|
-
}
|
|
3649
|
-
if (operator === "ne" && value !== null) return [[{ [field]: null }], [{ [key("!=")]: value }]];
|
|
3650
|
-
const suffixes = {
|
|
3651
|
-
eq: "",
|
|
3652
|
-
ne: "!=",
|
|
3653
|
-
gt: ">",
|
|
3654
|
-
gte: ">=",
|
|
3655
|
-
lt: "<",
|
|
3656
|
-
lte: "<=",
|
|
3657
|
-
like: "like"
|
|
3658
|
-
};
|
|
3659
|
-
if (negated && (operator === "gt" || operator === "gte" || operator === "lt" || operator === "lte")) return [[{ [field]: null }], [{ [key(suffixes[operator])]: value }]];
|
|
3660
|
-
return single(key(suffixes[operator]), value);
|
|
3661
|
-
}
|
|
3662
|
-
function crossProduct(left, right) {
|
|
3663
|
-
if (left.length * right.length > 128) return queryFail(`Content query filter expands beyond 128 OR branches`, "DATA_QUERY_UNSUPPORTED");
|
|
3664
|
-
return left.flatMap((leftGroup) => right.map((rightGroup) => [...leftGroup, ...rightGroup]));
|
|
3665
|
-
}
|
|
3666
|
-
function filterToDnf(filter, declared, negate = false) {
|
|
3667
|
-
if (filter.kind === "condition") {
|
|
3668
|
-
if (!declared.has(filter.field)) return queryFail(`Content query filter field is not declared: ${filter.field}`, "DATA_QUERY_FILTER_NOT_ALLOWED");
|
|
3669
|
-
return conditionToDnf(filter.field, negate ? inverseOperator(filter.operator) : filter.operator, filter.value, negate);
|
|
3670
|
-
}
|
|
3671
|
-
if (filter.kind === "not") return filterToDnf(filter.filter, declared, !negate);
|
|
3672
|
-
if (filter.kind === "all" && !negate || filter.kind === "any" && negate) return filter.filters.reduce((combined, child) => crossProduct(combined, filterToDnf(child, declared, negate)), [[]]);
|
|
3673
|
-
const branches = filter.filters.flatMap((child) => filterToDnf(child, declared, negate));
|
|
3674
|
-
if (branches.length > 128) return queryFail(`Content query filter expands beyond 128 OR branches`, "DATA_QUERY_UNSUPPORTED");
|
|
3675
|
-
return branches;
|
|
3676
|
-
}
|
|
3677
|
-
function normalizeScopeConditions(scope) {
|
|
3678
|
-
if (scope === void 0) return [];
|
|
3679
|
-
return (Array.isArray(scope) ? scope : [scope]).map((candidate) => {
|
|
3680
|
-
if (!isPlainRecord(candidate) || Object.keys(candidate).length === 0) throw new Error("Content query scope conditions must be non-empty plain objects");
|
|
3681
|
-
return { ...candidate };
|
|
3682
|
-
});
|
|
3683
|
-
}
|
|
3684
|
-
var DENY_ALL_SCOPE_CONDITION = Object.freeze({ ["id"]: null });
|
|
3685
|
-
function normalizeApplicationScope(scope) {
|
|
3686
|
-
if (scope === void 0) return [];
|
|
3687
|
-
const conditions = normalizeScopeConditions(scope);
|
|
3688
|
-
return conditions.length > 0 ? conditions : [{ ...DENY_ALL_SCOPE_CONDITION }];
|
|
3689
|
-
}
|
|
3690
|
-
function mergeContentQueryScope(scope, callerWhere) {
|
|
3691
|
-
const scopeConditions = normalizeApplicationScope(scope);
|
|
3692
|
-
const merged = (callerWhere && callerWhere.length > 0 ? callerWhere : [[]]).map((branch) => [...scopeConditions, ...branch]);
|
|
3693
|
-
if (merged.length === 1 && merged[0].length === 0) return void 0;
|
|
3694
|
-
if (merged.some((branch) => branch.length === 0)) return queryFail("Content query filter produced an unbounded OR branch", "DATA_QUERY_UNSUPPORTED");
|
|
3695
|
-
return merged;
|
|
3696
|
-
}
|
|
3697
|
-
var DATA_QUERY_MAX_WARNINGS = 100;
|
|
3698
|
-
var DATA_QUERY_MAX_WARNING_LENGTH = 512;
|
|
3699
|
-
function pushWarning(warnings, message) {
|
|
3700
|
-
if (warnings.length >= 100) return;
|
|
3701
|
-
const text = message.length > 512 ? `${message.slice(0, 511)}\u2026` : message;
|
|
3702
|
-
if (text.length > 0) warnings.push(text);
|
|
3703
|
-
}
|
|
3704
|
-
function capString(value, limit = DATA_QUERY_MAX_STRING_LENGTH) {
|
|
3705
|
-
if (value.length <= limit) return value;
|
|
3706
|
-
const cut = value.slice(0, limit);
|
|
3707
|
-
const last = cut.charCodeAt(cut.length - 1);
|
|
3708
|
-
return last >= 55296 && last <= 56319 ? cut.slice(0, -1) : cut;
|
|
3709
|
-
}
|
|
3710
|
-
function boundJsonValue(value, descriptor, truncation, depth = 0, ancestors = /* @__PURE__ */ new Set()) {
|
|
3711
|
-
const flag = () => {
|
|
3712
|
-
truncation?.fields.add(descriptor.id);
|
|
3713
|
-
};
|
|
3714
|
-
if (value === null || value === void 0) return null;
|
|
3715
|
-
if (typeof value === "boolean") return value;
|
|
3716
|
-
if (typeof value === "string") {
|
|
3717
|
-
if (value.length > 65536) {
|
|
3718
|
-
flag();
|
|
3719
|
-
return capString(value, DATA_QUERY_MAX_JSON_STRING_LENGTH);
|
|
3720
|
-
}
|
|
3721
|
-
return value;
|
|
3722
|
-
}
|
|
3723
|
-
if (typeof value === "number") {
|
|
3724
|
-
if (!Number.isFinite(value)) {
|
|
3725
|
-
flag();
|
|
3726
|
-
return null;
|
|
3727
|
-
}
|
|
3728
|
-
return value;
|
|
3729
|
-
}
|
|
3730
|
-
if (typeof value === "bigint") {
|
|
3731
|
-
if (!(value <= BigInt(Number.MAX_SAFE_INTEGER) && value >= BigInt(Number.MIN_SAFE_INTEGER))) {
|
|
3732
|
-
flag();
|
|
3733
|
-
return null;
|
|
3734
|
-
}
|
|
3735
|
-
return Number(value);
|
|
3736
|
-
}
|
|
3737
|
-
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value.toISOString();
|
|
3738
|
-
if (depth >= 16) {
|
|
3739
|
-
flag();
|
|
3740
|
-
return null;
|
|
3741
|
-
}
|
|
3742
|
-
if (Array.isArray(value)) {
|
|
3743
|
-
if (ancestors.has(value)) {
|
|
3744
|
-
flag();
|
|
3745
|
-
return null;
|
|
3746
|
-
}
|
|
3747
|
-
ancestors.add(value);
|
|
3748
|
-
try {
|
|
3749
|
-
let entries = value;
|
|
3750
|
-
if (entries.length > 1e3) {
|
|
3751
|
-
flag();
|
|
3752
|
-
entries = entries.slice(0, DATA_QUERY_MAX_JSON_CONTAINER_ITEMS);
|
|
3753
|
-
}
|
|
3754
|
-
return entries.map((entry) => boundJsonValue(entry, descriptor, truncation, depth + 1, ancestors));
|
|
3755
|
-
} finally {
|
|
3756
|
-
ancestors.delete(value);
|
|
3757
|
-
}
|
|
3758
|
-
}
|
|
3759
|
-
if (!isPlainRecord(value)) {
|
|
3760
|
-
flag();
|
|
3761
|
-
return null;
|
|
3762
|
-
}
|
|
3763
|
-
if (ancestors.has(value)) {
|
|
3764
|
-
flag();
|
|
3765
|
-
return null;
|
|
3766
|
-
}
|
|
3767
|
-
ancestors.add(value);
|
|
3768
|
-
try {
|
|
3769
|
-
let keys = Object.keys(value);
|
|
3770
|
-
if (keys.length > 1e3) {
|
|
3771
|
-
flag();
|
|
3772
|
-
keys = keys.slice(0, DATA_QUERY_MAX_JSON_CONTAINER_ITEMS);
|
|
3773
|
-
}
|
|
3774
|
-
const bounded = /* @__PURE__ */ Object.create(null);
|
|
3775
|
-
for (const key of keys) {
|
|
3776
|
-
if (key.length > 65536) {
|
|
3777
|
-
flag();
|
|
3778
|
-
continue;
|
|
3779
|
-
}
|
|
3780
|
-
if (DATA_QUERY_FORBIDDEN_JSON_KEYS.has(key)) {
|
|
3781
|
-
flag();
|
|
3782
|
-
continue;
|
|
3783
|
-
}
|
|
3784
|
-
Object.defineProperty(bounded, key, {
|
|
3785
|
-
value: boundJsonValue(value[key], descriptor, truncation, depth + 1, ancestors),
|
|
3786
|
-
enumerable: true,
|
|
3787
|
-
configurable: true,
|
|
3788
|
-
writable: true
|
|
3789
|
-
});
|
|
3790
|
-
}
|
|
3791
|
-
return bounded;
|
|
3792
|
-
} finally {
|
|
3793
|
-
ancestors.delete(value);
|
|
3794
|
-
}
|
|
3795
|
-
}
|
|
3796
|
-
function toDeclaredValue(value, descriptor, truncation) {
|
|
3797
|
-
if (value === void 0) return null;
|
|
3798
|
-
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value.toISOString();
|
|
3799
|
-
if (descriptor.type === "json") return boundJsonValue(value, descriptor, truncation);
|
|
3800
|
-
if (typeof value === "string" && value.length > 4096) {
|
|
3801
|
-
truncation?.fields.add(descriptor.id);
|
|
3802
|
-
return capString(value);
|
|
3803
|
-
}
|
|
3804
|
-
if (typeof value === "bigint") {
|
|
3805
|
-
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) return queryFail(`Content query value for ${descriptor.id} exceeds the safe integer range`, "DATA_QUERY_RESULT_INVALID");
|
|
3806
|
-
return Number(value);
|
|
3807
|
-
}
|
|
3808
|
-
if (descriptor.type === "boolean" && typeof value === "number") return value !== 0;
|
|
3809
|
-
return value;
|
|
3810
|
-
}
|
|
3811
|
-
function jsonByteLength(value) {
|
|
3812
|
-
return encoder.encode(JSON.stringify(value) ?? "null").byteLength;
|
|
3813
|
-
}
|
|
3814
|
-
function capStringBytes(value, maxBytes) {
|
|
3815
|
-
if (maxBytes <= 0) return "";
|
|
3816
|
-
const totalBytes = encoder.encode(value).byteLength;
|
|
3817
|
-
if (totalBytes <= maxBytes) return value;
|
|
3818
|
-
if (totalBytes === value.length) return value.slice(0, maxBytes);
|
|
3819
|
-
let used = 0;
|
|
3820
|
-
let end = 0;
|
|
3821
|
-
for (const character of value) {
|
|
3822
|
-
const point = character.codePointAt(0) ?? 0;
|
|
3823
|
-
const cost = point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
|
|
3824
|
-
if (used + cost > maxBytes) break;
|
|
3825
|
-
used += cost;
|
|
3826
|
-
end += character.length;
|
|
3827
|
-
}
|
|
3828
|
-
return value.slice(0, end);
|
|
3829
|
-
}
|
|
3830
|
-
function reductionFor(field, value, identityField, descriptors) {
|
|
3831
|
-
if (field === identityField || value === null) return "none";
|
|
3832
|
-
const type = descriptors.get(field)?.type;
|
|
3833
|
-
if (type === "json") return "null";
|
|
3834
|
-
if (type === "datetime") return "null";
|
|
3835
|
-
if (typeof value === "string" && value.length > 0) return "truncate";
|
|
3836
|
-
return "none";
|
|
3837
|
-
}
|
|
3838
|
-
var REDUCED_VALUE_BYTES = {
|
|
3839
|
-
truncate: 2,
|
|
3840
|
-
null: 4,
|
|
3841
|
-
none: 0
|
|
3842
|
-
};
|
|
3843
|
-
function measureRow(row, descriptors, identityField) {
|
|
3844
|
-
const entries = Object.entries(row);
|
|
3845
|
-
const fields = entries.map(([field, value]) => {
|
|
3846
|
-
const declared = reductionFor(field, value, identityField, descriptors);
|
|
3847
|
-
const valueBytes = jsonByteLength(value);
|
|
3848
|
-
const reduction = declared === "none" || REDUCED_VALUE_BYTES[declared] < valueBytes ? declared : "none";
|
|
3849
|
-
return {
|
|
3850
|
-
field,
|
|
3851
|
-
keyBytes: jsonByteLength(field),
|
|
3852
|
-
valueBytes,
|
|
3853
|
-
reduction,
|
|
3854
|
-
floorBytes: reduction === "none" ? valueBytes : REDUCED_VALUE_BYTES[reduction]
|
|
3855
|
-
};
|
|
3856
|
-
});
|
|
3857
|
-
const structural = entries.length === 0 ? 3 : entries.length + 2;
|
|
3858
|
-
const overhead = fields.reduce((sum, entry) => sum + entry.keyBytes + 1, structural);
|
|
3859
|
-
return {
|
|
3860
|
-
fields,
|
|
3861
|
-
structural,
|
|
3862
|
-
cost: fields.reduce((sum, entry) => sum + entry.valueBytes, overhead),
|
|
3863
|
-
floor: fields.reduce((sum, entry) => sum + entry.floorBytes, overhead)
|
|
3864
|
-
};
|
|
3865
|
-
}
|
|
3866
|
-
function waterFillCap(sizes, available, floorBytes) {
|
|
3867
|
-
if (sizes.length === 0) return available >= 0 ? Number.MAX_SAFE_INTEGER : void 0;
|
|
3868
|
-
if (available < sizes.length * floorBytes) return void 0;
|
|
3869
|
-
const sorted = [...sizes].sort((left, right) => left - right);
|
|
3870
|
-
let prefix = 0;
|
|
3871
|
-
for (let index = 0; index < sorted.length; index += 1) {
|
|
3872
|
-
const remaining = sorted.length - index;
|
|
3873
|
-
if (prefix + remaining * sorted[index] > available) return Math.max(floorBytes, Math.floor((available - prefix) / remaining));
|
|
3874
|
-
prefix += sorted[index];
|
|
3875
|
-
}
|
|
3876
|
-
return Number.MAX_SAFE_INTEGER;
|
|
3877
|
-
}
|
|
3878
|
-
function shrinkRowToBytes(row, allowance, measured, truncation) {
|
|
3879
|
-
if (measured.floor > allowance) return void 0;
|
|
3880
|
-
const nulled = /* @__PURE__ */ new Set();
|
|
3881
|
-
let cap;
|
|
3882
|
-
for (;;) {
|
|
3883
|
-
const kept = measured.fields.filter((entry) => entry.reduction !== "truncate" && !nulled.has(entry.field));
|
|
3884
|
-
const truncatable = measured.fields.filter((entry) => entry.reduction === "truncate");
|
|
3885
|
-
const fixed = kept.reduce((sum, entry) => sum + entry.valueBytes, 0);
|
|
3886
|
-
const nulledBytes = REDUCED_VALUE_BYTES.null * nulled.size;
|
|
3887
|
-
const available = allowance - measured.fields.reduce((sum, entry) => sum + entry.keyBytes + 1, measured.structural) - fixed - nulledBytes;
|
|
3888
|
-
cap = waterFillCap(truncatable.map((entry) => entry.valueBytes), available, REDUCED_VALUE_BYTES.truncate);
|
|
3889
|
-
if (cap !== void 0) break;
|
|
3890
|
-
const biggestNullable = measured.fields.filter((entry) => entry.reduction === "null" && !nulled.has(entry.field)).sort((left, right) => right.valueBytes - left.valueBytes)[0];
|
|
3891
|
-
if (biggestNullable === void 0) return void 0;
|
|
3892
|
-
nulled.add(biggestNullable.field);
|
|
3893
|
-
}
|
|
3894
|
-
if (cap === void 0) return void 0;
|
|
3895
|
-
const shrunk = { ...row };
|
|
3896
|
-
for (const entry of measured.fields) {
|
|
3897
|
-
if (nulled.has(entry.field)) {
|
|
3898
|
-
shrunk[entry.field] = null;
|
|
3899
|
-
truncation.fields.add(entry.field);
|
|
3900
|
-
continue;
|
|
3901
|
-
}
|
|
3902
|
-
if (entry.reduction !== "truncate" || entry.valueBytes <= cap) continue;
|
|
3903
|
-
const original = shrunk[entry.field];
|
|
3904
|
-
let content = capStringBytes(original, cap - 2);
|
|
3905
|
-
let guard = 0;
|
|
3906
|
-
while (jsonByteLength(content) > cap && content.length > 0 && guard < 8) {
|
|
3907
|
-
guard += 1;
|
|
3908
|
-
const overshoot = jsonByteLength(content) - cap;
|
|
3909
|
-
content = capStringBytes(content, Math.max(0, encoder.encode(content).byteLength - overshoot));
|
|
3910
|
-
}
|
|
3911
|
-
shrunk[entry.field] = content;
|
|
3912
|
-
truncation.fields.add(entry.field);
|
|
3913
|
-
}
|
|
3914
|
-
return shrunk;
|
|
3915
|
-
}
|
|
3916
|
-
function allocateRowBytes(floors, costs, budget) {
|
|
3917
|
-
const allowances = [...floors];
|
|
3918
|
-
const seated = floors.reduce((sum, floor) => sum + floor, 0);
|
|
3919
|
-
if (seated > budget) return allowances;
|
|
3920
|
-
const appetites = costs.map((cost, index) => Math.max(0, cost - floors[index]));
|
|
3921
|
-
const order = floors.map((_, index) => index).sort((left2, right) => appetites[left2] - appetites[right]);
|
|
3922
|
-
let surplus = budget - seated;
|
|
3923
|
-
let left = floors.length;
|
|
3924
|
-
for (const index of order) {
|
|
3925
|
-
const granted = Math.min(appetites[index], Math.floor(surplus / left));
|
|
3926
|
-
allowances[index] += granted;
|
|
3927
|
-
surplus -= granted;
|
|
3928
|
-
left -= 1;
|
|
3929
|
-
}
|
|
3930
|
-
return allowances;
|
|
3931
|
-
}
|
|
3932
|
-
function boundRowBytes(rows, maxResultBytes, descriptors, identityField, truncation) {
|
|
3933
|
-
const budget = Math.max(0, (maxResultBytes || 1e6) - RESULT_ENVELOPE_RESERVE_BYTES);
|
|
3934
|
-
const framing = rows.length > 0 ? 1 : 2;
|
|
3935
|
-
const measured = rows.map((row) => measureRow(row, descriptors, identityField));
|
|
3936
|
-
if (measured.reduce((sum, row) => sum + row.cost, framing) <= budget) return {
|
|
3937
|
-
rows,
|
|
3938
|
-
truncated: false
|
|
3939
|
-
};
|
|
3940
|
-
if (measured.reduce((sum, row) => sum + row.floor, framing) > budget) return queryFail("Content query cannot fit its rows inside the maximum result bytes; request fewer fields or a smaller page.", "DATA_QUERY_RESULT_TOO_LARGE");
|
|
3941
|
-
const allowances = allocateRowBytes(measured.map((row) => row.floor), measured.map((row) => row.cost), budget - framing);
|
|
3942
|
-
return {
|
|
3943
|
-
rows: rows.map((row, index) => {
|
|
3944
|
-
if (measured[index].cost <= allowances[index]) return row;
|
|
3945
|
-
const shrunk = shrinkRowToBytes(row, allowances[index], measured[index], truncation);
|
|
3946
|
-
if (shrunk === void 0) return queryFail("Content query cannot fit a row inside its maximum result bytes; request fewer fields or a smaller page.", "DATA_QUERY_RESULT_TOO_LARGE");
|
|
3947
|
-
return shrunk;
|
|
3948
|
-
}),
|
|
3949
|
-
truncated: true
|
|
3950
|
-
};
|
|
3951
|
-
}
|
|
3952
|
-
function orderByTerms(sort) {
|
|
3953
|
-
if (!sort || sort.length === 0) return void 0;
|
|
3954
|
-
return sort.map((term) => `${term.field} ${term.direction.toUpperCase()}`);
|
|
3955
|
-
}
|
|
3956
|
-
async function executeContentQuery(collection, rawRequest, options = {}) {
|
|
3957
|
-
const schema = options.schema ?? await buildContentQuerySchema();
|
|
3958
|
-
assertUsableResultBudget(schema);
|
|
3959
|
-
const request = normalizeDataQueryRequest(rawRequest, schema);
|
|
3960
|
-
const queryFingerprint = createDataQueryFingerprint(request, schema);
|
|
3961
|
-
const descriptors = new Map(schema.fields.map((field) => [field.id, field]));
|
|
3962
|
-
const declared = new Set(descriptors.keys());
|
|
3963
|
-
const callerWhere = request.filter ? filterToDnf(request.filter, declared) : void 0;
|
|
3964
|
-
const scopeConditions = [...normalizeScopeConditions(resolveContentTenantReadScope()), ...normalizeApplicationScope(options.scope)];
|
|
3965
|
-
const where = mergeContentQueryScope(scopeConditions.length > 0 ? scopeConditions : void 0, callerWhere);
|
|
3966
|
-
const countOptions = where === void 0 ? void 0 : { where };
|
|
3967
|
-
const warnings = [];
|
|
3968
|
-
let truncated = false;
|
|
3969
|
-
let facets;
|
|
3970
|
-
if (request.mode === "rows") {
|
|
3971
|
-
const projection = request.projection ?? [schema.identityField];
|
|
3972
|
-
const offset = request.page?.kind === "offset" ? request.page.offset : 0;
|
|
3973
|
-
const limit = request.page?.limit ?? schema.defaultPageLimit ?? 50;
|
|
3974
|
-
const orderBy = orderByTerms(request.sort);
|
|
3975
|
-
const listed = await collection.list({
|
|
3976
|
-
select: projection,
|
|
3977
|
-
offset,
|
|
3978
|
-
limit,
|
|
3979
|
-
...orderBy ? { orderBy: orderBy.length === 1 ? orderBy[0] : orderBy } : {},
|
|
3980
|
-
...where === void 0 ? {} : { where }
|
|
3981
|
-
});
|
|
3982
|
-
const truncation = { fields: /* @__PURE__ */ new Set() };
|
|
3983
|
-
const bounded = boundRowBytes(listed.map((row) => {
|
|
3984
|
-
const out = {};
|
|
3985
|
-
for (const field of projection) {
|
|
3986
|
-
const descriptor = descriptors.get(field);
|
|
3987
|
-
if (!descriptor) return queryFail(`Content query returned an undeclared field: ${field}`, "DATA_QUERY_RESULT_NOT_ALLOWED");
|
|
3988
|
-
out[field] = toDeclaredValue(row[field], descriptor, truncation);
|
|
3989
|
-
}
|
|
3990
|
-
return out;
|
|
3991
|
-
}), schema.maxResultBytes ?? 1e6, descriptors, schema.identityField, truncation);
|
|
3992
|
-
const rows = bounded.rows;
|
|
3993
|
-
truncated = bounded.truncated || truncation.fields.size > 0;
|
|
3994
|
-
if (bounded.truncated) pushWarning(warnings, "Content query shortened values to fit its maximum result bytes; request fewer fields or a smaller page.");
|
|
3995
|
-
if (truncation.fields.size > 0) pushWarning(warnings, `Content query shortened over-long values in: ${[...truncation.fields].sort().join(", ")}.`);
|
|
3996
|
-
const total2 = await collection.count(countOptions);
|
|
3997
|
-
const page = {
|
|
3998
|
-
kind: "offset",
|
|
3999
|
-
offset,
|
|
4000
|
-
limit,
|
|
4001
|
-
hasMore: offset + rows.length < total2
|
|
4002
|
-
};
|
|
4003
|
-
return normalizeDataQueryResult({
|
|
4004
|
-
version: 1,
|
|
4005
|
-
requestId: request.requestId,
|
|
4006
|
-
queryFingerprint,
|
|
4007
|
-
identityField: schema.identityField,
|
|
4008
|
-
rows,
|
|
4009
|
-
page,
|
|
4010
|
-
total: {
|
|
4011
|
-
kind: "exact",
|
|
4012
|
-
value: total2
|
|
4013
|
-
},
|
|
4014
|
-
freshness: {
|
|
4015
|
-
state: "fresh",
|
|
4016
|
-
asOf: (/* @__PURE__ */ new Date()).toISOString()
|
|
4017
|
-
},
|
|
4018
|
-
warnings,
|
|
4019
|
-
truncated
|
|
4020
|
-
}, request, schema);
|
|
4021
|
-
}
|
|
4022
|
-
const total = await collection.count(countOptions);
|
|
4023
|
-
if (request.mode === "facets") {
|
|
4024
|
-
const requested = request.facets ?? [];
|
|
4025
|
-
const sourceFacets = await collection.facets({
|
|
4026
|
-
fields: requested.map((facet) => ({
|
|
4027
|
-
field: facet.field,
|
|
4028
|
-
limit: facet.limit
|
|
4029
|
-
})),
|
|
4030
|
-
...where === void 0 ? {} : { where }
|
|
4031
|
-
});
|
|
4032
|
-
const byField = new Map(sourceFacets.map((facet) => [facet.field, facet]));
|
|
4033
|
-
const facetTruncation = { fields: /* @__PURE__ */ new Set() };
|
|
4034
|
-
let facetBudget = Math.max(0, (schema.maxResultBytes ?? 1e6) - RESULT_ENVELOPE_RESERVE_BYTES);
|
|
4035
|
-
let facetBudgetExhausted = false;
|
|
4036
|
-
facets = requested.map((facet) => {
|
|
4037
|
-
const descriptor = descriptors.get(facet.field);
|
|
4038
|
-
if (!descriptor) return queryFail(`Content query returned an undeclared facet: ${facet.field}`, "DATA_QUERY_RESULT_NOT_ALLOWED");
|
|
4039
|
-
const values = byField.get(facet.field)?.values ?? [];
|
|
4040
|
-
facetBudget -= jsonByteLength(facet.field) + 48;
|
|
4041
|
-
const kept = [];
|
|
4042
|
-
let boundedOut = false;
|
|
4043
|
-
for (const entry of values.slice(0, facet.limit)) {
|
|
4044
|
-
const value = toDeclaredValue(entry.value, descriptor, facetTruncation);
|
|
4045
|
-
const cost = jsonByteLength({
|
|
4046
|
-
value,
|
|
4047
|
-
count: entry.count
|
|
4048
|
-
}) + 1;
|
|
4049
|
-
if (cost > facetBudget) {
|
|
4050
|
-
boundedOut = true;
|
|
4051
|
-
facetBudgetExhausted = true;
|
|
4052
|
-
break;
|
|
4053
|
-
}
|
|
4054
|
-
facetBudget -= cost;
|
|
4055
|
-
kept.push({
|
|
4056
|
-
value,
|
|
4057
|
-
count: entry.count
|
|
4058
|
-
});
|
|
4059
|
-
}
|
|
4060
|
-
return {
|
|
4061
|
-
field: facet.field,
|
|
4062
|
-
values: kept,
|
|
4063
|
-
truncated: boundedOut || values.length >= facet.limit
|
|
4064
|
-
};
|
|
4065
|
-
});
|
|
4066
|
-
if (facetTruncation.fields.size > 0) pushWarning(warnings, `Content query shortened over-long values in: ${[...facetTruncation.fields].sort().join(", ")}.`);
|
|
4067
|
-
if (facetBudgetExhausted) pushWarning(warnings, "Content query facets were truncated to fit their maximum result bytes; request fewer facets or a smaller facet limit.");
|
|
4068
|
-
truncated = facets.some((facet) => facet.truncated) || facetTruncation.fields.size > 0;
|
|
4069
|
-
}
|
|
4070
|
-
return normalizeDataQueryResult({
|
|
4071
|
-
version: 1,
|
|
4072
|
-
requestId: request.requestId,
|
|
4073
|
-
queryFingerprint,
|
|
4074
|
-
identityField: schema.identityField,
|
|
4075
|
-
rows: [],
|
|
4076
|
-
total: {
|
|
4077
|
-
kind: "exact",
|
|
4078
|
-
value: total
|
|
4079
|
-
},
|
|
4080
|
-
...facets === void 0 ? {} : { facets },
|
|
4081
|
-
freshness: {
|
|
4082
|
-
state: "fresh",
|
|
4083
|
-
asOf: (/* @__PURE__ */ new Date()).toISOString()
|
|
4084
|
-
},
|
|
4085
|
-
warnings,
|
|
4086
|
-
truncated
|
|
4087
|
-
}, request, schema);
|
|
4088
|
-
}
|
|
4089
|
-
//#endregion
|
|
4090
|
-
export { parseContentReviewResponse as $, normalizeContentTransparency as A, getAcceptedContentReviewStatuses as B, resolveContentTenantReadScope as C, serializeFact as D, serializeContent as E, smrtContentReviewPrompt as F, getContentReviewProfile as G, getContentReviewKind as H, smrtContentThumbnailAIGeneratePrompt as I, getEffectiveContentGovernanceConfig as J, getContentReviewProfileKeys as K, buildContentGovernanceAssignmentKey as L, ContentReference as M, promptMessageOptions as N, getQueryRows as O, smrtContentApplyCorrectionPrompt as P, loadPersistedContentGovernanceDefinitions as Q, buildContentReviewPrompt as R, mergeContentQueryScope as S, ThumbnailGenerator as T, getContentReviewPolicies as U, getContentGovernanceConfig as V, getContentReviewPolicy as W, hasStaticContentGovernancePolicy as X, getFallbackPolicyKind as Y, hasStaticContentGovernanceProfile as Z, assertContentQuerySchema as _, CONTENT_QUERY_IDENTITY_FIELD as a, isAssetAssociable as at, clearContentQuerySchemaCache as b, CONTENT_QUERY_MIN_RESULT_BYTES as c, DATA_QUERY_MAX_JSON_DEPTH as d, resetContentGovernanceConfig as et, DATA_QUERY_MAX_JSON_STRING_LENGTH as f, MAX_CONTENT_QUERY_OR_BRANCHES as g, DATA_QUERY_MAX_WARNING_LENGTH as h, CONTENT_QUERY_EXCLUDED_FIELD_IDS as i, ContentAsset as it, ContentReferences as j, isMissingTableError as k, DATA_QUERY_FORBIDDEN_JSON_KEYS as l, DATA_QUERY_MAX_WARNINGS as m, CONTENT_QUERY_DEFAULT_PAGE_LIMIT as n, resolveEffectiveContentGovernance as nt, CONTENT_QUERY_MAX_PAGE_LIMIT as o, isMetadataAccessor as ot, DATA_QUERY_MAX_STRING_LENGTH as p, getContentReviewRequirements as q, CONTENT_QUERY_DEFAULT_SORT as r, ContentAssetCollection as rt, CONTENT_QUERY_MAX_RESULT_BYTES as s, CONTENT_QUERY_CLASS_NAME as t, resolveConfiguredContentGovernance as tt, DATA_QUERY_MAX_JSON_CONTAINER_ITEMS as u, buildContentQuerySchema as v, Content as w, executeContentQuery as x, buildDataQuerySchemaForClass as y, configureContentGovernance as z };
|
|
4091
|
-
|
|
4092
|
-
//# sourceMappingURL=content-query-CraB4BJx.js.map
|