GitHub Source
The github source fetches content from a GitHub repository through the GitHub API. It's the recommended way to ship applications whose source-of-truth lives in another repo.
github(options)
Creates a source that reads from a GitHub repository.
import { comarkContent } from 'comark-content'
import github from 'comark-content/sources/github'
const content = comarkContent({
source: github({
repo: 'comarkdown/comark',
branch: 'main',
path: 'docs/content',
}),
})Parameters:
options- AGithubSourceobject
Returns: Source. Pass it to comarkContent({ source }), or into a named sources map.
Options
GithubSource extends unstorage's github driver options and adds the source-level fields:
| Option | Type | Default | Description |
|---|---|---|---|
repo | string | - | owner/name slug of the repository. Required. |
branch | string | 'main' | Branch, tag, or commit SHA to read from. |
path | string | '' | File or directory inside the repo to use as the content root. |
token | string | undefined | GitHub token. Required for private repos; recommended for public ones to lift rate limits. |
ttl | number | 600 | Cache duration for the underlying driver, in seconds. |
prefix | string | undefined | Prepended to each entry's path (e.g. /blog). |
exclude | string[] | undefined | Picomatch globs of keys to drop before parsing. |
schema | JsonSchema | undefined | Explicit document data schema for types and query columns. |
repo
The owner/name slug of the repository to read from. This is the only required option.
branch
The branch, tag, or commit SHA to read from. Defaults to main. Pin it to an immutable commit SHA when you need every instance to render the exact same snapshot.
path
The file or directory inside the repo to use as the content root. The Content instance only sees what's underneath it:
github({
repo: 'nuxt/nuxt',
branch: 'main',
path: 'docs/1.getting-started',
})
await content.list() // only entries under docs/1.getting-started/**token
A GitHub token. Public repos work without one but share a 60-request/hour rate limit per IP. For anything serious, pass a personal access token (fine-grained Contents: read is enough):
const content = comarkContent({
source: github({
repo: 'org/private-docs',
branch: 'main',
path: 'content',
token: process.env.GITHUB_TOKEN,
}),
})ttl
How long the underlying driver caches responses, in seconds. Defaults to 600.
prefix
Prepended to every entry's public path. Combine it with path to remap the public path space:
github({
repo: 'org/handbook',
branch: 'main',
path: 'content/policies',
prefix: '/policies',
})
await content.get('/policies/security') // → content/policies/security.mdThe prefix does not affect the key (which stays <source>/<stem> inside the manifest), only the public path returned by content.get() and content.list().
exclude
Picomatch globs matched against each entry's key. Excluded files are dropped before parsing, so they never enter the manifest:
github({
repo: 'org/docs',
branch: 'main',
path: 'content',
exclude: ['drafts/**', '**/*.draft.md'],
})schema
An explicit JSON Schema for the source's data. When set, the Content instance reports Markdown, JSON, and YAML frontmatter validation issues during source load and on direct updates, and uses the schema to generate types and query columns.
Refresh
GitHub sources don't watch for changes. The driver caches responses for ttl seconds, so new commits surface once that window expires and the Content instance is re-initialized. To pick them up immediately, you must build a fresh Content instance.
import { comarkContent } from 'comark-content'
import github from 'comark-content/sources/github'
export function buildContent(ref: string) {
return comarkContent({
source: github({ repo: 'org/docs', branch: ref, path: 'content' }),
})
}