Sources

Where your content comes from.

A source is the boundary that hands Comark raw content. It's the only required piece of a Content: point the instance at one source, or mount several under names, and everything else (the manifest, cache, plugins) builds on top.

Interface

A source is intentionally tiny. Three methods do the work, and a few optional fields tune behaviour:

Source.ts
interface Source {
  keys: () => Promise<string[]> | string[]
  getItem: (key: string) => Promise<string> | string
  getItemRaw: (key: string) => Promise<unknown> | unknown
  prefix?: string
  schema?: JsonSchema
  watch?: Driver['watch']
}
The built-in sources (filesystem, GitHub, unstorage) all implement this interface, and you can write your own for any backend.
MemberTypeDescription
keys()() => string[] | Promise<string[]>Required. List every content key in the source.
getItem()(key) => string | Promise<string>Required. Return a key's text content.
getItemRaw()(key) => unknown | Promise<unknown>Required. Return a key's raw bytes, or null.
prefixstringPrepended to each entry's public path.
schemaJsonSchemaExplicit data schema for types and query columns. Use the schema-validation plugin to validate against it.
watch()Driver['watch']Forward change events to content.watch().

keys()

List every content key the source exposes, as forward-slash paths with no leading slash (e.g. posts/hello.md). Keys must round-trip: whatever keys() returns is exactly what getItem and getItemRaw receive.

getItem()

Return a key's text content: the raw Markdown (or JSON/YAML) that Comark parses. Throw if the key is unreachable, and the Content instance surfaces the error to the caller.

getItemRaw()

Return a key's raw bytes, as a Uint8Array, for media files. Required even if you only ship documents: return null when a key has no binary form.

prefix

Prepended to every entry's public path, which is handy when a folder owns a slice of the URL space. It does not change the key.

schema

An explicit JSON Schema for the source's data. The Content instance uses it to generate types and query columns. Register the schema-validation plugin to validate documents against it.

watch()

When present, content.watch() forwards the source's change events. Only drivers that implement it fire events (the filesystem source does; remote ones do not).

Single source

Pass source for the common case: one source, mounted under the implicit name default.

single.ts
const content = comarkContent({ source: fs('./content') })
await content.get('/about')   // resolves to default/about.md

Multiple sources

Pass sources to mount several under names. The name becomes part of every entry's key and is what you pass to list() / navigation() to scope them.

named.ts
const content = comarkContent({
  sources: {
    docs: github({ repo: 'acme/docs', path: 'content' }),
    blog: fs('./content/blog'),
  },
})
await content.list(['blog'])   // only entries from the blog source
Pass sourceorsources, never both.
Each built-in source has its own options and integration. Check the dedicated section for filesystem, GitHub, unstorage and custom sources.