PublishingBlock publishing.block@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- publishing
- Visibility
- first-party
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/publishing/block.v1.json
publishing.block@1: one rich content block, as openvibe-publishing/blocks parses a body. A body is Markdown plus blocks: the Markdown stays the source of truth (revisions diff it) and a block is a fenced directive (:::name{attr="value"} ... :::). The parsed tree is plain JSON, so a product's API hands it out next to the Markdown. Every block has a plain-HTML form and renders server-side; images are Media object ids, never a URL a product invented. Blocks nest: a section holds its prose and its own blocks. The schema checks the first two levels of the tree strictly (a block and the block inside it); deeper levels are objects, because a body nests as deep as its author wrote it.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
type | enum | yes | root is the whole body; text is a run of Markdown; the rest are the blocks. |
|
attrs | object | The attributes of the directive. Which ones a block takes is its own: hero (art, kicker, date), section (id, by, react), figure (src, alt, caption, credit, width, height), compare (before, after, caption), gallery (items, caption), clip (id), pic (id), video (id), embed (url), callout (tone, title), stat (value, label), patchnotes (from, to), infobox (title), timeline (title), quote (by). Unknown attributes are ignored. | ||
value | string | A text node: Markdown, the words between the blocks. |
| |
children | https://openvibe.network/contracts/publishing/block.v1.json#/$defs/block | The blocks and the prose inside this one. A section holds its prose and its own blocks. |
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: body
{
"type": "root",
"children": [
{
"type": "hero",
"attrs": {
"art": "med_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"kicker": "Devblog",
"date": "2026-11-09"
},
"children": [
{
"type": "text",
"value": "This month: blueprints rework, the Uzi, our biggest optimisation pass yet."
}
]
},
{
"type": "section",
"attrs": {
"id": "blueprint-rework",
"by": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"react": true
},
"children": [
{
"type": "text",
"value": "## Blueprint rework\n\nWorkbenches no longer need fragments."
},
{
"type": "figure",
"attrs": {
"src": "med_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"alt": "The channel header"
},
"children": []
}
]
},
{
"type": "patchnotes",
"attrs": {
"from": "2026-11-02",
"to": "2026-11-09"
},
"children": []
}
]
}Valid: section
{
"type": "section",
"attrs": {
"id": "blueprint-rework",
"by": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"react": true
},
"children": [
{
"type": "text",
"value": "## Blueprint rework\n\nWorkbenches no longer need fragments."
}
]
}Rejected: no-type
{
"children": []
}Rejected: unknown-type
{
"type": "mystery",
"attrs": {},
"children": []
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('publishing.block@1', value); // { valid, errors: [{ path, message }] }