Skip to main content

Assets

Asset management with file upload, storage integration, and schema-driven validation.

Database schema

The assetsTable stores asset metadata linked to files via @repo/storage:

import { assetsTable, assetsRelations } from '@repo/cms/database'
ColumnTypeDescription
iduuidPrimary key
nametextAsset name (required)
descriptiontextOptional description
fileIduuidFK to filesTable (cascade delete)
createdBytextUser who created
updatedBytextUser who last updated

The assetsRelations defines a one-to-one relation to filesTable.

Zod schemas

Auto-generated schemas for validation:

import {
assetsTableInsertSchema,
assetsTableSelectSchema,
assetsTableUpdateSchema,
} from '@repo/cms'

Additional schemas for form integration:

import { assetInsertSchema, getAssetUpdateSchema, assetListSchema } from '@repo/cms'
  • assetInsertSchema -- wraps fileInsertSchema with FileField.Root component
  • getAssetUpdateSchema(clientFileManager) -- includes optional file replacement with URL preview
  • assetListSchema -- partial pick of name and description for list filtering

AssetRepository

Server-side CRUD for assets. Extends Repository from @repo/db.

import { AssetRepository } from '@repo/cms/server'

const repo = new AssetRepository(getDbContext, serverFileManager, fileRepository, clientFileManager)

Methods

MethodDescription
get(id)Fetch asset with file metadata
overview(config)Paginated list with count
select(config?)Returns { label, value }[] for dropdowns
listWithUrl(ids?)Returns { [id]: { url } } map for rendering
create(data)Upload file and create asset record
update(data, id)Update metadata, optionally replace file
remove(id)Delete asset and its file (cascade)

Usage in a remote function

import { query } from '$app/server'
import { AssetRepository } from '@repo/cms/server'
import { z } from 'zod'

export const getAssets = query(z.object({}), async () => {
const repo = new AssetRepository(getDbContext, serverFileManager, fileRepository, clientFileManager)
return repo.overview({ page: 1, perPage: 20 })
})

Asset references in blocks

Reference assets in block schemas using zaf with a group:

import { zaf } from '@repo/form'
import { z } from 'zod'

const schema = z.object({
image: zaf(z.string(), {
component: AssetAutocompleteField,
group: 'assets',
}),
})

The group option lets getGroupsFromBlocks collect all asset IDs across blocks for batch loading:

import { getGroupsFromBlocks } from '@repo/cms'

const groups = getGroupsFromBlocks({ value: blockValues, blocks })
const assetUrls = await assetRepo.listWithUrl(groups.assets)

Types

import type { Asset, AssetWithFile } from '@repo/cms'

// Asset = assetsTable.$inferSelect
// AssetWithFile = Asset & { file: ManagedFile }