1"use strict";(globalThis.webpackChunk_walkeros_website=globalThis.webpackChunk_walkeros_website||[]).push([[3728],{8563(e,s,t){t.r(s),t.d(s,{assets:()=>o,contentTitle:()=>r,default:()=>p,frontMatter:()=>l,metadata:()=>n,toc:()=>d});let n=JSON.parse('{"id":"getting-started/flow/step-examples","title":"Step examples","description":"Embed input/output examples on each flow step for testing, documentation, and simulation","source":"@site/docs/getting-started/flow/step-examples.mdx","sourceDirName":"getting-started/flow","slug":"/getting-started/flow/step-examples","permalink":"/docs/getting-started/flow/step-examples","draft":false,"unlisted":false,"editUrl":"https://github.com/elbwalker/walkerOS/edit/main/website/docs/getting-started/flow/step-examples.mdx","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"title":"Step examples","description":"Embed input/output examples on each flow step for testing, documentation, and simulation","sidebar_position":1},"sidebar":"docsSidebar","previous":{"title":"Flow","permalink":"/docs/getting-started/flow/"},"next":{"title":"Contract","permalink":"/docs/getting-started/flow/contract"}}');var a=t(62540),i=t(65404);let l={title:"Step examples",description:"Embed input/output examples on each flow step for testing, documentation, and simulation",sidebar_position:1},r="Step examples",o={},d=[{value:"What are step examples",id:"what-are-step-examples",level:2},{value:"The <code>{ in, out }</code> format",id:"the--in-out--format",level:2},{value:"Command examples",id:"command-examples",level:3},{value:"Three type zones",id:"three-type-zones",level:2},{value:"Adding examples to a flow",id:"adding-examples-to-a-flow",level:2},{value:"Using examples with the CLI",id:"using-examples-with-the-cli",level:2},{value:"Simulate a single example",id:"simulate-a-single-example",level:3},{value:"Validate examples",id:"validate-examples",level:3},{value:"Cross-step validation",id:"cross-step-validation",level:3},{value:"Using examples in tests",id:"using-examples-in-tests",level:2},{value:"Package-level vs flow-level examples",id:"package-level-vs-flow-level-examples",level:2},{value:"Next steps",id:"next-steps",level:2}];function c(e){let s={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components},{CodeSnippet:t,Details:n}=s;return t||h("CodeSnippet",!0),n||h("Details",!0),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(s.header,{children:(0,a.jsx)(s.h1,{id:"step-examples",children:"Step examples"})}),"\n",(0,a.jsxs)(s.p,{children:["Add ",(0,a.jsx)(s.code,{children:"examples"})," to any step in your flow config to document what it expects and produces:"]}),"\n",(0,a.jsx)(s.pre,{children:(0,a.jsx)(s.code,{className:"language-json",children:'"examples": {\n "purchase": {\n "in": { "name": "order complete", "data": { "id": "ORD-123", "total": 149.97 } },\n "mapping": { "name": "purchase", "data": { "map": { "transaction_id": "data.id", "value": "data.total" } } },\n "out": ["event", "purchase", { "transaction_id": "ORD-123", "value": 149.97 }]\n }\n}\n'})}),"\n",(0,a.jsx)(s.p,{children:"Examples are test fixtures, documentation, and simulation data in one place. They live in your flow config, get stripped at build time, and have zero runtime impact."}),"\n",(0,a.jsx)(s.h2,{id:"what-are-step-examples",children:"What are step examples"}),"\n",(0,a.jsxs)(s.p,{children:["Every source, transformer, and destination in a walkerOS flow is a ",(0,a.jsx)(s.strong,{children:"step"}),". Each step receives input and produces output. Step examples are named ",(0,a.jsx)(s.code,{children:"{ in, out }"})," pairs that capture concrete data for each step: what goes in, what comes out."]}),"\n",(0,a.jsx)(s.p,{children:"They serve multiple purposes simultaneously:"}),"\n",(0,a.jsxs)(s.ul,{children:["\n",(0,a.jsxs)(s.li,{children:[(0,a.jsx)(s.strong,{children:"Documentation"}),": developers see real data shapes, not just type signatures"]}),"\n",(0,a.jsxs)(s.li,{children:[(0,a.jsx)(s.strong,{children:"Testing"}),": CI runs examples as regression tests via ",(0,a.jsx)(s.code,{children:"walkeros push --simulate"})]}),"\n",(0,a.jsxs)(s.li,{children:[(0,a.jsx)(s.strong,{children:"Simulation"}),": debug your pipeline before deployment"]}),"\n",(0,a.jsxs)(s.li,{children:[(0,a.jsx)(s.strong,{children:"LLM context"}),": AI tools use examples to suggest correct mappings"]}),"\n"]}),"\n",(0,a.jsxs)(s.h2,{id:"the--in-out--format",children:["The ",(0,a.jsx)(s.code,{children:"{ in, out }"})," format"]}),"\n",(0,a.jsx)(s.p,{children:"Each example has a human-readable name and two fields:"}),"\n",(0,a.jsx)(t,{code:`{ 2 "examples": { 3 "page view": { 4 "in": { 5 "name": "page view", 6 "data": { "title": "Home", "path": "/" } 7 }, 8 "out": ["event", "page_view", { "page_title": "Home" }] 9 }, 10 "purchase": { 11 "in": { 12 "name": "order complete", 13 "data": { "id": "ORD-123", "total": 149.97, "currency": "EUR" } 14 }, 15 "mapping": { 16 "name": "purchase", 17 "data": { 18 "map": { 19 "transaction_id": "data.id", 20 "value": "data.total", 21 "currency": "data.currency" 22 } 23 } 24 }, 25 "out": ["event", "purchase", { 26 "transaction_id": "ORD-123", 27 "value": 149.97, 28 "currency": "EUR" 29 }] 30 } 31 } 32}`,language:"json"}),"\n",(0,a.jsxs)(s.table,{children:[(0,a.jsx)(s.thead,{children:(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.th,{children:"Field"}),(0,a.jsx)(s.th,{children:"Type"}),(0,a.jsx)(s.th,{children:"Description"})]})}),(0,a.jsxs)(s.tbody,{children:[(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.td,{children:(0,a.jsx)(s.code,{children:"in"})}),(0,a.jsx)(s.td,{children:"any"}),(0,a.jsx)(s.td,{children:"The data the step receives"})]}),(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.td,{children:(0,a.jsx)(s.code,{children:"mapping"})}),(0,a.jsx)(s.td,{children:"object"}),(0,a.jsx)(s.td,{children:"The mapping rule applied to this event (destinations only)"})]}),(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.td,{children:(0,a.jsx)(s.code,{children:"out"})}),(0,a.jsx)(s.td,{children:"any"}),(0,a.jsx)(s.td,{children:"The data the step produces"})]}),(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.td,{children:(0,a.jsx)(s.code,{children:"out: false"})}),(0,a.jsx)(s.td,{children:(0,a.jsx)(s.code,{children:"false"})}),(0,a.jsx)(s.td,{children:"The step rejects or filters this event"})]}),(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.td,{children:(0,a.jsx)(s.code,{children:"command"})}),(0,a.jsx)(s.td,{children:"string"}),(0,a.jsxs)(s.td,{children:["Route ",(0,a.jsx)(s.code,{children:"in"})," through a walker command instead of pushing it as an event (",(0,a.jsx)(s.code,{children:"config"}),", ",(0,a.jsx)(s.code,{children:"consent"}),", ",(0,a.jsx)(s.code,{children:"user"}),", ",(0,a.jsx)(s.code,{children:"run"}),")"]})]})]})]}),"\n",(0,a.jsxs)(s.p,{children:["For destinations, the optional ",(0,a.jsx)(s.code,{children:"mapping"})," field captures the mapping rule that transforms the walkerOS event into the vendor-specific output. This ties the example to a specific mapping configuration, so tests and simulations can register it dynamically as ",(0,a.jsx)(s.code,{children:"{ [entity]: { [action]: example.mapping } }"}),"."]}),"\n",(0,a.jsx)(s.h3,{id:"command-examples",children:"Command examples"}),"\n",(0,a.jsxs)(s.p,{children:["Some destinations need to react to walker commands (consent updates, user identification, run state) rather than events. Set the ",(0,a.jsx)(s.code,{children:"command"})," field on a step example so the test runner invokes ",(0,a.jsx)(s.code,{children:"elb('walker <command>', in)"})," instead of pushing ",(0,a.jsx)(s.code,{children:"in"})," as a regular event:"]}),"\n",(0,a.jsx)(t,{code:`{ 33 "command": "consent", 34 "in": { "marketing": true, "functional": true }, 35 "out": ["consent", "update", { "ad_storage": "granted", "analytics_storage": "granted" }] 36}`,language:"json"}),"\n",(0,a.jsxs)(s.p,{children:["Supported commands: `config`, `consent`, `user`, `run`. When ",(0,a.jsx)(s.code,{children:"command"})," is set, ",(0,a.jsx)(s.code,{children:"mapping"}
36)," is ignored, because commands don't flow through event mapping. See the ",(0,a.jsx)(s.a,{href:"https://github.com/elbwalker/walkerOS/blob/main/skills/walkeros-using-step-examples/SKILL.md#command-step-example",children:"walkeros-using-step-examples skill"})," for the full test-runner pattern."]}),"\n",(0,a.jsxs)(s.p,{children:["You can add as many named examples as you need. Each name becomes addressable from the CLI with ",(0,a.jsx)(s.code,{children:"--example"}),"."]}),"\n",(0,a.jsx)(s.h2,{id:"three-type-zones",children:"Three type zones"}),"\n",(0,a.jsxs)(s.p,{children:["A walkerOS flow has three distinct type zones. The shape of ",(0,a.jsx)(s.code,{children:"in"})," and ",(0,a.jsx)(s.code,{children:"out"})," depends on where the step sits:"]}),"\n",(0,a.jsx)(s.pre,{children:(0,a.jsx)(s.code,{children:" ARBITRARY walkerOS.Event ARBITRARY\n \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 Source \u2502 \u2192 \u2502 Collector \u2192 Transform \u2502 \u2192 \u2502 Destination \u2502\n \u2502 ingest \u2502 \u2502 \u2192 ... \u2192 Transform \u2502 \u2502 output \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n package- known structure, package-\n specific varying properties specific\n"})}),"\n",(0,a.jsxs)(s.ul,{children:["\n",(0,a.jsxs)(s.li,{children:[(0,a.jsxs)(s.strong,{children:["Source ",(0,a.jsx)(s.code,{children:"in"})]}),": raw HTTP request body, DOM event, dataLayer push (package-specific)"]}),"\n",(0,a.jsxs)(s.li,{children:[(0,a.jsxs)(s.strong,{children:["Source ",(0,a.jsx)(s.code,{children:"out"})," through destination ",(0,a.jsx)(s.code,{children:"in"})]}),": ",(0,a.jsx)(s.code,{children:"walkerOS.Event"})," (known structure, varying properties)"]}),"\n",(0,a.jsxs)(s.li,{children:[(0,a.jsxs)(s.strong,{children:["Destination ",(0,a.jsx)(s.code,{children:"out"})]}),": ",(0,a.jsx)(s.code,{children:"gtag()"})," args, ",(0,a.jsx)(s.code,{children:"fbq()"})," args, HTTP POST body (vendor-specific)"]}),"\n"]}),"\n",(0,a.jsxs)(s.p,{children:["Transformers that filter events use ",(0,a.jsx)(s.code,{children:"out: false"})," to indicate rejection."]}),"\n",(0,a.jsx)(s.h2,{id:"adding-examples-to-a-flow",children:"Adding examples to a flow"}),"\n",(0,a.jsx)(s.p,{children:"Here is a complete flow config with examples on a source, transformer, and destination:"}),"\n",(0,a.jsx)(t,{code:`{ 37 "version": 4, 38 "flows": { 39 "default": { 40 "config": { "platform": "server" }, 41 "sources": { 42 "http": { 43 "package": "@walkeros/server-source-express", 44 "config": { "settings": { "port": 8080 } }, 45 "examples": { 46 "page view": { 47 "in": { 48 "method": "POST", 49 "body": { "name": "page view", "data": { "title": "Home" } } 50 }, 51 "out": { "name": "page view", "data": { "title": "Home" } } 52 } 53 } 54 } 55 }, 56 "transformers": { 57 "fingerprint": { 58 "package": "@walkeros/server-transformer-fingerprint", 59 "examples": { 60 "enriched event": { 61 "in": { "name": "page view", "data": { "title": "Home" } }, 62 "out": { "name": "page view", "data": { "title": "Home" } } 63 } 64 } 65 } 66 }, 67 "destinations": { 68 "ga4": { 69 "package": "@walkeros/web-destination-gtag", 70 "config": { 71 "settings": { "measurementId": "G-DEMO123456" } 72 }, 73 "examples": { 74 "page view": { 75 "in": { "name": "page view", "data": { "title": "Home" } }, 76 "mapping": { 77 "name": "page_view", 78 "data": { "map": { "page_title": "data.title" } } 79 }, 80 "out": ["event", "page_view", { "page_title": "Home" }] 81 } 82 } 83 } 84 }, 85 "collector": {} 86 } 87 } 88}`,language:"json"}),"\n",(0,a.jsx)(s.p,{children:"Examples are stripped by the bundler at build time. They never appear in your production bundle."}),"\n",(0,a.jsx)(s.h2,{id:"using-examples-with-the-cli",children:"Using examples with the CLI"}),"\n",(0,a.jsx)(s.h3,{id:"simulate-a-single-example",children:"Simulate a single example"}),"\n",(0,a.jsx)(s.p,{children:"Run a named example through the pipeline:"}),"\n",(0,a.jsx)(t,{code:`# Run the "page view" example from the ga4 destination 89walkeros push flow.json --simulate destination.ga4 --event '{"name":"page view","data":{"title":"Home"}}'`,language:"bash"}),"\n",(0,a.jsxs)(s.p,{children:["The CLI feeds ",(0,a.jsx)(s.code,{children:"in"})," to the step, runs it through the pipeline, and compares the actual output against ",(0,a.jsx)(s.code,{children:"out"}),". Mismatches are reported as errors."]}),"\n",(0,a.jsx)(s.h3,{id:"validate-examples",children:"Validate examples"}),"\n",(0,a.jsx)(s.p,{children:"Check that examples match expected shapes without running the full pipeline:"}),"\n",(0,a.jsx)(t,{code:"walkeros validate flow.json",language:"bash"}),"\n",(0,a.jsx)(s.h3,{id:"cross-step-validation",children:"Cross-step validation"}),"\n",(0,a.jsxs)(s.p,{children:["Cross-step example validation is included automatically when validating a flow. It verifies that connected steps (source \u2192 transformer \u2192 destination) have structurally compatible ",(0,a.jsx)(s.code,{children:"out"}),"/",(0,a.jsx)(s.code,{children:"in"})," pairs:"]}),"\n",(0,a.jsx)(t,{code:"walkeros validate flow.json",language:"bash"}),"\n",(0,a.jsx)(s.p,{children:"Cross-step validation checks that:"}),"\n",(0,a.jsxs)(s.ul,{children:["\n",(0,a.jsxs)(s.li,{children:["Source ",(0,a.jsx)(s.code,{children:"out"}
89)," types match transformer ",(0,a.jsx)(s.code,{children:"in"})," types"]}),"\n",(0,a.jsxs)(s.li,{children:["Transformer ",(0,a.jsx)(s.code,{children:"out"})," types match destination ",(0,a.jsx)(s.code,{children:"in"})," types"]}),"\n",(0,a.jsx)(s.li,{children:"Steps without examples produce warnings"}),"\n",(0,a.jsx)(s.li,{children:"Contract compliance when contracts are defined"}),"\n"]}),"\n",(0,a.jsx)(s.h2,{id:"using-examples-in-tests",children:"Using examples in tests"}),"\n",(0,a.jsx)(s.p,{children:"Extract examples from your flow config and use them as test fixtures:"}),"\n",(0,a.jsx)(t,{code:`import { readFileSync } from 'fs'; 90import { push } from '@walkeros/web-destination-gtag'; 91 92const flow = JSON.parse(readFileSync('flow.json', 'utf-8')); 93const ga4Examples = flow.flows.default.destinations.ga4.examples; 94 95const cases = Object.entries(ga4Examples).map( 96 ([name, ex]) => [name, ex.in, ex.out] 97); 98 99it.each(cases)('ga4 destination: %s', (name, input, expected) => { 100 const result = push(input); 101 expect(result).toEqual(expected); 102});`,language:"typescript"}),"\n",(0,a.jsx)(s.p,{children:"This pattern means your flow config is the single source of truth for both documentation and tests."}),"\n",(0,a.jsx)(s.h2,{id:"package-level-vs-flow-level-examples",children:"Package-level vs flow-level examples"}),"\n",(0,a.jsx)(s.p,{children:"Examples exist at two levels:"}),"\n",(0,a.jsxs)(s.table,{children:[(0,a.jsx)(s.thead,{children:(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.th,{children:"Level"}),(0,a.jsx)(s.th,{children:"Where"}),(0,a.jsx)(s.th,{children:"Purpose"})]})}),(0,a.jsxs)(s.tbody,{children:[(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.td,{children:(0,a.jsx)(s.strong,{children:"Package"})}),(0,a.jsxs)(s.td,{children:[(0,a.jsx)(s.code,{children:"walkerOS.json"})," in the npm package (via ",(0,a.jsx)(s.code,{children:"dev.ts"}),")"]}),(0,a.jsx)(s.td,{children:"Generic examples showing what the package handles"})]}),(0,a.jsxs)(s.tr,{children:[(0,a.jsx)(s.td,{children:(0,a.jsx)(s.strong,{children:"Flow"})}),(0,a.jsxs)(s.td,{children:["Inline on step references in ",(0,a.jsx)(s.code,{children:"flow.json"})]}),(0,a.jsx)(s.td,{children:"Specific examples for your actual data and mappings"})]})]})]}),"\n",(0,a.jsxs)(s.p,{children:[(0,a.jsx)(s.strong,{children:"Package examples"})," are generic and ship with the npm package. They show the package's capabilities with sample data. The CLI and MCP tools discover them from CDN."]}),"\n",(0,a.jsxs)(s.p,{children:[(0,a.jsx)(s.strong,{children:"Flow examples"})," are specific to your setup. They use your real event names, your actual data properties, and your configured mappings. They override or complement package examples."]}),"\n",(0,a.jsxs)(n,{children:[(0,a.jsx)("summary",{children:"How packages ship examples"}),(0,a.jsxs)(s.p,{children:["Packages export examples through the ",(0,a.jsx)(s.code,{children:"dev.ts"})," convention:"]}),(0,a.jsx)(t,{code:`// src/dev.ts 103export * as schemas from './schemas'; 104export * as examples from './examples';`,language:"typescript"}),(0,a.jsxs)(s.p,{children:["These are included in the package's ",(0,a.jsx)(s.code,{children:"walkerOS.json"})," metadata and discoverable via CDN, following the same ",(0,a.jsx)(s.code,{children:"{ in, out }"})," format used in flow configs."]})]}),"\n",(0,a.jsx)(s.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,a.jsxs)(s.ul,{children:["\n",(0,a.jsxs)(s.li,{children:[(0,a.jsx)(s.strong,{children:(0,a.jsx)(s.a,{href:"/docs/apps/cli",children:"CLI"})}),": Bundle and simulate flows with examples"]}),"\n",(0,a.jsxs)(s.li,{children:[(0,a.jsx)(s.strong,{children:(0,a.jsx)(s.a,{href:"/docs/getting-started/flow",children:"Flow"})}),": Learn the full flow configuration format"]}),"\n",(0,a.jsxs)(s.li,{children:[(0,a.jsx)(s.strong,{children:(0,a.jsx)(s.a,{href:"/docs/mapping",children:"Mapping"})}),": Transform events between steps"]}),"\n",(0,a.jsxs)(s.li,{children:[(0,a.jsx)(s.strong,{children:(0,a.jsx)(s.a,{href:"/docs/getting-started/event-model",children:"Event model"})}),": Understand the walkerOS event structure"]}),"\n"]})]})}function p(e={}){let{wrapper:s}={...(0,i.R)(),...e.components};return s?(0,a.jsx)(s,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}function h(e,s){throw Error("Expected "+(s?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},65404(e,s,t){t.d(s,{R:()=>l,x:()=>r});var n=t(63696);let a={},i=n.createContext(a);function l(e){let s=n.useContext(i);return n.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function r(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:l(e.components),n.createElement(i.Provider,{value:s},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.