import { SmrtCollectionOptions, SmrtCollection } from '@happyvertical/smrt-core'; import { Image } from '@happyvertical/smrt-images'; import { Content } from './content'; import { ResolveHostname } from './safe-remote-url'; import { ThumbnailStrategy } from './thumbnail-generator'; /** * Options accepted by {@link Contents.generateMissingThumbnails}. Also reused * (as a `Partial`) for the `thumbnail` config block passed through the * collection constructor from `smrt.config.js`. */ export interface GenerateMissingThumbnailsOptions { /** * Thumbnail generation strategy */ strategy: ThumbnailStrategy; /** * Optional filter for content to process */ where?: Record; /** * Maximum number of thumbnails to generate */ limit?: number; brandColor?: string; backgroundColor?: string; logoUrl?: string; template?: 'default' | 'news' | 'minimal'; mapProvider?: 'mapbox' | 'google'; zoom?: number; style?: 'photorealistic' | 'illustration' | 'abstract' | 'minimal'; width?: number; height?: number; } /** * Configuration options for Contents collection */ export interface ContentsOptions extends SmrtCollectionOptions { /** * Directory to store content files */ contentDir?: string; /** * Default thumbnail-generation settings sourced from `smrt.config.js`. Merged * under per-call options in `generateMissingThumbnails`. */ thumbnail?: Partial; } /** * Collection for managing Content objects * * The Contents collection provides functionality for managing and manipulating * collections of Content objects, including saving to the filesystem and * mirroring content from remote URLs. */ export declare class Contents extends SmrtCollection { /** * Class constructor for collection items */ static _itemClass: typeof Content; /** * Configuration options */ options: ContentsOptions; /** * Directory to store content files */ contentDir?: string; /** * Cache for loaded content */ loaded: Map; /** * Creates a new Contents collection * * Use the static `create()` method inherited from SmrtCollection for proper initialization. * * @param options - Configuration options */ constructor(options?: ContentsOptions); /** * Gets the database interface * * @returns Database interface */ getDb(): import('@happyvertical/sql').DatabaseInterface; /** * Initializes the collection * * @returns Promise that resolves to this instance */ initialize(): Promise; private getFactCollection; browseFacts(options?: { q?: string; query?: string; limit?: number | string; offset?: number | string; minSimilarity?: number | string; includeSuperseded?: boolean | string; latestOnly?: boolean | string; tenantId?: string | null; }): Promise<{ metadata: unknown; }[]>; getBySlug(options?: { slug?: string; context?: string; status?: string; tenantId?: string | null; }): Promise<{ referenceIds: unknown[]; references: { [x: string]: unknown; }[]; assetIds: unknown[]; assets: { [x: string]: unknown; }[]; } | null>; getGovernanceDefinitionsAction(options?: { tenantId?: string | null; }): Promise<{ effective: { policies: { id?: string; tenantId?: string | null; createdAt?: string | null; updatedAt?: string | null; key: string; label: string; kind: import('./content-governance').ContentReviewKind; instructions: string; enabled?: boolean; metadata?: Record; }[]; profiles: { id?: string; tenantId?: string | null; createdAt?: string | null; updatedAt?: string | null; key: string; label: string; description?: string; enabled?: boolean; requirements: import('./content-governance').ContentReviewRequirement[]; metadata?: Record; }[]; assignments: { id?: string; tenantId?: string | null; createdAt?: string | null; updatedAt?: string | null; key?: string; label?: string; contentType: string; contentVariant?: string | null; enabled?: boolean; factLinkingEnabled?: boolean; transparencyEnabled?: boolean; publicationProfileKey?: string | null; correctionProfileKey?: string | null; enforcePublishReadiness?: boolean; defaultFactRelationship?: import('@happyvertical/smrt-facts').FactContentRelationship; metadata?: Record; }[]; }; persisted: { policies: import('./content-governance').PersistedContentGovernancePolicyRecord[]; profiles: import('./content-governance').PersistedContentGovernanceProfileRecord[]; assignments: import('./content-governance').PersistedContentGovernanceAssignmentRecord[]; }; }>; resolveGovernanceAction(options?: { type?: string; variant?: string | null; tenantId?: string | null; }): Promise; /** * Mirrors content from a remote URL * * Downloads and stores content from a remote URL, extracting text * and saving it as a Content object. * * @param options - Mirror options * @param options.url - URL to mirror * @param options.mirrorDir - Directory for caching mirrored files * @param options.context - Context for the mirrored content * @returns Promise resolving to the mirrored Content object * @throws Error if URL is invalid or missing */ mirror(options: { url: string; mirrorDir?: string; context?: string; /** * Skip the SSRF host-blocking checks. Only set this for fully trusted, * operator-supplied URLs (e.g. local development), never for URLs that * originate from end users or external content. */ allowPrivateNetworkHosts?: boolean; /** Injectable DNS resolver (primarily for tests). */ resolveHostname?: ResolveHostname; /** Injectable fetch for redirect resolution (primarily for tests). */ fetchImpl?: typeof fetch; }): Promise; /** * Writes a Content object to the filesystem as a markdown file * * @param options - Options for writing the content file * @param options.content - Content object to write * @param options.contentDir - Directory to write the file to * @returns Promise that resolves when the file is written * @throws Error if contentDir is not provided */ writeContentFile(options: { content: Content; contentDir: string; }): Promise; /** * Checks if text appears to be in markdown format * * @param text - Text to check * @returns Boolean indicating if the text contains markdown syntax */ private isMarkdown; /** * Formats plain text as simple markdown * * @param text - Plain text to format * @returns Text formatted as basic markdown */ private formatAsMarkdown; /** * Synchronizes content to the filesystem * * Writes all article-type Content objects to the filesystem * as markdown files. * * @param options - Sync options * @param options.contentDir - Directory to write content files to * @returns Promise that resolves when synchronization is complete */ syncContentDir(options: { contentDir?: string; }): Promise; /** * Generate thumbnails for content that doesn't have one * * @param options - Options for bulk thumbnail generation * @returns Promise resolving to result object with generated images and failed content IDs * * @example Generate headline cards for all published articles * ```typescript * const result = await contents.generateMissingThumbnails({ * strategy: 'headline-card', * where: { type: 'article', status: 'published' }, * brandColor: '#1a56db' * }); * console.log(`Generated ${result.images.length} thumbnails`); * if (result.failed.length > 0) { * console.warn(`Failed to generate ${result.failed.length} thumbnails`); * } * ``` */ generateMissingThumbnails(options: GenerateMissingThumbnailsOptions): Promise<{ images: Image[]; failed: Array<{ contentId: string; error: string; }>; }>; /** * Find all content belonging to a specific tenant * * @param tenantId - The tenant ID to filter by * @returns Promise resolving to array of Content objects for the tenant * * @example * ```typescript * const tenantContent = await contents.findByTenant('tenant-123'); * ``` */ findByTenant(tenantId: string): Promise; /** * Find all global content (not associated with any tenant). * * Routes through the shared tenant-global helper so it does not throw under * an active tenant context (an explicit `tenant_id IS NULL` filter would be * flagged as an isolation violation). (#1600) * * @returns Promise resolving to array of global Content objects * * @example * ```typescript * const globalContent = await contents.findGlobal(); * ``` */ findGlobal(): Promise; /** * Find content for a tenant including global content. * * This returns both tenant-specific content and global content (tenantId is null), * useful for showing a tenant their content plus any shared/global resources. * * Fails closed if an active tenant context requests a different tenant's * rows; the admin/system path keeps the cross-tenant capability. (#1600) * * @param tenantId - The tenant ID to include * @returns Promise resolving to array of Content objects (tenant + global) * * @example * ```typescript * const allAccessibleContent = await contents.findWithGlobals('tenant-123'); * ``` */ findWithGlobals(tenantId: string): Promise; } //# sourceMappingURL=contents.d.ts.map