@ebitex/content-mcp 0.5.119 → 0.5.120

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,7 +21,7 @@ export const HELP_TOPICS = [
21
21
  {
22
22
  "slug": "content-adapters",
23
23
  "title": "Bridging Contracts with Adapters",
24
- "body": "# Bridging Contracts with Adapters\n\nWhen you bind a Component to a Template (see [Authoring a presentation](content-authoring.md)), the\nComponent's Contract normally has to be exactly what the Template needs, or a more specific kind of\nit. Sometimes the Component you want to use has a *different* Contract entirely — an **Adapter**\nbridges that gap by mapping the mismatched Contract's fields onto the ones the Template expects.\n\n## When the wizard offers one\n\nIn the Presentation wizard's **Select existing** tab, a Component whose Contract the Template\ndoesn't recognize at all lands in the **Needs an Adapter** group. Selecting one shows why it doesn't\nfit, and three buttons appear:\n\n- **Use existing Adapter** — pick an already-created Adapter that maps this Component's Contract onto\n something the Template accepts.\n- **Create Adapter** — build a new, reusable, named Adapter right there in the wizard, for this\n Contract pairing. It's saved to the **Adapters** page (under Configure) so anyone can reuse it\n later.\n- **Connect manually** — build a one-off mapping that's saved directly on this Presentation only,\n never listed on the Adapters page. Useful for a mapping you don't expect to need again. A **Save as\n Adapter…** action turns it into a named one later, without redoing the mapping.\n\nEither way, once a mapping is attached the field-by-field connections are drawn between the\nComponent's fields and the Template's, Complete becomes available, and the banner reads \"Mapped via\n*Adapter name*\" (or \"Mapped manually\" for a one-off).\n\nA Component that's already Compatible can still get an Adapter attached deliberately — useful when\nyou want to reshape its content on the way into this particular Template, even though it didn't\nstrictly need mapping.\n\n## After it's mapped\n\nOnce a mapping is attached, the set-value card offers a few more actions beside the Adapter's name:\n\n- **Edit mapping** — reopens the same field-by-field canvas, already filled in with the current\n mapping, so you can adjust it without starting over. This never changes *which* Component is\n bound, and editing a named Adapter's mapping this way never touches the shared Adapter itself (so\n every other Presentation using it is unaffected) — it becomes this Presentation's own one-off\n mapping instead, which you can turn back into a named Adapter with **Save as Adapter…** if you\n want to reuse it elsewhere.\n- **Change** — picks a different Component for this Presentation entirely. If the new Component's\n Contract still works with the mapping that was already in place, it's kept automatically; if not,\n it's dropped and the reason is explained right there, so you can map fresh.\n- **Save as Adapter…** — only shown for a one-off (\"manual mapping\") — turns it into a named,\n reusable Adapter without redoing any of the mapping work.\n\n## The four rule kinds, in plain language\n\nEvery field the Template needs gets exactly one rule saying where its value comes from:\n\n- **Copy** — take the value straight from one of the Component's own fields (the field types have to\n be compatible — see below).\n- **Compute** — build the value from a small set of building blocks: one of the Component's fields, a\n fixed piece of text, joining a few things together with an optional separator, falling back\n through a list of options until one isn't empty, converting a value from one field type to a\n compatible one (e.g. plain text into rich text), taking just the first item of a list, reading a\n field out of a referenced/nested item, mapping every item of a list, dispatching on which kind of\n item you have, or a simple condition/comparison — see **Logic and structure blocks** below for all\n of these. There's no free-text formula box — you build the computation visually, block by block, on\n the canvas.\n- **Map inner content** — for a field that holds another whole piece of content inside it (a nested\n or embedded Component), apply a second, smaller Adapter to that inner content: pick an existing\n named Adapter, or **Connect manually** to name that inner content's own two Contracts and map them\n right there, the same way you'd map the outer fields. (This is also available as the **For each\n item** block's own \"Adapt to another Contract\" mode — see below — which is the way to reach it when\n you're adding a fresh block rather than mapping a whole field.)\n- **Look up a fixed item** — instead of taking a value from the Component being mapped, always pull it\n from one specific, chosen Component or item.\n\n## Field compatibility\n\nTwo fields need to either already match, or be *coercible*, to connect — you can't map a text field\nstraight onto a number field, for example, but a few kinds of mismatch have a small conversion block\nthe canvas offers to insert for you automatically:\n\n- A single value can feed a field that accepts multiple values (it becomes a one-item list) — no\n extra block needed.\n- A field that accepts multiple values can feed a single-value field by inserting a **Take first\n item** block, which uses the first value and drops the rest.\n- Some field types can be converted into others by inserting a **Convert** block — plain text into\n rich text, plain text into a number (fails at delivery time if the text isn't actually numeric), a\n number into text, or rich text into plain text (its formatting is discarded).\n- A field that isn't translatable can feed a translatable one (it becomes that language's default,\n with no translations yet).\n- A field restricted to certain kinds of related content requires the source to already be\n restricted to the same (or a more specific) set.\n\nWhen you connect two fields that need one of these conversions, a small prompt appears offering to\ninsert the right block between them — accept it and the connection completes with that block already\nwired in place. Everything else — a translatable field into a non-translatable one, a personalizable\nfield into a non-personalizable one (or vice versa), or two field types with no registered\nconversion at all — isn't allowed, and the canvas explains why right there instead of drawing a\nconnection (incompatible fields are also visibly dimmed while you have a source selected).\n\n## What \"unmapped — delivers null\" means\n\nEvery field the Template *requires* needs a rule — the canvas won't let you save until they all do.\nA field that's merely optional can be left unmapped; the card for it reads **unmapped — delivers\nnull**, meaning a person or system reading this content afterward will see that field as empty,\nexactly as if it had no value at all. This is often exactly what you want for a field the source\nContract has no equivalent of.\n\n## The mapping canvas\n\nWhether you're on the standalone **Adapters** page (Configure → Adapters → New Adapter) or inside the\nwizard, mapping works the same way: every building block you add is its own node on one draggable,\nzoomable canvas — the **Input document** card starts on the left, the Template's (or the other\nContract's) fields on the right. Drag a line from one connector to another to connect them, or click a\nname to select it as the starting point and then click the one it should feed — both do exactly\nthe same thing, so use whichever is easier at the time. Click an existing connection, or the field's own\ndelete button, to remove it. `Escape` cancels a pending click-to-connect selection.\n\nThe **Input document** card is everything you're mapping *from*, in one place. It's always there, and\nit has three parts:\n\n- **Fields** — one connector per field of the Contract you're mapping from. This is the everyday\n one: drag a field straight across to the output it should fill.\n- **Input document** — the whole piece of content, as one thing. Use this when the same Adapter runs\n over several *different* kinds of content (a search result over every kind of page, say) and you\n need to branch on which kind each one actually is — connect it to a **Switch on Contract** block.\n- **System** — facts about the run itself rather than about the content: **Source contract external\n id** and **Source contract id**, which tell a consumer *which kind* of content a result came from.\n\nThe **+ Add node** button adds a building block to the canvas — **Join text**, **First non-null**, a\n**Constant value**, **Convert type**, **Take first item**, **Look up in** (a fixed reference to one\nComponent), **Expand fields**, **Build value**, **For each item**, **Switch on Contract**, **If / else**,\n**Equals**, or **Exists** (the last seven are covered in **Logic and structure blocks** below). Drag or click to\nwire fields into and out of it just like any other node; each block has its own small settings right on\nthe node itself (which characters to join with, what to convert into, and so on). Delete a block with\nthe **✕** in its own corner.\n\nA required field the Template needs that's still unconnected is called out in red at the bottom of the\ncanvas, and saving stays disabled until every one of them has a rule.\n\nA **Full screen** button, above the canvas, expands it to fill the whole screen for a more complex\nmapping that needs more room to work in — nothing about the mapping is lost switching in or out, and\n`Escape` exits back to the normal view.\n\nA **Preview** button lets you pick a sample piece of content of the source Contract and see exactly\nwhat the mapped result looks like, using the real mapping engine — no guessing.\n\nThe canvas remembers however you arrange the nodes — drag them into a layout that makes sense to\nyou, save, and it's still that way next time you (or anyone else) open this mapping, whether it's a\nnamed Adapter or a one-off mapping on a single Presentation. Dragging snaps each node to a light\ngrid so things line up cleanly. A node you add but never connect to anything doesn't have its\nposition remembered, since it isn't part of the saved mapping at all yet.\n\n## Logic and structure blocks\n\n**Lists always go through a \"For each item\" block.** None of the other blocks below — Expand fields,\nSwitch on Contract, If/else, Equals, Exists — ever work directly on a list; each expects one item.\nWhen the field you're reading from holds a list, add a **For each item** block first: it's the one\nblock that turns a list into \"one item at a time\" and back into a list again. Everything else you\nconnect after it (an Expand, a Switch, a comparison, whatever the mapping needs for one item) runs\nonce per item automatically.\n\n- **Expand fields** — reads a field out of something that isn't a plain value: a referenced item, a\n nested piece of content, or a component field. Pick which Contract you're expecting (skipped\n automatically when there's only one possibility), and the block grows one output for each of that\n Contract's own fields — connect whichever ones you need onward, just like any other field.\n- **Expand Linked Experience** — for a link field that points at a page in your Experience tree:\n opens the linked page in one step. Its outputs are the page's **Name**, **URL**, **Component** (the\n content it's built from — pick a Contract under \"Read content as…\" to get that content's own fields\n as further outputs) and **Presentation** — the page's own rendering, exactly as it's configured\n (its Template, its content, its settings). Connect **Presentation** to a Presentation-typed output\n to show that page's presentation inline on yours — a \"featured pages\" section that re-hosts each\n page's real rendering rather than rebuilding a card from its fields. An outside link, or a page\n with no presentation of its own, gives nothing here; inside a **For each item**, pair it with\n **Keep item when** (below) to drop those. If the output field only allows certain Templates, a\n relayed presentation built on a different Template comes out empty (with a warning) rather than\n slipping through — widen the field's allowed Templates if that's not what you want.\n- **Build value** — the opposite of Expand fields: assembles a nested piece of content, or a component\n field's inline value, out of other fields in this mapping. Pick which Contract you're building, and\n the block grows one input for each of that Contract's own fields (fields with no separate override —\n the \"context\" ones you'd only ever fill in on a specific usage — never appear here at all). Fields\n marked **Required** need a connection before the mapping can be saved; anything else is optional and\n comes out empty if you leave it unconnected. Pick **Nested** or **Component** to match whatever field\n you're feeding the result into.\n- **For each item** — the only block that crosses a list boundary, as above. Choose one of two modes:\n - **Map each item** — click **Edit mapping** to open a dedicated screen (it takes over the whole\n canvas, with a **Back** button to return) where you build the per-item transformation using an\n **Item** starting point and a **Result** ending point, with any of the other blocks in between —\n including another **For each item**, for a list inside a list. That screen also has a second\n ending point, **Keep item when**: wire a yes/no value into it (an Exists or Equals block,\n usually) and only the items where it comes out *yes* make it into the list — the rest are left\n out entirely, with no empty placeholder and no warning for them. Leave it unconnected to keep\n every item. The typical use is a list of links that mixes pages with outside links: **Expand\n Linked Experience → Component → Exists → Keep item when** drops everything that isn't a real\n page, instead of shipping an empty card for it. One output can feed several blocks at once, so\n the same Expand can supply both the check and the result.\n - **Adapt to another Contract** — apply a whole second, smaller Adapter to each item, exactly like\n **Map inner content** above (pick an existing named Adapter, or **Connect manually**).\n- **Switch on Contract** — for a field that could hold more than one kind of thing (several different\n Contracts), branch the mapping by which one it actually is. Add a case for each Contract you want to\n handle by name; each case gets its own **As *(Contract name)*** output (typically feeding an Expand\n fields block for that specific Contract) and its own **Value for this case** input for what should\n come out when it matches. An optional **Default** input covers any Contract you didn't add a case\n for. See **Reading one page type's fields into several outputs**, below, for the two ways to wire\n it up.\n- **If / else** — picks between two values based on a yes/no condition: wire something into **When**\n (must resolve to yes/no — an Exists or Equals block is the usual source), and one value each into\n **Then** and **Else**.\n- **Equals** — compares two values and outputs yes/no; both sides need to already be the same field\n type (no automatic conversion here — insert a Convert type block first if they aren't).\n- **Exists** — outputs yes unless the value it's checking is completely missing or an empty piece of\n text; useful as the condition for an If/else block (\"only use this if there's actually something\n there\").\n\n## Reading one page type's fields into several outputs\n\nA common shape: the same Adapter runs over several kinds of content, and one of those kinds has a\nhandful of extra fields you want to carry through. A search result over every kind of page, where a\nblog post additionally has a heading, an author, a publish date, an image, topics and an excerpt, is\nthe worked example.\n\nWire it exactly the way you'd draw it:\n\n1. **Input document → Switch on Contract** (its **Value to switch on** connector). Add one case,\n *Blog post*.\n2. **As Blog post → Expand fields.** The Expand grows one output per field a blog post has.\n3. Connect each of those outputs **straight across to the output field it fills** — heading to\n Heading, author to Author, and so on. You do not wire anything back into the Switch.\n\nThat's it. Behind the scenes each of those outputs becomes its own rule, gated on \"only when this\nreally is a blog post\"; anything that isn't a blog post simply leaves those fields empty, which is\nwhat you want. Reopening the Adapter later shows you the same one Switch and one Expand you drew.\n\n**Fields every kind of content has come off the Input document, not through the Switch.** Title and\nDescription exist on every page, so wire them straight from the Input document's **Fields** section.\nRouting them through a case would gain nothing and would leave them empty for anything the Switch\ndoesn't have a case for.\n\n**When one output needs a *different* value per type**, that's the Switch's own arms — \"Title is the\nblog post's heading if it's a blog post, otherwise the page's own title\":\n\n1. **Expand fields → heading → Value for this case** (the *Blog post* arm).\n2. **Input document → Fields → Title → Default.**\n3. **Switch → Result → Title.**\n\nOne connector can feed several places at once, so the same Expand's *heading* output can go to both\nthe Heading output field and the Switch's arm — it's still one Switch and one Expand on the canvas.\n\n**One thing the canvas won't do:** read *two different cases'* fields into a single output without\ngoing through the arms. If you try, that output field shows \"Fields read from different cases of one\nSwitch must go through the case arms and Output\" and saving is blocked until you rewire it — combining\nper-case values is exactly what the arms and **Result** are for. Every other output field keeps\nworking normally in the meantime.\n\n## Editing a named Adapter later\n\nAdapters created via **Create Adapter**, or saved via **Save as Adapter…**, live on the **Adapters**\npage (Configure → Adapters), listed with their input and output Contracts. Editing one there updates\nevery Presentation using it — but only once each of those is **published again**. Content that's\nalready published keeps its existing shape until republished, so a mapping change never silently\nchanges something a visitor is looking at right now.\n\nIf a named Adapter is deleted while still bound to a Presentation, the field-by-field connections stop\nresolving correctly — a warning appears on the affected field, and saving is blocked until you either\nrestore the Adapter, pick a different one, or unbind it.\n"
24
+ "body": "# Bridging Contracts with Adapters\n\nWhen you bind a Component to a Template (see [Authoring a presentation](content-authoring.md)), the\nComponent's Contract normally has to be exactly what the Template needs, or a more specific kind of\nit. Sometimes the Component you want to use has a *different* Contract entirely — an **Adapter**\nbridges that gap by mapping the mismatched Contract's fields onto the ones the Template expects.\n\n## When the wizard offers one\n\nIn the Presentation wizard's **Select existing** tab, a Component whose Contract the Template\ndoesn't recognize at all lands in the **Needs an Adapter** group. Selecting one shows why it doesn't\nfit, and three buttons appear:\n\n- **Use existing Adapter** — pick an already-created Adapter that maps this Component's Contract onto\n something the Template accepts.\n- **Create Adapter** — build a new, reusable, named Adapter right there in the wizard, for this\n Contract pairing. It's saved to the **Adapters** page (under Configure) so anyone can reuse it\n later.\n- **Connect manually** — build a one-off mapping that's saved directly on this Presentation only,\n never listed on the Adapters page. Useful for a mapping you don't expect to need again. A **Save as\n Adapter…** action turns it into a named one later, without redoing the mapping.\n\nEither way, once a mapping is attached the field-by-field connections are drawn between the\nComponent's fields and the Template's, Complete becomes available, and the banner reads \"Mapped via\n*Adapter name*\" (or \"Mapped manually\" for a one-off).\n\nA Component that's already Compatible can still get an Adapter attached deliberately — useful when\nyou want to reshape its content on the way into this particular Template, even though it didn't\nstrictly need mapping.\n\n## After it's mapped\n\nOnce a mapping is attached, the set-value card offers a few more actions beside the Adapter's name:\n\n- **Edit mapping** — reopens the same field-by-field canvas, already filled in with the current\n mapping, so you can adjust it without starting over. This never changes *which* Component is\n bound, and editing a named Adapter's mapping this way never touches the shared Adapter itself (so\n every other Presentation using it is unaffected) — it becomes this Presentation's own one-off\n mapping instead, which you can turn back into a named Adapter with **Save as Adapter…** if you\n want to reuse it elsewhere.\n- **Change** — picks a different Component for this Presentation entirely. If the new Component's\n Contract still works with the mapping that was already in place, it's kept automatically; if not,\n it's dropped and the reason is explained right there, so you can map fresh.\n- **Save as Adapter…** — only shown for a one-off (\"manual mapping\") — turns it into a named,\n reusable Adapter without redoing any of the mapping work.\n\n## The four rule kinds, in plain language\n\nEvery field the Template needs gets exactly one rule saying where its value comes from:\n\n- **Copy** — take the value straight from one of the Component's own fields (the field types have to\n be compatible — see below).\n- **Compute** — build the value from a small set of building blocks: one of the Component's fields, a\n fixed piece of text, joining a few things together with an optional separator, falling back\n through a list of options until one isn't empty, converting a value from one field type to a\n compatible one (e.g. plain text into rich text), taking just the first item of a list, reading a\n field out of a referenced/nested item, mapping every item of a list, dispatching on which kind of\n item you have, or a simple condition/comparison — see **Logic and structure blocks** below for all\n of these. There's no free-text formula box — you build the computation visually, block by block, on\n the canvas.\n- **Map inner content** — for a field that holds another whole piece of content inside it (a nested\n or embedded Component), apply a second, smaller Adapter to that inner content: pick an existing\n named Adapter, or **Connect manually** to name that inner content's own two Contracts and map them\n right there, the same way you'd map the outer fields. (This is also available as the **For each\n item** block's own \"Adapt to another Contract\" mode — see below — which is the way to reach it when\n you're adding a fresh block rather than mapping a whole field.)\n- **Look up a fixed item** — instead of taking a value from the Component being mapped, always pull it\n from one specific, chosen Component or item.\n\n## Field compatibility\n\nTwo fields need to either already match, or be *coercible*, to connect — you can't map a text field\nstraight onto a number field, for example, but a few kinds of mismatch have a small conversion block\nthe canvas offers to insert for you automatically:\n\n- A single value can feed a field that accepts multiple values (it becomes a one-item list) — no\n extra block needed.\n- A field that accepts multiple values can feed a single-value field by inserting a **Take first\n item** block, which uses the first value and drops the rest.\n- Some field types can be converted into others by inserting a **Convert** block — plain text into\n rich text, plain text into a number (fails at delivery time if the text isn't actually numeric), a\n number into text, or rich text into plain text (its formatting is discarded).\n- A field that isn't translatable can feed a translatable one (it becomes that language's default,\n with no translations yet).\n- A field restricted to certain kinds of related content requires the source to already be\n restricted to the same (or a more specific) set.\n\nWhen you connect two fields that need one of these conversions, a small prompt appears offering to\ninsert the right block between them — accept it and the connection completes with that block already\nwired in place. Everything else — a translatable field into a non-translatable one, a personalizable\nfield into a non-personalizable one (or vice versa), or two field types with no registered\nconversion at all — isn't allowed, and the canvas explains why right there instead of drawing a\nconnection (incompatible fields are also visibly dimmed while you have a source selected).\n\n## What \"unmapped — delivers null\" means\n\nEvery field the Template *requires* needs a rule — the canvas won't let you save until they all do.\nA field that's merely optional can be left unmapped; the card for it reads **unmapped — delivers\nnull**, meaning a person or system reading this content afterward will see that field as empty,\nexactly as if it had no value at all. This is often exactly what you want for a field the source\nContract has no equivalent of.\n\n## The mapping canvas\n\nWhether you're on the standalone **Adapters** page (Configure → Adapters → New Adapter) or inside the\nwizard, mapping works the same way: every building block you add is its own node on one draggable,\nzoomable canvas — the **Input document** card starts on the left, the Template's (or the other\nContract's) fields on the right. Drag a line from one connector to another to connect them, or click a\nname to select it as the starting point and then click the one it should feed — both do exactly\nthe same thing, so use whichever is easier at the time. Click an existing connection, or the field's own\ndelete button, to remove it. `Escape` cancels a pending click-to-connect selection.\n\nThe **Input document** card is everything you're mapping *from*, in one place. It's always there, and\nit has three parts:\n\n- **Fields** — one connector per field of the Contract you're mapping from. This is the everyday\n one: drag a field straight across to the output it should fill.\n- **Input document** — the whole piece of content, as one thing. Use this when the same Adapter runs\n over several *different* kinds of content (a search result over every kind of page, say) and you\n need to branch on which kind each one actually is — connect it to a **Switch on Contract** block.\n- **System** — facts about the run itself rather than about the content: **Source contract external\n id** and **Source contract id**, which tell a consumer *which kind* of content a result came from.\n\nThe **+ Add node** button adds a building block to the canvas — **Join text**, **First non-null**, a\n**Constant value**, **Convert type**, **Take first item**, **Look up in** (a fixed reference to one\nComponent), **Expand fields**, **Build value**, **For each item**, **Switch on Contract**, **If / else**,\n**Equals**, or **Exists** (the last seven are covered in **Logic and structure blocks** below). Drag or click to\nwire fields into and out of it just like any other node; each block has its own small settings right on\nthe node itself (which characters to join with, what to convert into, and so on). Delete a block with\nthe **✕** in its own corner.\n\nA required field the Template needs that's still unconnected is called out in red at the bottom of the\ncanvas, and saving stays disabled until every one of them has a rule.\n\nA **Full screen** button, above the canvas, expands it to fill the whole screen for a more complex\nmapping that needs more room to work in — nothing about the mapping is lost switching in or out, and\n`Escape` exits back to the normal view.\n\nA **Preview** button lets you pick a sample piece of content of the source Contract and see exactly\nwhat the mapped result looks like, using the real mapping engine — no guessing.\n\nThe canvas remembers however you arrange the nodes — drag them into a layout that makes sense to\nyou, save, and it's still that way next time you (or anyone else) open this mapping, whether it's a\nnamed Adapter or a one-off mapping on a single Presentation. Dragging snaps each node to a light\ngrid so things line up cleanly. A node you add but never connect to anything doesn't have its\nposition remembered, since it isn't part of the saved mapping at all yet.\n\n## Logic and structure blocks\n\n**Lists always go through a \"For each item\" block.** None of the other blocks below — Expand fields,\nSwitch on Contract, If/else, Equals, Exists — ever work directly on a list; each expects one item.\nWhen the field you're reading from holds a list, add a **For each item** block first: it's the one\nblock that turns a list into \"one item at a time\" and back into a list again. Everything else you\nconnect after it (an Expand, a Switch, a comparison, whatever the mapping needs for one item) runs\nonce per item automatically.\n\n- **Expand fields** — reads a field out of something that isn't a plain value: a referenced item, a\n nested piece of content, or a component field. Pick which Contract you're expecting (skipped\n automatically when there's only one possibility), and the block grows one output for each of that\n Contract's own fields — connect whichever ones you need onward, just like any other field.\n- **Expand Linked Experience** — for a link field that points at a page in your Experience tree:\n opens the linked page in one step. Its outputs are the page's **Name**, **URL**, **Component** (the\n content it's built from — pick a Contract under \"Read content as…\" to get that content's own fields\n as further outputs) and **Presentation** — the page's own rendering, exactly as it's configured\n (its Template, its content, its settings). Connect **Presentation** to a Presentation-typed output\n to show that page's presentation inline on yours — a \"featured pages\" section that re-hosts each\n page's real rendering rather than rebuilding a card from its fields. An outside link, or a page\n with no presentation of its own, gives nothing here; inside a **For each item**, pair it with\n **Keep item when** (below) to drop those. If the output field only allows certain Templates, a\n relayed presentation built on a different Template comes out empty (with a warning) rather than\n slipping through — widen the field's allowed Templates if that's not what you want.\n- **Build value** — the opposite of Expand fields: assembles a nested piece of content, or a component\n field's inline value, out of other fields in this mapping. Pick which Contract you're building, and\n the block grows one input for each of that Contract's own fields (fields with no separate override —\n the \"context\" ones you'd only ever fill in on a specific usage — never appear here at all). Fields\n marked **Required** need a connection before the mapping can be saved; anything else is optional and\n comes out empty if you leave it unconnected. Pick **Nested** or **Component** to match whatever field\n you're feeding the result into.\n- **For each item** — the only block that crosses a list boundary, as above. Choose one of two modes:\n - **Map each item** — click **Edit mapping** to open a dedicated screen (it takes over the whole\n canvas, with a **Back** button to return) where you build the per-item transformation using an\n **Item** starting point and a **Result** ending point, with any of the other blocks in between —\n including another **For each item**, for a list inside a list. That screen also has a second\n ending point, **Keep item when**: wire a yes/no value into it (an Exists or Equals block,\n usually) and only the items where it comes out *yes* make it into the list — the rest are left\n out entirely, with no empty placeholder and no warning for them. Leave it unconnected to keep\n every item. The typical use is a list of links that mixes pages with outside links: **Expand\n Linked Experience → Component → Exists → Keep item when** drops everything that isn't a real\n page, instead of shipping an empty card for it. One output can feed several blocks at once, so\n the same Expand can supply both the check and the result.\n - **Adapt to another Contract** — apply a whole second, smaller Adapter to each item, exactly like\n **Map inner content** above (pick an existing named Adapter, or **Connect manually**).\n- **Switch on Contract** — for a field that could hold more than one kind of thing (several different\n Contracts), branch the mapping by which one it actually is. Add a case for each Contract you want to\n handle by name; each case gets its own **As *(Contract name)*** output (typically feeding an Expand\n fields block for that specific Contract) and its own **Value for this case** input for what should\n come out when it matches. An optional **Default** input covers any Contract you didn't add a case\n for. See **Reading one page type's fields into several outputs**, below, for the two ways to wire\n it up.\n- **If / else** — picks between two values based on a yes/no condition: wire something into **When**\n (must resolve to yes/no — an Exists or Equals block is the usual source), and one value each into\n **Then** and **Else**.\n- **Equals** — compares two values and outputs yes/no; both sides need to already be the same field\n type (no automatic conversion here — insert a Convert type block first if they aren't).\n- **Exists** — outputs yes unless the value it's checking is completely missing or an empty piece of\n text; useful as the condition for an If/else block (\"only use this if there's actually something\n there\").\n\n## Reading one page type's fields into several outputs\n\nA common shape: the same Adapter runs over several kinds of content, and one of those kinds has a\nhandful of extra fields you want to carry through. A search result over every kind of page, where a\nblog post additionally has a heading, an author, a publish date, an image, topics and an excerpt, is\nthe worked example.\n\nWire it exactly the way you'd draw it:\n\n1. **Input document → Switch on Contract** (its **Value to switch on** connector). Add one case,\n *Blog post*.\n2. **As Blog post → Expand fields.** The Expand grows one output per field a blog post has.\n3. Connect each of those outputs **straight across to the output field it fills** — heading to\n Heading, author to Author, and so on. You do not wire anything back into the Switch.\n\nThat's it. Behind the scenes each of those outputs becomes its own rule, gated on \"only when this\nreally is a blog post\"; anything that isn't a blog post simply leaves those fields empty, which is\nwhat you want. Reopening the Adapter later shows you the same one Switch and one Expand you drew.\n\n**Fields every kind of content has come off the Input document, not through the Switch.** Title and\nDescription exist on every page, so wire them straight from the Input document's **Fields** section.\nRouting them through a case would gain nothing and would leave them empty for anything the Switch\ndoesn't have a case for.\n\n**When one output needs a *different* value per type**, that's the Switch's own arms — \"Title is the\nblog post's heading if it's a blog post, otherwise the page's own title\":\n\n1. **Expand fields → heading → Value for this case** (the *Blog post* arm).\n2. **Input document → Fields → Title → Default.**\n3. **Switch → Result → Title.**\n\nOne connector can feed several places at once, so the same Expand's *heading* output can go to both\nthe Heading output field and the Switch's arm — it's still one Switch and one Expand on the canvas.\n\n**One thing the canvas won't do:** read *two different cases'* fields into a single output without\ngoing through the arms. If you try, that output field shows \"Fields read from different cases of one\nSwitch must go through the case arms and Output\" and saving is blocked until you rewire it — combining\nper-case values is exactly what the arms and **Result** are for. Every other output field keeps\nworking normally in the meantime.\n\n## Suggest rules (Early Access)\n\nFor an organization with this Early Access feature turned on, a **Suggest rules** button appears\nabove the mapping canvas. Describe what you want in plain language — \"map the product's name to the\ncard's title, and its price to the subtitle as a formatted string\" — and it reads the two Contracts\ninvolved, drafts a candidate mapping, and checks its own work against the same validation the canvas\nalready runs, retrying until it's valid or it gives up and says so.\n\n**Nothing is written until you say so.** The panel shows the proposed rules — never the saved\nAdapter — with **Accept** and **Dismiss**. Accept merges the proposal into the mapping you're\ncurrently editing; you still have to press **Save** afterward, exactly as if you'd drawn the\nconnections yourself. Dismiss discards the proposal with no trace. If you already have some of the\nmapping done, describe what's missing — it's told what's already there and builds on it rather than\nstarting over.\n\nIf it can't produce a valid mapping, it says so rather than proposing something broken. If your\norganization has connected its own AI provider credential (see the **AI** section of your\norganization's settings), suggestions run on that provider instead of ebitex's, and a provider-side\nproblem (an expired key, exhausted credit) is reported by name so you know where to look.\n\n## Editing a named Adapter later\n\nAdapters created via **Create Adapter**, or saved via **Save as Adapter…**, live on the **Adapters**\npage (Configure → Adapters), listed with their input and output Contracts. Editing one there updates\nevery Presentation using it — but only once each of those is **published again**. Content that's\nalready published keeps its existing shape until republished, so a mapping change never silently\nchanges something a visitor is looking at right now.\n\nIf a named Adapter is deleted while still bound to a Presentation, the field-by-field connections stop\nresolving correctly — a warning appears on the affected field, and saving is blocked until you either\nrestore the Adapter, pick a different one, or unbind it.\n"
25
25
  },
26
26
  {
27
27
  "slug": "content-authoring",
@@ -1 +1 @@
1
- {"version":3,"file":"helpCorpus.generated.js","sourceRoot":"","sources":["../../src/resources/helpCorpus.generated.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpCorpus.generated.js","sourceRoot":"","sources":["../../src/resources/helpCorpus.generated.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ebitex/content-mcp",
3
- "version": "0.5.119",
3
+ "version": "0.5.120",
4
4
  "description": "An MCP server for ebitex Content: build and publish a content model from an AI agent.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://developers.ebitex.io/getting-started/content-as-code/",