Pulls content from external APIs and injects it into the Shevky build pipeline. Includes a mapping language, pagination, and request controls.
- Fetches remote content during build
- Flexible field mapping and transformations
- Pagination support (page, offset, cursor)
- Request settings (method, headers, body, timeout)
- Optional markdown export to disk
npm i @shevky/plugin-content-bridgeAdd the plugin to your Shevky config:
{
"plugins": [
"@shevky/plugin-content-bridge"
]
}Add plugin config in site.json (recommended: sources):
{
"pluginConfigs": {
"shevky-content-bridge": {
"maxItems": 10,
"output": {
"directory": "./tmp/content-bridge",
"fileNameFormat": "{lang}/{slug}.md"
},
"sources": [
{
"name": "posts",
"fetch": {
"endpointUrl": "https://dummyjson.com/posts",
"method": "GET",
"headers": {},
"timeoutMs": 30000,
"pagination": {
"pageParam": "skip",
"sizeParam": "limit",
"pageIndexStart": 0,
"pageSize": 10,
"itemsPath": "$_posts",
"totalPath": "$_total"
}
},
"mapping": {
"frontMatter": {
"id": "$_id",
"lang": "tr",
"title": "$_title",
"slug": "$slugify($_title)",
"canonical": "$concat('~/', $slugify($_title))",
"template": "post",
"layout": "default",
"status": "published",
"featured": true,
"tags": "$compact($unique($merge($extract($_categories, 'name'), $split($_keywords, ','))))",
"date": "$now()",
"description": "$_title",
"category": "$_tags[0]"
},
"content": "$_body",
"sourcePath": "$concat('bridge://dummyjson/posts/', $_id, '.md')"
},
"output": {
"directory": "./tmp/content-bridge/posts",
"fileNameFormat": "{frontMatter.slug}-{id}.md"
},
"maxItems": 5
}
]
}
}
}Use sources to fetch from multiple APIs. Each source has its own fetch and mapping.
sources: Array of{ name?, fetch, mapping, maxItems? }maxItems: Optional global limit (applies to all sources)output: Optional global markdown export config (source.outputcan override)
endpointUrl: API URL (required)method:GETorPOST(defaultGET)headers: Request headersbody: POST body (string or object). Objects are JSON-stringified.timeoutMs: Request timeout in ms (default30000)pagination: Optional. Enables multi-page fetching.
pageParam: Page parameter (page,skip,offset, etc.)sizeParam: Page size parameter (limit,pageSize, etc.)pageIndexStart: Start index (e.g. 0 or 1)pageIndexStep: Increment size. Inoffsetmode, usuallypageSize.pageSize: Page sizedelayMs: Delay between requestsitemsPath: Path to the array in the response (e.g.$_posts)totalPath: Path to the total count (e.g.$_total)hasMorePath: Boolean continuation flagnextPagePath: Next page numbernextCursorPath: Cursor valuecursorParam: Cursor parametercursorStart: Initial cursor valuemode:page|offset|cursor
Mode explanation:
page: page number increments by 1 (page=1,2,3)offset: index is an offset and increases bypageSize(skip=0,10,20)cursor: usesnextCursorPathand sends it viacursorParam
If pageParam is skip or offset, mode is inferred as offset.
Continuation priority:
nextCursorPathhasMorePathnextPagePathtotalPath- Short page check (
items.length < pageSize)
frontMatter: Maps Shevky front matter fieldscontent: Content body (markdown)sourcePath: Source path (required)
frontMatter values can be string expressions, literals, objects, or arrays. Example:
tags:
- "$if($eq($_status, 1), 'active', 'archived')"
- "$_location.city"
jobTags:
- label: "$_typeStr"
- label: "$if($_isExperienceRequired, 'Deneyim Gerekli', '')"
- label: "$if($lte($_dateCreateISO8601, $sub($today(), 15)), 'featured', '')"
type: "time"
files: "$iter($_files, $obj($_path, $_thumbnailPath))"
customTags: "$arr('remote', $_location.city, $if($_isExperienceRequired, 'experience-required', ''))"maxItems: Optional. Global limit for the plugin. Each source can override it with its ownmaxItems.
output.directory: Target folder for generated markdown files (relative paths are resolved from project root)output.fileNameFormat: Output file format (default:{slug}.md)source.output: Optional per-source override. Setfalseto disable export for that source.- Front matter arrays/objects are exported as YAML blocks (not JSON inline strings).
fileNameFormat supports:
- Placeholder format:
{slug},{id},{lang},{frontMatter.slug},{source.id} - Direct field references:
$_slug-$_id.md,$_frontMatter.lang/$_source.id.md - Mapping expression format:
"$concat($_lang, '/', $_slug, '.md')"
If no extension is provided, .md is appended automatically.
Unscoped fields (e.g. $_title, {title}) resolve with frontMatter priority, then source.
Use $_source.* for raw API values and $_frontMatter.* for explicit mapped header values.
Field references:
$_fieldreads from source$_tags[0]reads array element'text'is a literal string$slugify($_title)calls a function (functions can be nested)
Functions:
Structure and Collections:
$arr(v1, v2, ...)-> creates an array from values$obj(...)-> creates an object$iter(array, template)-> loops over array items and evaluates template for each item$split(value, separator)-> splits string/array items into an array (trimmed, empty items removed)$extract(array, path1, path2...)-> extracts one or more fields from object arrays$merge(array1, array2, ...)-> merges arrays$unique(array)-> removes duplicates$compact(array)-> removes empty items (null,undefined, empty string/array/object)
String and Content:
$slugify(value)-> URL-safe slug$concat(a, b, c...)-> joins values into one string$lower(value)-> lowercase string$upper(value)-> uppercase string$trim(value)-> trims whitespace$join(array, separator)-> joins array into a string$replace(value, from, to)-> string replace (all occurrences)$htmlToMD(value)-> converts basic HTML into Markdown$truncate(value, len)-> limits string length tolen
Logic and Comparison:
$if(condition, then, else)-> conditional value$eq(a, b)-> equality check$neq(a, b)-> inequality check$gt(a, b)-> greater-than check$gte(a, b)-> greater-than-or-equal check$lt(a, b)-> less-than check$lte(a, b)-> less-than-or-equal check$and(v1, v2, ...)-> logical AND$or(v1, v2, ...)-> logical OR$not(value)-> logical NOT$contains(valueOrArray, needle)-> checks string/array membership
Date and Math:
$date(value, format)-> formats a date; noformatreturns ISO$add(base, amount, unit?)-> adds to number/date. For dates, default unit isdayand returns ISO.$sub(base, amount, unit?)-> subtracts from number/date. For dates, default unit isdayand returns ISO.$now()-> current datetime in ISO$today()-> current datetime in ISO (same as$now)
Type and Fallback:
$number(value)-> parses to number (invalid ->undefined)$boolean(value)-> normalizes truthy values$default(value, fallback)-> fallback if value is empty$coalesce(v1, v2, v3...)-> first non-empty value (null,undefined,""are skipped)
IDs:
$nanoid(length)-> random id$uuid()-> random UUID (v4)
Notes:
- All functions must be called with parentheses. Example:
$today(), not$today. $obj($_path, $_thumbnailPath)infers keys from field names and returns{ path, thumbnailPath }.$obj('url', $_path, 'thumb', $_thumbnailPath)uses explicit key-value pairs.$extract($_categories, 'name')returns['Category A', 'Category B'].$extract($_files, 'path', 'thumbnailPath')returns[{ path, thumbnailPath }, ...].
$date format tokens: YYYY, MM, DD, HH, mm, ss.
idlangtitleslugcanonicaltemplatelayoutstatus
MIT