Skip to content
These docs describe arocapi v5, which is in beta. Install it with pnpm add arocapi@beta.

Entity meta

The Entity and File models (see Entities & hierarchy) each have a nullable JSON column, meta, for your own data. arocapi never puts meta in an API response, so it can hold storage locations and internal flags.

Column Passed to Typical use
Entity.meta both storage halves, and your entityVisibilityFilter can query it Where the RO-Crate metadata is stored; visibility flags such as drafts.
File.meta the storage backend’s content half Where the file’s bytes are stored.

meta is typed as Prisma’s JsonValue, so narrow it before reading fields.

Each reference storage backend reads a default Storage key from meta, unless you supply its locate option. Write these keys when you index:

Backend Content Metadata Override
DirectoryStorage File.meta.storagePath Entity.meta.storagePath locate.content(file, entity), locate.metadata(entity)
EntityMetaMetadata none (Metadata only) Entity.meta.rocrate, the RO-Crate metadata object itself key
S3Storage File.meta.storageKey Entity.meta.storageKey locate.content(file, entity), locate.metadata(entity)
OcflStorage File.meta.ocflObject + File.meta.ocflPath Entity.meta.ocflObject + Entity.meta.ocflPath (default ro-crate-metadata.json) locate.content(file, entity), locate.metadata(entity), returning { object, path }

Keys are relative to the backend’s root or bucket. An absent key is a 404. A key that isn’t a string, null included, or that is absolute or has a .. segment, is a 500. EntityMetaMetadata reads no key: the value is the Metadata, and one that isn’t a JSON object is a 500. OCFL keys are an object id, which the storage layout maps and isn’t checked for .., and a logical path inside its head version, not a path on disk. The root exports a TypeScript type for each shape, such as DirectoryStorageMeta:

import type { DirectoryStorageMeta } from 'arocapi';
import type { PrismaClient } from './generated/prisma/client.ts';
declare const prisma: PrismaClient;
// Index the item's crate and file with the keys DirectoryStorage reads, relative to its root
await prisma.entity.update({
where: { id: 'https://example.org/item' },
data: { meta: { storagePath: 'item/ro-crate-metadata.json' } satisfies DirectoryStorageMeta },
});
await prisma.file.update({
where: { id: 'https://example.org/item/song.wav' },
data: { meta: { storagePath: 'item/song.wav' } satisfies DirectoryStorageMeta },
});

A flag in Entity.meta can drive the visibility filters. Mirror it into your search documents as a declared field with no role, for example draft: { type: 'boolean' }, so the search filter can match the same entities. In Prisma, a plain not on a JSON path also excludes rows where meta or the path is null, so match those explicitly:

import type { EntityVisibilityFilter, SearchVisibilityFilter } from 'arocapi';
import { Prisma } from './generated/prisma/client.ts';
export const entityVisibilityFilter: EntityVisibilityFilter = () => ({
OR: [{ meta: { path: ['draft'], equals: Prisma.AnyNull } }, { meta: { path: ['draft'], not: true } }],
});
// With draft declared as { type: 'boolean' } and indexed from meta.draft
export const searchVisibilityFilter: SearchVisibilityFilter<{ draft: { type: 'boolean' } }> = () => ({
draft: { not: true },
});

Prisma here is the namespace from your generated Prisma client. JSON path filters can’t use arocapi’s indexes; for large repositories, store visibility flags in your own indexed columns.