@happyvertical/smrt-content 0.51.3 → 0.51.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.
@@ -1 +1 @@
1
- {"version":3,"file":"content-query-DHDcVo7N.js","names":["left","total"],"sources":["../../src/__smrt-register__.ts","../../src/asset-associable.ts","../../src/content-asset.ts","../../src/content-assets.ts","../../src/content-governance.ts","../../src/content-prompts.ts","../../src/content-reference.ts","../../src/content-references.ts","../../src/content-transparency.ts","../../src/database-utils.ts","../../src/serialization.ts","../../src/thumbnail-generator.ts","../../src/content.ts","../../src/content-query.ts"],"sourcesContent":["/**\n * Self-registers this package's build-time manifest before any @smrt() decorator\n * in the package fires. Fixes issue #1132: in consumer runtimes (tsx, SvelteKit\n * SSR, plain `vite dev`) the decorator's synchronous manifest lookup previously\n * missed because no step populated the global manifest cache — classes got\n * registered with zero fields and `save()` / `toJSON()` silently dropped every\n * declared property.\n *\n * Import this module as the first statement in `src/index.ts` so its top-level\n * side effect runs ahead of any class module's @smrt() decorator.\n *\n * Silent no-op in dev/test, where the vitest plugin already populates manifests\n * via a different path. Only needs to succeed in the published dist output.\n *\n * @see https://github.com/happyvertical/smrt/issues/1132\n */\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n// During library builds, smrtPlugin replaces this entire module with generated\n// code that embeds the scanned manifest inline (#1506/#1507) — published dists\n// never resolve this URL, so downstream bundlers cannot break registration by\n// relocating the compiled module away from dist/manifest.json. The runtime\n// lookup below is the fallback for source-mode runs without that transform.\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","import type { Asset } from '@happyvertical/smrt-assets';\n\n/**\n * Contract for objects that participate in the content/asset association\n * pattern.\n *\n * Any class that exposes asset-relationship methods (e.g. `Content` and its\n * STI subclasses) implements this interface explicitly so consumers can rely\n * on the methods existing instead of falling back to `typeof === 'function'`\n * duck-typing checks.\n *\n * @example\n * ```ts\n * import type { AssetAssociable } from '@happyvertical/smrt-content';\n *\n * async function attachThumbnail(\n * target: AssetAssociable,\n * image: Asset,\n * ): Promise<void> {\n * // No defensive runtime checks needed — the contract guarantees the method.\n * await target.addAsset(image, 'thumbnail', 0);\n * }\n * ```\n */\nexport interface AssetAssociable {\n /**\n * Get all assets associated with this object.\n *\n * @param relationship - Optional filter by relationship type\n * (e.g. `'thumbnail'`, `'attachment'`).\n * @returns Array of associated assets. Returns an empty array if the object\n * has not been persisted yet.\n */\n getAssets(relationship?: string): Promise<Asset[]>;\n\n /**\n * Associate an asset with this object via a typed relationship.\n *\n * @param asset - The asset to associate. Must be persisted (have an `id`).\n * @param relationship - Relationship type. Must match\n * `/^[a-zA-Z_][a-zA-Z0-9_]*$/`. Defaults to `'attachment'`.\n * @param sortOrder - Non-negative integer for display order.\n * @throws if either side is unsaved or the relationship/sort order is invalid.\n */\n addAsset(\n asset: Asset,\n relationship?: string,\n sortOrder?: number,\n ): Promise<void>;\n\n /**\n * Remove an associated asset.\n *\n * @param assetId - The asset ID to detach.\n * @param relationship - Optional specific relationship to remove. If omitted,\n * all relationships between this object and the asset are removed.\n */\n removeAsset(assetId: string, relationship?: string): Promise<void>;\n}\n\n/**\n * Contract for objects exposing typed access to a `metadata` JSON field.\n *\n * Use alongside an explicit interface (such as {@link AssetAssociable}) to\n * give consumers a stable contract for reading/writing the loose JSON bag,\n * without leaking the `metadata: Record<string, any>` type into call sites.\n */\nexport interface MetadataAccessor<\n TMetadata extends Record<string, unknown> = Record<string, unknown>,\n> {\n /**\n * Get the full metadata record. Always returns an object (never `null`).\n * The returned reference is the live object — callers should treat it as\n * read-only and use {@link MetadataAccessor.setMetadata} or\n * {@link MetadataAccessor.updateMetadata} to mutate it safely.\n */\n getMetadata(): TMetadata;\n\n /**\n * Replace the entire metadata record.\n *\n * @param metadata - The new metadata object. `null`/`undefined` clears it.\n */\n setMetadata(metadata: TMetadata | null | undefined): void;\n\n /**\n * Shallow-merge the supplied patch over the existing metadata.\n *\n * @param patch - Partial metadata. Keys present in the patch overwrite the\n * existing record; keys absent from the patch are preserved.\n * @returns The merged metadata record.\n */\n updateMetadata(patch: Partial<TMetadata>): TMetadata;\n}\n\n/**\n * Runtime type guard for {@link AssetAssociable}.\n *\n * The interface exists primarily so that statically-typed consumers can drop\n * defensive `typeof === 'function'` checks. This guard is for the rare cases\n * where a value enters the system as `unknown` (deserialised payload, plugin\n * input, etc.) and the caller needs to confirm shape before delegating.\n *\n * @example\n * ```ts\n * if (isAssetAssociable(input)) {\n * await input.addAsset(asset, 'attachment');\n * }\n * ```\n */\nexport function isAssetAssociable(value: unknown): value is AssetAssociable {\n if (!value || typeof value !== 'object') return false;\n const candidate = value as Partial<AssetAssociable>;\n return (\n typeof candidate.getAssets === 'function' &&\n typeof candidate.addAsset === 'function' &&\n typeof candidate.removeAsset === 'function'\n );\n}\n\n/**\n * Runtime type guard for {@link MetadataAccessor}.\n *\n * Mirrors {@link isAssetAssociable} for the metadata-accessor contract.\n */\nexport function isMetadataAccessor(value: unknown): value is MetadataAccessor {\n if (!value || typeof value !== 'object') return false;\n const candidate = value as Partial<MetadataAccessor>;\n return (\n typeof candidate.getMetadata === 'function' &&\n typeof candidate.setMetadata === 'function' &&\n typeof candidate.updateMetadata === 'function'\n );\n}\n\n/**\n * Returns `true` if `value` is a plain object (not an array, not `null`,\n * not a class instance with a custom prototype). Used by `Content`'s metadata\n * accessors to enforce the \"record-shaped\" contract — arrays and other\n * non-record objects are normalised to `{}` rather than silently leaked\n * through.\n *\n * @internal\n */\nexport function isPlainMetadataRecord(\n value: unknown,\n): value is Record<string, unknown> {\n if (!value || typeof value !== 'object') return false;\n if (Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n}\n","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface ContentAssetOptions extends SmrtObjectOptions {\n contentId?: string;\n assetId?: string;\n relationship?: string;\n sortOrder?: number;\n tenantId?: string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'content_assets',\n conflictColumns: ['content_id', 'asset_id', 'relationship'],\n api: false,\n mcp: false,\n cli: false,\n})\nexport class ContentAsset extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Content', { required: true })\n contentId = '';\n\n @crossPackageRef('@happyvertical/smrt-assets:Asset', { required: true })\n assetId = '';\n\n @field({ required: true })\n relationship = 'attachment';\n\n @field()\n sortOrder = 0;\n\n constructor(options: ContentAssetOptions = {}) {\n super(options);\n if (options.contentId) this.contentId = options.contentId;\n if (options.assetId) this.assetId = options.assetId;\n if (options.relationship) this.relationship = options.relationship;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n }\n}\n","import type { SmrtCollectionOptions } from '@happyvertical/smrt-core';\nimport { SmrtJunction, smrt } from '@happyvertical/smrt-core';\nimport { ContentAsset } from './content-asset';\n\nexport interface ContentAssetCollectionOptions extends SmrtCollectionOptions {}\n\n@smrt({\n api: false,\n mcp: false,\n cli: false,\n})\nexport class ContentAssetCollection extends SmrtJunction<ContentAsset> {\n static readonly _itemClass = ContentAsset;\n protected leftField = 'contentId';\n protected rightField = 'assetId';\n}\n","import type { Fact, FactContentRelationship } from '@happyvertical/smrt-facts';\nimport {\n getCurrentTenant,\n isSuperAdminBypass,\n isSystemContext,\n isTenancyEnabled,\n} from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { Content } from './content';\n\nexport type ContentReviewKind = 'facts' | 'safety' | 'custom';\n\nexport type ContentReviewStatus =\n | 'pending'\n | 'passed'\n | 'flagged'\n | 'failed'\n | 'waived';\n\nexport type ContentReviewSeverity = 'info' | 'warning' | 'error';\n\nexport type ContentVersionKind =\n | 'manual'\n | 'draft'\n | 'review'\n | 'publication'\n | 'correction'\n | 'auto-generated';\n\nexport type ContentCorrectionType = 'fact' | 'safety' | 'copy' | 'custom';\n\nexport type ContentCorrectionStatus = 'draft' | 'published' | 'retracted';\n\nexport interface ContentReviewFinding {\n severity: ContentReviewSeverity;\n title: string;\n detail: string;\n factId?: string;\n quote?: string;\n suggestedChange?: string;\n ruleId?: string;\n}\n\nexport interface ContentReviewResult {\n status: ContentReviewStatus;\n summary: string;\n findings: ContentReviewFinding[];\n}\n\nexport interface ContentReviewRequirement {\n policyKey: string;\n label?: string;\n blocking?: boolean;\n acceptedStatuses?: ContentReviewStatus[];\n}\n\nexport interface ContentReviewProfileEvaluationItem {\n kind: ContentReviewKind;\n policyKey: string;\n label: string;\n blocking: boolean;\n acceptedStatuses: ContentReviewStatus[];\n missing: boolean;\n stale: boolean;\n executed: boolean;\n satisfied: boolean;\n latestReviewId: string | null;\n latestStatus: ContentReviewStatus | null;\n latestSummary: string | null;\n}\n\nexport interface ContentReviewProfileEvaluation {\n profileKey: string;\n ready: boolean;\n complete: boolean;\n requirements: ContentReviewProfileEvaluationItem[];\n}\n\nexport interface ContentReviewPolicyDefinition {\n key: string;\n label: string;\n kind: ContentReviewKind;\n instructions: string;\n enabled?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ContentGovernanceProfileDefinition {\n key: string;\n label: string;\n description?: string;\n enabled?: boolean;\n requirements: ContentReviewRequirement[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface ContentGovernanceAssignmentDefinition {\n key?: string;\n label?: string;\n contentType: string;\n contentVariant?: string | null;\n enabled?: boolean;\n factLinkingEnabled?: boolean;\n transparencyEnabled?: boolean;\n publicationProfileKey?: string | null;\n correctionProfileKey?: string | null;\n enforcePublishReadiness?: boolean;\n defaultFactRelationship?: FactContentRelationship;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ContentGovernanceConfig {\n policies: ContentReviewPolicyDefinition[];\n profiles: ContentGovernanceProfileDefinition[];\n assignments: ContentGovernanceAssignmentDefinition[];\n}\n\nexport interface PersistedContentGovernancePolicyRecord\n extends ContentReviewPolicyDefinition {\n id?: string;\n tenantId?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n}\n\nexport interface PersistedContentGovernanceProfileRecord\n extends ContentGovernanceProfileDefinition {\n id?: string;\n tenantId?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n}\n\nexport interface PersistedContentGovernanceAssignmentRecord\n extends ContentGovernanceAssignmentDefinition {\n id?: string;\n tenantId?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n}\n\nexport interface PersistedContentGovernanceDefinitions {\n policies: PersistedContentGovernancePolicyRecord[];\n profiles: PersistedContentGovernanceProfileRecord[];\n assignments: PersistedContentGovernanceAssignmentRecord[];\n}\n\nexport interface ResolvedContentGovernance {\n isGoverned: boolean;\n factLinkingEnabled: boolean;\n transparencyEnabled: boolean;\n publicationProfileKey: string | null;\n correctionProfileKey: string | null;\n enforcePublishReadiness: boolean;\n defaultFactRelationship: FactContentRelationship;\n reviewPolicies: ContentReviewPolicyDefinition[];\n availableProfiles: ContentGovernanceProfileDefinition[];\n assignment: ContentGovernanceAssignmentDefinition | null;\n}\n\nexport interface ContentGovernanceState extends ResolvedContentGovernance {\n reviewProfiles: ContentReviewProfileEvaluation[];\n}\n\nexport interface CreateContentVersionOptions {\n kind?: ContentVersionKind;\n summary?: string;\n metadata?: Record<string, unknown>;\n snapshot?: Record<string, unknown>;\n}\n\nexport interface RunContentReviewOptions {\n kind?: ContentReviewKind;\n policyKey?: string;\n reviewer?: string;\n instructions?: string;\n facts?: Fact[];\n factIds?: string[];\n metadata?: Record<string, unknown>;\n createVersion?: boolean;\n /** Claim the loaded content revision after AI work, before persisting review artifacts. */\n expectedUpdatedAt?: Date | string;\n}\n\nexport interface IssueContentCorrectionOptions {\n correctionType?: ContentCorrectionType;\n factId?: string;\n correctedFactText?: string;\n summary: string;\n incorrectText?: string;\n correctedText?: string;\n publicNote?: string;\n metadata?: Record<string, unknown>;\n createVersion?: boolean;\n publish?: boolean;\n}\n\nexport interface BuildContentReviewPromptOptions {\n kind: ContentReviewKind;\n content: Pick<\n Content,\n | 'id'\n | 'type'\n | 'status'\n | 'state'\n | 'title'\n | 'description'\n | 'body'\n | 'author'\n | 'publish_date'\n >;\n facts?: Fact[];\n policy?: ContentReviewPolicyDefinition | null;\n customInstructions?: string;\n}\n\nexport interface ResolveContentGovernanceOptions {\n contentType?: string | null;\n contentVariant?: string | null;\n db?: DatabaseInterface | null;\n tenantId?: string | null;\n}\n\nconst DEFAULT_FACT_RELATIONSHIP: FactContentRelationship = 'supports';\n\nconst DEFAULT_REVIEW_POLICIES: ContentReviewPolicyDefinition[] = [\n {\n key: 'facts',\n label: 'Facts Review',\n kind: 'facts',\n instructions: [\n 'Compare the draft copy against the supplied facts only.',\n 'Flag contradictions, unsupported claims, stale claims, and places where the copy should cite or qualify a statement.',\n 'Do not invent missing facts. If the draft makes a claim that is not supported by the provided facts, flag it clearly.',\n ].join(' '),\n enabled: true,\n },\n {\n key: 'safety',\n label: 'Safety Review',\n kind: 'safety',\n instructions: [\n 'Review the content for legal, reputational, and user-safety risks.',\n 'At minimum, check for defamation risk, privacy leaks, unverified allegations, unsafe instructions, and medical, legal, or financial claims that need qualification.',\n 'Flag content that should be softened, attributed, removed, or escalated for human review.',\n ].join(' '),\n enabled: true,\n },\n];\n\nconst DEFAULT_REVIEW_PROFILES: ContentGovernanceProfileDefinition[] = [\n {\n key: 'publication',\n label: 'Publication',\n description: 'Default publication-time editorial checks.',\n enabled: true,\n requirements: [\n {\n policyKey: 'safety',\n label: 'Safety Review',\n blocking: false,\n },\n {\n policyKey: 'facts',\n label: 'Facts Review',\n blocking: false,\n },\n ],\n },\n {\n key: 'correction',\n label: 'Correction',\n description: 'Default correction-time editorial checks.',\n enabled: true,\n requirements: [\n {\n policyKey: 'safety',\n label: 'Safety Review',\n blocking: false,\n },\n ],\n },\n];\n\nconst DEFAULT_CONTENT_GOVERNANCE_CONFIG: ContentGovernanceConfig = {\n policies: DEFAULT_REVIEW_POLICIES.map(clonePolicyDefinition),\n profiles: DEFAULT_REVIEW_PROFILES.map(cloneProfileDefinition),\n assignments: [],\n};\n\nlet governanceConfig: ContentGovernanceConfig = cloneGovernanceConfig(\n DEFAULT_CONTENT_GOVERNANCE_CONFIG,\n);\n// Process-global by design: apps are expected to configure governance once at\n// startup and use persisted records for runtime admin overrides.\n\nfunction cloneReviewRequirement(\n requirement: ContentReviewRequirement,\n): ContentReviewRequirement {\n return {\n ...requirement,\n acceptedStatuses: requirement.acceptedStatuses\n ? [...requirement.acceptedStatuses]\n : undefined,\n };\n}\n\nfunction normalizePolicyDefinition(\n policy: ContentReviewPolicyDefinition,\n): ContentReviewPolicyDefinition {\n return {\n key: policy.key,\n label: policy.label || policy.key,\n kind: policy.kind || getFallbackPolicyKind(policy.key),\n instructions: policy.instructions || '',\n enabled: policy.enabled !== false,\n metadata: policy.metadata ? { ...policy.metadata } : undefined,\n };\n}\n\nfunction clonePolicyDefinition(\n policy: ContentReviewPolicyDefinition,\n): ContentReviewPolicyDefinition {\n return normalizePolicyDefinition(policy);\n}\n\nfunction normalizeProfileDefinition(\n profile: ContentGovernanceProfileDefinition,\n): ContentGovernanceProfileDefinition {\n return {\n key: profile.key,\n label: profile.label || profile.key,\n description: profile.description || '',\n enabled: profile.enabled !== false,\n requirements: Array.isArray(profile.requirements)\n ? profile.requirements.map(cloneReviewRequirement)\n : [],\n metadata: profile.metadata ? { ...profile.metadata } : undefined,\n };\n}\n\nfunction cloneProfileDefinition(\n profile: ContentGovernanceProfileDefinition,\n): ContentGovernanceProfileDefinition {\n return normalizeProfileDefinition(profile);\n}\n\nexport function buildContentGovernanceAssignmentKey(\n contentType: string,\n contentVariant?: string | null,\n): string {\n return `${contentType || ''}::${contentVariant || ''}`;\n}\n\nfunction normalizeAssignmentDefinition(\n assignment: ContentGovernanceAssignmentDefinition,\n): ContentGovernanceAssignmentDefinition {\n return {\n key:\n assignment.key ||\n buildContentGovernanceAssignmentKey(\n assignment.contentType,\n assignment.contentVariant,\n ),\n label: assignment.label || '',\n contentType: assignment.contentType,\n contentVariant: assignment.contentVariant || '',\n enabled: assignment.enabled !== false,\n factLinkingEnabled: assignment.factLinkingEnabled === true,\n transparencyEnabled: assignment.transparencyEnabled === true,\n publicationProfileKey: assignment.publicationProfileKey || null,\n correctionProfileKey: assignment.correctionProfileKey || null,\n enforcePublishReadiness: assignment.enforcePublishReadiness === true,\n defaultFactRelationship:\n assignment.defaultFactRelationship || DEFAULT_FACT_RELATIONSHIP,\n metadata: assignment.metadata ? { ...assignment.metadata } : undefined,\n };\n}\n\nfunction cloneAssignmentDefinition(\n assignment: ContentGovernanceAssignmentDefinition,\n): ContentGovernanceAssignmentDefinition {\n return normalizeAssignmentDefinition(assignment);\n}\n\nfunction cloneGovernanceConfig(\n config: ContentGovernanceConfig,\n): ContentGovernanceConfig {\n return {\n policies: config.policies.map(clonePolicyDefinition),\n profiles: config.profiles.map(cloneProfileDefinition),\n assignments: config.assignments.map(cloneAssignmentDefinition),\n };\n}\n\nfunction mergeByKey<T extends { key?: string }>(\n previous: T[],\n next: T[],\n normalize: (value: T) => T,\n): T[] {\n const merged = new Map<string, T>();\n\n for (const value of previous) {\n const normalized = normalize(value);\n if (normalized.key) {\n merged.set(normalized.key, normalized);\n }\n }\n\n for (const value of next) {\n const normalized = normalize(value);\n if (normalized.key) {\n merged.set(normalized.key, normalized);\n }\n }\n\n return [...merged.values()];\n}\n\nexport function getFallbackPolicyKind(key: string): ContentReviewKind {\n if (key === 'facts') {\n return 'facts';\n }\n\n if (key === 'safety') {\n return 'safety';\n }\n\n return 'custom';\n}\n\nfunction getPolicyMap(\n policies: ContentReviewPolicyDefinition[],\n): Map<string, ContentReviewPolicyDefinition> {\n return new Map(\n policies.map((policy) => {\n const normalized = normalizePolicyDefinition(policy);\n return [normalized.key, normalized];\n }),\n );\n}\n\nfunction getProfileMap(\n profiles: ContentGovernanceProfileDefinition[],\n): Map<string, ContentGovernanceProfileDefinition> {\n return new Map(\n profiles.map((profile) => {\n const normalized = normalizeProfileDefinition(profile);\n return [normalized.key, normalized];\n }),\n );\n}\n\nfunction isMissingGovernanceTableError(error: unknown): boolean {\n const message =\n error instanceof Error ? error.message : String(error || 'Unknown error');\n\n return (\n message.includes(\"Run 'smrt db:migrate'\") ||\n /no such table/i.test(message) ||\n /does not exist/i.test(message)\n );\n}\n\nfunction getRowTimestamp(\n row: Record<string, unknown>,\n primaryKey: 'createdAt' | 'updatedAt',\n): string | null {\n const snakeCaseKey = primaryKey === 'createdAt' ? 'created_at' : 'updated_at';\n const value = row[primaryKey] ?? row[snakeCaseKey];\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nfunction getRowTenantId(row: Record<string, unknown>): string | null {\n const value = row.tenantId ?? row.tenant_id ?? null;\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nfunction getRowString(\n row: Record<string, unknown>,\n ...keys: string[]\n): string | null {\n for (const key of keys) {\n const value = row[key];\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n }\n return null;\n}\n\nfunction safeParseJSONObject(value: unknown): Record<string, unknown> {\n if (!value) {\n return {};\n }\n\n if (typeof value === 'object' && !Array.isArray(value)) {\n return { ...(value as Record<string, unknown>) };\n }\n\n try {\n const parsed = JSON.parse(String(value));\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? { ...(parsed as Record<string, unknown>) }\n : {};\n } catch {\n return {};\n }\n}\n\nfunction safeParseJSONArray<T>(value: unknown, mapEntry: (entry: T) => T): T[] {\n if (!value) {\n return [];\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => mapEntry(entry as T));\n }\n\n try {\n const parsed = JSON.parse(String(value));\n return Array.isArray(parsed)\n ? parsed.map((entry) => mapEntry(entry as T))\n : [];\n } catch {\n return [];\n }\n}\n\nfunction resolveGovernanceTenantFilter(\n tenantId: string | null | undefined,\n): string | null | undefined {\n if (tenantId !== undefined) {\n return tenantId;\n }\n\n if (isSystemContext() || isSuperAdminBypass()) {\n return undefined;\n }\n\n const currentTenant = getCurrentTenant();\n if (currentTenant?.tenantId) {\n return currentTenant.tenantId;\n }\n\n return isTenancyEnabled() ? null : undefined;\n}\n\nfunction mapPersistedPolicyRow(\n row: Record<string, unknown>,\n): PersistedContentGovernancePolicyRecord {\n return {\n id: typeof row.id === 'string' ? row.id : undefined,\n tenantId: getRowTenantId(row),\n createdAt: getRowTimestamp(row, 'createdAt'),\n updatedAt: getRowTimestamp(row, 'updatedAt'),\n ...normalizePolicyDefinition({\n key: String(row.key || ''),\n label: String(row.label || row.key || ''),\n kind: (row.kind ||\n getFallbackPolicyKind(String(row.key || ''))) as ContentReviewKind,\n instructions: String(row.instructions || ''),\n enabled: row.enabled !== false && row.enabled !== 0,\n metadata: safeParseJSONObject(row.metadata),\n }),\n };\n}\n\nfunction mapPersistedProfileRow(\n row: Record<string, unknown>,\n): PersistedContentGovernanceProfileRecord {\n return {\n id: typeof row.id === 'string' ? row.id : undefined,\n tenantId: getRowTenantId(row),\n createdAt: getRowTimestamp(row, 'createdAt'),\n updatedAt: getRowTimestamp(row, 'updatedAt'),\n ...normalizeProfileDefinition({\n key: String(row.key || ''),\n label: String(row.label || row.key || ''),\n description: String(row.description || ''),\n enabled: row.enabled !== false && row.enabled !== 0,\n requirements: safeParseJSONArray<ContentReviewRequirement>(\n row.requirements,\n cloneReviewRequirement,\n ),\n metadata: safeParseJSONObject(row.metadata),\n }),\n };\n}\n\nfunction mapPersistedAssignmentRow(\n row: Record<string, unknown>,\n): PersistedContentGovernanceAssignmentRecord {\n return {\n id: typeof row.id === 'string' ? row.id : undefined,\n tenantId: getRowTenantId(row),\n createdAt: getRowTimestamp(row, 'createdAt'),\n updatedAt: getRowTimestamp(row, 'updatedAt'),\n ...normalizeAssignmentDefinition({\n key: String(row.key || ''),\n label: String(row.label || ''),\n contentType: String(row.contentType || row.content_type || ''),\n contentVariant: String(row.contentVariant || row.content_variant || ''),\n enabled: row.enabled !== false && row.enabled !== 0,\n factLinkingEnabled:\n row.factLinkingEnabled === true ||\n row.fact_linking_enabled === true ||\n row.fact_linking_enabled === 1,\n transparencyEnabled:\n row.transparencyEnabled === true ||\n row.transparency_enabled === true ||\n row.transparency_enabled === 1,\n publicationProfileKey: getRowString(\n row,\n 'publicationProfileKey',\n 'publication_profile_key',\n ),\n correctionProfileKey: getRowString(\n row,\n 'correctionProfileKey',\n 'correction_profile_key',\n ),\n enforcePublishReadiness:\n row.enforcePublishReadiness === true ||\n row.enforce_publish_readiness === true ||\n row.enforce_publish_readiness === 1,\n // The relationship is stored as a string; trust the persisted value and\n // fall back to the default when absent.\n defaultFactRelationship:\n (getRowString(\n row,\n 'defaultFactRelationship',\n 'default_fact_relationship',\n ) as FactContentRelationship | null) || DEFAULT_FACT_RELATIONSHIP,\n metadata: safeParseJSONObject(row.metadata),\n }),\n };\n}\n\nexport async function loadPersistedContentGovernanceDefinitions(\n options: { db?: DatabaseInterface | null; tenantId?: string | null } = {},\n): Promise<PersistedContentGovernanceDefinitions> {\n const { db } = options;\n if (!db) {\n return {\n policies: [],\n profiles: [],\n assignments: [],\n };\n }\n\n try {\n const tenantId = resolveGovernanceTenantFilter(options.tenantId);\n const listGovernanceRows = async (tableName: string) => {\n const byCreatedAt = (\n a: Record<string, unknown>,\n b: Record<string, unknown>,\n ): number =>\n String(a.created_at || a.createdAt || '').localeCompare(\n String(b.created_at || b.createdAt || ''),\n );\n const sortRows = (rows: Record<string, unknown>[]) =>\n rows.sort(byCreatedAt);\n\n if (tenantId === undefined) {\n return sortRows(\n (await db.list(tableName, {})) as Record<string, unknown>[],\n );\n }\n\n if (tenantId === null) {\n return sortRows(\n (await db.list(tableName, {\n tenant_id: null,\n })) as Record<string, unknown>[],\n );\n }\n\n const [globalRows, tenantRows] = await Promise.all([\n db.list(tableName, { tenant_id: null }) as Promise<\n Record<string, unknown>[]\n >,\n db.list(tableName, { tenant_id: tenantId }) as Promise<\n Record<string, unknown>[]\n >,\n ]);\n\n return [...sortRows(globalRows), ...sortRows(tenantRows)];\n };\n const [policyRows, profileRows, assignmentRows] = await Promise.all([\n listGovernanceRows('content_governance_policies'),\n listGovernanceRows('content_governance_profiles'),\n listGovernanceRows('content_governance_assignments'),\n ]);\n\n return {\n policies: policyRows.map((row: Record<string, unknown>) =>\n mapPersistedPolicyRow(row),\n ),\n profiles: profileRows.map((row: Record<string, unknown>) =>\n mapPersistedProfileRow(row),\n ),\n assignments: assignmentRows.map((row: Record<string, unknown>) =>\n mapPersistedAssignmentRow(row),\n ),\n };\n } catch (error) {\n if (isMissingGovernanceTableError(error)) {\n return {\n policies: [],\n profiles: [],\n assignments: [],\n };\n }\n throw error;\n }\n}\n\nfunction resolveAssignmentDefinition(\n assignments: ContentGovernanceAssignmentDefinition[],\n options: Pick<\n ResolveContentGovernanceOptions,\n 'contentType' | 'contentVariant'\n >,\n): ContentGovernanceAssignmentDefinition | null {\n if (!options.contentType) {\n return null;\n }\n\n const exactMatch =\n assignments.find(\n (assignment) =>\n assignment.contentType === options.contentType &&\n (assignment.contentVariant || '') === (options.contentVariant || ''),\n ) || null;\n\n if (exactMatch) {\n return cloneAssignmentDefinition(exactMatch);\n }\n\n const typeOnlyMatch =\n assignments.find(\n (assignment) =>\n assignment.contentType === options.contentType &&\n !assignment.contentVariant,\n ) || null;\n\n return typeOnlyMatch ? cloneAssignmentDefinition(typeOnlyMatch) : null;\n}\n\nfunction buildResolvedGovernance(\n config: ContentGovernanceConfig,\n assignment: ContentGovernanceAssignmentDefinition | null,\n): ResolvedContentGovernance {\n const normalizedAssignment = assignment\n ? normalizeAssignmentDefinition(assignment)\n : null;\n if (normalizedAssignment?.enabled !== true) {\n return {\n isGoverned: false,\n factLinkingEnabled: false,\n transparencyEnabled: false,\n publicationProfileKey: null,\n correctionProfileKey: null,\n enforcePublishReadiness: false,\n defaultFactRelationship: DEFAULT_FACT_RELATIONSHIP,\n reviewPolicies: config.policies\n .map(clonePolicyDefinition)\n .filter((policy) => policy.enabled !== false),\n availableProfiles: config.profiles\n .map(cloneProfileDefinition)\n .filter((profile) => profile.enabled !== false),\n assignment: normalizedAssignment,\n };\n }\n\n return {\n isGoverned: true,\n factLinkingEnabled: normalizedAssignment.factLinkingEnabled === true,\n transparencyEnabled: normalizedAssignment.transparencyEnabled === true,\n publicationProfileKey: normalizedAssignment.publicationProfileKey || null,\n correctionProfileKey: normalizedAssignment.correctionProfileKey || null,\n enforcePublishReadiness:\n normalizedAssignment.enforcePublishReadiness === true,\n defaultFactRelationship:\n normalizedAssignment.defaultFactRelationship || DEFAULT_FACT_RELATIONSHIP,\n reviewPolicies: config.policies\n .map(clonePolicyDefinition)\n .filter((policy) => policy.enabled !== false),\n availableProfiles: config.profiles\n .map(cloneProfileDefinition)\n .filter((profile) => profile.enabled !== false),\n assignment: normalizedAssignment,\n };\n}\n\nfunction normalizeStatus(status: unknown): ContentReviewStatus {\n switch (status) {\n case 'pending':\n case 'passed':\n case 'flagged':\n case 'failed':\n case 'waived':\n return status;\n default:\n return 'flagged';\n }\n}\n\nfunction normalizeSeverity(severity: unknown): ContentReviewSeverity {\n switch (severity) {\n case 'info':\n case 'warning':\n case 'error':\n return severity;\n default:\n return 'warning';\n }\n}\n\nfunction extractJSONObject(raw: string): string | null {\n const start = raw.indexOf('{');\n const end = raw.lastIndexOf('}');\n if (start === -1 || end === -1 || end <= start) {\n return null;\n }\n return raw.slice(start, end + 1);\n}\n\nexport function getContentGovernanceConfig(): ContentGovernanceConfig {\n return cloneGovernanceConfig(governanceConfig);\n}\n\nexport function getStaticContentGovernanceConfig(): ContentGovernanceConfig {\n return cloneGovernanceConfig(governanceConfig);\n}\n\nexport function configureContentGovernance(\n config: Partial<ContentGovernanceConfig>,\n): ContentGovernanceConfig {\n governanceConfig = {\n policies: config.policies\n ? mergeByKey(\n governanceConfig.policies,\n config.policies,\n normalizePolicyDefinition,\n )\n : governanceConfig.policies.map(clonePolicyDefinition),\n profiles: config.profiles\n ? mergeByKey(\n governanceConfig.profiles,\n config.profiles,\n normalizeProfileDefinition,\n )\n : governanceConfig.profiles.map(cloneProfileDefinition),\n assignments: config.assignments\n ? mergeByKey(\n governanceConfig.assignments,\n config.assignments,\n normalizeAssignmentDefinition,\n )\n : governanceConfig.assignments.map(cloneAssignmentDefinition),\n };\n\n return getContentGovernanceConfig();\n}\n\nexport function resetContentGovernanceConfig(): ContentGovernanceConfig {\n governanceConfig = cloneGovernanceConfig(DEFAULT_CONTENT_GOVERNANCE_CONFIG);\n return getContentGovernanceConfig();\n}\n\nexport async function getEffectiveContentGovernanceConfig(\n options: { db?: DatabaseInterface | null; tenantId?: string | null } = {},\n): Promise<ContentGovernanceConfig> {\n const persisted = await loadPersistedContentGovernanceDefinitions({\n db: options.db,\n tenantId: options.tenantId,\n });\n\n return {\n policies: mergeByKey(\n governanceConfig.policies,\n persisted.policies,\n normalizePolicyDefinition,\n ),\n profiles: mergeByKey(\n governanceConfig.profiles,\n persisted.profiles,\n normalizeProfileDefinition,\n ),\n assignments: mergeByKey(\n governanceConfig.assignments,\n persisted.assignments,\n normalizeAssignmentDefinition,\n ),\n };\n}\n\nexport function hasStaticContentGovernancePolicy(key: string): boolean {\n return getPolicyMap(governanceConfig.policies).has(key);\n}\n\nexport function hasStaticContentGovernanceProfile(key: string): boolean {\n return getProfileMap(governanceConfig.profiles).has(key);\n}\n\nexport function getContentReviewPolicy(\n policyKey: string,\n policies: ContentReviewPolicyDefinition[] = governanceConfig.policies,\n): ContentReviewPolicyDefinition | null {\n return getPolicyMap(policies).get(policyKey) || null;\n}\n\nexport function getContentReviewKind(\n policyKey: string,\n policies: ContentReviewPolicyDefinition[] = governanceConfig.policies,\n): ContentReviewKind {\n const configuredKind = getPolicyMap(policies).get(policyKey)?.kind;\n return configuredKind || getFallbackPolicyKind(policyKey);\n}\n\nexport function getContentReviewProfile(\n profileKey: string,\n profiles: ContentGovernanceProfileDefinition[] = governanceConfig.profiles,\n): ContentGovernanceProfileDefinition | null {\n return getProfileMap(profiles).get(profileKey) || null;\n}\n\nexport function getContentReviewProfileKeys(\n profiles: ContentGovernanceProfileDefinition[] = governanceConfig.profiles,\n): string[] {\n return profiles\n .map(cloneProfileDefinition)\n .filter((profile) => profile.enabled !== false)\n .map((profile) => profile.key);\n}\n\nexport function getContentReviewPolicies(\n policies: ContentReviewPolicyDefinition[] = governanceConfig.policies,\n): ContentReviewPolicyDefinition[] {\n return policies\n .map(clonePolicyDefinition)\n .filter((policy) => policy.enabled !== false);\n}\n\nexport function getContentReviewRequirements(\n profileKey: string,\n profiles: ContentGovernanceProfileDefinition[] = governanceConfig.profiles,\n): ContentReviewRequirement[] {\n const profile = getContentReviewProfile(profileKey, profiles);\n return profile?.requirements.map(cloneReviewRequirement) || [];\n}\n\nexport function getAcceptedContentReviewStatuses(\n requirement: Pick<ContentReviewRequirement, 'acceptedStatuses'>,\n): ContentReviewStatus[] {\n return requirement.acceptedStatuses && requirement.acceptedStatuses.length > 0\n ? [...requirement.acceptedStatuses]\n : ['passed', 'waived'];\n}\n\nexport function resolveConfiguredContentGovernance(\n options: Pick<\n ResolveContentGovernanceOptions,\n 'contentType' | 'contentVariant'\n >,\n): ResolvedContentGovernance {\n const assignment = resolveAssignmentDefinition(governanceConfig.assignments, {\n contentType: options.contentType,\n contentVariant: options.contentVariant,\n });\n\n return buildResolvedGovernance(governanceConfig, assignment);\n}\n\nexport async function resolveEffectiveContentGovernance(\n options: ResolveContentGovernanceOptions,\n): Promise<ResolvedContentGovernance> {\n const effectiveConfig = await getEffectiveContentGovernanceConfig({\n db: options.db,\n tenantId: options.tenantId,\n });\n const assignment = resolveAssignmentDefinition(effectiveConfig.assignments, {\n contentType: options.contentType,\n contentVariant: options.contentVariant,\n });\n\n return buildResolvedGovernance(effectiveConfig, assignment);\n}\n\nexport function buildContentReviewPrompt(\n options: BuildContentReviewPromptOptions,\n): string {\n const { kind, content, facts = [], policy, customInstructions } = options;\n\n const factLines =\n facts.length > 0\n ? facts\n .map(\n (fact) =>\n `- [${fact.id}] status=${fact.status}; confidence=${fact.confidence}; sources=${fact.sourceCount}; text=${fact.textRefined}`,\n )\n .join('\\n')\n : 'No facts were supplied for this review.';\n\n const policyText =\n customInstructions?.trim() ||\n policy?.instructions ||\n getContentReviewPolicy(kind)?.instructions ||\n '';\n\n return `You are a structured editorial reviewer.\n\nReturn ONLY valid JSON with this shape:\n{\n \"status\": \"passed\" | \"flagged\" | \"failed\" | \"waived\",\n \"summary\": \"short summary\",\n \"findings\": [\n {\n \"severity\": \"info\" | \"warning\" | \"error\",\n \"title\": \"short title\",\n \"detail\": \"what is wrong and why\",\n \"factId\": \"optional fact id\",\n \"quote\": \"optional quoted text from the draft\",\n \"suggestedChange\": \"optional suggested fix\",\n \"ruleId\": \"optional policy or rule id\"\n }\n ]\n}\n\nReview kind: ${kind}\nPolicy key: ${policy?.key || kind}\nReview instructions:\n${policyText}\n\nDraft content:\n- id: ${content.id ?? ''}\n- type: ${content.type ?? ''}\n- status: ${content.status}\n- state: ${content.state}\n- author: ${content.author ?? ''}\n- publish_date: ${content.publish_date?.toISOString?.() ?? ''}\n\nTitle:\n${content.title}\n\nDescription:\n${content.description ?? ''}\n\nBody:\n${content.body}\n\nRelevant facts:\n${factLines}`;\n}\n\nexport function parseContentReviewResponse(raw: string): ContentReviewResult {\n const normalizedRaw = raw.trim();\n const jsonCandidate = extractJSONObject(normalizedRaw);\n\n if (jsonCandidate) {\n try {\n const parsed = JSON.parse(jsonCandidate) as {\n status?: unknown;\n summary?: unknown;\n findings?: unknown;\n };\n const findings = Array.isArray(parsed.findings)\n ? parsed.findings.map((rawFinding): ContentReviewFinding => {\n const finding =\n rawFinding && typeof rawFinding === 'object'\n ? (rawFinding as Record<string, unknown>)\n : {};\n return {\n severity: normalizeSeverity(finding.severity),\n title: String(finding.title || 'Review finding'),\n detail: String(finding.detail || ''),\n factId:\n typeof finding.factId === 'string' ? finding.factId : undefined,\n quote:\n typeof finding.quote === 'string' ? finding.quote : undefined,\n suggestedChange:\n typeof finding.suggestedChange === 'string'\n ? finding.suggestedChange\n : undefined,\n ruleId:\n typeof finding.ruleId === 'string' ? finding.ruleId : undefined,\n };\n })\n : [];\n\n return {\n status: normalizeStatus(parsed.status),\n summary: String(parsed.summary || normalizedRaw || 'Review completed'),\n findings,\n };\n } catch {\n // Fall through to a normalized fallback result.\n }\n }\n\n return {\n status: 'flagged',\n summary: normalizedRaw || 'Review completed without structured output.',\n findings: normalizedRaw\n ? [\n {\n severity: 'warning',\n title: 'Unstructured review output',\n detail: normalizedRaw,\n },\n ]\n : [],\n };\n}\n","import {\n definePrompt,\n type ResolvedPromptAI,\n} from '@happyvertical/smrt-prompts';\n\nexport const smrtContentReviewPrompt = definePrompt({\n key: 'smrtContent.review',\n template: `Content review request\n\nContent ID: {contentId}\nReview kind: {kind}\nPolicy key: {policyKey}\nTitle: {contentTitle}\nDescription: {contentDescription}\n\nBody:\n{contentBody}\n\n{reviewPrompt}`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport const smrtContentApplyCorrectionPrompt = definePrompt({\n key: 'smrtContent.applyCorrection',\n template: `You are revising an article draft to apply a factual correction.\n\nReturn only the fully revised body text, with no commentary.\n\nCurrent body:\n{body}\n\nCorrection summary:\n{summary}\n\nIncorrect text to fix:\n{incorrectText}\n\nCorrected text to incorporate:\n{correctedText}`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport const smrtContentThumbnailAIGeneratePrompt = definePrompt({\n key: 'smrtContent.thumbnail.aiGenerate',\n 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.`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport function promptMessageOptions(ai: ResolvedPromptAI) {\n return {\n ...(ai.params || {}),\n ...(ai.model ? { model: ai.model } : {}),\n ...(typeof ai.temperature === 'number'\n ? { temperature: ai.temperature }\n : {}),\n ...(typeof ai.maxTokens === 'number' ? { maxTokens: ai.maxTokens } : {}),\n };\n}\n","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface ContentReferenceOptions extends SmrtObjectOptions {\n sourceId?: string;\n targetId?: string;\n tenantId?: string | null;\n // ContentVersion.version pinned at citation time. Optional: references\n // created without a pin behave as before (they track the live target).\n // When set, callers can compare against the target's latest version to\n // surface drift between what was cited and what the target now says.\n targetVersion?: number | null;\n createdAt?: Date;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'content_references',\n conflictColumns: ['source_id', 'target_id'],\n})\nexport class ContentReference extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Content', { required: true })\n sourceId = '';\n\n @foreignKey('Content', { required: true })\n targetId = '';\n\n @field({ type: 'integer', nullable: true })\n targetVersion: number | null = null;\n\n @field()\n createdAt = new Date();\n\n constructor(options: ContentReferenceOptions = {}) {\n super(options);\n if (options.sourceId) this.sourceId = options.sourceId;\n if (options.targetId) this.targetId = options.targetId;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.targetVersion !== undefined)\n this.targetVersion = options.targetVersion;\n if (options.createdAt) this.createdAt = options.createdAt;\n }\n}\n","import type {\n JunctionAttachOptions,\n SmrtCollectionOptions,\n} from '@happyvertical/smrt-core';\nimport { SmrtJunction, smrt } from '@happyvertical/smrt-core';\nimport { ContentReference } from './content-reference';\n\nexport interface ContentReferencesOptions extends SmrtCollectionOptions {}\n\n/**\n * The `attach()` override below restores find-or-create idempotency for\n * `(sourceId, targetId)` — duplicate calls return the existing row\n * unchanged, preserving `id` and `createdAt`. This matters because\n * `ContentReference` rows are externally addressable via\n * `/api/v1/contentreferences/[id]`.\n *\n * Two REST entry points (both auto-generated by the scanner):\n * - `POST /api/v1/contentreferences` (from model CRUD) calls\n * `collection.create()` which is upsert-based — id/createdAt get\n * rewritten on conflict. Convenient for callers that don't care\n * about row id stability.\n * - `POST /api/v1/contentreferences/attach` (from the override below)\n * is idempotent. Use this for stable URLs.\n *\n * Internal callers (`Content.addReference()`) always hit the idempotent\n * path because they call the collection directly.\n *\n * The `/attach` route exists because R2 round-7 added `@smrt()` to this\n * class, which made the scanner pick up the override as a custom\n * collection method route. Pre-R2 had a `/link` route from the\n * pre-rename method name.\n */\n// Decorator with empty config — only needed so the scanner detects the\n// class. See FactContentCollection for the full rationale.\n@smrt()\nexport class ContentReferences extends SmrtJunction<ContentReference> {\n static readonly _itemClass = ContentReference;\n protected leftField = 'sourceId';\n protected rightField = 'targetId';\n // content_references has no sort_order column — preserve insertion order\n // by sorting on created_at, and disable setLinks position auto-indexing\n // so it doesn't try to write integer indices into the timestamp column.\n protected sortField: string | null = 'createdAt';\n protected positionField: string | null = null;\n\n async getForSource(sourceId: string): Promise<ContentReference[]> {\n return (await this.list({\n where: { sourceId },\n orderBy: 'created_at ASC',\n })) as ContentReference[];\n }\n\n async getForTarget(targetId: string): Promise<ContentReference[]> {\n return (await this.list({\n where: { targetId },\n orderBy: 'created_at ASC',\n })) as ContentReference[];\n }\n\n /**\n * Find-or-create idempotency: if a reference already exists for\n * (sourceId, targetId), return the existing row unchanged instead of\n * upserting a new row. This preserves the existing row's `id` and\n * `createdAt`, which is important because reference rows are\n * externally addressable via `/api/v1/contentreferences/[id]`.\n *\n * The base `SmrtJunction.attach` flow (this.create → db.upsert) would\n * overwrite both columns on every duplicate call.\n *\n * Reference pinning (main): `opts.targetVersion` pins the citation to a\n * specific `ContentVersion.version` for drift detection. Re-attaching an\n * existing edge with a different `targetVersion` updates the pin in place;\n * `undefined` leaves an existing pin untouched, while a brand-new row\n * defaults the pin to `null` (unpinned).\n */\n async attach(\n sourceId: string,\n targetId: string,\n opts: JunctionAttachOptions = {},\n ): Promise<ContentReference> {\n const targetVersion = opts.targetVersion as number | null | undefined;\n const existing = (await this.get({\n sourceId,\n targetId,\n })) as ContentReference | null;\n if (existing) {\n if (\n targetVersion !== undefined &&\n existing.targetVersion !== targetVersion\n ) {\n existing.targetVersion = targetVersion;\n await existing.save();\n }\n return existing;\n }\n return super.attach(sourceId, targetId, {\n ...opts,\n targetVersion: targetVersion ?? null,\n });\n }\n\n async unlink(sourceId: string, targetId: string): Promise<void> {\n await this.detach(sourceId, targetId);\n }\n}\n","export interface ContentTransparencyGeneration {\n aiAssisted: boolean;\n publicPrompt: string | null;\n model: string | null;\n}\n\nexport interface ContentTransparencySource {\n id: string | null;\n sourceType: string | null;\n sourceUrl: string | null;\n sourceTitle: string | null;\n credibility: number | null;\n extractedAt: string | null;\n metadata: Record<string, unknown>;\n}\n\nexport interface ContentTransparencyFact {\n id: string | null;\n textRaw?: string | null;\n textRefined?: string | null;\n status?: string | null;\n domain?: string | null;\n confidence?: number | null;\n sourceCount?: number | null;\n metadata?: Record<string, unknown>;\n relationship?: string | null;\n linkMetadata?: Record<string, unknown>;\n usedInArticle?: boolean;\n sources?: ContentTransparencySource[];\n}\n\nexport interface ContentTransparencyReference {\n id: string | null;\n title: string | null;\n url: string | null;\n originalUrl: string | null;\n type: string | null;\n source: string | null;\n usedFactIds: string[];\n extractedFacts: ContentTransparencyFact[];\n}\n\nexport interface ContentTransparencyPublicationVersion {\n id: string | null;\n version: number | null;\n kind: string | null;\n summary: string;\n createdAt: string | null;\n}\n\nexport interface ContentTransparencyVersionHistoryItem {\n id: string | null;\n version: number | null;\n kind: string | null;\n summary: string;\n createdAt: string | null;\n provenance: Record<string, unknown>;\n}\n\n/**\n * Serialized review record carried in a transparency snapshot. Only the fields\n * consumers read are named; the index signature preserves the remaining\n * serialized properties.\n */\nexport interface ContentTransparencyReview {\n id?: string | null;\n kind?: string | null;\n policyKey?: string | null;\n status?: string | null;\n summary?: string | null;\n createdAt?: string | null;\n [key: string]: unknown;\n}\n\n/**\n * Serialized review-profile evaluation carried in a transparency snapshot.\n */\nexport interface ContentTransparencyReviewProfile {\n profileKey?: string | null;\n [key: string]: unknown;\n}\n\n/**\n * Serialized correction record carried in a transparency snapshot.\n */\nexport interface ContentTransparencyCorrection {\n id?: string | null;\n summary?: string | null;\n publicNote?: string | null;\n publishedAt?: string | null;\n [key: string]: unknown;\n}\n\nexport interface ContentTransparencyData {\n generatedAt: string | null;\n snapshotKind: 'preview' | 'published';\n contentId: string | null;\n currentContentStatus: string | null;\n publicationProfileKey: string;\n publicationVersion: ContentTransparencyPublicationVersion | null;\n generation: ContentTransparencyGeneration;\n factsUsed: ContentTransparencyFact[];\n linkedFacts: ContentTransparencyFact[];\n otherExtractedFacts: ContentTransparencyFact[];\n references: ContentTransparencyReference[];\n reviews: ContentTransparencyReview[];\n reviewProfiles: ContentTransparencyReviewProfile[];\n corrections: ContentTransparencyCorrection[];\n versionHistory: ContentTransparencyVersionHistoryItem[];\n}\n\nfunction asObject(\n value: unknown,\n fallback: Record<string, unknown> = {},\n): Record<string, unknown> {\n return value && typeof value === 'object'\n ? { ...(value as Record<string, unknown>) }\n : fallback;\n}\n\nfunction asString(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nfunction asNumber(value: unknown): number | null {\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\nfunction asArray<T>(value: unknown): T[] {\n return Array.isArray(value) ? (value as T[]) : [];\n}\n\nfunction normalizeGeneration(value: unknown): ContentTransparencyGeneration {\n const generation = asObject(value);\n return {\n aiAssisted: Boolean(generation.aiAssisted),\n publicPrompt: asString(generation.publicPrompt),\n model: asString(generation.model),\n };\n}\n\nfunction normalizeFact(value: unknown): ContentTransparencyFact {\n const fact = asObject(value);\n return {\n ...fact,\n id: asString(fact.id),\n relationship: asString(fact.relationship),\n linkMetadata: asObject(fact.linkMetadata),\n usedInArticle: Boolean(fact.usedInArticle),\n sources: asArray<unknown>(fact.sources).map(normalizeSource),\n };\n}\n\nfunction normalizeSource(value: unknown): ContentTransparencySource {\n const source = asObject(value);\n return {\n id: asString(source.id),\n sourceType: asString(source.sourceType),\n sourceUrl: asString(source.sourceUrl),\n sourceTitle: asString(source.sourceTitle),\n credibility: asNumber(source.credibility),\n extractedAt: asString(source.extractedAt),\n metadata: asObject(source.metadata),\n };\n}\n\nfunction normalizeReference(value: unknown): ContentTransparencyReference {\n const reference = asObject(value);\n return {\n id: asString(reference.id),\n title: asString(reference.title),\n url: asString(reference.url),\n originalUrl: asString(reference.originalUrl),\n type: asString(reference.type),\n source: asString(reference.source),\n usedFactIds: asArray<string>(reference.usedFactIds).filter(Boolean),\n extractedFacts: asArray<unknown>(reference.extractedFacts).map(\n normalizeFact,\n ),\n };\n}\n\nfunction normalizePublicationVersion(\n value: unknown,\n): ContentTransparencyPublicationVersion | null {\n const publicationVersion = asObject(value);\n if (!publicationVersion.id && publicationVersion.version === undefined) {\n return null;\n }\n\n return {\n id: asString(publicationVersion.id),\n version: asNumber(publicationVersion.version),\n kind: asString(publicationVersion.kind),\n summary:\n typeof publicationVersion.summary === 'string'\n ? publicationVersion.summary\n : '',\n createdAt: asString(publicationVersion.createdAt),\n };\n}\n\nfunction normalizeVersionHistoryItem(\n value: unknown,\n): ContentTransparencyVersionHistoryItem {\n const version = asObject(value);\n return {\n id: asString(version.id),\n version: asNumber(version.version),\n kind: asString(version.kind),\n summary: typeof version.summary === 'string' ? version.summary : '',\n createdAt: asString(version.createdAt),\n provenance: asObject(version.provenance),\n };\n}\n\nfunction dedupeFacts(facts: ContentTransparencyFact[]) {\n const byKey = new Map<string, ContentTransparencyFact>();\n\n for (const fact of facts) {\n // Collapse effectively empty facts into a single placeholder bucket rather\n // than rendering duplicate blank entries in the public transparency view.\n const key =\n fact.id ||\n fact.textRefined ||\n fact.textRaw ||\n JSON.stringify(fact.metadata || {});\n if (!key) {\n continue;\n }\n\n byKey.set(key, fact);\n }\n\n return [...byKey.values()];\n}\n\nexport function normalizeContentTransparency(\n value: unknown,\n defaults: Partial<ContentTransparencyData> = {},\n): ContentTransparencyData {\n const snapshot = asObject(value);\n const references = asArray<unknown>(snapshot.references).map(\n normalizeReference,\n );\n const linkedFacts = asArray<unknown>(snapshot.linkedFacts).map(normalizeFact);\n const factsUsed =\n asArray<unknown>(snapshot.factsUsed).length > 0\n ? asArray<unknown>(snapshot.factsUsed).map(normalizeFact)\n : linkedFacts.filter((fact) => fact.usedInArticle);\n const otherExtractedFacts =\n asArray<unknown>(snapshot.otherExtractedFacts).length > 0\n ? asArray<unknown>(snapshot.otherExtractedFacts).map(normalizeFact)\n : dedupeFacts(\n references.flatMap((reference) =>\n reference.extractedFacts.filter((fact) => !fact.usedInArticle),\n ),\n );\n\n return {\n generatedAt: asString(snapshot.generatedAt) ?? defaults.generatedAt ?? null,\n snapshotKind:\n snapshot.snapshotKind === 'published'\n ? 'published'\n : defaults.snapshotKind || 'preview',\n contentId: asString(snapshot.contentId) ?? defaults.contentId ?? null,\n currentContentStatus:\n asString(snapshot.currentContentStatus) ??\n defaults.currentContentStatus ??\n null,\n publicationProfileKey:\n asString(snapshot.publicationProfileKey) ??\n asString(snapshot.publicationReviewProfileKey) ??\n defaults.publicationProfileKey ??\n 'publication',\n publicationVersion:\n normalizePublicationVersion(snapshot.publicationVersion) ??\n defaults.publicationVersion ??\n null,\n generation: normalizeGeneration(\n snapshot.generation ?? defaults.generation ?? {},\n ),\n factsUsed,\n linkedFacts,\n otherExtractedFacts,\n references,\n reviews: asArray<ContentTransparencyReview>(snapshot.reviews),\n reviewProfiles: asArray<ContentTransparencyReviewProfile>(\n snapshot.reviewProfiles,\n ),\n corrections: asArray<ContentTransparencyCorrection>(snapshot.corrections),\n versionHistory: asArray<unknown>(snapshot.versionHistory).map(\n normalizeVersionHistoryItem,\n ),\n };\n}\n","export function isMissingTableError(\n error: unknown,\n tableName: string,\n): boolean {\n const message = String(\n (error as Error)?.message || error || '',\n ).toLowerCase();\n\n return (\n message.includes(tableName.toLowerCase()) &&\n (message.includes('no such table') ||\n message.includes('does not exist') ||\n message.includes('relation'))\n );\n}\n\nexport function getQueryRows(result: unknown): Record<string, unknown>[] {\n return Array.isArray(result)\n ? (result as Record<string, unknown>[])\n : Array.isArray((result as { rows?: Record<string, unknown>[] })?.rows)\n ? ((result as { rows: Record<string, unknown>[] }).rows ?? [])\n : [];\n}\n","/**\n * Plain JSON shape produced by serializing a SMRT model instance. Values are\n * intentionally `unknown` — callers spread these records into API responses and\n * narrow individual fields where they need a concrete type.\n */\ntype SerializedRecord = Record<string, unknown>;\n\n/**\n * Minimal structural view of the model instances passed to the serializers.\n * Every model used here exposes `toJSON()` plus optional accessor methods for\n * its JSON-backed fields; the accessors are typed loosely because each model\n * returns a different concrete shape.\n */\ninterface SerializableModel {\n toJSON?: () => unknown;\n getMetadata?: () => unknown;\n getSnapshot?: () => unknown;\n getFindings?: () => unknown;\n getAllowedChannels?: () => unknown;\n getIntakeRules?: () => unknown;\n getPromotion?: () => unknown;\n getRevisions?: () => Promise<unknown[]> | unknown[];\n getAttachments?: () => Promise<unknown[]> | unknown[];\n getContributor?: () => Promise<unknown> | unknown;\n getReferences?: () => Promise<unknown[]> | unknown[];\n getAssets?: () => Promise<unknown[]> | unknown[];\n getReferenceDrift?: () => Promise<unknown> | unknown;\n metadata?: unknown;\n}\n\nfunction asModel(value: unknown): SerializableModel {\n return value && typeof value === 'object' ? (value as SerializableModel) : {};\n}\n\nfunction toJSON(value: unknown): SerializedRecord {\n const model = asModel(value);\n if (typeof model.toJSON === 'function') {\n const serialized = model.toJSON();\n return serialized && typeof serialized === 'object'\n ? (serialized as SerializedRecord)\n : {};\n }\n\n return value && typeof value === 'object' ? (value as SerializedRecord) : {};\n}\n\nexport function serializeFact(fact: unknown) {\n const model = asModel(fact);\n const data = toJSON(fact);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeFactLink(link: unknown) {\n const model = asModel(link);\n const data = toJSON(link);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentVersion(version: unknown) {\n const model = asModel(version);\n const data = toJSON(version);\n return {\n ...data,\n snapshot:\n typeof model.getSnapshot === 'function'\n ? model.getSnapshot()\n : data.snapshot || {},\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentReview(review: unknown) {\n const model = asModel(review);\n const data = toJSON(review);\n return {\n ...data,\n findings:\n typeof model.getFindings === 'function'\n ? model.getFindings()\n : data.findings || [],\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentCorrection(correction: unknown) {\n const model = asModel(correction);\n const data = toJSON(correction);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentContributor(contributor: unknown) {\n const model = asModel(contributor);\n const data = toJSON(contributor);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentContributionType(contributionType: unknown) {\n const model = asModel(contributionType);\n const data = toJSON(contributionType);\n return {\n ...data,\n allowedChannels:\n typeof model.getAllowedChannels === 'function'\n ? model.getAllowedChannels()\n : data.allowedChannels || [],\n intakeRules:\n typeof model.getIntakeRules === 'function'\n ? model.getIntakeRules()\n : data.intakeRules || {},\n promotion:\n typeof model.getPromotion === 'function'\n ? model.getPromotion()\n : data.promotion || {},\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentContributionRevision(revision: unknown) {\n const model = asModel(revision);\n const data = toJSON(revision);\n return {\n ...data,\n sourceMessageId: data.sourceMessageId || null,\n sourceThreadKey: data.sourceThreadKey || null,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentContributionAttachment(attachment: unknown) {\n const model = asModel(attachment);\n const data = toJSON(attachment);\n return {\n ...data,\n revisionId: data.revisionId || null,\n fileKey: data.fileKey || null,\n sourceUri: data.sourceUri || null,\n promotedAssetId: data.promotedAssetId || null,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport async function serializeContentContribution(contribution: unknown) {\n const model = asModel(contribution);\n const [revisions, attachments, contributor] = await Promise.all([\n typeof model.getRevisions === 'function' ? model.getRevisions() : [],\n typeof model.getAttachments === 'function' ? model.getAttachments() : [],\n typeof model.getContributor === 'function' ? model.getContributor() : null,\n ]);\n\n return {\n ...toJSON(contribution),\n contributor: contributor ? serializeContentContributor(contributor) : null,\n revisions: revisions.map(serializeContentContributionRevision),\n attachments: attachments.map(serializeContentContributionAttachment),\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : model.metadata || {},\n };\n}\n\nexport function serializeContentReviewProfileEvaluation(profile: unknown) {\n const data = toJSON(profile);\n return {\n ...data,\n requirements: Array.isArray(data.requirements) ? data.requirements : [],\n };\n}\n\nexport function serializeContentReviewPolicy(policy: unknown) {\n return {\n ...toJSON(policy),\n };\n}\n\nexport function serializeContentGovernanceProfile(profile: unknown) {\n const model = asModel(profile);\n const data = toJSON(profile);\n return {\n ...data,\n requirements: Array.isArray(data.requirements) ? data.requirements : [],\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentGovernanceAssignment(assignment: unknown) {\n const model = asModel(assignment);\n const data = toJSON(assignment);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentGovernanceState(state: unknown) {\n const data = toJSON(state);\n return {\n ...data,\n reviewPolicies: Array.isArray(data.reviewPolicies)\n ? data.reviewPolicies.map(serializeContentReviewPolicy)\n : [],\n availableProfiles: Array.isArray(data.availableProfiles)\n ? data.availableProfiles.map(serializeContentGovernanceProfile)\n : [],\n reviewProfiles: Array.isArray(data.reviewProfiles)\n ? data.reviewProfiles.map(serializeContentReviewProfileEvaluation)\n : [],\n };\n}\n\n/**\n * Reference-drift edge keyed by target content id. Mirrors the shape returned\n * by `Content.getReferenceDrift()`.\n */\ninterface ReferenceDriftEdge {\n citedVersion: number | null;\n currentVersion: number | null;\n isDrifted: boolean;\n}\n\nexport async function serializeContent(content: unknown) {\n const model = asModel(content);\n const [references, assets] = await Promise.all([\n typeof model.getReferences === 'function' ? model.getReferences() : [],\n typeof model.getAssets === 'function' ? model.getAssets() : [],\n ]);\n\n // Only resolve drift when there are references to drift against — list\n // endpoints serializing many ref-less items shouldn't pay the version\n // lookup cost.\n const drift =\n references.length > 0 && typeof model.getReferenceDrift === 'function'\n ? await model.getReferenceDrift()\n : [];\n\n const driftByTargetId = new Map<string, ReferenceDriftEdge>(\n Array.isArray(drift)\n ? drift\n .map((entry) => asModel(entry))\n .filter(\n (entry): entry is SerializableModel & { targetId: string } =>\n typeof (entry as { targetId?: unknown }).targetId === 'string',\n )\n .map((entry) => {\n const edge = entry as {\n targetId: string;\n citedVersion?: unknown;\n currentVersion?: unknown;\n isDrifted?: unknown;\n };\n return [\n edge.targetId,\n {\n citedVersion: (edge.citedVersion as number | null) ?? null,\n currentVersion: (edge.currentVersion as number | null) ?? null,\n isDrifted: Boolean(edge.isDrifted),\n },\n ] satisfies [string, ReferenceDriftEdge];\n })\n : [],\n );\n\n return {\n ...toJSON(content),\n referenceIds: references\n .map((reference) => asModel(reference) as { id?: unknown })\n .map((reference) => reference.id)\n .filter(Boolean),\n references: references.map((reference) => {\n const base = toJSON(reference);\n const edge =\n typeof base.id === 'string' ? driftByTargetId.get(base.id) : null;\n return edge\n ? {\n ...base,\n citedVersion: edge.citedVersion,\n currentVersion: edge.currentVersion,\n isDrifted: edge.isDrifted,\n }\n : base;\n }),\n assetIds: assets\n .map((asset) => (asModel(asset) as { id?: unknown }).id)\n .filter(Boolean),\n assets: assets.map((asset) => toJSON(asset)),\n };\n}\n","/**\n * Thumbnail Generator for Content\n *\n * Generates thumbnail images for content using various strategies:\n * - headline-card: Draws article title on branded background\n * - static-map: Uses static maps API for location-based content\n * - ai-generate: Uses AI image generation for creative thumbnails\n */\n\nimport type { AIClient, AIClientOptions } from '@happyvertical/ai';\nimport { fetchStaticMap, type StaticMapProvider } from '@happyvertical/geo';\nimport {\n generateHeadlineCard,\n type HeadlineCardTemplate,\n} from '@happyvertical/images';\nimport type { DatabaseConfig } from '@happyvertical/smrt-core';\nimport type { Image } from '@happyvertical/smrt-images';\nimport { ImageCollection } from '@happyvertical/smrt-images';\nimport {\n type ResolvedPrompt,\n resolvePrompt,\n} from '@happyvertical/smrt-prompts';\nimport type { Content } from './content';\nimport {\n promptMessageOptions,\n smrtContentThumbnailAIGeneratePrompt,\n} from './content-prompts';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Available thumbnail generation strategies\n */\nexport type ThumbnailStrategy = 'headline-card' | 'static-map' | 'ai-generate';\n\n/**\n * Base options for all strategies\n */\ninterface BaseThumbnailOptions {\n /**\n * Generation strategy\n */\n strategy: ThumbnailStrategy;\n\n /**\n * Width in pixels\n * @default 1200\n */\n width?: number;\n\n /**\n * Height in pixels\n * @default 630\n */\n height?: number;\n}\n\n/**\n * Options for headline card strategy\n */\nexport interface HeadlineCardThumbnailOptions extends BaseThumbnailOptions {\n strategy: 'headline-card';\n\n /**\n * Primary brand color (hex)\n * @default '#3b82f6'\n */\n brandColor?: string;\n\n /**\n * Background color (hex)\n * @default '#ffffff'\n */\n backgroundColor?: string;\n\n /**\n * Optional subtitle/category text\n */\n subtitle?: string;\n\n /**\n * Optional logo URL\n */\n logoUrl?: string;\n\n /**\n * Template style\n * @default 'default'\n */\n template?: HeadlineCardTemplate;\n}\n\n/**\n * Options for static map strategy\n */\nexport interface StaticMapThumbnailOptions extends BaseThumbnailOptions {\n strategy: 'static-map';\n\n /**\n * Map provider\n * @default 'mapbox'\n */\n mapProvider?: StaticMapProvider;\n\n /**\n * Zoom level (1-20)\n * @default 14\n */\n zoom?: number;\n\n /**\n * Marker color\n * @default 'e74c3c'\n */\n markerColor?: string;\n\n /**\n * Mapbox style (if using mapbox provider)\n */\n mapboxStyle?: string;\n\n /**\n * Google map type (if using google provider)\n */\n googleMapType?: 'roadmap' | 'satellite' | 'terrain' | 'hybrid';\n}\n\n/**\n * Options for AI generation strategy\n */\nexport interface AIGenerateThumbnailOptions extends BaseThumbnailOptions {\n strategy: 'ai-generate';\n\n /**\n * AI provider configuration\n */\n ai?: AIClientOptions | AIClient;\n\n /**\n * Custom prompt for image generation\n * If not provided, generates based on content title/body\n */\n prompt?: string;\n\n /**\n * Style hint for image generation\n * @default 'photorealistic'\n */\n style?: 'photorealistic' | 'illustration' | 'abstract' | 'minimal';\n}\n\n/**\n * Union type for all thumbnail options\n */\nexport type ThumbnailOptions =\n | HeadlineCardThumbnailOptions\n | StaticMapThumbnailOptions\n | AIGenerateThumbnailOptions;\n\n// ============================================================================\n// Generator Class\n// ============================================================================\n\n/**\n * Options for ThumbnailGenerator\n */\nexport interface ThumbnailGeneratorOptions {\n /**\n * Database configuration for storing generated images\n */\n db?: DatabaseConfig;\n\n /**\n * Alias for `db` — mirrors the `SmrtClassOptions.persistence` alias so\n * callers can pass the same options shape they use for SmrtObject/Collection.\n *\n * @deprecated Prefer `db`. Retained for parity with `SmrtClassOptions`.\n */\n persistence?: DatabaseConfig;\n\n /**\n * AI client configuration for AI-generated thumbnails\n */\n ai?: AIClientOptions | AIClient;\n}\n\ninterface ImageGenerationClient {\n generateImage(\n prompt: string,\n options?: Record<string, unknown>,\n ): Promise<{\n images?: Array<{ data?: Buffer | string }>;\n }>;\n}\n\nfunction isImageGenerationClient(\n value: AIClientOptions | AIClient,\n): value is AIClient & ImageGenerationClient {\n return (\n !!value &&\n typeof value === 'object' &&\n typeof (value as Record<string, unknown>).generateImage === 'function'\n );\n}\n\nfunction isAIClientOptions(\n value: AIClientOptions | AIClient,\n): value is AIClientOptions {\n return (\n !!value && typeof value === 'object' && !isImageGenerationClient(value)\n );\n}\n\n/**\n * ThumbnailGenerator creates thumbnails for content using various strategies\n */\nexport class ThumbnailGenerator {\n constructor(\n private content: Content,\n private options: ThumbnailGeneratorOptions = {},\n ) {\n // Normalize the `persistence` alias to `db` once so every downstream call\n // (prompt resolution, ImageCollection.create, save sites) sees the same\n // database regardless of which option name the caller used. Without this,\n // a caller passing `persistence: ...` would have prompt resolution honor\n // the alias while image saving silently used `undefined`.\n if (!this.options.db && this.options.persistence) {\n this.options.db = this.options.persistence;\n }\n }\n\n /**\n * Generate a thumbnail using the specified strategy\n */\n async generate(options: ThumbnailOptions): Promise<Image> {\n switch (options.strategy) {\n case 'headline-card':\n return this.generateHeadlineCard(options);\n case 'static-map':\n return this.generateStaticMap(options);\n case 'ai-generate':\n return this.generateWithAI(options);\n default:\n throw new Error(\n // `options` is narrowed to `never` here (exhaustive switch); read the\n // runtime discriminant through a minimal structural view.\n `Unknown thumbnail strategy: ${(options as { strategy: string }).strategy}`,\n );\n }\n }\n\n /**\n * Generate a headline card thumbnail\n */\n private async generateHeadlineCard(\n options: HeadlineCardThumbnailOptions,\n ): Promise<Image> {\n const title = this.content.title || this.content.name || 'Untitled';\n\n const result = await generateHeadlineCard(title, {\n width: options.width ?? 1200,\n height: options.height ?? 630,\n brandColor: options.brandColor,\n backgroundColor: options.backgroundColor,\n subtitle: options.subtitle ?? this.content.category ?? undefined,\n logoUrl: options.logoUrl,\n template: options.template,\n });\n\n return this.createImageFromBuffer(result.buffer, {\n width: result.width,\n height: result.height,\n mimeType: result.mimeType,\n name: `${this.content.id}-headline.png`,\n });\n }\n\n /**\n * Generate a static map thumbnail\n */\n private async generateStaticMap(\n options: StaticMapThumbnailOptions,\n ): Promise<Image> {\n // Coordinates live in the loose `metadata` bag (typed `unknown` values);\n // read them at a documented `string | number` boundary for arithmetic.\n const coordinateMetadata = this.content.metadata as Record<\n string,\n string | number | null | undefined\n >;\n const rawLatitude = coordinateMetadata?.latitude ?? coordinateMetadata?.lat;\n const rawLongitude =\n coordinateMetadata?.longitude ??\n coordinateMetadata?.lng ??\n coordinateMetadata?.lon;\n\n if (rawLatitude == null || rawLongitude == null) {\n throw new Error(\n 'Content metadata must contain latitude and longitude for static-map strategy',\n );\n }\n\n // Parse and validate coordinates\n // Use unary + for strict parsing (rejects \"45invalid\" unlike parseFloat)\n const latitude =\n typeof rawLatitude === 'string' ? +rawLatitude : rawLatitude;\n const longitude =\n typeof rawLongitude === 'string' ? +rawLongitude : rawLongitude;\n\n if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90) {\n throw new Error(\n `Invalid latitude value \"${rawLatitude}\" in content metadata; expected a number between -90 and 90.`,\n );\n }\n\n if (!Number.isFinite(longitude) || longitude < -180 || longitude > 180) {\n throw new Error(\n `Invalid longitude value \"${rawLongitude}\" in content metadata; expected a number between -180 and 180.`,\n );\n }\n\n type FetchStaticMapOptions = NonNullable<\n Parameters<typeof fetchStaticMap>[2]\n >;\n const mapboxStyle = options.mapboxStyle as\n | FetchStaticMapOptions['mapboxStyle']\n | undefined;\n\n const result = await fetchStaticMap(latitude, longitude, {\n provider: options.mapProvider ?? 'mapbox',\n width: options.width ?? 1200,\n height: options.height ?? 630,\n zoom: options.zoom ?? 14,\n markerColor: options.markerColor,\n mapboxStyle,\n googleMapType: options.googleMapType,\n });\n\n return this.createImageFromBuffer(result.buffer, {\n width: result.width,\n height: result.height,\n mimeType: result.mimeType,\n name: `${this.content.id}-map.png`,\n });\n }\n\n /**\n * Generate a thumbnail using AI image generation\n */\n private async generateWithAI(\n options: AIGenerateThumbnailOptions,\n ): Promise<Image> {\n // Dynamic import to avoid requiring AI package when not using this strategy\n const { getAI } = await import('@happyvertical/ai');\n\n const aiInput = options.ai ?? this.options.ai;\n if (!aiInput) {\n throw new Error(\n 'AI configuration required for ai-generate strategy. Provide via options.ai or constructor options.',\n );\n }\n\n const ai = isImageGenerationClient(aiInput)\n ? aiInput\n : isAIClientOptions(aiInput)\n ? await getAI(aiInput)\n : (() => {\n throw new Error(\n 'AI client does not support image generation for ai-generate thumbnails.',\n );\n })();\n\n // Generate prompt if not provided. When the caller supplies a literal\n // prompt we skip prompt resolution entirely (no tenant override path).\n // When we resolve from the registry we also forward the resolved AI\n // options (model, params) so `editable: { model, params }` actually\n // takes effect for thumbnail generation.\n const width = options.width ?? 1200;\n const height = options.height ?? 630;\n let prompt: string;\n let aiOverrideOptions: Record<string, unknown> = {};\n if (options.prompt) {\n prompt = options.prompt;\n } else {\n const built = await this.buildAIPrompt(options.style ?? 'photorealistic');\n prompt = built.text;\n aiOverrideOptions = promptMessageOptions(built.ai);\n }\n\n const result = await ai.generateImage(prompt, {\n ...aiOverrideOptions,\n size: `${width}x${height}`,\n outputFormat: 'buffer',\n });\n\n if (!result.images || result.images.length === 0) {\n throw new Error('AI image generation returned no results');\n }\n\n // Handle buffer or base64 responses\n let buffer: Buffer;\n const imageData = result.images[0].data;\n if (Buffer.isBuffer(imageData)) {\n buffer = imageData;\n } else if (typeof imageData === 'string') {\n // Could be base64 or URL - try base64 first\n if (imageData.startsWith('http')) {\n const response = await fetch(imageData);\n if (!response.ok) {\n throw new Error(\n `AI image generation URL fetch failed: ${response.status} ${response.statusText}`,\n );\n }\n buffer = Buffer.from(await response.arrayBuffer());\n } else {\n buffer = Buffer.from(imageData, 'base64');\n }\n } else {\n throw new Error('AI image generation returned unexpected format');\n }\n\n return this.createImageFromBuffer(buffer, {\n width: options.width ?? 1200,\n height: options.height ?? 630,\n mimeType: 'image/png',\n name: `${this.content.id}-ai.png`,\n });\n }\n\n /**\n * Build a prompt for AI image generation based on content.\n *\n * Resolves via `@happyvertical/smrt-prompts` so tenants can override the\n * template/profile/model/params at runtime. Only non-PII content fields\n * (title, description) and the caller-supplied style hint are passed.\n * Internal IDs and the freeform `metadata` blob are intentionally excluded.\n *\n * Returns the full ResolvedPrompt (text + ai config) so the caller can\n * forward `model`/`params` overrides to `ai.generateImage()`. Returning\n * only the text would silently drop the editable model/params overrides.\n */\n private async buildAIPrompt(style: string): Promise<ResolvedPrompt> {\n const title = this.content.title || 'Untitled';\n const description = this.content.description || '';\n\n const stylePrompts: Record<string, string> = {\n photorealistic:\n 'photorealistic, high quality, professional photography, 8k resolution',\n illustration:\n 'digital illustration, clean vector art, modern design, vibrant colors',\n abstract:\n 'abstract art, geometric shapes, modern minimalist, artistic interpretation',\n minimal:\n 'minimalist design, simple shapes, clean composition, subtle colors',\n };\n\n const styleHint = stylePrompts[style] || stylePrompts.photorealistic;\n\n return resolvePrompt(smrtContentThumbnailAIGeneratePrompt.key, {\n db: this.options.db,\n tenantId: this.content.tenantId,\n variables: {\n style,\n title,\n styleHint,\n descriptionClause: description\n ? `The article is about: ${description}. `\n : '',\n },\n });\n }\n\n /**\n * Create an Image object from a buffer\n */\n private async createImageFromBuffer(\n buffer: Buffer,\n metadata: {\n width: number;\n height: number;\n mimeType: string;\n name: string;\n },\n ): Promise<Image> {\n const images = await ImageCollection.create({\n db: this.options.db,\n });\n\n // Create the image record. `SmrtCollection.create()` already persists\n // (upsert) the row, so a follow-up `image.save()` was redundant (#1387).\n const image = await images.create({\n name: metadata.name,\n mimeType: metadata.mimeType,\n width: metadata.width,\n height: metadata.height,\n sourceUri: `data:${metadata.mimeType};base64,${buffer.toString('base64')}`,\n });\n\n return image;\n }\n}\n","import { type Asset, AssetCollection } from '@happyvertical/smrt-assets';\nimport type {\n SmrtObjectOptions,\n SmrtSaveOptions,\n} from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport type {\n Fact,\n FactClaimSupportAssessment,\n FactClaimSupportStatus,\n FactContent,\n FactContentRelationship,\n FactEvidence,\n FactEvidenceStatus,\n FactExtractionCandidate,\n FactSource,\n} from '@happyvertical/smrt-facts';\nimport type { Image } from '@happyvertical/smrt-images';\nimport { ImageCollection } from '@happyvertical/smrt-images';\nimport { resolvePrompt } from '@happyvertical/smrt-prompts';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { AssetAssociable, MetadataAccessor } from './asset-associable';\nimport { isPlainMetadataRecord } from './asset-associable';\nimport type { ContentBodyFormat } from './body-format';\nimport { isContentBodyFormat } from './body-format';\nimport { ContentAssetCollection } from './content-assets';\nimport {\n buildContentGovernanceAssignmentKey,\n buildContentReviewPrompt,\n type ContentGovernanceState,\n type ContentReviewFinding,\n type ContentReviewProfileEvaluation,\n type CreateContentVersionOptions,\n getAcceptedContentReviewStatuses,\n getContentReviewKind,\n getContentReviewPolicy,\n getContentReviewProfileKeys,\n getContentReviewRequirements,\n type IssueContentCorrectionOptions,\n parseContentReviewResponse,\n type ResolvedContentGovernance,\n type RunContentReviewOptions,\n resolveConfiguredContentGovernance,\n resolveEffectiveContentGovernance,\n} from './content-governance';\nimport {\n promptMessageOptions,\n smrtContentApplyCorrectionPrompt,\n smrtContentReviewPrompt,\n} from './content-prompts';\nimport { ContentReferences } from './content-references';\nimport type { ContentReview } from './content-review';\nimport { normalizeContentTransparency } from './content-transparency';\nimport { isMissingTableError } from './database-utils';\nimport {\n serializeContent,\n serializeContentCorrection,\n serializeContentReview,\n serializeContentVersion,\n serializeFact,\n serializeFactLink,\n} from './serialization';\nimport type { ThumbnailOptions } from './thumbnail-generator';\nimport { ThumbnailGenerator } from './thumbnail-generator';\n\nconst USED_FACT_RELATIONSHIPS = new Set<FactContentRelationship>([\n 'supports',\n 'referenced_in',\n 'contradicts',\n]);\nconst FACT_AUDIT_GENERATED_BY = 'content.factAudit';\nconst FACT_AUDIT_DOMAIN = 'content-audit';\n\ntype FactAuditSourceMaterial = {\n sourceKind: string;\n sourceId: string;\n sourceUrl: string;\n sourceTitle: string;\n locator: string;\n text: string;\n};\n\ntype FactAuditSourceSelector = {\n sourceKind: string;\n sourceId: string;\n};\n\ntype FactAuditResourceRepairOptions = {\n sources?: FactAuditSourceSelector[];\n maxFactsPerSource?: number;\n context?: string;\n};\n\ntype FactAuditClaimRecheckOptions = {\n claimFactIds?: string[];\n sourceIds?: string[];\n sources?: FactAuditSourceSelector[];\n maxCandidateEvidence?: number;\n};\n\ntype FactEvidenceStatusUpdateOptions = {\n evidenceIds?: string[];\n status?: FactEvidenceStatus;\n reason?: string;\n};\n\ntype FactAuditClaim = {\n id: string | null;\n fact: Record<string, unknown>;\n supportStatus: FactClaimSupportStatus;\n claimQuote: string | null;\n rationale: string | null;\n confidence: number | null;\n relationship: string | null;\n linkMetadata: Record<string, unknown>;\n evidence: Record<string, unknown>[];\n matchedFacts: Array<{\n fact: Record<string, unknown>;\n evidence: Record<string, unknown>[];\n }>;\n};\n\ntype FactAuditResourceClaim = {\n id: string | null;\n fact: Record<string, unknown>;\n sourceKind: string | null;\n sourceId: string | null;\n sourceUrl: string | null;\n sourceTitle: string | null;\n locator: string | null;\n quote: string | null;\n status: FactEvidenceStatus;\n confidence: number | null;\n evidence: Record<string, unknown>[];\n};\n\n/**\n * Minimal structural view of a metadata-bearing SMRT record (fact link,\n * fact, evidence, source, version, review, correction). The fact-audit and\n * transparency code paths interact with these entities loosely via their\n * accessor methods rather than importing the concrete cross-package classes\n * (which would create circular dependencies). `getMetadata`/`setMetadata`\n * are optional because some paths receive plain serialized records.\n */\ninterface MetadataBearer {\n getMetadata?: () => Record<string, unknown>;\n setMetadata?: (metadata: Record<string, unknown>) => void;\n updateMetadata?: (patch: Record<string, unknown>) => unknown;\n metadata?: unknown;\n}\n\n/**\n * Structural view of a content↔fact link as consumed by the fact-audit\n * pipeline. Backed by `FactContent` from `@happyvertical/smrt-facts`.\n */\ninterface FactAuditLinkLike extends MetadataBearer {\n factId?: string | null;\n relationship?: string | null;\n save?: () => Promise<unknown>;\n delete?: () => Promise<unknown>;\n}\n\n/**\n * Structural view of a fact-evidence record as consumed by the fact-audit\n * pipeline. Backed by `FactEvidence` from `@happyvertical/smrt-facts`.\n */\ninterface FactAuditEvidenceLike extends MetadataBearer {\n id?: string | null;\n factId?: string | null;\n status?: string | null;\n sourceKind?: string | null;\n sourceId?: string | null;\n sourceUrl?: string | null;\n sourceTitle?: string | null;\n locator?: string | null;\n quote?: string | null;\n confidence?: number | null;\n evidenceKey?: string | null;\n tenantId?: string | null;\n delete?: () => Promise<unknown>;\n}\n\n/**\n * Structural view of a fact-source record as consumed by the fact-audit\n * pipeline. Backed by `FactSource` from `@happyvertical/smrt-facts`.\n */\ninterface FactAuditSourceLike extends MetadataBearer {\n id?: string | null;\n sourceType?: string | null;\n delete?: () => Promise<unknown>;\n}\n\n/**\n * Loosely-read extra fields the fact-audit source scanner probes on an\n * {@link Asset}. These are not declared `Asset` fields (assets vary by\n * provider); they are read defensively and normalized via `normalizeAuditText`.\n */\ninterface FactAuditAssetExtraFields {\n text?: unknown;\n body?: unknown;\n title?: unknown;\n filename?: unknown;\n url?: unknown;\n sourceUrl?: unknown;\n fileKey?: unknown;\n}\n\n/**\n * Structural view of a support candidate carried through claim assessment.\n * The `evidence` array holds the serialized evidence summaries built in\n * {@link Content.getCurrentFactAuditSupportCandidates}.\n */\ninterface FactAuditSupportCandidate {\n id: string;\n statement: string;\n evidence: Array<{ id?: string | null; [key: string]: unknown }>;\n}\n\n/**\n * Loose view of a serialized record produced by the `serialize*` helpers\n * (which return index-signature records that erase named keys at the type\n * level). Adds back the few keys the transparency snapshot reads while keeping\n * the rest as `unknown`.\n */\ninterface SerializedRecord {\n id?: string | null;\n status?: unknown;\n usedInArticle?: boolean;\n metadata?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * Transient, non-persisted fields synchronized into junction links during\n * `save()`. They are attached dynamically from constructor options rather\n * than declared as ORM-managed fields, so callers narrow `this` to this\n * shape instead of reaching in untyped.\n */\ninterface ContentTransientLinkIds {\n referenceIds?: string[];\n assetIds?: string[];\n}\n\ntype FactAuditState = {\n counts: Record<FactClaimSupportStatus | 'total', number>;\n claims: FactAuditClaim[];\n resourceClaims: FactAuditResourceClaim[];\n warnings: string[];\n generatedBy: string;\n latestAuditRunId: string | null;\n};\n\nfunction normalizeFingerprintValue(value: unknown): unknown {\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => normalizeFingerprintValue(entry));\n }\n\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entryValue]) => [\n key,\n normalizeFingerprintValue(entryValue),\n ]),\n );\n }\n\n return value ?? null;\n}\n\nfunction hashFingerprint(input: string): string {\n let hash = 5381;\n\n for (let index = 0; index < input.length; index += 1) {\n hash = (hash * 33) ^ input.charCodeAt(index);\n }\n\n return `fp-${(hash >>> 0).toString(16).padStart(8, '0')}`;\n}\n\nfunction createFingerprint(value: unknown): string {\n return hashFingerprint(JSON.stringify(normalizeFingerprintValue(value)));\n}\n\nfunction normalizeAuditText(value: unknown): string {\n return String(value ?? '')\n .trim()\n .replace(/\\s+/g, ' ');\n}\n\n/**\n * Extract a human-readable message from an unknown caught value. Mirrors the\n * previous `error.message || error` template interpolation without relying on\n * an `any`-typed catch binding.\n */\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (\n error &&\n typeof error === 'object' &&\n 'message' in error &&\n typeof (error as { message?: unknown }).message === 'string'\n ) {\n return (error as { message: string }).message;\n }\n return String(error);\n}\n\nfunction createFactAuditRunId(contentId: string): string {\n return `fact-audit-${hashFingerprint(\n `${contentId}:${new Date().toISOString()}:${Math.random()}`,\n )}`;\n}\n\nfunction parseAuditMetadata(value: unknown): Record<string, unknown> {\n if (!value) return {};\n if (typeof value === 'object') return value as Record<string, unknown>;\n try {\n return JSON.parse(String(value)) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nfunction getLinkMetadata(link: MetadataBearer): Record<string, unknown> {\n return typeof link?.getMetadata === 'function' ? link.getMetadata() : {};\n}\n\nfunction getFactMetadata(fact: MetadataBearer): Record<string, unknown> {\n return typeof fact?.getMetadata === 'function'\n ? fact.getMetadata()\n : parseAuditMetadata(fact?.metadata);\n}\n\nfunction getGeneratedFactAuditMetadata(\n link: MetadataBearer,\n): Record<string, unknown> | null {\n const metadata = getLinkMetadata(link);\n if (metadata.generatedBy === FACT_AUDIT_GENERATED_BY) {\n return metadata;\n }\n\n const nested = metadata.factAudit;\n if (\n nested &&\n typeof nested === 'object' &&\n (nested as Record<string, unknown>).generatedBy === FACT_AUDIT_GENERATED_BY\n ) {\n return nested as Record<string, unknown>;\n }\n\n return null;\n}\n\nfunction getEvidenceMetadata(\n evidence: MetadataBearer,\n): Record<string, unknown> {\n return typeof evidence?.getMetadata === 'function'\n ? evidence.getMetadata()\n : parseAuditMetadata(evidence?.metadata);\n}\n\nfunction isGeneratedFactAuditEvidence(\n evidence: MetadataBearer,\n contentId: string,\n): boolean {\n const metadata = getEvidenceMetadata(evidence);\n return (\n metadata.generatedBy === FACT_AUDIT_GENERATED_BY &&\n metadata.contentId === contentId\n );\n}\n\nfunction isGeneratedArticleClaimFact(\n fact: MetadataBearer,\n contentId: string,\n): boolean {\n const metadata = getFactMetadata(fact);\n if (metadata.generatedBy !== FACT_AUDIT_GENERATED_BY) {\n return false;\n }\n\n const role = metadata.auditFactRole || metadata.factAuditRole;\n const isArticleClaim =\n role === 'article-claim' || metadata.claimOnly === true;\n\n return isArticleClaim && metadata.contentId === contentId;\n}\n\nfunction normalizeFactEvidenceStatus(\n value: unknown,\n): FactEvidenceStatus | null {\n const allowed: FactEvidenceStatus[] = [\n 'supports',\n 'contradicts',\n 'unclear',\n 'irrelevant',\n 'invalid',\n ];\n\n return allowed.includes(value as FactEvidenceStatus)\n ? (value as FactEvidenceStatus)\n : null;\n}\n\nfunction sourceMatchesSelector(\n source: FactAuditSourceMaterial,\n selector: FactAuditSourceSelector,\n): boolean {\n return (\n source.sourceKind === selector.sourceKind &&\n source.sourceId === selector.sourceId\n );\n}\n\nfunction filterAuditSources(\n sources: FactAuditSourceMaterial[],\n selectors: FactAuditSourceSelector[] | undefined,\n): FactAuditSourceMaterial[] {\n if (!selectors || selectors.length === 0) {\n return sources;\n }\n\n return sources.filter((source) =>\n selectors.some((selector) => sourceMatchesSelector(source, selector)),\n );\n}\n\nfunction getContentText(content: Content): string {\n return [content.title, content.description, content.body]\n .map(normalizeAuditText)\n .filter(Boolean)\n .join('\\n\\n');\n}\n\nfunction readNestedString(\n source: Record<string, unknown>,\n path: string[],\n): string | null {\n let current: unknown = source;\n for (const key of path) {\n if (!current || typeof current !== 'object') {\n return null;\n }\n current = (current as Record<string, unknown>)[key];\n }\n return typeof current === 'string' && current ? current : null;\n}\n\n/**\n * Coerce an unknown value into a plain record. Objects pass through; JSON\n * strings are parsed (falling back to `{}` on failure); anything else yields\n * an empty record. Used to read loosely-typed `metadata` fields that may be\n * stored either as parsed objects or JSON strings.\n */\nfunction asRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n }\n return {};\n}\n\n/**\n * Walk a nested record path, returning the record at the end of the path or\n * an empty record if any segment is missing/non-record-shaped.\n */\nfunction readNestedRecord(\n source: Record<string, unknown>,\n path: string[],\n): Record<string, unknown> {\n let current: unknown = source;\n for (const key of path) {\n if (!current || typeof current !== 'object') {\n return {};\n }\n current = (current as Record<string, unknown>)[key];\n }\n return asRecord(current);\n}\n\nfunction getPublicPrompt(metadata: Record<string, unknown>): string | null {\n return (\n readNestedString(metadata, [\n 'transparency',\n 'generation',\n 'publicPrompt',\n ]) ||\n readNestedString(metadata, ['generation', 'publicPrompt']) ||\n readNestedString(metadata, ['publicPrompt']) ||\n null\n );\n}\n\n/**\n * Options for Content initialization\n */\nexport interface ContentOptions extends SmrtObjectOptions {\n /**\n * Content type classification\n */\n type?: string | null;\n\n /**\n * Content variant for namespaced classification within types\n * Format: generator:domain:specific-type\n * Example: \"praeco:meeting:upcoming\"\n */\n variant?: string | null;\n\n /**\n * Reference to file storage key\n */\n fileKey?: string | null;\n\n /**\n * Author of the content\n */\n author?: string | null;\n\n /**\n * Content title\n */\n title?: string | null;\n\n /**\n * Short description or summary\n */\n description?: string | null;\n\n /**\n * Main content body text\n */\n body?: string | null;\n\n /**\n * Stored body format.\n */\n bodyFormat?: ContentBodyFormat | null;\n\n /**\n * Date when content was published\n */\n publish_date?: Date | null;\n\n /**\n * URL source of the content\n */\n url?: string | null;\n\n /**\n * Original source identifier\n */\n source?: string | null;\n\n /**\n * Publication status\n */\n status?: 'published' | 'draft' | 'review' | 'archived' | 'deleted' | null;\n\n /**\n * Content state flag\n */\n state?: 'deprecated' | 'active' | 'highlighted' | null;\n\n /**\n * Original URL of the content\n */\n original_url?: string | null;\n\n /**\n * Content language\n */\n language?: string | null;\n\n /**\n * Content tags\n */\n tags?: string[];\n\n /**\n * Hierarchical category path for URL routing\n * Format: 'parent/child' (e.g., 'politics/local')\n * Each content belongs to exactly ONE category\n */\n category?: string | null;\n\n /**\n * Additional metadata\n */\n metadata?: Record<string, unknown>;\n\n /**\n * ID of the thumbnail asset for this content\n */\n thumbnailAssetId?: string | null;\n\n /**\n * Transient reference IDs used by editors and API payloads.\n * These are synchronized into ContentReference links during save.\n */\n referenceIds?: string[];\n\n /**\n * Transient asset IDs used by editors and API payloads.\n */\n assetIds?: string[];\n\n /**\n * Tenant ID for multi-tenant isolation\n */\n tenantId?: string | null;\n}\n\n/**\n * Structured content object with metadata and body text\n *\n * Content represents any text-based content with metadata such as\n * title, author, description, and publishing information. It supports\n * referencing related content objects.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: {\n include: [\n 'list',\n 'get',\n 'create',\n 'update',\n 'delete',\n 'getFactsState',\n 'syncFactsState',\n 'getFactAuditStateAction',\n 'repairFactAuditAction',\n 'repairFactEvidenceAction',\n 'recheckFactClaimsAction',\n 'updateFactEvidenceStatusAction',\n 'getGovernanceStateAction',\n 'listReviews',\n 'runReviewAction',\n 'listReviewProfilesAction',\n 'evaluateReviewProfileAction',\n 'getPublishedTransparencyAction',\n 'previewTransparencyAction',\n 'listCorrections',\n 'issueCorrectionAction',\n 'listVersions',\n 'mutateVersionAction',\n ],\n routes: {\n getFactsState: { method: 'GET', path: 'facts' },\n syncFactsState: { method: 'PUT', path: 'facts' },\n getFactAuditStateAction: { method: 'GET', path: 'fact-audit' },\n repairFactAuditAction: { method: 'POST', path: 'fact-audit/repair' },\n repairFactEvidenceAction: {\n method: 'POST',\n path: 'fact-audit/evidence/repair',\n },\n recheckFactClaimsAction: {\n method: 'POST',\n path: 'fact-audit/claims/recheck',\n },\n updateFactEvidenceStatusAction: {\n method: 'PUT',\n path: 'fact-audit/evidence/status',\n },\n getGovernanceStateAction: { method: 'GET', path: 'governance' },\n listReviews: { method: 'GET', path: 'reviews' },\n runReviewAction: { method: 'POST', path: 'reviews' },\n listReviewProfilesAction: { method: 'GET', path: 'review-profiles' },\n evaluateReviewProfileAction: {\n method: 'GET',\n path: 'review-profiles/[profileKey]',\n },\n getPublishedTransparencyAction: {\n method: 'GET',\n path: 'transparency',\n },\n previewTransparencyAction: {\n method: 'GET',\n path: 'transparency/preview',\n },\n listCorrections: { method: 'GET', path: 'corrections' },\n issueCorrectionAction: { method: 'POST', path: 'corrections' },\n listVersions: { method: 'GET', path: 'versions' },\n mutateVersionAction: { method: 'POST', path: 'versions' },\n },\n serializers: {\n item: {\n importPath: '$lib/server/content-api-serializers',\n exportName: 'serializeContent',\n },\n },\n },\n mcp: {\n include: ['list', 'get', 'create', 'update'], // AI tools for content management\n },\n cli: true, // Enable CLI commands for content management\n // Content's own list pages sort by publish date inside a tenant, not by\n // `created_at`, so the generated `(tenant_id, created_at)` ordering index\n // (#2363) does not serve them — this is the second access path on the same\n // table and it has to be declared (#2357, measured in #2340). Declared\n // indexes are appended before the automatic passes, so this one also stands\n // in for the standalone `contents_tenant_id_idx` (#2359): a btree serves\n // every prefix of its column list.\n indexes: [\n {\n name: 'contents_tenant_id_publish_date_idx',\n columns: ['tenantId', 'publish_date'],\n },\n ],\n})\nexport class Content\n extends SmrtObject\n implements AssetAssociable, MetadataAccessor<Record<string, unknown>>\n{\n /**\n * Tenant ID for multi-tenant isolation\n * Nullable to support both tenant-scoped and global content\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Array of referenced content objects\n */\n protected references: Content[] = [];\n\n /**\n * Content type classification\n */\n public type: string | null = null;\n\n /**\n * Content variant for namespaced classification within types\n * Format: generator:domain:specific-type\n * Example: \"praeco:meeting:upcoming\"\n */\n public variant: string | null = null;\n\n /**\n * Reference to file storage key\n */\n public fileKey: string | null = null;\n\n /**\n * Author of the content\n */\n public author: string | null = null;\n\n /**\n * Human-readable name for SMRT framework compatibility\n */\n @field({ required: true })\n public name: string = '';\n\n /**\n * Content title\n */\n public title = '';\n\n /**\n * Short description or summary\n */\n public description: string | null = null;\n\n /**\n * Main content body text\n */\n public body = '';\n\n /**\n * Format used to persist the body field.\n */\n public bodyFormat: ContentBodyFormat | null = null;\n\n /**\n * Date when content was published\n */\n public publish_date: Date | null = null;\n\n /**\n * URL source of the content\n */\n public url: string | null = null;\n\n /**\n * Original source identifier\n */\n public source: string | null = null;\n\n /**\n * Original URL of the content\n */\n public original_url: string | null = null;\n\n /**\n * Content language\n */\n public language: string | null = null;\n\n /**\n * Content tags\n */\n public tags: string[] = [];\n\n /**\n * Hierarchical category path for URL routing\n * Format: 'parent/child' (e.g., 'politics/local')\n * Each content belongs to exactly ONE category\n */\n public category: string | null = null;\n\n /**\n * Publication status\n */\n public status: 'published' | 'draft' | 'review' | 'archived' | 'deleted' =\n 'draft';\n\n /**\n * Content state flag\n */\n public state: 'deprecated' | 'active' | 'highlighted' = 'active';\n\n /**\n * Additional JSON metadata for flexible schema extension\n */\n public metadata: Record<string, unknown> = {};\n\n /**\n * ID of the thumbnail asset for this content\n */\n @crossPackageRef('@happyvertical/smrt-assets:Asset')\n public thumbnailAssetId: string | null = null;\n\n /**\n * Creates a new Content instance\n */\n constructor(options: ContentOptions = {}) {\n super(options);\n this.type = options.type || null;\n this.variant = options.variant || null;\n this.fileKey = options.fileKey || null;\n this.author = options.author || null;\n if (options.name) this.name = options.name;\n this.title = options.title || '';\n this.description = options.description || null;\n this.body = options.body || '';\n this.bodyFormat = isContentBodyFormat(options.bodyFormat)\n ? options.bodyFormat\n : null;\n this.publish_date = options.publish_date || null;\n this.source = options.source || null;\n this.original_url = options.original_url || null;\n this.language = options.language || null;\n this.status = options.status || 'draft';\n this.tags = options.tags || [];\n this.category = options.category || null;\n this.state = options.state || 'active';\n this.metadata = options.metadata || {};\n this.thumbnailAssetId = options.thumbnailAssetId ?? null;\n const transient = this as Content & ContentTransientLinkIds;\n if (Array.isArray(options.referenceIds)) {\n transient.referenceIds = [...options.referenceIds];\n }\n if (Array.isArray(options.assetIds)) {\n transient.assetIds = [...options.assetIds];\n }\n }\n\n /**\n * Initializes this content object\n *\n * @returns Promise that resolves to this instance\n */\n async initialize(): Promise<this> {\n await super.initialize();\n return this;\n }\n\n protected override async validateBeforeSave(): Promise<void> {\n if (!this.name && this.title) {\n this.name = this.title;\n }\n\n if (!this.title && this.name) {\n this.title = this.name;\n }\n\n await super.validateBeforeSave();\n\n if (this.status !== 'published') {\n return;\n }\n\n const governance = await this.resolvePublicationGovernance();\n const profileKey = governance?.publicationProfileKey;\n\n if (\n !governance?.isGoverned ||\n !governance.enforcePublishReadiness ||\n !profileKey\n ) {\n return;\n }\n\n const evaluation = await this.evaluateReviewProfile(profileKey);\n const blockingRequirements = evaluation.requirements.filter(\n (requirement) => requirement.blocking && !requirement.satisfied,\n );\n\n if (blockingRequirements.length === 0) {\n return;\n }\n\n const details = blockingRequirements.map((requirement) => {\n if (requirement.missing) {\n return `${requirement.label} has not been run yet`;\n }\n\n if (requirement.stale) {\n return `${requirement.label} is stale and must be rerun`;\n }\n\n if (requirement.latestStatus) {\n return `${requirement.label} returned ${requirement.latestStatus}`;\n }\n\n return `${requirement.label} is not satisfied`;\n });\n\n throw new ValidationError(\n `Cannot publish content until the \"${profileKey}\" review profile is satisfied. ${details.join('; ')}`,\n 'VALIDATION_PUBLISH_READINESS',\n {\n profileKey,\n blockingRequirements: blockingRequirements.map((requirement) => ({\n policyKey: requirement.policyKey,\n label: requirement.label,\n missing: requirement.missing,\n stale: requirement.stale,\n latestStatus: requirement.latestStatus,\n })),\n },\n );\n }\n\n override async save(options: SmrtSaveOptions = {}) {\n const shouldConsiderPublicationSnapshot = this.status === 'published';\n\n let governance: ResolvedContentGovernance | null = null;\n let previous: Content | null = null;\n let previousPublicationFingerprint: string | null = null;\n\n if (shouldConsiderPublicationSnapshot) {\n governance = await this.resolvePublicationGovernance();\n\n if (governance?.isGoverned && governance.transparencyEnabled) {\n previous = await this.getPersistedContent();\n previousPublicationFingerprint =\n await this.getLatestPublicationSnapshotFingerprint();\n }\n }\n\n await super.save(options);\n await this.syncPendingReferenceIds();\n await this.syncPendingAssetIds();\n\n if (\n !shouldConsiderPublicationSnapshot ||\n !governance?.isGoverned ||\n !governance.transparencyEnabled\n ) {\n return this;\n }\n\n const nextPublicationFingerprint =\n await this.buildPublicationSnapshotFingerprint(governance);\n\n if (\n nextPublicationFingerprint &&\n nextPublicationFingerprint !== previousPublicationFingerprint\n ) {\n await this.createVersion({\n kind: 'publication',\n summary:\n previous?.status === 'published'\n ? 'Published content updated.'\n : 'Content published.',\n metadata: {\n publicationSnapshotFingerprint: nextPublicationFingerprint,\n publicationProfileKey: governance.publicationProfileKey,\n transparency: await this.buildTransparencySnapshot({\n snapshotKind: 'published',\n governance,\n }),\n },\n });\n }\n\n return this;\n }\n\n private async getReferenceCollection() {\n return ContentReferences.create({ db: this.db });\n }\n\n private async getFactCollection() {\n const { FactCollection } = await import('@happyvertical/smrt-facts');\n return FactCollection.create(this.options);\n }\n\n private async getFactContentCollection() {\n const { FactContentCollection } = await import('@happyvertical/smrt-facts');\n return FactContentCollection.create(this.options);\n }\n\n private async getFactSourceCollection() {\n const { FactSourceCollection } = await import('@happyvertical/smrt-facts');\n return FactSourceCollection.create(this.options);\n }\n\n private async getFactEvidenceCollection() {\n const { FactEvidenceCollection } = await import(\n '@happyvertical/smrt-facts'\n );\n return FactEvidenceCollection.create(this.options);\n }\n\n private async getContentVersionCollection() {\n const { ContentVersionCollection } = await import('./content-versions');\n return ContentVersionCollection.create(this.options);\n }\n\n private async getContentReviewCollection() {\n const { ContentReviewCollection } = await import('./content-reviews');\n return ContentReviewCollection.create(this.options);\n }\n\n private async getContentCorrectionCollection() {\n const { ContentCorrectionCollection } = await import(\n './content-corrections'\n );\n return ContentCorrectionCollection.create(this.options);\n }\n\n private async getContentsCollection() {\n const { Contents } = await import('./contents');\n return Contents.create({ db: this.db });\n }\n\n private getConfiguredGovernance(): ResolvedContentGovernance {\n return resolveConfiguredContentGovernance({\n contentType: this.type,\n contentVariant: this.variant,\n });\n }\n\n public async resolveGovernance(): Promise<ResolvedContentGovernance> {\n return resolveEffectiveContentGovernance({\n contentType: this.type,\n contentVariant: this.variant,\n db: this.db,\n tenantId: this.tenantId ?? null,\n });\n }\n\n private async hasPersistedGovernanceAssignments(): Promise<boolean> {\n if (!this.db || typeof this.db.query !== 'function') {\n return false;\n }\n\n try {\n const exactKey = buildContentGovernanceAssignmentKey(\n this.type || '',\n this.variant || '',\n );\n const typeOnlyKey = buildContentGovernanceAssignmentKey(this.type || '');\n const keys =\n exactKey === typeOnlyKey ? [exactKey] : [exactKey, typeOnlyKey];\n const placeholders = keys.map(() => '?').join(', ');\n const result = await this.db.query(\n `SELECT 1 AS matched FROM content_governance_assignments WHERE key IN (${placeholders}) LIMIT 1`,\n keys,\n );\n const rows = Array.isArray(result) ? result : (result?.rows ?? []);\n return rows.length > 0;\n } catch {\n return false;\n }\n }\n\n private async resolvePublicationGovernance(): Promise<ResolvedContentGovernance | null> {\n const configuredGovernance = this.getConfiguredGovernance();\n\n if (configuredGovernance.isGoverned) {\n return this.resolveGovernance();\n }\n\n if (!(await this.hasPersistedGovernanceAssignments())) {\n return null;\n }\n\n const governance = await this.resolveGovernance();\n return governance.isGoverned ? governance : null;\n }\n\n private async requireGovernance(\n feature = 'governance workflow',\n ): Promise<ResolvedContentGovernance> {\n const governance = await this.resolveGovernance();\n\n if (!governance.isGoverned) {\n throw new Error(\n `Governance is not enabled for content type \"${this.type || 'content'}\"${this.variant ? ` variant \"${this.variant}\"` : ''}, so ${feature} is unavailable.`,\n );\n }\n\n return governance;\n }\n\n private async requireFactLinking(\n feature = 'fact linking',\n ): Promise<ResolvedContentGovernance> {\n const governance = await this.requireGovernance(feature);\n\n if (!governance.factLinkingEnabled) {\n throw new Error(\n `Fact linking is not enabled for content type \"${this.type || 'content'}\"${this.variant ? ` variant \"${this.variant}\"` : ''}.`,\n );\n }\n\n return governance;\n }\n\n private async getPersistedContent(): Promise<Content | null> {\n if (!this.id) {\n return null;\n }\n\n const contents = await this.getContentsCollection();\n return (await contents.get({ id: this.id as string })) as Content | null;\n }\n\n private async buildReviewFingerprint(policyKey: string): Promise<string> {\n const governance = await this.resolveGovernance();\n const kind = getContentReviewKind(policyKey, governance.reviewPolicies);\n const policy = getContentReviewPolicy(policyKey, governance.reviewPolicies);\n const [references, facts, factLinks] = await Promise.all([\n this.getReferences(),\n kind === 'facts' && governance.factLinkingEnabled\n ? this.getFacts({\n latestOnly: true,\n includeSuperseded: false,\n })\n : Promise.resolve([]),\n kind === 'facts' && governance.factLinkingEnabled\n ? this.getFactLinks()\n : Promise.resolve([]),\n ]);\n\n return createFingerprint({\n scope: 'content-review',\n policyKey,\n kind,\n policyInstructions: policy?.instructions || '',\n content: {\n id: this.id || null,\n type: this.type,\n variant: this.variant,\n title: this.title,\n description: this.description,\n body: this.body,\n author: this.author,\n state: this.state,\n publishDate: this.publish_date,\n language: this.language,\n category: this.category,\n tags: this.tags,\n metadata: this.metadata,\n },\n referenceIds: references\n .map((reference) => reference.id)\n .filter(Boolean)\n .sort(),\n facts: facts.map((fact) => ({\n id: fact.id || null,\n // Pre-R3-C this was `parentId`; renamed to `previousFactId` in\n // smrt-facts. Existing cached fingerprints will invalidate, which\n // is the correct behaviour — the review surface (a key in the\n // hash) changed.\n previousFactId: fact.previousFactId || null,\n status: fact.status || null,\n textRefined: fact.textRefined || '',\n sourceCount: fact.sourceCount ?? 0,\n confidence: fact.confidence ?? null,\n metadata:\n typeof fact?.getMetadata === 'function' ? fact.getMetadata() : {},\n })),\n factLinks: factLinks.map((link) => ({\n factId: link.factId || null,\n relationship: link.relationship || null,\n metadata:\n typeof link?.getMetadata === 'function' ? link.getMetadata() : {},\n })),\n });\n }\n\n private async buildTransparencySnapshot(\n options: {\n snapshotKind?: 'preview' | 'published';\n governance?: ResolvedContentGovernance;\n } = {},\n ) {\n const snapshotKind = options.snapshotKind || 'preview';\n const governance = options.governance || (await this.resolveGovernance());\n\n if (!governance.isGoverned || !governance.transparencyEnabled) {\n return null;\n }\n\n const [\n references,\n facts,\n factLinks,\n reviews,\n corrections,\n versions,\n reviewProfiles,\n ] = await Promise.all([\n this.getReferences(),\n governance.factLinkingEnabled\n ? this.getFacts({\n latestOnly: true,\n includeSuperseded: false,\n })\n : Promise.resolve([]),\n governance.factLinkingEnabled ? this.getFactLinks() : Promise.resolve([]),\n this.listReviews(),\n this.listCorrections(),\n this.listVersions(),\n this.listReviewProfilesAction(),\n ]);\n\n const factSources = await this.getFactSourceCollection();\n const factSourcesByFactId = new Map<string, FactSource[]>();\n\n for (const fact of facts) {\n const factId = fact.id as string | undefined;\n if (!factId) {\n continue;\n }\n\n const sources = await factSources.getForFact(factId);\n factSourcesByFactId.set(factId, sources);\n }\n\n const usedFactIds = new Set(\n factLinks\n .filter((link) =>\n USED_FACT_RELATIONSHIPS.has(\n (link.relationship || 'related') as FactContentRelationship,\n ),\n )\n .map((link) => link.factId)\n .filter(Boolean),\n );\n\n const linkedFacts = facts.map((fact) => {\n const factId = fact.id as string | undefined;\n const link = factLinks.find((entry) => entry.factId === factId);\n const sources = (factId ? factSourcesByFactId.get(factId) : []) || [];\n\n return {\n ...serializeFact(fact),\n relationship: link?.relationship || null,\n linkMetadata:\n typeof link?.getMetadata === 'function' ? link.getMetadata() : {},\n usedInArticle: factId ? usedFactIds.has(factId) : false,\n sources: sources.map((source) => ({\n id: source.id || null,\n sourceType: source.sourceType || null,\n sourceUrl: source.sourceUrl || null,\n sourceTitle: source.sourceTitle || null,\n credibility: source.credibility ?? null,\n extractedAt: source.extractedAt || null,\n metadata:\n typeof source?.getMetadata === 'function'\n ? source.getMetadata()\n : {},\n })),\n };\n });\n\n const referenceGroups = await Promise.all(\n references.map(async (reference) => {\n const sourceUrls = [\n reference.url,\n reference.original_url,\n reference.source,\n ].filter(Boolean) as string[];\n\n const extractedFacts = new Map<string, Fact>();\n for (const sourceUrl of sourceUrls) {\n const matches = await factSources.list({\n where: { sourceUrl },\n orderBy: 'created_at ASC',\n });\n\n for (const match of matches) {\n if (!match.factId || extractedFacts.has(match.factId)) {\n continue;\n }\n\n const fact = await match.getFact();\n if (fact?.id) {\n extractedFacts.set(fact.id as string, fact);\n }\n }\n }\n\n const extractedFactRecords: SerializedRecord[] = [\n ...extractedFacts.values(),\n ].map((fact) => {\n const factId = fact.id as string | undefined;\n return {\n ...serializeFact(fact),\n usedInArticle: factId ? usedFactIds.has(factId) : false,\n };\n });\n\n return {\n id: reference.id || null,\n title: reference.title || reference.name || reference.url || null,\n url: reference.url || null,\n originalUrl: reference.original_url || null,\n type: reference.type || null,\n source: reference.source || null,\n usedFactIds: extractedFactRecords\n .filter((fact) => fact.id && usedFactIds.has(fact.id))\n .map((fact) => fact.id),\n extractedFacts: extractedFactRecords,\n };\n }),\n );\n\n const publicGeneration = readNestedRecord(this.metadata, [\n 'transparency',\n 'generation',\n ]);\n const generationMetadata = readNestedRecord(this.metadata, ['generation']);\n const serializedCorrections = (corrections as SerializedRecord[])\n .filter((correction) => correction.status === 'published')\n .map((correction) => {\n // `corrections` is already serialized to plain records, so the\n // metadata is the parsed object on `correction.metadata`.\n const correctionMetadata = asRecord(correction.metadata);\n\n return {\n ...serializeContentCorrection(correction),\n provenance: {\n autoGeneratedDraft: Boolean(correctionMetadata.autoGeneratedDraft),\n draftVersionId: correctionMetadata.draftVersionId || null,\n draftVersionNumber: correctionMetadata.draftVersionNumber || null,\n sourceCorrectionVersionId:\n correctionMetadata.sourceCorrectionVersionId || null,\n sourceCorrectionVersionNumber:\n correctionMetadata.sourceCorrectionVersionNumber || null,\n },\n };\n });\n const serializedVersionHistory = (versions as SerializedRecord[]).map(\n (version) => {\n // `versions` is already serialized to plain records.\n const versionMetadata = asRecord(version.metadata);\n\n return {\n id: version.id || null,\n version: version.version ?? null,\n kind: version.kind || null,\n summary: version.summary || '',\n createdAt: version.createdAt || null,\n provenance: {\n policyKey: versionMetadata.policyKey || null,\n reviewFingerprint:\n versionMetadata.reviewFingerprint ||\n versionMetadata.contentFingerprint ||\n null,\n factId: versionMetadata.factId || null,\n replacementFactId: versionMetadata.replacementFactId || null,\n sourceCorrectionVersionId:\n versionMetadata.sourceCorrectionVersionId || null,\n sourceCorrectionVersionNumber:\n versionMetadata.sourceCorrectionVersionNumber || null,\n correctionDraft: versionMetadata.correctionDraft || null,\n publicationSnapshotFingerprint:\n versionMetadata.publicationSnapshotFingerprint || null,\n },\n };\n },\n );\n\n return normalizeContentTransparency(\n {\n generatedAt: new Date().toISOString(),\n snapshotKind,\n contentId: (this.id as string) || null,\n currentContentStatus: this.status || null,\n publicationProfileKey: governance.publicationProfileKey || undefined,\n generation: {\n aiAssisted:\n publicGeneration.aiAssisted ??\n generationMetadata.aiAssisted ??\n Boolean(getPublicPrompt(this.metadata)),\n publicPrompt: getPublicPrompt(this.metadata),\n model: publicGeneration.model || generationMetadata.model || null,\n },\n factsUsed: linkedFacts.filter((fact) => fact.usedInArticle),\n linkedFacts,\n otherExtractedFacts: referenceGroups.flatMap((reference) =>\n reference.extractedFacts.filter((fact) => !fact.usedInArticle),\n ),\n references: referenceGroups,\n reviews,\n reviewProfiles,\n corrections: serializedCorrections,\n versionHistory: serializedVersionHistory,\n },\n {\n snapshotKind,\n contentId: (this.id as string) || null,\n currentContentStatus: this.status || null,\n publicationProfileKey: governance.publicationProfileKey || undefined,\n },\n );\n }\n\n /**\n * Fingerprint of the *content-bearing* publication surface only.\n *\n * This must converge: two byte-identical `save()`s of published content\n * have to produce the same fingerprint so the publication-version writer\n * (`save()`) does not append a redundant `ContentVersion` on every save.\n *\n * It therefore deliberately excludes everything that grows or carries a\n * timestamp/ordering with each save — `versionHistory`, `reviews`,\n * `corrections`, and any `generatedAt`/`createdAt`/`id` fields. The earlier\n * implementation fingerprinted the full transparency snapshot (which embeds\n * the growing `versionHistory`), so the stored fingerprint of vN predated vN\n * and the next save's recomputed fingerprint always differed → unbounded\n * redundant publication versions (#1387 blocker).\n *\n * The surface mirrors `buildReviewFingerprint`'s content block, plus the\n * pinned reference edges (`{ targetId, targetVersion }`) — a pin change is a\n * meaningful republication — and the publication profile key.\n */\n private async buildPublicationSnapshotFingerprint(\n governance: ResolvedContentGovernance,\n ): Promise<string | null> {\n if (!governance.isGoverned || !governance.transparencyEnabled) {\n return null;\n }\n\n const referenceCollection = await this.getReferenceCollection();\n const [referenceEdges, facts, factLinks] = await Promise.all([\n this.id ? referenceCollection.getForSource(this.id) : Promise.resolve([]),\n governance.factLinkingEnabled\n ? this.getFacts({ latestOnly: true, includeSuperseded: false })\n : Promise.resolve([]),\n governance.factLinkingEnabled ? this.getFactLinks() : Promise.resolve([]),\n ]);\n\n return createFingerprint({\n scope: 'content-publication',\n publicationProfileKey: governance.publicationProfileKey || null,\n content: {\n id: this.id || null,\n type: this.type,\n variant: this.variant,\n title: this.title,\n description: this.description,\n body: this.body,\n author: this.author,\n state: this.state,\n publishDate: this.publish_date,\n language: this.language,\n category: this.category,\n tags: this.tags,\n metadata: this.metadata,\n },\n // Pinned reference edges only — ordering-independent so it converges.\n references: referenceEdges\n .map((edge) => ({\n targetId: edge.targetId || null,\n targetVersion: edge.targetVersion ?? null,\n }))\n .sort((a, b) => String(a.targetId).localeCompare(String(b.targetId))),\n facts: facts\n .map((fact) => ({\n id: fact.id || null,\n previousFactId: fact.previousFactId || null,\n status: fact.status || null,\n textRefined: fact.textRefined || '',\n sourceCount: fact.sourceCount ?? 0,\n confidence: fact.confidence ?? null,\n metadata:\n typeof fact?.getMetadata === 'function' ? fact.getMetadata() : {},\n }))\n .sort((a, b) => String(a.id).localeCompare(String(b.id))),\n factLinks: factLinks\n .map((link) => ({\n factId: link.factId || null,\n relationship: link.relationship || null,\n metadata:\n typeof link?.getMetadata === 'function' ? link.getMetadata() : {},\n }))\n .sort((a, b) => String(a.factId).localeCompare(String(b.factId))),\n });\n }\n\n private async getLatestPublicationSnapshotFingerprint(): Promise<\n string | null\n > {\n const versions = await this.getVersions();\n const latestPublicationVersion = [...versions]\n .reverse()\n .find((version) => version.kind === 'publication');\n\n if (!latestPublicationVersion) {\n return null;\n }\n\n return (\n latestPublicationVersion.getMetadata().publicationSnapshotFingerprint ||\n null\n );\n }\n\n private async buildCorrectionDraftSnapshot(\n options: IssueContentCorrectionOptions,\n replacementFactId: string,\n ): Promise<{\n snapshot: Record<string, unknown>;\n metadata: Record<string, unknown>;\n }> {\n const correctedText =\n options.correctedText || options.correctedFactText || '';\n const incorrectText = options.incorrectText || '';\n let body = this.body;\n let generationMethod = 'metadata';\n\n if (incorrectText && correctedText && body.includes(incorrectText)) {\n body = body.replace(incorrectText, correctedText);\n generationMethod = 'replace';\n } else if (correctedText) {\n const ai = this.ai as {\n message?: (\n prompt: string,\n options?: Record<string, unknown>,\n ) => Promise<string>;\n };\n if (ai?.message) {\n const resolvedPrompt = await resolvePrompt(\n smrtContentApplyCorrectionPrompt.key,\n {\n db: this.options.db,\n tenantId: this.tenantId,\n variables: {\n body: this.body,\n correctedText,\n incorrectText: incorrectText || 'Not provided',\n summary: options.summary || '',\n },\n },\n );\n\n try {\n const proposedBody = (\n await ai.message(\n resolvedPrompt.text,\n promptMessageOptions(resolvedPrompt.ai),\n )\n ).trim();\n if (proposedBody) {\n body = proposedBody;\n generationMethod = 'ai';\n }\n } catch {\n generationMethod = 'metadata';\n }\n }\n }\n\n return {\n snapshot: {\n title: this.title,\n description: this.description,\n body,\n status: 'draft',\n metadata: {\n ...(this.metadata || {}),\n governance: {\n ...asRecord(this.metadata.governance),\n correctionDraft: {\n summary: options.summary,\n incorrectText,\n correctedText,\n factId: options.factId || null,\n replacementFactId: replacementFactId || null,\n autoGenerated: true,\n generationMethod,\n },\n },\n },\n },\n metadata: {\n summary: options.summary,\n incorrectText,\n correctedText,\n factId: options.factId || null,\n replacementFactId: replacementFactId || null,\n autoGenerated: true,\n generationMethod,\n },\n };\n }\n\n private async getAssetCollection() {\n return AssetCollection.create({ db: this.db });\n }\n\n private async getContentAssetCollection() {\n return ContentAssetCollection.create({ db: this.db });\n }\n\n private async getContentAssetLinks(\n relationship?: string,\n ): Promise<Array<{ assetId: string; sortOrder: number }>> {\n if (!this.id) {\n return [];\n }\n\n try {\n const contentAssets = await this.getContentAssetCollection();\n const links = await contentAssets.byLeft(\n this.id,\n relationship ? { relationship } : {},\n );\n\n return links\n .filter((link) => link.assetId)\n .map((link) => ({\n assetId: link.assetId,\n sortOrder: link.sortOrder ?? 0,\n }));\n } catch (error) {\n if (isMissingTableError(error, 'content_assets')) {\n return [];\n }\n\n throw error;\n }\n }\n\n private async resolveAssetsForLinks(\n links: Array<{ assetId: string; sortOrder: number }>,\n ): Promise<Asset[]> {\n if (links.length === 0) {\n return [];\n }\n\n const assetIds = [...new Set(links.map((link) => link.assetId))];\n const assets = await this.getAssetCollection();\n const resolved = await assets.listByIds(assetIds);\n const assetsById = new Map(\n resolved\n .filter((asset) => asset.id)\n .map((asset) => [asset.id as string, asset]),\n );\n\n return links\n .map((link) => assetsById.get(link.assetId))\n .filter(Boolean) as Asset[];\n }\n\n private async resolveReferenceTarget(content: Content | string) {\n if (typeof content !== 'string') {\n return content;\n }\n\n const contents = await this.getContentsCollection();\n\n return (await contents.getOrUpsert(\n {\n url: content,\n tenantId: this.tenantId,\n },\n {\n name: content,\n title: content,\n type: 'reference',\n tenantId: this.tenantId,\n },\n )) as Content;\n }\n\n /**\n * Loads referenced content objects\n *\n * @returns Promise that resolves when references are loaded\n */\n public async loadReferences() {\n this.references = await this.getReferences();\n }\n\n private getPendingReferenceIds(): string[] | null {\n const pendingReferenceIds = (this as Content & ContentTransientLinkIds)\n .referenceIds;\n\n if (!Array.isArray(pendingReferenceIds)) {\n return null;\n }\n\n return [\n ...new Set(\n pendingReferenceIds.filter(\n (referenceId): referenceId is string =>\n typeof referenceId === 'string' &&\n referenceId.length > 0 &&\n referenceId !== this.id,\n ),\n ),\n ];\n }\n\n private getPendingAssetIds(): string[] | null {\n const pendingAssetIds = (this as Content & ContentTransientLinkIds)\n .assetIds;\n\n if (!Array.isArray(pendingAssetIds)) {\n return null;\n }\n\n return [\n ...new Set(\n pendingAssetIds.filter(\n (assetId): assetId is string =>\n typeof assetId === 'string' && assetId.length > 0,\n ),\n ),\n ];\n }\n\n private async syncPendingReferenceIds(): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const pendingReferenceIds = this.getPendingReferenceIds();\n if (pendingReferenceIds === null) {\n return;\n }\n\n const currentReferences = await this.getReferences();\n const currentReferenceIds = currentReferences\n .map((reference) => reference.id)\n .filter((referenceId): referenceId is string => Boolean(referenceId));\n const currentReferenceIdSet = new Set(currentReferenceIds);\n const pendingReferenceIdSet = new Set(pendingReferenceIds);\n\n for (const referenceId of currentReferenceIds) {\n if (!pendingReferenceIdSet.has(referenceId)) {\n await this.removeReference(referenceId);\n }\n }\n\n const referenceIdsToAdd = pendingReferenceIds.filter(\n (referenceId) => !currentReferenceIdSet.has(referenceId),\n );\n\n if (referenceIdsToAdd.length === 0) {\n this.references = await this.getReferences();\n return;\n }\n\n const contents = await this.getContentsCollection();\n const resolvedReferences = await contents.listByIds(referenceIdsToAdd);\n const referencesById = new Map(\n resolvedReferences\n .filter((reference) => reference.id)\n .map((reference) => [reference.id as string, reference]),\n );\n\n for (const referenceId of referenceIdsToAdd) {\n const reference = referencesById.get(referenceId);\n if (reference) {\n await this.addReference(reference);\n }\n }\n\n this.references = await this.getReferences();\n }\n\n private async syncPendingAssetIds(): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const pendingAssetIds = this.getPendingAssetIds();\n if (pendingAssetIds === null) {\n return;\n }\n\n const currentAssets = await this.getAssets();\n const currentAssetIds = currentAssets\n .map((asset) => asset.id)\n .filter((assetId): assetId is string => Boolean(assetId));\n const currentAssetIdSet = new Set(currentAssetIds);\n const pendingAssetIdSet = new Set(pendingAssetIds);\n\n for (const assetId of currentAssetIds) {\n if (!pendingAssetIdSet.has(assetId)) {\n await this.removeAsset(assetId);\n }\n }\n\n const assetIdsToAdd = pendingAssetIds.filter(\n (assetId) => !currentAssetIdSet.has(assetId),\n );\n\n if (assetIdsToAdd.length === 0) {\n return;\n }\n\n const assets = await this.getAssetCollection();\n const resolvedAssets = await assets.listByIds(assetIdsToAdd);\n const assetsById = new Map(\n resolvedAssets\n .filter((asset) => asset.id)\n .map((asset) => [asset.id as string, asset]),\n );\n\n for (const assetId of assetIdsToAdd) {\n const asset = assetsById.get(assetId);\n if (asset) {\n await this.addAsset(asset);\n }\n }\n }\n\n /**\n * Adds a reference to another content object.\n *\n * @param content - Content object or URL to reference\n * @param options.targetVersion - Optional ContentVersion.version to pin the\n * citation to. Pass the target's current version (typically the latest\n * publication) to enable drift detection later. Pass `null` or omit to\n * leave the reference untracked.\n * @returns Promise that resolves when the reference is added\n */\n public async addReference(\n content: Content | string,\n options: { targetVersion?: number | null } = {},\n ) {\n if (!this.id) {\n throw new Error('Cannot add reference to unsaved content');\n }\n\n const target = await this.resolveReferenceTarget(content);\n\n if (!target.id) {\n throw new Error('Cannot add reference to unsaved content');\n }\n if (this.id === target.id) {\n return;\n }\n\n const references = await this.getReferenceCollection();\n // R2 junction `attach` carries extra row fields via its opts bag, so the\n // tenant scope and main's citation pin (targetVersion) ride along together.\n await references.attach(this.id, target.id, {\n tenantId: this.tenantId,\n targetVersion: options.targetVersion,\n });\n this.references = await this.getReferences();\n }\n\n /**\n * Removes a reference to another content object\n *\n * @param targetId - ID of the referenced content to remove\n */\n public async removeReference(targetId: string) {\n if (!this.id) {\n return;\n }\n\n const references = await this.getReferenceCollection();\n await references.detach(this.id, targetId);\n this.references = this.references.filter(\n (reference) => reference.id !== targetId,\n );\n }\n\n /**\n * Gets all referenced content objects\n *\n * @returns Promise resolving to an array of referenced Content objects\n */\n public async getReferences() {\n if (!this.id) {\n return [];\n }\n\n const references = await this.getReferenceCollection();\n const linkedReferences = await references.byLeft(this.id);\n const targetIds = linkedReferences.map((reference) => reference.targetId);\n\n if (targetIds.length === 0) {\n this.references = [];\n return this.references;\n }\n\n const contents = await this.getContentsCollection();\n const resolved = await contents.listByIds(targetIds);\n const referencesById = new Map(\n resolved\n .filter((content) => content.id)\n .map((content) => [content.id as string, content]),\n );\n\n this.references = targetIds\n .map((targetId) => referencesById.get(targetId))\n .filter(Boolean) as Content[];\n return this.references;\n }\n\n /**\n * Returns the raw reference edges with their citation pins\n * (`{ targetId, targetVersion }`). Unlike `getReferences()` (which resolves\n * to `Content` objects and loses the per-edge `targetVersion`), this keeps\n * the pin so callers — notably version snapshots — can reconstruct pinned\n * citations on restore. See `ContentVersionCollection.restoreIntoContent`.\n */\n public async getReferenceEdges(): Promise<\n Array<{ targetId: string; targetVersion: number | null }>\n > {\n if (!this.id) {\n return [];\n }\n\n const references = await this.getReferenceCollection();\n const linkedReferences = await references.getForSource(this.id);\n return linkedReferences\n .filter((edge) => Boolean(edge.targetId))\n .map((edge) => ({\n targetId: edge.targetId as string,\n targetVersion: edge.targetVersion ?? null,\n }));\n }\n\n /**\n * Returns one entry per reference edge with the pinned `targetVersion` and\n * the target's latest version. Drift exists when both are present and\n * differ — callers can use this to surface \"the source you cited has been\n * updated\" affordances in editors or review tools.\n *\n * `currentVersion` is the target's latest **publication** `ContentVersion`,\n * because pins are taken against the latest publication (see `addReference`).\n * Auto-created `correction`/`draft`/`manual` versions bump the shared\n * `(content_id, version)` counter but do NOT republish, so comparing against\n * the max version of *any* kind produced false drift positives (#1387 #4).\n *\n * Unpinned references (`citedVersion === null`) are included with\n * `currentVersion` populated when available so callers can choose to\n * surface them as \"pinnable\" suggestions.\n */\n public async getReferenceDrift(): Promise<\n Array<{\n targetId: string;\n citedVersion: number | null;\n currentVersion: number | null;\n isDrifted: boolean;\n }>\n > {\n if (!this.id) {\n return [];\n }\n\n const references = await this.getReferenceCollection();\n const linkedReferences = await references.getForSource(this.id);\n if (linkedReferences.length === 0) {\n return [];\n }\n\n const versions = await this.getContentVersionCollection();\n const targetIds = linkedReferences.map((reference) => reference.targetId);\n\n // Single query for all target *publication* versions; pick the max per\n // contentId. Pins are taken against the latest publication, so only\n // publication versions count as drift (#1387 #4). Filtering by kind here\n // also avoids the N+1 of loading each version to inspect its kind.\n const allVersions = await versions.list({\n where: { contentId: targetIds, kind: 'publication' },\n orderBy: 'version DESC',\n });\n const latestByContentId = new Map<string, number>();\n for (const version of allVersions) {\n if (!latestByContentId.has(version.contentId)) {\n latestByContentId.set(version.contentId, version.version);\n }\n }\n\n return linkedReferences.map((reference) => {\n const currentVersion = latestByContentId.get(reference.targetId) ?? null;\n const citedVersion = reference.targetVersion ?? null;\n return {\n targetId: reference.targetId,\n citedVersion,\n currentVersion,\n isDrifted:\n citedVersion !== null &&\n currentVersion !== null &&\n citedVersion !== currentVersion,\n };\n });\n }\n\n public isGoverned(): boolean {\n return this.getConfiguredGovernance().isGoverned;\n }\n\n public async getFactLinks(\n options: { relationship?: FactContentRelationship } = {},\n ) {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.factLinkingEnabled || !this.id) {\n return [];\n }\n\n if (!this.id) {\n return [];\n }\n\n const links = await this.getFactContentCollection();\n return options.relationship\n ? links.byRight(this.id as string, { relationship: options.relationship })\n : links.byRight(this.id as string);\n }\n\n public async getFacts(\n options: {\n relationship?: FactContentRelationship;\n includeSuperseded?: boolean;\n latestOnly?: boolean;\n } = {},\n ): Promise<Fact[]> {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.factLinkingEnabled || !this.id) {\n return [];\n }\n\n if (!this.id) {\n return [];\n }\n\n const facts = await this.getFactCollection();\n return facts.getForContent(this.id as string, options);\n }\n\n public async addFact(\n fact: Fact | string,\n relationship?: FactContentRelationship,\n metadata?: Record<string, unknown>,\n ) {\n const governance = await this.requireFactLinking('fact association');\n\n if (!this.id) {\n throw new Error('Cannot associate an unsaved content item with a fact');\n }\n\n const factId = typeof fact === 'string' ? fact : (fact.id as string);\n if (!factId) {\n throw new Error('Fact ID is required to create a content-fact link');\n }\n\n const links = await this.getFactContentCollection();\n return links.attach(factId, this.id as string, {\n relationship: relationship || governance.defaultFactRelationship,\n metadata,\n });\n }\n\n public async removeFact(\n factId: string,\n relationship?: FactContentRelationship,\n ): Promise<void> {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.factLinkingEnabled) {\n return;\n }\n\n if (!this.id) {\n return;\n }\n\n const links = await this.getFactContentCollection();\n if (relationship) {\n await links.detach(factId, this.id as string, { relationship });\n return;\n }\n\n await links.detach(factId, this.id as string);\n }\n\n public async syncFacts(\n factIds: string[],\n relationship?: FactContentRelationship,\n ): Promise<{ added: string[]; kept: string[]; removed: string[] }> {\n const governance = await this.requireFactLinking('fact sync');\n\n if (!this.id) {\n throw new Error('Cannot sync facts for unsaved content');\n }\n\n const uniqueFactIds = [...new Set(factIds.filter(Boolean))];\n const links = await this.getFactContentCollection();\n const resolvedRelationship =\n relationship || governance.defaultFactRelationship;\n const existing = await links.byRight(this.id as string, {\n relationship: resolvedRelationship,\n });\n\n const existingIds = new Set(existing.map((link) => link.factId));\n const desiredIds = new Set(uniqueFactIds);\n\n const kept = uniqueFactIds.filter((factId) => existingIds.has(factId));\n const added = uniqueFactIds.filter((factId) => !existingIds.has(factId));\n const removed = existing\n .map((link) => link.factId)\n .filter((factId) => !desiredIds.has(factId));\n\n for (const factId of added) {\n await links.attach(factId, this.id as string, {\n relationship: resolvedRelationship,\n });\n }\n\n for (const factId of removed) {\n await links.detach(factId, this.id as string, {\n relationship: resolvedRelationship,\n });\n }\n\n return { added, kept, removed };\n }\n\n public async browseFacts(\n query = '',\n options: {\n limit?: number;\n offset?: number;\n minSimilarity?: number;\n includeSuperseded?: boolean;\n latestOnly?: boolean;\n } = {},\n ): Promise<Fact[]> {\n await this.requireFactLinking('fact catalog browsing');\n const facts = await this.getFactCollection();\n return facts.browseCatalog(query, {\n ...options,\n tenantId: this.tenantId,\n });\n }\n\n private async getFactAuditSourceMaterials(): Promise<{\n sources: FactAuditSourceMaterial[];\n warnings: string[];\n }> {\n const warnings: string[] = [];\n const sources: FactAuditSourceMaterial[] = [];\n const references = await this.getReferences();\n const assets = await this.getAssets();\n\n for (const reference of references) {\n const referenceId = (reference.id as string | undefined) || '';\n const text = getContentText(reference);\n // `sourceUrl` is not a declared Content field; read it structurally.\n const referenceSourceUrl = (reference as { sourceUrl?: unknown })\n .sourceUrl;\n const sourceUrl =\n normalizeAuditText(reference.url) ||\n normalizeAuditText(referenceSourceUrl) ||\n normalizeAuditText(reference.fileKey);\n const sourceTitle =\n normalizeAuditText(reference.title) ||\n normalizeAuditText(reference.name) ||\n sourceUrl ||\n referenceId;\n\n if (!text) {\n warnings.push(\n `Reference ${sourceTitle || referenceId} has no extracted text.`,\n );\n continue;\n }\n\n sources.push({\n sourceKind: 'content-reference',\n sourceId: referenceId,\n sourceUrl,\n sourceTitle,\n locator: sourceTitle,\n text,\n });\n }\n\n for (const asset of assets as Array<Asset & FactAuditAssetExtraFields>) {\n const metadata =\n typeof asset?.getMetadata === 'function'\n ? asset.getMetadata()\n : parseAuditMetadata(asset?.metadata);\n const text = [\n metadata.extractedText,\n metadata.text,\n metadata.ocrText,\n asset?.text,\n asset?.body,\n asset?.description,\n ]\n .map(normalizeAuditText)\n .filter(Boolean)\n .join('\\n\\n');\n const assetId = normalizeAuditText(asset?.id);\n const sourceTitle =\n normalizeAuditText(asset?.title) ||\n normalizeAuditText(asset?.name) ||\n normalizeAuditText(asset?.filename) ||\n assetId;\n const sourceUrl =\n normalizeAuditText(asset?.url) ||\n normalizeAuditText(asset?.sourceUrl) ||\n normalizeAuditText(asset?.fileKey);\n\n if (!text) {\n warnings.push(`Asset ${sourceTitle || assetId} has no extracted text.`);\n continue;\n }\n\n sources.push({\n sourceKind: 'asset',\n sourceId: assetId,\n sourceUrl,\n sourceTitle,\n locator: sourceTitle,\n text,\n });\n }\n\n return { sources, warnings };\n }\n\n private factMatchesTenant(fact: {\n tenantId?: string | null;\n tenant_id?: string | null;\n }): boolean {\n return (\n fact.tenantId === this.tenantId ||\n fact.tenant_id === this.tenantId ||\n (!fact.tenantId && !fact.tenant_id && !this.tenantId)\n );\n }\n\n private async findExactArticleClaimFact(\n statement: string,\n ): Promise<Fact | null> {\n const normalizedStatement = normalizeAuditText(statement);\n const facts = await this.getFactCollection();\n const linkedClaimFacts = await Promise.all(\n (await this.getFactLinks({ relationship: 'referenced_in' })).map((link) =>\n facts.get({ id: link.factId }),\n ),\n );\n const linkedMatch = linkedClaimFacts.find(\n (fact): fact is Fact =>\n Boolean(fact) &&\n this.factMatchesTenant(fact as Fact) &&\n normalizeAuditText((fact as Fact).textRefined) === normalizedStatement,\n );\n if (linkedMatch) {\n return linkedMatch;\n }\n\n const matches = await facts.list({\n where: { textRefined: normalizedStatement },\n orderBy: 'updated_at DESC',\n });\n\n return (\n matches.find(\n (fact) =>\n this.factMatchesTenant(fact) &&\n this.id &&\n isGeneratedArticleClaimFact(fact, this.id as string),\n ) || null\n );\n }\n\n private async safeAuditLink(\n factId: string,\n relationship: FactContentRelationship,\n metadata: Record<string, unknown>,\n ) {\n const links = await this.getFactContentCollection();\n const existing = (\n await links.byRight(this.id as string, { relationship })\n ).find((link) => link.factId === factId);\n\n if (existing) {\n const existingMetadata = getLinkMetadata(existing);\n if (existingMetadata.generatedBy === FACT_AUDIT_GENERATED_BY) {\n existing.setMetadata?.({\n ...existingMetadata,\n ...metadata,\n });\n } else {\n existing.setMetadata?.({\n ...existingMetadata,\n factAudit: {\n ...asRecord(existingMetadata.factAudit),\n ...metadata,\n },\n });\n }\n await existing.save();\n return existing;\n }\n\n return links.attach(factId, this.id as string, { relationship, metadata });\n }\n\n private async clearGeneratedFactAudit(): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const [links, evidences] = await Promise.all([\n this.getFactLinks(),\n this.getFactEvidenceCollection(),\n ]);\n\n for (const link of links) {\n const metadata = getLinkMetadata(link);\n const nestedFactAudit = asRecord(metadata.factAudit);\n if (metadata.generatedBy === FACT_AUDIT_GENERATED_BY) {\n await link.delete();\n } else if (\n metadata.factAudit &&\n typeof metadata.factAudit === 'object' &&\n nestedFactAudit.generatedBy === FACT_AUDIT_GENERATED_BY\n ) {\n const { factAudit: _removed, ...preservedMetadata } = metadata;\n link.setMetadata?.(preservedMetadata);\n await link.save();\n }\n }\n\n const generatedEvidence = await evidences.list({\n where: { tenantId: this.tenantId ?? null },\n });\n for (const evidence of generatedEvidence) {\n const metadata =\n typeof evidence.getMetadata === 'function'\n ? evidence.getMetadata()\n : {};\n if (\n metadata.generatedBy === FACT_AUDIT_GENERATED_BY &&\n metadata.contentId === this.id\n ) {\n await evidence.delete();\n }\n }\n }\n\n private async clearGeneratedFactSourcesForSources(\n sources: FactAuditSourceMaterial[],\n ): Promise<string[]> {\n if (!this.id || sources.length === 0) {\n return [];\n }\n\n const sourceKeys = new Set(\n sources.map((source) => `${source.sourceKind}:${source.sourceId}`),\n );\n const factSources = await this.getFactSourceCollection();\n const generatedSources = await factSources.list({\n where: { tenantId: this.tenantId ?? null },\n });\n const deletedSourceIds: string[] = [];\n\n for (const source of generatedSources) {\n const metadata =\n typeof source.getMetadata === 'function' ? source.getMetadata() : {};\n const sourceKey = `${source.sourceType || ''}:${metadata.sourceId || ''}`;\n if (\n sourceKeys.has(sourceKey) &&\n metadata.generatedBy === FACT_AUDIT_GENERATED_BY &&\n metadata.contentId === this.id\n ) {\n if (typeof source.id === 'string') {\n deletedSourceIds.push(source.id);\n }\n await source.delete();\n }\n }\n\n return deletedSourceIds;\n }\n\n private async extractReferenceFactsForAudit(\n sources: FactAuditSourceMaterial[],\n options: {\n auditRunId: string;\n maxFactsPerSource?: number;\n context?: string;\n replaceGenerated?: boolean;\n },\n ) {\n const facts = await this.getFactCollection();\n const evidences = await this.getFactEvidenceCollection();\n const warnings: string[] = [];\n const referenceFacts = new Map<string, Fact>();\n let deletedEvidenceIds: string[] = [];\n let deletedSourceIds: string[] = [];\n\n if (options.replaceGenerated && sources.length > 0) {\n const replacement = await evidences.replaceGeneratedForSources(\n sources.map((source) => ({\n sourceKind: source.sourceKind,\n sourceId: source.sourceId,\n })),\n {\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id as string,\n tenantId: this.tenantId ?? null,\n },\n );\n deletedEvidenceIds = replacement.deletedEvidenceIds;\n deletedSourceIds =\n await this.clearGeneratedFactSourcesForSources(sources);\n }\n\n for (const source of sources) {\n let candidates: FactExtractionCandidate[] = [];\n try {\n candidates = await facts.extractCandidatesFromText(source.text, {\n domain: FACT_AUDIT_DOMAIN,\n sourceType: source.sourceKind,\n context: options.context || source.sourceTitle,\n maxFacts: options.maxFactsPerSource ?? 24,\n tenantId: this.tenantId,\n });\n } catch (error) {\n warnings.push(\n `Failed to extract facts from ${source.sourceTitle}: ${errorMessage(error)}`,\n );\n continue;\n }\n\n for (const candidate of candidates) {\n const result = await facts.reconcile({\n rawInput: candidate.statement,\n type: candidate.type || 'assertion',\n domain: FACT_AUDIT_DOMAIN,\n tenantId: this.tenantId,\n source: {\n sourceType: source.sourceKind,\n sourceUrl: source.sourceUrl,\n sourceTitle: source.sourceTitle,\n credibility: candidate.confidence ?? 0.75,\n metadata: {\n auditRunId: options.auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n sourceId: source.sourceId,\n quote: candidate.sourceExcerpt || null,\n locator: source.locator || null,\n },\n },\n });\n referenceFacts.set(result.fact.id as string, result.fact);\n\n await evidences.upsertEvidence({\n factId: result.fact.id as string,\n status: 'supports',\n sourceKind: source.sourceKind,\n sourceId: source.sourceId,\n sourceUrl: source.sourceUrl,\n sourceTitle: source.sourceTitle,\n quote: candidate.sourceExcerpt || candidate.statement,\n locator: source.locator,\n extractionMethod: 'ai-reference-fact',\n confidence: candidate.confidence ?? 0.75,\n tenantId: this.tenantId,\n metadata: {\n auditRunId: options.auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n candidateMetadata: candidate.metadata || {},\n },\n });\n }\n }\n\n return {\n referenceFacts,\n warnings,\n referenceFactsExtracted: referenceFacts.size,\n deletedEvidenceIds,\n deletedSourceIds,\n repairedSources: sources.map((source) => ({\n sourceKind: source.sourceKind,\n sourceId: source.sourceId,\n sourceTitle: source.sourceTitle,\n })),\n };\n }\n\n private async getCurrentFactAuditSupportCandidates(\n options: {\n referenceFacts?: Map<string, Fact>;\n sources?: FactAuditSourceSelector[];\n sourceIds?: string[];\n maxCandidateEvidence?: number;\n } = {},\n ) {\n const evidences = await this.getFactEvidenceCollection();\n const allFacts = await this.getFactCollection();\n const candidateFacts = new Map<string, FactAuditSupportCandidate>();\n const candidateEvidence = new Map<string, FactEvidence>();\n const sourceKeys = new Set(\n (options.sources || []).map(\n (source) => `${source.sourceKind}:${source.sourceId}`,\n ),\n );\n const sourceIds = new Set(options.sourceIds || []);\n const maxCandidateEvidence = Math.max(\n 1,\n options.maxCandidateEvidence ?? 120,\n );\n\n const evidenceEntries = options.referenceFacts\n ? (\n await Promise.all(\n [...options.referenceFacts.keys()].map((factId) =>\n evidences.getForFact(factId),\n ),\n )\n ).flat()\n : await evidences.list({\n where: { tenantId: this.tenantId ?? null },\n });\n\n for (const entry of evidenceEntries) {\n if (!isGeneratedFactAuditEvidence(entry, this.id as string)) {\n continue;\n }\n if (entry.sourceKind === 'content') {\n continue;\n }\n if (entry.status === 'irrelevant' || entry.status === 'invalid') {\n continue;\n }\n if (\n sourceKeys.size > 0 &&\n !sourceKeys.has(`${entry.sourceKind}:${entry.sourceId}`)\n ) {\n continue;\n }\n if (sourceIds.size > 0 && !sourceIds.has(entry.sourceId)) {\n continue;\n }\n if (candidateEvidence.size >= maxCandidateEvidence) {\n break;\n }\n\n const fact =\n options.referenceFacts?.get(entry.factId) ||\n (await allFacts.get({ id: entry.factId }));\n if (!fact) {\n continue;\n }\n\n const factId = fact.id as string;\n const existing = candidateFacts.get(factId) || {\n id: factId,\n statement: fact.textRefined || fact.textRaw || '',\n evidence: [],\n };\n const serializedEvidence = {\n id: entry.id || null,\n status: entry.status || 'supports',\n quote: entry.quote || null,\n sourceTitle: entry.sourceTitle || null,\n sourceUrl: entry.sourceUrl || null,\n locator: entry.locator || null,\n };\n existing.evidence.push(serializedEvidence);\n candidateFacts.set(factId, existing);\n if (typeof entry.id === 'string') {\n candidateEvidence.set(entry.id, entry);\n }\n }\n\n return {\n supportCandidates: [...candidateFacts.values()],\n candidateFactIds: new Set(candidateFacts.keys()),\n candidateEvidence,\n };\n }\n\n public async repairFactAudit(\n options: {\n maxReferenceFactsPerSource?: number;\n maxArticleClaims?: number;\n context?: string;\n } = {},\n ) {\n await this.requireFactLinking('fact audit repair');\n if (!this.id) {\n throw new Error('Cannot repair fact audit for unsaved content');\n }\n\n const auditRunId = createFactAuditRunId(this.id as string);\n const facts = await this.getFactCollection();\n const evidences = await this.getFactEvidenceCollection();\n const warnings: string[] = [];\n const articleText = getContentText(this);\n\n const sourceMaterials = await this.getFactAuditSourceMaterials();\n warnings.push(...sourceMaterials.warnings);\n await this.clearGeneratedFactAudit();\n const referenceRepair = await this.extractReferenceFactsForAudit(\n sourceMaterials.sources,\n {\n auditRunId,\n maxFactsPerSource: options.maxReferenceFactsPerSource,\n context: options.context,\n },\n );\n warnings.push(...referenceRepair.warnings);\n const referenceFacts = referenceRepair.referenceFacts;\n\n let claims: FactExtractionCandidate[] = [];\n if (!articleText) {\n warnings.push('Article has no text to audit.');\n } else {\n try {\n claims = await facts.extractArticleClaims(articleText, {\n domain: FACT_AUDIT_DOMAIN,\n sourceType: 'article',\n context: options.context || this.title || this.slug || '',\n maxFacts: options.maxArticleClaims ?? 32,\n tenantId: this.tenantId,\n });\n } catch (error) {\n warnings.push(\n `Failed to extract article claims: ${errorMessage(error)}`,\n );\n }\n }\n\n const { supportCandidates, candidateFactIds, candidateEvidence } =\n await this.getCurrentFactAuditSupportCandidates({\n referenceFacts,\n });\n\n const findings: ContentReviewFinding[] = [];\n\n for (const claim of claims) {\n let assessment: FactClaimSupportAssessment;\n try {\n assessment = await facts.assessClaimSupport(\n claim.statement,\n supportCandidates,\n { tenantId: this.tenantId },\n );\n } catch (error) {\n warnings.push(\n `Failed to assess claim \"${claim.statement}\": ${errorMessage(error)}`,\n );\n assessment = {\n status: 'needs_review' as FactClaimSupportStatus,\n matchedFactIds: [],\n matchedEvidenceIds: [],\n rationale: 'Support assessment failed.',\n confidence: undefined,\n };\n }\n\n const matchedFactIds = assessment.matchedFactIds.filter((factId) =>\n candidateFactIds.has(factId),\n );\n let claimFact = await this.findExactArticleClaimFact(claim.statement);\n\n if (!claimFact) {\n claimFact = await facts.create({\n textRefined: claim.statement,\n textRaw: claim.statement,\n type: claim.type || 'assertion',\n domain: FACT_AUDIT_DOMAIN,\n status:\n assessment.status === 'unsupported' ||\n assessment.status === 'needs_review'\n ? 'pending'\n : 'active',\n sourceCount: 0,\n confidence: claim.confidence ?? assessment.confidence ?? 0.5,\n tenantId: this.tenantId,\n metadata: JSON.stringify({\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n auditFactRole: 'article-claim',\n claimOnly: matchedFactIds.length === 0,\n }),\n });\n } else if (\n this.id &&\n isGeneratedArticleClaimFact(claimFact, this.id as string)\n ) {\n claimFact.status =\n assessment.status === 'unsupported' ||\n assessment.status === 'needs_review'\n ? 'pending'\n : 'active';\n claimFact.confidence =\n claim.confidence ?? assessment.confidence ?? claimFact.confidence;\n claimFact.updateMetadata?.({\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n auditFactRole: 'article-claim',\n claimOnly: matchedFactIds.length === 0,\n });\n await claimFact.save();\n }\n\n const articleEvidence = await evidences.upsertEvidence({\n factId: claimFact.id as string,\n status: 'supports',\n sourceKind: 'content',\n sourceId: this.id as string,\n sourceTitle: this.title || this.slug || (this.id as string),\n quote: claim.sourceExcerpt || claim.statement,\n locator: this.title || this.slug || '',\n extractionMethod: 'ai-article-claim',\n confidence: claim.confidence ?? assessment.confidence ?? 0.5,\n tenantId: this.tenantId,\n metadata: {\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n supportStatus: assessment.status,\n },\n });\n\n let supportingEvidenceIds = assessment.matchedEvidenceIds.filter(\n (evidenceId) => candidateEvidence.has(evidenceId),\n );\n for (const matchedFactId of matchedFactIds) {\n if (supportingEvidenceIds.length > 0) {\n continue;\n }\n const candidate = supportCandidates.find(\n (entry) => entry.id === matchedFactId,\n );\n supportingEvidenceIds = [\n ...supportingEvidenceIds,\n ...(candidate?.evidence || [])\n .map((entry) => entry.id)\n .filter((id: unknown): id is string => typeof id === 'string'),\n ];\n }\n supportingEvidenceIds = [...new Set(supportingEvidenceIds)];\n\n const linkMetadata = {\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n supportStatus: assessment.status,\n claimQuote: claim.sourceExcerpt || claim.statement,\n claimFactId: claimFact.id as string,\n articleEvidenceId: articleEvidence.id || null,\n supportingFactIds: matchedFactIds,\n supportingEvidenceIds,\n rationale: assessment.rationale,\n confidence: assessment.confidence ?? claim.confidence ?? null,\n };\n\n await this.safeAuditLink(\n claimFact.id as string,\n 'referenced_in',\n linkMetadata,\n );\n\n for (const matchedFactId of matchedFactIds) {\n await this.safeAuditLink(\n matchedFactId,\n assessment.status === 'contradicted' ? 'contradicts' : 'supports',\n {\n ...linkMetadata,\n supportingEvidenceIds,\n },\n );\n }\n\n if (assessment.status !== 'supported') {\n findings.push({\n severity: assessment.status === 'contradicted' ? 'error' : 'warning',\n title:\n assessment.status === 'contradicted'\n ? 'Contradicted article claim'\n : 'Unsupported article claim',\n detail: assessment.rationale || 'The claim needs editorial review.',\n factId: claimFact.id as string,\n quote: claim.sourceExcerpt || claim.statement,\n ruleId: 'fact-audit',\n });\n }\n }\n\n const reviews = await this.getContentReviewCollection();\n await reviews.createFromResult({\n contentId: this.id as string,\n kind: 'facts',\n policyKey: 'facts',\n reviewer: 'system',\n result: {\n status: findings.length > 0 ? 'flagged' : 'passed',\n summary:\n findings.length > 0\n ? `${findings.length} article claim(s) need review.`\n : 'Article claims are supported by available evidence.',\n findings,\n },\n metadata: {\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n warnings,\n },\n tenantId: this.tenantId,\n });\n\n const state = await this.getFactAuditState();\n return {\n ...state,\n repair: {\n auditRunId,\n claimsExtracted: claims.length,\n referenceFactsExtracted: referenceRepair.referenceFactsExtracted,\n warnings,\n },\n };\n }\n\n public async repairFactAuditAction(\n options: {\n maxReferenceFactsPerSource?: number;\n maxArticleClaims?: number;\n context?: string;\n } = {},\n ) {\n return this.repairFactAudit(options);\n }\n\n public async repairFactEvidence(\n options: FactAuditResourceRepairOptions = {},\n ) {\n await this.requireFactLinking('fact evidence repair');\n if (!this.id) {\n throw new Error('Cannot repair fact evidence for unsaved content');\n }\n\n const auditRunId = createFactAuditRunId(this.id as string);\n const sourceMaterials = await this.getFactAuditSourceMaterials();\n const sources = filterAuditSources(\n sourceMaterials.sources,\n options.sources,\n );\n const warnings: string[] = [];\n\n if (options.sources?.length && sources.length === 0) {\n warnings.push('No matching resource text was available for repair.');\n }\n\n const repair = await this.extractReferenceFactsForAudit(sources, {\n auditRunId,\n maxFactsPerSource: options.maxFactsPerSource,\n context: options.context,\n replaceGenerated: true,\n });\n warnings.push(...repair.warnings);\n\n const state = await this.getFactAuditState();\n return {\n ...state,\n evidenceRepair: {\n auditRunId,\n referenceFactsExtracted: repair.referenceFactsExtracted,\n repairedSources: repair.repairedSources,\n deletedEvidenceIds: repair.deletedEvidenceIds,\n deletedSourceIds: repair.deletedSourceIds,\n warnings,\n },\n };\n }\n\n public async repairFactEvidenceAction(\n options: FactAuditResourceRepairOptions = {},\n ) {\n return this.repairFactEvidence(options);\n }\n\n private async clearGeneratedSupportLinksForClaim(\n claimFactId: string,\n articleEvidenceId: string | null,\n ): Promise<void> {\n const links = await this.getFactLinks();\n\n for (const link of links) {\n if (\n link.relationship !== 'supports' &&\n link.relationship !== 'contradicts'\n ) {\n continue;\n }\n\n const metadata = getGeneratedFactAuditMetadata(link);\n if (!metadata) {\n continue;\n }\n\n const matchesEvidence =\n articleEvidenceId &&\n typeof metadata.articleEvidenceId === 'string' &&\n metadata.articleEvidenceId === articleEvidenceId;\n const matchesClaim =\n typeof metadata.claimFactId === 'string' &&\n metadata.claimFactId === claimFactId;\n\n if (matchesEvidence || matchesClaim) {\n await link.delete();\n }\n }\n }\n\n public async recheckFactClaims(options: FactAuditClaimRecheckOptions = {}) {\n await this.requireFactLinking('claim support recheck');\n if (!this.id) {\n throw new Error('Cannot recheck fact claims for unsaved content');\n }\n\n const auditRunId = createFactAuditRunId(this.id as string);\n const facts = await this.getFactCollection();\n const evidences = await this.getFactEvidenceCollection();\n const links = await this.getFactContentCollection();\n const claimIdFilter = new Set(options.claimFactIds || []);\n const { supportCandidates, candidateFactIds, candidateEvidence } =\n await this.getCurrentFactAuditSupportCandidates({\n sources: options.sources,\n sourceIds: options.sourceIds,\n maxCandidateEvidence: options.maxCandidateEvidence,\n });\n const claimLinks = (\n await links.byRight(this.id as string, { relationship: 'referenced_in' })\n )\n .map((link) => ({\n link,\n metadata: getGeneratedFactAuditMetadata(link),\n }))\n .filter(\n (\n entry,\n ): entry is { link: FactContent; metadata: Record<string, unknown> } =>\n entry.metadata !== null &&\n (claimIdFilter.size === 0 || claimIdFilter.has(entry.link.factId)),\n );\n const warnings: string[] = [];\n let recheckedClaims = 0;\n\n for (const { link, metadata } of claimLinks) {\n const claimFact = await facts.get({ id: link.factId });\n if (!claimFact) {\n continue;\n }\n\n const claimText =\n normalizeAuditText(metadata.claimQuote) ||\n normalizeAuditText(claimFact.textRefined) ||\n normalizeAuditText(claimFact.textRaw);\n if (!claimText) {\n continue;\n }\n\n let assessment: FactClaimSupportAssessment;\n try {\n assessment = await facts.assessClaimSupport(\n claimText,\n supportCandidates,\n { tenantId: this.tenantId },\n );\n } catch (error) {\n warnings.push(\n `Failed to recheck claim \"${claimText}\": ${errorMessage(error)}`,\n );\n assessment = {\n status: 'needs_review',\n matchedFactIds: [],\n matchedEvidenceIds: [],\n rationale: 'Support assessment failed.',\n confidence: undefined,\n };\n }\n\n const matchedFactIds = assessment.matchedFactIds.filter((factId) =>\n candidateFactIds.has(factId),\n );\n let supportStatus = assessment.status;\n if (\n (supportStatus === 'supported' || supportStatus === 'contradicted') &&\n matchedFactIds.length === 0\n ) {\n supportStatus = 'needs_review';\n }\n let supportingEvidenceIds = assessment.matchedEvidenceIds.filter(\n (evidenceId) => candidateEvidence.has(evidenceId),\n );\n if (supportingEvidenceIds.length === 0) {\n for (const matchedFactId of matchedFactIds) {\n const candidate = supportCandidates.find(\n (entry) => entry.id === matchedFactId,\n );\n supportingEvidenceIds.push(\n ...(candidate?.evidence || [])\n .map((entry) => entry.id)\n .filter((id: unknown): id is string => typeof id === 'string'),\n );\n }\n }\n supportingEvidenceIds = [...new Set(supportingEvidenceIds)];\n\n const articleEvidenceId =\n typeof metadata.articleEvidenceId === 'string'\n ? metadata.articleEvidenceId\n : null;\n const nextMetadata = {\n ...metadata,\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n supportStatus,\n supportingFactIds: matchedFactIds,\n supportingEvidenceIds,\n rationale: assessment.rationale,\n confidence: assessment.confidence ?? metadata.confidence ?? null,\n claimFactId: link.factId,\n };\n const existingMetadata = getLinkMetadata(link);\n if (existingMetadata.generatedBy === FACT_AUDIT_GENERATED_BY) {\n link.setMetadata?.(nextMetadata);\n } else {\n link.setMetadata?.({\n ...existingMetadata,\n factAudit: nextMetadata,\n });\n }\n await link.save();\n\n if (articleEvidenceId) {\n const articleEvidence = await evidences.get({ id: articleEvidenceId });\n if (articleEvidence) {\n articleEvidence.updateMetadata({\n auditRunId,\n supportStatus,\n });\n await articleEvidence.save();\n }\n }\n\n await this.clearGeneratedSupportLinksForClaim(\n link.factId,\n articleEvidenceId,\n );\n for (const matchedFactId of matchedFactIds) {\n await this.safeAuditLink(\n matchedFactId,\n supportStatus === 'contradicted' ? 'contradicts' : 'supports',\n {\n ...nextMetadata,\n articleEvidenceId,\n },\n );\n }\n\n recheckedClaims += 1;\n }\n\n const state = await this.getFactAuditState();\n return {\n ...state,\n claimRecheck: {\n auditRunId,\n recheckedClaims,\n candidateFacts: supportCandidates.length,\n candidateEvidence: candidateEvidence.size,\n warnings,\n },\n };\n }\n\n public async recheckFactClaimsAction(\n options: FactAuditClaimRecheckOptions = {},\n ) {\n return this.recheckFactClaims(options);\n }\n\n public async updateFactEvidenceStatus(\n options: FactEvidenceStatusUpdateOptions = {},\n ) {\n await this.requireFactLinking('evidence status update');\n if (!this.id) {\n throw new Error('Cannot update fact evidence for unsaved content');\n }\n\n const status = normalizeFactEvidenceStatus(options.status);\n if (!status) {\n throw new Error('A valid evidence status is required');\n }\n\n const requestedEvidenceIds = [\n ...new Set(\n (options.evidenceIds || []).filter(\n (id): id is string => typeof id === 'string' && id.length > 0,\n ),\n ),\n ];\n const evidences = await this.getFactEvidenceCollection();\n const sourceMaterials = await this.getFactAuditSourceMaterials();\n const allowedSourceKeys = new Set(\n sourceMaterials.sources.map(\n (source: FactAuditSourceMaterial) =>\n `${source.sourceKind}:${source.sourceId}`,\n ),\n );\n const allowedEvidenceIds: string[] = [];\n\n for (const evidenceId of requestedEvidenceIds) {\n const evidence = await evidences.get({ id: evidenceId });\n if (!evidence) {\n continue;\n }\n\n if (\n this.tenantId &&\n evidence.tenantId &&\n evidence.tenantId !== this.tenantId\n ) {\n continue;\n }\n\n const metadata = getEvidenceMetadata(evidence);\n const sourceKey = `${evidence.sourceKind || ''}:${\n evidence.sourceId || ''\n }`;\n if (\n metadata.contentId === this.id ||\n (evidence.sourceKind === 'content' && evidence.sourceId === this.id) ||\n allowedSourceKeys.has(sourceKey)\n ) {\n allowedEvidenceIds.push(evidenceId);\n }\n }\n\n const updated = await evidences.bulkUpdateStatus(\n allowedEvidenceIds,\n status,\n {\n reason: options.reason,\n },\n );\n const state = await this.getFactAuditState();\n\n return {\n ...state,\n evidenceStatusUpdate: {\n status,\n requestedEvidenceIds,\n updatedEvidenceIds: updated\n .map((entry) => entry.id)\n .filter((id: unknown): id is string => typeof id === 'string'),\n skippedEvidenceIds: requestedEvidenceIds.filter(\n (id) => !allowedEvidenceIds.includes(id),\n ),\n },\n };\n }\n\n public async updateFactEvidenceStatusAction(\n options: FactEvidenceStatusUpdateOptions = {},\n ) {\n return this.updateFactEvidenceStatus(options);\n }\n\n public async getFactAuditState(): Promise<FactAuditState> {\n if (!this.id) {\n return {\n counts: {\n total: 0,\n supported: 0,\n unsupported: 0,\n contradicted: 0,\n needs_review: 0,\n },\n claims: [],\n resourceClaims: [],\n warnings: [],\n generatedBy: FACT_AUDIT_GENERATED_BY,\n latestAuditRunId: null,\n };\n }\n\n const [facts, factLinks] = await Promise.all([\n this.getFacts({\n relationship: 'referenced_in',\n latestOnly: false,\n includeSuperseded: false,\n }),\n this.getFactLinks({ relationship: 'referenced_in' }),\n ]);\n const factMap = new Map(\n facts\n .filter((fact) => fact.id)\n .map((fact) => [fact.id as string, fact] as const),\n );\n const evidences = await this.getFactEvidenceCollection();\n const allFacts = await this.getFactCollection();\n const generatedLinks = factLinks\n .map((link) => ({\n link,\n metadata: getGeneratedFactAuditMetadata(link),\n }))\n .filter(\n (\n entry,\n ): entry is { link: FactContent; metadata: Record<string, unknown> } =>\n entry.metadata !== null,\n );\n const claims: FactAuditClaim[] = [];\n const resourceClaimsByKey = new Map<string, FactAuditResourceClaim>();\n const warnings: string[] = [];\n let latestAuditRunId: string | null = null;\n\n for (const { link, metadata } of generatedLinks) {\n const fact = factMap.get(link.factId);\n if (!fact) {\n continue;\n }\n\n // Opaque audit-link metadata values; cast at the read boundary.\n latestAuditRunId =\n (metadata.auditRunId as string | null) || latestAuditRunId;\n const status = (metadata.supportStatus ||\n 'needs_review') as FactClaimSupportStatus;\n const matchedFactIds = Array.isArray(metadata.supportingFactIds)\n ? metadata.supportingFactIds\n : [];\n const articleEvidenceId =\n typeof metadata.articleEvidenceId === 'string'\n ? metadata.articleEvidenceId\n : null;\n const supportingEvidenceIds = new Set(\n Array.isArray(metadata.supportingEvidenceIds)\n ? metadata.supportingEvidenceIds.filter(\n (id: unknown): id is string => typeof id === 'string',\n )\n : [],\n );\n const [allClaimEvidence, matchedFacts] = await Promise.all([\n evidences.getForFact(fact.id as string),\n Promise.all(\n matchedFactIds.map(async (factId: string) => {\n const matchedFact = await allFacts.get({ id: factId });\n const matchedEvidence = (await evidences.getForFact(factId)).filter(\n (entry) =>\n supportingEvidenceIds.size === 0\n ? entry.sourceKind !== 'content' || entry.sourceId !== this.id\n : supportingEvidenceIds.has(entry.id as string),\n );\n return matchedFact\n ? {\n fact: serializeFact(matchedFact),\n evidence: matchedEvidence.map((entry) => ({\n ...serializeFact(entry),\n metadata:\n typeof entry.getMetadata === 'function'\n ? entry.getMetadata()\n : {},\n })),\n }\n : null;\n }),\n ),\n ]);\n const claimEvidence = allClaimEvidence.filter((entry) =>\n articleEvidenceId\n ? entry.id === articleEvidenceId\n : entry.sourceKind === 'content' && entry.sourceId === this.id,\n );\n\n claims.push({\n id: fact.id as string,\n fact: serializeFact(fact),\n supportStatus: status,\n // Opaque audit-link metadata values; cast at the read boundary.\n claimQuote: (metadata.claimQuote as string | null) || null,\n rationale: (metadata.rationale as string | null) || null,\n confidence: (metadata.confidence as number | null) ?? null,\n relationship: link.relationship || null,\n linkMetadata: metadata,\n evidence: claimEvidence.map((entry) => ({\n ...serializeFact(entry),\n metadata:\n typeof entry.getMetadata === 'function' ? entry.getMetadata() : {},\n })),\n matchedFacts: matchedFacts.filter(\n Boolean,\n ) as FactAuditClaim['matchedFacts'],\n });\n }\n\n const generatedEvidence = await evidences.list({\n where: { tenantId: this.tenantId ?? null },\n });\n for (const evidence of generatedEvidence) {\n const metadata =\n typeof evidence.getMetadata === 'function'\n ? evidence.getMetadata()\n : {};\n if (\n metadata.generatedBy !== FACT_AUDIT_GENERATED_BY ||\n metadata.contentId !== this.id ||\n evidence.sourceKind === 'content'\n ) {\n continue;\n }\n\n const fact = await allFacts.get({ id: evidence.factId });\n if (!fact) {\n continue;\n }\n\n const key = [\n evidence.factId,\n evidence.sourceKind,\n evidence.sourceId,\n evidence.evidenceKey,\n ].join(':');\n const serializedEvidence = {\n ...serializeFact(evidence),\n metadata,\n };\n const existing = resourceClaimsByKey.get(key);\n if (existing) {\n existing.evidence.push(serializedEvidence);\n continue;\n }\n\n resourceClaimsByKey.set(key, {\n id: fact.id as string,\n fact: serializeFact(fact),\n sourceKind: evidence.sourceKind || null,\n sourceId: evidence.sourceId || null,\n sourceUrl: evidence.sourceUrl || null,\n sourceTitle: evidence.sourceTitle || null,\n locator: evidence.locator || null,\n quote: evidence.quote || null,\n status: evidence.status || 'supports',\n confidence: evidence.confidence ?? null,\n evidence: [serializedEvidence],\n });\n }\n\n const latestReview = (\n await this.getContentReviewCollection()\n ).getLatestForPolicyKey(this.id as string, 'facts');\n const review = await latestReview;\n const reviewMetadata =\n review && typeof review.getMetadata === 'function'\n ? review.getMetadata()\n : {};\n if (\n reviewMetadata.generatedBy === FACT_AUDIT_GENERATED_BY &&\n Array.isArray(reviewMetadata.warnings)\n ) {\n warnings.push(...reviewMetadata.warnings);\n }\n\n const counts = {\n total: claims.length,\n supported: 0,\n unsupported: 0,\n contradicted: 0,\n needs_review: 0,\n };\n for (const claim of claims) {\n counts[claim.supportStatus] += 1;\n }\n\n return {\n counts,\n claims,\n resourceClaims: [...resourceClaimsByKey.values()],\n warnings,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n latestAuditRunId,\n };\n }\n\n public async getFactAuditStateAction() {\n return this.getFactAuditState();\n }\n\n public async getFactsState(\n options: { relationship?: FactContentRelationship } = {},\n ) {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.factLinkingEnabled) {\n return {\n factIds: [],\n facts: [],\n factLinks: [],\n };\n }\n\n const relationship = options.relationship;\n const [facts, factLinks] = await Promise.all([\n this.getFacts({\n relationship,\n latestOnly: true,\n includeSuperseded: false,\n }),\n this.getFactLinks(relationship ? { relationship } : {}),\n ]);\n\n return {\n factIds: facts.map((fact) => fact.id).filter(Boolean),\n facts: facts.map(serializeFact),\n factLinks: factLinks.map(serializeFactLink),\n };\n }\n\n public async syncFactsState(\n options: {\n factIds?: string[];\n relationship?: FactContentRelationship;\n } = {},\n ) {\n const governance = await this.requireFactLinking('fact sync');\n const relationship =\n options.relationship || governance.defaultFactRelationship;\n const sync = await this.syncFacts(options.factIds || [], relationship);\n const state = await this.getFactsState({ relationship });\n return {\n ...state,\n sync,\n };\n }\n\n public async createVersion(options: CreateContentVersionOptions = {}) {\n const versions = await this.getContentVersionCollection();\n return versions.createSnapshot(this, options);\n }\n\n public async getVersions() {\n if (!this.id) {\n return [];\n }\n\n const versions = await this.getContentVersionCollection();\n return versions.listForContent(this.id as string);\n }\n\n public async restoreFromVersion(versionNumber: number) {\n const versions = await this.getContentVersionCollection();\n return versions.restoreIntoContent(this, versionNumber);\n }\n\n public async getReviews(kind?: RunContentReviewOptions['kind']) {\n if (!this.id) {\n return [];\n }\n\n const reviews = await this.getContentReviewCollection();\n return reviews.listForContent(this.id as string, kind);\n }\n\n public async listReviews(\n options: { kind?: RunContentReviewOptions['kind'] } = {},\n ) {\n const reviews = await this.getReviews(options.kind);\n return reviews.map(serializeContentReview);\n }\n\n public async getReviewRequirements(\n profileKey: string,\n governance?: ResolvedContentGovernance,\n ) {\n const resolvedGovernance = governance || (await this.resolveGovernance());\n return getContentReviewRequirements(\n profileKey,\n resolvedGovernance.availableProfiles,\n );\n }\n\n public async getGovernanceState(): Promise<ContentGovernanceState> {\n const governance = await this.resolveGovernance();\n\n if (!governance.isGoverned) {\n return {\n ...governance,\n reviewProfiles: [],\n };\n }\n\n return {\n ...governance,\n reviewProfiles: await this.listReviewProfilesAction(),\n };\n }\n\n public async getGovernanceStateAction() {\n return this.getGovernanceState();\n }\n\n public async listReviewProfilesAction() {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned) {\n return [];\n }\n\n return Promise.all(\n getContentReviewProfileKeys(governance.availableProfiles).map(\n (profileKey) => this.evaluateReviewProfile(profileKey),\n ),\n );\n }\n\n public async evaluateReviewProfile(\n profileKey: string,\n ): Promise<ContentReviewProfileEvaluation> {\n const governance = await this.resolveGovernance();\n const requirements = await this.getReviewRequirements(\n profileKey,\n governance,\n );\n\n if (requirements.length === 0) {\n return {\n profileKey,\n ready: true,\n complete: true,\n requirements: [],\n };\n }\n\n const reviews = await this.getContentReviewCollection();\n const reviewFingerprintCache = new Map<string, string>();\n const evaluatedRequirements = await Promise.all(\n requirements.map(async (requirement) => {\n if (!reviewFingerprintCache.has(requirement.policyKey)) {\n reviewFingerprintCache.set(\n requirement.policyKey,\n await this.buildReviewFingerprint(requirement.policyKey),\n );\n }\n\n const latestReview =\n this.id && requirement.policyKey\n ? await reviews.getLatestForPolicyKey(\n this.id as string,\n requirement.policyKey,\n )\n : null;\n const acceptedStatuses = getAcceptedContentReviewStatuses(requirement);\n const latestStatus = latestReview?.status ?? null;\n const latestMetadata =\n typeof latestReview?.getMetadata === 'function'\n ? latestReview.getMetadata()\n : {};\n const currentFingerprint =\n reviewFingerprintCache.get(requirement.policyKey) || null;\n const reviewedFingerprint =\n latestMetadata?.reviewFingerprint ||\n latestMetadata?.contentFingerprint ||\n null;\n const missing = !latestReview;\n const stale =\n !missing &&\n !!reviewedFingerprint &&\n reviewedFingerprint !== currentFingerprint;\n const executed =\n latestStatus !== null && latestStatus !== 'pending' && !stale;\n const satisfied =\n !stale &&\n latestStatus !== null &&\n acceptedStatuses.includes(latestStatus);\n\n return {\n kind: getContentReviewKind(\n requirement.policyKey,\n governance.reviewPolicies,\n ),\n policyKey: requirement.policyKey,\n label:\n requirement.label ||\n getContentReviewPolicy(\n requirement.policyKey,\n governance.reviewPolicies,\n )?.label ||\n requirement.policyKey,\n blocking: requirement.blocking === true,\n acceptedStatuses,\n missing,\n stale,\n executed,\n satisfied,\n latestReviewId: (latestReview?.id as string) || null,\n latestStatus,\n latestSummary: latestReview?.summary || null,\n };\n }),\n );\n\n return {\n profileKey,\n ready: evaluatedRequirements\n .filter((requirement) => requirement.blocking)\n .every((requirement) => requirement.satisfied),\n complete: evaluatedRequirements.every(\n (requirement) => requirement.executed,\n ),\n requirements: evaluatedRequirements,\n };\n }\n\n public async evaluateReviewProfileAction(\n options: { profileKey?: string } = {},\n ) {\n if (!options.profileKey) {\n throw new Error('profileKey is required');\n }\n\n return this.evaluateReviewProfile(options.profileKey);\n }\n\n public async isReadyForReviewProfile(profileKey: string): Promise<boolean> {\n const evaluation = await this.evaluateReviewProfile(profileKey);\n return evaluation.ready;\n }\n\n public async getPublishedTransparency() {\n if (!this.id) {\n return null;\n }\n\n const versions = await this.getContentVersionCollection();\n const latestPublicationVersion =\n await versions.getLatestPublishedForContent(this.id as string);\n\n return latestPublicationVersion?.getTransparency() || null;\n }\n\n public async getPublishedTransparencyAction() {\n return this.getPublishedTransparency();\n }\n\n public async previewTransparency() {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.transparencyEnabled) {\n return null;\n }\n\n return this.buildTransparencySnapshot({\n snapshotKind: 'preview',\n governance,\n });\n }\n\n public async previewTransparencyAction() {\n return this.previewTransparency();\n }\n\n public async runReview(options: RunContentReviewOptions = {}) {\n const governance = await this.requireGovernance('review execution');\n\n if (!this.id) {\n throw new Error('Cannot review unsaved content');\n }\n\n const policyKey = options.policyKey || options.kind || 'custom';\n const policy = getContentReviewPolicy(policyKey, governance.reviewPolicies);\n const kind =\n options.kind ||\n getContentReviewKind(policyKey, governance.reviewPolicies);\n const facts =\n options.facts !== undefined\n ? options.facts\n : governance.factLinkingEnabled &&\n (kind === 'facts' || Boolean(options.factIds?.length))\n ? await this.getFacts({\n latestOnly: true,\n includeSuperseded: false,\n })\n : [];\n const filteredFacts =\n options.factIds && options.factIds.length > 0\n ? facts.filter((fact) => options.factIds?.includes(fact.id as string))\n : facts;\n const reviewPrompt = buildContentReviewPrompt({\n kind,\n content: this,\n facts: filteredFacts,\n policy,\n customInstructions: options.instructions,\n });\n const resolvedPrompt = await resolvePrompt(smrtContentReviewPrompt.key, {\n db: this.options.db,\n tenantId: this.tenantId,\n variables: {\n contentBody: this.body,\n contentDescription: this.description ?? '',\n contentId: this.id ?? '',\n contentTitle: this.title,\n kind,\n policyKey: policy?.key || kind,\n reviewPrompt,\n },\n });\n const reviewFingerprint = await this.buildReviewFingerprint(policyKey);\n const ai = this.ai as {\n message?: (\n prompt: string,\n options?: Record<string, unknown>,\n ) => Promise<string>;\n };\n if (!ai?.message) {\n throw new Error('AI client is not configured for content reviews');\n }\n\n const rawResponse = await ai.message(\n resolvedPrompt.text,\n promptMessageOptions(resolvedPrompt.ai),\n );\n const result = parseContentReviewResponse(rawResponse);\n const persistReview = async (content: Content) => {\n if (options.expectedUpdatedAt !== undefined) {\n await content.claimRevision(options.expectedUpdatedAt);\n }\n const version =\n options.createVersion === false\n ? null\n : await content.createVersion({\n kind: 'review',\n summary: result.summary,\n metadata: {\n kind,\n policyKey,\n reviewFingerprint,\n },\n });\n\n const reviews = await content.getContentReviewCollection();\n return reviews.createFromResult({\n contentId: content.id as string,\n contentVersionId: version?.id as string | undefined,\n kind,\n policyKey,\n reviewer: options.reviewer || 'system',\n result,\n metadata: {\n ...(options.metadata || {}),\n prompt: resolvedPrompt.text,\n rawResponse,\n reviewFingerprint,\n factIds: filteredFacts.map((fact) => fact.id),\n },\n tenantId: content.tenantId,\n });\n };\n\n if (options.expectedUpdatedAt !== undefined) {\n const db = this.db;\n if (!db.transaction) {\n throw new Error(\n 'Atomic content review persistence requires transaction support',\n );\n }\n return this.withTransaction(persistReview);\n }\n return persistReview(this);\n }\n\n public async runReviewAction(options: RunContentReviewOptions = {}) {\n let review: ContentReview;\n\n if (options.kind === 'facts') {\n review = await this.reviewFacts(options);\n } else if (options.kind === 'safety') {\n review = await this.reviewSafety(options);\n } else {\n review = await this.runReview(options);\n }\n\n return serializeContentReview(review);\n }\n\n public async reviewFacts(\n options: Omit<RunContentReviewOptions, 'kind'> = {},\n ) {\n return this.runReview({\n ...options,\n kind: 'facts',\n policyKey: options.policyKey || 'facts',\n });\n }\n\n public async reviewSafety(\n options: Omit<RunContentReviewOptions, 'kind'> = {},\n ) {\n const governance = await this.requireGovernance('safety review');\n const safetyPolicy = getContentReviewPolicy(\n options.policyKey || 'safety',\n governance.reviewPolicies,\n );\n const baseInstructions = safetyPolicy?.instructions || '';\n\n return this.runReview({\n ...options,\n kind: 'safety',\n policyKey: options.policyKey || 'safety',\n instructions:\n options.instructions && baseInstructions\n ? `${baseInstructions}\\n\\nAdditional app-level guidance:\\n${options.instructions}`\n : options.instructions || baseInstructions,\n });\n }\n\n public async getCorrections() {\n if (!this.id) {\n return [];\n }\n\n const corrections = await this.getContentCorrectionCollection();\n return corrections.listForContent(this.id as string);\n }\n\n public async listCorrections() {\n const corrections = await this.getCorrections();\n return corrections.map(serializeContentCorrection);\n }\n\n public async issueCorrection(options: IssueContentCorrectionOptions) {\n const governance = await this.requireGovernance('corrections');\n\n if (!this.id) {\n throw new Error('Cannot issue a correction for unsaved content');\n }\n\n let replacementFactId = '';\n if (\n governance.factLinkingEnabled &&\n options.factId &&\n options.correctedFactText\n ) {\n const facts = await this.getFactCollection();\n const existing = await facts.get({ id: options.factId });\n if (!existing) {\n throw new Error(`Fact not found for correction: ${options.factId}`);\n }\n\n // Create the correction branch directly so editorial corrections do not\n // block on synchronous embedding generation inside facts.branch().\n const replacement = await facts.create({\n textRefined: options.correctedFactText,\n textRaw: options.correctedFactText,\n type: existing.getType(),\n domain: existing.domain,\n status: 'active',\n tenantId: existing.tenantId ?? this.tenantId ?? null,\n previousFactId: options.factId,\n evolutionType: 'correction',\n });\n existing.status = 'superseded';\n await existing.save();\n replacementFactId = replacement.id as string;\n await this.addFact(replacementFactId);\n }\n\n const version =\n options.createVersion === false\n ? null\n : await this.createVersion({\n kind: 'correction',\n summary: options.summary,\n metadata: {\n factId: options.factId || null,\n replacementFactId: replacementFactId || null,\n },\n });\n const correctionDraft =\n options.createVersion === false\n ? null\n : await this.buildCorrectionDraftSnapshot(options, replacementFactId);\n const draftVersion =\n options.createVersion === false || !correctionDraft\n ? null\n : await this.createVersion({\n kind: 'draft',\n summary: `Auto-created correction draft: ${options.summary}`,\n snapshot: correctionDraft.snapshot,\n metadata: {\n ...correctionDraft.metadata,\n sourceCorrectionVersionId: (version?.id as string) || null,\n sourceCorrectionVersionNumber: version?.version ?? null,\n },\n });\n\n const corrections = await this.getContentCorrectionCollection();\n const shouldPublish = options.publish ?? this.status === 'published';\n return corrections.issue({\n contentId: this.id as string,\n contentVersionId: (version?.id as string) || '',\n factId: options.factId || '',\n replacementFactId,\n correctionType: options.correctionType || 'fact',\n status: shouldPublish ? 'published' : 'draft',\n summary: options.summary,\n incorrectText: options.incorrectText || '',\n correctedText: options.correctedText || options.correctedFactText || '',\n publicNote: options.publicNote || '',\n metadata: {\n ...(options.metadata || {}),\n autoGeneratedDraft: Boolean(draftVersion),\n draftVersionId: (draftVersion?.id as string) || null,\n draftVersionNumber: draftVersion?.version ?? null,\n sourceCorrectionVersionId: (version?.id as string) || null,\n sourceCorrectionVersionNumber: version?.version ?? null,\n correctionProfileKey: governance.correctionProfileKey || null,\n },\n tenantId: this.tenantId,\n publishedAt: shouldPublish ? new Date() : null,\n });\n }\n\n public async issueCorrectionAction(options: IssueContentCorrectionOptions) {\n const correction = await this.issueCorrection(options);\n return serializeContentCorrection(correction);\n }\n\n public async listVersions() {\n const versions = await this.getVersions();\n return versions.map(serializeContentVersion);\n }\n\n public async mutateVersionAction(\n options: CreateContentVersionOptions & {\n action?: string;\n versionNumber?: number | string;\n } = {},\n ) {\n if (options.action === 'restore') {\n const versionNumber = Number(options.versionNumber);\n if (!Number.isFinite(versionNumber)) {\n throw new Error('versionNumber is required to restore a version');\n }\n\n const restored = await this.restoreFromVersion(versionNumber);\n return serializeContent(restored);\n }\n\n const version = await this.createVersion(options);\n return serializeContentVersion(version);\n }\n\n /**\n * Note: toJSON() is inherited from SmrtObject\n *\n * The parent implementation handles:\n * - STI discriminator (_meta_type) for polymorphic queries\n * - Meta field extraction (_meta_data) for child-specific fields\n * - Automatic serialization of all fields from manifest\n *\n * DO NOT override toJSON() unless you call super.toJSON() first.\n * See issue #377 for details on why this override was removed.\n */\n\n // ============================================\n // Category Helper Methods\n // ============================================\n\n /**\n * Get category segments as array\n * @example 'politics/local' -> ['politics', 'local']\n */\n getCategorySegments(): string[] {\n if (!this.category) return [];\n return this.category.split('/').filter(Boolean);\n }\n\n /**\n * Get parent category path\n * @example 'politics/local/town' -> 'politics/local'\n * @example 'politics' -> null\n */\n getParentCategory(): string | null {\n const segments = this.getCategorySegments();\n if (segments.length <= 1) return null;\n return segments.slice(0, -1).join('/');\n }\n\n /**\n * Get root (top-level) category\n * @example 'politics/local/town' -> 'politics'\n */\n getRootCategory(): string | null {\n const segments = this.getCategorySegments();\n return segments[0] || null;\n }\n\n /**\n * Get all ancestor category paths (for breadcrumbs)\n * @example 'politics/local' -> ['politics', 'politics/local']\n */\n getAncestorPaths(): string[] {\n const segments = this.getCategorySegments();\n return segments.map((_, i) => segments.slice(0, i + 1).join('/'));\n }\n\n /**\n * Check if content belongs to a category (optionally including subcategories)\n * @param categoryPath - Category to check\n * @param includeChildren - If true, matches 'politics' for content in 'politics/local'\n */\n isInCategory(categoryPath: string, includeChildren = true): boolean {\n if (!this.category) return false;\n if (includeChildren) {\n return (\n this.category === categoryPath ||\n this.category.startsWith(`${categoryPath}/`)\n );\n }\n return this.category === categoryPath;\n }\n\n // ============================================\n // Asset Relationship Methods\n // ============================================\n\n /**\n * Get all assets associated with this content\n * @param relationship - Optional filter by relationship type (e.g., 'thumbnail', 'attachment')\n * @returns Promise resolving to array of assets\n */\n async getAssets(relationship?: string): Promise<Asset[]> {\n if (!this.id) {\n return [];\n }\n\n return this.resolveAssetsForLinks(\n await this.getContentAssetLinks(relationship),\n );\n }\n\n /**\n * Add an asset to this content with a relationship type\n * @param asset - The asset to associate\n * @param relationship - Relationship type (e.g., 'thumbnail', 'attachment', 'inline')\n * @param sortOrder - Optional sort order for display\n */\n async addAsset(\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n if (!this.id || !asset.id) {\n throw new Error('Cannot associate unsaved content or asset');\n }\n\n // Validate relationship - must start with letter/underscore, contain only alphanumeric and underscores\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(relationship)) {\n throw new Error(\n `Invalid relationship type \"${relationship}\"; must start with a letter or underscore and contain only letters, digits, and underscores`,\n );\n }\n\n // Validate sortOrder is a reasonable integer\n if (\n !Number.isInteger(sortOrder) ||\n sortOrder < 0 ||\n sortOrder > 2147483647\n ) {\n throw new Error(\n `Invalid sortOrder \"${sortOrder}\"; must be a non-negative integer`,\n );\n }\n\n const contentAssets = await this.getContentAssetCollection();\n await contentAssets.attach(this.id, asset.id, {\n relationship,\n sortOrder,\n tenantId: this.tenantId,\n });\n }\n\n /**\n * Remove an asset from this content\n * @param assetId - ID of the asset to remove\n * @param relationship - Optional specific relationship to remove (removes all if not specified)\n */\n async removeAsset(assetId: string, relationship?: string): Promise<void> {\n if (!this.id) {\n return;\n }\n\n try {\n const contentAssets = await this.getContentAssetCollection();\n await contentAssets.detach(\n this.id,\n assetId,\n relationship ? { relationship } : {},\n );\n } catch (error) {\n if (!isMissingTableError(error, 'content_assets')) {\n throw error;\n }\n }\n }\n\n // ============================================\n // Metadata Accessors (MetadataAccessor contract)\n // ============================================\n\n /**\n * Get the full metadata record. Always returns a plain object — never\n * `null`, never an array — so callers can safely read nested keys without\n * defensive checks.\n *\n * Pure read with no side-effect on `this.metadata`: if the field is\n * currently `null` (e.g. fresh from the DB) or non-record-shaped, an\n * empty object is returned but the field is **not** mutated. This avoids\n * accidentally marking the object dirty during a read, which would\n * otherwise cause SmrtObject's save lifecycle to write `{}` back over a\n * NULL column on the next save. Callers that want to normalise the\n * stored field should use {@link Content.setMetadata}.\n */\n getMetadata(): Record<string, unknown> {\n return isPlainMetadataRecord(this.metadata) ? this.metadata : {};\n }\n\n /**\n * Replace the full metadata record. Passing `null`/`undefined` (or any\n * non-record value such as an array) clears it to an empty object so\n * downstream readers can rely on the field always being a plain object.\n */\n setMetadata(metadata: Record<string, unknown> | null | undefined): void {\n this.metadata = isPlainMetadataRecord(metadata) ? { ...metadata } : {};\n }\n\n /**\n * Shallow-merge a patch over the current metadata. Returns the resulting\n * record so callers can chain reads without re-reading the field. Unlike\n * {@link Content.getMetadata}, this method does intentionally write back\n * to `this.metadata` because the merge is a write.\n */\n updateMetadata(\n patch: Partial<Record<string, unknown>>,\n ): Record<string, unknown> {\n const next = { ...this.getMetadata(), ...(patch ?? {}) };\n this.metadata = next;\n return next;\n }\n\n // ============================================\n // Thumbnail Convenience Methods\n // ============================================\n\n /**\n * Get the thumbnail image for this content\n * @returns Promise resolving to the thumbnail Image or null\n */\n async getThumbnail(): Promise<Image | null> {\n if (!this.thumbnailAssetId) {\n return null;\n }\n\n const images = await ImageCollection.create({\n db: this.options?.db,\n });\n\n return images.get({ id: this.thumbnailAssetId });\n }\n\n /**\n * Set the thumbnail image for this content\n * @param image - The image to set as thumbnail\n */\n async setThumbnail(image: Image): Promise<void> {\n // Add as asset with 'thumbnail' relationship\n await this.addAsset(image, 'thumbnail', 0);\n\n // Update thumbnailAssetId\n this.thumbnailAssetId = image.id ?? null;\n await this.save();\n }\n\n /**\n * Generate a thumbnail for this content using the specified strategy\n *\n * @param options - Thumbnail generation options including strategy\n * @returns Promise resolving to the generated Image\n *\n * @example Headline card thumbnail\n * ```typescript\n * const thumbnail = await content.generateThumbnail({\n * strategy: 'headline-card',\n * brandColor: '#1a56db',\n * logoUrl: 'https://example.com/logo.png'\n * });\n * ```\n *\n * @example Static map thumbnail (requires metadata.latitude/longitude)\n * ```typescript\n * const thumbnail = await content.generateThumbnail({\n * strategy: 'static-map',\n * mapProvider: 'mapbox'\n * });\n * ```\n *\n * @example AI-generated thumbnail\n * ```typescript\n * const thumbnail = await content.generateThumbnail({\n * strategy: 'ai-generate'\n * });\n * ```\n */\n async generateThumbnail(options: ThumbnailOptions): Promise<Image> {\n const generator = new ThumbnailGenerator(this, this.options);\n const image = await generator.generate(options);\n await this.setThumbnail(image);\n return image;\n }\n}\n","/**\n * Bounded, tenant-safe content data queries (#2452) over the canonical\n * transport-neutral query protocol (#2444).\n *\n * `ContentList` (and any other consumer) sends a `DataQueryRequest`; this\n * module normalizes it against a schema derived from the registered `Content`\n * field metadata, executes it through `SmrtCollection.list/count/facets` — never\n * raw SQL, never a full collection hydration — and returns a validated\n * `DataQueryResult`.\n *\n * Three independent boundaries protect a read:\n *\n * 1. **Schema** — `buildContentQuerySchema()` declares the only field ids a\n * caller may name. `sensitive`, `readPermission`-gated, transient,\n * non-column-backed, tenant, and internal (`_`-prefixed) fields are never\n * declared, so `normalizeDataQueryRequest()` rejects them outright.\n * 2. **Collection** — every projection, order term, and predicate still passes\n * through `SmrtCollection`, which independently refuses sensitive and\n * permission-gated fields. A schema bug alone cannot expose a field.\n * 3. **Scope** — trusted, server-derived conditions are ANDed into every branch\n * of the caller's filter, so a request can only ever narrow the read.\n */\n\nimport {\n createDataQueryFingerprint,\n DataQueryValidationError,\n normalizeDataQueryRequest,\n normalizeDataQueryResult,\n normalizeDataQuerySchema,\n ObjectRegistry,\n} from '@happyvertical/smrt-core';\nimport {\n getCurrentTenant,\n isSuperAdminBypass,\n isSystemContext,\n isTenancyEnabled,\n} from '@happyvertical/smrt-tenancy';\nimport type {\n DataQueryFacetResult,\n DataQueryFieldDescriptor,\n DataQueryFilter,\n DataQueryFilterOperator,\n DataQueryRequest,\n DataQueryResult,\n DataQueryRow,\n DataQuerySchema,\n DataQuerySort,\n} from '@happyvertical/smrt-types';\n\n/** Registered qualified name of the STI base every content query reads. */\nexport const CONTENT_QUERY_CLASS_NAME = '@happyvertical/smrt-content:Content';\n\n/** Row identity for every content query. Never a page or display index. */\nexport const CONTENT_QUERY_IDENTITY_FIELD = 'id';\n\n/**\n * Deterministic default ordering: most recently updated first, tie-broken by\n * id. `updated_at` is chosen over `publish_date` deliberately — it is always\n * populated, so ordering never depends on engine-specific NULL placement, and\n * it matches the ordering the rest of the `Contents` collection already uses.\n */\nexport const CONTENT_QUERY_DEFAULT_SORT: DataQuerySort[] = [\n { field: 'updated_at', direction: 'desc' },\n { field: CONTENT_QUERY_IDENTITY_FIELD, direction: 'asc' },\n];\n\n/** Page bounds. Content rows can carry long text, so the ceiling is modest. */\nexport const CONTENT_QUERY_DEFAULT_PAGE_LIMIT = 50;\nexport const CONTENT_QUERY_MAX_PAGE_LIMIT = 200;\nexport const CONTENT_QUERY_MAX_RESULT_BYTES = 1_000_000;\n\n/**\n * Fields the content query never declares even though they are column-backed.\n *\n * `body` is a document, not list data: the canonical envelope caps a scalar at\n * {@link DATA_QUERY_MAX_STRING_LENGTH} characters, so a real body could only\n * ever be returned mangled. Read a body through the item route\n * (`GET /api/v1/contents/{id}`), which serializes it in full.\n */\nexport const CONTENT_QUERY_EXCLUDED_FIELD_IDS: readonly string[] = ['body'];\n\n/**\n * The protocol's hard scalar cap (`dataQueryScalar` in\n * `@happyvertical/smrt-core`): a string value longer than this makes the whole\n * result invalid, so long values are truncated and flagged instead.\n */\nexport const DATA_QUERY_MAX_STRING_LENGTH = 4_096;\n\n/**\n * The protocol's limits for a `json` field, mirrored from\n * `canonicalJson` in `@happyvertical/smrt-core`. Exceeding any of them makes\n * the whole result invalid rather than the one value, so the adapter bounds a\n * JSON document itself (see `boundJsonValue`).\n */\nexport const DATA_QUERY_MAX_JSON_STRING_LENGTH = 65_536;\nexport const DATA_QUERY_MAX_JSON_CONTAINER_ITEMS = 1_000;\nexport const DATA_QUERY_MAX_JSON_DEPTH = 16;\n\n/**\n * Keys `plainObject` refuses outright (`FORBIDDEN_DATA_QUERY`), mirrored from\n * `@happyvertical/smrt-core`. This is a *validity* rule rather than a size\n * limit, and it is the reachable one: `metadata` is the documented extension\n * point, it is writable through the generated REST API and through\n * `Content.mirror()` ingestion, and `JSON.parse` of the stored column creates\n * an own `__proto__` property. One row carrying such a key would otherwise make\n * every query projecting that field return 400 for the whole page, with no way\n * to page past it.\n */\nexport const DATA_QUERY_FORBIDDEN_JSON_KEYS: ReadonlySet<string> = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n]);\n\n/**\n * Bytes held back from the row budget for the envelope itself (request id,\n * fingerprint, page, total, freshness, warnings). The normalizer re-checks the\n * complete serialized envelope against `maxResultBytes`, so the row budget must\n * leave room for it.\n */\nexport const RESULT_ENVELOPE_RESERVE_BYTES = 4_096;\n\n/**\n * Smallest row allowance a page can be given and still answer with anything.\n * Comfortably holds one identity-only row plus a few projected scalars.\n */\nconst MIN_RESULT_ROW_BYTES = 512;\n\n/**\n * The smallest `maxResultBytes` a schema may declare.\n *\n * The row budget is `maxResultBytes` minus the envelope reserve, so a schema\n * below the reserve leaves nothing for rows: every query would answer with an\n * empty page flagged `truncated`, forever, and a page small enough that the\n * metadata alone overruns the budget would fail `normalizeDataQueryResult`\n * outright. Both look like \"no content matched\" from the outside.\n *\n * `schema` is trusted adapter configuration, never caller input, so a budget\n * this small is a deployment mistake rather than a bad request — and it is\n * refused loudly at the boundary rather than degrading every read.\n */\nexport const CONTENT_QUERY_MIN_RESULT_BYTES =\n RESULT_ENVELOPE_RESERVE_BYTES + MIN_RESULT_ROW_BYTES;\n\n/**\n * Refuse a result budget too small to carry an envelope and a row.\n *\n * Throws a plain `Error`, not a `DataQueryValidationError`: a validation error\n * becomes a 400 and tells the caller they asked for something wrong, when the\n * fault is in the host's own schema. This mirrors how an unusable `scope` is\n * refused.\n *\n * Applied uniformly across query modes, including `count`, which returns no\n * rows and would technically work. A schema too small to serve its own row\n * mode is misconfigured whatever this particular request asked for, and letting\n * `count` succeed would hide that until the first rows query.\n */\nfunction assertUsableResultBudget(schema: DataQuerySchema): void {\n const budget = schema.maxResultBytes ?? CONTENT_QUERY_MAX_RESULT_BYTES;\n if (budget >= CONTENT_QUERY_MIN_RESULT_BYTES) return;\n throw new Error(\n `Content query schema maxResultBytes must be at least ${CONTENT_QUERY_MIN_RESULT_BYTES} ` +\n `(${RESULT_ENVELOPE_RESERVE_BYTES} reserved for the result envelope, ` +\n `${MIN_RESULT_ROW_BYTES} for rows); received ${budget}.`,\n );\n}\n\n/**\n * Upper bound on OR branches handed to the collection query builder.\n *\n * Exported so a client can mirror it: the null-safe `ne`/`notIn` lowering below\n * turns one predicate into two branches, and an `all` of them multiplies, so a\n * caller has to be able to stop short of the ceiling rather than be refused.\n */\nexport const MAX_CONTENT_QUERY_OR_BRANCHES = 128;\n\nconst encoder = new TextEncoder();\n\n/** One AND-ed group of SMRT `where` conditions. */\ntype WhereCondition = Record<string, unknown>;\n\n/** Bounded disjunctive-normal-form `where`: outer OR of inner AND groups. */\ntype WhereDnf = WhereCondition[][];\n\n/**\n * The subset of `SmrtCollection` a content query needs. Structural so this\n * module never imports `Contents` (which imports this one) and so a host can\n * supply an application-owned collection that preserves the same boundary.\n */\nexport interface ContentQueryCollection {\n list(options: {\n select?: readonly string[];\n where?: WhereCondition | WhereDnf;\n offset?: number;\n limit?: number;\n orderBy?: string | string[];\n }): Promise<Record<string, unknown>[]>;\n count(options?: { where?: WhereCondition | WhereDnf }): Promise<number>;\n facets(options: {\n fields: readonly { field: string; limit?: number }[];\n where?: WhereCondition | WhereDnf;\n }): Promise<{ field: string; values: { value: unknown; count: number }[] }[]>;\n}\n\n/**\n * Trusted, server-derived narrowing conditions.\n *\n * Each entry is a plain SMRT `where` condition object (`{ status: 'published' }`,\n * `{ 'publish_date <=': someInstant }`, `{ category: ['news', 'sport'] }`).\n * Every condition is ANDed into **every** OR branch of the caller's filter.\n */\nexport type ContentQueryScope = WhereCondition | readonly WhereCondition[];\n\nexport interface ContentQueryOptions {\n /**\n * Application-supplied narrowing conditions derived from the authenticated\n * server-side context — never from the request body.\n *\n * This is how an application expresses site, organization, workspace, or\n * ownership scoping. The framework deliberately does not model site or\n * organization: `Content` carries tenancy plus a freeform `metadata` blob and\n * nothing else, so the host that knows what \"site\" means for its deployment\n * passes the conditions that mean it here (a subclass column, a denormalized\n * id column, a pre-resolved id list, and so on).\n *\n * SECURITY INVARIANT: scope may only come from trusted server-side context. A\n * `DataQueryRequest` has no way to supply, replace, widen, or remove a scope\n * condition — scope conditions are ANDed into every branch of the caller's\n * filter, including inside `any`/`not` branches, so a request can only ever\n * narrow the result set. Never derive `scope` from client input.\n *\n * `undefined` and `[]` mean OPPOSITE things. Omit the option to apply no\n * application scope; pass an empty array to say the principal is permitted\n * nothing, which matches no rows. A host deriving the scope from an\n * allowed-resource list gets the safe answer by construction: an empty list\n * denies instead of unlocking the whole tenant.\n */\n scope?: ContentQueryScope;\n /**\n * Trusted adapter policy override. Defaults to the memoized `Content` schema.\n * This is adapter configuration, never caller input; it exists so a host (or\n * a test) can execute the same bounded protocol against another registered\n * class. Supplying a schema does NOT relax the collection-level field checks.\n */\n schema?: DataQuerySchema;\n}\n\n/**\n * Validate a host-supplied schema before anything depends on it.\n *\n * `executeContentQuery` performs the same checks on every request, so a\n * misconfigured schema can never actually serve a query — but a request-path\n * failure reaches the caller as an opaque 500 through the generated route, with\n * the message that names the minimum only in the server log. Call this once\n * where the schema is configured, so the failure lands next to the mistake:\n *\n * ```ts\n * const schema = buildAdminContentSchema();\n * assertContentQuerySchema(schema); // at startup, not on the first request\n * ```\n *\n * Covers core's own schema rules as well as this adapter's, so one call is\n * enough.\n */\nexport function assertContentQuerySchema(schema: DataQuerySchema): void {\n normalizeDataQuerySchema(schema);\n assertUsableResultBudget(schema);\n}\n\n/**\n * Resolve the fail-closed tenant read scope for a content query.\n *\n * Mirrors the generated route helpers `tenantReadScope()` /\n * `tenantReadOptionsScope()`: with tenancy enabled and no active tenant\n * context, reads are restricted to NULL-tenant (global) rows rather than\n * passing through unfiltered, because `Content` is\n * `@TenantScoped({ mode: 'optional' })` and the interceptor alone would not\n * filter an anonymous read. `withSystemContext()` and super-admin bypass remain\n * the explicit, deliberate cross-tenant paths.\n */\nexport function resolveContentTenantReadScope():\n | { tenantId: string | null }\n | undefined {\n if (!isTenancyEnabled()) return undefined;\n if (isSuperAdminBypass() || isSystemContext()) return undefined;\n return { tenantId: getCurrentTenant()?.tenantId ?? null };\n}\n\nfunction queryFail(message: string, code = 'INVALID_DATA_QUERY'): never {\n throw new DataQueryValidationError(message, code);\n}\n\nfunction isPlainRecord(value: unknown): value is WhereCondition {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction queryFieldType(\n type: unknown,\n): DataQueryFieldDescriptor['type'] | undefined {\n switch (type) {\n case 'text':\n case 'foreignKey':\n case 'crossPackageRef':\n return 'string';\n case 'integer':\n case 'decimal':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'datetime':\n return 'datetime';\n case 'json':\n return 'json';\n // `meta`, `oneToMany`, `manyToMany`, and anything a future scanner adds are\n // not column-backed scalars. Fail closed by leaving them undeclared.\n default:\n return undefined;\n }\n}\n\nfunction filterOperatorsFor(\n type: DataQueryFieldDescriptor['type'],\n): DataQueryFilterOperator[] | undefined {\n switch (type) {\n case 'string':\n return ['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'like'];\n case 'number':\n case 'datetime':\n return ['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn'];\n case 'boolean':\n return ['eq', 'ne', 'in', 'notIn'];\n // JSON columns store serialized documents; there is no portable predicate\n // for them at the collection boundary, so they stay unfilterable.\n case 'json':\n return undefined;\n }\n}\n\ninterface RegistryFieldLike {\n type?: unknown;\n sensitive?: unknown;\n readPermission?: unknown;\n transient?: unknown;\n _meta?: Record<string, unknown>;\n __tenancy?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nfunction meta(field: RegistryFieldLike): Record<string, unknown> {\n return isPlainRecord(field._meta) ? field._meta : {};\n}\n\n/** `sensitive`/`readPermission` may be declared top-level or under `_meta`. */\nfunction isRestrictedField(field: RegistryFieldLike): boolean {\n const fieldMeta = meta(field);\n return (\n field.sensitive === true ||\n fieldMeta.sensitive === true ||\n typeof field.readPermission === 'string' ||\n typeof fieldMeta.readPermission === 'string'\n );\n}\n\nfunction isTransientField(field: RegistryFieldLike): boolean {\n return field.transient === true || meta(field).transient === true;\n}\n\nfunction isTenantField(name: string, field: RegistryFieldLike): boolean {\n const fieldMeta = meta(field);\n const tenancy = isPlainRecord(field.__tenancy)\n ? field.__tenancy\n : isPlainRecord(fieldMeta.__tenancy)\n ? fieldMeta.__tenancy\n : undefined;\n return (\n tenancy?.isTenantIdField === true ||\n name === 'tenantId' ||\n name === 'tenant_id'\n );\n}\n\n/**\n * Build a `DataQuerySchema` from registered field metadata.\n *\n * Excluded, and therefore un-nameable by any caller:\n * - `sensitive` and `readPermission`-gated fields (exposure boundary);\n * - transient and non-column-backed fields (`meta`, `oneToMany`, `manyToMany`);\n * - the tenant field — tenancy is enforced by the executor, and a caller must\n * never be able to filter, sort, project, or facet on it;\n * - internal `_`-prefixed fields such as the STI discriminator.\n */\nasync function buildQuerySchemaForClass(\n qualifiedName: string,\n excluded: ReadonlySet<string>,\n): Promise<DataQuerySchema> {\n const registered = (await ObjectRegistry.getAllFields(qualifiedName)) as Map<\n string,\n RegistryFieldLike\n >;\n const fields: DataQueryFieldDescriptor[] = [];\n for (const [name, field] of registered) {\n if (name.startsWith('_')) continue;\n if (excluded.has(name)) continue;\n if (isRestrictedField(field)) continue;\n if (isTransientField(field)) continue;\n if (isTenantField(name, field)) continue;\n const type = queryFieldType(field.type);\n if (!type) continue;\n const filterOperators = filterOperatorsFor(type);\n fields.push({\n id: name,\n type,\n projectable: true,\n // JSON documents have no portable ordering at the SQL layer.\n sortable: type !== 'json',\n // Facets group by the stored column: only bounded scalar domains are\n // useful, and the identity field is unique by definition.\n facetable:\n name !== CONTENT_QUERY_IDENTITY_FIELD &&\n (type === 'string' || type === 'boolean' || type === 'number'),\n ...(filterOperators ? { filterOperators } : {}),\n });\n }\n\n const identity = fields.find(\n (field) => field.id === CONTENT_QUERY_IDENTITY_FIELD,\n );\n if (!identity) {\n throw new Error(\n `${qualifiedName} does not declare a queryable '${CONTENT_QUERY_IDENTITY_FIELD}' field`,\n );\n }\n\n const declared = new Set(fields.map((field) => field.id));\n const defaultSort = CONTENT_QUERY_DEFAULT_SORT.filter((term) =>\n declared.has(term.field),\n );\n\n return {\n version: 1,\n identityField: CONTENT_QUERY_IDENTITY_FIELD,\n fields,\n defaultPageLimit: CONTENT_QUERY_DEFAULT_PAGE_LIMIT,\n maxPageLimit: CONTENT_QUERY_MAX_PAGE_LIMIT,\n maxResultBytes: CONTENT_QUERY_MAX_RESULT_BYTES,\n ...(defaultSort.length > 0 ? { defaultSort } : {}),\n supports: {\n // Offset paging only: cursor paging would need an opaque, query-bound\n // cursor the collection read path does not issue today.\n cursorPagination: false,\n // Live table reads; no snapshot or as-of capability.\n consistency: false,\n facets: true,\n },\n };\n}\n\nconst schemaCache = new Map<string, Promise<DataQuerySchema>>();\n\n/**\n * Memoized query schema for one registered class (keyed by qualified name).\n * The schema is derived from immutable registration metadata, so it is built\n * once per process rather than per request.\n */\nexport function buildDataQuerySchemaForClass(\n qualifiedName: string,\n options: { exclude?: readonly string[] } = {},\n): Promise<DataQuerySchema> {\n const excluded = [...new Set(options.exclude ?? [])].sort();\n const key = `${qualifiedName}::${excluded.join(',')}`;\n const cached = schemaCache.get(key);\n if (cached) return cached;\n const pending = buildQuerySchemaForClass(\n qualifiedName,\n new Set(excluded),\n ).catch((cause) => {\n schemaCache.delete(key);\n throw cause;\n });\n schemaCache.set(key, pending);\n return pending;\n}\n\n/** Memoized bounded query schema for `Content`. */\nexport function buildContentQuerySchema(): Promise<DataQuerySchema> {\n return buildDataQuerySchemaForClass(CONTENT_QUERY_CLASS_NAME, {\n exclude: CONTENT_QUERY_EXCLUDED_FIELD_IDS,\n });\n}\n\n/** Testing seam: drop memoized schemas so a rebuild re-reads the registry. */\nexport function clearContentQuerySchemaCache(): void {\n schemaCache.clear();\n}\n\nfunction inverseOperator(\n operator: DataQueryFilterOperator,\n): DataQueryFilterOperator {\n switch (operator) {\n case 'eq':\n return 'ne';\n case 'ne':\n return 'eq';\n case 'gt':\n return 'lte';\n case 'gte':\n return 'lt';\n case 'lt':\n return 'gte';\n case 'lte':\n return 'gt';\n case 'in':\n return 'notIn';\n case 'notIn':\n return 'in';\n case 'like':\n return queryFail(\n 'Content queries cannot negate a like predicate',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n}\n\n/**\n * Lower one condition to bounded DNF.\n *\n * `negated` says the condition was reached through an odd number of `not`s and\n * its operator has already been inverted by {@link inverseOperator}. It matters\n * only for the ordered comparisons: `lte` asked for directly must exclude a\n * NULL row, exactly as SQL and the local evaluator both do, while the `lte`\n * that `not(gt)` produces must INCLUDE it or the predicate and its negation are\n * not complements and a row with no value falls through both.\n */\nfunction conditionToDnf(\n field: string,\n operator: DataQueryFilterOperator,\n value: unknown,\n negated = false,\n): WhereDnf {\n const key = (suffix: string) => (suffix ? `${field} ${suffix}` : field);\n const single = (whereKey: string, whereValue: unknown): WhereDnf => [\n [{ [whereKey]: whereValue }],\n ];\n\n if (operator === 'in') {\n const values = (value as unknown[]) ?? [];\n const nonNull = values.filter((entry) => entry !== null);\n if (nonNull.length === 0) return single(field, null);\n if (nonNull.length === values.length) return single(key('in'), nonNull);\n // SQL `IN` never matches NULL; model the caller-visible union explicitly.\n return [[{ [field]: null }], [{ [key('in')]: nonNull }]];\n }\n\n if (operator === 'notIn') {\n const values = (value as unknown[]) ?? [];\n if (values.length === 0) {\n // The normalizer refuses an empty list, so this is unreachable; failing\n // is still the only safe answer, because \"excludes nothing\" would have to\n // be an unbounded OR branch.\n return queryFail(\n 'Content query notIn requires at least one value',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n // `buildWhere()` has no NOT IN primitive. A bounded AND of inequalities has\n // the same null-safe semantics and stays fully validated by the collection.\n const inequalities = values\n .filter((entry) => entry !== null)\n .map((entry) => ({ [key('!=')]: entry }));\n if (values.some((entry) => entry === null)) {\n // A listed `null` says \"rows with no value are excluded too\", so the\n // null-safe union below must NOT be added — it would return exactly the\n // rows the caller asked to exclude, and would make `in [x, null]` and its\n // negation overlap. `{ field '!=': null }` is `IS NOT NULL`.\n return [[...inequalities, { [key('!=')]: null }]];\n }\n // No `null` was listed. SQL's `<>` is UNKNOWN for NULL, so a bare AND of\n // inequalities silently excludes rows with no value at all — while the\n // caller-visible meaning of \"not one of these\" includes them, and the local\n // evaluator agrees. Model that union explicitly, exactly as `in` does\n // above, so the same shared link returns the same rows whether the list is\n // server-backed or not.\n return [[{ [field]: null }], inequalities];\n }\n\n if (operator === 'ne' && value !== null) {\n // Same reasoning as `notIn`. A `ne null` is left alone: it is the\n // `isNotNull` predicate, and unioning IS NULL into it would match every row.\n return [[{ [field]: null }], [{ [key('!=')]: value }]];\n }\n\n const suffixes: Record<\n Exclude<DataQueryFilterOperator, 'in' | 'notIn'>,\n string\n > = {\n eq: '',\n ne: '!=',\n gt: '>',\n gte: '>=',\n lt: '<',\n lte: '<=',\n like: 'like',\n };\n\n if (\n negated &&\n (operator === 'gt' ||\n operator === 'gte' ||\n operator === 'lt' ||\n operator === 'lte')\n ) {\n // The complement of an ordered comparison. SQL's `>`/`<` are UNKNOWN for\n // NULL, so `not(gt v)` lowered as a bare `<= v` leaves a row with no value\n // matching NEITHER side — the same gap `ne`/`notIn` close above. `eq`\n // reached by negating `ne` gets no union: the complement of\n // \"IS NULL OR <> v\" is \"= v\", which excludes NULL by construction.\n return [[{ [field]: null }], [{ [key(suffixes[operator])]: value }]];\n }\n\n return single(key(suffixes[operator]), value);\n}\n\nfunction crossProduct(left: WhereDnf, right: WhereDnf): WhereDnf {\n if (left.length * right.length > MAX_CONTENT_QUERY_OR_BRANCHES) {\n return queryFail(\n `Content query filter expands beyond ${MAX_CONTENT_QUERY_OR_BRANCHES} OR branches`,\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n return left.flatMap((leftGroup) =>\n right.map((rightGroup) => [...leftGroup, ...rightGroup]),\n );\n}\n\nfunction filterToDnf(\n filter: DataQueryFilter,\n declared: ReadonlySet<string>,\n negate = false,\n): WhereDnf {\n if (filter.kind === 'condition') {\n // The normalizer already rejected undeclared fields; re-check so a schema\n // and an executor can never disagree about what is queryable.\n if (!declared.has(filter.field)) {\n return queryFail(\n `Content query filter field is not declared: ${filter.field}`,\n 'DATA_QUERY_FILTER_NOT_ALLOWED',\n );\n }\n return conditionToDnf(\n filter.field,\n negate ? inverseOperator(filter.operator) : filter.operator,\n filter.value,\n negate,\n );\n }\n\n if (filter.kind === 'not') {\n return filterToDnf(filter.filter, declared, !negate);\n }\n\n // De Morgan: a negated `any` behaves as an `all` of negated children.\n const combineWithAnd =\n (filter.kind === 'all' && !negate) || (filter.kind === 'any' && negate);\n if (combineWithAnd) {\n return filter.filters.reduce<WhereDnf>(\n (combined, child) =>\n crossProduct(combined, filterToDnf(child, declared, negate)),\n [[]],\n );\n }\n\n const branches = filter.filters.flatMap((child) =>\n filterToDnf(child, declared, negate),\n );\n if (branches.length > MAX_CONTENT_QUERY_OR_BRANCHES) {\n return queryFail(\n `Content query filter expands beyond ${MAX_CONTENT_QUERY_OR_BRANCHES} OR branches`,\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n return branches;\n}\n\nfunction normalizeScopeConditions(\n scope: ContentQueryScope | undefined,\n): WhereCondition[] {\n if (scope === undefined) return [];\n const candidates = Array.isArray(scope)\n ? (scope as readonly unknown[])\n : [scope];\n return candidates.map((candidate) => {\n if (!isPlainRecord(candidate) || Object.keys(candidate).length === 0) {\n throw new Error(\n 'Content query scope conditions must be non-empty plain objects',\n );\n }\n return { ...candidate };\n });\n}\n\n/**\n * A scope condition no row can satisfy.\n *\n * `id` is the primary key, so it is never NULL and `id IS NULL` is false for\n * every row on every dialect — the portable way to say \"permit nothing\" through\n * a `where` clause rather than by special-casing the read path.\n */\nconst DENY_ALL_SCOPE_CONDITION: WhereCondition = Object.freeze({\n [CONTENT_QUERY_IDENTITY_FIELD]: null,\n});\n\n/**\n * Normalize the APPLICATION scope, where an explicitly empty set denies.\n *\n * The two absences are not the same thing, and conflating them is an\n * authorization fail-open:\n *\n * - `undefined` means \"this deployment applies no application scope\" — read\n * the tenant, subject to tenancy alone.\n * - `[]` means \"the set of conditions this principal is permitted is EMPTY\".\n * A host builds a scope from an allowed-resource list — the sites,\n * workspaces, or organizations this principal may see — and that list is\n * empty exactly when the principal may see nothing. Treating it as \"no\n * scope\" turns *access to zero sites* into *access to every row in the\n * tenant*, which is the failure the two-layer scope design exists to\n * prevent.\n *\n * An empty set is a legitimate authorization state, not a programming error, so\n * it lowers to a predicate that matches nothing rather than throwing — a throw\n * would answer a correct \"you may see nothing\" with a 500.\n */\nfunction normalizeApplicationScope(\n scope: ContentQueryScope | undefined,\n): WhereCondition[] {\n if (scope === undefined) return [];\n const conditions = normalizeScopeConditions(scope);\n return conditions.length > 0 ? conditions : [{ ...DENY_ALL_SCOPE_CONDITION }];\n}\n\n/**\n * AND every trusted scope condition into every OR branch of the caller's\n * filter.\n *\n * This is the whole widening story: a branch can only ever gain conditions, and\n * conjunction is monotonically narrowing, so no filter shape — including\n * `any` (OR) and `not` (negation) — can produce a branch that escapes the base\n * scope. A caller predicate on a scoped field can contradict the scope (and\n * return nothing); it can never replace it.\n *\n * Returns `undefined` only when there is neither a scope nor a filter, so the\n * collection sees a plain unfiltered read rather than an empty DNF branch.\n *\n * An explicitly EMPTY scope denies rather than passing through; see\n * {@link normalizeApplicationScope}. Pass `undefined`, not `[]`, to mean \"no\n * application scope\".\n */\nexport function mergeContentQueryScope(\n scope: ContentQueryScope | undefined,\n callerWhere: WhereDnf | undefined,\n): WhereDnf | undefined {\n const scopeConditions = normalizeApplicationScope(scope);\n const branches: WhereDnf =\n callerWhere && callerWhere.length > 0 ? callerWhere : [[]];\n const merged = branches.map((branch) => [...scopeConditions, ...branch]);\n if (merged.length === 1 && merged[0].length === 0) return undefined;\n if (merged.some((branch) => branch.length === 0)) {\n // An empty OR branch matches every row, which would widen the read.\n return queryFail(\n 'Content query filter produced an unbounded OR branch',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n return merged;\n}\n\n/**\n * The result normalizer's warning rule: at most 100 entries, each a non-empty\n * string of at most 512 characters. A warning that names a field list derived\n * from a host-supplied schema could otherwise exceed it and fail the result\n * this warning exists to explain.\n */\nexport const DATA_QUERY_MAX_WARNINGS = 100;\nexport const DATA_QUERY_MAX_WARNING_LENGTH = 512;\n\n/** Appends a warning bounded to what `normalizeDataQueryResult` accepts. */\nfunction pushWarning(warnings: string[], message: string): void {\n if (warnings.length >= DATA_QUERY_MAX_WARNINGS) return;\n const text =\n message.length > DATA_QUERY_MAX_WARNING_LENGTH\n ? `${message.slice(0, DATA_QUERY_MAX_WARNING_LENGTH - 1)}\\u2026`\n : message;\n if (text.length > 0) warnings.push(text);\n}\n\n/** Records values the adapter had to shorten so the caller is told. */\nexport interface TruncationLog {\n fields: Set<string>;\n}\n\n/**\n * Cut an over-long string to the protocol's scalar cap without leaving a lone\n * surrogate behind.\n */\nfunction capString(\n value: string,\n limit = DATA_QUERY_MAX_STRING_LENGTH,\n): string {\n if (value.length <= limit) return value;\n const cut = value.slice(0, limit);\n const last = cut.charCodeAt(cut.length - 1);\n return last >= 0xd800 && last <= 0xdbff ? cut.slice(0, -1) : cut;\n}\n\n/**\n * Bound one JSON document the same way {@link capString} bounds a scalar.\n *\n * `normalizeDataQueryResult` validates a `json` field with `canonicalJson`,\n * which *rejects the whole result* — not just the offending value — when a\n * nested string exceeds {@link DATA_QUERY_MAX_JSON_STRING_LENGTH}, a container\n * exceeds {@link DATA_QUERY_MAX_JSON_CONTAINER_ITEMS}, nesting passes\n * {@link DATA_QUERY_MAX_JSON_DEPTH}, a number is non-finite, a value is not a\n * plain JSON type, or the document contains a cycle. One row with a large\n * `metadata` blob would therefore fail an otherwise valid page.\n *\n * Every one of those is bounded here instead, and the field is flagged so the\n * caller sees `truncated` plus a warning naming it.\n */\nfunction boundJsonValue(\n value: unknown,\n descriptor: DataQueryFieldDescriptor,\n truncation: TruncationLog | undefined,\n depth = 0,\n ancestors = new Set<object>(),\n): unknown {\n const flag = (): void => {\n truncation?.fields.add(descriptor.id);\n };\n if (value === null || value === undefined) return null;\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') {\n if (value.length > DATA_QUERY_MAX_JSON_STRING_LENGTH) {\n flag();\n return capString(value, DATA_QUERY_MAX_JSON_STRING_LENGTH);\n }\n return value;\n }\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n flag();\n return null;\n }\n return value;\n }\n if (typeof value === 'bigint') {\n const safe =\n value <= BigInt(Number.MAX_SAFE_INTEGER) &&\n value >= BigInt(Number.MIN_SAFE_INTEGER);\n if (!safe) {\n flag();\n return null;\n }\n return Number(value);\n }\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value.toISOString();\n }\n // Deeper than the validator accepts: keep the row, drop the sub-document.\n if (depth >= DATA_QUERY_MAX_JSON_DEPTH) {\n flag();\n return null;\n }\n if (Array.isArray(value)) {\n if (ancestors.has(value)) {\n flag();\n return null;\n }\n ancestors.add(value);\n try {\n let entries = value;\n if (entries.length > DATA_QUERY_MAX_JSON_CONTAINER_ITEMS) {\n flag();\n entries = entries.slice(0, DATA_QUERY_MAX_JSON_CONTAINER_ITEMS);\n }\n return entries.map((entry) =>\n boundJsonValue(entry, descriptor, truncation, depth + 1, ancestors),\n );\n } finally {\n ancestors.delete(value);\n }\n }\n if (!isPlainRecord(value)) {\n // A class instance, function, or symbol would fail `plainObject` outright.\n flag();\n return null;\n }\n if (ancestors.has(value)) {\n flag();\n return null;\n }\n ancestors.add(value);\n try {\n let keys = Object.keys(value);\n if (keys.length > DATA_QUERY_MAX_JSON_CONTAINER_ITEMS) {\n flag();\n keys = keys.slice(0, DATA_QUERY_MAX_JSON_CONTAINER_ITEMS);\n }\n // A null prototype, so writing a key named `__proto__` stores an own\n // property instead of invoking the inherited setter — which would silently\n // drop the key AND change this object's prototype, failing `plainObject`'s\n // prototype check on the way out. `Object.prototype` and `null` are the two\n // prototypes the validator accepts.\n const bounded = Object.create(null) as Record<string, unknown>;\n for (const key of keys) {\n if (key.length > DATA_QUERY_MAX_JSON_STRING_LENGTH) {\n flag();\n continue;\n }\n // `plainObject` REJECTS the whole result for one of these keys, and\n // `JSON.parse` of a stored `metadata` column creates an own `__proto__`\n // property, so a single row could otherwise brick every query that\n // projects the field. Dropping the key keeps the row readable.\n if (DATA_QUERY_FORBIDDEN_JSON_KEYS.has(key)) {\n flag();\n continue;\n }\n Object.defineProperty(bounded, key, {\n value: boundJsonValue(\n value[key],\n descriptor,\n truncation,\n depth + 1,\n ancestors,\n ),\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n return bounded;\n } finally {\n ancestors.delete(value);\n }\n}\n\nfunction toDeclaredValue(\n value: unknown,\n descriptor: DataQueryFieldDescriptor,\n truncation?: TruncationLog,\n): unknown {\n if (value === undefined) return null;\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value.toISOString();\n }\n // A json field is validated as a document, not a scalar: it has its own,\n // larger limits, and the scalar cap would corrupt a serialized payload.\n if (descriptor.type === 'json') {\n return boundJsonValue(value, descriptor, truncation);\n }\n if (\n typeof value === 'string' &&\n value.length > DATA_QUERY_MAX_STRING_LENGTH\n ) {\n // The envelope rejects any scalar longer than the cap, which would turn one\n // long row into a failed query. Shorten it and say so instead.\n truncation?.fields.add(descriptor.id);\n return capString(value);\n }\n if (typeof value === 'bigint') {\n if (\n value > BigInt(Number.MAX_SAFE_INTEGER) ||\n value < BigInt(Number.MIN_SAFE_INTEGER)\n ) {\n return queryFail(\n `Content query value for ${descriptor.id} exceeds the safe integer range`,\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n return Number(value);\n }\n if (descriptor.type === 'boolean' && typeof value === 'number') {\n // SQLite/DuckDB surface booleans as 0/1.\n return value !== 0;\n }\n return value;\n}\n\nfunction jsonByteLength(value: unknown): number {\n return encoder.encode(JSON.stringify(value) ?? 'null').byteLength;\n}\n\nexport interface BoundedRows {\n rows: DataQueryRow[];\n truncated: boolean;\n}\n\n/** Cut a string to a BYTE budget without splitting a code point. */\nfunction capStringBytes(value: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n const totalBytes = encoder.encode(value).byteLength;\n if (totalBytes <= maxBytes) return value;\n // Fast path: an all-ASCII value has one byte per code unit, so the cut is a\n // slice. Encoding character by character allocates a typed array PER\n // CHARACTER, which dominates the whole bounding pass on a large page.\n if (totalBytes === value.length) return value.slice(0, maxBytes);\n let used = 0;\n let end = 0;\n for (const character of value) {\n const point = character.codePointAt(0) ?? 0;\n const cost = point < 0x80 ? 1 : point < 0x800 ? 2 : point < 0x10000 ? 3 : 4;\n if (used + cost > maxBytes) break;\n used += cost;\n end += character.length;\n }\n return value.slice(0, end);\n}\n\n/**\n * How a field's value may give way when a row has to get smaller.\n *\n * The distinction that matters is FORMAT. A `string` is free text, so a prefix\n * of it is still a valid string. A `datetime` is an RFC 3339 instant and NO\n * prefix of one is valid — truncating it makes the adapter emit a value that\n * violates the field type it declared, and the result normalizer then rejects\n * the whole page with `must be an RFC 3339 instant`, blaming the caller for a\n * shape the adapter produced. `json` is a document with no incremental\n * shortening. Both of those are all-or-nothing.\n *\n * Numbers and booleans are already minimal, and the identity field is the row's\n * address, so neither is reducible at all.\n */\ntype FieldReduction = 'truncate' | 'null' | 'none';\n\nfunction reductionFor(\n field: string,\n value: unknown,\n identityField: string,\n descriptors: Map<string, DataQueryFieldDescriptor>,\n): FieldReduction {\n if (field === identityField || value === null) return 'none';\n const type = descriptors.get(field)?.type;\n if (type === 'json') return 'null';\n // Format-constrained: reduce to null or not at all, never to a prefix.\n if (type === 'datetime') return 'null';\n if (typeof value === 'string' && value.length > 0) return 'truncate';\n return 'none';\n}\n\n/** The JSON byte cost of a value once it has given way completely. */\nconst REDUCED_VALUE_BYTES: Record<FieldReduction, number> = {\n truncate: 2, // `\"\"`\n null: 4, // `null`\n none: 0, // replaced by the value's own size\n};\n\ninterface MeasuredField {\n field: string;\n /** `\"key\":` — fixed for the life of the row. */\n keyBytes: number;\n /** Current JSON byte cost of the value. */\n valueBytes: number;\n reduction: FieldReduction;\n /** Value bytes once fully reduced. */\n floorBytes: number;\n}\n\ninterface MeasuredRow {\n fields: MeasuredField[];\n /** Braces, commas, and the array separator — independent of the values. */\n structural: number;\n /** Current serialized cost, equal to `jsonByteLength(row) + 1`. */\n cost: number;\n /** The smallest this row can ever be: every reducible value given way. */\n floor: number;\n}\n\n/**\n * Measure a row ONCE, so every later decision is arithmetic.\n *\n * The previous shrink re-serialized the whole row on every iteration AND every\n * field on every iteration, turning an ordinary page — 200 rows of a wide\n * projection at the default 1 MB budget — into seconds of blocked event loop.\n * The serialized size of an object is exactly its structural bytes plus, per\n * field, the key, a colon, and the value; so it can be recomputed from a single\n * measurement as values change, with no further stringification.\n */\nfunction measureRow(\n row: DataQueryRow,\n descriptors: Map<string, DataQueryFieldDescriptor>,\n identityField: string,\n): MeasuredRow {\n const entries = Object.entries(row);\n const fields = entries.map(([field, value]) => {\n const declared = reductionFor(field, value, identityField, descriptors);\n const valueBytes = jsonByteLength(value);\n // A reduction that would not SHRINK the field is not a reduction. `{}` and\n // `[]` serialize to two bytes, so nulling them costs four and makes the row\n // bigger; taking the reduced size as the floor unconditionally also\n // overstates the floor, which refuses pages that would have fitted.\n const reduction: FieldReduction =\n declared === 'none' || REDUCED_VALUE_BYTES[declared] < valueBytes\n ? declared\n : 'none';\n return {\n field,\n keyBytes: jsonByteLength(field),\n valueBytes,\n reduction,\n floorBytes:\n reduction === 'none' ? valueBytes : REDUCED_VALUE_BYTES[reduction],\n };\n });\n // `{`, `}`, one comma between fields, and the separator this row costs inside\n // the rows array.\n const structural = entries.length === 0 ? 3 : entries.length + 2;\n const overhead = fields.reduce(\n (sum, entry) => sum + entry.keyBytes + 1,\n structural,\n );\n return {\n fields,\n structural,\n cost: fields.reduce((sum, entry) => sum + entry.valueBytes, overhead),\n floor: fields.reduce((sum, entry) => sum + entry.floorBytes, overhead),\n };\n}\n\n/**\n * The largest per-value byte cap that keeps a set of truncatable sizes within\n * `available`, or `undefined` when even the floor does not fit.\n *\n * Classic max-min water-filling: sizes at or below the cap keep their real\n * cost, and everything above it is levelled to the cap. Solved by walking the\n * sorted sizes once rather than by repeated halving and re-measurement.\n */\nfunction waterFillCap(\n sizes: readonly number[],\n available: number,\n floorBytes: number,\n): number | undefined {\n if (sizes.length === 0)\n return available >= 0 ? Number.MAX_SAFE_INTEGER : undefined;\n if (available < sizes.length * floorBytes) return undefined;\n const sorted = [...sizes].sort((left, right) => left - right);\n let prefix = 0;\n for (let index = 0; index < sorted.length; index += 1) {\n const remaining = sorted.length - index;\n // Everything from `index` on levelled to `sorted[index]`.\n if (prefix + remaining * sorted[index] > available) {\n return Math.max(floorBytes, Math.floor((available - prefix) / remaining));\n }\n prefix += sorted[index];\n }\n return Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Shrink ONE row so its serialized form fits `allowance` bytes.\n *\n * HOW a field gives way depends on its declared type (see {@link reductionFor}):\n * a string is levelled to a shared cap, while a `json` document or a `datetime`\n * is all-or-nothing, dropped to `null`, because no prefix of either is valid.\n *\n * **Strings give way FIRST.** An all-or-nothing field loses its whole value to\n * save its bytes, so it is dropped only when the row cannot fit with it kept —\n * that is, only while it is larger than the cap the strings could otherwise\n * level down to. At a 50 KB allowance a 30 KB `metadata` blob beside a 100 KB\n * `title` therefore SURVIVES: levelling the title alone is enough. The same\n * blob beside a 20-character title does not, because no amount of levelling\n * gets there. Reaching for the largest field first would instead empty the blob\n * whenever it happened to be the biggest, discarding a whole document to save\n * bytes the strings had to spare.\n *\n * Returns `undefined` only when the row's floor exceeds the allowance. Callers\n * allocate at least each row's floor, so in practice this never fires.\n */\nfunction shrinkRowToBytes(\n row: DataQueryRow,\n allowance: number,\n measured: MeasuredRow,\n truncation: TruncationLog,\n): DataQueryRow | undefined {\n if (measured.floor > allowance) return undefined;\n const nulled = new Set<string>();\n let cap: number | undefined;\n\n // Give way on the all-or-nothing fields only while one of them is a bigger\n // contributor than any string would be after levelling.\n for (;;) {\n const kept = measured.fields.filter(\n (entry) => entry.reduction !== 'truncate' && !nulled.has(entry.field),\n );\n const truncatable = measured.fields.filter(\n (entry) => entry.reduction === 'truncate',\n );\n const fixed = kept.reduce((sum, entry) => sum + entry.valueBytes, 0);\n const nulledBytes = REDUCED_VALUE_BYTES.null * nulled.size;\n const overhead = measured.fields.reduce(\n (sum, entry) => sum + entry.keyBytes + 1,\n measured.structural,\n );\n const available = allowance - overhead - fixed - nulledBytes;\n cap = waterFillCap(\n truncatable.map((entry) => entry.valueBytes),\n available,\n REDUCED_VALUE_BYTES.truncate,\n );\n // An all-or-nothing field gives way only when the row cannot fit with it\n // KEPT. Dropping one loses a whole value to save a few bytes, so it is a\n // last resort rather than a race with the strings: a 200 KB `metadata`\n // blob makes the row infeasible and goes immediately, while a 26-byte\n // `updated_at` survives whenever the strings can absorb the difference.\n if (cap !== undefined) break;\n const biggestNullable = measured.fields\n .filter((entry) => entry.reduction === 'null' && !nulled.has(entry.field))\n .sort((left, right) => right.valueBytes - left.valueBytes)[0];\n if (biggestNullable === undefined) return undefined;\n nulled.add(biggestNullable.field);\n }\n if (cap === undefined) return undefined;\n\n const shrunk: DataQueryRow = { ...row };\n for (const entry of measured.fields) {\n if (nulled.has(entry.field)) {\n shrunk[entry.field] = null;\n truncation.fields.add(entry.field);\n continue;\n }\n if (entry.reduction !== 'truncate' || entry.valueBytes <= cap) continue;\n const original = shrunk[entry.field] as string;\n // The cap is a budget for the SERIALIZED value, so the content budget is\n // two bytes smaller; JSON escaping can inflate the rest, so the value is\n // measured once and trimmed again on the rare occasion it overshoots.\n let content = capStringBytes(original, cap - 2);\n let guard = 0;\n while (jsonByteLength(content) > cap && content.length > 0 && guard < 8) {\n guard += 1;\n const overshoot = jsonByteLength(content) - cap;\n content = capStringBytes(\n content,\n Math.max(0, encoder.encode(content).byteLength - overshoot),\n );\n }\n shrunk[entry.field] = content;\n truncation.fields.add(entry.field);\n }\n return shrunk;\n}\n\n/**\n * Share a byte budget across rows: every row keeps its irreducible floor, and\n * the surplus is divided max-min fair over what each row could still use.\n *\n * Allocating max-min fair over the rows' CURRENT costs — without seating the\n * floors first — can declare a feasible page impossible. A small row is handed\n * its whole cost while a large, mostly-irreducible row is left below its own\n * floor, so the request fails even though the floors fit the budget with room\n * to spare. Seating the floors first makes the guarantee unconditional: if\n * `sum(floors) <= budget` then every row is allocated at least its floor,\n * whatever the shape of the page.\n *\n * Exported because that guarantee is a property of the ARITHMETIC, not of any\n * page the content schema can actually produce — a row's floor is dominated by\n * the projection's key bytes, which are identical across rows, so the disparity\n * that breaks cost-first ordering is not reachable through `executeContentQuery`.\n * The property is real and worth holding; this is the level it can be held at.\n *\n * PRECONDITION: `floors[i] <= costs[i]` for every row — a floor is a size the\n * row can actually be reduced TO, so it can never exceed the size it already\n * is. {@link measureRow} guarantees this by declining any reduction that would\n * not shrink the field. The appetite below is clamped at zero so that a\n * violation still yields at least the floor rather than silently starving a row.\n *\n * @param floors - Per-row irreducible byte cost; at most the row's cost.\n * @param costs - Per-row current byte cost; always at least the floor.\n * @param budget - Bytes available for the rows themselves.\n * @returns Per-row byte allowance, each at least the row's floor.\n */\nexport function allocateRowBytes(\n floors: readonly number[],\n costs: readonly number[],\n budget: number,\n): number[] {\n const allowances = [...floors];\n const seated = floors.reduce((sum, floor) => sum + floor, 0);\n if (seated > budget) return allowances;\n // What each row could still use ON TOP of its floor. Ordering by appetite\n // rather than by cost is what keeps a row that needs nothing from consuming\n // another row's floor.\n const appetites = costs.map((cost, index) =>\n Math.max(0, cost - floors[index]),\n );\n const order = floors\n .map((_, index) => index)\n .sort((left, right) => appetites[left] - appetites[right]);\n let surplus = budget - seated;\n let left = floors.length;\n for (const index of order) {\n const granted = Math.min(appetites[index], Math.floor(surplus / left));\n allowances[index] += granted;\n surplus -= granted;\n left -= 1;\n }\n return allowances;\n}\n\n/**\n * Keep the returned rows inside the schema byte budget WITHOUT dropping any.\n *\n * The normalizer rejects an oversized result rather than trimming it, and one\n * content row can carry megabytes of `metadata`, so the adapter has to bound\n * the payload itself. It used to do that by dropping trailing rows — which is\n * silent, permanent data loss: offset paging advances by the requested LIMIT,\n * not by the number of rows actually returned, so the next page starts past the\n * dropped rows and they are skipped on every page, forever. `DataQueryResult`'s\n * offset page is `{ kind, offset, limit, hasMore }` with no next-offset slot,\n * and the normalizer refuses a `nextCursor` on an offset page, so a\n * continuation offset cannot be expressed to say \"resume at 170\" either.\n *\n * So a row is never dropped for size — only shortened, which is a state the\n * result already reports through `truncated` and its warning, and which leaves\n * offset paging exact.\n *\n * Allocation is floor-first, then max-min fair. Every row is given its\n * irreducible floor before any surplus is shared, so a page whose floors fit is\n * always produced — ordering rows by their CURRENT cost could otherwise hand a\n * small row more than it needed and starve a large one below its floor,\n * declaring a feasible page impossible.\n *\n * Throws only when the floors themselves exceed the budget, which is the one\n * case no amount of shortening can reach. Failing loudly beats answering with a\n * page that silently omits rows.\n */\nexport function boundRowBytes(\n rows: DataQueryRow[],\n maxResultBytes: number,\n descriptors: Map<string, DataQueryFieldDescriptor>,\n identityField: string,\n truncation: TruncationLog,\n): BoundedRows {\n const budget = Math.max(\n 0,\n (maxResultBytes || CONTENT_QUERY_MAX_RESULT_BYTES) -\n RESULT_ENVELOPE_RESERVE_BYTES,\n );\n // `[` and `]`. Each row's `structural` charges the separator that FOLLOWS it,\n // but N rows need N-1, so a non-empty page has one separator too many; refund\n // it here rather than special-casing the last row. Without the refund a page\n // whose true size exactly equals the budget is needlessly shortened — or, if\n // it is irreducible, refused.\n const framing = rows.length > 0 ? 1 : 2;\n const measured = rows.map((row) =>\n measureRow(row, descriptors, identityField),\n );\n const total = measured.reduce((sum, row) => sum + row.cost, framing);\n if (total <= budget) return { rows, truncated: false };\n\n const floors = measured.reduce((sum, row) => sum + row.floor, framing);\n if (floors > budget) {\n return queryFail(\n 'Content query cannot fit its rows inside the maximum result bytes; request fewer fields or a smaller page.',\n 'DATA_QUERY_RESULT_TOO_LARGE',\n );\n }\n\n const allowances = allocateRowBytes(\n measured.map((row) => row.floor),\n measured.map((row) => row.cost),\n budget - framing,\n );\n\n const bounded = rows.map((row, index) => {\n if (measured[index].cost <= allowances[index]) return row;\n const shrunk = shrinkRowToBytes(\n row,\n allowances[index],\n measured[index],\n truncation,\n );\n if (shrunk === undefined) {\n return queryFail(\n 'Content query cannot fit a row inside its maximum result bytes; request fewer fields or a smaller page.',\n 'DATA_QUERY_RESULT_TOO_LARGE',\n );\n }\n return shrunk;\n });\n return { rows: bounded, truncated: true };\n}\n\nfunction orderByTerms(sort: DataQuerySort[] | undefined): string[] | undefined {\n if (!sort || sort.length === 0) return undefined;\n return sort.map((term) => `${term.field} ${term.direction.toUpperCase()}`);\n}\n\n/**\n * Execute one bounded content query.\n *\n * Every read goes through `SmrtCollection.list({ select, where, orderBy,\n * offset, limit })`, `count()`, and `facets()` — the collection remains the\n * authorization, tenancy-interception, and SQL boundary. The full collection is\n * never hydrated to filter or page in memory.\n *\n * Tenancy is applied by this function itself (see\n * {@link resolveContentTenantReadScope}) in addition to any application\n * `scope`; a caller cannot opt out of it.\n *\n * @param collection Content collection to read through.\n * @param rawRequest Untrusted `DataQueryRequest` (typically an HTTP body).\n * @param options Trusted adapter configuration — never derived from the caller.\n */\nexport async function executeContentQuery(\n collection: ContentQueryCollection,\n rawRequest: unknown,\n options: ContentQueryOptions = {},\n): Promise<DataQueryResult> {\n const schema = options.schema ?? (await buildContentQuerySchema());\n // Configuration first: a budget too small to hold an envelope plus a row\n // would otherwise answer every query with an empty page rather than fail.\n assertUsableResultBudget(schema);\n const request: DataQueryRequest = normalizeDataQueryRequest(\n rawRequest,\n schema,\n );\n const queryFingerprint = createDataQueryFingerprint(request, schema);\n const descriptors = new Map(schema.fields.map((field) => [field.id, field]));\n const declared = new Set(descriptors.keys());\n\n const callerWhere = request.filter\n ? filterToDnf(request.filter, declared)\n : undefined;\n // Tenancy first, then the application scope: both are trusted, both narrow.\n // An empty application scope contributes its deny-all condition here, so it\n // survives the merge alongside tenancy rather than being mistaken for\n // \"unscoped\" — an empty app scope plus a tenant scope must still deny.\n const scopeConditions = [\n ...normalizeScopeConditions(resolveContentTenantReadScope()),\n ...normalizeApplicationScope(options.scope),\n ];\n // `undefined`, never `[]`: the aggregate is empty only when there genuinely\n // is no scope, and `[]` now means the opposite.\n const where = mergeContentQueryScope(\n scopeConditions.length > 0 ? scopeConditions : undefined,\n callerWhere,\n );\n const countOptions = where === undefined ? undefined : { where };\n\n const warnings: string[] = [];\n let truncated = false;\n let facets: DataQueryFacetResult[] | undefined;\n\n if (request.mode === 'rows') {\n const projection = request.projection ?? [schema.identityField];\n const offset = request.page?.kind === 'offset' ? request.page.offset : 0;\n const limit =\n request.page?.limit ??\n schema.defaultPageLimit ??\n CONTENT_QUERY_DEFAULT_PAGE_LIMIT;\n const orderBy = orderByTerms(request.sort);\n const listed = await collection.list({\n select: projection,\n offset,\n limit,\n ...(orderBy\n ? { orderBy: orderBy.length === 1 ? orderBy[0] : orderBy }\n : {}),\n ...(where === undefined ? {} : { where }),\n });\n const truncation: TruncationLog = { fields: new Set() };\n const mapped = listed.map((row) => {\n const out: DataQueryRow = {};\n for (const field of projection) {\n const descriptor = descriptors.get(field);\n if (!descriptor) {\n return queryFail(\n `Content query returned an undeclared field: ${field}`,\n 'DATA_QUERY_RESULT_NOT_ALLOWED',\n );\n }\n out[field] = toDeclaredValue(row[field], descriptor, truncation);\n }\n return out;\n });\n const bounded = boundRowBytes(\n mapped,\n schema.maxResultBytes ?? CONTENT_QUERY_MAX_RESULT_BYTES,\n descriptors,\n schema.identityField,\n truncation,\n );\n const rows: DataQueryRow[] = bounded.rows;\n truncated = bounded.truncated || truncation.fields.size > 0;\n if (bounded.truncated) {\n pushWarning(\n warnings,\n 'Content query shortened values to fit its maximum result bytes; request fewer fields or a smaller page.',\n );\n }\n if (truncation.fields.size > 0) {\n pushWarning(\n warnings,\n `Content query shortened over-long values in: ${[...truncation.fields].sort().join(', ')}.`,\n );\n }\n const total = await collection.count(countOptions);\n const page: DataQueryResult['page'] = {\n kind: 'offset',\n offset,\n limit,\n // No row is ever dropped for size any more, so the page is exactly the\n // rows the offset asked for and `hasMore` is a plain positional fact.\n hasMore: offset + rows.length < total,\n };\n return normalizeDataQueryResult(\n {\n version: 1 as const,\n requestId: request.requestId,\n queryFingerprint,\n identityField: schema.identityField,\n rows,\n page,\n total: { kind: 'exact' as const, value: total },\n freshness: { state: 'fresh' as const, asOf: new Date().toISOString() },\n warnings,\n truncated,\n },\n request,\n schema,\n );\n }\n\n const total = await collection.count(countOptions);\n\n if (request.mode === 'facets') {\n const requested = request.facets ?? [];\n const sourceFacets = await collection.facets({\n fields: requested.map((facet) => ({\n field: facet.field,\n limit: facet.limit,\n })),\n ...(where === undefined ? {} : { where }),\n });\n const byField = new Map(sourceFacets.map((facet) => [facet.field, facet]));\n const facetTruncation: TruncationLog = { fields: new Set() };\n // Facet values go through the SAME shared byte budget the rows do: two text\n // facets of 200 distinct 4096-character values are inside every per-value\n // cap and still over the 1 MB result limit, which would make the normalizer\n // reject an otherwise valid response.\n let facetBudget = Math.max(\n 0,\n (schema.maxResultBytes ?? CONTENT_QUERY_MAX_RESULT_BYTES) -\n RESULT_ENVELOPE_RESERVE_BYTES,\n );\n let facetBudgetExhausted = false;\n facets = requested.map((facet) => {\n const descriptor = descriptors.get(facet.field);\n if (!descriptor) {\n return queryFail(\n `Content query returned an undeclared facet: ${facet.field}`,\n 'DATA_QUERY_RESULT_NOT_ALLOWED',\n );\n }\n const values = byField.get(facet.field)?.values ?? [];\n // The envelope around one facet: field name, brackets, and flags.\n facetBudget -= jsonByteLength(facet.field) + 48;\n const kept: Array<{\n value: string | number | boolean | null;\n count: number;\n }> = [];\n let boundedOut = false;\n for (const entry of values.slice(0, facet.limit)) {\n const value = toDeclaredValue(\n entry.value,\n descriptor,\n facetTruncation,\n ) as string | number | boolean | null;\n const cost = jsonByteLength({ value, count: entry.count }) + 1;\n if (cost > facetBudget) {\n boundedOut = true;\n facetBudgetExhausted = true;\n break;\n }\n facetBudget -= cost;\n kept.push({ value, count: entry.count });\n }\n return {\n field: facet.field,\n values: kept,\n // The collection bounds this grouping query in the database; an exactly\n // full page may have more values, so report conservatively.\n truncated: boundedOut || values.length >= facet.limit,\n };\n });\n if (facetTruncation.fields.size > 0) {\n pushWarning(\n warnings,\n `Content query shortened over-long values in: ${[...facetTruncation.fields].sort().join(', ')}.`,\n );\n }\n if (facetBudgetExhausted) {\n pushWarning(\n warnings,\n 'Content query facets were truncated to fit their maximum result bytes; request fewer facets or a smaller facet limit.',\n );\n }\n truncated =\n facets.some((facet) => facet.truncated) ||\n facetTruncation.fields.size > 0;\n }\n\n return normalizeDataQueryResult(\n {\n version: 1 as const,\n requestId: request.requestId,\n queryFingerprint,\n identityField: schema.identityField,\n rows: [],\n total: { kind: 'exact' as const, value: total },\n ...(facets === undefined ? {} : { facets }),\n freshness: { state: 'fresh' as const, asOf: new Date().toISOString() },\n warnings,\n truncated,\n },\n request,\n schema,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"content-query-BBUbitoV.js","names":["left","total"],"sources":["../../src/__smrt-register__.ts","../../src/asset-associable.ts","../../src/content-asset.ts","../../src/content-assets.ts","../../src/content-governance.ts","../../src/content-prompts.ts","../../src/content-reference.ts","../../src/content-references.ts","../../src/content-transparency.ts","../../src/database-utils.ts","../../src/serialization.ts","../../src/thumbnail-generator.ts","../../src/content.ts","../../src/content-query.ts"],"sourcesContent":["/**\n * Self-registers this package's build-time manifest before any @smrt() decorator\n * in the package fires. Fixes issue #1132: in consumer runtimes (tsx, SvelteKit\n * SSR, plain `vite dev`) the decorator's synchronous manifest lookup previously\n * missed because no step populated the global manifest cache — classes got\n * registered with zero fields and `save()` / `toJSON()` silently dropped every\n * declared property.\n *\n * Import this module as the first statement in `src/index.ts` so its top-level\n * side effect runs ahead of any class module's @smrt() decorator.\n *\n * Silent no-op in dev/test, where the vitest plugin already populates manifests\n * via a different path. Only needs to succeed in the published dist output.\n *\n * @see https://github.com/happyvertical/smrt/issues/1132\n */\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n// During library builds, smrtPlugin replaces this entire module with generated\n// code that embeds the scanned manifest inline (#1506/#1507) — published dists\n// never resolve this URL, so downstream bundlers cannot break registration by\n// relocating the compiled module away from dist/manifest.json. The runtime\n// lookup below is the fallback for source-mode runs without that transform.\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","import type { Asset } from '@happyvertical/smrt-assets';\n\n/**\n * Contract for objects that participate in the content/asset association\n * pattern.\n *\n * Any class that exposes asset-relationship methods (e.g. `Content` and its\n * STI subclasses) implements this interface explicitly so consumers can rely\n * on the methods existing instead of falling back to `typeof === 'function'`\n * duck-typing checks.\n *\n * @example\n * ```ts\n * import type { AssetAssociable } from '@happyvertical/smrt-content';\n *\n * async function attachThumbnail(\n * target: AssetAssociable,\n * image: Asset,\n * ): Promise<void> {\n * // No defensive runtime checks needed — the contract guarantees the method.\n * await target.addAsset(image, 'thumbnail', 0);\n * }\n * ```\n */\nexport interface AssetAssociable {\n /**\n * Get all assets associated with this object.\n *\n * @param relationship - Optional filter by relationship type\n * (e.g. `'thumbnail'`, `'attachment'`).\n * @returns Array of associated assets. Returns an empty array if the object\n * has not been persisted yet.\n */\n getAssets(relationship?: string): Promise<Asset[]>;\n\n /**\n * Associate an asset with this object via a typed relationship.\n *\n * @param asset - The asset to associate. Must be persisted (have an `id`).\n * @param relationship - Relationship type. Must match\n * `/^[a-zA-Z_][a-zA-Z0-9_]*$/`. Defaults to `'attachment'`.\n * @param sortOrder - Non-negative integer for display order.\n * @throws if either side is unsaved or the relationship/sort order is invalid.\n */\n addAsset(\n asset: Asset,\n relationship?: string,\n sortOrder?: number,\n ): Promise<void>;\n\n /**\n * Remove an associated asset.\n *\n * @param assetId - The asset ID to detach.\n * @param relationship - Optional specific relationship to remove. If omitted,\n * all relationships between this object and the asset are removed.\n */\n removeAsset(assetId: string, relationship?: string): Promise<void>;\n}\n\n/**\n * Contract for objects exposing typed access to a `metadata` JSON field.\n *\n * Use alongside an explicit interface (such as {@link AssetAssociable}) to\n * give consumers a stable contract for reading/writing the loose JSON bag,\n * without leaking the `metadata: Record<string, any>` type into call sites.\n */\nexport interface MetadataAccessor<\n TMetadata extends Record<string, unknown> = Record<string, unknown>,\n> {\n /**\n * Get the full metadata record. Always returns an object (never `null`).\n * The returned reference is the live object — callers should treat it as\n * read-only and use {@link MetadataAccessor.setMetadata} or\n * {@link MetadataAccessor.updateMetadata} to mutate it safely.\n */\n getMetadata(): TMetadata;\n\n /**\n * Replace the entire metadata record.\n *\n * @param metadata - The new metadata object. `null`/`undefined` clears it.\n */\n setMetadata(metadata: TMetadata | null | undefined): void;\n\n /**\n * Shallow-merge the supplied patch over the existing metadata.\n *\n * @param patch - Partial metadata. Keys present in the patch overwrite the\n * existing record; keys absent from the patch are preserved.\n * @returns The merged metadata record.\n */\n updateMetadata(patch: Partial<TMetadata>): TMetadata;\n}\n\n/**\n * Runtime type guard for {@link AssetAssociable}.\n *\n * The interface exists primarily so that statically-typed consumers can drop\n * defensive `typeof === 'function'` checks. This guard is for the rare cases\n * where a value enters the system as `unknown` (deserialised payload, plugin\n * input, etc.) and the caller needs to confirm shape before delegating.\n *\n * @example\n * ```ts\n * if (isAssetAssociable(input)) {\n * await input.addAsset(asset, 'attachment');\n * }\n * ```\n */\nexport function isAssetAssociable(value: unknown): value is AssetAssociable {\n if (!value || typeof value !== 'object') return false;\n const candidate = value as Partial<AssetAssociable>;\n return (\n typeof candidate.getAssets === 'function' &&\n typeof candidate.addAsset === 'function' &&\n typeof candidate.removeAsset === 'function'\n );\n}\n\n/**\n * Runtime type guard for {@link MetadataAccessor}.\n *\n * Mirrors {@link isAssetAssociable} for the metadata-accessor contract.\n */\nexport function isMetadataAccessor(value: unknown): value is MetadataAccessor {\n if (!value || typeof value !== 'object') return false;\n const candidate = value as Partial<MetadataAccessor>;\n return (\n typeof candidate.getMetadata === 'function' &&\n typeof candidate.setMetadata === 'function' &&\n typeof candidate.updateMetadata === 'function'\n );\n}\n\n/**\n * Returns `true` if `value` is a plain object (not an array, not `null`,\n * not a class instance with a custom prototype). Used by `Content`'s metadata\n * accessors to enforce the \"record-shaped\" contract — arrays and other\n * non-record objects are normalised to `{}` rather than silently leaked\n * through.\n *\n * @internal\n */\nexport function isPlainMetadataRecord(\n value: unknown,\n): value is Record<string, unknown> {\n if (!value || typeof value !== 'object') return false;\n if (Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n}\n","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface ContentAssetOptions extends SmrtObjectOptions {\n contentId?: string;\n assetId?: string;\n relationship?: string;\n sortOrder?: number;\n tenantId?: string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'content_assets',\n conflictColumns: ['content_id', 'asset_id', 'relationship'],\n api: false,\n mcp: false,\n cli: false,\n})\nexport class ContentAsset extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Content', { required: true })\n contentId = '';\n\n @crossPackageRef('@happyvertical/smrt-assets:Asset', { required: true })\n assetId = '';\n\n @field({ required: true })\n relationship = 'attachment';\n\n @field()\n sortOrder = 0;\n\n constructor(options: ContentAssetOptions = {}) {\n super(options);\n if (options.contentId) this.contentId = options.contentId;\n if (options.assetId) this.assetId = options.assetId;\n if (options.relationship) this.relationship = options.relationship;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n }\n}\n","import type { SmrtCollectionOptions } from '@happyvertical/smrt-core';\nimport { SmrtJunction, smrt } from '@happyvertical/smrt-core';\nimport { ContentAsset } from './content-asset';\n\nexport interface ContentAssetCollectionOptions extends SmrtCollectionOptions {}\n\n@smrt({\n api: false,\n mcp: false,\n cli: false,\n})\nexport class ContentAssetCollection extends SmrtJunction<ContentAsset> {\n static readonly _itemClass = ContentAsset;\n protected leftField = 'contentId';\n protected rightField = 'assetId';\n}\n","import type { Fact, FactContentRelationship } from '@happyvertical/smrt-facts';\nimport {\n getCurrentTenant,\n isSuperAdminBypass,\n isSystemContext,\n isTenancyEnabled,\n} from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { Content } from './content';\n\nexport type ContentReviewKind = 'facts' | 'safety' | 'custom';\n\nexport type ContentReviewStatus =\n | 'pending'\n | 'passed'\n | 'flagged'\n | 'failed'\n | 'waived';\n\nexport type ContentReviewSeverity = 'info' | 'warning' | 'error';\n\nexport type ContentVersionKind =\n | 'manual'\n | 'draft'\n | 'review'\n | 'publication'\n | 'correction'\n | 'auto-generated';\n\nexport type ContentCorrectionType = 'fact' | 'safety' | 'copy' | 'custom';\n\nexport type ContentCorrectionStatus = 'draft' | 'published' | 'retracted';\n\nexport interface ContentReviewFinding {\n severity: ContentReviewSeverity;\n title: string;\n detail: string;\n factId?: string;\n quote?: string;\n suggestedChange?: string;\n ruleId?: string;\n}\n\nexport interface ContentReviewResult {\n status: ContentReviewStatus;\n summary: string;\n findings: ContentReviewFinding[];\n}\n\nexport interface ContentReviewRequirement {\n policyKey: string;\n label?: string;\n blocking?: boolean;\n acceptedStatuses?: ContentReviewStatus[];\n}\n\nexport interface ContentReviewProfileEvaluationItem {\n kind: ContentReviewKind;\n policyKey: string;\n label: string;\n blocking: boolean;\n acceptedStatuses: ContentReviewStatus[];\n missing: boolean;\n stale: boolean;\n executed: boolean;\n satisfied: boolean;\n latestReviewId: string | null;\n latestStatus: ContentReviewStatus | null;\n latestSummary: string | null;\n}\n\nexport interface ContentReviewProfileEvaluation {\n profileKey: string;\n ready: boolean;\n complete: boolean;\n requirements: ContentReviewProfileEvaluationItem[];\n}\n\nexport interface ContentReviewPolicyDefinition {\n key: string;\n label: string;\n kind: ContentReviewKind;\n instructions: string;\n enabled?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ContentGovernanceProfileDefinition {\n key: string;\n label: string;\n description?: string;\n enabled?: boolean;\n requirements: ContentReviewRequirement[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface ContentGovernanceAssignmentDefinition {\n key?: string;\n label?: string;\n contentType: string;\n contentVariant?: string | null;\n enabled?: boolean;\n factLinkingEnabled?: boolean;\n transparencyEnabled?: boolean;\n publicationProfileKey?: string | null;\n correctionProfileKey?: string | null;\n enforcePublishReadiness?: boolean;\n defaultFactRelationship?: FactContentRelationship;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ContentGovernanceConfig {\n policies: ContentReviewPolicyDefinition[];\n profiles: ContentGovernanceProfileDefinition[];\n assignments: ContentGovernanceAssignmentDefinition[];\n}\n\nexport interface PersistedContentGovernancePolicyRecord\n extends ContentReviewPolicyDefinition {\n id?: string;\n tenantId?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n}\n\nexport interface PersistedContentGovernanceProfileRecord\n extends ContentGovernanceProfileDefinition {\n id?: string;\n tenantId?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n}\n\nexport interface PersistedContentGovernanceAssignmentRecord\n extends ContentGovernanceAssignmentDefinition {\n id?: string;\n tenantId?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n}\n\nexport interface PersistedContentGovernanceDefinitions {\n policies: PersistedContentGovernancePolicyRecord[];\n profiles: PersistedContentGovernanceProfileRecord[];\n assignments: PersistedContentGovernanceAssignmentRecord[];\n}\n\nexport interface ResolvedContentGovernance {\n isGoverned: boolean;\n factLinkingEnabled: boolean;\n transparencyEnabled: boolean;\n publicationProfileKey: string | null;\n correctionProfileKey: string | null;\n enforcePublishReadiness: boolean;\n defaultFactRelationship: FactContentRelationship;\n reviewPolicies: ContentReviewPolicyDefinition[];\n availableProfiles: ContentGovernanceProfileDefinition[];\n assignment: ContentGovernanceAssignmentDefinition | null;\n}\n\nexport interface ContentGovernanceState extends ResolvedContentGovernance {\n reviewProfiles: ContentReviewProfileEvaluation[];\n}\n\nexport interface CreateContentVersionOptions {\n kind?: ContentVersionKind;\n summary?: string;\n metadata?: Record<string, unknown>;\n snapshot?: Record<string, unknown>;\n}\n\nexport interface RunContentReviewOptions {\n kind?: ContentReviewKind;\n policyKey?: string;\n reviewer?: string;\n instructions?: string;\n facts?: Fact[];\n factIds?: string[];\n metadata?: Record<string, unknown>;\n createVersion?: boolean;\n /** Claim the loaded content revision after AI work, before persisting review artifacts. */\n expectedUpdatedAt?: Date | string;\n}\n\nexport interface IssueContentCorrectionOptions {\n correctionType?: ContentCorrectionType;\n factId?: string;\n correctedFactText?: string;\n summary: string;\n incorrectText?: string;\n correctedText?: string;\n publicNote?: string;\n metadata?: Record<string, unknown>;\n createVersion?: boolean;\n publish?: boolean;\n}\n\nexport interface BuildContentReviewPromptOptions {\n kind: ContentReviewKind;\n content: Pick<\n Content,\n | 'id'\n | 'type'\n | 'status'\n | 'state'\n | 'title'\n | 'description'\n | 'body'\n | 'author'\n | 'publish_date'\n >;\n facts?: Fact[];\n policy?: ContentReviewPolicyDefinition | null;\n customInstructions?: string;\n}\n\nexport interface ResolveContentGovernanceOptions {\n contentType?: string | null;\n contentVariant?: string | null;\n db?: DatabaseInterface | null;\n tenantId?: string | null;\n}\n\nconst DEFAULT_FACT_RELATIONSHIP: FactContentRelationship = 'supports';\n\nconst DEFAULT_REVIEW_POLICIES: ContentReviewPolicyDefinition[] = [\n {\n key: 'facts',\n label: 'Facts Review',\n kind: 'facts',\n instructions: [\n 'Compare the draft copy against the supplied facts only.',\n 'Flag contradictions, unsupported claims, stale claims, and places where the copy should cite or qualify a statement.',\n 'Do not invent missing facts. If the draft makes a claim that is not supported by the provided facts, flag it clearly.',\n ].join(' '),\n enabled: true,\n },\n {\n key: 'safety',\n label: 'Safety Review',\n kind: 'safety',\n instructions: [\n 'Review the content for legal, reputational, and user-safety risks.',\n 'At minimum, check for defamation risk, privacy leaks, unverified allegations, unsafe instructions, and medical, legal, or financial claims that need qualification.',\n 'Flag content that should be softened, attributed, removed, or escalated for human review.',\n ].join(' '),\n enabled: true,\n },\n];\n\nconst DEFAULT_REVIEW_PROFILES: ContentGovernanceProfileDefinition[] = [\n {\n key: 'publication',\n label: 'Publication',\n description: 'Default publication-time editorial checks.',\n enabled: true,\n requirements: [\n {\n policyKey: 'safety',\n label: 'Safety Review',\n blocking: false,\n },\n {\n policyKey: 'facts',\n label: 'Facts Review',\n blocking: false,\n },\n ],\n },\n {\n key: 'correction',\n label: 'Correction',\n description: 'Default correction-time editorial checks.',\n enabled: true,\n requirements: [\n {\n policyKey: 'safety',\n label: 'Safety Review',\n blocking: false,\n },\n ],\n },\n];\n\nconst DEFAULT_CONTENT_GOVERNANCE_CONFIG: ContentGovernanceConfig = {\n policies: DEFAULT_REVIEW_POLICIES.map(clonePolicyDefinition),\n profiles: DEFAULT_REVIEW_PROFILES.map(cloneProfileDefinition),\n assignments: [],\n};\n\nlet governanceConfig: ContentGovernanceConfig = cloneGovernanceConfig(\n DEFAULT_CONTENT_GOVERNANCE_CONFIG,\n);\n// Process-global by design: apps are expected to configure governance once at\n// startup and use persisted records for runtime admin overrides.\n\nfunction cloneReviewRequirement(\n requirement: ContentReviewRequirement,\n): ContentReviewRequirement {\n return {\n ...requirement,\n acceptedStatuses: requirement.acceptedStatuses\n ? [...requirement.acceptedStatuses]\n : undefined,\n };\n}\n\nfunction normalizePolicyDefinition(\n policy: ContentReviewPolicyDefinition,\n): ContentReviewPolicyDefinition {\n return {\n key: policy.key,\n label: policy.label || policy.key,\n kind: policy.kind || getFallbackPolicyKind(policy.key),\n instructions: policy.instructions || '',\n enabled: policy.enabled !== false,\n metadata: policy.metadata ? { ...policy.metadata } : undefined,\n };\n}\n\nfunction clonePolicyDefinition(\n policy: ContentReviewPolicyDefinition,\n): ContentReviewPolicyDefinition {\n return normalizePolicyDefinition(policy);\n}\n\nfunction normalizeProfileDefinition(\n profile: ContentGovernanceProfileDefinition,\n): ContentGovernanceProfileDefinition {\n return {\n key: profile.key,\n label: profile.label || profile.key,\n description: profile.description || '',\n enabled: profile.enabled !== false,\n requirements: Array.isArray(profile.requirements)\n ? profile.requirements.map(cloneReviewRequirement)\n : [],\n metadata: profile.metadata ? { ...profile.metadata } : undefined,\n };\n}\n\nfunction cloneProfileDefinition(\n profile: ContentGovernanceProfileDefinition,\n): ContentGovernanceProfileDefinition {\n return normalizeProfileDefinition(profile);\n}\n\nexport function buildContentGovernanceAssignmentKey(\n contentType: string,\n contentVariant?: string | null,\n): string {\n return `${contentType || ''}::${contentVariant || ''}`;\n}\n\nfunction normalizeAssignmentDefinition(\n assignment: ContentGovernanceAssignmentDefinition,\n): ContentGovernanceAssignmentDefinition {\n return {\n key:\n assignment.key ||\n buildContentGovernanceAssignmentKey(\n assignment.contentType,\n assignment.contentVariant,\n ),\n label: assignment.label || '',\n contentType: assignment.contentType,\n contentVariant: assignment.contentVariant || '',\n enabled: assignment.enabled !== false,\n factLinkingEnabled: assignment.factLinkingEnabled === true,\n transparencyEnabled: assignment.transparencyEnabled === true,\n publicationProfileKey: assignment.publicationProfileKey || null,\n correctionProfileKey: assignment.correctionProfileKey || null,\n enforcePublishReadiness: assignment.enforcePublishReadiness === true,\n defaultFactRelationship:\n assignment.defaultFactRelationship || DEFAULT_FACT_RELATIONSHIP,\n metadata: assignment.metadata ? { ...assignment.metadata } : undefined,\n };\n}\n\nfunction cloneAssignmentDefinition(\n assignment: ContentGovernanceAssignmentDefinition,\n): ContentGovernanceAssignmentDefinition {\n return normalizeAssignmentDefinition(assignment);\n}\n\nfunction cloneGovernanceConfig(\n config: ContentGovernanceConfig,\n): ContentGovernanceConfig {\n return {\n policies: config.policies.map(clonePolicyDefinition),\n profiles: config.profiles.map(cloneProfileDefinition),\n assignments: config.assignments.map(cloneAssignmentDefinition),\n };\n}\n\nfunction mergeByKey<T extends { key?: string }>(\n previous: T[],\n next: T[],\n normalize: (value: T) => T,\n): T[] {\n const merged = new Map<string, T>();\n\n for (const value of previous) {\n const normalized = normalize(value);\n if (normalized.key) {\n merged.set(normalized.key, normalized);\n }\n }\n\n for (const value of next) {\n const normalized = normalize(value);\n if (normalized.key) {\n merged.set(normalized.key, normalized);\n }\n }\n\n return [...merged.values()];\n}\n\nexport function getFallbackPolicyKind(key: string): ContentReviewKind {\n if (key === 'facts') {\n return 'facts';\n }\n\n if (key === 'safety') {\n return 'safety';\n }\n\n return 'custom';\n}\n\nfunction getPolicyMap(\n policies: ContentReviewPolicyDefinition[],\n): Map<string, ContentReviewPolicyDefinition> {\n return new Map(\n policies.map((policy) => {\n const normalized = normalizePolicyDefinition(policy);\n return [normalized.key, normalized];\n }),\n );\n}\n\nfunction getProfileMap(\n profiles: ContentGovernanceProfileDefinition[],\n): Map<string, ContentGovernanceProfileDefinition> {\n return new Map(\n profiles.map((profile) => {\n const normalized = normalizeProfileDefinition(profile);\n return [normalized.key, normalized];\n }),\n );\n}\n\nfunction isMissingGovernanceTableError(error: unknown): boolean {\n const message =\n error instanceof Error ? error.message : String(error || 'Unknown error');\n\n return (\n message.includes(\"Run 'smrt db:migrate'\") ||\n /no such table/i.test(message) ||\n /does not exist/i.test(message)\n );\n}\n\nfunction getRowTimestamp(\n row: Record<string, unknown>,\n primaryKey: 'createdAt' | 'updatedAt',\n): string | null {\n const snakeCaseKey = primaryKey === 'createdAt' ? 'created_at' : 'updated_at';\n const value = row[primaryKey] ?? row[snakeCaseKey];\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nfunction getRowTenantId(row: Record<string, unknown>): string | null {\n const value = row.tenantId ?? row.tenant_id ?? null;\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nfunction getRowString(\n row: Record<string, unknown>,\n ...keys: string[]\n): string | null {\n for (const key of keys) {\n const value = row[key];\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n }\n return null;\n}\n\nfunction safeParseJSONObject(value: unknown): Record<string, unknown> {\n if (!value) {\n return {};\n }\n\n if (typeof value === 'object' && !Array.isArray(value)) {\n return { ...(value as Record<string, unknown>) };\n }\n\n try {\n const parsed = JSON.parse(String(value));\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? { ...(parsed as Record<string, unknown>) }\n : {};\n } catch {\n return {};\n }\n}\n\nfunction safeParseJSONArray<T>(value: unknown, mapEntry: (entry: T) => T): T[] {\n if (!value) {\n return [];\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => mapEntry(entry as T));\n }\n\n try {\n const parsed = JSON.parse(String(value));\n return Array.isArray(parsed)\n ? parsed.map((entry) => mapEntry(entry as T))\n : [];\n } catch {\n return [];\n }\n}\n\nfunction resolveGovernanceTenantFilter(\n tenantId: string | null | undefined,\n): string | null | undefined {\n if (tenantId !== undefined) {\n return tenantId;\n }\n\n if (isSystemContext() || isSuperAdminBypass()) {\n return undefined;\n }\n\n const currentTenant = getCurrentTenant();\n if (currentTenant?.tenantId) {\n return currentTenant.tenantId;\n }\n\n return isTenancyEnabled() ? null : undefined;\n}\n\nfunction mapPersistedPolicyRow(\n row: Record<string, unknown>,\n): PersistedContentGovernancePolicyRecord {\n return {\n id: typeof row.id === 'string' ? row.id : undefined,\n tenantId: getRowTenantId(row),\n createdAt: getRowTimestamp(row, 'createdAt'),\n updatedAt: getRowTimestamp(row, 'updatedAt'),\n ...normalizePolicyDefinition({\n key: String(row.key || ''),\n label: String(row.label || row.key || ''),\n kind: (row.kind ||\n getFallbackPolicyKind(String(row.key || ''))) as ContentReviewKind,\n instructions: String(row.instructions || ''),\n enabled: row.enabled !== false && row.enabled !== 0,\n metadata: safeParseJSONObject(row.metadata),\n }),\n };\n}\n\nfunction mapPersistedProfileRow(\n row: Record<string, unknown>,\n): PersistedContentGovernanceProfileRecord {\n return {\n id: typeof row.id === 'string' ? row.id : undefined,\n tenantId: getRowTenantId(row),\n createdAt: getRowTimestamp(row, 'createdAt'),\n updatedAt: getRowTimestamp(row, 'updatedAt'),\n ...normalizeProfileDefinition({\n key: String(row.key || ''),\n label: String(row.label || row.key || ''),\n description: String(row.description || ''),\n enabled: row.enabled !== false && row.enabled !== 0,\n requirements: safeParseJSONArray<ContentReviewRequirement>(\n row.requirements,\n cloneReviewRequirement,\n ),\n metadata: safeParseJSONObject(row.metadata),\n }),\n };\n}\n\nfunction mapPersistedAssignmentRow(\n row: Record<string, unknown>,\n): PersistedContentGovernanceAssignmentRecord {\n return {\n id: typeof row.id === 'string' ? row.id : undefined,\n tenantId: getRowTenantId(row),\n createdAt: getRowTimestamp(row, 'createdAt'),\n updatedAt: getRowTimestamp(row, 'updatedAt'),\n ...normalizeAssignmentDefinition({\n key: String(row.key || ''),\n label: String(row.label || ''),\n contentType: String(row.contentType || row.content_type || ''),\n contentVariant: String(row.contentVariant || row.content_variant || ''),\n enabled: row.enabled !== false && row.enabled !== 0,\n factLinkingEnabled:\n row.factLinkingEnabled === true ||\n row.fact_linking_enabled === true ||\n row.fact_linking_enabled === 1,\n transparencyEnabled:\n row.transparencyEnabled === true ||\n row.transparency_enabled === true ||\n row.transparency_enabled === 1,\n publicationProfileKey: getRowString(\n row,\n 'publicationProfileKey',\n 'publication_profile_key',\n ),\n correctionProfileKey: getRowString(\n row,\n 'correctionProfileKey',\n 'correction_profile_key',\n ),\n enforcePublishReadiness:\n row.enforcePublishReadiness === true ||\n row.enforce_publish_readiness === true ||\n row.enforce_publish_readiness === 1,\n // The relationship is stored as a string; trust the persisted value and\n // fall back to the default when absent.\n defaultFactRelationship:\n (getRowString(\n row,\n 'defaultFactRelationship',\n 'default_fact_relationship',\n ) as FactContentRelationship | null) || DEFAULT_FACT_RELATIONSHIP,\n metadata: safeParseJSONObject(row.metadata),\n }),\n };\n}\n\nexport async function loadPersistedContentGovernanceDefinitions(\n options: { db?: DatabaseInterface | null; tenantId?: string | null } = {},\n): Promise<PersistedContentGovernanceDefinitions> {\n const { db } = options;\n if (!db) {\n return {\n policies: [],\n profiles: [],\n assignments: [],\n };\n }\n\n try {\n const tenantId = resolveGovernanceTenantFilter(options.tenantId);\n const listGovernanceRows = async (tableName: string) => {\n const byCreatedAt = (\n a: Record<string, unknown>,\n b: Record<string, unknown>,\n ): number =>\n String(a.created_at || a.createdAt || '').localeCompare(\n String(b.created_at || b.createdAt || ''),\n );\n const sortRows = (rows: Record<string, unknown>[]) =>\n rows.sort(byCreatedAt);\n\n if (tenantId === undefined) {\n return sortRows(\n (await db.list(tableName, {})) as Record<string, unknown>[],\n );\n }\n\n if (tenantId === null) {\n return sortRows(\n (await db.list(tableName, {\n tenant_id: null,\n })) as Record<string, unknown>[],\n );\n }\n\n const [globalRows, tenantRows] = await Promise.all([\n db.list(tableName, { tenant_id: null }) as Promise<\n Record<string, unknown>[]\n >,\n db.list(tableName, { tenant_id: tenantId }) as Promise<\n Record<string, unknown>[]\n >,\n ]);\n\n return [...sortRows(globalRows), ...sortRows(tenantRows)];\n };\n const [policyRows, profileRows, assignmentRows] = await Promise.all([\n listGovernanceRows('content_governance_policies'),\n listGovernanceRows('content_governance_profiles'),\n listGovernanceRows('content_governance_assignments'),\n ]);\n\n return {\n policies: policyRows.map((row: Record<string, unknown>) =>\n mapPersistedPolicyRow(row),\n ),\n profiles: profileRows.map((row: Record<string, unknown>) =>\n mapPersistedProfileRow(row),\n ),\n assignments: assignmentRows.map((row: Record<string, unknown>) =>\n mapPersistedAssignmentRow(row),\n ),\n };\n } catch (error) {\n if (isMissingGovernanceTableError(error)) {\n return {\n policies: [],\n profiles: [],\n assignments: [],\n };\n }\n throw error;\n }\n}\n\nfunction resolveAssignmentDefinition(\n assignments: ContentGovernanceAssignmentDefinition[],\n options: Pick<\n ResolveContentGovernanceOptions,\n 'contentType' | 'contentVariant'\n >,\n): ContentGovernanceAssignmentDefinition | null {\n if (!options.contentType) {\n return null;\n }\n\n const exactMatch =\n assignments.find(\n (assignment) =>\n assignment.contentType === options.contentType &&\n (assignment.contentVariant || '') === (options.contentVariant || ''),\n ) || null;\n\n if (exactMatch) {\n return cloneAssignmentDefinition(exactMatch);\n }\n\n const typeOnlyMatch =\n assignments.find(\n (assignment) =>\n assignment.contentType === options.contentType &&\n !assignment.contentVariant,\n ) || null;\n\n return typeOnlyMatch ? cloneAssignmentDefinition(typeOnlyMatch) : null;\n}\n\nfunction buildResolvedGovernance(\n config: ContentGovernanceConfig,\n assignment: ContentGovernanceAssignmentDefinition | null,\n): ResolvedContentGovernance {\n const normalizedAssignment = assignment\n ? normalizeAssignmentDefinition(assignment)\n : null;\n if (normalizedAssignment?.enabled !== true) {\n return {\n isGoverned: false,\n factLinkingEnabled: false,\n transparencyEnabled: false,\n publicationProfileKey: null,\n correctionProfileKey: null,\n enforcePublishReadiness: false,\n defaultFactRelationship: DEFAULT_FACT_RELATIONSHIP,\n reviewPolicies: config.policies\n .map(clonePolicyDefinition)\n .filter((policy) => policy.enabled !== false),\n availableProfiles: config.profiles\n .map(cloneProfileDefinition)\n .filter((profile) => profile.enabled !== false),\n assignment: normalizedAssignment,\n };\n }\n\n return {\n isGoverned: true,\n factLinkingEnabled: normalizedAssignment.factLinkingEnabled === true,\n transparencyEnabled: normalizedAssignment.transparencyEnabled === true,\n publicationProfileKey: normalizedAssignment.publicationProfileKey || null,\n correctionProfileKey: normalizedAssignment.correctionProfileKey || null,\n enforcePublishReadiness:\n normalizedAssignment.enforcePublishReadiness === true,\n defaultFactRelationship:\n normalizedAssignment.defaultFactRelationship || DEFAULT_FACT_RELATIONSHIP,\n reviewPolicies: config.policies\n .map(clonePolicyDefinition)\n .filter((policy) => policy.enabled !== false),\n availableProfiles: config.profiles\n .map(cloneProfileDefinition)\n .filter((profile) => profile.enabled !== false),\n assignment: normalizedAssignment,\n };\n}\n\nfunction normalizeStatus(status: unknown): ContentReviewStatus {\n switch (status) {\n case 'pending':\n case 'passed':\n case 'flagged':\n case 'failed':\n case 'waived':\n return status;\n default:\n return 'flagged';\n }\n}\n\nfunction normalizeSeverity(severity: unknown): ContentReviewSeverity {\n switch (severity) {\n case 'info':\n case 'warning':\n case 'error':\n return severity;\n default:\n return 'warning';\n }\n}\n\nfunction extractJSONObject(raw: string): string | null {\n const start = raw.indexOf('{');\n const end = raw.lastIndexOf('}');\n if (start === -1 || end === -1 || end <= start) {\n return null;\n }\n return raw.slice(start, end + 1);\n}\n\nexport function getContentGovernanceConfig(): ContentGovernanceConfig {\n return cloneGovernanceConfig(governanceConfig);\n}\n\nexport function getStaticContentGovernanceConfig(): ContentGovernanceConfig {\n return cloneGovernanceConfig(governanceConfig);\n}\n\nexport function configureContentGovernance(\n config: Partial<ContentGovernanceConfig>,\n): ContentGovernanceConfig {\n governanceConfig = {\n policies: config.policies\n ? mergeByKey(\n governanceConfig.policies,\n config.policies,\n normalizePolicyDefinition,\n )\n : governanceConfig.policies.map(clonePolicyDefinition),\n profiles: config.profiles\n ? mergeByKey(\n governanceConfig.profiles,\n config.profiles,\n normalizeProfileDefinition,\n )\n : governanceConfig.profiles.map(cloneProfileDefinition),\n assignments: config.assignments\n ? mergeByKey(\n governanceConfig.assignments,\n config.assignments,\n normalizeAssignmentDefinition,\n )\n : governanceConfig.assignments.map(cloneAssignmentDefinition),\n };\n\n return getContentGovernanceConfig();\n}\n\nexport function resetContentGovernanceConfig(): ContentGovernanceConfig {\n governanceConfig = cloneGovernanceConfig(DEFAULT_CONTENT_GOVERNANCE_CONFIG);\n return getContentGovernanceConfig();\n}\n\nexport async function getEffectiveContentGovernanceConfig(\n options: { db?: DatabaseInterface | null; tenantId?: string | null } = {},\n): Promise<ContentGovernanceConfig> {\n const persisted = await loadPersistedContentGovernanceDefinitions({\n db: options.db,\n tenantId: options.tenantId,\n });\n\n return {\n policies: mergeByKey(\n governanceConfig.policies,\n persisted.policies,\n normalizePolicyDefinition,\n ),\n profiles: mergeByKey(\n governanceConfig.profiles,\n persisted.profiles,\n normalizeProfileDefinition,\n ),\n assignments: mergeByKey(\n governanceConfig.assignments,\n persisted.assignments,\n normalizeAssignmentDefinition,\n ),\n };\n}\n\nexport function hasStaticContentGovernancePolicy(key: string): boolean {\n return getPolicyMap(governanceConfig.policies).has(key);\n}\n\nexport function hasStaticContentGovernanceProfile(key: string): boolean {\n return getProfileMap(governanceConfig.profiles).has(key);\n}\n\nexport function getContentReviewPolicy(\n policyKey: string,\n policies: ContentReviewPolicyDefinition[] = governanceConfig.policies,\n): ContentReviewPolicyDefinition | null {\n return getPolicyMap(policies).get(policyKey) || null;\n}\n\nexport function getContentReviewKind(\n policyKey: string,\n policies: ContentReviewPolicyDefinition[] = governanceConfig.policies,\n): ContentReviewKind {\n const configuredKind = getPolicyMap(policies).get(policyKey)?.kind;\n return configuredKind || getFallbackPolicyKind(policyKey);\n}\n\nexport function getContentReviewProfile(\n profileKey: string,\n profiles: ContentGovernanceProfileDefinition[] = governanceConfig.profiles,\n): ContentGovernanceProfileDefinition | null {\n return getProfileMap(profiles).get(profileKey) || null;\n}\n\nexport function getContentReviewProfileKeys(\n profiles: ContentGovernanceProfileDefinition[] = governanceConfig.profiles,\n): string[] {\n return profiles\n .map(cloneProfileDefinition)\n .filter((profile) => profile.enabled !== false)\n .map((profile) => profile.key);\n}\n\nexport function getContentReviewPolicies(\n policies: ContentReviewPolicyDefinition[] = governanceConfig.policies,\n): ContentReviewPolicyDefinition[] {\n return policies\n .map(clonePolicyDefinition)\n .filter((policy) => policy.enabled !== false);\n}\n\nexport function getContentReviewRequirements(\n profileKey: string,\n profiles: ContentGovernanceProfileDefinition[] = governanceConfig.profiles,\n): ContentReviewRequirement[] {\n const profile = getContentReviewProfile(profileKey, profiles);\n return profile?.requirements.map(cloneReviewRequirement) || [];\n}\n\nexport function getAcceptedContentReviewStatuses(\n requirement: Pick<ContentReviewRequirement, 'acceptedStatuses'>,\n): ContentReviewStatus[] {\n return requirement.acceptedStatuses && requirement.acceptedStatuses.length > 0\n ? [...requirement.acceptedStatuses]\n : ['passed', 'waived'];\n}\n\nexport function resolveConfiguredContentGovernance(\n options: Pick<\n ResolveContentGovernanceOptions,\n 'contentType' | 'contentVariant'\n >,\n): ResolvedContentGovernance {\n const assignment = resolveAssignmentDefinition(governanceConfig.assignments, {\n contentType: options.contentType,\n contentVariant: options.contentVariant,\n });\n\n return buildResolvedGovernance(governanceConfig, assignment);\n}\n\nexport async function resolveEffectiveContentGovernance(\n options: ResolveContentGovernanceOptions,\n): Promise<ResolvedContentGovernance> {\n const effectiveConfig = await getEffectiveContentGovernanceConfig({\n db: options.db,\n tenantId: options.tenantId,\n });\n const assignment = resolveAssignmentDefinition(effectiveConfig.assignments, {\n contentType: options.contentType,\n contentVariant: options.contentVariant,\n });\n\n return buildResolvedGovernance(effectiveConfig, assignment);\n}\n\nexport function buildContentReviewPrompt(\n options: BuildContentReviewPromptOptions,\n): string {\n const { kind, content, facts = [], policy, customInstructions } = options;\n\n const factLines =\n facts.length > 0\n ? facts\n .map(\n (fact) =>\n `- [${fact.id}] status=${fact.status}; confidence=${fact.confidence}; sources=${fact.sourceCount}; text=${fact.textRefined}`,\n )\n .join('\\n')\n : 'No facts were supplied for this review.';\n\n const policyText =\n customInstructions?.trim() ||\n policy?.instructions ||\n getContentReviewPolicy(kind)?.instructions ||\n '';\n\n return `You are a structured editorial reviewer.\n\nReturn ONLY valid JSON with this shape:\n{\n \"status\": \"passed\" | \"flagged\" | \"failed\" | \"waived\",\n \"summary\": \"short summary\",\n \"findings\": [\n {\n \"severity\": \"info\" | \"warning\" | \"error\",\n \"title\": \"short title\",\n \"detail\": \"what is wrong and why\",\n \"factId\": \"optional fact id\",\n \"quote\": \"optional quoted text from the draft\",\n \"suggestedChange\": \"optional suggested fix\",\n \"ruleId\": \"optional policy or rule id\"\n }\n ]\n}\n\nReview kind: ${kind}\nPolicy key: ${policy?.key || kind}\nReview instructions:\n${policyText}\n\nDraft content:\n- id: ${content.id ?? ''}\n- type: ${content.type ?? ''}\n- status: ${content.status}\n- state: ${content.state}\n- author: ${content.author ?? ''}\n- publish_date: ${content.publish_date?.toISOString?.() ?? ''}\n\nTitle:\n${content.title}\n\nDescription:\n${content.description ?? ''}\n\nBody:\n${content.body}\n\nRelevant facts:\n${factLines}`;\n}\n\nexport function parseContentReviewResponse(raw: string): ContentReviewResult {\n const normalizedRaw = raw.trim();\n const jsonCandidate = extractJSONObject(normalizedRaw);\n\n if (jsonCandidate) {\n try {\n const parsed = JSON.parse(jsonCandidate) as {\n status?: unknown;\n summary?: unknown;\n findings?: unknown;\n };\n const findings = Array.isArray(parsed.findings)\n ? parsed.findings.map((rawFinding): ContentReviewFinding => {\n const finding =\n rawFinding && typeof rawFinding === 'object'\n ? (rawFinding as Record<string, unknown>)\n : {};\n return {\n severity: normalizeSeverity(finding.severity),\n title: String(finding.title || 'Review finding'),\n detail: String(finding.detail || ''),\n factId:\n typeof finding.factId === 'string' ? finding.factId : undefined,\n quote:\n typeof finding.quote === 'string' ? finding.quote : undefined,\n suggestedChange:\n typeof finding.suggestedChange === 'string'\n ? finding.suggestedChange\n : undefined,\n ruleId:\n typeof finding.ruleId === 'string' ? finding.ruleId : undefined,\n };\n })\n : [];\n\n return {\n status: normalizeStatus(parsed.status),\n summary: String(parsed.summary || normalizedRaw || 'Review completed'),\n findings,\n };\n } catch {\n // Fall through to a normalized fallback result.\n }\n }\n\n return {\n status: 'flagged',\n summary: normalizedRaw || 'Review completed without structured output.',\n findings: normalizedRaw\n ? [\n {\n severity: 'warning',\n title: 'Unstructured review output',\n detail: normalizedRaw,\n },\n ]\n : [],\n };\n}\n","import {\n definePrompt,\n type ResolvedPromptAI,\n} from '@happyvertical/smrt-prompts';\n\nexport const smrtContentReviewPrompt = definePrompt({\n key: 'smrtContent.review',\n template: `Content review request\n\nContent ID: {contentId}\nReview kind: {kind}\nPolicy key: {policyKey}\nTitle: {contentTitle}\nDescription: {contentDescription}\n\nBody:\n{contentBody}\n\n{reviewPrompt}`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport const smrtContentApplyCorrectionPrompt = definePrompt({\n key: 'smrtContent.applyCorrection',\n template: `You are revising an article draft to apply a factual correction.\n\nReturn only the fully revised body text, with no commentary.\n\nCurrent body:\n{body}\n\nCorrection summary:\n{summary}\n\nIncorrect text to fix:\n{incorrectText}\n\nCorrected text to incorporate:\n{correctedText}`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport const smrtContentThumbnailAIGeneratePrompt = definePrompt({\n key: 'smrtContent.thumbnail.aiGenerate',\n 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.`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport function promptMessageOptions(ai: ResolvedPromptAI) {\n return {\n ...(ai.params || {}),\n ...(ai.model ? { model: ai.model } : {}),\n ...(typeof ai.temperature === 'number'\n ? { temperature: ai.temperature }\n : {}),\n ...(typeof ai.maxTokens === 'number' ? { maxTokens: ai.maxTokens } : {}),\n };\n}\n","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface ContentReferenceOptions extends SmrtObjectOptions {\n sourceId?: string;\n targetId?: string;\n tenantId?: string | null;\n // ContentVersion.version pinned at citation time. Optional: references\n // created without a pin behave as before (they track the live target).\n // When set, callers can compare against the target's latest version to\n // surface drift between what was cited and what the target now says.\n targetVersion?: number | null;\n createdAt?: Date;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'content_references',\n conflictColumns: ['source_id', 'target_id'],\n})\nexport class ContentReference extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Content', { required: true })\n sourceId = '';\n\n @foreignKey('Content', { required: true })\n targetId = '';\n\n @field({ type: 'integer', nullable: true })\n targetVersion: number | null = null;\n\n @field()\n createdAt = new Date();\n\n constructor(options: ContentReferenceOptions = {}) {\n super(options);\n if (options.sourceId) this.sourceId = options.sourceId;\n if (options.targetId) this.targetId = options.targetId;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.targetVersion !== undefined)\n this.targetVersion = options.targetVersion;\n if (options.createdAt) this.createdAt = options.createdAt;\n }\n}\n","import type {\n JunctionAttachOptions,\n SmrtCollectionOptions,\n} from '@happyvertical/smrt-core';\nimport { SmrtJunction, smrt } from '@happyvertical/smrt-core';\nimport { ContentReference } from './content-reference';\n\nexport interface ContentReferencesOptions extends SmrtCollectionOptions {}\n\n/**\n * The `attach()` override below restores find-or-create idempotency for\n * `(sourceId, targetId)` — duplicate calls return the existing row\n * unchanged, preserving `id` and `createdAt`. This matters because\n * `ContentReference` rows are externally addressable via\n * `/api/v1/contentreferences/[id]`.\n *\n * Two REST entry points (both auto-generated by the scanner):\n * - `POST /api/v1/contentreferences` (from model CRUD) calls\n * `collection.create()` which is upsert-based — id/createdAt get\n * rewritten on conflict. Convenient for callers that don't care\n * about row id stability.\n * - `POST /api/v1/contentreferences/attach` (from the override below)\n * is idempotent. Use this for stable URLs.\n *\n * Internal callers (`Content.addReference()`) always hit the idempotent\n * path because they call the collection directly.\n *\n * The `/attach` route exists because R2 round-7 added `@smrt()` to this\n * class, which made the scanner pick up the override as a custom\n * collection method route. Pre-R2 had a `/link` route from the\n * pre-rename method name.\n */\n// Decorator with empty config — only needed so the scanner detects the\n// class. See FactContentCollection for the full rationale.\n@smrt()\nexport class ContentReferences extends SmrtJunction<ContentReference> {\n static readonly _itemClass = ContentReference;\n protected leftField = 'sourceId';\n protected rightField = 'targetId';\n // content_references has no sort_order column — preserve insertion order\n // by sorting on created_at, and disable setLinks position auto-indexing\n // so it doesn't try to write integer indices into the timestamp column.\n protected sortField: string | null = 'createdAt';\n protected positionField: string | null = null;\n\n async getForSource(sourceId: string): Promise<ContentReference[]> {\n return (await this.list({\n where: { sourceId },\n orderBy: 'created_at ASC',\n })) as ContentReference[];\n }\n\n async getForTarget(targetId: string): Promise<ContentReference[]> {\n return (await this.list({\n where: { targetId },\n orderBy: 'created_at ASC',\n })) as ContentReference[];\n }\n\n /**\n * Find-or-create idempotency: if a reference already exists for\n * (sourceId, targetId), return the existing row unchanged instead of\n * upserting a new row. This preserves the existing row's `id` and\n * `createdAt`, which is important because reference rows are\n * externally addressable via `/api/v1/contentreferences/[id]`.\n *\n * The base `SmrtJunction.attach` flow (this.create → db.upsert) would\n * overwrite both columns on every duplicate call.\n *\n * Reference pinning (main): `opts.targetVersion` pins the citation to a\n * specific `ContentVersion.version` for drift detection. Re-attaching an\n * existing edge with a different `targetVersion` updates the pin in place;\n * `undefined` leaves an existing pin untouched, while a brand-new row\n * defaults the pin to `null` (unpinned).\n */\n async attach(\n sourceId: string,\n targetId: string,\n opts: JunctionAttachOptions = {},\n ): Promise<ContentReference> {\n const targetVersion = opts.targetVersion as number | null | undefined;\n const existing = (await this.get({\n sourceId,\n targetId,\n })) as ContentReference | null;\n if (existing) {\n if (\n targetVersion !== undefined &&\n existing.targetVersion !== targetVersion\n ) {\n existing.targetVersion = targetVersion;\n await existing.save();\n }\n return existing;\n }\n return super.attach(sourceId, targetId, {\n ...opts,\n targetVersion: targetVersion ?? null,\n });\n }\n\n async unlink(sourceId: string, targetId: string): Promise<void> {\n await this.detach(sourceId, targetId);\n }\n}\n","export interface ContentTransparencyGeneration {\n aiAssisted: boolean;\n publicPrompt: string | null;\n model: string | null;\n}\n\nexport interface ContentTransparencySource {\n id: string | null;\n sourceType: string | null;\n sourceUrl: string | null;\n sourceTitle: string | null;\n credibility: number | null;\n extractedAt: string | null;\n metadata: Record<string, unknown>;\n}\n\nexport interface ContentTransparencyFact {\n id: string | null;\n textRaw?: string | null;\n textRefined?: string | null;\n status?: string | null;\n domain?: string | null;\n confidence?: number | null;\n sourceCount?: number | null;\n metadata?: Record<string, unknown>;\n relationship?: string | null;\n linkMetadata?: Record<string, unknown>;\n usedInArticle?: boolean;\n sources?: ContentTransparencySource[];\n}\n\nexport interface ContentTransparencyReference {\n id: string | null;\n title: string | null;\n url: string | null;\n originalUrl: string | null;\n type: string | null;\n source: string | null;\n usedFactIds: string[];\n extractedFacts: ContentTransparencyFact[];\n}\n\nexport interface ContentTransparencyPublicationVersion {\n id: string | null;\n version: number | null;\n kind: string | null;\n summary: string;\n createdAt: string | null;\n}\n\nexport interface ContentTransparencyVersionHistoryItem {\n id: string | null;\n version: number | null;\n kind: string | null;\n summary: string;\n createdAt: string | null;\n provenance: Record<string, unknown>;\n}\n\n/**\n * Serialized review record carried in a transparency snapshot. Only the fields\n * consumers read are named; the index signature preserves the remaining\n * serialized properties.\n */\nexport interface ContentTransparencyReview {\n id?: string | null;\n kind?: string | null;\n policyKey?: string | null;\n status?: string | null;\n summary?: string | null;\n createdAt?: string | null;\n [key: string]: unknown;\n}\n\n/**\n * Serialized review-profile evaluation carried in a transparency snapshot.\n */\nexport interface ContentTransparencyReviewProfile {\n profileKey?: string | null;\n [key: string]: unknown;\n}\n\n/**\n * Serialized correction record carried in a transparency snapshot.\n */\nexport interface ContentTransparencyCorrection {\n id?: string | null;\n summary?: string | null;\n publicNote?: string | null;\n publishedAt?: string | null;\n [key: string]: unknown;\n}\n\nexport interface ContentTransparencyData {\n generatedAt: string | null;\n snapshotKind: 'preview' | 'published';\n contentId: string | null;\n currentContentStatus: string | null;\n publicationProfileKey: string;\n publicationVersion: ContentTransparencyPublicationVersion | null;\n generation: ContentTransparencyGeneration;\n factsUsed: ContentTransparencyFact[];\n linkedFacts: ContentTransparencyFact[];\n otherExtractedFacts: ContentTransparencyFact[];\n references: ContentTransparencyReference[];\n reviews: ContentTransparencyReview[];\n reviewProfiles: ContentTransparencyReviewProfile[];\n corrections: ContentTransparencyCorrection[];\n versionHistory: ContentTransparencyVersionHistoryItem[];\n}\n\nfunction asObject(\n value: unknown,\n fallback: Record<string, unknown> = {},\n): Record<string, unknown> {\n return value && typeof value === 'object'\n ? { ...(value as Record<string, unknown>) }\n : fallback;\n}\n\nfunction asString(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nfunction asNumber(value: unknown): number | null {\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\nfunction asArray<T>(value: unknown): T[] {\n return Array.isArray(value) ? (value as T[]) : [];\n}\n\nfunction normalizeGeneration(value: unknown): ContentTransparencyGeneration {\n const generation = asObject(value);\n return {\n aiAssisted: Boolean(generation.aiAssisted),\n publicPrompt: asString(generation.publicPrompt),\n model: asString(generation.model),\n };\n}\n\nfunction normalizeFact(value: unknown): ContentTransparencyFact {\n const fact = asObject(value);\n return {\n ...fact,\n id: asString(fact.id),\n relationship: asString(fact.relationship),\n linkMetadata: asObject(fact.linkMetadata),\n usedInArticle: Boolean(fact.usedInArticle),\n sources: asArray<unknown>(fact.sources).map(normalizeSource),\n };\n}\n\nfunction normalizeSource(value: unknown): ContentTransparencySource {\n const source = asObject(value);\n return {\n id: asString(source.id),\n sourceType: asString(source.sourceType),\n sourceUrl: asString(source.sourceUrl),\n sourceTitle: asString(source.sourceTitle),\n credibility: asNumber(source.credibility),\n extractedAt: asString(source.extractedAt),\n metadata: asObject(source.metadata),\n };\n}\n\nfunction normalizeReference(value: unknown): ContentTransparencyReference {\n const reference = asObject(value);\n return {\n id: asString(reference.id),\n title: asString(reference.title),\n url: asString(reference.url),\n originalUrl: asString(reference.originalUrl),\n type: asString(reference.type),\n source: asString(reference.source),\n usedFactIds: asArray<string>(reference.usedFactIds).filter(Boolean),\n extractedFacts: asArray<unknown>(reference.extractedFacts).map(\n normalizeFact,\n ),\n };\n}\n\nfunction normalizePublicationVersion(\n value: unknown,\n): ContentTransparencyPublicationVersion | null {\n const publicationVersion = asObject(value);\n if (!publicationVersion.id && publicationVersion.version === undefined) {\n return null;\n }\n\n return {\n id: asString(publicationVersion.id),\n version: asNumber(publicationVersion.version),\n kind: asString(publicationVersion.kind),\n summary:\n typeof publicationVersion.summary === 'string'\n ? publicationVersion.summary\n : '',\n createdAt: asString(publicationVersion.createdAt),\n };\n}\n\nfunction normalizeVersionHistoryItem(\n value: unknown,\n): ContentTransparencyVersionHistoryItem {\n const version = asObject(value);\n return {\n id: asString(version.id),\n version: asNumber(version.version),\n kind: asString(version.kind),\n summary: typeof version.summary === 'string' ? version.summary : '',\n createdAt: asString(version.createdAt),\n provenance: asObject(version.provenance),\n };\n}\n\nfunction dedupeFacts(facts: ContentTransparencyFact[]) {\n const byKey = new Map<string, ContentTransparencyFact>();\n\n for (const fact of facts) {\n // Collapse effectively empty facts into a single placeholder bucket rather\n // than rendering duplicate blank entries in the public transparency view.\n const key =\n fact.id ||\n fact.textRefined ||\n fact.textRaw ||\n JSON.stringify(fact.metadata || {});\n if (!key) {\n continue;\n }\n\n byKey.set(key, fact);\n }\n\n return [...byKey.values()];\n}\n\nexport function normalizeContentTransparency(\n value: unknown,\n defaults: Partial<ContentTransparencyData> = {},\n): ContentTransparencyData {\n const snapshot = asObject(value);\n const references = asArray<unknown>(snapshot.references).map(\n normalizeReference,\n );\n const linkedFacts = asArray<unknown>(snapshot.linkedFacts).map(normalizeFact);\n const factsUsed =\n asArray<unknown>(snapshot.factsUsed).length > 0\n ? asArray<unknown>(snapshot.factsUsed).map(normalizeFact)\n : linkedFacts.filter((fact) => fact.usedInArticle);\n const otherExtractedFacts =\n asArray<unknown>(snapshot.otherExtractedFacts).length > 0\n ? asArray<unknown>(snapshot.otherExtractedFacts).map(normalizeFact)\n : dedupeFacts(\n references.flatMap((reference) =>\n reference.extractedFacts.filter((fact) => !fact.usedInArticle),\n ),\n );\n\n return {\n generatedAt: asString(snapshot.generatedAt) ?? defaults.generatedAt ?? null,\n snapshotKind:\n snapshot.snapshotKind === 'published'\n ? 'published'\n : defaults.snapshotKind || 'preview',\n contentId: asString(snapshot.contentId) ?? defaults.contentId ?? null,\n currentContentStatus:\n asString(snapshot.currentContentStatus) ??\n defaults.currentContentStatus ??\n null,\n publicationProfileKey:\n asString(snapshot.publicationProfileKey) ??\n asString(snapshot.publicationReviewProfileKey) ??\n defaults.publicationProfileKey ??\n 'publication',\n publicationVersion:\n normalizePublicationVersion(snapshot.publicationVersion) ??\n defaults.publicationVersion ??\n null,\n generation: normalizeGeneration(\n snapshot.generation ?? defaults.generation ?? {},\n ),\n factsUsed,\n linkedFacts,\n otherExtractedFacts,\n references,\n reviews: asArray<ContentTransparencyReview>(snapshot.reviews),\n reviewProfiles: asArray<ContentTransparencyReviewProfile>(\n snapshot.reviewProfiles,\n ),\n corrections: asArray<ContentTransparencyCorrection>(snapshot.corrections),\n versionHistory: asArray<unknown>(snapshot.versionHistory).map(\n normalizeVersionHistoryItem,\n ),\n };\n}\n","export function isMissingTableError(\n error: unknown,\n tableName: string,\n): boolean {\n const message = String(\n (error as Error)?.message || error || '',\n ).toLowerCase();\n\n return (\n message.includes(tableName.toLowerCase()) &&\n (message.includes('no such table') ||\n message.includes('does not exist') ||\n message.includes('relation'))\n );\n}\n\nexport function getQueryRows(result: unknown): Record<string, unknown>[] {\n return Array.isArray(result)\n ? (result as Record<string, unknown>[])\n : Array.isArray((result as { rows?: Record<string, unknown>[] })?.rows)\n ? ((result as { rows: Record<string, unknown>[] }).rows ?? [])\n : [];\n}\n","/**\n * Plain JSON shape produced by serializing a SMRT model instance. Values are\n * intentionally `unknown` — callers spread these records into API responses and\n * narrow individual fields where they need a concrete type.\n */\ntype SerializedRecord = Record<string, unknown>;\n\n/**\n * Minimal structural view of the model instances passed to the serializers.\n * Every model used here exposes `toJSON()` plus optional accessor methods for\n * its JSON-backed fields; the accessors are typed loosely because each model\n * returns a different concrete shape.\n */\ninterface SerializableModel {\n toJSON?: () => unknown;\n getMetadata?: () => unknown;\n getSnapshot?: () => unknown;\n getFindings?: () => unknown;\n getAllowedChannels?: () => unknown;\n getIntakeRules?: () => unknown;\n getPromotion?: () => unknown;\n getRevisions?: () => Promise<unknown[]> | unknown[];\n getAttachments?: () => Promise<unknown[]> | unknown[];\n getContributor?: () => Promise<unknown> | unknown;\n getReferences?: () => Promise<unknown[]> | unknown[];\n getAssets?: () => Promise<unknown[]> | unknown[];\n getReferenceDrift?: () => Promise<unknown> | unknown;\n metadata?: unknown;\n}\n\nfunction asModel(value: unknown): SerializableModel {\n return value && typeof value === 'object' ? (value as SerializableModel) : {};\n}\n\nfunction toJSON(value: unknown): SerializedRecord {\n const model = asModel(value);\n if (typeof model.toJSON === 'function') {\n const serialized = model.toJSON();\n return serialized && typeof serialized === 'object'\n ? (serialized as SerializedRecord)\n : {};\n }\n\n return value && typeof value === 'object' ? (value as SerializedRecord) : {};\n}\n\nexport function serializeFact(fact: unknown) {\n const model = asModel(fact);\n const data = toJSON(fact);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeFactLink(link: unknown) {\n const model = asModel(link);\n const data = toJSON(link);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentVersion(version: unknown) {\n const model = asModel(version);\n const data = toJSON(version);\n return {\n ...data,\n snapshot:\n typeof model.getSnapshot === 'function'\n ? model.getSnapshot()\n : data.snapshot || {},\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentReview(review: unknown) {\n const model = asModel(review);\n const data = toJSON(review);\n return {\n ...data,\n findings:\n typeof model.getFindings === 'function'\n ? model.getFindings()\n : data.findings || [],\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentCorrection(correction: unknown) {\n const model = asModel(correction);\n const data = toJSON(correction);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentContributor(contributor: unknown) {\n const model = asModel(contributor);\n const data = toJSON(contributor);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentContributionType(contributionType: unknown) {\n const model = asModel(contributionType);\n const data = toJSON(contributionType);\n return {\n ...data,\n allowedChannels:\n typeof model.getAllowedChannels === 'function'\n ? model.getAllowedChannels()\n : data.allowedChannels || [],\n intakeRules:\n typeof model.getIntakeRules === 'function'\n ? model.getIntakeRules()\n : data.intakeRules || {},\n promotion:\n typeof model.getPromotion === 'function'\n ? model.getPromotion()\n : data.promotion || {},\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentContributionRevision(revision: unknown) {\n const model = asModel(revision);\n const data = toJSON(revision);\n return {\n ...data,\n sourceMessageId: data.sourceMessageId || null,\n sourceThreadKey: data.sourceThreadKey || null,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentContributionAttachment(attachment: unknown) {\n const model = asModel(attachment);\n const data = toJSON(attachment);\n return {\n ...data,\n revisionId: data.revisionId || null,\n fileKey: data.fileKey || null,\n sourceUri: data.sourceUri || null,\n promotedAssetId: data.promotedAssetId || null,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport async function serializeContentContribution(contribution: unknown) {\n const model = asModel(contribution);\n const [revisions, attachments, contributor] = await Promise.all([\n typeof model.getRevisions === 'function' ? model.getRevisions() : [],\n typeof model.getAttachments === 'function' ? model.getAttachments() : [],\n typeof model.getContributor === 'function' ? model.getContributor() : null,\n ]);\n\n return {\n ...toJSON(contribution),\n contributor: contributor ? serializeContentContributor(contributor) : null,\n revisions: revisions.map(serializeContentContributionRevision),\n attachments: attachments.map(serializeContentContributionAttachment),\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : model.metadata || {},\n };\n}\n\nexport function serializeContentReviewProfileEvaluation(profile: unknown) {\n const data = toJSON(profile);\n return {\n ...data,\n requirements: Array.isArray(data.requirements) ? data.requirements : [],\n };\n}\n\nexport function serializeContentReviewPolicy(policy: unknown) {\n return {\n ...toJSON(policy),\n };\n}\n\nexport function serializeContentGovernanceProfile(profile: unknown) {\n const model = asModel(profile);\n const data = toJSON(profile);\n return {\n ...data,\n requirements: Array.isArray(data.requirements) ? data.requirements : [],\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentGovernanceAssignment(assignment: unknown) {\n const model = asModel(assignment);\n const data = toJSON(assignment);\n return {\n ...data,\n metadata:\n typeof model.getMetadata === 'function'\n ? model.getMetadata()\n : data.metadata || {},\n };\n}\n\nexport function serializeContentGovernanceState(state: unknown) {\n const data = toJSON(state);\n return {\n ...data,\n reviewPolicies: Array.isArray(data.reviewPolicies)\n ? data.reviewPolicies.map(serializeContentReviewPolicy)\n : [],\n availableProfiles: Array.isArray(data.availableProfiles)\n ? data.availableProfiles.map(serializeContentGovernanceProfile)\n : [],\n reviewProfiles: Array.isArray(data.reviewProfiles)\n ? data.reviewProfiles.map(serializeContentReviewProfileEvaluation)\n : [],\n };\n}\n\n/**\n * Reference-drift edge keyed by target content id. Mirrors the shape returned\n * by `Content.getReferenceDrift()`.\n */\ninterface ReferenceDriftEdge {\n citedVersion: number | null;\n currentVersion: number | null;\n isDrifted: boolean;\n}\n\nexport async function serializeContent(content: unknown) {\n const model = asModel(content);\n const [references, assets] = await Promise.all([\n typeof model.getReferences === 'function' ? model.getReferences() : [],\n typeof model.getAssets === 'function' ? model.getAssets() : [],\n ]);\n\n // Only resolve drift when there are references to drift against — list\n // endpoints serializing many ref-less items shouldn't pay the version\n // lookup cost.\n const drift =\n references.length > 0 && typeof model.getReferenceDrift === 'function'\n ? await model.getReferenceDrift()\n : [];\n\n const driftByTargetId = new Map<string, ReferenceDriftEdge>(\n Array.isArray(drift)\n ? drift\n .map((entry) => asModel(entry))\n .filter(\n (entry): entry is SerializableModel & { targetId: string } =>\n typeof (entry as { targetId?: unknown }).targetId === 'string',\n )\n .map((entry) => {\n const edge = entry as {\n targetId: string;\n citedVersion?: unknown;\n currentVersion?: unknown;\n isDrifted?: unknown;\n };\n return [\n edge.targetId,\n {\n citedVersion: (edge.citedVersion as number | null) ?? null,\n currentVersion: (edge.currentVersion as number | null) ?? null,\n isDrifted: Boolean(edge.isDrifted),\n },\n ] satisfies [string, ReferenceDriftEdge];\n })\n : [],\n );\n\n return {\n ...toJSON(content),\n referenceIds: references\n .map((reference) => asModel(reference) as { id?: unknown })\n .map((reference) => reference.id)\n .filter(Boolean),\n references: references.map((reference) => {\n const base = toJSON(reference);\n const edge =\n typeof base.id === 'string' ? driftByTargetId.get(base.id) : null;\n return edge\n ? {\n ...base,\n citedVersion: edge.citedVersion,\n currentVersion: edge.currentVersion,\n isDrifted: edge.isDrifted,\n }\n : base;\n }),\n assetIds: assets\n .map((asset) => (asModel(asset) as { id?: unknown }).id)\n .filter(Boolean),\n assets: assets.map((asset) => toJSON(asset)),\n };\n}\n","/**\n * Thumbnail Generator for Content\n *\n * Generates thumbnail images for content using various strategies:\n * - headline-card: Draws article title on branded background\n * - static-map: Uses static maps API for location-based content\n * - ai-generate: Uses AI image generation for creative thumbnails\n */\n\nimport type { AIClient, AIClientOptions } from '@happyvertical/ai';\nimport { fetchStaticMap, type StaticMapProvider } from '@happyvertical/geo';\nimport {\n generateHeadlineCard,\n type HeadlineCardTemplate,\n} from '@happyvertical/images';\nimport type { DatabaseConfig } from '@happyvertical/smrt-core';\nimport type { Image } from '@happyvertical/smrt-images';\nimport { ImageCollection } from '@happyvertical/smrt-images';\nimport {\n type ResolvedPrompt,\n resolvePrompt,\n} from '@happyvertical/smrt-prompts';\nimport type { Content } from './content';\nimport {\n promptMessageOptions,\n smrtContentThumbnailAIGeneratePrompt,\n} from './content-prompts';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Available thumbnail generation strategies\n */\nexport type ThumbnailStrategy = 'headline-card' | 'static-map' | 'ai-generate';\n\n/**\n * Base options for all strategies\n */\ninterface BaseThumbnailOptions {\n /**\n * Generation strategy\n */\n strategy: ThumbnailStrategy;\n\n /**\n * Width in pixels\n * @default 1200\n */\n width?: number;\n\n /**\n * Height in pixels\n * @default 630\n */\n height?: number;\n}\n\n/**\n * Options for headline card strategy\n */\nexport interface HeadlineCardThumbnailOptions extends BaseThumbnailOptions {\n strategy: 'headline-card';\n\n /**\n * Primary brand color (hex)\n * @default '#3b82f6'\n */\n brandColor?: string;\n\n /**\n * Background color (hex)\n * @default '#ffffff'\n */\n backgroundColor?: string;\n\n /**\n * Optional subtitle/category text\n */\n subtitle?: string;\n\n /**\n * Optional logo URL\n */\n logoUrl?: string;\n\n /**\n * Template style\n * @default 'default'\n */\n template?: HeadlineCardTemplate;\n}\n\n/**\n * Options for static map strategy\n */\nexport interface StaticMapThumbnailOptions extends BaseThumbnailOptions {\n strategy: 'static-map';\n\n /**\n * Map provider\n * @default 'mapbox'\n */\n mapProvider?: StaticMapProvider;\n\n /**\n * Zoom level (1-20)\n * @default 14\n */\n zoom?: number;\n\n /**\n * Marker color\n * @default 'e74c3c'\n */\n markerColor?: string;\n\n /**\n * Mapbox style (if using mapbox provider)\n */\n mapboxStyle?: string;\n\n /**\n * Google map type (if using google provider)\n */\n googleMapType?: 'roadmap' | 'satellite' | 'terrain' | 'hybrid';\n}\n\n/**\n * Options for AI generation strategy\n */\nexport interface AIGenerateThumbnailOptions extends BaseThumbnailOptions {\n strategy: 'ai-generate';\n\n /**\n * AI provider configuration\n */\n ai?: AIClientOptions | AIClient;\n\n /**\n * Custom prompt for image generation\n * If not provided, generates based on content title/body\n */\n prompt?: string;\n\n /**\n * Style hint for image generation\n * @default 'photorealistic'\n */\n style?: 'photorealistic' | 'illustration' | 'abstract' | 'minimal';\n}\n\n/**\n * Union type for all thumbnail options\n */\nexport type ThumbnailOptions =\n | HeadlineCardThumbnailOptions\n | StaticMapThumbnailOptions\n | AIGenerateThumbnailOptions;\n\n// ============================================================================\n// Generator Class\n// ============================================================================\n\n/**\n * Options for ThumbnailGenerator\n */\nexport interface ThumbnailGeneratorOptions {\n /**\n * Database configuration for storing generated images\n */\n db?: DatabaseConfig;\n\n /**\n * Alias for `db` — mirrors the `SmrtClassOptions.persistence` alias so\n * callers can pass the same options shape they use for SmrtObject/Collection.\n *\n * @deprecated Prefer `db`. Retained for parity with `SmrtClassOptions`.\n */\n persistence?: DatabaseConfig;\n\n /**\n * AI client configuration for AI-generated thumbnails\n */\n ai?: AIClientOptions | AIClient;\n}\n\ninterface ImageGenerationClient {\n generateImage(\n prompt: string,\n options?: Record<string, unknown>,\n ): Promise<{\n images?: Array<{ data?: Buffer | string }>;\n }>;\n}\n\nfunction isImageGenerationClient(\n value: AIClientOptions | AIClient,\n): value is AIClient & ImageGenerationClient {\n return (\n !!value &&\n typeof value === 'object' &&\n typeof (value as Record<string, unknown>).generateImage === 'function'\n );\n}\n\nfunction isAIClientOptions(\n value: AIClientOptions | AIClient,\n): value is AIClientOptions {\n return (\n !!value && typeof value === 'object' && !isImageGenerationClient(value)\n );\n}\n\n/**\n * ThumbnailGenerator creates thumbnails for content using various strategies\n */\nexport class ThumbnailGenerator {\n constructor(\n private content: Content,\n private options: ThumbnailGeneratorOptions = {},\n ) {\n // Normalize the `persistence` alias to `db` once so every downstream call\n // (prompt resolution, ImageCollection.create, save sites) sees the same\n // database regardless of which option name the caller used. Without this,\n // a caller passing `persistence: ...` would have prompt resolution honor\n // the alias while image saving silently used `undefined`.\n if (!this.options.db && this.options.persistence) {\n this.options.db = this.options.persistence;\n }\n }\n\n /**\n * Generate a thumbnail using the specified strategy\n */\n async generate(options: ThumbnailOptions): Promise<Image> {\n switch (options.strategy) {\n case 'headline-card':\n return this.generateHeadlineCard(options);\n case 'static-map':\n return this.generateStaticMap(options);\n case 'ai-generate':\n return this.generateWithAI(options);\n default:\n throw new Error(\n // `options` is narrowed to `never` here (exhaustive switch); read the\n // runtime discriminant through a minimal structural view.\n `Unknown thumbnail strategy: ${(options as { strategy: string }).strategy}`,\n );\n }\n }\n\n /**\n * Generate a headline card thumbnail\n */\n private async generateHeadlineCard(\n options: HeadlineCardThumbnailOptions,\n ): Promise<Image> {\n const title = this.content.title || this.content.name || 'Untitled';\n\n const result = await generateHeadlineCard(title, {\n width: options.width ?? 1200,\n height: options.height ?? 630,\n brandColor: options.brandColor,\n backgroundColor: options.backgroundColor,\n subtitle: options.subtitle ?? this.content.category ?? undefined,\n logoUrl: options.logoUrl,\n template: options.template,\n });\n\n return this.createImageFromBuffer(result.buffer, {\n width: result.width,\n height: result.height,\n mimeType: result.mimeType,\n name: `${this.content.id}-headline.png`,\n });\n }\n\n /**\n * Generate a static map thumbnail\n */\n private async generateStaticMap(\n options: StaticMapThumbnailOptions,\n ): Promise<Image> {\n // Coordinates live in the loose `metadata` bag (typed `unknown` values);\n // read them at a documented `string | number` boundary for arithmetic.\n const coordinateMetadata = this.content.metadata as Record<\n string,\n string | number | null | undefined\n >;\n const rawLatitude = coordinateMetadata?.latitude ?? coordinateMetadata?.lat;\n const rawLongitude =\n coordinateMetadata?.longitude ??\n coordinateMetadata?.lng ??\n coordinateMetadata?.lon;\n\n if (rawLatitude == null || rawLongitude == null) {\n throw new Error(\n 'Content metadata must contain latitude and longitude for static-map strategy',\n );\n }\n\n // Parse and validate coordinates\n // Use unary + for strict parsing (rejects \"45invalid\" unlike parseFloat)\n const latitude =\n typeof rawLatitude === 'string' ? +rawLatitude : rawLatitude;\n const longitude =\n typeof rawLongitude === 'string' ? +rawLongitude : rawLongitude;\n\n if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90) {\n throw new Error(\n `Invalid latitude value \"${rawLatitude}\" in content metadata; expected a number between -90 and 90.`,\n );\n }\n\n if (!Number.isFinite(longitude) || longitude < -180 || longitude > 180) {\n throw new Error(\n `Invalid longitude value \"${rawLongitude}\" in content metadata; expected a number between -180 and 180.`,\n );\n }\n\n type FetchStaticMapOptions = NonNullable<\n Parameters<typeof fetchStaticMap>[2]\n >;\n const mapboxStyle = options.mapboxStyle as\n | FetchStaticMapOptions['mapboxStyle']\n | undefined;\n\n const result = await fetchStaticMap(latitude, longitude, {\n provider: options.mapProvider ?? 'mapbox',\n width: options.width ?? 1200,\n height: options.height ?? 630,\n zoom: options.zoom ?? 14,\n markerColor: options.markerColor,\n mapboxStyle,\n googleMapType: options.googleMapType,\n });\n\n return this.createImageFromBuffer(result.buffer, {\n width: result.width,\n height: result.height,\n mimeType: result.mimeType,\n name: `${this.content.id}-map.png`,\n });\n }\n\n /**\n * Generate a thumbnail using AI image generation\n */\n private async generateWithAI(\n options: AIGenerateThumbnailOptions,\n ): Promise<Image> {\n // Dynamic import to avoid requiring AI package when not using this strategy\n const { getAI } = await import('@happyvertical/ai');\n\n const aiInput = options.ai ?? this.options.ai;\n if (!aiInput) {\n throw new Error(\n 'AI configuration required for ai-generate strategy. Provide via options.ai or constructor options.',\n );\n }\n\n const ai = isImageGenerationClient(aiInput)\n ? aiInput\n : isAIClientOptions(aiInput)\n ? await getAI(aiInput)\n : (() => {\n throw new Error(\n 'AI client does not support image generation for ai-generate thumbnails.',\n );\n })();\n\n // Generate prompt if not provided. When the caller supplies a literal\n // prompt we skip prompt resolution entirely (no tenant override path).\n // When we resolve from the registry we also forward the resolved AI\n // options (model, params) so `editable: { model, params }` actually\n // takes effect for thumbnail generation.\n const width = options.width ?? 1200;\n const height = options.height ?? 630;\n let prompt: string;\n let aiOverrideOptions: Record<string, unknown> = {};\n if (options.prompt) {\n prompt = options.prompt;\n } else {\n const built = await this.buildAIPrompt(options.style ?? 'photorealistic');\n prompt = built.text;\n aiOverrideOptions = promptMessageOptions(built.ai);\n }\n\n const result = await ai.generateImage(prompt, {\n ...aiOverrideOptions,\n size: `${width}x${height}`,\n outputFormat: 'buffer',\n });\n\n if (!result.images || result.images.length === 0) {\n throw new Error('AI image generation returned no results');\n }\n\n // Handle buffer or base64 responses\n let buffer: Buffer;\n const imageData = result.images[0].data;\n if (Buffer.isBuffer(imageData)) {\n buffer = imageData;\n } else if (typeof imageData === 'string') {\n // Could be base64 or URL - try base64 first\n if (imageData.startsWith('http')) {\n const response = await fetch(imageData);\n if (!response.ok) {\n throw new Error(\n `AI image generation URL fetch failed: ${response.status} ${response.statusText}`,\n );\n }\n buffer = Buffer.from(await response.arrayBuffer());\n } else {\n buffer = Buffer.from(imageData, 'base64');\n }\n } else {\n throw new Error('AI image generation returned unexpected format');\n }\n\n return this.createImageFromBuffer(buffer, {\n width: options.width ?? 1200,\n height: options.height ?? 630,\n mimeType: 'image/png',\n name: `${this.content.id}-ai.png`,\n });\n }\n\n /**\n * Build a prompt for AI image generation based on content.\n *\n * Resolves via `@happyvertical/smrt-prompts` so tenants can override the\n * template/profile/model/params at runtime. Only non-PII content fields\n * (title, description) and the caller-supplied style hint are passed.\n * Internal IDs and the freeform `metadata` blob are intentionally excluded.\n *\n * Returns the full ResolvedPrompt (text + ai config) so the caller can\n * forward `model`/`params` overrides to `ai.generateImage()`. Returning\n * only the text would silently drop the editable model/params overrides.\n */\n private async buildAIPrompt(style: string): Promise<ResolvedPrompt> {\n const title = this.content.title || 'Untitled';\n const description = this.content.description || '';\n\n const stylePrompts: Record<string, string> = {\n photorealistic:\n 'photorealistic, high quality, professional photography, 8k resolution',\n illustration:\n 'digital illustration, clean vector art, modern design, vibrant colors',\n abstract:\n 'abstract art, geometric shapes, modern minimalist, artistic interpretation',\n minimal:\n 'minimalist design, simple shapes, clean composition, subtle colors',\n };\n\n const styleHint = stylePrompts[style] || stylePrompts.photorealistic;\n\n return resolvePrompt(smrtContentThumbnailAIGeneratePrompt.key, {\n db: this.options.db,\n tenantId: this.content.tenantId,\n variables: {\n style,\n title,\n styleHint,\n descriptionClause: description\n ? `The article is about: ${description}. `\n : '',\n },\n });\n }\n\n /**\n * Create an Image object from a buffer\n */\n private async createImageFromBuffer(\n buffer: Buffer,\n metadata: {\n width: number;\n height: number;\n mimeType: string;\n name: string;\n },\n ): Promise<Image> {\n const images = await ImageCollection.create({\n db: this.options.db,\n });\n\n // Create the image record. `SmrtCollection.create()` already persists\n // (upsert) the row, so a follow-up `image.save()` was redundant (#1387).\n const image = await images.create({\n name: metadata.name,\n mimeType: metadata.mimeType,\n width: metadata.width,\n height: metadata.height,\n sourceUri: `data:${metadata.mimeType};base64,${buffer.toString('base64')}`,\n });\n\n return image;\n }\n}\n","import { type Asset, AssetCollection } from '@happyvertical/smrt-assets';\nimport type {\n SmrtObjectOptions,\n SmrtSaveOptions,\n} from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport type {\n Fact,\n FactClaimSupportAssessment,\n FactClaimSupportStatus,\n FactContent,\n FactContentRelationship,\n FactEvidence,\n FactEvidenceStatus,\n FactExtractionCandidate,\n FactSource,\n} from '@happyvertical/smrt-facts';\nimport type { Image } from '@happyvertical/smrt-images';\nimport { ImageCollection } from '@happyvertical/smrt-images';\nimport { resolvePrompt } from '@happyvertical/smrt-prompts';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { AssetAssociable, MetadataAccessor } from './asset-associable';\nimport { isPlainMetadataRecord } from './asset-associable';\nimport type { ContentBodyFormat } from './body-format';\nimport { isContentBodyFormat } from './body-format';\nimport { ContentAssetCollection } from './content-assets';\nimport {\n buildContentGovernanceAssignmentKey,\n buildContentReviewPrompt,\n type ContentGovernanceState,\n type ContentReviewFinding,\n type ContentReviewProfileEvaluation,\n type CreateContentVersionOptions,\n getAcceptedContentReviewStatuses,\n getContentReviewKind,\n getContentReviewPolicy,\n getContentReviewProfileKeys,\n getContentReviewRequirements,\n type IssueContentCorrectionOptions,\n parseContentReviewResponse,\n type ResolvedContentGovernance,\n type RunContentReviewOptions,\n resolveConfiguredContentGovernance,\n resolveEffectiveContentGovernance,\n} from './content-governance';\nimport {\n promptMessageOptions,\n smrtContentApplyCorrectionPrompt,\n smrtContentReviewPrompt,\n} from './content-prompts';\nimport { ContentReferences } from './content-references';\nimport type { ContentReview } from './content-review';\nimport { normalizeContentTransparency } from './content-transparency';\nimport { isMissingTableError } from './database-utils';\nimport {\n serializeContent,\n serializeContentCorrection,\n serializeContentReview,\n serializeContentVersion,\n serializeFact,\n serializeFactLink,\n} from './serialization';\nimport type { ThumbnailOptions } from './thumbnail-generator';\nimport { ThumbnailGenerator } from './thumbnail-generator';\n\nconst USED_FACT_RELATIONSHIPS = new Set<FactContentRelationship>([\n 'supports',\n 'referenced_in',\n 'contradicts',\n]);\nconst FACT_AUDIT_GENERATED_BY = 'content.factAudit';\nconst FACT_AUDIT_DOMAIN = 'content-audit';\n\ntype FactAuditSourceMaterial = {\n sourceKind: string;\n sourceId: string;\n sourceUrl: string;\n sourceTitle: string;\n locator: string;\n text: string;\n};\n\ntype FactAuditSourceSelector = {\n sourceKind: string;\n sourceId: string;\n};\n\ntype FactAuditResourceRepairOptions = {\n sources?: FactAuditSourceSelector[];\n maxFactsPerSource?: number;\n context?: string;\n};\n\ntype FactAuditClaimRecheckOptions = {\n claimFactIds?: string[];\n sourceIds?: string[];\n sources?: FactAuditSourceSelector[];\n maxCandidateEvidence?: number;\n};\n\ntype FactEvidenceStatusUpdateOptions = {\n evidenceIds?: string[];\n status?: FactEvidenceStatus;\n reason?: string;\n};\n\ntype FactAuditClaim = {\n id: string | null;\n fact: Record<string, unknown>;\n supportStatus: FactClaimSupportStatus;\n claimQuote: string | null;\n rationale: string | null;\n confidence: number | null;\n relationship: string | null;\n linkMetadata: Record<string, unknown>;\n evidence: Record<string, unknown>[];\n matchedFacts: Array<{\n fact: Record<string, unknown>;\n evidence: Record<string, unknown>[];\n }>;\n};\n\ntype FactAuditResourceClaim = {\n id: string | null;\n fact: Record<string, unknown>;\n sourceKind: string | null;\n sourceId: string | null;\n sourceUrl: string | null;\n sourceTitle: string | null;\n locator: string | null;\n quote: string | null;\n status: FactEvidenceStatus;\n confidence: number | null;\n evidence: Record<string, unknown>[];\n};\n\n/**\n * Minimal structural view of a metadata-bearing SMRT record (fact link,\n * fact, evidence, source, version, review, correction). The fact-audit and\n * transparency code paths interact with these entities loosely via their\n * accessor methods rather than importing the concrete cross-package classes\n * (which would create circular dependencies). `getMetadata`/`setMetadata`\n * are optional because some paths receive plain serialized records.\n */\ninterface MetadataBearer {\n getMetadata?: () => Record<string, unknown>;\n setMetadata?: (metadata: Record<string, unknown>) => void;\n updateMetadata?: (patch: Record<string, unknown>) => unknown;\n metadata?: unknown;\n}\n\n/**\n * Structural view of a content↔fact link as consumed by the fact-audit\n * pipeline. Backed by `FactContent` from `@happyvertical/smrt-facts`.\n */\ninterface FactAuditLinkLike extends MetadataBearer {\n factId?: string | null;\n relationship?: string | null;\n save?: () => Promise<unknown>;\n delete?: () => Promise<unknown>;\n}\n\n/**\n * Structural view of a fact-evidence record as consumed by the fact-audit\n * pipeline. Backed by `FactEvidence` from `@happyvertical/smrt-facts`.\n */\ninterface FactAuditEvidenceLike extends MetadataBearer {\n id?: string | null;\n factId?: string | null;\n status?: string | null;\n sourceKind?: string | null;\n sourceId?: string | null;\n sourceUrl?: string | null;\n sourceTitle?: string | null;\n locator?: string | null;\n quote?: string | null;\n confidence?: number | null;\n evidenceKey?: string | null;\n tenantId?: string | null;\n delete?: () => Promise<unknown>;\n}\n\n/**\n * Structural view of a fact-source record as consumed by the fact-audit\n * pipeline. Backed by `FactSource` from `@happyvertical/smrt-facts`.\n */\ninterface FactAuditSourceLike extends MetadataBearer {\n id?: string | null;\n sourceType?: string | null;\n delete?: () => Promise<unknown>;\n}\n\n/**\n * Loosely-read extra fields the fact-audit source scanner probes on an\n * {@link Asset}. These are not declared `Asset` fields (assets vary by\n * provider); they are read defensively and normalized via `normalizeAuditText`.\n */\ninterface FactAuditAssetExtraFields {\n text?: unknown;\n body?: unknown;\n title?: unknown;\n filename?: unknown;\n url?: unknown;\n sourceUrl?: unknown;\n fileKey?: unknown;\n}\n\n/**\n * Structural view of a support candidate carried through claim assessment.\n * The `evidence` array holds the serialized evidence summaries built in\n * {@link Content.getCurrentFactAuditSupportCandidates}.\n */\ninterface FactAuditSupportCandidate {\n id: string;\n statement: string;\n evidence: Array<{ id?: string | null; [key: string]: unknown }>;\n}\n\n/**\n * Loose view of a serialized record produced by the `serialize*` helpers\n * (which return index-signature records that erase named keys at the type\n * level). Adds back the few keys the transparency snapshot reads while keeping\n * the rest as `unknown`.\n */\ninterface SerializedRecord {\n id?: string | null;\n status?: unknown;\n usedInArticle?: boolean;\n metadata?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * Transient, non-persisted fields synchronized into junction links during\n * `save()`. They are attached dynamically from constructor options rather\n * than declared as ORM-managed fields, so callers narrow `this` to this\n * shape instead of reaching in untyped.\n */\ninterface ContentTransientLinkIds {\n referenceIds?: string[];\n assetIds?: string[];\n}\n\ntype FactAuditState = {\n counts: Record<FactClaimSupportStatus | 'total', number>;\n claims: FactAuditClaim[];\n resourceClaims: FactAuditResourceClaim[];\n warnings: string[];\n generatedBy: string;\n latestAuditRunId: string | null;\n};\n\nfunction normalizeFingerprintValue(value: unknown): unknown {\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => normalizeFingerprintValue(entry));\n }\n\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entryValue]) => [\n key,\n normalizeFingerprintValue(entryValue),\n ]),\n );\n }\n\n return value ?? null;\n}\n\nfunction hashFingerprint(input: string): string {\n let hash = 5381;\n\n for (let index = 0; index < input.length; index += 1) {\n hash = (hash * 33) ^ input.charCodeAt(index);\n }\n\n return `fp-${(hash >>> 0).toString(16).padStart(8, '0')}`;\n}\n\nfunction createFingerprint(value: unknown): string {\n return hashFingerprint(JSON.stringify(normalizeFingerprintValue(value)));\n}\n\nfunction normalizeAuditText(value: unknown): string {\n return String(value ?? '')\n .trim()\n .replace(/\\s+/g, ' ');\n}\n\n/**\n * Extract a human-readable message from an unknown caught value. Mirrors the\n * previous `error.message || error` template interpolation without relying on\n * an `any`-typed catch binding.\n */\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (\n error &&\n typeof error === 'object' &&\n 'message' in error &&\n typeof (error as { message?: unknown }).message === 'string'\n ) {\n return (error as { message: string }).message;\n }\n return String(error);\n}\n\nfunction createFactAuditRunId(contentId: string): string {\n return `fact-audit-${hashFingerprint(\n `${contentId}:${new Date().toISOString()}:${Math.random()}`,\n )}`;\n}\n\nfunction parseAuditMetadata(value: unknown): Record<string, unknown> {\n if (!value) return {};\n if (typeof value === 'object') return value as Record<string, unknown>;\n try {\n return JSON.parse(String(value)) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nfunction getLinkMetadata(link: MetadataBearer): Record<string, unknown> {\n return typeof link?.getMetadata === 'function' ? link.getMetadata() : {};\n}\n\nfunction getFactMetadata(fact: MetadataBearer): Record<string, unknown> {\n return typeof fact?.getMetadata === 'function'\n ? fact.getMetadata()\n : parseAuditMetadata(fact?.metadata);\n}\n\nfunction getGeneratedFactAuditMetadata(\n link: MetadataBearer,\n): Record<string, unknown> | null {\n const metadata = getLinkMetadata(link);\n if (metadata.generatedBy === FACT_AUDIT_GENERATED_BY) {\n return metadata;\n }\n\n const nested = metadata.factAudit;\n if (\n nested &&\n typeof nested === 'object' &&\n (nested as Record<string, unknown>).generatedBy === FACT_AUDIT_GENERATED_BY\n ) {\n return nested as Record<string, unknown>;\n }\n\n return null;\n}\n\nfunction getEvidenceMetadata(\n evidence: MetadataBearer,\n): Record<string, unknown> {\n return typeof evidence?.getMetadata === 'function'\n ? evidence.getMetadata()\n : parseAuditMetadata(evidence?.metadata);\n}\n\nfunction isGeneratedFactAuditEvidence(\n evidence: MetadataBearer,\n contentId: string,\n): boolean {\n const metadata = getEvidenceMetadata(evidence);\n return (\n metadata.generatedBy === FACT_AUDIT_GENERATED_BY &&\n metadata.contentId === contentId\n );\n}\n\nfunction isGeneratedArticleClaimFact(\n fact: MetadataBearer,\n contentId: string,\n): boolean {\n const metadata = getFactMetadata(fact);\n if (metadata.generatedBy !== FACT_AUDIT_GENERATED_BY) {\n return false;\n }\n\n const role = metadata.auditFactRole || metadata.factAuditRole;\n const isArticleClaim =\n role === 'article-claim' || metadata.claimOnly === true;\n\n return isArticleClaim && metadata.contentId === contentId;\n}\n\nfunction normalizeFactEvidenceStatus(\n value: unknown,\n): FactEvidenceStatus | null {\n const allowed: FactEvidenceStatus[] = [\n 'supports',\n 'contradicts',\n 'unclear',\n 'irrelevant',\n 'invalid',\n ];\n\n return allowed.includes(value as FactEvidenceStatus)\n ? (value as FactEvidenceStatus)\n : null;\n}\n\nfunction sourceMatchesSelector(\n source: FactAuditSourceMaterial,\n selector: FactAuditSourceSelector,\n): boolean {\n return (\n source.sourceKind === selector.sourceKind &&\n source.sourceId === selector.sourceId\n );\n}\n\nfunction filterAuditSources(\n sources: FactAuditSourceMaterial[],\n selectors: FactAuditSourceSelector[] | undefined,\n): FactAuditSourceMaterial[] {\n if (!selectors || selectors.length === 0) {\n return sources;\n }\n\n return sources.filter((source) =>\n selectors.some((selector) => sourceMatchesSelector(source, selector)),\n );\n}\n\nfunction getContentText(content: Content): string {\n return [content.title, content.description, content.body]\n .map(normalizeAuditText)\n .filter(Boolean)\n .join('\\n\\n');\n}\n\nfunction readNestedString(\n source: Record<string, unknown>,\n path: string[],\n): string | null {\n let current: unknown = source;\n for (const key of path) {\n if (!current || typeof current !== 'object') {\n return null;\n }\n current = (current as Record<string, unknown>)[key];\n }\n return typeof current === 'string' && current ? current : null;\n}\n\n/**\n * Coerce an unknown value into a plain record. Objects pass through; JSON\n * strings are parsed (falling back to `{}` on failure); anything else yields\n * an empty record. Used to read loosely-typed `metadata` fields that may be\n * stored either as parsed objects or JSON strings.\n */\nfunction asRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n }\n return {};\n}\n\n/**\n * Walk a nested record path, returning the record at the end of the path or\n * an empty record if any segment is missing/non-record-shaped.\n */\nfunction readNestedRecord(\n source: Record<string, unknown>,\n path: string[],\n): Record<string, unknown> {\n let current: unknown = source;\n for (const key of path) {\n if (!current || typeof current !== 'object') {\n return {};\n }\n current = (current as Record<string, unknown>)[key];\n }\n return asRecord(current);\n}\n\nfunction getPublicPrompt(metadata: Record<string, unknown>): string | null {\n return (\n readNestedString(metadata, [\n 'transparency',\n 'generation',\n 'publicPrompt',\n ]) ||\n readNestedString(metadata, ['generation', 'publicPrompt']) ||\n readNestedString(metadata, ['publicPrompt']) ||\n null\n );\n}\n\n/**\n * Options for Content initialization\n */\nexport interface ContentOptions extends SmrtObjectOptions {\n /**\n * Content type classification\n */\n type?: string | null;\n\n /**\n * Content variant for namespaced classification within types\n * Format: generator:domain:specific-type\n * Example: \"praeco:meeting:upcoming\"\n */\n variant?: string | null;\n\n /**\n * Reference to file storage key\n */\n fileKey?: string | null;\n\n /**\n * Author of the content\n */\n author?: string | null;\n\n /**\n * Content title\n */\n title?: string | null;\n\n /**\n * Short description or summary\n */\n description?: string | null;\n\n /**\n * Main content body text\n */\n body?: string | null;\n\n /**\n * Stored body format.\n */\n bodyFormat?: ContentBodyFormat | null;\n\n /**\n * Date when content was published\n */\n publish_date?: Date | null;\n\n /**\n * URL source of the content\n */\n url?: string | null;\n\n /**\n * Original source identifier\n */\n source?: string | null;\n\n /**\n * Publication status\n */\n status?: 'published' | 'draft' | 'review' | 'archived' | 'deleted' | null;\n\n /**\n * Content state flag\n */\n state?: 'deprecated' | 'active' | 'highlighted' | null;\n\n /**\n * Original URL of the content\n */\n original_url?: string | null;\n\n /**\n * Content language\n */\n language?: string | null;\n\n /**\n * Content tags\n */\n tags?: string[];\n\n /**\n * Hierarchical category path for URL routing\n * Format: 'parent/child' (e.g., 'politics/local')\n * Each content belongs to exactly ONE category\n */\n category?: string | null;\n\n /**\n * Additional metadata\n */\n metadata?: Record<string, unknown>;\n\n /**\n * ID of the thumbnail asset for this content\n */\n thumbnailAssetId?: string | null;\n\n /**\n * Transient reference IDs used by editors and API payloads.\n * These are synchronized into ContentReference links during save.\n */\n referenceIds?: string[];\n\n /**\n * Transient asset IDs used by editors and API payloads.\n */\n assetIds?: string[];\n\n /**\n * Tenant ID for multi-tenant isolation\n */\n tenantId?: string | null;\n}\n\n/**\n * Structured content object with metadata and body text\n *\n * Content represents any text-based content with metadata such as\n * title, author, description, and publishing information. It supports\n * referencing related content objects.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: {\n include: [\n 'list',\n 'get',\n 'create',\n 'update',\n 'delete',\n 'getFactsState',\n 'syncFactsState',\n 'getFactAuditStateAction',\n 'repairFactAuditAction',\n 'repairFactEvidenceAction',\n 'recheckFactClaimsAction',\n 'updateFactEvidenceStatusAction',\n 'getGovernanceStateAction',\n 'listReviews',\n 'runReviewAction',\n 'listReviewProfilesAction',\n 'evaluateReviewProfileAction',\n 'getPublishedTransparencyAction',\n 'previewTransparencyAction',\n 'listCorrections',\n 'issueCorrectionAction',\n 'listVersions',\n 'mutateVersionAction',\n ],\n routes: {\n getFactsState: { method: 'GET', path: 'facts' },\n syncFactsState: { method: 'PUT', path: 'facts' },\n getFactAuditStateAction: { method: 'GET', path: 'fact-audit' },\n repairFactAuditAction: { method: 'POST', path: 'fact-audit/repair' },\n repairFactEvidenceAction: {\n method: 'POST',\n path: 'fact-audit/evidence/repair',\n },\n recheckFactClaimsAction: {\n method: 'POST',\n path: 'fact-audit/claims/recheck',\n },\n updateFactEvidenceStatusAction: {\n method: 'PUT',\n path: 'fact-audit/evidence/status',\n },\n getGovernanceStateAction: { method: 'GET', path: 'governance' },\n listReviews: { method: 'GET', path: 'reviews' },\n runReviewAction: { method: 'POST', path: 'reviews' },\n listReviewProfilesAction: { method: 'GET', path: 'review-profiles' },\n evaluateReviewProfileAction: {\n method: 'GET',\n path: 'review-profiles/[profileKey]',\n },\n getPublishedTransparencyAction: {\n method: 'GET',\n path: 'transparency',\n },\n previewTransparencyAction: {\n method: 'GET',\n path: 'transparency/preview',\n },\n listCorrections: { method: 'GET', path: 'corrections' },\n issueCorrectionAction: { method: 'POST', path: 'corrections' },\n listVersions: { method: 'GET', path: 'versions' },\n mutateVersionAction: { method: 'POST', path: 'versions' },\n },\n serializers: {\n item: {\n importPath: '$lib/server/content-api-serializers',\n exportName: 'serializeContent',\n },\n },\n },\n mcp: {\n include: ['list', 'get', 'create', 'update'], // AI tools for content management\n },\n cli: true, // Enable CLI commands for content management\n // Content's own list pages sort by publish date inside a tenant, not by\n // `created_at`, so the generated `(tenant_id, created_at)` ordering index\n // (#2363) does not serve them — this is the second access path on the same\n // table and it has to be declared (#2357, measured in #2340). Declared\n // indexes are appended before the automatic passes, so this one also stands\n // in for the standalone `contents_tenant_id_idx` (#2359): a btree serves\n // every prefix of its column list.\n indexes: [\n {\n name: 'contents_tenant_id_publish_date_idx',\n columns: ['tenantId', 'publish_date'],\n },\n ],\n})\nexport class Content\n extends SmrtObject\n implements AssetAssociable, MetadataAccessor<Record<string, unknown>>\n{\n /**\n * Tenant ID for multi-tenant isolation\n * Nullable to support both tenant-scoped and global content\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Array of referenced content objects\n */\n protected references: Content[] = [];\n\n /**\n * Content type classification\n */\n public type: string | null = null;\n\n /**\n * Content variant for namespaced classification within types\n * Format: generator:domain:specific-type\n * Example: \"praeco:meeting:upcoming\"\n */\n public variant: string | null = null;\n\n /**\n * Reference to file storage key\n */\n public fileKey: string | null = null;\n\n /**\n * Author of the content\n */\n public author: string | null = null;\n\n /**\n * Human-readable name for SMRT framework compatibility\n */\n @field({ required: true })\n public name: string = '';\n\n /**\n * Content title\n */\n public title = '';\n\n /**\n * Short description or summary\n */\n public description: string | null = null;\n\n /**\n * Main content body text\n */\n public body = '';\n\n /**\n * Format used to persist the body field.\n */\n public bodyFormat: ContentBodyFormat | null = null;\n\n /**\n * Date when content was published\n */\n public publish_date: Date | null = null;\n\n /**\n * URL source of the content\n */\n public url: string | null = null;\n\n /**\n * Original source identifier\n */\n public source: string | null = null;\n\n /**\n * Original URL of the content\n */\n public original_url: string | null = null;\n\n /**\n * Content language\n */\n public language: string | null = null;\n\n /**\n * Content tags\n */\n public tags: string[] = [];\n\n /**\n * Hierarchical category path for URL routing\n * Format: 'parent/child' (e.g., 'politics/local')\n * Each content belongs to exactly ONE category\n */\n public category: string | null = null;\n\n /**\n * Publication status\n */\n public status: 'published' | 'draft' | 'review' | 'archived' | 'deleted' =\n 'draft';\n\n /**\n * Content state flag\n */\n public state: 'deprecated' | 'active' | 'highlighted' = 'active';\n\n /**\n * Additional JSON metadata for flexible schema extension\n */\n public metadata: Record<string, unknown> = {};\n\n /**\n * ID of the thumbnail asset for this content\n */\n @crossPackageRef('@happyvertical/smrt-assets:Asset')\n public thumbnailAssetId: string | null = null;\n\n /**\n * Creates a new Content instance\n */\n constructor(options: ContentOptions = {}) {\n super(options);\n this.type = options.type || null;\n this.variant = options.variant || null;\n this.fileKey = options.fileKey || null;\n this.author = options.author || null;\n if (options.name) this.name = options.name;\n this.title = options.title || '';\n this.description = options.description || null;\n this.body = options.body || '';\n this.bodyFormat = isContentBodyFormat(options.bodyFormat)\n ? options.bodyFormat\n : null;\n this.publish_date = options.publish_date || null;\n this.source = options.source || null;\n this.original_url = options.original_url || null;\n this.language = options.language || null;\n this.status = options.status || 'draft';\n this.tags = options.tags || [];\n this.category = options.category || null;\n this.state = options.state || 'active';\n this.metadata = options.metadata || {};\n this.thumbnailAssetId = options.thumbnailAssetId ?? null;\n const transient = this as Content & ContentTransientLinkIds;\n if (Array.isArray(options.referenceIds)) {\n transient.referenceIds = [...options.referenceIds];\n }\n if (Array.isArray(options.assetIds)) {\n transient.assetIds = [...options.assetIds];\n }\n }\n\n /**\n * Initializes this content object\n *\n * @returns Promise that resolves to this instance\n */\n async initialize(): Promise<this> {\n await super.initialize();\n return this;\n }\n\n protected override async validateBeforeSave(): Promise<void> {\n if (!this.name && this.title) {\n this.name = this.title;\n }\n\n if (!this.title && this.name) {\n this.title = this.name;\n }\n\n await super.validateBeforeSave();\n\n if (this.status !== 'published') {\n return;\n }\n\n const governance = await this.resolvePublicationGovernance();\n const profileKey = governance?.publicationProfileKey;\n\n if (\n !governance?.isGoverned ||\n !governance.enforcePublishReadiness ||\n !profileKey\n ) {\n return;\n }\n\n const evaluation = await this.evaluateReviewProfile(profileKey);\n const blockingRequirements = evaluation.requirements.filter(\n (requirement) => requirement.blocking && !requirement.satisfied,\n );\n\n if (blockingRequirements.length === 0) {\n return;\n }\n\n const details = blockingRequirements.map((requirement) => {\n if (requirement.missing) {\n return `${requirement.label} has not been run yet`;\n }\n\n if (requirement.stale) {\n return `${requirement.label} is stale and must be rerun`;\n }\n\n if (requirement.latestStatus) {\n return `${requirement.label} returned ${requirement.latestStatus}`;\n }\n\n return `${requirement.label} is not satisfied`;\n });\n\n throw new ValidationError(\n `Cannot publish content until the \"${profileKey}\" review profile is satisfied. ${details.join('; ')}`,\n 'VALIDATION_PUBLISH_READINESS',\n {\n profileKey,\n blockingRequirements: blockingRequirements.map((requirement) => ({\n policyKey: requirement.policyKey,\n label: requirement.label,\n missing: requirement.missing,\n stale: requirement.stale,\n latestStatus: requirement.latestStatus,\n })),\n },\n );\n }\n\n override async save(options: SmrtSaveOptions = {}) {\n const shouldConsiderPublicationSnapshot = this.status === 'published';\n\n let governance: ResolvedContentGovernance | null = null;\n let previous: Content | null = null;\n let previousPublicationFingerprint: string | null = null;\n\n if (shouldConsiderPublicationSnapshot) {\n governance = await this.resolvePublicationGovernance();\n\n if (governance?.isGoverned && governance.transparencyEnabled) {\n previous = await this.getPersistedContent();\n previousPublicationFingerprint =\n await this.getLatestPublicationSnapshotFingerprint();\n }\n }\n\n await super.save(options);\n await this.syncPendingReferenceIds();\n await this.syncPendingAssetIds();\n\n if (\n !shouldConsiderPublicationSnapshot ||\n !governance?.isGoverned ||\n !governance.transparencyEnabled\n ) {\n return this;\n }\n\n const nextPublicationFingerprint =\n await this.buildPublicationSnapshotFingerprint(governance);\n\n if (\n nextPublicationFingerprint &&\n nextPublicationFingerprint !== previousPublicationFingerprint\n ) {\n await this.createVersion({\n kind: 'publication',\n summary:\n previous?.status === 'published'\n ? 'Published content updated.'\n : 'Content published.',\n metadata: {\n publicationSnapshotFingerprint: nextPublicationFingerprint,\n publicationProfileKey: governance.publicationProfileKey,\n transparency: await this.buildTransparencySnapshot({\n snapshotKind: 'published',\n governance,\n }),\n },\n });\n }\n\n return this;\n }\n\n private async getReferenceCollection() {\n return ContentReferences.create({ db: this.db });\n }\n\n private async getFactCollection() {\n const { FactCollection } = await import('@happyvertical/smrt-facts');\n return FactCollection.create(this.options);\n }\n\n private async getFactContentCollection() {\n const { FactContentCollection } = await import('@happyvertical/smrt-facts');\n return FactContentCollection.create(this.options);\n }\n\n private async getFactSourceCollection() {\n const { FactSourceCollection } = await import('@happyvertical/smrt-facts');\n return FactSourceCollection.create(this.options);\n }\n\n private async getFactEvidenceCollection() {\n const { FactEvidenceCollection } = await import(\n '@happyvertical/smrt-facts'\n );\n return FactEvidenceCollection.create(this.options);\n }\n\n private async getContentVersionCollection() {\n const { ContentVersionCollection } = await import('./content-versions');\n return ContentVersionCollection.create(this.options);\n }\n\n private async getContentReviewCollection() {\n const { ContentReviewCollection } = await import('./content-reviews');\n return ContentReviewCollection.create(this.options);\n }\n\n private async getContentCorrectionCollection() {\n const { ContentCorrectionCollection } = await import(\n './content-corrections'\n );\n return ContentCorrectionCollection.create(this.options);\n }\n\n private async getContentsCollection() {\n const { Contents } = await import('./contents');\n return Contents.create({ db: this.db });\n }\n\n private getConfiguredGovernance(): ResolvedContentGovernance {\n return resolveConfiguredContentGovernance({\n contentType: this.type,\n contentVariant: this.variant,\n });\n }\n\n public async resolveGovernance(): Promise<ResolvedContentGovernance> {\n return resolveEffectiveContentGovernance({\n contentType: this.type,\n contentVariant: this.variant,\n db: this.db,\n tenantId: this.tenantId ?? null,\n });\n }\n\n private async hasPersistedGovernanceAssignments(): Promise<boolean> {\n if (!this.db || typeof this.db.query !== 'function') {\n return false;\n }\n\n try {\n const exactKey = buildContentGovernanceAssignmentKey(\n this.type || '',\n this.variant || '',\n );\n const typeOnlyKey = buildContentGovernanceAssignmentKey(this.type || '');\n const keys =\n exactKey === typeOnlyKey ? [exactKey] : [exactKey, typeOnlyKey];\n const placeholders = keys.map(() => '?').join(', ');\n const result = await this.db.query(\n `SELECT 1 AS matched FROM content_governance_assignments WHERE key IN (${placeholders}) LIMIT 1`,\n keys,\n );\n const rows = Array.isArray(result) ? result : (result?.rows ?? []);\n return rows.length > 0;\n } catch {\n return false;\n }\n }\n\n private async resolvePublicationGovernance(): Promise<ResolvedContentGovernance | null> {\n const configuredGovernance = this.getConfiguredGovernance();\n\n if (configuredGovernance.isGoverned) {\n return this.resolveGovernance();\n }\n\n if (!(await this.hasPersistedGovernanceAssignments())) {\n return null;\n }\n\n const governance = await this.resolveGovernance();\n return governance.isGoverned ? governance : null;\n }\n\n private async requireGovernance(\n feature = 'governance workflow',\n ): Promise<ResolvedContentGovernance> {\n const governance = await this.resolveGovernance();\n\n if (!governance.isGoverned) {\n throw new Error(\n `Governance is not enabled for content type \"${this.type || 'content'}\"${this.variant ? ` variant \"${this.variant}\"` : ''}, so ${feature} is unavailable.`,\n );\n }\n\n return governance;\n }\n\n private async requireFactLinking(\n feature = 'fact linking',\n ): Promise<ResolvedContentGovernance> {\n const governance = await this.requireGovernance(feature);\n\n if (!governance.factLinkingEnabled) {\n throw new Error(\n `Fact linking is not enabled for content type \"${this.type || 'content'}\"${this.variant ? ` variant \"${this.variant}\"` : ''}.`,\n );\n }\n\n return governance;\n }\n\n private async getPersistedContent(): Promise<Content | null> {\n if (!this.id) {\n return null;\n }\n\n const contents = await this.getContentsCollection();\n return (await contents.get({ id: this.id as string })) as Content | null;\n }\n\n private async buildReviewFingerprint(policyKey: string): Promise<string> {\n const governance = await this.resolveGovernance();\n const kind = getContentReviewKind(policyKey, governance.reviewPolicies);\n const policy = getContentReviewPolicy(policyKey, governance.reviewPolicies);\n const [references, facts, factLinks] = await Promise.all([\n this.getReferences(),\n kind === 'facts' && governance.factLinkingEnabled\n ? this.getFacts({\n latestOnly: true,\n includeSuperseded: false,\n })\n : Promise.resolve([]),\n kind === 'facts' && governance.factLinkingEnabled\n ? this.getFactLinks()\n : Promise.resolve([]),\n ]);\n\n return createFingerprint({\n scope: 'content-review',\n policyKey,\n kind,\n policyInstructions: policy?.instructions || '',\n content: {\n id: this.id || null,\n type: this.type,\n variant: this.variant,\n title: this.title,\n description: this.description,\n body: this.body,\n author: this.author,\n state: this.state,\n publishDate: this.publish_date,\n language: this.language,\n category: this.category,\n tags: this.tags,\n metadata: this.metadata,\n },\n referenceIds: references\n .map((reference) => reference.id)\n .filter(Boolean)\n .sort(),\n facts: facts.map((fact) => ({\n id: fact.id || null,\n // Pre-R3-C this was `parentId`; renamed to `previousFactId` in\n // smrt-facts. Existing cached fingerprints will invalidate, which\n // is the correct behaviour — the review surface (a key in the\n // hash) changed.\n previousFactId: fact.previousFactId || null,\n status: fact.status || null,\n textRefined: fact.textRefined || '',\n sourceCount: fact.sourceCount ?? 0,\n confidence: fact.confidence ?? null,\n metadata:\n typeof fact?.getMetadata === 'function' ? fact.getMetadata() : {},\n })),\n factLinks: factLinks.map((link) => ({\n factId: link.factId || null,\n relationship: link.relationship || null,\n metadata:\n typeof link?.getMetadata === 'function' ? link.getMetadata() : {},\n })),\n });\n }\n\n private async buildTransparencySnapshot(\n options: {\n snapshotKind?: 'preview' | 'published';\n governance?: ResolvedContentGovernance;\n } = {},\n ) {\n const snapshotKind = options.snapshotKind || 'preview';\n const governance = options.governance || (await this.resolveGovernance());\n\n if (!governance.isGoverned || !governance.transparencyEnabled) {\n return null;\n }\n\n const [\n references,\n facts,\n factLinks,\n reviews,\n corrections,\n versions,\n reviewProfiles,\n ] = await Promise.all([\n this.getReferences(),\n governance.factLinkingEnabled\n ? this.getFacts({\n latestOnly: true,\n includeSuperseded: false,\n })\n : Promise.resolve([]),\n governance.factLinkingEnabled ? this.getFactLinks() : Promise.resolve([]),\n this.listReviews(),\n this.listCorrections(),\n this.listVersions(),\n this.listReviewProfilesAction(),\n ]);\n\n const factSources = await this.getFactSourceCollection();\n const factSourcesByFactId = new Map<string, FactSource[]>();\n\n for (const fact of facts) {\n const factId = fact.id as string | undefined;\n if (!factId) {\n continue;\n }\n\n const sources = await factSources.getForFact(factId);\n factSourcesByFactId.set(factId, sources);\n }\n\n const usedFactIds = new Set(\n factLinks\n .filter((link) =>\n USED_FACT_RELATIONSHIPS.has(\n (link.relationship || 'related') as FactContentRelationship,\n ),\n )\n .map((link) => link.factId)\n .filter(Boolean),\n );\n\n const linkedFacts = facts.map((fact) => {\n const factId = fact.id as string | undefined;\n const link = factLinks.find((entry) => entry.factId === factId);\n const sources = (factId ? factSourcesByFactId.get(factId) : []) || [];\n\n return {\n ...serializeFact(fact),\n relationship: link?.relationship || null,\n linkMetadata:\n typeof link?.getMetadata === 'function' ? link.getMetadata() : {},\n usedInArticle: factId ? usedFactIds.has(factId) : false,\n sources: sources.map((source) => ({\n id: source.id || null,\n sourceType: source.sourceType || null,\n sourceUrl: source.sourceUrl || null,\n sourceTitle: source.sourceTitle || null,\n credibility: source.credibility ?? null,\n extractedAt: source.extractedAt || null,\n metadata:\n typeof source?.getMetadata === 'function'\n ? source.getMetadata()\n : {},\n })),\n };\n });\n\n const referenceGroups = await Promise.all(\n references.map(async (reference) => {\n const sourceUrls = [\n reference.url,\n reference.original_url,\n reference.source,\n ].filter(Boolean) as string[];\n\n const extractedFacts = new Map<string, Fact>();\n for (const sourceUrl of sourceUrls) {\n const matches = await factSources.list({\n where: { sourceUrl },\n orderBy: 'created_at ASC',\n });\n\n for (const match of matches) {\n if (!match.factId || extractedFacts.has(match.factId)) {\n continue;\n }\n\n const fact = await match.getFact();\n if (fact?.id) {\n extractedFacts.set(fact.id as string, fact);\n }\n }\n }\n\n const extractedFactRecords: SerializedRecord[] = [\n ...extractedFacts.values(),\n ].map((fact) => {\n const factId = fact.id as string | undefined;\n return {\n ...serializeFact(fact),\n usedInArticle: factId ? usedFactIds.has(factId) : false,\n };\n });\n\n return {\n id: reference.id || null,\n title: reference.title || reference.name || reference.url || null,\n url: reference.url || null,\n originalUrl: reference.original_url || null,\n type: reference.type || null,\n source: reference.source || null,\n usedFactIds: extractedFactRecords\n .filter((fact) => fact.id && usedFactIds.has(fact.id))\n .map((fact) => fact.id),\n extractedFacts: extractedFactRecords,\n };\n }),\n );\n\n const publicGeneration = readNestedRecord(this.metadata, [\n 'transparency',\n 'generation',\n ]);\n const generationMetadata = readNestedRecord(this.metadata, ['generation']);\n const serializedCorrections = (corrections as SerializedRecord[])\n .filter((correction) => correction.status === 'published')\n .map((correction) => {\n // `corrections` is already serialized to plain records, so the\n // metadata is the parsed object on `correction.metadata`.\n const correctionMetadata = asRecord(correction.metadata);\n\n return {\n ...serializeContentCorrection(correction),\n provenance: {\n autoGeneratedDraft: Boolean(correctionMetadata.autoGeneratedDraft),\n draftVersionId: correctionMetadata.draftVersionId || null,\n draftVersionNumber: correctionMetadata.draftVersionNumber || null,\n sourceCorrectionVersionId:\n correctionMetadata.sourceCorrectionVersionId || null,\n sourceCorrectionVersionNumber:\n correctionMetadata.sourceCorrectionVersionNumber || null,\n },\n };\n });\n const serializedVersionHistory = (versions as SerializedRecord[]).map(\n (version) => {\n // `versions` is already serialized to plain records.\n const versionMetadata = asRecord(version.metadata);\n\n return {\n id: version.id || null,\n version: version.version ?? null,\n kind: version.kind || null,\n summary: version.summary || '',\n createdAt: version.createdAt || null,\n provenance: {\n policyKey: versionMetadata.policyKey || null,\n reviewFingerprint:\n versionMetadata.reviewFingerprint ||\n versionMetadata.contentFingerprint ||\n null,\n factId: versionMetadata.factId || null,\n replacementFactId: versionMetadata.replacementFactId || null,\n sourceCorrectionVersionId:\n versionMetadata.sourceCorrectionVersionId || null,\n sourceCorrectionVersionNumber:\n versionMetadata.sourceCorrectionVersionNumber || null,\n correctionDraft: versionMetadata.correctionDraft || null,\n publicationSnapshotFingerprint:\n versionMetadata.publicationSnapshotFingerprint || null,\n },\n };\n },\n );\n\n return normalizeContentTransparency(\n {\n generatedAt: new Date().toISOString(),\n snapshotKind,\n contentId: (this.id as string) || null,\n currentContentStatus: this.status || null,\n publicationProfileKey: governance.publicationProfileKey || undefined,\n generation: {\n aiAssisted:\n publicGeneration.aiAssisted ??\n generationMetadata.aiAssisted ??\n Boolean(getPublicPrompt(this.metadata)),\n publicPrompt: getPublicPrompt(this.metadata),\n model: publicGeneration.model || generationMetadata.model || null,\n },\n factsUsed: linkedFacts.filter((fact) => fact.usedInArticle),\n linkedFacts,\n otherExtractedFacts: referenceGroups.flatMap((reference) =>\n reference.extractedFacts.filter((fact) => !fact.usedInArticle),\n ),\n references: referenceGroups,\n reviews,\n reviewProfiles,\n corrections: serializedCorrections,\n versionHistory: serializedVersionHistory,\n },\n {\n snapshotKind,\n contentId: (this.id as string) || null,\n currentContentStatus: this.status || null,\n publicationProfileKey: governance.publicationProfileKey || undefined,\n },\n );\n }\n\n /**\n * Fingerprint of the *content-bearing* publication surface only.\n *\n * This must converge: two byte-identical `save()`s of published content\n * have to produce the same fingerprint so the publication-version writer\n * (`save()`) does not append a redundant `ContentVersion` on every save.\n *\n * It therefore deliberately excludes everything that grows or carries a\n * timestamp/ordering with each save — `versionHistory`, `reviews`,\n * `corrections`, and any `generatedAt`/`createdAt`/`id` fields. The earlier\n * implementation fingerprinted the full transparency snapshot (which embeds\n * the growing `versionHistory`), so the stored fingerprint of vN predated vN\n * and the next save's recomputed fingerprint always differed → unbounded\n * redundant publication versions (#1387 blocker).\n *\n * The surface mirrors `buildReviewFingerprint`'s content block, plus the\n * pinned reference edges (`{ targetId, targetVersion }`) — a pin change is a\n * meaningful republication — and the publication profile key.\n */\n private async buildPublicationSnapshotFingerprint(\n governance: ResolvedContentGovernance,\n ): Promise<string | null> {\n if (!governance.isGoverned || !governance.transparencyEnabled) {\n return null;\n }\n\n const referenceCollection = await this.getReferenceCollection();\n const [referenceEdges, facts, factLinks] = await Promise.all([\n this.id ? referenceCollection.getForSource(this.id) : Promise.resolve([]),\n governance.factLinkingEnabled\n ? this.getFacts({ latestOnly: true, includeSuperseded: false })\n : Promise.resolve([]),\n governance.factLinkingEnabled ? this.getFactLinks() : Promise.resolve([]),\n ]);\n\n return createFingerprint({\n scope: 'content-publication',\n publicationProfileKey: governance.publicationProfileKey || null,\n content: {\n id: this.id || null,\n type: this.type,\n variant: this.variant,\n title: this.title,\n description: this.description,\n body: this.body,\n author: this.author,\n state: this.state,\n publishDate: this.publish_date,\n language: this.language,\n category: this.category,\n tags: this.tags,\n metadata: this.metadata,\n },\n // Pinned reference edges only — ordering-independent so it converges.\n references: referenceEdges\n .map((edge) => ({\n targetId: edge.targetId || null,\n targetVersion: edge.targetVersion ?? null,\n }))\n .sort((a, b) => String(a.targetId).localeCompare(String(b.targetId))),\n facts: facts\n .map((fact) => ({\n id: fact.id || null,\n previousFactId: fact.previousFactId || null,\n status: fact.status || null,\n textRefined: fact.textRefined || '',\n sourceCount: fact.sourceCount ?? 0,\n confidence: fact.confidence ?? null,\n metadata:\n typeof fact?.getMetadata === 'function' ? fact.getMetadata() : {},\n }))\n .sort((a, b) => String(a.id).localeCompare(String(b.id))),\n factLinks: factLinks\n .map((link) => ({\n factId: link.factId || null,\n relationship: link.relationship || null,\n metadata:\n typeof link?.getMetadata === 'function' ? link.getMetadata() : {},\n }))\n .sort((a, b) => String(a.factId).localeCompare(String(b.factId))),\n });\n }\n\n private async getLatestPublicationSnapshotFingerprint(): Promise<\n string | null\n > {\n const versions = await this.getVersions();\n const latestPublicationVersion = [...versions]\n .reverse()\n .find((version) => version.kind === 'publication');\n\n if (!latestPublicationVersion) {\n return null;\n }\n\n return (\n latestPublicationVersion.getMetadata().publicationSnapshotFingerprint ||\n null\n );\n }\n\n private async buildCorrectionDraftSnapshot(\n options: IssueContentCorrectionOptions,\n replacementFactId: string,\n ): Promise<{\n snapshot: Record<string, unknown>;\n metadata: Record<string, unknown>;\n }> {\n const correctedText =\n options.correctedText || options.correctedFactText || '';\n const incorrectText = options.incorrectText || '';\n let body = this.body;\n let generationMethod = 'metadata';\n\n if (incorrectText && correctedText && body.includes(incorrectText)) {\n body = body.replace(incorrectText, correctedText);\n generationMethod = 'replace';\n } else if (correctedText) {\n const ai = this.ai as {\n message?: (\n prompt: string,\n options?: Record<string, unknown>,\n ) => Promise<string>;\n };\n if (ai?.message) {\n const resolvedPrompt = await resolvePrompt(\n smrtContentApplyCorrectionPrompt.key,\n {\n db: this.options.db,\n tenantId: this.tenantId,\n variables: {\n body: this.body,\n correctedText,\n incorrectText: incorrectText || 'Not provided',\n summary: options.summary || '',\n },\n },\n );\n\n try {\n const proposedBody = (\n await ai.message(\n resolvedPrompt.text,\n promptMessageOptions(resolvedPrompt.ai),\n )\n ).trim();\n if (proposedBody) {\n body = proposedBody;\n generationMethod = 'ai';\n }\n } catch {\n generationMethod = 'metadata';\n }\n }\n }\n\n return {\n snapshot: {\n title: this.title,\n description: this.description,\n body,\n status: 'draft',\n metadata: {\n ...(this.metadata || {}),\n governance: {\n ...asRecord(this.metadata.governance),\n correctionDraft: {\n summary: options.summary,\n incorrectText,\n correctedText,\n factId: options.factId || null,\n replacementFactId: replacementFactId || null,\n autoGenerated: true,\n generationMethod,\n },\n },\n },\n },\n metadata: {\n summary: options.summary,\n incorrectText,\n correctedText,\n factId: options.factId || null,\n replacementFactId: replacementFactId || null,\n autoGenerated: true,\n generationMethod,\n },\n };\n }\n\n private async getAssetCollection() {\n return AssetCollection.create({ db: this.db });\n }\n\n private async getContentAssetCollection() {\n return ContentAssetCollection.create({ db: this.db });\n }\n\n private async getContentAssetLinks(\n relationship?: string,\n ): Promise<Array<{ assetId: string; sortOrder: number }>> {\n if (!this.id) {\n return [];\n }\n\n try {\n const contentAssets = await this.getContentAssetCollection();\n const links = await contentAssets.byLeft(\n this.id,\n relationship ? { relationship } : {},\n );\n\n return links\n .filter((link) => link.assetId)\n .map((link) => ({\n assetId: link.assetId,\n sortOrder: link.sortOrder ?? 0,\n }));\n } catch (error) {\n if (isMissingTableError(error, 'content_assets')) {\n return [];\n }\n\n throw error;\n }\n }\n\n private async resolveAssetsForLinks(\n links: Array<{ assetId: string; sortOrder: number }>,\n ): Promise<Asset[]> {\n if (links.length === 0) {\n return [];\n }\n\n const assetIds = [...new Set(links.map((link) => link.assetId))];\n const assets = await this.getAssetCollection();\n const resolved = await assets.listByIds(assetIds);\n const assetsById = new Map(\n resolved\n .filter((asset) => asset.id)\n .map((asset) => [asset.id as string, asset]),\n );\n\n return links\n .map((link) => assetsById.get(link.assetId))\n .filter(Boolean) as Asset[];\n }\n\n private async resolveReferenceTarget(content: Content | string) {\n if (typeof content !== 'string') {\n return content;\n }\n\n const contents = await this.getContentsCollection();\n\n return (await contents.getOrUpsert(\n {\n url: content,\n tenantId: this.tenantId,\n },\n {\n name: content,\n title: content,\n type: 'reference',\n tenantId: this.tenantId,\n },\n )) as Content;\n }\n\n /**\n * Loads referenced content objects\n *\n * @returns Promise that resolves when references are loaded\n */\n public async loadReferences() {\n this.references = await this.getReferences();\n }\n\n private getPendingReferenceIds(): string[] | null {\n const pendingReferenceIds = (this as Content & ContentTransientLinkIds)\n .referenceIds;\n\n if (!Array.isArray(pendingReferenceIds)) {\n return null;\n }\n\n return [\n ...new Set(\n pendingReferenceIds.filter(\n (referenceId): referenceId is string =>\n typeof referenceId === 'string' &&\n referenceId.length > 0 &&\n referenceId !== this.id,\n ),\n ),\n ];\n }\n\n private getPendingAssetIds(): string[] | null {\n const pendingAssetIds = (this as Content & ContentTransientLinkIds)\n .assetIds;\n\n if (!Array.isArray(pendingAssetIds)) {\n return null;\n }\n\n return [\n ...new Set(\n pendingAssetIds.filter(\n (assetId): assetId is string =>\n typeof assetId === 'string' && assetId.length > 0,\n ),\n ),\n ];\n }\n\n private async syncPendingReferenceIds(): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const pendingReferenceIds = this.getPendingReferenceIds();\n if (pendingReferenceIds === null) {\n return;\n }\n\n const currentReferences = await this.getReferences();\n const currentReferenceIds = currentReferences\n .map((reference) => reference.id)\n .filter((referenceId): referenceId is string => Boolean(referenceId));\n const currentReferenceIdSet = new Set(currentReferenceIds);\n const pendingReferenceIdSet = new Set(pendingReferenceIds);\n\n for (const referenceId of currentReferenceIds) {\n if (!pendingReferenceIdSet.has(referenceId)) {\n await this.removeReference(referenceId);\n }\n }\n\n const referenceIdsToAdd = pendingReferenceIds.filter(\n (referenceId) => !currentReferenceIdSet.has(referenceId),\n );\n\n if (referenceIdsToAdd.length === 0) {\n this.references = await this.getReferences();\n return;\n }\n\n const contents = await this.getContentsCollection();\n const resolvedReferences = await contents.listByIds(referenceIdsToAdd);\n const referencesById = new Map(\n resolvedReferences\n .filter((reference) => reference.id)\n .map((reference) => [reference.id as string, reference]),\n );\n\n for (const referenceId of referenceIdsToAdd) {\n const reference = referencesById.get(referenceId);\n if (reference) {\n await this.addReference(reference);\n }\n }\n\n this.references = await this.getReferences();\n }\n\n private async syncPendingAssetIds(): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const pendingAssetIds = this.getPendingAssetIds();\n if (pendingAssetIds === null) {\n return;\n }\n\n const currentAssets = await this.getAssets();\n const currentAssetIds = currentAssets\n .map((asset) => asset.id)\n .filter((assetId): assetId is string => Boolean(assetId));\n const currentAssetIdSet = new Set(currentAssetIds);\n const pendingAssetIdSet = new Set(pendingAssetIds);\n\n for (const assetId of currentAssetIds) {\n if (!pendingAssetIdSet.has(assetId)) {\n await this.removeAsset(assetId);\n }\n }\n\n const assetIdsToAdd = pendingAssetIds.filter(\n (assetId) => !currentAssetIdSet.has(assetId),\n );\n\n if (assetIdsToAdd.length === 0) {\n return;\n }\n\n const assets = await this.getAssetCollection();\n const resolvedAssets = await assets.listByIds(assetIdsToAdd);\n const assetsById = new Map(\n resolvedAssets\n .filter((asset) => asset.id)\n .map((asset) => [asset.id as string, asset]),\n );\n\n for (const assetId of assetIdsToAdd) {\n const asset = assetsById.get(assetId);\n if (asset) {\n await this.addAsset(asset);\n }\n }\n }\n\n /**\n * Adds a reference to another content object.\n *\n * @param content - Content object or URL to reference\n * @param options.targetVersion - Optional ContentVersion.version to pin the\n * citation to. Pass the target's current version (typically the latest\n * publication) to enable drift detection later. Pass `null` or omit to\n * leave the reference untracked.\n * @returns Promise that resolves when the reference is added\n */\n public async addReference(\n content: Content | string,\n options: { targetVersion?: number | null } = {},\n ) {\n if (!this.id) {\n throw new Error('Cannot add reference to unsaved content');\n }\n\n const target = await this.resolveReferenceTarget(content);\n\n if (!target.id) {\n throw new Error('Cannot add reference to unsaved content');\n }\n if (this.id === target.id) {\n return;\n }\n\n const references = await this.getReferenceCollection();\n // R2 junction `attach` carries extra row fields via its opts bag, so the\n // tenant scope and main's citation pin (targetVersion) ride along together.\n await references.attach(this.id, target.id, {\n tenantId: this.tenantId,\n targetVersion: options.targetVersion,\n });\n this.references = await this.getReferences();\n }\n\n /**\n * Removes a reference to another content object\n *\n * @param targetId - ID of the referenced content to remove\n */\n public async removeReference(targetId: string) {\n if (!this.id) {\n return;\n }\n\n const references = await this.getReferenceCollection();\n await references.detach(this.id, targetId);\n this.references = this.references.filter(\n (reference) => reference.id !== targetId,\n );\n }\n\n /**\n * Gets all referenced content objects\n *\n * @returns Promise resolving to an array of referenced Content objects\n */\n public async getReferences() {\n if (!this.id) {\n return [];\n }\n\n const references = await this.getReferenceCollection();\n const linkedReferences = await references.byLeft(this.id);\n const targetIds = linkedReferences.map((reference) => reference.targetId);\n\n if (targetIds.length === 0) {\n this.references = [];\n return this.references;\n }\n\n const contents = await this.getContentsCollection();\n const resolved = await contents.listByIds(targetIds);\n const referencesById = new Map(\n resolved\n .filter((content) => content.id)\n .map((content) => [content.id as string, content]),\n );\n\n this.references = targetIds\n .map((targetId) => referencesById.get(targetId))\n .filter(Boolean) as Content[];\n return this.references;\n }\n\n /**\n * Returns the raw reference edges with their citation pins\n * (`{ targetId, targetVersion }`). Unlike `getReferences()` (which resolves\n * to `Content` objects and loses the per-edge `targetVersion`), this keeps\n * the pin so callers — notably version snapshots — can reconstruct pinned\n * citations on restore. See `ContentVersionCollection.restoreIntoContent`.\n */\n public async getReferenceEdges(): Promise<\n Array<{ targetId: string; targetVersion: number | null }>\n > {\n if (!this.id) {\n return [];\n }\n\n const references = await this.getReferenceCollection();\n const linkedReferences = await references.getForSource(this.id);\n return linkedReferences\n .filter((edge) => Boolean(edge.targetId))\n .map((edge) => ({\n targetId: edge.targetId as string,\n targetVersion: edge.targetVersion ?? null,\n }));\n }\n\n /**\n * Returns one entry per reference edge with the pinned `targetVersion` and\n * the target's latest version. Drift exists when both are present and\n * differ — callers can use this to surface \"the source you cited has been\n * updated\" affordances in editors or review tools.\n *\n * `currentVersion` is the target's latest **publication** `ContentVersion`,\n * because pins are taken against the latest publication (see `addReference`).\n * Auto-created `correction`/`draft`/`manual` versions bump the shared\n * `(content_id, version)` counter but do NOT republish, so comparing against\n * the max version of *any* kind produced false drift positives (#1387 #4).\n *\n * Unpinned references (`citedVersion === null`) are included with\n * `currentVersion` populated when available so callers can choose to\n * surface them as \"pinnable\" suggestions.\n */\n public async getReferenceDrift(): Promise<\n Array<{\n targetId: string;\n citedVersion: number | null;\n currentVersion: number | null;\n isDrifted: boolean;\n }>\n > {\n if (!this.id) {\n return [];\n }\n\n const references = await this.getReferenceCollection();\n const linkedReferences = await references.getForSource(this.id);\n if (linkedReferences.length === 0) {\n return [];\n }\n\n const versions = await this.getContentVersionCollection();\n const targetIds = linkedReferences.map((reference) => reference.targetId);\n\n // Single query for all target *publication* versions; pick the max per\n // contentId. Pins are taken against the latest publication, so only\n // publication versions count as drift (#1387 #4). Filtering by kind here\n // also avoids the N+1 of loading each version to inspect its kind.\n const allVersions = await versions.list({\n where: { contentId: targetIds, kind: 'publication' },\n orderBy: 'version DESC',\n });\n const latestByContentId = new Map<string, number>();\n for (const version of allVersions) {\n if (!latestByContentId.has(version.contentId)) {\n latestByContentId.set(version.contentId, version.version);\n }\n }\n\n return linkedReferences.map((reference) => {\n const currentVersion = latestByContentId.get(reference.targetId) ?? null;\n const citedVersion = reference.targetVersion ?? null;\n return {\n targetId: reference.targetId,\n citedVersion,\n currentVersion,\n isDrifted:\n citedVersion !== null &&\n currentVersion !== null &&\n citedVersion !== currentVersion,\n };\n });\n }\n\n public isGoverned(): boolean {\n return this.getConfiguredGovernance().isGoverned;\n }\n\n public async getFactLinks(\n options: { relationship?: FactContentRelationship } = {},\n ) {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.factLinkingEnabled || !this.id) {\n return [];\n }\n\n if (!this.id) {\n return [];\n }\n\n const links = await this.getFactContentCollection();\n return options.relationship\n ? links.byRight(this.id as string, { relationship: options.relationship })\n : links.byRight(this.id as string);\n }\n\n public async getFacts(\n options: {\n relationship?: FactContentRelationship;\n includeSuperseded?: boolean;\n latestOnly?: boolean;\n } = {},\n ): Promise<Fact[]> {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.factLinkingEnabled || !this.id) {\n return [];\n }\n\n if (!this.id) {\n return [];\n }\n\n const facts = await this.getFactCollection();\n return facts.getForContent(this.id as string, options);\n }\n\n public async addFact(\n fact: Fact | string,\n relationship?: FactContentRelationship,\n metadata?: Record<string, unknown>,\n ) {\n const governance = await this.requireFactLinking('fact association');\n\n if (!this.id) {\n throw new Error('Cannot associate an unsaved content item with a fact');\n }\n\n const factId = typeof fact === 'string' ? fact : (fact.id as string);\n if (!factId) {\n throw new Error('Fact ID is required to create a content-fact link');\n }\n\n const links = await this.getFactContentCollection();\n return links.attach(factId, this.id as string, {\n relationship: relationship || governance.defaultFactRelationship,\n metadata,\n });\n }\n\n public async removeFact(\n factId: string,\n relationship?: FactContentRelationship,\n ): Promise<void> {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.factLinkingEnabled) {\n return;\n }\n\n if (!this.id) {\n return;\n }\n\n const links = await this.getFactContentCollection();\n if (relationship) {\n await links.detach(factId, this.id as string, { relationship });\n return;\n }\n\n await links.detach(factId, this.id as string);\n }\n\n public async syncFacts(\n factIds: string[],\n relationship?: FactContentRelationship,\n ): Promise<{ added: string[]; kept: string[]; removed: string[] }> {\n const governance = await this.requireFactLinking('fact sync');\n\n if (!this.id) {\n throw new Error('Cannot sync facts for unsaved content');\n }\n\n const uniqueFactIds = [...new Set(factIds.filter(Boolean))];\n const links = await this.getFactContentCollection();\n const resolvedRelationship =\n relationship || governance.defaultFactRelationship;\n const existing = await links.byRight(this.id as string, {\n relationship: resolvedRelationship,\n });\n\n const existingIds = new Set(existing.map((link) => link.factId));\n const desiredIds = new Set(uniqueFactIds);\n\n const kept = uniqueFactIds.filter((factId) => existingIds.has(factId));\n const added = uniqueFactIds.filter((factId) => !existingIds.has(factId));\n const removed = existing\n .map((link) => link.factId)\n .filter((factId) => !desiredIds.has(factId));\n\n for (const factId of added) {\n await links.attach(factId, this.id as string, {\n relationship: resolvedRelationship,\n });\n }\n\n for (const factId of removed) {\n await links.detach(factId, this.id as string, {\n relationship: resolvedRelationship,\n });\n }\n\n return { added, kept, removed };\n }\n\n public async browseFacts(\n query = '',\n options: {\n limit?: number;\n offset?: number;\n minSimilarity?: number;\n includeSuperseded?: boolean;\n latestOnly?: boolean;\n } = {},\n ): Promise<Fact[]> {\n await this.requireFactLinking('fact catalog browsing');\n const facts = await this.getFactCollection();\n return facts.browseCatalog(query, {\n ...options,\n tenantId: this.tenantId,\n });\n }\n\n private async getFactAuditSourceMaterials(): Promise<{\n sources: FactAuditSourceMaterial[];\n warnings: string[];\n }> {\n const warnings: string[] = [];\n const sources: FactAuditSourceMaterial[] = [];\n const references = await this.getReferences();\n const assets = await this.getAssets();\n\n for (const reference of references) {\n const referenceId = (reference.id as string | undefined) || '';\n const text = getContentText(reference);\n // `sourceUrl` is not a declared Content field; read it structurally.\n const referenceSourceUrl = (reference as { sourceUrl?: unknown })\n .sourceUrl;\n const sourceUrl =\n normalizeAuditText(reference.url) ||\n normalizeAuditText(referenceSourceUrl) ||\n normalizeAuditText(reference.fileKey);\n const sourceTitle =\n normalizeAuditText(reference.title) ||\n normalizeAuditText(reference.name) ||\n sourceUrl ||\n referenceId;\n\n if (!text) {\n warnings.push(\n `Reference ${sourceTitle || referenceId} has no extracted text.`,\n );\n continue;\n }\n\n sources.push({\n sourceKind: 'content-reference',\n sourceId: referenceId,\n sourceUrl,\n sourceTitle,\n locator: sourceTitle,\n text,\n });\n }\n\n for (const asset of assets as Array<Asset & FactAuditAssetExtraFields>) {\n const metadata =\n typeof asset?.getMetadata === 'function'\n ? asset.getMetadata()\n : parseAuditMetadata(asset?.metadata);\n const text = [\n metadata.extractedText,\n metadata.text,\n metadata.ocrText,\n asset?.text,\n asset?.body,\n asset?.description,\n ]\n .map(normalizeAuditText)\n .filter(Boolean)\n .join('\\n\\n');\n const assetId = normalizeAuditText(asset?.id);\n const sourceTitle =\n normalizeAuditText(asset?.title) ||\n normalizeAuditText(asset?.name) ||\n normalizeAuditText(asset?.filename) ||\n assetId;\n const sourceUrl =\n normalizeAuditText(asset?.url) ||\n normalizeAuditText(asset?.sourceUrl) ||\n normalizeAuditText(asset?.fileKey);\n\n if (!text) {\n warnings.push(`Asset ${sourceTitle || assetId} has no extracted text.`);\n continue;\n }\n\n sources.push({\n sourceKind: 'asset',\n sourceId: assetId,\n sourceUrl,\n sourceTitle,\n locator: sourceTitle,\n text,\n });\n }\n\n return { sources, warnings };\n }\n\n private factMatchesTenant(fact: {\n tenantId?: string | null;\n tenant_id?: string | null;\n }): boolean {\n return (\n fact.tenantId === this.tenantId ||\n fact.tenant_id === this.tenantId ||\n (!fact.tenantId && !fact.tenant_id && !this.tenantId)\n );\n }\n\n private async findExactArticleClaimFact(\n statement: string,\n ): Promise<Fact | null> {\n const normalizedStatement = normalizeAuditText(statement);\n const facts = await this.getFactCollection();\n const linkedClaimFacts = await Promise.all(\n (await this.getFactLinks({ relationship: 'referenced_in' })).map((link) =>\n facts.get({ id: link.factId }),\n ),\n );\n const linkedMatch = linkedClaimFacts.find(\n (fact): fact is Fact =>\n Boolean(fact) &&\n this.factMatchesTenant(fact as Fact) &&\n normalizeAuditText((fact as Fact).textRefined) === normalizedStatement,\n );\n if (linkedMatch) {\n return linkedMatch;\n }\n\n const matches = await facts.list({\n where: { textRefined: normalizedStatement },\n orderBy: 'updated_at DESC',\n });\n\n return (\n matches.find(\n (fact) =>\n this.factMatchesTenant(fact) &&\n this.id &&\n isGeneratedArticleClaimFact(fact, this.id as string),\n ) || null\n );\n }\n\n private async safeAuditLink(\n factId: string,\n relationship: FactContentRelationship,\n metadata: Record<string, unknown>,\n ) {\n const links = await this.getFactContentCollection();\n const existing = (\n await links.byRight(this.id as string, { relationship })\n ).find((link) => link.factId === factId);\n\n if (existing) {\n const existingMetadata = getLinkMetadata(existing);\n if (existingMetadata.generatedBy === FACT_AUDIT_GENERATED_BY) {\n existing.setMetadata?.({\n ...existingMetadata,\n ...metadata,\n });\n } else {\n existing.setMetadata?.({\n ...existingMetadata,\n factAudit: {\n ...asRecord(existingMetadata.factAudit),\n ...metadata,\n },\n });\n }\n await existing.save();\n return existing;\n }\n\n return links.attach(factId, this.id as string, { relationship, metadata });\n }\n\n private async clearGeneratedFactAudit(): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const [links, evidences] = await Promise.all([\n this.getFactLinks(),\n this.getFactEvidenceCollection(),\n ]);\n\n for (const link of links) {\n const metadata = getLinkMetadata(link);\n const nestedFactAudit = asRecord(metadata.factAudit);\n if (metadata.generatedBy === FACT_AUDIT_GENERATED_BY) {\n await link.delete();\n } else if (\n metadata.factAudit &&\n typeof metadata.factAudit === 'object' &&\n nestedFactAudit.generatedBy === FACT_AUDIT_GENERATED_BY\n ) {\n const { factAudit: _removed, ...preservedMetadata } = metadata;\n link.setMetadata?.(preservedMetadata);\n await link.save();\n }\n }\n\n const generatedEvidence = await evidences.list({\n where: { tenantId: this.tenantId ?? null },\n });\n for (const evidence of generatedEvidence) {\n const metadata =\n typeof evidence.getMetadata === 'function'\n ? evidence.getMetadata()\n : {};\n if (\n metadata.generatedBy === FACT_AUDIT_GENERATED_BY &&\n metadata.contentId === this.id\n ) {\n await evidence.delete();\n }\n }\n }\n\n private async clearGeneratedFactSourcesForSources(\n sources: FactAuditSourceMaterial[],\n ): Promise<string[]> {\n if (!this.id || sources.length === 0) {\n return [];\n }\n\n const sourceKeys = new Set(\n sources.map((source) => `${source.sourceKind}:${source.sourceId}`),\n );\n const factSources = await this.getFactSourceCollection();\n const generatedSources = await factSources.list({\n where: { tenantId: this.tenantId ?? null },\n });\n const deletedSourceIds: string[] = [];\n\n for (const source of generatedSources) {\n const metadata =\n typeof source.getMetadata === 'function' ? source.getMetadata() : {};\n const sourceKey = `${source.sourceType || ''}:${metadata.sourceId || ''}`;\n if (\n sourceKeys.has(sourceKey) &&\n metadata.generatedBy === FACT_AUDIT_GENERATED_BY &&\n metadata.contentId === this.id\n ) {\n if (typeof source.id === 'string') {\n deletedSourceIds.push(source.id);\n }\n await source.delete();\n }\n }\n\n return deletedSourceIds;\n }\n\n private async extractReferenceFactsForAudit(\n sources: FactAuditSourceMaterial[],\n options: {\n auditRunId: string;\n maxFactsPerSource?: number;\n context?: string;\n replaceGenerated?: boolean;\n },\n ) {\n const facts = await this.getFactCollection();\n const evidences = await this.getFactEvidenceCollection();\n const warnings: string[] = [];\n const referenceFacts = new Map<string, Fact>();\n let deletedEvidenceIds: string[] = [];\n let deletedSourceIds: string[] = [];\n\n if (options.replaceGenerated && sources.length > 0) {\n const replacement = await evidences.replaceGeneratedForSources(\n sources.map((source) => ({\n sourceKind: source.sourceKind,\n sourceId: source.sourceId,\n })),\n {\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id as string,\n tenantId: this.tenantId ?? null,\n },\n );\n deletedEvidenceIds = replacement.deletedEvidenceIds;\n deletedSourceIds =\n await this.clearGeneratedFactSourcesForSources(sources);\n }\n\n for (const source of sources) {\n let candidates: FactExtractionCandidate[] = [];\n try {\n candidates = await facts.extractCandidatesFromText(source.text, {\n domain: FACT_AUDIT_DOMAIN,\n sourceType: source.sourceKind,\n context: options.context || source.sourceTitle,\n maxFacts: options.maxFactsPerSource ?? 24,\n tenantId: this.tenantId,\n });\n } catch (error) {\n warnings.push(\n `Failed to extract facts from ${source.sourceTitle}: ${errorMessage(error)}`,\n );\n continue;\n }\n\n for (const candidate of candidates) {\n const result = await facts.reconcile({\n rawInput: candidate.statement,\n type: candidate.type || 'assertion',\n domain: FACT_AUDIT_DOMAIN,\n tenantId: this.tenantId,\n source: {\n sourceType: source.sourceKind,\n sourceUrl: source.sourceUrl,\n sourceTitle: source.sourceTitle,\n credibility: candidate.confidence ?? 0.75,\n metadata: {\n auditRunId: options.auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n sourceId: source.sourceId,\n quote: candidate.sourceExcerpt || null,\n locator: source.locator || null,\n },\n },\n });\n referenceFacts.set(result.fact.id as string, result.fact);\n\n await evidences.upsertEvidence({\n factId: result.fact.id as string,\n status: 'supports',\n sourceKind: source.sourceKind,\n sourceId: source.sourceId,\n sourceUrl: source.sourceUrl,\n sourceTitle: source.sourceTitle,\n quote: candidate.sourceExcerpt || candidate.statement,\n locator: source.locator,\n extractionMethod: 'ai-reference-fact',\n confidence: candidate.confidence ?? 0.75,\n tenantId: this.tenantId,\n metadata: {\n auditRunId: options.auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n candidateMetadata: candidate.metadata || {},\n },\n });\n }\n }\n\n return {\n referenceFacts,\n warnings,\n referenceFactsExtracted: referenceFacts.size,\n deletedEvidenceIds,\n deletedSourceIds,\n repairedSources: sources.map((source) => ({\n sourceKind: source.sourceKind,\n sourceId: source.sourceId,\n sourceTitle: source.sourceTitle,\n })),\n };\n }\n\n private async getCurrentFactAuditSupportCandidates(\n options: {\n referenceFacts?: Map<string, Fact>;\n sources?: FactAuditSourceSelector[];\n sourceIds?: string[];\n maxCandidateEvidence?: number;\n } = {},\n ) {\n const evidences = await this.getFactEvidenceCollection();\n const allFacts = await this.getFactCollection();\n const candidateFacts = new Map<string, FactAuditSupportCandidate>();\n const candidateEvidence = new Map<string, FactEvidence>();\n const sourceKeys = new Set(\n (options.sources || []).map(\n (source) => `${source.sourceKind}:${source.sourceId}`,\n ),\n );\n const sourceIds = new Set(options.sourceIds || []);\n const maxCandidateEvidence = Math.max(\n 1,\n options.maxCandidateEvidence ?? 120,\n );\n\n const evidenceEntries = options.referenceFacts\n ? (\n await Promise.all(\n [...options.referenceFacts.keys()].map((factId) =>\n evidences.getForFact(factId),\n ),\n )\n ).flat()\n : await evidences.list({\n where: { tenantId: this.tenantId ?? null },\n });\n\n for (const entry of evidenceEntries) {\n if (!isGeneratedFactAuditEvidence(entry, this.id as string)) {\n continue;\n }\n if (entry.sourceKind === 'content') {\n continue;\n }\n if (entry.status === 'irrelevant' || entry.status === 'invalid') {\n continue;\n }\n if (\n sourceKeys.size > 0 &&\n !sourceKeys.has(`${entry.sourceKind}:${entry.sourceId}`)\n ) {\n continue;\n }\n if (sourceIds.size > 0 && !sourceIds.has(entry.sourceId)) {\n continue;\n }\n if (candidateEvidence.size >= maxCandidateEvidence) {\n break;\n }\n\n const fact =\n options.referenceFacts?.get(entry.factId) ||\n (await allFacts.get({ id: entry.factId }));\n if (!fact) {\n continue;\n }\n\n const factId = fact.id as string;\n const existing = candidateFacts.get(factId) || {\n id: factId,\n statement: fact.textRefined || fact.textRaw || '',\n evidence: [],\n };\n const serializedEvidence = {\n id: entry.id || null,\n status: entry.status || 'supports',\n quote: entry.quote || null,\n sourceTitle: entry.sourceTitle || null,\n sourceUrl: entry.sourceUrl || null,\n locator: entry.locator || null,\n };\n existing.evidence.push(serializedEvidence);\n candidateFacts.set(factId, existing);\n if (typeof entry.id === 'string') {\n candidateEvidence.set(entry.id, entry);\n }\n }\n\n return {\n supportCandidates: [...candidateFacts.values()],\n candidateFactIds: new Set(candidateFacts.keys()),\n candidateEvidence,\n };\n }\n\n public async repairFactAudit(\n options: {\n maxReferenceFactsPerSource?: number;\n maxArticleClaims?: number;\n context?: string;\n } = {},\n ) {\n await this.requireFactLinking('fact audit repair');\n if (!this.id) {\n throw new Error('Cannot repair fact audit for unsaved content');\n }\n\n const auditRunId = createFactAuditRunId(this.id as string);\n const facts = await this.getFactCollection();\n const evidences = await this.getFactEvidenceCollection();\n const warnings: string[] = [];\n const articleText = getContentText(this);\n\n const sourceMaterials = await this.getFactAuditSourceMaterials();\n warnings.push(...sourceMaterials.warnings);\n await this.clearGeneratedFactAudit();\n const referenceRepair = await this.extractReferenceFactsForAudit(\n sourceMaterials.sources,\n {\n auditRunId,\n maxFactsPerSource: options.maxReferenceFactsPerSource,\n context: options.context,\n },\n );\n warnings.push(...referenceRepair.warnings);\n const referenceFacts = referenceRepair.referenceFacts;\n\n let claims: FactExtractionCandidate[] = [];\n if (!articleText) {\n warnings.push('Article has no text to audit.');\n } else {\n try {\n claims = await facts.extractArticleClaims(articleText, {\n domain: FACT_AUDIT_DOMAIN,\n sourceType: 'article',\n context: options.context || this.title || this.slug || '',\n maxFacts: options.maxArticleClaims ?? 32,\n tenantId: this.tenantId,\n });\n } catch (error) {\n warnings.push(\n `Failed to extract article claims: ${errorMessage(error)}`,\n );\n }\n }\n\n const { supportCandidates, candidateFactIds, candidateEvidence } =\n await this.getCurrentFactAuditSupportCandidates({\n referenceFacts,\n });\n\n const findings: ContentReviewFinding[] = [];\n\n for (const claim of claims) {\n let assessment: FactClaimSupportAssessment;\n try {\n assessment = await facts.assessClaimSupport(\n claim.statement,\n supportCandidates,\n { tenantId: this.tenantId },\n );\n } catch (error) {\n warnings.push(\n `Failed to assess claim \"${claim.statement}\": ${errorMessage(error)}`,\n );\n assessment = {\n status: 'needs_review' as FactClaimSupportStatus,\n matchedFactIds: [],\n matchedEvidenceIds: [],\n rationale: 'Support assessment failed.',\n confidence: undefined,\n };\n }\n\n const matchedFactIds = assessment.matchedFactIds.filter((factId) =>\n candidateFactIds.has(factId),\n );\n let claimFact = await this.findExactArticleClaimFact(claim.statement);\n\n if (!claimFact) {\n claimFact = await facts.create({\n textRefined: claim.statement,\n textRaw: claim.statement,\n type: claim.type || 'assertion',\n domain: FACT_AUDIT_DOMAIN,\n status:\n assessment.status === 'unsupported' ||\n assessment.status === 'needs_review'\n ? 'pending'\n : 'active',\n sourceCount: 0,\n confidence: claim.confidence ?? assessment.confidence ?? 0.5,\n tenantId: this.tenantId,\n metadata: JSON.stringify({\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n auditFactRole: 'article-claim',\n claimOnly: matchedFactIds.length === 0,\n }),\n });\n } else if (\n this.id &&\n isGeneratedArticleClaimFact(claimFact, this.id as string)\n ) {\n claimFact.status =\n assessment.status === 'unsupported' ||\n assessment.status === 'needs_review'\n ? 'pending'\n : 'active';\n claimFact.confidence =\n claim.confidence ?? assessment.confidence ?? claimFact.confidence;\n claimFact.updateMetadata?.({\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n auditFactRole: 'article-claim',\n claimOnly: matchedFactIds.length === 0,\n });\n await claimFact.save();\n }\n\n const articleEvidence = await evidences.upsertEvidence({\n factId: claimFact.id as string,\n status: 'supports',\n sourceKind: 'content',\n sourceId: this.id as string,\n sourceTitle: this.title || this.slug || (this.id as string),\n quote: claim.sourceExcerpt || claim.statement,\n locator: this.title || this.slug || '',\n extractionMethod: 'ai-article-claim',\n confidence: claim.confidence ?? assessment.confidence ?? 0.5,\n tenantId: this.tenantId,\n metadata: {\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n contentId: this.id,\n supportStatus: assessment.status,\n },\n });\n\n let supportingEvidenceIds = assessment.matchedEvidenceIds.filter(\n (evidenceId) => candidateEvidence.has(evidenceId),\n );\n for (const matchedFactId of matchedFactIds) {\n if (supportingEvidenceIds.length > 0) {\n continue;\n }\n const candidate = supportCandidates.find(\n (entry) => entry.id === matchedFactId,\n );\n supportingEvidenceIds = [\n ...supportingEvidenceIds,\n ...(candidate?.evidence || [])\n .map((entry) => entry.id)\n .filter((id: unknown): id is string => typeof id === 'string'),\n ];\n }\n supportingEvidenceIds = [...new Set(supportingEvidenceIds)];\n\n const linkMetadata = {\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n supportStatus: assessment.status,\n claimQuote: claim.sourceExcerpt || claim.statement,\n claimFactId: claimFact.id as string,\n articleEvidenceId: articleEvidence.id || null,\n supportingFactIds: matchedFactIds,\n supportingEvidenceIds,\n rationale: assessment.rationale,\n confidence: assessment.confidence ?? claim.confidence ?? null,\n };\n\n await this.safeAuditLink(\n claimFact.id as string,\n 'referenced_in',\n linkMetadata,\n );\n\n for (const matchedFactId of matchedFactIds) {\n await this.safeAuditLink(\n matchedFactId,\n assessment.status === 'contradicted' ? 'contradicts' : 'supports',\n {\n ...linkMetadata,\n supportingEvidenceIds,\n },\n );\n }\n\n if (assessment.status !== 'supported') {\n findings.push({\n severity: assessment.status === 'contradicted' ? 'error' : 'warning',\n title:\n assessment.status === 'contradicted'\n ? 'Contradicted article claim'\n : 'Unsupported article claim',\n detail: assessment.rationale || 'The claim needs editorial review.',\n factId: claimFact.id as string,\n quote: claim.sourceExcerpt || claim.statement,\n ruleId: 'fact-audit',\n });\n }\n }\n\n const reviews = await this.getContentReviewCollection();\n await reviews.createFromResult({\n contentId: this.id as string,\n kind: 'facts',\n policyKey: 'facts',\n reviewer: 'system',\n result: {\n status: findings.length > 0 ? 'flagged' : 'passed',\n summary:\n findings.length > 0\n ? `${findings.length} article claim(s) need review.`\n : 'Article claims are supported by available evidence.',\n findings,\n },\n metadata: {\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n warnings,\n },\n tenantId: this.tenantId,\n });\n\n const state = await this.getFactAuditState();\n return {\n ...state,\n repair: {\n auditRunId,\n claimsExtracted: claims.length,\n referenceFactsExtracted: referenceRepair.referenceFactsExtracted,\n warnings,\n },\n };\n }\n\n public async repairFactAuditAction(\n options: {\n maxReferenceFactsPerSource?: number;\n maxArticleClaims?: number;\n context?: string;\n } = {},\n ) {\n return this.repairFactAudit(options);\n }\n\n public async repairFactEvidence(\n options: FactAuditResourceRepairOptions = {},\n ) {\n await this.requireFactLinking('fact evidence repair');\n if (!this.id) {\n throw new Error('Cannot repair fact evidence for unsaved content');\n }\n\n const auditRunId = createFactAuditRunId(this.id as string);\n const sourceMaterials = await this.getFactAuditSourceMaterials();\n const sources = filterAuditSources(\n sourceMaterials.sources,\n options.sources,\n );\n const warnings: string[] = [];\n\n if (options.sources?.length && sources.length === 0) {\n warnings.push('No matching resource text was available for repair.');\n }\n\n const repair = await this.extractReferenceFactsForAudit(sources, {\n auditRunId,\n maxFactsPerSource: options.maxFactsPerSource,\n context: options.context,\n replaceGenerated: true,\n });\n warnings.push(...repair.warnings);\n\n const state = await this.getFactAuditState();\n return {\n ...state,\n evidenceRepair: {\n auditRunId,\n referenceFactsExtracted: repair.referenceFactsExtracted,\n repairedSources: repair.repairedSources,\n deletedEvidenceIds: repair.deletedEvidenceIds,\n deletedSourceIds: repair.deletedSourceIds,\n warnings,\n },\n };\n }\n\n public async repairFactEvidenceAction(\n options: FactAuditResourceRepairOptions = {},\n ) {\n return this.repairFactEvidence(options);\n }\n\n private async clearGeneratedSupportLinksForClaim(\n claimFactId: string,\n articleEvidenceId: string | null,\n ): Promise<void> {\n const links = await this.getFactLinks();\n\n for (const link of links) {\n if (\n link.relationship !== 'supports' &&\n link.relationship !== 'contradicts'\n ) {\n continue;\n }\n\n const metadata = getGeneratedFactAuditMetadata(link);\n if (!metadata) {\n continue;\n }\n\n const matchesEvidence =\n articleEvidenceId &&\n typeof metadata.articleEvidenceId === 'string' &&\n metadata.articleEvidenceId === articleEvidenceId;\n const matchesClaim =\n typeof metadata.claimFactId === 'string' &&\n metadata.claimFactId === claimFactId;\n\n if (matchesEvidence || matchesClaim) {\n await link.delete();\n }\n }\n }\n\n public async recheckFactClaims(options: FactAuditClaimRecheckOptions = {}) {\n await this.requireFactLinking('claim support recheck');\n if (!this.id) {\n throw new Error('Cannot recheck fact claims for unsaved content');\n }\n\n const auditRunId = createFactAuditRunId(this.id as string);\n const facts = await this.getFactCollection();\n const evidences = await this.getFactEvidenceCollection();\n const links = await this.getFactContentCollection();\n const claimIdFilter = new Set(options.claimFactIds || []);\n const { supportCandidates, candidateFactIds, candidateEvidence } =\n await this.getCurrentFactAuditSupportCandidates({\n sources: options.sources,\n sourceIds: options.sourceIds,\n maxCandidateEvidence: options.maxCandidateEvidence,\n });\n const claimLinks = (\n await links.byRight(this.id as string, { relationship: 'referenced_in' })\n )\n .map((link) => ({\n link,\n metadata: getGeneratedFactAuditMetadata(link),\n }))\n .filter(\n (\n entry,\n ): entry is { link: FactContent; metadata: Record<string, unknown> } =>\n entry.metadata !== null &&\n (claimIdFilter.size === 0 || claimIdFilter.has(entry.link.factId)),\n );\n const warnings: string[] = [];\n let recheckedClaims = 0;\n\n for (const { link, metadata } of claimLinks) {\n const claimFact = await facts.get({ id: link.factId });\n if (!claimFact) {\n continue;\n }\n\n const claimText =\n normalizeAuditText(metadata.claimQuote) ||\n normalizeAuditText(claimFact.textRefined) ||\n normalizeAuditText(claimFact.textRaw);\n if (!claimText) {\n continue;\n }\n\n let assessment: FactClaimSupportAssessment;\n try {\n assessment = await facts.assessClaimSupport(\n claimText,\n supportCandidates,\n { tenantId: this.tenantId },\n );\n } catch (error) {\n warnings.push(\n `Failed to recheck claim \"${claimText}\": ${errorMessage(error)}`,\n );\n assessment = {\n status: 'needs_review',\n matchedFactIds: [],\n matchedEvidenceIds: [],\n rationale: 'Support assessment failed.',\n confidence: undefined,\n };\n }\n\n const matchedFactIds = assessment.matchedFactIds.filter((factId) =>\n candidateFactIds.has(factId),\n );\n let supportStatus = assessment.status;\n if (\n (supportStatus === 'supported' || supportStatus === 'contradicted') &&\n matchedFactIds.length === 0\n ) {\n supportStatus = 'needs_review';\n }\n let supportingEvidenceIds = assessment.matchedEvidenceIds.filter(\n (evidenceId) => candidateEvidence.has(evidenceId),\n );\n if (supportingEvidenceIds.length === 0) {\n for (const matchedFactId of matchedFactIds) {\n const candidate = supportCandidates.find(\n (entry) => entry.id === matchedFactId,\n );\n supportingEvidenceIds.push(\n ...(candidate?.evidence || [])\n .map((entry) => entry.id)\n .filter((id: unknown): id is string => typeof id === 'string'),\n );\n }\n }\n supportingEvidenceIds = [...new Set(supportingEvidenceIds)];\n\n const articleEvidenceId =\n typeof metadata.articleEvidenceId === 'string'\n ? metadata.articleEvidenceId\n : null;\n const nextMetadata = {\n ...metadata,\n auditRunId,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n supportStatus,\n supportingFactIds: matchedFactIds,\n supportingEvidenceIds,\n rationale: assessment.rationale,\n confidence: assessment.confidence ?? metadata.confidence ?? null,\n claimFactId: link.factId,\n };\n const existingMetadata = getLinkMetadata(link);\n if (existingMetadata.generatedBy === FACT_AUDIT_GENERATED_BY) {\n link.setMetadata?.(nextMetadata);\n } else {\n link.setMetadata?.({\n ...existingMetadata,\n factAudit: nextMetadata,\n });\n }\n await link.save();\n\n if (articleEvidenceId) {\n const articleEvidence = await evidences.get({ id: articleEvidenceId });\n if (articleEvidence) {\n articleEvidence.updateMetadata({\n auditRunId,\n supportStatus,\n });\n await articleEvidence.save();\n }\n }\n\n await this.clearGeneratedSupportLinksForClaim(\n link.factId,\n articleEvidenceId,\n );\n for (const matchedFactId of matchedFactIds) {\n await this.safeAuditLink(\n matchedFactId,\n supportStatus === 'contradicted' ? 'contradicts' : 'supports',\n {\n ...nextMetadata,\n articleEvidenceId,\n },\n );\n }\n\n recheckedClaims += 1;\n }\n\n const state = await this.getFactAuditState();\n return {\n ...state,\n claimRecheck: {\n auditRunId,\n recheckedClaims,\n candidateFacts: supportCandidates.length,\n candidateEvidence: candidateEvidence.size,\n warnings,\n },\n };\n }\n\n public async recheckFactClaimsAction(\n options: FactAuditClaimRecheckOptions = {},\n ) {\n return this.recheckFactClaims(options);\n }\n\n public async updateFactEvidenceStatus(\n options: FactEvidenceStatusUpdateOptions = {},\n ) {\n await this.requireFactLinking('evidence status update');\n if (!this.id) {\n throw new Error('Cannot update fact evidence for unsaved content');\n }\n\n const status = normalizeFactEvidenceStatus(options.status);\n if (!status) {\n throw new Error('A valid evidence status is required');\n }\n\n const requestedEvidenceIds = [\n ...new Set(\n (options.evidenceIds || []).filter(\n (id): id is string => typeof id === 'string' && id.length > 0,\n ),\n ),\n ];\n const evidences = await this.getFactEvidenceCollection();\n const sourceMaterials = await this.getFactAuditSourceMaterials();\n const allowedSourceKeys = new Set(\n sourceMaterials.sources.map(\n (source: FactAuditSourceMaterial) =>\n `${source.sourceKind}:${source.sourceId}`,\n ),\n );\n const allowedEvidenceIds: string[] = [];\n\n for (const evidenceId of requestedEvidenceIds) {\n const evidence = await evidences.get({ id: evidenceId });\n if (!evidence) {\n continue;\n }\n\n if (\n this.tenantId &&\n evidence.tenantId &&\n evidence.tenantId !== this.tenantId\n ) {\n continue;\n }\n\n const metadata = getEvidenceMetadata(evidence);\n const sourceKey = `${evidence.sourceKind || ''}:${\n evidence.sourceId || ''\n }`;\n if (\n metadata.contentId === this.id ||\n (evidence.sourceKind === 'content' && evidence.sourceId === this.id) ||\n allowedSourceKeys.has(sourceKey)\n ) {\n allowedEvidenceIds.push(evidenceId);\n }\n }\n\n const updated = await evidences.bulkUpdateStatus(\n allowedEvidenceIds,\n status,\n {\n reason: options.reason,\n },\n );\n const state = await this.getFactAuditState();\n\n return {\n ...state,\n evidenceStatusUpdate: {\n status,\n requestedEvidenceIds,\n updatedEvidenceIds: updated\n .map((entry) => entry.id)\n .filter((id: unknown): id is string => typeof id === 'string'),\n skippedEvidenceIds: requestedEvidenceIds.filter(\n (id) => !allowedEvidenceIds.includes(id),\n ),\n },\n };\n }\n\n public async updateFactEvidenceStatusAction(\n options: FactEvidenceStatusUpdateOptions = {},\n ) {\n return this.updateFactEvidenceStatus(options);\n }\n\n public async getFactAuditState(): Promise<FactAuditState> {\n if (!this.id) {\n return {\n counts: {\n total: 0,\n supported: 0,\n unsupported: 0,\n contradicted: 0,\n needs_review: 0,\n },\n claims: [],\n resourceClaims: [],\n warnings: [],\n generatedBy: FACT_AUDIT_GENERATED_BY,\n latestAuditRunId: null,\n };\n }\n\n const [facts, factLinks] = await Promise.all([\n this.getFacts({\n relationship: 'referenced_in',\n latestOnly: false,\n includeSuperseded: false,\n }),\n this.getFactLinks({ relationship: 'referenced_in' }),\n ]);\n const factMap = new Map(\n facts\n .filter((fact) => fact.id)\n .map((fact) => [fact.id as string, fact] as const),\n );\n const evidences = await this.getFactEvidenceCollection();\n const allFacts = await this.getFactCollection();\n const generatedLinks = factLinks\n .map((link) => ({\n link,\n metadata: getGeneratedFactAuditMetadata(link),\n }))\n .filter(\n (\n entry,\n ): entry is { link: FactContent; metadata: Record<string, unknown> } =>\n entry.metadata !== null,\n );\n const claims: FactAuditClaim[] = [];\n const resourceClaimsByKey = new Map<string, FactAuditResourceClaim>();\n const warnings: string[] = [];\n let latestAuditRunId: string | null = null;\n\n for (const { link, metadata } of generatedLinks) {\n const fact = factMap.get(link.factId);\n if (!fact) {\n continue;\n }\n\n // Opaque audit-link metadata values; cast at the read boundary.\n latestAuditRunId =\n (metadata.auditRunId as string | null) || latestAuditRunId;\n const status = (metadata.supportStatus ||\n 'needs_review') as FactClaimSupportStatus;\n const matchedFactIds = Array.isArray(metadata.supportingFactIds)\n ? metadata.supportingFactIds\n : [];\n const articleEvidenceId =\n typeof metadata.articleEvidenceId === 'string'\n ? metadata.articleEvidenceId\n : null;\n const supportingEvidenceIds = new Set(\n Array.isArray(metadata.supportingEvidenceIds)\n ? metadata.supportingEvidenceIds.filter(\n (id: unknown): id is string => typeof id === 'string',\n )\n : [],\n );\n const [allClaimEvidence, matchedFacts] = await Promise.all([\n evidences.getForFact(fact.id as string),\n Promise.all(\n matchedFactIds.map(async (factId: string) => {\n const matchedFact = await allFacts.get({ id: factId });\n const matchedEvidence = (await evidences.getForFact(factId)).filter(\n (entry) =>\n supportingEvidenceIds.size === 0\n ? entry.sourceKind !== 'content' || entry.sourceId !== this.id\n : supportingEvidenceIds.has(entry.id as string),\n );\n return matchedFact\n ? {\n fact: serializeFact(matchedFact),\n evidence: matchedEvidence.map((entry) => ({\n ...serializeFact(entry),\n metadata:\n typeof entry.getMetadata === 'function'\n ? entry.getMetadata()\n : {},\n })),\n }\n : null;\n }),\n ),\n ]);\n const claimEvidence = allClaimEvidence.filter((entry) =>\n articleEvidenceId\n ? entry.id === articleEvidenceId\n : entry.sourceKind === 'content' && entry.sourceId === this.id,\n );\n\n claims.push({\n id: fact.id as string,\n fact: serializeFact(fact),\n supportStatus: status,\n // Opaque audit-link metadata values; cast at the read boundary.\n claimQuote: (metadata.claimQuote as string | null) || null,\n rationale: (metadata.rationale as string | null) || null,\n confidence: (metadata.confidence as number | null) ?? null,\n relationship: link.relationship || null,\n linkMetadata: metadata,\n evidence: claimEvidence.map((entry) => ({\n ...serializeFact(entry),\n metadata:\n typeof entry.getMetadata === 'function' ? entry.getMetadata() : {},\n })),\n matchedFacts: matchedFacts.filter(\n Boolean,\n ) as FactAuditClaim['matchedFacts'],\n });\n }\n\n const generatedEvidence = await evidences.list({\n where: { tenantId: this.tenantId ?? null },\n });\n for (const evidence of generatedEvidence) {\n const metadata =\n typeof evidence.getMetadata === 'function'\n ? evidence.getMetadata()\n : {};\n if (\n metadata.generatedBy !== FACT_AUDIT_GENERATED_BY ||\n metadata.contentId !== this.id ||\n evidence.sourceKind === 'content'\n ) {\n continue;\n }\n\n const fact = await allFacts.get({ id: evidence.factId });\n if (!fact) {\n continue;\n }\n\n const key = [\n evidence.factId,\n evidence.sourceKind,\n evidence.sourceId,\n evidence.evidenceKey,\n ].join(':');\n const serializedEvidence = {\n ...serializeFact(evidence),\n metadata,\n };\n const existing = resourceClaimsByKey.get(key);\n if (existing) {\n existing.evidence.push(serializedEvidence);\n continue;\n }\n\n resourceClaimsByKey.set(key, {\n id: fact.id as string,\n fact: serializeFact(fact),\n sourceKind: evidence.sourceKind || null,\n sourceId: evidence.sourceId || null,\n sourceUrl: evidence.sourceUrl || null,\n sourceTitle: evidence.sourceTitle || null,\n locator: evidence.locator || null,\n quote: evidence.quote || null,\n status: evidence.status || 'supports',\n confidence: evidence.confidence ?? null,\n evidence: [serializedEvidence],\n });\n }\n\n const latestReview = (\n await this.getContentReviewCollection()\n ).getLatestForPolicyKey(this.id as string, 'facts');\n const review = await latestReview;\n const reviewMetadata =\n review && typeof review.getMetadata === 'function'\n ? review.getMetadata()\n : {};\n if (\n reviewMetadata.generatedBy === FACT_AUDIT_GENERATED_BY &&\n Array.isArray(reviewMetadata.warnings)\n ) {\n warnings.push(...reviewMetadata.warnings);\n }\n\n const counts = {\n total: claims.length,\n supported: 0,\n unsupported: 0,\n contradicted: 0,\n needs_review: 0,\n };\n for (const claim of claims) {\n counts[claim.supportStatus] += 1;\n }\n\n return {\n counts,\n claims,\n resourceClaims: [...resourceClaimsByKey.values()],\n warnings,\n generatedBy: FACT_AUDIT_GENERATED_BY,\n latestAuditRunId,\n };\n }\n\n public async getFactAuditStateAction() {\n return this.getFactAuditState();\n }\n\n public async getFactsState(\n options: { relationship?: FactContentRelationship } = {},\n ) {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.factLinkingEnabled) {\n return {\n factIds: [],\n facts: [],\n factLinks: [],\n };\n }\n\n const relationship = options.relationship;\n const [facts, factLinks] = await Promise.all([\n this.getFacts({\n relationship,\n latestOnly: true,\n includeSuperseded: false,\n }),\n this.getFactLinks(relationship ? { relationship } : {}),\n ]);\n\n return {\n factIds: facts.map((fact) => fact.id).filter(Boolean),\n facts: facts.map(serializeFact),\n factLinks: factLinks.map(serializeFactLink),\n };\n }\n\n public async syncFactsState(\n options: {\n factIds?: string[];\n relationship?: FactContentRelationship;\n } = {},\n ) {\n const governance = await this.requireFactLinking('fact sync');\n const relationship =\n options.relationship || governance.defaultFactRelationship;\n const sync = await this.syncFacts(options.factIds || [], relationship);\n const state = await this.getFactsState({ relationship });\n return {\n ...state,\n sync,\n };\n }\n\n public async createVersion(options: CreateContentVersionOptions = {}) {\n const versions = await this.getContentVersionCollection();\n return versions.createSnapshot(this, options);\n }\n\n public async getVersions() {\n if (!this.id) {\n return [];\n }\n\n const versions = await this.getContentVersionCollection();\n return versions.listForContent(this.id as string);\n }\n\n public async restoreFromVersion(versionNumber: number) {\n const versions = await this.getContentVersionCollection();\n return versions.restoreIntoContent(this, versionNumber);\n }\n\n public async getReviews(kind?: RunContentReviewOptions['kind']) {\n if (!this.id) {\n return [];\n }\n\n const reviews = await this.getContentReviewCollection();\n return reviews.listForContent(this.id as string, kind);\n }\n\n public async listReviews(\n options: { kind?: RunContentReviewOptions['kind'] } = {},\n ) {\n const reviews = await this.getReviews(options.kind);\n return reviews.map(serializeContentReview);\n }\n\n public async getReviewRequirements(\n profileKey: string,\n governance?: ResolvedContentGovernance,\n ) {\n const resolvedGovernance = governance || (await this.resolveGovernance());\n return getContentReviewRequirements(\n profileKey,\n resolvedGovernance.availableProfiles,\n );\n }\n\n public async getGovernanceState(): Promise<ContentGovernanceState> {\n const governance = await this.resolveGovernance();\n\n if (!governance.isGoverned) {\n return {\n ...governance,\n reviewProfiles: [],\n };\n }\n\n return {\n ...governance,\n reviewProfiles: await this.listReviewProfilesAction(),\n };\n }\n\n public async getGovernanceStateAction() {\n return this.getGovernanceState();\n }\n\n public async listReviewProfilesAction() {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned) {\n return [];\n }\n\n return Promise.all(\n getContentReviewProfileKeys(governance.availableProfiles).map(\n (profileKey) => this.evaluateReviewProfile(profileKey),\n ),\n );\n }\n\n public async evaluateReviewProfile(\n profileKey: string,\n ): Promise<ContentReviewProfileEvaluation> {\n const governance = await this.resolveGovernance();\n const requirements = await this.getReviewRequirements(\n profileKey,\n governance,\n );\n\n if (requirements.length === 0) {\n return {\n profileKey,\n ready: true,\n complete: true,\n requirements: [],\n };\n }\n\n const reviews = await this.getContentReviewCollection();\n const reviewFingerprintCache = new Map<string, string>();\n const evaluatedRequirements = await Promise.all(\n requirements.map(async (requirement) => {\n if (!reviewFingerprintCache.has(requirement.policyKey)) {\n reviewFingerprintCache.set(\n requirement.policyKey,\n await this.buildReviewFingerprint(requirement.policyKey),\n );\n }\n\n const latestReview =\n this.id && requirement.policyKey\n ? await reviews.getLatestForPolicyKey(\n this.id as string,\n requirement.policyKey,\n )\n : null;\n const acceptedStatuses = getAcceptedContentReviewStatuses(requirement);\n const latestStatus = latestReview?.status ?? null;\n const latestMetadata =\n typeof latestReview?.getMetadata === 'function'\n ? latestReview.getMetadata()\n : {};\n const currentFingerprint =\n reviewFingerprintCache.get(requirement.policyKey) || null;\n const reviewedFingerprint =\n latestMetadata?.reviewFingerprint ||\n latestMetadata?.contentFingerprint ||\n null;\n const missing = !latestReview;\n const stale =\n !missing &&\n !!reviewedFingerprint &&\n reviewedFingerprint !== currentFingerprint;\n const executed =\n latestStatus !== null && latestStatus !== 'pending' && !stale;\n const satisfied =\n !stale &&\n latestStatus !== null &&\n acceptedStatuses.includes(latestStatus);\n\n return {\n kind: getContentReviewKind(\n requirement.policyKey,\n governance.reviewPolicies,\n ),\n policyKey: requirement.policyKey,\n label:\n requirement.label ||\n getContentReviewPolicy(\n requirement.policyKey,\n governance.reviewPolicies,\n )?.label ||\n requirement.policyKey,\n blocking: requirement.blocking === true,\n acceptedStatuses,\n missing,\n stale,\n executed,\n satisfied,\n latestReviewId: (latestReview?.id as string) || null,\n latestStatus,\n latestSummary: latestReview?.summary || null,\n };\n }),\n );\n\n return {\n profileKey,\n ready: evaluatedRequirements\n .filter((requirement) => requirement.blocking)\n .every((requirement) => requirement.satisfied),\n complete: evaluatedRequirements.every(\n (requirement) => requirement.executed,\n ),\n requirements: evaluatedRequirements,\n };\n }\n\n public async evaluateReviewProfileAction(\n options: { profileKey?: string } = {},\n ) {\n if (!options.profileKey) {\n throw new Error('profileKey is required');\n }\n\n return this.evaluateReviewProfile(options.profileKey);\n }\n\n public async isReadyForReviewProfile(profileKey: string): Promise<boolean> {\n const evaluation = await this.evaluateReviewProfile(profileKey);\n return evaluation.ready;\n }\n\n public async getPublishedTransparency() {\n if (!this.id) {\n return null;\n }\n\n const versions = await this.getContentVersionCollection();\n const latestPublicationVersion =\n await versions.getLatestPublishedForContent(this.id as string);\n\n return latestPublicationVersion?.getTransparency() || null;\n }\n\n public async getPublishedTransparencyAction() {\n return this.getPublishedTransparency();\n }\n\n public async previewTransparency() {\n const governance = await this.resolveGovernance();\n if (!governance.isGoverned || !governance.transparencyEnabled) {\n return null;\n }\n\n return this.buildTransparencySnapshot({\n snapshotKind: 'preview',\n governance,\n });\n }\n\n public async previewTransparencyAction() {\n return this.previewTransparency();\n }\n\n public async runReview(options: RunContentReviewOptions = {}) {\n const governance = await this.requireGovernance('review execution');\n\n if (!this.id) {\n throw new Error('Cannot review unsaved content');\n }\n\n const policyKey = options.policyKey || options.kind || 'custom';\n const policy = getContentReviewPolicy(policyKey, governance.reviewPolicies);\n const kind =\n options.kind ||\n getContentReviewKind(policyKey, governance.reviewPolicies);\n const facts =\n options.facts !== undefined\n ? options.facts\n : governance.factLinkingEnabled &&\n (kind === 'facts' || Boolean(options.factIds?.length))\n ? await this.getFacts({\n latestOnly: true,\n includeSuperseded: false,\n })\n : [];\n const filteredFacts =\n options.factIds && options.factIds.length > 0\n ? facts.filter((fact) => options.factIds?.includes(fact.id as string))\n : facts;\n const reviewPrompt = buildContentReviewPrompt({\n kind,\n content: this,\n facts: filteredFacts,\n policy,\n customInstructions: options.instructions,\n });\n const resolvedPrompt = await resolvePrompt(smrtContentReviewPrompt.key, {\n db: this.options.db,\n tenantId: this.tenantId,\n variables: {\n contentBody: this.body,\n contentDescription: this.description ?? '',\n contentId: this.id ?? '',\n contentTitle: this.title,\n kind,\n policyKey: policy?.key || kind,\n reviewPrompt,\n },\n });\n const reviewFingerprint = await this.buildReviewFingerprint(policyKey);\n const ai = this.ai as {\n message?: (\n prompt: string,\n options?: Record<string, unknown>,\n ) => Promise<string>;\n };\n if (!ai?.message) {\n throw new Error('AI client is not configured for content reviews');\n }\n\n const rawResponse = await ai.message(\n resolvedPrompt.text,\n promptMessageOptions(resolvedPrompt.ai),\n );\n const result = parseContentReviewResponse(rawResponse);\n const persistReview = async (content: Content) => {\n if (options.expectedUpdatedAt !== undefined) {\n await content.claimRevision(options.expectedUpdatedAt);\n }\n const version =\n options.createVersion === false\n ? null\n : await content.createVersion({\n kind: 'review',\n summary: result.summary,\n metadata: {\n kind,\n policyKey,\n reviewFingerprint,\n },\n });\n\n const reviews = await content.getContentReviewCollection();\n return reviews.createFromResult({\n contentId: content.id as string,\n contentVersionId: version?.id as string | undefined,\n kind,\n policyKey,\n reviewer: options.reviewer || 'system',\n result,\n metadata: {\n ...(options.metadata || {}),\n prompt: resolvedPrompt.text,\n rawResponse,\n reviewFingerprint,\n factIds: filteredFacts.map((fact) => fact.id),\n },\n tenantId: content.tenantId,\n });\n };\n\n if (options.expectedUpdatedAt !== undefined) {\n const db = this.db;\n if (!db.transaction) {\n throw new Error(\n 'Atomic content review persistence requires transaction support',\n );\n }\n return this.withTransaction(persistReview);\n }\n return persistReview(this);\n }\n\n public async runReviewAction(options: RunContentReviewOptions = {}) {\n let review: ContentReview;\n\n if (options.kind === 'facts') {\n review = await this.reviewFacts(options);\n } else if (options.kind === 'safety') {\n review = await this.reviewSafety(options);\n } else {\n review = await this.runReview(options);\n }\n\n return serializeContentReview(review);\n }\n\n public async reviewFacts(\n options: Omit<RunContentReviewOptions, 'kind'> = {},\n ) {\n return this.runReview({\n ...options,\n kind: 'facts',\n policyKey: options.policyKey || 'facts',\n });\n }\n\n public async reviewSafety(\n options: Omit<RunContentReviewOptions, 'kind'> = {},\n ) {\n const governance = await this.requireGovernance('safety review');\n const safetyPolicy = getContentReviewPolicy(\n options.policyKey || 'safety',\n governance.reviewPolicies,\n );\n const baseInstructions = safetyPolicy?.instructions || '';\n\n return this.runReview({\n ...options,\n kind: 'safety',\n policyKey: options.policyKey || 'safety',\n instructions:\n options.instructions && baseInstructions\n ? `${baseInstructions}\\n\\nAdditional app-level guidance:\\n${options.instructions}`\n : options.instructions || baseInstructions,\n });\n }\n\n public async getCorrections() {\n if (!this.id) {\n return [];\n }\n\n const corrections = await this.getContentCorrectionCollection();\n return corrections.listForContent(this.id as string);\n }\n\n public async listCorrections() {\n const corrections = await this.getCorrections();\n return corrections.map(serializeContentCorrection);\n }\n\n public async issueCorrection(options: IssueContentCorrectionOptions) {\n const governance = await this.requireGovernance('corrections');\n\n if (!this.id) {\n throw new Error('Cannot issue a correction for unsaved content');\n }\n\n let replacementFactId = '';\n if (\n governance.factLinkingEnabled &&\n options.factId &&\n options.correctedFactText\n ) {\n const facts = await this.getFactCollection();\n const existing = await facts.get({ id: options.factId });\n if (!existing) {\n throw new Error(`Fact not found for correction: ${options.factId}`);\n }\n\n // Create the correction branch directly so editorial corrections do not\n // block on synchronous embedding generation inside facts.branch().\n const replacement = await facts.create({\n textRefined: options.correctedFactText,\n textRaw: options.correctedFactText,\n type: existing.getType(),\n domain: existing.domain,\n status: 'active',\n tenantId: existing.tenantId ?? this.tenantId ?? null,\n previousFactId: options.factId,\n evolutionType: 'correction',\n });\n existing.status = 'superseded';\n await existing.save();\n replacementFactId = replacement.id as string;\n await this.addFact(replacementFactId);\n }\n\n const version =\n options.createVersion === false\n ? null\n : await this.createVersion({\n kind: 'correction',\n summary: options.summary,\n metadata: {\n factId: options.factId || null,\n replacementFactId: replacementFactId || null,\n },\n });\n const correctionDraft =\n options.createVersion === false\n ? null\n : await this.buildCorrectionDraftSnapshot(options, replacementFactId);\n const draftVersion =\n options.createVersion === false || !correctionDraft\n ? null\n : await this.createVersion({\n kind: 'draft',\n summary: `Auto-created correction draft: ${options.summary}`,\n snapshot: correctionDraft.snapshot,\n metadata: {\n ...correctionDraft.metadata,\n sourceCorrectionVersionId: (version?.id as string) || null,\n sourceCorrectionVersionNumber: version?.version ?? null,\n },\n });\n\n const corrections = await this.getContentCorrectionCollection();\n const shouldPublish = options.publish ?? this.status === 'published';\n return corrections.issue({\n contentId: this.id as string,\n contentVersionId: (version?.id as string) || '',\n factId: options.factId || '',\n replacementFactId,\n correctionType: options.correctionType || 'fact',\n status: shouldPublish ? 'published' : 'draft',\n summary: options.summary,\n incorrectText: options.incorrectText || '',\n correctedText: options.correctedText || options.correctedFactText || '',\n publicNote: options.publicNote || '',\n metadata: {\n ...(options.metadata || {}),\n autoGeneratedDraft: Boolean(draftVersion),\n draftVersionId: (draftVersion?.id as string) || null,\n draftVersionNumber: draftVersion?.version ?? null,\n sourceCorrectionVersionId: (version?.id as string) || null,\n sourceCorrectionVersionNumber: version?.version ?? null,\n correctionProfileKey: governance.correctionProfileKey || null,\n },\n tenantId: this.tenantId,\n publishedAt: shouldPublish ? new Date() : null,\n });\n }\n\n public async issueCorrectionAction(options: IssueContentCorrectionOptions) {\n const correction = await this.issueCorrection(options);\n return serializeContentCorrection(correction);\n }\n\n public async listVersions() {\n const versions = await this.getVersions();\n return versions.map(serializeContentVersion);\n }\n\n public async mutateVersionAction(\n options: CreateContentVersionOptions & {\n action?: string;\n versionNumber?: number | string;\n } = {},\n ) {\n if (options.action === 'restore') {\n const versionNumber = Number(options.versionNumber);\n if (!Number.isFinite(versionNumber)) {\n throw new Error('versionNumber is required to restore a version');\n }\n\n const restored = await this.restoreFromVersion(versionNumber);\n return serializeContent(restored);\n }\n\n const version = await this.createVersion(options);\n return serializeContentVersion(version);\n }\n\n /**\n * Note: toJSON() is inherited from SmrtObject\n *\n * The parent implementation handles:\n * - STI discriminator (_meta_type) for polymorphic queries\n * - Meta field extraction (_meta_data) for child-specific fields\n * - Automatic serialization of all fields from manifest\n *\n * DO NOT override toJSON() unless you call super.toJSON() first.\n * See issue #377 for details on why this override was removed.\n */\n\n // ============================================\n // Category Helper Methods\n // ============================================\n\n /**\n * Get category segments as array\n * @example 'politics/local' -> ['politics', 'local']\n */\n getCategorySegments(): string[] {\n if (!this.category) return [];\n return this.category.split('/').filter(Boolean);\n }\n\n /**\n * Get parent category path\n * @example 'politics/local/town' -> 'politics/local'\n * @example 'politics' -> null\n */\n getParentCategory(): string | null {\n const segments = this.getCategorySegments();\n if (segments.length <= 1) return null;\n return segments.slice(0, -1).join('/');\n }\n\n /**\n * Get root (top-level) category\n * @example 'politics/local/town' -> 'politics'\n */\n getRootCategory(): string | null {\n const segments = this.getCategorySegments();\n return segments[0] || null;\n }\n\n /**\n * Get all ancestor category paths (for breadcrumbs)\n * @example 'politics/local' -> ['politics', 'politics/local']\n */\n getAncestorPaths(): string[] {\n const segments = this.getCategorySegments();\n return segments.map((_, i) => segments.slice(0, i + 1).join('/'));\n }\n\n /**\n * Check if content belongs to a category (optionally including subcategories)\n * @param categoryPath - Category to check\n * @param includeChildren - If true, matches 'politics' for content in 'politics/local'\n */\n isInCategory(categoryPath: string, includeChildren = true): boolean {\n if (!this.category) return false;\n if (includeChildren) {\n return (\n this.category === categoryPath ||\n this.category.startsWith(`${categoryPath}/`)\n );\n }\n return this.category === categoryPath;\n }\n\n // ============================================\n // Asset Relationship Methods\n // ============================================\n\n /**\n * Get all assets associated with this content\n * @param relationship - Optional filter by relationship type (e.g., 'thumbnail', 'attachment')\n * @returns Promise resolving to array of assets\n */\n async getAssets(relationship?: string): Promise<Asset[]> {\n if (!this.id) {\n return [];\n }\n\n return this.resolveAssetsForLinks(\n await this.getContentAssetLinks(relationship),\n );\n }\n\n /**\n * Add an asset to this content with a relationship type\n * @param asset - The asset to associate\n * @param relationship - Relationship type (e.g., 'thumbnail', 'attachment', 'inline')\n * @param sortOrder - Optional sort order for display\n */\n async addAsset(\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n if (!this.id || !asset.id) {\n throw new Error('Cannot associate unsaved content or asset');\n }\n\n // Validate relationship - must start with letter/underscore, contain only alphanumeric and underscores\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(relationship)) {\n throw new Error(\n `Invalid relationship type \"${relationship}\"; must start with a letter or underscore and contain only letters, digits, and underscores`,\n );\n }\n\n // Validate sortOrder is a reasonable integer\n if (\n !Number.isInteger(sortOrder) ||\n sortOrder < 0 ||\n sortOrder > 2147483647\n ) {\n throw new Error(\n `Invalid sortOrder \"${sortOrder}\"; must be a non-negative integer`,\n );\n }\n\n const contentAssets = await this.getContentAssetCollection();\n await contentAssets.attach(this.id, asset.id, {\n relationship,\n sortOrder,\n tenantId: this.tenantId,\n });\n }\n\n /**\n * Remove an asset from this content\n * @param assetId - ID of the asset to remove\n * @param relationship - Optional specific relationship to remove (removes all if not specified)\n */\n async removeAsset(assetId: string, relationship?: string): Promise<void> {\n if (!this.id) {\n return;\n }\n\n try {\n const contentAssets = await this.getContentAssetCollection();\n await contentAssets.detach(\n this.id,\n assetId,\n relationship ? { relationship } : {},\n );\n } catch (error) {\n if (!isMissingTableError(error, 'content_assets')) {\n throw error;\n }\n }\n }\n\n // ============================================\n // Metadata Accessors (MetadataAccessor contract)\n // ============================================\n\n /**\n * Get the full metadata record. Always returns a plain object — never\n * `null`, never an array — so callers can safely read nested keys without\n * defensive checks.\n *\n * Pure read with no side-effect on `this.metadata`: if the field is\n * currently `null` (e.g. fresh from the DB) or non-record-shaped, an\n * empty object is returned but the field is **not** mutated. This avoids\n * accidentally marking the object dirty during a read, which would\n * otherwise cause SmrtObject's save lifecycle to write `{}` back over a\n * NULL column on the next save. Callers that want to normalise the\n * stored field should use {@link Content.setMetadata}.\n */\n getMetadata(): Record<string, unknown> {\n return isPlainMetadataRecord(this.metadata) ? this.metadata : {};\n }\n\n /**\n * Replace the full metadata record. Passing `null`/`undefined` (or any\n * non-record value such as an array) clears it to an empty object so\n * downstream readers can rely on the field always being a plain object.\n */\n setMetadata(metadata: Record<string, unknown> | null | undefined): void {\n this.metadata = isPlainMetadataRecord(metadata) ? { ...metadata } : {};\n }\n\n /**\n * Shallow-merge a patch over the current metadata. Returns the resulting\n * record so callers can chain reads without re-reading the field. Unlike\n * {@link Content.getMetadata}, this method does intentionally write back\n * to `this.metadata` because the merge is a write.\n */\n updateMetadata(\n patch: Partial<Record<string, unknown>>,\n ): Record<string, unknown> {\n const next = { ...this.getMetadata(), ...(patch ?? {}) };\n this.metadata = next;\n return next;\n }\n\n // ============================================\n // Thumbnail Convenience Methods\n // ============================================\n\n /**\n * Get the thumbnail image for this content\n * @returns Promise resolving to the thumbnail Image or null\n */\n async getThumbnail(): Promise<Image | null> {\n if (!this.thumbnailAssetId) {\n return null;\n }\n\n const images = await ImageCollection.create({\n db: this.options?.db,\n });\n\n return images.get({ id: this.thumbnailAssetId });\n }\n\n /**\n * Set the thumbnail image for this content\n * @param image - The image to set as thumbnail\n */\n async setThumbnail(image: Image): Promise<void> {\n // Add as asset with 'thumbnail' relationship\n await this.addAsset(image, 'thumbnail', 0);\n\n // Update thumbnailAssetId\n this.thumbnailAssetId = image.id ?? null;\n await this.save();\n }\n\n /**\n * Generate a thumbnail for this content using the specified strategy\n *\n * @param options - Thumbnail generation options including strategy\n * @returns Promise resolving to the generated Image\n *\n * @example Headline card thumbnail\n * ```typescript\n * const thumbnail = await content.generateThumbnail({\n * strategy: 'headline-card',\n * brandColor: '#1a56db',\n * logoUrl: 'https://example.com/logo.png'\n * });\n * ```\n *\n * @example Static map thumbnail (requires metadata.latitude/longitude)\n * ```typescript\n * const thumbnail = await content.generateThumbnail({\n * strategy: 'static-map',\n * mapProvider: 'mapbox'\n * });\n * ```\n *\n * @example AI-generated thumbnail\n * ```typescript\n * const thumbnail = await content.generateThumbnail({\n * strategy: 'ai-generate'\n * });\n * ```\n */\n async generateThumbnail(options: ThumbnailOptions): Promise<Image> {\n const generator = new ThumbnailGenerator(this, this.options);\n const image = await generator.generate(options);\n await this.setThumbnail(image);\n return image;\n }\n}\n","/**\n * Bounded, tenant-safe content data queries (#2452) over the canonical\n * transport-neutral query protocol (#2444).\n *\n * `ContentList` (and any other consumer) sends a `DataQueryRequest`; this\n * module normalizes it against a schema derived from the registered `Content`\n * field metadata, executes it through `SmrtCollection.list/count/facets` — never\n * raw SQL, never a full collection hydration — and returns a validated\n * `DataQueryResult`.\n *\n * Three independent boundaries protect a read:\n *\n * 1. **Schema** — `buildContentQuerySchema()` declares the only field ids a\n * caller may name. `sensitive`, `readPermission`-gated, transient,\n * non-column-backed, tenant, and internal (`_`-prefixed) fields are never\n * declared, so `normalizeDataQueryRequest()` rejects them outright.\n * 2. **Collection** — every projection, order term, and predicate still passes\n * through `SmrtCollection`, which independently refuses sensitive and\n * permission-gated fields. A schema bug alone cannot expose a field.\n * 3. **Scope** — trusted, server-derived conditions are ANDed into every branch\n * of the caller's filter, so a request can only ever narrow the read.\n */\n\nimport {\n createDataQueryFingerprint,\n DataQueryValidationError,\n normalizeDataQueryRequest,\n normalizeDataQueryResult,\n normalizeDataQuerySchema,\n ObjectRegistry,\n} from '@happyvertical/smrt-core';\nimport {\n getCurrentTenant,\n isSuperAdminBypass,\n isSystemContext,\n isTenancyEnabled,\n} from '@happyvertical/smrt-tenancy';\nimport type {\n DataQueryFacetResult,\n DataQueryFieldDescriptor,\n DataQueryFilter,\n DataQueryFilterOperator,\n DataQueryRequest,\n DataQueryResult,\n DataQueryRow,\n DataQuerySchema,\n DataQuerySort,\n} from '@happyvertical/smrt-types';\n\n/** Registered qualified name of the STI base every content query reads. */\nexport const CONTENT_QUERY_CLASS_NAME = '@happyvertical/smrt-content:Content';\n\n/** Row identity for every content query. Never a page or display index. */\nexport const CONTENT_QUERY_IDENTITY_FIELD = 'id';\n\n/**\n * Deterministic default ordering: most recently updated first, tie-broken by\n * id. `updated_at` is chosen over `publish_date` deliberately — it is always\n * populated, so ordering never depends on engine-specific NULL placement, and\n * it matches the ordering the rest of the `Contents` collection already uses.\n */\nexport const CONTENT_QUERY_DEFAULT_SORT: DataQuerySort[] = [\n { field: 'updated_at', direction: 'desc' },\n { field: CONTENT_QUERY_IDENTITY_FIELD, direction: 'asc' },\n];\n\n/** Page bounds. Content rows can carry long text, so the ceiling is modest. */\nexport const CONTENT_QUERY_DEFAULT_PAGE_LIMIT = 50;\nexport const CONTENT_QUERY_MAX_PAGE_LIMIT = 200;\nexport const CONTENT_QUERY_MAX_RESULT_BYTES = 1_000_000;\n\n/**\n * Fields the content query never declares even though they are column-backed.\n *\n * `body` is a document, not list data: the canonical envelope caps a scalar at\n * {@link DATA_QUERY_MAX_STRING_LENGTH} characters, so a real body could only\n * ever be returned mangled. Read a body through the item route\n * (`GET /api/v1/contents/{id}`), which serializes it in full.\n */\nexport const CONTENT_QUERY_EXCLUDED_FIELD_IDS: readonly string[] = ['body'];\n\n/**\n * The protocol's hard scalar cap (`dataQueryScalar` in\n * `@happyvertical/smrt-core`): a string value longer than this makes the whole\n * result invalid, so long values are truncated and flagged instead.\n */\nexport const DATA_QUERY_MAX_STRING_LENGTH = 4_096;\n\n/**\n * The protocol's limits for a `json` field, mirrored from\n * `canonicalJson` in `@happyvertical/smrt-core`. Exceeding any of them makes\n * the whole result invalid rather than the one value, so the adapter bounds a\n * JSON document itself (see `boundJsonValue`).\n */\nexport const DATA_QUERY_MAX_JSON_STRING_LENGTH = 65_536;\nexport const DATA_QUERY_MAX_JSON_CONTAINER_ITEMS = 1_000;\nexport const DATA_QUERY_MAX_JSON_DEPTH = 16;\n\n/**\n * Keys `plainObject` refuses outright (`FORBIDDEN_DATA_QUERY`), mirrored from\n * `@happyvertical/smrt-core`. This is a *validity* rule rather than a size\n * limit, and it is the reachable one: `metadata` is the documented extension\n * point, it is writable through the generated REST API and through\n * `Content.mirror()` ingestion, and `JSON.parse` of the stored column creates\n * an own `__proto__` property. One row carrying such a key would otherwise make\n * every query projecting that field return 400 for the whole page, with no way\n * to page past it.\n */\nexport const DATA_QUERY_FORBIDDEN_JSON_KEYS: ReadonlySet<string> = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n]);\n\n/**\n * Bytes held back from the row budget for the envelope itself (request id,\n * fingerprint, page, total, freshness, warnings). The normalizer re-checks the\n * complete serialized envelope against `maxResultBytes`, so the row budget must\n * leave room for it.\n */\nexport const RESULT_ENVELOPE_RESERVE_BYTES = 4_096;\n\n/**\n * Smallest row allowance a page can be given and still answer with anything.\n * Comfortably holds one identity-only row plus a few projected scalars.\n */\nconst MIN_RESULT_ROW_BYTES = 512;\n\n/**\n * The smallest `maxResultBytes` a schema may declare.\n *\n * The row budget is `maxResultBytes` minus the envelope reserve, so a schema\n * below the reserve leaves nothing for rows: every query would answer with an\n * empty page flagged `truncated`, forever, and a page small enough that the\n * metadata alone overruns the budget would fail `normalizeDataQueryResult`\n * outright. Both look like \"no content matched\" from the outside.\n *\n * `schema` is trusted adapter configuration, never caller input, so a budget\n * this small is a deployment mistake rather than a bad request — and it is\n * refused loudly at the boundary rather than degrading every read.\n */\nexport const CONTENT_QUERY_MIN_RESULT_BYTES =\n RESULT_ENVELOPE_RESERVE_BYTES + MIN_RESULT_ROW_BYTES;\n\n/**\n * Refuse a result budget too small to carry an envelope and a row.\n *\n * Throws a plain `Error`, not a `DataQueryValidationError`: a validation error\n * becomes a 400 and tells the caller they asked for something wrong, when the\n * fault is in the host's own schema. This mirrors how an unusable `scope` is\n * refused.\n *\n * Applied uniformly across query modes, including `count`, which returns no\n * rows and would technically work. A schema too small to serve its own row\n * mode is misconfigured whatever this particular request asked for, and letting\n * `count` succeed would hide that until the first rows query.\n */\nfunction assertUsableResultBudget(schema: DataQuerySchema): void {\n const budget = schema.maxResultBytes ?? CONTENT_QUERY_MAX_RESULT_BYTES;\n if (budget >= CONTENT_QUERY_MIN_RESULT_BYTES) return;\n throw new Error(\n `Content query schema maxResultBytes must be at least ${CONTENT_QUERY_MIN_RESULT_BYTES} ` +\n `(${RESULT_ENVELOPE_RESERVE_BYTES} reserved for the result envelope, ` +\n `${MIN_RESULT_ROW_BYTES} for rows); received ${budget}.`,\n );\n}\n\n/**\n * Upper bound on OR branches handed to the collection query builder.\n *\n * Exported so a client can mirror it: the null-safe `ne`/`notIn` lowering below\n * turns one predicate into two branches, and an `all` of them multiplies, so a\n * caller has to be able to stop short of the ceiling rather than be refused.\n */\nexport const MAX_CONTENT_QUERY_OR_BRANCHES = 128;\n\nconst encoder = new TextEncoder();\n\n/** One AND-ed group of SMRT `where` conditions. */\ntype WhereCondition = Record<string, unknown>;\n\n/** Bounded disjunctive-normal-form `where`: outer OR of inner AND groups. */\ntype WhereDnf = WhereCondition[][];\n\n/**\n * The subset of `SmrtCollection` a content query needs. Structural so this\n * module never imports `Contents` (which imports this one) and so a host can\n * supply an application-owned collection that preserves the same boundary.\n */\nexport interface ContentQueryCollection {\n list(options: {\n select?: readonly string[];\n where?: WhereCondition | WhereDnf;\n offset?: number;\n limit?: number;\n orderBy?: string | string[];\n }): Promise<Record<string, unknown>[]>;\n count(options?: { where?: WhereCondition | WhereDnf }): Promise<number>;\n facets(options: {\n fields: readonly { field: string; limit?: number }[];\n where?: WhereCondition | WhereDnf;\n }): Promise<{ field: string; values: { value: unknown; count: number }[] }[]>;\n}\n\n/**\n * Trusted, server-derived narrowing conditions.\n *\n * Each entry is a plain SMRT `where` condition object (`{ status: 'published' }`,\n * `{ 'publish_date <=': someInstant }`, `{ category: ['news', 'sport'] }`).\n * Every condition is ANDed into **every** OR branch of the caller's filter.\n */\nexport type ContentQueryScope = WhereCondition | readonly WhereCondition[];\n\nexport interface ContentQueryOptions {\n /**\n * Application-supplied narrowing conditions derived from the authenticated\n * server-side context — never from the request body.\n *\n * This is how an application expresses site, organization, workspace, or\n * ownership scoping. The framework deliberately does not model site or\n * organization: `Content` carries tenancy plus a freeform `metadata` blob and\n * nothing else, so the host that knows what \"site\" means for its deployment\n * passes the conditions that mean it here (a subclass column, a denormalized\n * id column, a pre-resolved id list, and so on).\n *\n * SECURITY INVARIANT: scope may only come from trusted server-side context. A\n * `DataQueryRequest` has no way to supply, replace, widen, or remove a scope\n * condition — scope conditions are ANDed into every branch of the caller's\n * filter, including inside `any`/`not` branches, so a request can only ever\n * narrow the result set. Never derive `scope` from client input.\n *\n * `undefined` and `[]` mean OPPOSITE things. Omit the option to apply no\n * application scope; pass an empty array to say the principal is permitted\n * nothing, which matches no rows. A host deriving the scope from an\n * allowed-resource list gets the safe answer by construction: an empty list\n * denies instead of unlocking the whole tenant.\n */\n scope?: ContentQueryScope;\n /**\n * Trusted adapter policy override. Defaults to the memoized `Content` schema.\n * This is adapter configuration, never caller input; it exists so a host (or\n * a test) can execute the same bounded protocol against another registered\n * class. Supplying a schema does NOT relax the collection-level field checks.\n */\n schema?: DataQuerySchema;\n}\n\n/**\n * Validate a host-supplied schema before anything depends on it.\n *\n * `executeContentQuery` performs the same checks on every request, so a\n * misconfigured schema can never actually serve a query — but a request-path\n * failure reaches the caller as an opaque 500 through the generated route, with\n * the message that names the minimum only in the server log. Call this once\n * where the schema is configured, so the failure lands next to the mistake:\n *\n * ```ts\n * const schema = buildAdminContentSchema();\n * assertContentQuerySchema(schema); // at startup, not on the first request\n * ```\n *\n * Covers core's own schema rules as well as this adapter's, so one call is\n * enough.\n */\nexport function assertContentQuerySchema(schema: DataQuerySchema): void {\n normalizeDataQuerySchema(schema);\n assertUsableResultBudget(schema);\n}\n\n/**\n * Resolve the fail-closed tenant read scope for a content query.\n *\n * Mirrors the generated route helpers `tenantReadScope()` /\n * `tenantReadOptionsScope()`: with tenancy enabled and no active tenant\n * context, reads are restricted to NULL-tenant (global) rows rather than\n * passing through unfiltered, because `Content` is\n * `@TenantScoped({ mode: 'optional' })` and the interceptor alone would not\n * filter an anonymous read. `withSystemContext()` and super-admin bypass remain\n * the explicit, deliberate cross-tenant paths.\n */\nexport function resolveContentTenantReadScope():\n | { tenantId: string | null }\n | undefined {\n if (!isTenancyEnabled()) return undefined;\n if (isSuperAdminBypass() || isSystemContext()) return undefined;\n return { tenantId: getCurrentTenant()?.tenantId ?? null };\n}\n\nfunction queryFail(message: string, code = 'INVALID_DATA_QUERY'): never {\n throw new DataQueryValidationError(message, code);\n}\n\nfunction isPlainRecord(value: unknown): value is WhereCondition {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction queryFieldType(\n type: unknown,\n): DataQueryFieldDescriptor['type'] | undefined {\n switch (type) {\n case 'text':\n case 'foreignKey':\n case 'crossPackageRef':\n return 'string';\n case 'integer':\n case 'decimal':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'datetime':\n return 'datetime';\n case 'json':\n return 'json';\n // `meta`, `oneToMany`, `manyToMany`, and anything a future scanner adds are\n // not column-backed scalars. Fail closed by leaving them undeclared.\n default:\n return undefined;\n }\n}\n\nfunction filterOperatorsFor(\n type: DataQueryFieldDescriptor['type'],\n): DataQueryFilterOperator[] | undefined {\n switch (type) {\n case 'string':\n return ['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'like'];\n case 'number':\n case 'datetime':\n return ['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn'];\n case 'boolean':\n return ['eq', 'ne', 'in', 'notIn'];\n // JSON columns store serialized documents; there is no portable predicate\n // for them at the collection boundary, so they stay unfilterable.\n case 'json':\n return undefined;\n }\n}\n\ninterface RegistryFieldLike {\n type?: unknown;\n sensitive?: unknown;\n readPermission?: unknown;\n transient?: unknown;\n _meta?: Record<string, unknown>;\n __tenancy?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nfunction meta(field: RegistryFieldLike): Record<string, unknown> {\n return isPlainRecord(field._meta) ? field._meta : {};\n}\n\n/** `sensitive`/`readPermission` may be declared top-level or under `_meta`. */\nfunction isRestrictedField(field: RegistryFieldLike): boolean {\n const fieldMeta = meta(field);\n return (\n field.sensitive === true ||\n fieldMeta.sensitive === true ||\n typeof field.readPermission === 'string' ||\n typeof fieldMeta.readPermission === 'string'\n );\n}\n\nfunction isTransientField(field: RegistryFieldLike): boolean {\n return field.transient === true || meta(field).transient === true;\n}\n\nfunction isTenantField(name: string, field: RegistryFieldLike): boolean {\n const fieldMeta = meta(field);\n const tenancy = isPlainRecord(field.__tenancy)\n ? field.__tenancy\n : isPlainRecord(fieldMeta.__tenancy)\n ? fieldMeta.__tenancy\n : undefined;\n return (\n tenancy?.isTenantIdField === true ||\n name === 'tenantId' ||\n name === 'tenant_id'\n );\n}\n\n/**\n * Build a `DataQuerySchema` from registered field metadata.\n *\n * Excluded, and therefore un-nameable by any caller:\n * - `sensitive` and `readPermission`-gated fields (exposure boundary);\n * - transient and non-column-backed fields (`meta`, `oneToMany`, `manyToMany`);\n * - the tenant field — tenancy is enforced by the executor, and a caller must\n * never be able to filter, sort, project, or facet on it;\n * - internal `_`-prefixed fields such as the STI discriminator.\n */\nasync function buildQuerySchemaForClass(\n qualifiedName: string,\n excluded: ReadonlySet<string>,\n): Promise<DataQuerySchema> {\n const registered = (await ObjectRegistry.getAllFields(qualifiedName)) as Map<\n string,\n RegistryFieldLike\n >;\n const fields: DataQueryFieldDescriptor[] = [];\n for (const [name, field] of registered) {\n if (name.startsWith('_')) continue;\n if (excluded.has(name)) continue;\n if (isRestrictedField(field)) continue;\n if (isTransientField(field)) continue;\n if (isTenantField(name, field)) continue;\n const type = queryFieldType(field.type);\n if (!type) continue;\n const filterOperators = filterOperatorsFor(type);\n fields.push({\n id: name,\n type,\n projectable: true,\n // JSON documents have no portable ordering at the SQL layer.\n sortable: type !== 'json',\n // Facets group by the stored column: only bounded scalar domains are\n // useful, and the identity field is unique by definition.\n facetable:\n name !== CONTENT_QUERY_IDENTITY_FIELD &&\n (type === 'string' || type === 'boolean' || type === 'number'),\n ...(filterOperators ? { filterOperators } : {}),\n });\n }\n\n const identity = fields.find(\n (field) => field.id === CONTENT_QUERY_IDENTITY_FIELD,\n );\n if (!identity) {\n throw new Error(\n `${qualifiedName} does not declare a queryable '${CONTENT_QUERY_IDENTITY_FIELD}' field`,\n );\n }\n\n const declared = new Set(fields.map((field) => field.id));\n const defaultSort = CONTENT_QUERY_DEFAULT_SORT.filter((term) =>\n declared.has(term.field),\n );\n\n return {\n version: 1,\n identityField: CONTENT_QUERY_IDENTITY_FIELD,\n fields,\n defaultPageLimit: CONTENT_QUERY_DEFAULT_PAGE_LIMIT,\n maxPageLimit: CONTENT_QUERY_MAX_PAGE_LIMIT,\n maxResultBytes: CONTENT_QUERY_MAX_RESULT_BYTES,\n ...(defaultSort.length > 0 ? { defaultSort } : {}),\n supports: {\n // Offset paging only: cursor paging would need an opaque, query-bound\n // cursor the collection read path does not issue today.\n cursorPagination: false,\n // Live table reads; no snapshot or as-of capability.\n consistency: false,\n facets: true,\n },\n };\n}\n\nconst schemaCache = new Map<string, Promise<DataQuerySchema>>();\n\n/**\n * Memoized query schema for one registered class (keyed by qualified name).\n * The schema is derived from immutable registration metadata, so it is built\n * once per process rather than per request.\n */\nexport function buildDataQuerySchemaForClass(\n qualifiedName: string,\n options: { exclude?: readonly string[] } = {},\n): Promise<DataQuerySchema> {\n const excluded = [...new Set(options.exclude ?? [])].sort();\n const key = `${qualifiedName}::${excluded.join(',')}`;\n const cached = schemaCache.get(key);\n if (cached) return cached;\n const pending = buildQuerySchemaForClass(\n qualifiedName,\n new Set(excluded),\n ).catch((cause) => {\n schemaCache.delete(key);\n throw cause;\n });\n schemaCache.set(key, pending);\n return pending;\n}\n\n/** Memoized bounded query schema for `Content`. */\nexport function buildContentQuerySchema(): Promise<DataQuerySchema> {\n return buildDataQuerySchemaForClass(CONTENT_QUERY_CLASS_NAME, {\n exclude: CONTENT_QUERY_EXCLUDED_FIELD_IDS,\n });\n}\n\n/** Testing seam: drop memoized schemas so a rebuild re-reads the registry. */\nexport function clearContentQuerySchemaCache(): void {\n schemaCache.clear();\n}\n\nfunction inverseOperator(\n operator: DataQueryFilterOperator,\n): DataQueryFilterOperator {\n switch (operator) {\n case 'eq':\n return 'ne';\n case 'ne':\n return 'eq';\n case 'gt':\n return 'lte';\n case 'gte':\n return 'lt';\n case 'lt':\n return 'gte';\n case 'lte':\n return 'gt';\n case 'in':\n return 'notIn';\n case 'notIn':\n return 'in';\n case 'like':\n return queryFail(\n 'Content queries cannot negate a like predicate',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n}\n\n/**\n * Lower one condition to bounded DNF.\n *\n * `negated` says the condition was reached through an odd number of `not`s and\n * its operator has already been inverted by {@link inverseOperator}. It matters\n * only for the ordered comparisons: `lte` asked for directly must exclude a\n * NULL row, exactly as SQL and the local evaluator both do, while the `lte`\n * that `not(gt)` produces must INCLUDE it or the predicate and its negation are\n * not complements and a row with no value falls through both.\n */\nfunction conditionToDnf(\n field: string,\n operator: DataQueryFilterOperator,\n value: unknown,\n negated = false,\n): WhereDnf {\n const key = (suffix: string) => (suffix ? `${field} ${suffix}` : field);\n const single = (whereKey: string, whereValue: unknown): WhereDnf => [\n [{ [whereKey]: whereValue }],\n ];\n\n if (operator === 'in') {\n const values = (value as unknown[]) ?? [];\n const nonNull = values.filter((entry) => entry !== null);\n if (nonNull.length === 0) return single(field, null);\n if (nonNull.length === values.length) return single(key('in'), nonNull);\n // SQL `IN` never matches NULL; model the caller-visible union explicitly.\n return [[{ [field]: null }], [{ [key('in')]: nonNull }]];\n }\n\n if (operator === 'notIn') {\n const values = (value as unknown[]) ?? [];\n if (values.length === 0) {\n // The normalizer refuses an empty list, so this is unreachable; failing\n // is still the only safe answer, because \"excludes nothing\" would have to\n // be an unbounded OR branch.\n return queryFail(\n 'Content query notIn requires at least one value',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n // `buildWhere()` has no NOT IN primitive. A bounded AND of inequalities has\n // the same null-safe semantics and stays fully validated by the collection.\n const inequalities = values\n .filter((entry) => entry !== null)\n .map((entry) => ({ [key('!=')]: entry }));\n if (values.some((entry) => entry === null)) {\n // A listed `null` says \"rows with no value are excluded too\", so the\n // null-safe union below must NOT be added — it would return exactly the\n // rows the caller asked to exclude, and would make `in [x, null]` and its\n // negation overlap. `{ field '!=': null }` is `IS NOT NULL`.\n return [[...inequalities, { [key('!=')]: null }]];\n }\n // No `null` was listed. SQL's `<>` is UNKNOWN for NULL, so a bare AND of\n // inequalities silently excludes rows with no value at all — while the\n // caller-visible meaning of \"not one of these\" includes them, and the local\n // evaluator agrees. Model that union explicitly, exactly as `in` does\n // above, so the same shared link returns the same rows whether the list is\n // server-backed or not.\n return [[{ [field]: null }], inequalities];\n }\n\n if (operator === 'ne' && value !== null) {\n // Same reasoning as `notIn`. A `ne null` is left alone: it is the\n // `isNotNull` predicate, and unioning IS NULL into it would match every row.\n return [[{ [field]: null }], [{ [key('!=')]: value }]];\n }\n\n const suffixes: Record<\n Exclude<DataQueryFilterOperator, 'in' | 'notIn'>,\n string\n > = {\n eq: '',\n ne: '!=',\n gt: '>',\n gte: '>=',\n lt: '<',\n lte: '<=',\n like: 'like',\n };\n\n if (\n negated &&\n (operator === 'gt' ||\n operator === 'gte' ||\n operator === 'lt' ||\n operator === 'lte')\n ) {\n // The complement of an ordered comparison. SQL's `>`/`<` are UNKNOWN for\n // NULL, so `not(gt v)` lowered as a bare `<= v` leaves a row with no value\n // matching NEITHER side — the same gap `ne`/`notIn` close above. `eq`\n // reached by negating `ne` gets no union: the complement of\n // \"IS NULL OR <> v\" is \"= v\", which excludes NULL by construction.\n return [[{ [field]: null }], [{ [key(suffixes[operator])]: value }]];\n }\n\n return single(key(suffixes[operator]), value);\n}\n\nfunction crossProduct(left: WhereDnf, right: WhereDnf): WhereDnf {\n if (left.length * right.length > MAX_CONTENT_QUERY_OR_BRANCHES) {\n return queryFail(\n `Content query filter expands beyond ${MAX_CONTENT_QUERY_OR_BRANCHES} OR branches`,\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n return left.flatMap((leftGroup) =>\n right.map((rightGroup) => [...leftGroup, ...rightGroup]),\n );\n}\n\nfunction filterToDnf(\n filter: DataQueryFilter,\n declared: ReadonlySet<string>,\n negate = false,\n): WhereDnf {\n if (filter.kind === 'condition') {\n // The normalizer already rejected undeclared fields; re-check so a schema\n // and an executor can never disagree about what is queryable.\n if (!declared.has(filter.field)) {\n return queryFail(\n `Content query filter field is not declared: ${filter.field}`,\n 'DATA_QUERY_FILTER_NOT_ALLOWED',\n );\n }\n return conditionToDnf(\n filter.field,\n negate ? inverseOperator(filter.operator) : filter.operator,\n filter.value,\n negate,\n );\n }\n\n if (filter.kind === 'not') {\n return filterToDnf(filter.filter, declared, !negate);\n }\n\n // De Morgan: a negated `any` behaves as an `all` of negated children.\n const combineWithAnd =\n (filter.kind === 'all' && !negate) || (filter.kind === 'any' && negate);\n if (combineWithAnd) {\n return filter.filters.reduce<WhereDnf>(\n (combined, child) =>\n crossProduct(combined, filterToDnf(child, declared, negate)),\n [[]],\n );\n }\n\n const branches = filter.filters.flatMap((child) =>\n filterToDnf(child, declared, negate),\n );\n if (branches.length > MAX_CONTENT_QUERY_OR_BRANCHES) {\n return queryFail(\n `Content query filter expands beyond ${MAX_CONTENT_QUERY_OR_BRANCHES} OR branches`,\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n return branches;\n}\n\nfunction normalizeScopeConditions(\n scope: ContentQueryScope | undefined,\n): WhereCondition[] {\n if (scope === undefined) return [];\n const candidates = Array.isArray(scope)\n ? (scope as readonly unknown[])\n : [scope];\n return candidates.map((candidate) => {\n if (!isPlainRecord(candidate) || Object.keys(candidate).length === 0) {\n throw new Error(\n 'Content query scope conditions must be non-empty plain objects',\n );\n }\n return { ...candidate };\n });\n}\n\n/**\n * A scope condition no row can satisfy.\n *\n * `id` is the primary key, so it is never NULL and `id IS NULL` is false for\n * every row on every dialect — the portable way to say \"permit nothing\" through\n * a `where` clause rather than by special-casing the read path.\n */\nconst DENY_ALL_SCOPE_CONDITION: WhereCondition = Object.freeze({\n [CONTENT_QUERY_IDENTITY_FIELD]: null,\n});\n\n/**\n * Normalize the APPLICATION scope, where an explicitly empty set denies.\n *\n * The two absences are not the same thing, and conflating them is an\n * authorization fail-open:\n *\n * - `undefined` means \"this deployment applies no application scope\" — read\n * the tenant, subject to tenancy alone.\n * - `[]` means \"the set of conditions this principal is permitted is EMPTY\".\n * A host builds a scope from an allowed-resource list — the sites,\n * workspaces, or organizations this principal may see — and that list is\n * empty exactly when the principal may see nothing. Treating it as \"no\n * scope\" turns *access to zero sites* into *access to every row in the\n * tenant*, which is the failure the two-layer scope design exists to\n * prevent.\n *\n * An empty set is a legitimate authorization state, not a programming error, so\n * it lowers to a predicate that matches nothing rather than throwing — a throw\n * would answer a correct \"you may see nothing\" with a 500.\n */\nfunction normalizeApplicationScope(\n scope: ContentQueryScope | undefined,\n): WhereCondition[] {\n if (scope === undefined) return [];\n const conditions = normalizeScopeConditions(scope);\n return conditions.length > 0 ? conditions : [{ ...DENY_ALL_SCOPE_CONDITION }];\n}\n\n/**\n * AND every trusted scope condition into every OR branch of the caller's\n * filter.\n *\n * This is the whole widening story: a branch can only ever gain conditions, and\n * conjunction is monotonically narrowing, so no filter shape — including\n * `any` (OR) and `not` (negation) — can produce a branch that escapes the base\n * scope. A caller predicate on a scoped field can contradict the scope (and\n * return nothing); it can never replace it.\n *\n * Returns `undefined` only when there is neither a scope nor a filter, so the\n * collection sees a plain unfiltered read rather than an empty DNF branch.\n *\n * An explicitly EMPTY scope denies rather than passing through; see\n * {@link normalizeApplicationScope}. Pass `undefined`, not `[]`, to mean \"no\n * application scope\".\n */\nexport function mergeContentQueryScope(\n scope: ContentQueryScope | undefined,\n callerWhere: WhereDnf | undefined,\n): WhereDnf | undefined {\n const scopeConditions = normalizeApplicationScope(scope);\n const branches: WhereDnf =\n callerWhere && callerWhere.length > 0 ? callerWhere : [[]];\n const merged = branches.map((branch) => [...scopeConditions, ...branch]);\n if (merged.length === 1 && merged[0].length === 0) return undefined;\n if (merged.some((branch) => branch.length === 0)) {\n // An empty OR branch matches every row, which would widen the read.\n return queryFail(\n 'Content query filter produced an unbounded OR branch',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n return merged;\n}\n\n/**\n * The result normalizer's warning rule: at most 100 entries, each a non-empty\n * string of at most 512 characters. A warning that names a field list derived\n * from a host-supplied schema could otherwise exceed it and fail the result\n * this warning exists to explain.\n */\nexport const DATA_QUERY_MAX_WARNINGS = 100;\nexport const DATA_QUERY_MAX_WARNING_LENGTH = 512;\n\n/** Appends a warning bounded to what `normalizeDataQueryResult` accepts. */\nfunction pushWarning(warnings: string[], message: string): void {\n if (warnings.length >= DATA_QUERY_MAX_WARNINGS) return;\n const text =\n message.length > DATA_QUERY_MAX_WARNING_LENGTH\n ? `${message.slice(0, DATA_QUERY_MAX_WARNING_LENGTH - 1)}\\u2026`\n : message;\n if (text.length > 0) warnings.push(text);\n}\n\n/** Records values the adapter had to shorten so the caller is told. */\nexport interface TruncationLog {\n fields: Set<string>;\n}\n\n/**\n * Cut an over-long string to the protocol's scalar cap without leaving a lone\n * surrogate behind.\n */\nfunction capString(\n value: string,\n limit = DATA_QUERY_MAX_STRING_LENGTH,\n): string {\n if (value.length <= limit) return value;\n const cut = value.slice(0, limit);\n const last = cut.charCodeAt(cut.length - 1);\n return last >= 0xd800 && last <= 0xdbff ? cut.slice(0, -1) : cut;\n}\n\n/**\n * Bound one JSON document the same way {@link capString} bounds a scalar.\n *\n * `normalizeDataQueryResult` validates a `json` field with `canonicalJson`,\n * which *rejects the whole result* — not just the offending value — when a\n * nested string exceeds {@link DATA_QUERY_MAX_JSON_STRING_LENGTH}, a container\n * exceeds {@link DATA_QUERY_MAX_JSON_CONTAINER_ITEMS}, nesting passes\n * {@link DATA_QUERY_MAX_JSON_DEPTH}, a number is non-finite, a value is not a\n * plain JSON type, or the document contains a cycle. One row with a large\n * `metadata` blob would therefore fail an otherwise valid page.\n *\n * Every one of those is bounded here instead, and the field is flagged so the\n * caller sees `truncated` plus a warning naming it.\n */\nfunction boundJsonValue(\n value: unknown,\n descriptor: DataQueryFieldDescriptor,\n truncation: TruncationLog | undefined,\n depth = 0,\n ancestors = new Set<object>(),\n): unknown {\n const flag = (): void => {\n truncation?.fields.add(descriptor.id);\n };\n if (value === null || value === undefined) return null;\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') {\n if (value.length > DATA_QUERY_MAX_JSON_STRING_LENGTH) {\n flag();\n return capString(value, DATA_QUERY_MAX_JSON_STRING_LENGTH);\n }\n return value;\n }\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n flag();\n return null;\n }\n return value;\n }\n if (typeof value === 'bigint') {\n const safe =\n value <= BigInt(Number.MAX_SAFE_INTEGER) &&\n value >= BigInt(Number.MIN_SAFE_INTEGER);\n if (!safe) {\n flag();\n return null;\n }\n return Number(value);\n }\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value.toISOString();\n }\n // Deeper than the validator accepts: keep the row, drop the sub-document.\n if (depth >= DATA_QUERY_MAX_JSON_DEPTH) {\n flag();\n return null;\n }\n if (Array.isArray(value)) {\n if (ancestors.has(value)) {\n flag();\n return null;\n }\n ancestors.add(value);\n try {\n let entries = value;\n if (entries.length > DATA_QUERY_MAX_JSON_CONTAINER_ITEMS) {\n flag();\n entries = entries.slice(0, DATA_QUERY_MAX_JSON_CONTAINER_ITEMS);\n }\n return entries.map((entry) =>\n boundJsonValue(entry, descriptor, truncation, depth + 1, ancestors),\n );\n } finally {\n ancestors.delete(value);\n }\n }\n if (!isPlainRecord(value)) {\n // A class instance, function, or symbol would fail `plainObject` outright.\n flag();\n return null;\n }\n if (ancestors.has(value)) {\n flag();\n return null;\n }\n ancestors.add(value);\n try {\n let keys = Object.keys(value);\n if (keys.length > DATA_QUERY_MAX_JSON_CONTAINER_ITEMS) {\n flag();\n keys = keys.slice(0, DATA_QUERY_MAX_JSON_CONTAINER_ITEMS);\n }\n // A null prototype, so writing a key named `__proto__` stores an own\n // property instead of invoking the inherited setter — which would silently\n // drop the key AND change this object's prototype, failing `plainObject`'s\n // prototype check on the way out. `Object.prototype` and `null` are the two\n // prototypes the validator accepts.\n const bounded = Object.create(null) as Record<string, unknown>;\n for (const key of keys) {\n if (key.length > DATA_QUERY_MAX_JSON_STRING_LENGTH) {\n flag();\n continue;\n }\n // `plainObject` REJECTS the whole result for one of these keys, and\n // `JSON.parse` of a stored `metadata` column creates an own `__proto__`\n // property, so a single row could otherwise brick every query that\n // projects the field. Dropping the key keeps the row readable.\n if (DATA_QUERY_FORBIDDEN_JSON_KEYS.has(key)) {\n flag();\n continue;\n }\n Object.defineProperty(bounded, key, {\n value: boundJsonValue(\n value[key],\n descriptor,\n truncation,\n depth + 1,\n ancestors,\n ),\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n return bounded;\n } finally {\n ancestors.delete(value);\n }\n}\n\nfunction toDeclaredValue(\n value: unknown,\n descriptor: DataQueryFieldDescriptor,\n truncation?: TruncationLog,\n): unknown {\n if (value === undefined) return null;\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value.toISOString();\n }\n // A json field is validated as a document, not a scalar: it has its own,\n // larger limits, and the scalar cap would corrupt a serialized payload.\n if (descriptor.type === 'json') {\n return boundJsonValue(value, descriptor, truncation);\n }\n if (\n typeof value === 'string' &&\n value.length > DATA_QUERY_MAX_STRING_LENGTH\n ) {\n // The envelope rejects any scalar longer than the cap, which would turn one\n // long row into a failed query. Shorten it and say so instead.\n truncation?.fields.add(descriptor.id);\n return capString(value);\n }\n if (typeof value === 'bigint') {\n if (\n value > BigInt(Number.MAX_SAFE_INTEGER) ||\n value < BigInt(Number.MIN_SAFE_INTEGER)\n ) {\n return queryFail(\n `Content query value for ${descriptor.id} exceeds the safe integer range`,\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n return Number(value);\n }\n if (descriptor.type === 'boolean' && typeof value === 'number') {\n // SQLite/DuckDB surface booleans as 0/1.\n return value !== 0;\n }\n return value;\n}\n\nfunction jsonByteLength(value: unknown): number {\n return encoder.encode(JSON.stringify(value) ?? 'null').byteLength;\n}\n\nexport interface BoundedRows {\n rows: DataQueryRow[];\n truncated: boolean;\n}\n\n/** Cut a string to a BYTE budget without splitting a code point. */\nfunction capStringBytes(value: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n const totalBytes = encoder.encode(value).byteLength;\n if (totalBytes <= maxBytes) return value;\n // Fast path: an all-ASCII value has one byte per code unit, so the cut is a\n // slice. Encoding character by character allocates a typed array PER\n // CHARACTER, which dominates the whole bounding pass on a large page.\n if (totalBytes === value.length) return value.slice(0, maxBytes);\n let used = 0;\n let end = 0;\n for (const character of value) {\n const point = character.codePointAt(0) ?? 0;\n const cost = point < 0x80 ? 1 : point < 0x800 ? 2 : point < 0x10000 ? 3 : 4;\n if (used + cost > maxBytes) break;\n used += cost;\n end += character.length;\n }\n return value.slice(0, end);\n}\n\n/**\n * How a field's value may give way when a row has to get smaller.\n *\n * The distinction that matters is FORMAT. A `string` is free text, so a prefix\n * of it is still a valid string. A `datetime` is an RFC 3339 instant and NO\n * prefix of one is valid — truncating it makes the adapter emit a value that\n * violates the field type it declared, and the result normalizer then rejects\n * the whole page with `must be an RFC 3339 instant`, blaming the caller for a\n * shape the adapter produced. `json` is a document with no incremental\n * shortening. Both of those are all-or-nothing.\n *\n * Numbers and booleans are already minimal, and the identity field is the row's\n * address, so neither is reducible at all.\n */\ntype FieldReduction = 'truncate' | 'null' | 'none';\n\nfunction reductionFor(\n field: string,\n value: unknown,\n identityField: string,\n descriptors: Map<string, DataQueryFieldDescriptor>,\n): FieldReduction {\n if (field === identityField || value === null) return 'none';\n const type = descriptors.get(field)?.type;\n if (type === 'json') return 'null';\n // Format-constrained: reduce to null or not at all, never to a prefix.\n if (type === 'datetime') return 'null';\n if (typeof value === 'string' && value.length > 0) return 'truncate';\n return 'none';\n}\n\n/** The JSON byte cost of a value once it has given way completely. */\nconst REDUCED_VALUE_BYTES: Record<FieldReduction, number> = {\n truncate: 2, // `\"\"`\n null: 4, // `null`\n none: 0, // replaced by the value's own size\n};\n\ninterface MeasuredField {\n field: string;\n /** `\"key\":` — fixed for the life of the row. */\n keyBytes: number;\n /** Current JSON byte cost of the value. */\n valueBytes: number;\n reduction: FieldReduction;\n /** Value bytes once fully reduced. */\n floorBytes: number;\n}\n\ninterface MeasuredRow {\n fields: MeasuredField[];\n /** Braces, commas, and the array separator — independent of the values. */\n structural: number;\n /** Current serialized cost, equal to `jsonByteLength(row) + 1`. */\n cost: number;\n /** The smallest this row can ever be: every reducible value given way. */\n floor: number;\n}\n\n/**\n * Measure a row ONCE, so every later decision is arithmetic.\n *\n * The previous shrink re-serialized the whole row on every iteration AND every\n * field on every iteration, turning an ordinary page — 200 rows of a wide\n * projection at the default 1 MB budget — into seconds of blocked event loop.\n * The serialized size of an object is exactly its structural bytes plus, per\n * field, the key, a colon, and the value; so it can be recomputed from a single\n * measurement as values change, with no further stringification.\n */\nfunction measureRow(\n row: DataQueryRow,\n descriptors: Map<string, DataQueryFieldDescriptor>,\n identityField: string,\n): MeasuredRow {\n const entries = Object.entries(row);\n const fields = entries.map(([field, value]) => {\n const declared = reductionFor(field, value, identityField, descriptors);\n const valueBytes = jsonByteLength(value);\n // A reduction that would not SHRINK the field is not a reduction. `{}` and\n // `[]` serialize to two bytes, so nulling them costs four and makes the row\n // bigger; taking the reduced size as the floor unconditionally also\n // overstates the floor, which refuses pages that would have fitted.\n const reduction: FieldReduction =\n declared === 'none' || REDUCED_VALUE_BYTES[declared] < valueBytes\n ? declared\n : 'none';\n return {\n field,\n keyBytes: jsonByteLength(field),\n valueBytes,\n reduction,\n floorBytes:\n reduction === 'none' ? valueBytes : REDUCED_VALUE_BYTES[reduction],\n };\n });\n // `{`, `}`, one comma between fields, and the separator this row costs inside\n // the rows array.\n const structural = entries.length === 0 ? 3 : entries.length + 2;\n const overhead = fields.reduce(\n (sum, entry) => sum + entry.keyBytes + 1,\n structural,\n );\n return {\n fields,\n structural,\n cost: fields.reduce((sum, entry) => sum + entry.valueBytes, overhead),\n floor: fields.reduce((sum, entry) => sum + entry.floorBytes, overhead),\n };\n}\n\n/**\n * The largest per-value byte cap that keeps a set of truncatable sizes within\n * `available`, or `undefined` when even the floor does not fit.\n *\n * Classic max-min water-filling: sizes at or below the cap keep their real\n * cost, and everything above it is levelled to the cap. Solved by walking the\n * sorted sizes once rather than by repeated halving and re-measurement.\n */\nfunction waterFillCap(\n sizes: readonly number[],\n available: number,\n floorBytes: number,\n): number | undefined {\n if (sizes.length === 0)\n return available >= 0 ? Number.MAX_SAFE_INTEGER : undefined;\n if (available < sizes.length * floorBytes) return undefined;\n const sorted = [...sizes].sort((left, right) => left - right);\n let prefix = 0;\n for (let index = 0; index < sorted.length; index += 1) {\n const remaining = sorted.length - index;\n // Everything from `index` on levelled to `sorted[index]`.\n if (prefix + remaining * sorted[index] > available) {\n return Math.max(floorBytes, Math.floor((available - prefix) / remaining));\n }\n prefix += sorted[index];\n }\n return Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Shrink ONE row so its serialized form fits `allowance` bytes.\n *\n * HOW a field gives way depends on its declared type (see {@link reductionFor}):\n * a string is levelled to a shared cap, while a `json` document or a `datetime`\n * is all-or-nothing, dropped to `null`, because no prefix of either is valid.\n *\n * **Strings give way FIRST.** An all-or-nothing field loses its whole value to\n * save its bytes, so it is dropped only when the row cannot fit with it kept —\n * that is, only while it is larger than the cap the strings could otherwise\n * level down to. At a 50 KB allowance a 30 KB `metadata` blob beside a 100 KB\n * `title` therefore SURVIVES: levelling the title alone is enough. The same\n * blob beside a 20-character title does not, because no amount of levelling\n * gets there. Reaching for the largest field first would instead empty the blob\n * whenever it happened to be the biggest, discarding a whole document to save\n * bytes the strings had to spare.\n *\n * Returns `undefined` only when the row's floor exceeds the allowance. Callers\n * allocate at least each row's floor, so in practice this never fires.\n */\nfunction shrinkRowToBytes(\n row: DataQueryRow,\n allowance: number,\n measured: MeasuredRow,\n truncation: TruncationLog,\n): DataQueryRow | undefined {\n if (measured.floor > allowance) return undefined;\n const nulled = new Set<string>();\n let cap: number | undefined;\n\n // Give way on the all-or-nothing fields only while one of them is a bigger\n // contributor than any string would be after levelling.\n for (;;) {\n const kept = measured.fields.filter(\n (entry) => entry.reduction !== 'truncate' && !nulled.has(entry.field),\n );\n const truncatable = measured.fields.filter(\n (entry) => entry.reduction === 'truncate',\n );\n const fixed = kept.reduce((sum, entry) => sum + entry.valueBytes, 0);\n const nulledBytes = REDUCED_VALUE_BYTES.null * nulled.size;\n const overhead = measured.fields.reduce(\n (sum, entry) => sum + entry.keyBytes + 1,\n measured.structural,\n );\n const available = allowance - overhead - fixed - nulledBytes;\n cap = waterFillCap(\n truncatable.map((entry) => entry.valueBytes),\n available,\n REDUCED_VALUE_BYTES.truncate,\n );\n // An all-or-nothing field gives way only when the row cannot fit with it\n // KEPT. Dropping one loses a whole value to save a few bytes, so it is a\n // last resort rather than a race with the strings: a 200 KB `metadata`\n // blob makes the row infeasible and goes immediately, while a 26-byte\n // `updated_at` survives whenever the strings can absorb the difference.\n if (cap !== undefined) break;\n const biggestNullable = measured.fields\n .filter((entry) => entry.reduction === 'null' && !nulled.has(entry.field))\n .sort((left, right) => right.valueBytes - left.valueBytes)[0];\n if (biggestNullable === undefined) return undefined;\n nulled.add(biggestNullable.field);\n }\n if (cap === undefined) return undefined;\n\n const shrunk: DataQueryRow = { ...row };\n for (const entry of measured.fields) {\n if (nulled.has(entry.field)) {\n shrunk[entry.field] = null;\n truncation.fields.add(entry.field);\n continue;\n }\n if (entry.reduction !== 'truncate' || entry.valueBytes <= cap) continue;\n const original = shrunk[entry.field] as string;\n // The cap is a budget for the SERIALIZED value, so the content budget is\n // two bytes smaller; JSON escaping can inflate the rest, so the value is\n // measured once and trimmed again on the rare occasion it overshoots.\n let content = capStringBytes(original, cap - 2);\n let guard = 0;\n while (jsonByteLength(content) > cap && content.length > 0 && guard < 8) {\n guard += 1;\n const overshoot = jsonByteLength(content) - cap;\n content = capStringBytes(\n content,\n Math.max(0, encoder.encode(content).byteLength - overshoot),\n );\n }\n shrunk[entry.field] = content;\n truncation.fields.add(entry.field);\n }\n return shrunk;\n}\n\n/**\n * Share a byte budget across rows: every row keeps its irreducible floor, and\n * the surplus is divided max-min fair over what each row could still use.\n *\n * Allocating max-min fair over the rows' CURRENT costs — without seating the\n * floors first — can declare a feasible page impossible. A small row is handed\n * its whole cost while a large, mostly-irreducible row is left below its own\n * floor, so the request fails even though the floors fit the budget with room\n * to spare. Seating the floors first makes the guarantee unconditional: if\n * `sum(floors) <= budget` then every row is allocated at least its floor,\n * whatever the shape of the page.\n *\n * Exported because that guarantee is a property of the ARITHMETIC, not of any\n * page the content schema can actually produce — a row's floor is dominated by\n * the projection's key bytes, which are identical across rows, so the disparity\n * that breaks cost-first ordering is not reachable through `executeContentQuery`.\n * The property is real and worth holding; this is the level it can be held at.\n *\n * PRECONDITION: `floors[i] <= costs[i]` for every row — a floor is a size the\n * row can actually be reduced TO, so it can never exceed the size it already\n * is. {@link measureRow} guarantees this by declining any reduction that would\n * not shrink the field. The appetite below is clamped at zero so that a\n * violation still yields at least the floor rather than silently starving a row.\n *\n * @param floors - Per-row irreducible byte cost; at most the row's cost.\n * @param costs - Per-row current byte cost; always at least the floor.\n * @param budget - Bytes available for the rows themselves.\n * @returns Per-row byte allowance, each at least the row's floor.\n */\nexport function allocateRowBytes(\n floors: readonly number[],\n costs: readonly number[],\n budget: number,\n): number[] {\n const allowances = [...floors];\n const seated = floors.reduce((sum, floor) => sum + floor, 0);\n if (seated > budget) return allowances;\n // What each row could still use ON TOP of its floor. Ordering by appetite\n // rather than by cost is what keeps a row that needs nothing from consuming\n // another row's floor.\n const appetites = costs.map((cost, index) =>\n Math.max(0, cost - floors[index]),\n );\n const order = floors\n .map((_, index) => index)\n .sort((left, right) => appetites[left] - appetites[right]);\n let surplus = budget - seated;\n let left = floors.length;\n for (const index of order) {\n const granted = Math.min(appetites[index], Math.floor(surplus / left));\n allowances[index] += granted;\n surplus -= granted;\n left -= 1;\n }\n return allowances;\n}\n\n/**\n * Keep the returned rows inside the schema byte budget WITHOUT dropping any.\n *\n * The normalizer rejects an oversized result rather than trimming it, and one\n * content row can carry megabytes of `metadata`, so the adapter has to bound\n * the payload itself. It used to do that by dropping trailing rows — which is\n * silent, permanent data loss: offset paging advances by the requested LIMIT,\n * not by the number of rows actually returned, so the next page starts past the\n * dropped rows and they are skipped on every page, forever. `DataQueryResult`'s\n * offset page is `{ kind, offset, limit, hasMore }` with no next-offset slot,\n * and the normalizer refuses a `nextCursor` on an offset page, so a\n * continuation offset cannot be expressed to say \"resume at 170\" either.\n *\n * So a row is never dropped for size — only shortened, which is a state the\n * result already reports through `truncated` and its warning, and which leaves\n * offset paging exact.\n *\n * Allocation is floor-first, then max-min fair. Every row is given its\n * irreducible floor before any surplus is shared, so a page whose floors fit is\n * always produced — ordering rows by their CURRENT cost could otherwise hand a\n * small row more than it needed and starve a large one below its floor,\n * declaring a feasible page impossible.\n *\n * Throws only when the floors themselves exceed the budget, which is the one\n * case no amount of shortening can reach. Failing loudly beats answering with a\n * page that silently omits rows.\n */\nexport function boundRowBytes(\n rows: DataQueryRow[],\n maxResultBytes: number,\n descriptors: Map<string, DataQueryFieldDescriptor>,\n identityField: string,\n truncation: TruncationLog,\n): BoundedRows {\n const budget = Math.max(\n 0,\n (maxResultBytes || CONTENT_QUERY_MAX_RESULT_BYTES) -\n RESULT_ENVELOPE_RESERVE_BYTES,\n );\n // `[` and `]`. Each row's `structural` charges the separator that FOLLOWS it,\n // but N rows need N-1, so a non-empty page has one separator too many; refund\n // it here rather than special-casing the last row. Without the refund a page\n // whose true size exactly equals the budget is needlessly shortened — or, if\n // it is irreducible, refused.\n const framing = rows.length > 0 ? 1 : 2;\n const measured = rows.map((row) =>\n measureRow(row, descriptors, identityField),\n );\n const total = measured.reduce((sum, row) => sum + row.cost, framing);\n if (total <= budget) return { rows, truncated: false };\n\n const floors = measured.reduce((sum, row) => sum + row.floor, framing);\n if (floors > budget) {\n return queryFail(\n 'Content query cannot fit its rows inside the maximum result bytes; request fewer fields or a smaller page.',\n 'DATA_QUERY_RESULT_TOO_LARGE',\n );\n }\n\n const allowances = allocateRowBytes(\n measured.map((row) => row.floor),\n measured.map((row) => row.cost),\n budget - framing,\n );\n\n const bounded = rows.map((row, index) => {\n if (measured[index].cost <= allowances[index]) return row;\n const shrunk = shrinkRowToBytes(\n row,\n allowances[index],\n measured[index],\n truncation,\n );\n if (shrunk === undefined) {\n return queryFail(\n 'Content query cannot fit a row inside its maximum result bytes; request fewer fields or a smaller page.',\n 'DATA_QUERY_RESULT_TOO_LARGE',\n );\n }\n return shrunk;\n });\n return { rows: bounded, truncated: true };\n}\n\nfunction orderByTerms(sort: DataQuerySort[] | undefined): string[] | undefined {\n if (!sort || sort.length === 0) return undefined;\n return sort.map((term) => `${term.field} ${term.direction.toUpperCase()}`);\n}\n\n/**\n * Execute one bounded content query.\n *\n * Every read goes through `SmrtCollection.list({ select, where, orderBy,\n * offset, limit })`, `count()`, and `facets()` — the collection remains the\n * authorization, tenancy-interception, and SQL boundary. The full collection is\n * never hydrated to filter or page in memory.\n *\n * Tenancy is applied by this function itself (see\n * {@link resolveContentTenantReadScope}) in addition to any application\n * `scope`; a caller cannot opt out of it.\n *\n * @param collection Content collection to read through.\n * @param rawRequest Untrusted `DataQueryRequest` (typically an HTTP body).\n * @param options Trusted adapter configuration — never derived from the caller.\n */\nexport async function executeContentQuery(\n collection: ContentQueryCollection,\n rawRequest: unknown,\n options: ContentQueryOptions = {},\n): Promise<DataQueryResult> {\n const schema = options.schema ?? (await buildContentQuerySchema());\n // Configuration first: a budget too small to hold an envelope plus a row\n // would otherwise answer every query with an empty page rather than fail.\n assertUsableResultBudget(schema);\n const request: DataQueryRequest = normalizeDataQueryRequest(\n rawRequest,\n schema,\n );\n const queryFingerprint = createDataQueryFingerprint(request, schema);\n const descriptors = new Map(schema.fields.map((field) => [field.id, field]));\n const declared = new Set(descriptors.keys());\n\n const callerWhere = request.filter\n ? filterToDnf(request.filter, declared)\n : undefined;\n // Tenancy first, then the application scope: both are trusted, both narrow.\n // An empty application scope contributes its deny-all condition here, so it\n // survives the merge alongside tenancy rather than being mistaken for\n // \"unscoped\" — an empty app scope plus a tenant scope must still deny.\n const scopeConditions = [\n ...normalizeScopeConditions(resolveContentTenantReadScope()),\n ...normalizeApplicationScope(options.scope),\n ];\n // `undefined`, never `[]`: the aggregate is empty only when there genuinely\n // is no scope, and `[]` now means the opposite.\n const where = mergeContentQueryScope(\n scopeConditions.length > 0 ? scopeConditions : undefined,\n callerWhere,\n );\n const countOptions = where === undefined ? undefined : { where };\n\n const warnings: string[] = [];\n let truncated = false;\n let facets: DataQueryFacetResult[] | undefined;\n\n if (request.mode === 'rows') {\n const projection = request.projection ?? [schema.identityField];\n const offset = request.page?.kind === 'offset' ? request.page.offset : 0;\n const limit =\n request.page?.limit ??\n schema.defaultPageLimit ??\n CONTENT_QUERY_DEFAULT_PAGE_LIMIT;\n const orderBy = orderByTerms(request.sort);\n const listed = await collection.list({\n select: projection,\n offset,\n limit,\n ...(orderBy\n ? { orderBy: orderBy.length === 1 ? orderBy[0] : orderBy }\n : {}),\n ...(where === undefined ? {} : { where }),\n });\n const truncation: TruncationLog = { fields: new Set() };\n const mapped = listed.map((row) => {\n const out: DataQueryRow = {};\n for (const field of projection) {\n const descriptor = descriptors.get(field);\n if (!descriptor) {\n return queryFail(\n `Content query returned an undeclared field: ${field}`,\n 'DATA_QUERY_RESULT_NOT_ALLOWED',\n );\n }\n out[field] = toDeclaredValue(row[field], descriptor, truncation);\n }\n return out;\n });\n const bounded = boundRowBytes(\n mapped,\n schema.maxResultBytes ?? CONTENT_QUERY_MAX_RESULT_BYTES,\n descriptors,\n schema.identityField,\n truncation,\n );\n const rows: DataQueryRow[] = bounded.rows;\n truncated = bounded.truncated || truncation.fields.size > 0;\n if (bounded.truncated) {\n pushWarning(\n warnings,\n 'Content query shortened values to fit its maximum result bytes; request fewer fields or a smaller page.',\n );\n }\n if (truncation.fields.size > 0) {\n pushWarning(\n warnings,\n `Content query shortened over-long values in: ${[...truncation.fields].sort().join(', ')}.`,\n );\n }\n const total = await collection.count(countOptions);\n const page: DataQueryResult['page'] = {\n kind: 'offset',\n offset,\n limit,\n // No row is ever dropped for size any more, so the page is exactly the\n // rows the offset asked for and `hasMore` is a plain positional fact.\n hasMore: offset + rows.length < total,\n };\n return normalizeDataQueryResult(\n {\n version: 1 as const,\n requestId: request.requestId,\n queryFingerprint,\n identityField: schema.identityField,\n rows,\n page,\n total: { kind: 'exact' as const, value: total },\n freshness: { state: 'fresh' as const, asOf: new Date().toISOString() },\n warnings,\n truncated,\n },\n request,\n schema,\n );\n }\n\n const total = await collection.count(countOptions);\n\n if (request.mode === 'facets') {\n const requested = request.facets ?? [];\n const sourceFacets = await collection.facets({\n fields: requested.map((facet) => ({\n field: facet.field,\n limit: facet.limit,\n })),\n ...(where === undefined ? {} : { where }),\n });\n const byField = new Map(sourceFacets.map((facet) => [facet.field, facet]));\n const facetTruncation: TruncationLog = { fields: new Set() };\n // Facet values go through the SAME shared byte budget the rows do: two text\n // facets of 200 distinct 4096-character values are inside every per-value\n // cap and still over the 1 MB result limit, which would make the normalizer\n // reject an otherwise valid response.\n let facetBudget = Math.max(\n 0,\n (schema.maxResultBytes ?? CONTENT_QUERY_MAX_RESULT_BYTES) -\n RESULT_ENVELOPE_RESERVE_BYTES,\n );\n let facetBudgetExhausted = false;\n facets = requested.map((facet) => {\n const descriptor = descriptors.get(facet.field);\n if (!descriptor) {\n return queryFail(\n `Content query returned an undeclared facet: ${facet.field}`,\n 'DATA_QUERY_RESULT_NOT_ALLOWED',\n );\n }\n const values = byField.get(facet.field)?.values ?? [];\n // The envelope around one facet: field name, brackets, and flags.\n facetBudget -= jsonByteLength(facet.field) + 48;\n const kept: Array<{\n value: string | number | boolean | null;\n count: number;\n }> = [];\n let boundedOut = false;\n for (const entry of values.slice(0, facet.limit)) {\n const value = toDeclaredValue(\n entry.value,\n descriptor,\n facetTruncation,\n ) as string | number | boolean | null;\n const cost = jsonByteLength({ value, count: entry.count }) + 1;\n if (cost > facetBudget) {\n boundedOut = true;\n facetBudgetExhausted = true;\n break;\n }\n facetBudget -= cost;\n kept.push({ value, count: entry.count });\n }\n return {\n field: facet.field,\n values: kept,\n // The collection bounds this grouping query in the database; an exactly\n // full page may have more values, so report conservatively.\n truncated: boundedOut || values.length >= facet.limit,\n };\n });\n if (facetTruncation.fields.size > 0) {\n pushWarning(\n warnings,\n `Content query shortened over-long values in: ${[...facetTruncation.fields].sort().join(', ')}.`,\n );\n }\n if (facetBudgetExhausted) {\n pushWarning(\n warnings,\n 'Content query facets were truncated to fit their maximum result bytes; request fewer facets or a smaller facet limit.',\n );\n }\n truncated =\n facets.some((facet) => facet.truncated) ||\n facetTruncation.fields.size > 0;\n }\n\n return normalizeDataQueryResult(\n {\n version: 1 as const,\n requestId: request.requestId,\n queryFingerprint,\n identityField: schema.identityField,\n rows: [],\n total: { kind: 'exact' as const, value: total },\n ...(facets === undefined ? {} : { facets }),\n freshness: { state: 'fresh' as const, asOf: new Date().toISOString() },\n warnings,\n truncated,\n },\n request,\n schema,\n );\n}\n"],"mappings":"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"}