[{"data":1,"prerenderedAt":5550},["ShallowReactive",2],{"search-sections-flume":3,"nav-flume":1798,"content-tree-flume":1852,"footer-resources":1878,"content-/v1.0.1/overview":4731,"surround-/v1.0.1/overview":5548},[4,10,14,20,25,31,36,41,45,50,55,60,64,69,74,79,84,88,93,98,103,108,113,118,123,128,133,138,143,148,153,158,162,167,172,177,182,187,192,197,202,207,212,217,222,226,231,236,241,245,249,253,257,262,267,271,276,281,286,291,296,301,306,310,315,320,325,329,333,337,342,347,351,356,361,365,370,375,380,385,390,394,399,404,409,413,417,422,427,432,437,441,446,450,454,459,464,469,474,478,483,488,493,497,502,507,511,516,521,526,530,535,540,545,549,554,559,563,568,573,578,582,586,590,594,598,603,608,613,617,622,627,631,636,641,645,650,655,659,664,669,673,678,683,687,692,697,702,707,711,715,719,723,728,733,738,743,747,752,757,761,765,770,774,779,783,787,792,796,800,804,808,813,817,821,825,830,835,840,845,848,853,858,863,868,873,877,882,886,891,896,901,906,911,916,921,926,931,935,940,945,950,955,960,965,969,973,977,981,985,989,994,999,1004,1009,1014,1018,1023,1028,1033,1037,1042,1047,1052,1056,1061,1066,1070,1075,1080,1085,1090,1094,1099,1103,1108,1113,1118,1123,1128,1133,1138,1143,1147,1151,1156,1160,1165,1170,1175,1180,1185,1189,1194,1199,1204,1209,1213,1218,1223,1228,1233,1237,1242,1247,1252,1257,1262,1265,1270,1275,1280,1285,1289,1294,1299,1304,1309,1314,1319,1324,1329,1334,1339,1342,1347,1352,1356,1361,1366,1371,1376,1381,1386,1391,1396,1401,1405,1410,1414,1419,1423,1427,1431,1436,1441,1445,1450,1455,1460,1465,1470,1475,1480,1485,1490,1495,1500,1505,1510,1515,1520,1525,1530,1535,1540,1544,1548,1552,1556,1560,1564,1568,1571,1575,1579,1583,1587,1591,1595,1599,1603,1607,1611,1615,1619,1623,1627,1631,1636,1640,1645,1649,1653,1658,1663,1668,1672,1677,1681,1686,1691,1696,1701,1705,1710,1715,1720,1725,1730,1735,1740,1745,1750,1755,1760,1765,1770,1774,1779,1784,1789,1794],{"id":5,"title":6,"titles":7,"content":8,"level":9},"/v1.0.1/overview","Overview",[],"Schema-driven pipeline factory for pipz with hot-reloading capabilities",1,{"id":11,"title":6,"titles":12,"content":13,"level":9},"/v1.0.1/overview#overview",[],"Building data pipelines in Go typically means hardcoding structure at compile time. Change the flow? Rebuild and redeploy. Flume offers a different approach: define pipeline structure in configuration, update it at runtime. factory := flume.New[Order]()\n\n// Register reusable components\nfactory.Add(pipz.Apply(\"validate\", validateOrder))\nfactory.Add(pipz.Transform(\"enrich\", enrichOrder))\nfactory.AddPredicate(flume.Predicate[Order]{\n    Name:      \"high-value\",\n    Predicate: func(ctx context.Context, o Order) bool { return o.Total > 1000 },\n})\n\n// Build from schema\npipeline, _ := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: high-value\n    then:\n      ref: enrich\n`)\n\n// Update at runtime - no restart required\nfactory.SetSchema(\"orders\", newSchema) Type-safe, hot-reloadable, zero external dependencies.",{"id":15,"title":16,"titles":17,"content":18,"level":19},"/v1.0.1/overview#architecture","Architecture",[6],"┌──────────────────────────────────────────────────────────────┐\n│                         Factory[T]                           │\n│                                                              │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │\n│  │ Processors  │  │ Predicates  │  │ Conditions  │          │\n│  │ (Chainable) │  │  (bool fn)  │  │ (string fn) │          │\n│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │\n│         │                │                │                  │\n│         └────────────────┼────────────────┘                  │\n│                          ▼                                   │\n│  ┌───────────────────────────────────────────────────────┐  │\n│  │                   Schema (YAML/JSON)                  │  │\n│  │   type: sequence                                      │  │\n│  │   children:                                           │  │\n│  │     - ref: validate                                   │  │\n│  │     - type: filter ...                                │  │\n│  └───────────────────────────────────────────────────────┘  │\n│                          │                                   │\n│                    Build │ Validate                          │\n│                          ▼                                   │\n│  ┌───────────────────────────────────────────────────────┐  │\n│  │              pipz.Chainable[T] Pipeline               │  │\n│  └───────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────┘ Register components once, compose them via schemas, build executable pipelines. Schemas validate against registered components before building.",2,{"id":21,"title":22,"titles":23,"content":24,"level":19},"/v1.0.1/overview#philosophy","Philosophy",[6],"",{"id":26,"title":27,"titles":28,"content":29,"level":30},"/v1.0.1/overview#configuration-over-code","Configuration Over Code",[6,22],"Pipeline structure belongs in configuration. Business logic belongs in code. # Configuration: structure\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: process // Code: behaviour\nfactory.Add(pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n    if o.Total \u003C= 0 {\n        return o, errors.New(\"invalid total\")\n    }\n    return o, nil\n}))",3,{"id":32,"title":33,"titles":34,"content":35,"level":30},"/v1.0.1/overview#zero-magic","Zero Magic",[6,22],"Processors name themselves via pipz.NameSchemas are plain YAML/JSONValidation errors include full pathsNo reflection at runtime",{"id":37,"title":38,"titles":39,"content":40,"level":19},"/v1.0.1/overview#capabilities","Capabilities",[6],"Schema-driven pipelines open possibilities: Hot Reloading - Update pipeline behaviour without restarts. A/B test processing logic, toggle features, respond to changing requirements. Multi-tenant Processing - Different schemas per tenant. Same registered components, different compositions based on customer tier or configuration. Channel Integration - Route pipeline outputs to Go channels. Fan-out to multiple streams, integrate with async consumers. Resilience Patterns - Retry, timeout, circuit breaker, rate limiting - all declarative in schema. Change resilience strategy without code changes. Flume provides the composition layer. What pipelines you build is up to you.",{"id":42,"title":43,"titles":44,"content":24,"level":19},"/v1.0.1/overview#priorities","Priorities",[6],{"id":46,"title":47,"titles":48,"content":49,"level":30},"/v1.0.1/overview#type-safety","Type Safety",[6,43],"Full generics from factory to pipeline. The type flows through: factory := flume.New[Order]()      // Factory[Order]\nfactory.Add(orderProcessor)         // Only accepts Chainable[Order]\npipeline, _ := factory.Build(schema)\nresult, _ := pipeline.Process(ctx, order) // Returns (Order, error)",{"id":51,"title":52,"titles":53,"content":54,"level":30},"/v1.0.1/overview#validation","Validation",[6,43],"Schemas validate before building. Missing references, invalid configurations, structural errors - caught early with clear messages: 3 validation errors:\n  1. root.children[0]: processor 'missing' not found\n  2. root.children[1]: predicate 'unknown' not found\n  3. root.children[2].timeout: invalid duration \"bad\"",{"id":56,"title":57,"titles":58,"content":59,"level":30},"/v1.0.1/overview#performance","Performance",[6,43],"Built pipelines execute with zero overhead - the result is a pipz pipeline. Cost is only at build time: OperationTimePipeline execution (3-step sequence)~459 nsSchema build (10-step sequence)~6.7 µs Build once, execute many times.",{"id":61,"title":62,"titles":63,"content":24,"level":19},"/v1.0.1/overview#documentation","Documentation",[6],{"id":65,"title":66,"titles":67,"content":68,"level":30},"/v1.0.1/overview#learn","Learn",[6,62],"Quickstart - Your first pipeline in 5 minutesCore Concepts - Factories, schemas, and componentsArchitecture - How Flume works under the hoodBuilding Pipelines - From simple to complex",{"id":70,"title":71,"titles":72,"content":73,"level":30},"/v1.0.1/overview#guides","Guides",[6,62],"Schema Design - Best practices for schema structureHot Reloading - Update pipelines without restartsError Handling - Retry, fallback, circuit breakersTesting - Testing schema-driven pipelinesObservability - Monitoring with capitan events",{"id":75,"title":76,"titles":77,"content":78,"level":30},"/v1.0.1/overview#reference","Reference",[6,62],"API Reference - Factory methods and typesSchema Format - YAML/JSON specificationConnector Types - All 14 connectorsEvents - Observability signals html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}",{"id":80,"title":81,"titles":82,"content":83,"level":9},"/v1.0.1/learn/quickstart","Quickstart",[],"Build your first Flume pipeline in 5 minutes",{"id":85,"title":81,"titles":86,"content":87,"level":9},"/v1.0.1/learn/quickstart#quickstart",[],"Build your first schema-driven pipeline in 5 minutes.",{"id":89,"title":90,"titles":91,"content":92,"level":19},"/v1.0.1/learn/quickstart#installation","Installation",[81],"go get github.com/zoobz-io/flume",{"id":94,"title":95,"titles":96,"content":97,"level":19},"/v1.0.1/learn/quickstart#step-1-define-your-data-type","Step 1: Define Your Data Type",[81],"Your data type must implement pipz.Cloner[T]: package main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/zoobz-io/flume\"\n    \"github.com/zoobz-io/pipz\"\n)\n\ntype Order struct {\n    ID       string\n    Customer string\n    Total    float64\n    Status   string\n}\n\nfunc (o Order) Clone() Order {\n    return Order{\n        ID:       o.ID,\n        Customer: o.Customer,\n        Total:    o.Total,\n        Status:   o.Status,\n    }\n}",{"id":99,"title":100,"titles":101,"content":102,"level":19},"/v1.0.1/learn/quickstart#step-2-create-a-factory","Step 2: Create a Factory",[81],"func main() {\n    factory := flume.New[Order]()\n}",{"id":104,"title":105,"titles":106,"content":107,"level":19},"/v1.0.1/learn/quickstart#step-3-register-processors","Step 3: Register Processors",[81],"// Validate order\n    factory.Add(pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n        if o.Total \u003C= 0 {\n            return o, fmt.Errorf(\"invalid total: %f\", o.Total)\n        }\n        return o, nil\n    }))\n\n    // Enrich with status\n    factory.Add(pipz.Transform(\"enrich\", func(ctx context.Context, o Order) Order {\n        o.Status = \"validated\"\n        return o\n    }))\n\n    // Log order\n    factory.Add(pipz.Effect(\"log\", func(ctx context.Context, o Order) error {\n        fmt.Printf(\"Processing order: %s for %s ($%.2f)\\n\", o.ID, o.Customer, o.Total)\n        return nil\n    }))",{"id":109,"title":110,"titles":111,"content":112,"level":19},"/v1.0.1/learn/quickstart#step-4-define-schema","Step 4: Define Schema",[81],"schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n  - ref: log\n`",{"id":114,"title":115,"titles":116,"content":117,"level":19},"/v1.0.1/learn/quickstart#step-5-build-and-use","Step 5: Build and Use",[81],"pipeline, err := factory.BuildFromYAML(schema)\n    if err != nil {\n        panic(err)\n    }\n\n    order := Order{\n        ID:       \"ORD-001\",\n        Customer: \"Alice\",\n        Total:    99.99,\n    }\n\n    result, err := pipeline.Process(context.Background(), order)\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Printf(\"Result: %+v\\n\", result)\n}",{"id":119,"title":120,"titles":121,"content":122,"level":19},"/v1.0.1/learn/quickstart#complete-example","Complete Example",[81],"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/zoobz-io/flume\"\n    \"github.com/zoobz-io/pipz\"\n)\n\ntype Order struct {\n    ID       string\n    Customer string\n    Total    float64\n    Status   string\n}\n\nfunc (o Order) Clone() Order {\n    return Order{ID: o.ID, Customer: o.Customer, Total: o.Total, Status: o.Status}\n}\n\nfunc main() {\n    factory := flume.New[Order]()\n\n    // Register processors\n    factory.Add(\n        pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n            if o.Total \u003C= 0 {\n                return o, fmt.Errorf(\"invalid total: %f\", o.Total)\n            }\n            return o, nil\n        }),\n        pipz.Transform(\"enrich\", func(ctx context.Context, o Order) Order {\n            o.Status = \"validated\"\n            return o\n        }),\n        pipz.Effect(\"log\", func(ctx context.Context, o Order) error {\n            fmt.Printf(\"Order: %s ($%.2f)\\n\", o.ID, o.Total)\n            return nil\n        }),\n    )\n\n    // Define and build pipeline\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n  - ref: log\n`\n\n    pipeline, err := factory.BuildFromYAML(schema)\n    if err != nil {\n        panic(err)\n    }\n\n    // Process\n    result, err := pipeline.Process(context.Background(), Order{\n        ID:       \"ORD-001\",\n        Customer: \"Alice\",\n        Total:    99.99,\n    })\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Printf(\"Final: %+v\\n\", result)\n} Output: Order: ORD-001 ($99.99)\nFinal: {ID:ORD-001 Customer:Alice Total:99.99 Status:validated}",{"id":124,"title":125,"titles":126,"content":127,"level":19},"/v1.0.1/learn/quickstart#adding-conditional-logic","Adding Conditional Logic",[81],"Add a predicate for conditional processing: factory.AddPredicate(flume.Predicate[Order]{\n        Name: \"high-value\",\n        Predicate: func(ctx context.Context, o Order) bool {\n            return o.Total > 100\n        },\n    })\n\n    factory.Add(pipz.Effect(\"premium-notify\", func(ctx context.Context, o Order) error {\n        fmt.Println(\"High-value order detected!\")\n        return nil\n    }))\n\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: high-value\n    then:\n      ref: premium-notify\n  - ref: log\n`",{"id":129,"title":130,"titles":131,"content":132,"level":19},"/v1.0.1/learn/quickstart#adding-error-handling","Adding Error Handling",[81],"Wrap processors with retry: schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: retry\n    attempts: 3\n    child:\n      ref: external-api-call\n  - ref: log\n`",{"id":134,"title":135,"titles":136,"content":137,"level":19},"/v1.0.1/learn/quickstart#merging-concurrent-results","Merging Concurrent Results",[81],"When running processors concurrently, use a reducer to merge results: // Register parallel enrichment processors\n    factory.Add(\n        pipz.Transform(\"fetch-customer\", func(ctx context.Context, o Order) Order {\n            o.Customer = \"Alice (Premium)\"\n            return o\n        }),\n        pipz.Transform(\"fetch-inventory\", func(ctx context.Context, o Order) Order {\n            o.Status = \"in-stock\"\n            return o\n        }),\n    )\n\n    // Register a reducer to merge results\n    factory.AddReducer(flume.Reducer[Order]{\n        Name: \"merge-enrichments\",\n        Reducer: func(original Order, results map[pipz.Name]Order, errors map[pipz.Name]error) Order {\n            for _, result := range results {\n                if result.Customer != \"\" {\n                    original.Customer = result.Customer\n                }\n                if result.Status != \"\" {\n                    original.Status = result.Status\n                }\n            }\n            return original\n        },\n    })\n\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: concurrent\n    reducer: merge-enrichments\n    children:\n      - ref: fetch-customer\n      - ref: fetch-inventory\n  - ref: log\n`",{"id":139,"title":140,"titles":141,"content":142,"level":19},"/v1.0.1/learn/quickstart#loading-from-files","Loading from Files",[81],"pipeline, err := factory.BuildFromFile(\"pipeline.yaml\")",{"id":144,"title":145,"titles":146,"content":147,"level":19},"/v1.0.1/learn/quickstart#using-named-schemas","Using Named Schemas",[81],"For hot-reloading support: // Register named schema\n    err := factory.SetSchema(\"order-processing\", schema)\n    if err != nil {\n        panic(err)\n    }\n\n    // Create binding with auto-sync\n    pipelineID := factory.Identity(\"order-processor\", \"Processes orders\")\n    binding, err := factory.Bind(pipelineID, \"order-processing\", flume.WithAutoSync())\n    if err != nil {\n        panic(err)\n    }\n\n    // Process requests\n    result, err := binding.Process(ctx, order)\n\n    // Update schema at runtime - binding rebuilds automatically\n    newSchema := Schema{...}\n    factory.SetSchema(\"order-processing\", newSchema)",{"id":149,"title":150,"titles":151,"content":152,"level":19},"/v1.0.1/learn/quickstart#next-steps","Next Steps",[81],"Building Pipelines - Complex schema patternsCore Concepts - Deeper understandingSchema Format - Complete reference html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .suWN2, html code.shiki .suWN2{--shiki-default:var(--shiki-tag)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}",{"id":154,"title":155,"titles":156,"content":157,"level":9},"/v1.0.1/learn/core-concepts","Core Concepts",[],"Understanding Flume's fundamental building blocks - factories, schemas, and components",{"id":159,"title":155,"titles":160,"content":161,"level":9},"/v1.0.1/learn/core-concepts#core-concepts",[],"Flume is built around three core concepts: the Factory, Schemas, and Components.",{"id":163,"title":164,"titles":165,"content":166,"level":19},"/v1.0.1/learn/core-concepts#the-factory","The Factory",[155],"The factory is Flume's central registry. It holds all registered components and builds pipelines from schemas. factory := flume.New[Order]() The factory is generic over your data type T. This type must implement pipz.Cloner[T] to support parallel processing: type Order struct {\n    ID    string\n    Total float64\n}\n\nfunc (o Order) Clone() Order {\n    return Order{ID: o.ID, Total: o.Total}\n}",{"id":168,"title":169,"titles":170,"content":171,"level":30},"/v1.0.1/learn/core-concepts#factory-responsibilities","Factory Responsibilities",[155,164],"Component Registry - Store processors, predicates, and conditionsSchema Storage - Manage named schemas with hot-reload supportPipeline Building - Construct pipz pipelines from schemasValidation - Verify schemas before building",{"id":173,"title":174,"titles":175,"content":176,"level":19},"/v1.0.1/learn/core-concepts#components","Components",[155],"Components are the building blocks registered with the factory. There are three types:",{"id":178,"title":179,"titles":180,"content":181,"level":30},"/v1.0.1/learn/core-concepts#processors","Processors",[155,174],"Processors are pipz Chainable[T] implementations - the actual processing logic: // Using pipz constructors\nfactory.Add(\n    pipz.Apply(\"validate\", validateOrder),      // T -> (T, error)\n    pipz.Transform(\"normalize\", normalizeOrder), // T -> T\n    pipz.Effect(\"log\", logOrder),               // T -> error (no modification)\n) Reference in schemas: ref: validate",{"id":183,"title":184,"titles":185,"content":186,"level":30},"/v1.0.1/learn/core-concepts#predicates","Predicates",[155,174],"Predicates are boolean functions for conditional processing: factory.AddPredicate(flume.Predicate[Order]{\n    Name:        \"is-premium\",\n    Description: \"Checks if customer has premium tier\",\n    Predicate: func(ctx context.Context, o Order) bool {\n        return o.CustomerTier == \"premium\"\n    },\n}) Used in filter nodes: type: filter\npredicate: is-premium\nthen:\n  ref: premium-handler",{"id":188,"title":189,"titles":190,"content":191,"level":30},"/v1.0.1/learn/core-concepts#conditions","Conditions",[155,174],"Conditions return strings for multi-way routing: factory.AddCondition(flume.Condition[Order]{\n    Name:        \"order-status\",\n    Description: \"Returns the current order status\",\n    Values:      []string{\"pending\", \"approved\", \"rejected\"},\n    Condition: func(ctx context.Context, o Order) string {\n        return o.Status\n    },\n}) Used in switch nodes: type: switch\ncondition: order-status\nroutes:\n  pending:\n    ref: handle-pending\n  approved:\n    ref: handle-approved\ndefault:\n  ref: handle-unknown",{"id":193,"title":194,"titles":195,"content":196,"level":19},"/v1.0.1/learn/core-concepts#schemas","Schemas",[155],"Schemas define pipeline structure as YAML or JSON documents.",{"id":198,"title":199,"titles":200,"content":201,"level":30},"/v1.0.1/learn/core-concepts#schema-structure","Schema Structure",[155,194],"version: \"1.0.0\"    # Optional version tracking\ntype: sequence      # Connector type\nname: my-pipeline   # Optional name override\nchildren:           # Child nodes\n  - ref: step1\n  - ref: step2",{"id":203,"title":204,"titles":205,"content":206,"level":30},"/v1.0.1/learn/core-concepts#node-types","Node Types",[155,194],"Nodes are either references or connectors: # Reference: points to registered processor\nref: validate\n\n# Connector: defines structure\ntype: sequence\nchildren:\n  - ref: step1\n  - ref: step2",{"id":208,"title":209,"titles":210,"content":211,"level":30},"/v1.0.1/learn/core-concepts#building-pipelines","Building Pipelines",[155,194],"Build from strings or files: // From YAML string\npipeline, err := factory.BuildFromYAML(yamlStr)\n\n// From JSON string\npipeline, err := factory.BuildFromJSON(jsonStr)\n\n// From file (auto-detects format)\npipeline, err := factory.BuildFromFile(\"pipeline.yaml\")\n\n// From Schema struct\npipeline, err := factory.Build(schema)",{"id":213,"title":214,"titles":215,"content":216,"level":19},"/v1.0.1/learn/core-concepts#dynamic-schema-management","Dynamic Schema Management",[155],"Flume supports named schemas that can be updated at runtime: // Register a named schema\nerr := factory.SetSchema(\"order-pipeline\", schema)\n\n// Create a binding with auto-sync enabled\npipelineID := factory.Identity(\"order-processor\", \"Processes orders\")\nbinding, err := factory.Bind(pipelineID, \"order-pipeline\", flume.WithAutoSync())\n\n// Process requests (lock-free)\nresult, err := binding.Process(ctx, order)\n\n// Update the schema - auto-sync bindings rebuild automatically\nerr = factory.SetSchema(\"order-pipeline\", newSchema)\n\n// Remove a schema\nremoved := factory.RemoveSchema(\"order-pipeline\")\n\n// List all schemas\nnames := factory.ListSchemas()",{"id":218,"title":219,"titles":220,"content":221,"level":30},"/v1.0.1/learn/core-concepts#hot-reloading","Hot Reloading",[155,214],"When you update a schema: New pipeline is built and validatedAll auto-sync bindings rebuild atomicallyIn-flight requests complete with old pipelineNew requests use updated pipeline // Watcher pattern\nfor schemaChange := range watcher.Changes() {\n    if err := factory.SetSchema(schemaChange.Name, schemaChange.Schema); err != nil {\n        log.Printf(\"failed to update schema: %v\", err)\n        continue\n    }\n    log.Printf(\"schema %s updated to version %s\",\n        schemaChange.Name, schemaChange.Schema.Version)\n}",{"id":223,"title":52,"titles":224,"content":225,"level":19},"/v1.0.1/learn/core-concepts#validation",[155],"Flume validates schemas before building, catching errors early: err := factory.ValidateSchema(schema)\nif err != nil {\n    // ValidationErrors with detailed paths\n    fmt.Println(err)\n    // Output:\n    // 3 validation errors:\n    //   1. root.children[0]: processor 'missing' not found\n    //   2. root.children[1]: predicate 'unknown' not found\n    //   3. root.children[1].then: processor 'also-missing' not found\n}",{"id":227,"title":228,"titles":229,"content":230,"level":30},"/v1.0.1/learn/core-concepts#what-gets-validated","What Gets Validated",[155,52],"All processor/predicate/condition references existRequired fields are presentConnector constraints are met (e.g., fallback needs 2 children)Configuration values are valid (e.g., positive retry attempts)Duration strings are parseableNo circular references",{"id":232,"title":233,"titles":234,"content":235,"level":19},"/v1.0.1/learn/core-concepts#component-introspection","Component Introspection",[155],"Query the factory's registrations: // Check existence\nfactory.HasProcessor(\"validate\")\nfactory.HasPredicate(\"is-premium\")\nfactory.HasCondition(\"order-status\")\n\n// List all\nprocessors := factory.ListProcessors()  // []pipz.Name\npredicates := factory.ListPredicates()\nconditions := factory.ListConditions()",{"id":237,"title":238,"titles":239,"content":240,"level":19},"/v1.0.1/learn/core-concepts#component-removal","Component Removal",[155],"Remove components when no longer needed: // Remove processors (returns count removed)\nremoved := factory.Remove(\"old-processor\", \"deprecated\")\n\n// Remove predicates\nfactory.RemovePredicate(\"old-predicate\")\n\n// Remove conditions\nfactory.RemoveCondition(\"old-condition\") Note: Removing a component doesn't affect already-built pipelines, but will cause validation errors if you try to build schemas that reference them.",{"id":242,"title":150,"titles":243,"content":244,"level":19},"/v1.0.1/learn/core-concepts#next-steps",[155],"Architecture - How Flume works under the hoodQuickstart - Build your first pipelineAPI Reference - Complete method documentation html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}",{"id":246,"title":16,"titles":247,"content":248,"level":9},"/v1.0.1/learn/architecture",[],"How Flume works under the hood - from schema to pipeline",{"id":250,"title":16,"titles":251,"content":252,"level":9},"/v1.0.1/learn/architecture#architecture",[],"Understanding Flume's internal architecture helps you use it effectively and debug issues.",{"id":254,"title":6,"titles":255,"content":256,"level":19},"/v1.0.1/learn/architecture#overview",[16],"┌─────────────────────────────────────────────────────────────┐\n│                         Factory[T]                          │\n├─────────────────────────────────────────────────────────────┤\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │\n│  │ Processors  │  │ Predicates  │  │ Conditions  │         │\n│  │  map[Name]  │  │  map[Name]  │  │  map[Name]  │         │\n│  └─────────────┘  └─────────────┘  └─────────────┘         │\n│                                                             │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │\n│  │  Schemas    │  │  Pipelines  │  │  Channels   │         │\n│  │ map[string] │  │ atomic.Ptr  │  │ map[string] │         │\n│  └─────────────┘  └─────────────┘  └─────────────┘         │\n└─────────────────────────────────────────────────────────────┘\n                           │\n                           ▼\n              ┌────────────────────────┐\n              │    Schema Document     │\n              │  (YAML/JSON/Struct)    │\n              └────────────────────────┘\n                           │\n            ┌──────────────┼──────────────┐\n            ▼              ▼              ▼\n      ┌──────────┐  ┌──────────┐  ┌──────────┐\n      │  Parse   │  │ Validate │  │  Build   │\n      └──────────┘  └──────────┘  └──────────┘\n                           │\n                           ▼\n              ┌────────────────────────┐\n              │   pipz.Chainable[T]    │\n              │    (ready to use)      │\n              └────────────────────────┘",{"id":258,"title":259,"titles":260,"content":261,"level":19},"/v1.0.1/learn/architecture#factory-structure","Factory Structure",[16],"The factory maintains six internal maps protected by a read-write mutex: type Factory[T pipz.Cloner[T]] struct {\n    processors map[pipz.Name]processorMeta[T]\n    predicates map[pipz.Name]predicateMeta[T]\n    conditions map[pipz.Name]conditionMeta[T]\n    schemas    map[string]*Schema\n    pipelines  map[string]*atomic.Pointer[pipz.Chainable[T]]\n    channels   map[string]chan\u003C- T\n    mu         sync.RWMutex\n}",{"id":263,"title":264,"titles":265,"content":266,"level":30},"/v1.0.1/learn/architecture#thread-safety","Thread Safety",[16,259],"Read operations (lookups, list, build) acquire read locksWrite operations (add, remove, set schema) acquire write locksPipeline access uses atomic pointers for lock-free retrieval",{"id":268,"title":269,"titles":270,"content":24,"level":19},"/v1.0.1/learn/architecture#schema-processing-pipeline","Schema Processing Pipeline",[16],{"id":272,"title":273,"titles":274,"content":275,"level":30},"/v1.0.1/learn/architecture#_1-parsing","1. Parsing",[16,269],"Schemas can be loaded from multiple sources: // String parsing\nfactory.BuildFromYAML(yamlStr)\nfactory.BuildFromJSON(jsonStr)\n\n// File loading (detects format from extension)\nfactory.BuildFromFile(\"pipeline.yaml\")\n\n// Direct struct\nfactory.Build(schema) The parser converts YAML/JSON into the Schema struct: type Schema struct {\n    Version string\n    Node    // embedded\n}\n\ntype Node struct {\n    Ref       string\n    Type      string\n    Name      string\n    Children  []Node\n    Child     *Node\n    // ... connector-specific fields\n}",{"id":277,"title":278,"titles":279,"content":280,"level":30},"/v1.0.1/learn/architecture#_2-validation","2. Validation",[16,269],"Before building, the factory validates the entire schema tree: func (f *Factory[T]) ValidateSchema(schema Schema) error {\n    var errors ValidationErrors\n    f.validateNode(&schema.Node, []string{\"root\"}, &errors)\n    if len(errors) > 0 {\n        return errors\n    }\n    return nil\n} Validation traverses the tree recursively, checking: References exist - All ref: values point to registered processorsPredicates exist - All predicate: values are registeredConditions exist - All condition: values are registeredRequired fields - Each node type has its required fieldsConstraints - Type-specific rules (e.g., fallback needs exactly 2 children)No cycles - Reference chains don't loop back",{"id":282,"title":283,"titles":284,"content":285,"level":30},"/v1.0.1/learn/architecture#_3-building","3. Building",[16,269],"The builder recursively constructs pipz chainables: func (f *Factory[T]) buildNode(node *Node) (pipz.Chainable[T], error) {\n    // Handle processor reference\n    if node.Ref != \"\" {\n        return f.processors[pipz.Name(node.Ref)].processor, nil\n    }\n\n    // Handle connector types\n    switch node.Type {\n    case \"sequence\":\n        return f.buildSequence(node)\n    case \"concurrent\":\n        return f.buildConcurrent(node)\n    // ... other types\n    }\n} Each connector type has a dedicated builder that: Validates connector-specific requirementsRecursively builds child nodesConstructs the pipz connector with appropriate options",{"id":287,"title":288,"titles":289,"content":290,"level":19},"/v1.0.1/learn/architecture#connector-mapping","Connector Mapping",[16],"Flume schema types map directly to pipz constructors: Schema Typepipz Constructorsequencepipz.NewSequenceconcurrentpipz.NewConcurrentracepipz.NewRacefallbackpipz.NewFallbackretrypipz.NewRetry or pipz.NewBackofftimeoutpipz.NewTimeoutfilterpipz.NewFilter or custom routingswitchpipz.NewSwitchcircuit-breakerpipz.NewCircuitBreakerrate-limitpipz.NewRateLimiter + pipz.NewSequence",{"id":292,"title":293,"titles":294,"content":295,"level":19},"/v1.0.1/learn/architecture#hot-reload-mechanism","Hot Reload Mechanism",[16],"Named schemas support atomic updates: func (f *Factory[T]) SetSchema(name string, schema Schema) error {\n    // 1. Validate first\n    if err := f.ValidateSchema(schema); err != nil {\n        return err\n    }\n\n    // 2. Build pipeline\n    pipeline, err := f.Build(schema)\n    if err != nil {\n        return err\n    }\n\n    // 3. Atomic update\n    f.mu.Lock()\n    defer f.mu.Unlock()\n\n    f.schemas[name] = &schema\n    if ptr, exists := f.pipelines[name]; exists {\n        ptr.Store(&pipeline)  // Atomic swap\n    } else {\n        ptr := &atomic.Pointer[pipz.Chainable[T]]{}\n        ptr.Store(&pipeline)\n        f.pipelines[name] = ptr\n    }\n    return nil\n} Retrieval is lock-free after the initial lookup: func (f *Factory[T]) Pipeline(name string) (pipz.Chainable[T], bool) {\n    f.mu.RLock()\n    ptr := f.pipelines[name]\n    f.mu.RUnlock()\n\n    if ptr == nil {\n        return nil, false\n    }\n    return *ptr.Load(), true  // Atomic load\n}",{"id":297,"title":298,"titles":299,"content":300,"level":19},"/v1.0.1/learn/architecture#observability-integration","Observability Integration",[16],"Flume emits Capitan events throughout its lifecycle: // Factory events\nFactoryCreated\nProcessorRegistered\nPredicateRegistered\nConditionRegistered\n\n// Schema events\nSchemaValidationStarted\nSchemaValidationCompleted\nSchemaValidationFailed\nSchemaBuildStarted\nSchemaBuildCompleted\nSchemaBuildFailed\n\n// Dynamic schema events\nSchemaRegistered\nSchemaUpdated\nSchemaRemoved\nPipelineRetrieved Events include typed fields: capitan.Emit(ctx, SchemaRegistered,\n    KeyName.Field(name),\n    KeyVersion.Field(schema.Version))",{"id":302,"title":303,"titles":304,"content":305,"level":19},"/v1.0.1/learn/architecture#channel-integration","Channel Integration",[16],"Channels enable stream processing patterns: factory.AddChannel(\"output\", outputChan) Stream nodes wrap channels in pipz effects: func (f *Factory[T]) buildStream(node *Node) (pipz.Chainable[T], error) {\n    channel := f.channels[node.Stream]\n\n    return pipz.Effect(\n        pipz.Name(fmt.Sprintf(\"stream:%s\", node.Stream)),\n        func(_ context.Context, item T) error {\n            channel \u003C- item\n            return nil\n        },\n    ), nil\n}",{"id":307,"title":308,"titles":309,"content":24,"level":19},"/v1.0.1/learn/architecture#memory-model","Memory Model",[16],{"id":311,"title":312,"titles":313,"content":314,"level":30},"/v1.0.1/learn/architecture#component-storage","Component Storage",[16,308],"Components are stored by value in maps: type processorMeta[T any] struct {\n    processor   pipz.Chainable[T]  // Interface value\n    description string\n    tags        []string\n}",{"id":316,"title":317,"titles":318,"content":319,"level":30},"/v1.0.1/learn/architecture#pipeline-lifecycle","Pipeline Lifecycle",[16,308],"Registration - Components stored in factory mapsBuild - New pipeline created from current registrationsStorage - Pipeline stored via atomic pointer (for named schemas)Usage - Pipeline used directly, no factory reference neededUpdate - New pipeline built, pointer atomically swappedRemoval - Schema removed, pipeline garbage collected when unreferenced",{"id":321,"title":322,"titles":323,"content":324,"level":30},"/v1.0.1/learn/architecture#concurrency","Concurrency",[16,308],"Multiple goroutines can safely call Pipeline() concurrentlyBuild operations are serialized through the write lockBuilt pipelines are independent of the factory",{"id":326,"title":150,"titles":327,"content":328,"level":19},"/v1.0.1/learn/architecture#next-steps",[16],"Quickstart - Build your first pipelineSchema Design - Best practicesEvents Reference - All observability signals html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}",{"id":330,"title":209,"titles":331,"content":332,"level":9},"/v1.0.1/learn/building-pipelines",[],"From simple sequences to complex nested pipelines",{"id":334,"title":209,"titles":335,"content":336,"level":9},"/v1.0.1/learn/building-pipelines#building-pipelines",[],"Learn to construct increasingly sophisticated pipelines with Flume schemas.",{"id":338,"title":339,"titles":340,"content":341,"level":19},"/v1.0.1/learn/building-pipelines#simple-sequences","Simple Sequences",[209],"The most basic pipeline chains processors sequentially: type: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n  - ref: save Each processor receives the output of the previous one.",{"id":343,"title":344,"titles":345,"content":346,"level":19},"/v1.0.1/learn/building-pipelines#parallel-execution","Parallel Execution",[209],"Process data concurrently with the concurrent type: type: sequence\nchildren:\n  - ref: validate\n  - type: concurrent\n    children:\n      - ref: enrich-from-db\n      - ref: enrich-from-api\n      - ref: calculate-score\n  - ref: save All concurrent children receive cloned data and execute in parallel. Results are merged.",{"id":348,"title":349,"titles":350,"content":24,"level":19},"/v1.0.1/learn/building-pipelines#conditional-processing","Conditional Processing",[209],{"id":352,"title":353,"titles":354,"content":355,"level":30},"/v1.0.1/learn/building-pipelines#filter","Filter",[209,349],"Execute a branch only when a condition is met: type: filter\npredicate: is-premium\nthen:\n  ref: apply-discount With else branch: type: filter\npredicate: is-premium\nthen:\n  ref: premium-handler\nelse:\n  ref: standard-handler",{"id":357,"title":358,"titles":359,"content":360,"level":30},"/v1.0.1/learn/building-pipelines#switch","Switch",[209,349],"Route to different handlers based on a condition value: type: switch\ncondition: order-type\nroutes:\n  subscription:\n    ref: handle-subscription\n  one-time:\n    ref: handle-single-purchase\n  gift:\n    type: sequence\n    children:\n      - ref: validate-gift\n      - ref: handle-gift\ndefault:\n  ref: handle-unknown Register the condition: factory.AddCondition(flume.Condition[Order]{\n    Name: \"order-type\",\n    Condition: func(ctx context.Context, o Order) string {\n        return o.Type // \"subscription\", \"one-time\", \"gift\", etc.\n    },\n})",{"id":362,"title":363,"titles":364,"content":24,"level":19},"/v1.0.1/learn/building-pipelines#error-handling","Error Handling",[209],{"id":366,"title":367,"titles":368,"content":369,"level":30},"/v1.0.1/learn/building-pipelines#retry","Retry",[209,363],"Retry failed operations: type: retry\nattempts: 3\nchild:\n  ref: flaky-api With exponential backoff: type: retry\nattempts: 5\nbackoff: \"100ms\"\nchild:\n  ref: external-service",{"id":371,"title":372,"titles":373,"content":374,"level":30},"/v1.0.1/learn/building-pipelines#fallback","Fallback",[209,363],"Use a backup handler on failure: type: fallback\nchildren:\n  - ref: primary-service\n  - ref: backup-service",{"id":376,"title":377,"titles":378,"content":379,"level":30},"/v1.0.1/learn/building-pipelines#timeout","Timeout",[209,363],"Enforce time limits: type: timeout\nduration: \"5s\"\nchild:\n  ref: slow-operation",{"id":381,"title":382,"titles":383,"content":384,"level":30},"/v1.0.1/learn/building-pipelines#circuit-breaker","Circuit Breaker",[209,363],"Prevent cascading failures: type: circuit-breaker\nfailure_threshold: 5\nrecovery_timeout: \"30s\"\nchild:\n  ref: unreliable-service",{"id":386,"title":387,"titles":388,"content":389,"level":30},"/v1.0.1/learn/building-pipelines#rate-limiting","Rate Limiting",[209,363],"Control throughput: type: rate-limit\nrequests_per_second: 100.0\nburst_size: 10\nchild:\n  ref: rate-sensitive-api",{"id":391,"title":392,"titles":393,"content":24,"level":19},"/v1.0.1/learn/building-pipelines#nesting-patterns","Nesting Patterns",[209],{"id":395,"title":396,"titles":397,"content":398,"level":30},"/v1.0.1/learn/building-pipelines#resilient-external-calls","Resilient External Calls",[209,392],"type: circuit-breaker\nfailure_threshold: 3\nrecovery_timeout: \"60s\"\nchild:\n  type: timeout\n  duration: \"10s\"\n  child:\n    type: retry\n    attempts: 3\n    backoff: \"200ms\"\n    child:\n      ref: external-api",{"id":400,"title":401,"titles":402,"content":403,"level":30},"/v1.0.1/learn/building-pipelines#conditional-with-fallback","Conditional with Fallback",[209,392],"type: filter\npredicate: has-cache\nthen:\n  type: fallback\n  children:\n    - ref: get-from-cache\n    - ref: get-from-db\nelse:\n  ref: get-from-db",{"id":405,"title":406,"titles":407,"content":408,"level":30},"/v1.0.1/learn/building-pipelines#parallel-with-error-handling","Parallel with Error Handling",[209,392],"type: concurrent\nchildren:\n  - type: retry\n    attempts: 2\n    child:\n      ref: service-a\n  - type: fallback\n    children:\n      - ref: service-b-primary\n      - ref: service-b-backup\n  - ref: service-c",{"id":410,"title":120,"titles":411,"content":412,"level":19},"/v1.0.1/learn/building-pipelines#complete-example",[209],"An order processing pipeline: version: \"2.0.0\"\ntype: sequence\nname: order-processing\nchildren:\n  # Step 1: Validate\n  - ref: validate-order\n\n  # Step 2: Parallel enrichment\n  - type: concurrent\n    name: enrich\n    children:\n      - ref: fetch-customer\n      - ref: fetch-inventory\n      - ref: calculate-tax\n\n  # Step 3: Premium handling\n  - type: filter\n    predicate: is-premium-customer\n    then:\n      type: sequence\n      children:\n        - ref: apply-loyalty-discount\n        - ref: priority-queue\n\n  # Step 4: Payment routing\n  - type: switch\n    condition: payment-method\n    routes:\n      credit:\n        type: circuit-breaker\n        failure_threshold: 3\n        recovery_timeout: \"60s\"\n        child:\n          type: retry\n          attempts: 3\n          backoff: \"500ms\"\n          child:\n            ref: charge-credit-card\n      paypal:\n        type: timeout\n        duration: \"30s\"\n        child:\n          ref: paypal-checkout\n      crypto:\n        ref: crypto-payment\n    default:\n      ref: manual-payment-review\n\n  # Step 5: Post-payment\n  - type: concurrent\n    children:\n      - ref: update-inventory\n      - ref: send-confirmation\n      - type: filter\n        predicate: requires-shipping\n        then:\n          ref: create-shipment\n\n  # Step 6: Finalize\n  - ref: complete-order Registrations: // Processors\nfactory.Add(\n    pipz.Apply(\"validate-order\", validateOrder),\n    pipz.Apply(\"fetch-customer\", fetchCustomer),\n    pipz.Apply(\"fetch-inventory\", fetchInventory),\n    // ... more processors\n)\n\n// Predicates\nfactory.AddPredicate(\n    flume.Predicate[Order]{Name: \"is-premium-customer\", Predicate: isPremium},\n    flume.Predicate[Order]{Name: \"requires-shipping\", Predicate: needsShipping},\n)\n\n// Conditions\nfactory.AddCondition(flume.Condition[Order]{\n    Name:   \"payment-method\",\n    Values: []string{\"credit\", \"paypal\", \"crypto\"},\n    Condition: func(ctx context.Context, o Order) string {\n        return o.PaymentMethod\n    },\n})",{"id":414,"title":415,"titles":416,"content":24,"level":19},"/v1.0.1/learn/building-pipelines#schema-design-tips","Schema Design Tips",[209],{"id":418,"title":419,"titles":420,"content":421,"level":30},"/v1.0.1/learn/building-pipelines#_1-name-complex-nodes","1. Name Complex Nodes",[209,415],"type: sequence\nname: payment-handling  # Helps with debugging\nchildren:\n  - ref: charge\n  - ref: confirm",{"id":423,"title":424,"titles":425,"content":426,"level":30},"/v1.0.1/learn/building-pipelines#_2-keep-depth-manageable","2. Keep Depth Manageable",[209,415],"Break deeply nested schemas into named sub-pipelines: // Register sub-pipeline\nfactory.SetSchema(\"payment-flow\", paymentSchema)",{"id":428,"title":429,"titles":430,"content":431,"level":30},"/v1.0.1/learn/building-pipelines#_3-version-your-schemas","3. Version Your Schemas",[209,415],"version: \"1.2.0\"\ntype: sequence\n# ...",{"id":433,"title":434,"titles":435,"content":436,"level":30},"/v1.0.1/learn/building-pipelines#_4-document-with-comments","4. Document with Comments",[209,415],"YAML comments aren't preserved, but you can add documentation in companion files or use the description fields when registering components: factory.AddPredicate(flume.Predicate[Order]{\n    Name:        \"high-value\",\n    Description: \"Orders over $1000 for premium handling\",\n    Predicate:   isHighValue,\n})",{"id":438,"title":150,"titles":439,"content":440,"level":19},"/v1.0.1/learn/building-pipelines#next-steps",[209],"Schema Design Guide - Best practicesError Handling Guide - Resilience patternsConnector Types Reference - All options html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":442,"title":443,"titles":444,"content":445,"level":9},"/v1.0.1/guides/schema-design","Schema Design",[],"Best practices for designing maintainable Flume schemas",{"id":447,"title":443,"titles":448,"content":449,"level":9},"/v1.0.1/guides/schema-design#schema-design",[],"Best practices for designing clear, maintainable Flume schemas.",{"id":451,"title":452,"titles":453,"content":24,"level":19},"/v1.0.1/guides/schema-design#naming-conventions","Naming Conventions",[443],{"id":455,"title":456,"titles":457,"content":458,"level":30},"/v1.0.1/guides/schema-design#processor-names","Processor Names",[443,452],"Use kebab-case with verb-noun patterns: // Good\npipz.Apply(\"validate-order\", ...)\npipz.Apply(\"fetch-customer\", ...)\npipz.Apply(\"send-notification\", ...)\n\n// Avoid\npipz.Apply(\"OrderValidation\", ...)\npipz.Apply(\"customer\", ...)\npipz.Apply(\"doStuff\", ...)",{"id":460,"title":461,"titles":462,"content":463,"level":30},"/v1.0.1/guides/schema-design#predicate-names","Predicate Names",[443,452],"Use is-/has-/can- prefixes: // Good\nflume.Predicate[T]{Name: \"is-premium\", ...}\nflume.Predicate[T]{Name: \"has-discount-code\", ...}\nflume.Predicate[T]{Name: \"can-ship-internationally\", ...}\n\n// Avoid\nflume.Predicate[T]{Name: \"premium\", ...}\nflume.Predicate[T]{Name: \"check-discount\", ...}",{"id":465,"title":466,"titles":467,"content":468,"level":30},"/v1.0.1/guides/schema-design#condition-names","Condition Names",[443,452],"Use get- prefix or descriptive nouns: // Good\nflume.Condition[T]{Name: \"get-order-type\", ...}\nflume.Condition[T]{Name: \"payment-method\", ...}\nflume.Condition[T]{Name: \"customer-tier\", ...}",{"id":470,"title":471,"titles":472,"content":473,"level":30},"/v1.0.1/guides/schema-design#schema-names","Schema Names",[443,452],"Use descriptive kebab-case: factory.SetSchema(\"order-processing\", ...)\nfactory.SetSchema(\"user-onboarding\", ...)\nfactory.SetSchema(\"payment-v2\", ...)",{"id":475,"title":476,"titles":477,"content":24,"level":19},"/v1.0.1/guides/schema-design#structure-guidelines","Structure Guidelines",[443],{"id":479,"title":480,"titles":481,"content":482,"level":30},"/v1.0.1/guides/schema-design#keep-depth-shallow","Keep Depth Shallow",[443,476],"Deeply nested schemas are hard to read and debug: # Hard to follow (5+ levels)\ntype: sequence\nchildren:\n  - type: filter\n    predicate: a\n    then:\n      type: switch\n        condition: b\n        routes:\n          x:\n            type: retry\n            child:\n              type: timeout\n                child:\n                  ref: processor Break into logical sub-schemas: # Main schema\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: resilient-external-call  # Pre-composed\n  - ref: finalize // Register composed processor\nresilientCall := pipz.NewCircuitBreaker(\"resilient\",\n    pipz.NewTimeout(\"timeout\", apiCall, 5*time.Second),\n    3, 30*time.Second,\n)\nfactory.Add(resilientCall)",{"id":484,"title":485,"titles":486,"content":487,"level":30},"/v1.0.1/guides/schema-design#group-related-operations","Group Related Operations",[443,476],"Use sequence to group related steps: type: sequence\nname: payment-processing\nchildren:\n  - ref: validate-payment\n  - ref: authorize-payment\n  - ref: capture-payment\n  - ref: record-transaction",{"id":489,"title":490,"titles":491,"content":492,"level":30},"/v1.0.1/guides/schema-design#name-complex-nodes","Name Complex Nodes",[443,476],"Add names to non-trivial nodes for debugging: type: concurrent\nname: parallel-enrichment\nchildren:\n  - ref: fetch-customer\n  - ref: fetch-inventory\n\ntype: filter\nname: premium-check\npredicate: is-premium\nthen:\n  ref: premium-handler",{"id":494,"title":495,"titles":496,"content":24,"level":19},"/v1.0.1/guides/schema-design#version-management","Version Management",[443],{"id":498,"title":499,"titles":500,"content":501,"level":30},"/v1.0.1/guides/schema-design#semantic-versioning","Semantic Versioning",[443,495],"Use semantic versioning for schemas: version: \"1.0.0\"  # Initial\nversion: \"1.1.0\"  # Added new route\nversion: \"2.0.0\"  # Breaking change to structure",{"id":503,"title":504,"titles":505,"content":506,"level":30},"/v1.0.1/guides/schema-design#version-in-schema-name","Version in Schema Name",[443,495],"For A/B testing or gradual rollouts: factory.SetSchema(\"checkout-v1\", schemaV1)\nfactory.SetSchema(\"checkout-v2\", schemaV2)\n\n// Create bindings for each variant\nbindingV1, _ := factory.Bind(v1ID, \"checkout-v1\", flume.WithAutoSync())\nbindingV2, _ := factory.Bind(v2ID, \"checkout-v2\", flume.WithAutoSync())\n\n// Route traffic\nbinding := getBindingForUser(user, bindingV1, bindingV2)\nresult, _ := binding.Process(ctx, order)",{"id":508,"title":509,"titles":510,"content":24,"level":19},"/v1.0.1/guides/schema-design#error-handling-placement","Error Handling Placement",[443],{"id":512,"title":513,"titles":514,"content":515,"level":30},"/v1.0.1/guides/schema-design#wrap-at-boundaries","Wrap at Boundaries",[443,509],"Apply error handling at service boundaries: type: sequence\nchildren:\n  - ref: validate  # Internal - no wrap needed\n  - type: circuit-breaker\n    failure_threshold: 5\n    child:\n      type: retry\n        attempts: 3\n        child:\n          ref: external-api  # External - wrap\n  - ref: transform  # Internal - no wrap",{"id":517,"title":518,"titles":519,"content":520,"level":30},"/v1.0.1/guides/schema-design#dont-over-protect","Don't Over-Protect",[443,509],"Avoid redundant error handling: # Overkill\ntype: retry\nchild:\n  type: retry\n    child:\n      type: fallback\n        children:\n          - type: retry\n              child:\n                ref: processor\n          - ref: fallback",{"id":522,"title":523,"titles":524,"content":525,"level":30},"/v1.0.1/guides/schema-design#match-retry-to-operation","Match Retry to Operation",[443,509],"# Quick operation - few retries, no backoff\ntype: retry\nattempts: 2\nchild:\n  ref: cache-lookup\n\n# Slow external service - more retries with backoff\ntype: retry\nattempts: 5\nbackoff: \"500ms\"\nchild:\n  ref: payment-gateway",{"id":527,"title":528,"titles":529,"content":24,"level":19},"/v1.0.1/guides/schema-design#performance-considerations","Performance Considerations",[443],{"id":531,"title":532,"titles":533,"content":534,"level":30},"/v1.0.1/guides/schema-design#minimize-cloning","Minimize Cloning",[443,528],"concurrent and race nodes clone data. Avoid unnecessary parallelism: # Unnecessary clone\ntype: concurrent\nchildren:\n  - ref: quick-transform  # Could be sequential\n\n# Justified parallelism\ntype: concurrent\nchildren:\n  - ref: slow-api-call\n  - ref: another-slow-call",{"id":536,"title":537,"titles":538,"content":539,"level":30},"/v1.0.1/guides/schema-design#rate-limit-at-entry-points","Rate Limit at Entry Points",[443,528],"Place rate limiters early: type: sequence\nchildren:\n  - type: rate-limit\n    requests_per_second: 100.0\n    child:\n      ref: validate  # Everything after is protected\n  - ref: process\n  - ref: external-call",{"id":541,"title":542,"titles":543,"content":544,"level":30},"/v1.0.1/guides/schema-design#use-timeouts-wisely","Use Timeouts Wisely",[443,528],"Set realistic timeouts: type: timeout\nduration: \"30s\"  # Based on actual SLA\nchild:\n  ref: external-service",{"id":546,"title":547,"titles":548,"content":24,"level":19},"/v1.0.1/guides/schema-design#schema-organization","Schema Organization",[443],{"id":550,"title":551,"titles":552,"content":553,"level":30},"/v1.0.1/guides/schema-design#single-responsibility","Single Responsibility",[443,547],"Each schema should do one thing well: // Separate concerns\nfactory.SetSchema(\"order-validation\", validationSchema)\nfactory.SetSchema(\"order-payment\", paymentSchema)\nfactory.SetSchema(\"order-fulfillment\", fulfillmentSchema)",{"id":555,"title":556,"titles":557,"content":558,"level":30},"/v1.0.1/guides/schema-design#compose-larger-flows","Compose Larger Flows",[443,547],"Build complex flows from simple schemas: // High-level orchestration\nfactory.SetSchema(\"order-complete\", Schema{\n    Node: Node{\n        Type: \"sequence\",\n        Children: []Node{\n            {Ref: \"order-validation\"},   // References another pipeline\n            {Ref: \"order-payment\"},\n            {Ref: \"order-fulfillment\"},\n        },\n    },\n})",{"id":560,"title":561,"titles":562,"content":24,"level":19},"/v1.0.1/guides/schema-design#documentation-practices","Documentation Practices",[443],{"id":564,"title":565,"titles":566,"content":567,"level":30},"/v1.0.1/guides/schema-design#use-descriptions","Use Descriptions",[443,561],"Add descriptions when registering: factory.AddPredicate(flume.Predicate[Order]{\n    Name:        \"high-value\",\n    Description: \"Orders exceeding $1000 threshold for premium handling\",\n    Predicate:   isHighValue,\n})\n\nfactory.AddCondition(flume.Condition[Order]{\n    Name:        \"fulfillment-type\",\n    Description: \"Determines shipping vs. digital delivery\",\n    Values:      []string{\"ship\", \"digital\", \"pickup\"},\n    Condition:   getFulfillmentType,\n})",{"id":569,"title":570,"titles":571,"content":572,"level":30},"/v1.0.1/guides/schema-design#companion-documentation","Companion Documentation",[443,561],"Maintain schema documentation alongside files: schemas/\n  order-processing.yaml\n  order-processing.md    # Documents the schema",{"id":574,"title":575,"titles":576,"content":577,"level":30},"/v1.0.1/guides/schema-design#schema-diagrams","Schema Diagrams",[443,561],"For complex pipelines, create visual diagrams: validate → [concurrent: enrich] → [filter: premium?] → [switch: payment] → complete\n                                        ↓                    ↓\n                                  premium-handler     credit|paypal|crypto",{"id":579,"title":150,"titles":580,"content":581,"level":19},"/v1.0.1/guides/schema-design#next-steps",[443],"Hot Reloading - Dynamic schema updatesTesting - Testing schema-driven pipelinesSchema Format Reference - Complete specification html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":583,"title":219,"titles":584,"content":585,"level":9},"/v1.0.1/guides/hot-reloading",[],"Update pipeline behaviour at runtime without restarts",{"id":587,"title":219,"titles":588,"content":589,"level":9},"/v1.0.1/guides/hot-reloading#hot-reloading",[],"Update pipeline definitions at runtime without service restarts.",{"id":591,"title":6,"titles":592,"content":593,"level":19},"/v1.0.1/guides/hot-reloading#overview",[219],"Flume's hot reloading enables: Zero-downtime updates - Swap pipelines while requests continueA/B testing - Switch between pipeline variantsFeature flags - Enable/disable pipeline stages dynamicallyConfiguration-driven behaviour - Operators modify pipelines without deploys",{"id":595,"title":596,"titles":597,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#basic-usage","Basic Usage",[219],{"id":599,"title":600,"titles":601,"content":602,"level":30},"/v1.0.1/guides/hot-reloading#register-named-schemas","Register Named Schemas",[219,596],"factory := flume.New[Order]()\n\n// Register components\nfactory.Add(processors...)\nfactory.AddPredicate(predicates...)\n\n// Register named schema\nschema := flume.Schema{\n    Version: \"1.0.0\",\n    Node: flume.Node{\n        Type: \"sequence\",\n        Children: []flume.Node{\n            {Ref: \"validate\"},\n            {Ref: \"process\"},\n        },\n    },\n}\n\nerr := factory.SetSchema(\"order-pipeline\", schema)",{"id":604,"title":605,"titles":606,"content":607,"level":30},"/v1.0.1/guides/hot-reloading#create-a-binding","Create a Binding",[219,596],"// Create a binding with auto-sync enabled\npipelineID := factory.Identity(\"order-processor\", \"Processes incoming orders\")\nbinding, err := factory.Bind(pipelineID, \"order-pipeline\", flume.WithAutoSync())\nif err != nil {\n    return fmt.Errorf(\"failed to bind: %w\", err)\n}\n\n// Process requests (lock-free)\nresult, err := binding.Process(ctx, order)",{"id":609,"title":610,"titles":611,"content":612,"level":30},"/v1.0.1/guides/hot-reloading#update-at-runtime","Update at Runtime",[219,596],"newSchema := flume.Schema{\n    Version: \"1.1.0\",\n    Node: flume.Node{\n        Type: \"sequence\",\n        Children: []flume.Node{\n            {Ref: \"validate\"},\n            {Ref: \"enrich\"},  // Added step\n            {Ref: \"process\"},\n        },\n    },\n}\n\nerr := factory.SetSchema(\"order-pipeline\", newSchema)\n// New requests immediately use updated pipeline",{"id":614,"title":615,"titles":616,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#how-it-works","How It Works",[219],{"id":618,"title":619,"titles":620,"content":621,"level":30},"/v1.0.1/guides/hot-reloading#atomic-pointer-swap","Atomic Pointer Swap",[219,615],"// Internally, pipelines are stored as atomic pointers\npipelines map[string]*atomic.Pointer[pipz.Chainable[T]]\n\n// Update atomically swaps the pointer\nptr.Store(&newPipeline)\n\n// Retrieval loads atomically\nreturn *ptr.Load(), true",{"id":623,"title":624,"titles":625,"content":626,"level":30},"/v1.0.1/guides/hot-reloading#request-continuity","Request Continuity",[219,615],"Request A starts with pipeline v1Schema updates to v2Request A completes with v1 (unaffected)Request B starts with v2 No locks are held during processing - updates don't block requests.",{"id":628,"title":629,"titles":630,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#file-based-reloading","File-Based Reloading",[219],{"id":632,"title":633,"titles":634,"content":635,"level":30},"/v1.0.1/guides/hot-reloading#watch-for-changes","Watch for Changes",[219,629],"func watchSchemaFile(ctx context.Context, factory *flume.Factory[Order], path string) {\n    watcher, _ := fsnotify.NewWatcher()\n    defer watcher.Close()\n\n    watcher.Add(path)\n\n    for {\n        select {\n        case \u003C-ctx.Done():\n            return\n        case event := \u003C-watcher.Events:\n            if event.Op&fsnotify.Write == fsnotify.Write {\n                reloadSchema(factory, path)\n            }\n        }\n    }\n}\n\nfunc reloadSchema(factory *flume.Factory[Order], path string) {\n    pipeline, err := factory.BuildFromFile(path)\n    if err != nil {\n        log.Printf(\"failed to reload schema: %v\", err)\n        return\n    }\n\n    // Read file to get schema for SetSchema\n    data, _ := os.ReadFile(path)\n    var schema flume.Schema\n    yaml.Unmarshal(data, &schema)\n\n    if err := factory.SetSchema(\"main\", schema); err != nil {\n        log.Printf(\"failed to set schema: %v\", err)\n    }\n}",{"id":637,"title":638,"titles":639,"content":640,"level":30},"/v1.0.1/guides/hot-reloading#multi-schema-directory","Multi-Schema Directory",[219,629],"func watchSchemaDir(ctx context.Context, factory *flume.Factory[Order], dir string) {\n    watcher, _ := fsnotify.NewWatcher()\n    watcher.Add(dir)\n\n    for event := range watcher.Events {\n        if event.Op&fsnotify.Write == 0 {\n            continue\n        }\n\n        name := strings.TrimSuffix(filepath.Base(event.Name), filepath.Ext(event.Name))\n\n        data, _ := os.ReadFile(event.Name)\n        var schema flume.Schema\n        if err := yaml.Unmarshal(data, &schema); err != nil {\n            log.Printf(\"invalid schema %s: %v\", name, err)\n            continue\n        }\n\n        if err := factory.SetSchema(name, schema); err != nil {\n            log.Printf(\"failed to update %s: %v\", name, err)\n        }\n    }\n}",{"id":642,"title":643,"titles":644,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#remote-configuration","Remote Configuration",[219],{"id":646,"title":647,"titles":648,"content":649,"level":30},"/v1.0.1/guides/hot-reloading#http-endpoint","HTTP Endpoint",[219,643],"http.HandleFunc(\"/schemas/{name}\", func(w http.ResponseWriter, r *http.Request) {\n    name := r.PathValue(\"name\")\n\n    switch r.Method {\n    case \"GET\":\n        schema, ok := factory.GetSchema(name)\n        if !ok {\n            http.NotFound(w, r)\n            return\n        }\n        json.NewEncoder(w).Encode(schema)\n\n    case \"PUT\":\n        var schema flume.Schema\n        json.NewDecoder(r.Body).Decode(&schema)\n\n        if err := factory.SetSchema(name, schema); err != nil {\n            http.Error(w, err.Error(), 400)\n            return\n        }\n        w.WriteHeader(204)\n\n    case \"DELETE\":\n        if !factory.RemoveSchema(name) {\n            http.NotFound(w, r)\n            return\n        }\n        w.WriteHeader(204)\n    }\n})",{"id":651,"title":652,"titles":653,"content":654,"level":30},"/v1.0.1/guides/hot-reloading#polling","Polling",[219,643],"func pollSchemas(ctx context.Context, factory *flume.Factory[Order], url string) {\n    ticker := time.NewTicker(30 * time.Second)\n    defer ticker.Stop()\n\n    for {\n        select {\n        case \u003C-ctx.Done():\n            return\n        case \u003C-ticker.C:\n            resp, err := http.Get(url)\n            if err != nil {\n                continue\n            }\n\n            var schemas map[string]flume.Schema\n            json.NewDecoder(resp.Body).Decode(&schemas)\n            resp.Body.Close()\n\n            for name, schema := range schemas {\n                existing, ok := factory.GetSchema(name)\n                if ok && existing.Version == schema.Version {\n                    continue // No change\n                }\n                factory.SetSchema(name, schema)\n            }\n        }\n    }\n}",{"id":656,"title":657,"titles":658,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#version-tracking","Version Tracking",[219],{"id":660,"title":661,"titles":662,"content":663,"level":30},"/v1.0.1/guides/hot-reloading#compare-versions","Compare Versions",[219,657],"existing, ok := factory.GetSchema(\"pipeline\")\nif ok && existing.Version == newSchema.Version {\n    return // Already up to date\n}\n\nerr := factory.SetSchema(\"pipeline\", newSchema)",{"id":665,"title":666,"titles":667,"content":668,"level":30},"/v1.0.1/guides/hot-reloading#observability","Observability",[219,657],"Flume emits events on schema changes: import \"github.com/zoobz-io/capitan\"\n\ncapitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n    var name, oldVersion, newVersion string\n    for _, f := range fields {\n        switch f.Key {\n        case \"name\":\n            name = f.String()\n        case \"old_version\":\n            oldVersion = f.String()\n        case \"new_version\":\n            newVersion = f.String()\n        }\n    }\n    log.Printf(\"schema %s updated: %s -> %s\", name, oldVersion, newVersion)\n})",{"id":670,"title":671,"titles":672,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#graceful-updates","Graceful Updates",[219],{"id":674,"title":675,"titles":676,"content":677,"level":30},"/v1.0.1/guides/hot-reloading#validation-first","Validation First",[219,671],"Always validate before applying: if err := factory.ValidateSchema(newSchema); err != nil {\n    return fmt.Errorf(\"invalid schema: %w\", err)\n}\n\n// Schema is valid, safe to apply\nfactory.SetSchema(name, newSchema)",{"id":679,"title":680,"titles":681,"content":682,"level":30},"/v1.0.1/guides/hot-reloading#rollback-pattern","Rollback Pattern",[219,671],"func updateWithRollback(factory *flume.Factory[Order], name string, newSchema flume.Schema, binding *flume.Binding[Order]) error {\n    // Save current\n    oldSchema, hadOld := factory.GetSchema(name)\n\n    // Apply new (auto-sync bindings rebuild automatically)\n    if err := factory.SetSchema(name, newSchema); err != nil {\n        return err\n    }\n\n    // Test with canary request\n    _, err := binding.Process(context.Background(), canaryOrder)\n\n    if err != nil && hadOld {\n        // Rollback to previous schema\n        factory.SetSchema(name, oldSchema)\n        return fmt.Errorf(\"canary failed, rolled back: %w\", err)\n    }\n\n    return nil\n}",{"id":684,"title":685,"titles":686,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#best-practices","Best Practices",[219],{"id":688,"title":689,"titles":690,"content":691,"level":30},"/v1.0.1/guides/hot-reloading#_1-use-semantic-versioning","1. Use Semantic Versioning",[219,685],"version: \"1.2.3\"  # MAJOR.MINOR.PATCH",{"id":693,"title":694,"titles":695,"content":696,"level":30},"/v1.0.1/guides/hot-reloading#_2-log-all-changes","2. Log All Changes",[219,685],"log.Printf(\"schema %s updated to version %s\", name, schema.Version)",{"id":698,"title":699,"titles":700,"content":701,"level":30},"/v1.0.1/guides/hot-reloading#_3-validate-component-dependencies","3. Validate Component Dependencies",[219,685],"Before removing a processor, check if schemas reference it: for _, schemaName := range factory.ListSchemas() {\n    schema, _ := factory.GetSchema(schemaName)\n    if schemaReferencesProcessor(schema, \"old-processor\") {\n        return fmt.Errorf(\"cannot remove: schema %s uses it\", schemaName)\n    }\n}",{"id":703,"title":704,"titles":705,"content":706,"level":30},"/v1.0.1/guides/hot-reloading#_4-consider-circuit-breakers","4. Consider Circuit Breakers",[219,685],"Protect against bad schema updates: type GuardedFactory[T pipz.Cloner[T]] struct {\n    factory       *flume.Factory[T]\n    updateBreaker *circuitbreaker.CircuitBreaker\n}\n\nfunc (g *GuardedFactory[T]) SetSchema(name string, schema flume.Schema) error {\n    return g.updateBreaker.Execute(func() error {\n        return g.factory.SetSchema(name, schema)\n    })\n}",{"id":708,"title":150,"titles":709,"content":710,"level":19},"/v1.0.1/guides/hot-reloading#next-steps",[219],"Testing - Test hot reload scenariosObservability - Monitor schema changesEvents Reference - All schema events html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}",{"id":712,"title":363,"titles":713,"content":714,"level":9},"/v1.0.1/guides/error-handling",[],"Build resilient pipelines with retry, fallback, circuit breakers, and timeouts",{"id":716,"title":363,"titles":717,"content":718,"level":9},"/v1.0.1/guides/error-handling#error-handling",[],"Build resilient pipelines that gracefully handle failures.",{"id":720,"title":367,"titles":721,"content":722,"level":19},"/v1.0.1/guides/error-handling#retry",[363],"Retry operations that may fail transiently.",{"id":724,"title":725,"titles":726,"content":727,"level":30},"/v1.0.1/guides/error-handling#basic-retry","Basic Retry",[363,367],"type: retry\nattempts: 3\nchild:\n  ref: flaky-operation Retries up to 3 times on any error.",{"id":729,"title":730,"titles":731,"content":732,"level":30},"/v1.0.1/guides/error-handling#retry-with-backoff","Retry with Backoff",[363,367],"type: retry\nattempts: 5\nbackoff: \"100ms\"\nchild:\n  ref: rate-limited-api Waits backoff duration between attempts, doubling each time (exponential backoff).",{"id":734,"title":735,"titles":736,"content":737,"level":30},"/v1.0.1/guides/error-handling#when-to-use","When to Use",[363,367],"Network calls that may timeoutRate-limited APIs that return temporary errorsDatabase operations during high loadMessage queue operations",{"id":739,"title":740,"titles":741,"content":742,"level":30},"/v1.0.1/guides/error-handling#configuration","Configuration",[363,367],"FieldDefaultDescriptionattempts3Maximum retry attemptsbackoff(none)Initial backoff duration",{"id":744,"title":372,"titles":745,"content":746,"level":19},"/v1.0.1/guides/error-handling#fallback",[363],"Provide alternative handling when primary fails.",{"id":748,"title":749,"titles":750,"content":751,"level":30},"/v1.0.1/guides/error-handling#basic-fallback","Basic Fallback",[363,372],"type: fallback\nchildren:\n  - ref: primary-service\n  - ref: backup-service Tries primary first; if it errors, tries backup.",{"id":753,"title":754,"titles":755,"content":756,"level":30},"/v1.0.1/guides/error-handling#cascading-fallbacks","Cascading Fallbacks",[363,372],"type: fallback\nchildren:\n  - ref: primary-cache\n  - type: fallback\n    children:\n      - ref: secondary-cache\n      - ref: database",{"id":758,"title":735,"titles":759,"content":760,"level":30},"/v1.0.1/guides/error-handling#when-to-use-1",[363,372],"Service redundancyCache miss handlingFeature degradationDefault value provision",{"id":762,"title":377,"titles":763,"content":764,"level":19},"/v1.0.1/guides/error-handling#timeout",[363],"Enforce time limits on operations.",{"id":766,"title":767,"titles":768,"content":769,"level":30},"/v1.0.1/guides/error-handling#basic-timeout","Basic Timeout",[363,377],"type: timeout\nduration: \"5s\"\nchild:\n  ref: slow-operation Cancels operation if not complete within duration.",{"id":771,"title":740,"titles":772,"content":773,"level":30},"/v1.0.1/guides/error-handling#configuration-1",[363,377],"FieldDefaultDescriptionduration30sMaximum execution time",{"id":775,"title":776,"titles":777,"content":778,"level":30},"/v1.0.1/guides/error-handling#duration-formats","Duration Formats",[363,377],"duration: \"100ms\"   # 100 milliseconds\nduration: \"5s\"      # 5 seconds\nduration: \"2m\"      # 2 minutes\nduration: \"1h30m\"   # 1.5 hours",{"id":780,"title":735,"titles":781,"content":782,"level":30},"/v1.0.1/guides/error-handling#when-to-use-2",[363,377],"External API callsLong-running computationsUser-facing requests requiring responsivenessPreventing resource exhaustion",{"id":784,"title":382,"titles":785,"content":786,"level":19},"/v1.0.1/guides/error-handling#circuit-breaker",[363],"Prevent cascading failures by stopping calls to failing services.",{"id":788,"title":789,"titles":790,"content":791,"level":30},"/v1.0.1/guides/error-handling#basic-circuit-breaker","Basic Circuit Breaker",[363,382],"type: circuit-breaker\nfailure_threshold: 5\nrecovery_timeout: \"60s\"\nchild:\n  ref: external-service",{"id":793,"title":615,"titles":794,"content":795,"level":30},"/v1.0.1/guides/error-handling#how-it-works",[363,382],"Closed - Normal operation, failures countedOpen - After failure_threshold failures, requests fail immediatelyHalf-Open - After recovery_timeout, one test request allowedClosed - If test succeeds, resume normal operation",{"id":797,"title":740,"titles":798,"content":799,"level":30},"/v1.0.1/guides/error-handling#configuration-2",[363,382],"FieldDefaultDescriptionfailure_threshold5Failures before openingrecovery_timeout60sTime before testing recovery",{"id":801,"title":735,"titles":802,"content":803,"level":30},"/v1.0.1/guides/error-handling#when-to-use-3",[363,382],"Calling external servicesProtecting against cascade failuresAllowing degraded operationPreventing resource exhaustion from retrying failing calls",{"id":805,"title":387,"titles":806,"content":807,"level":19},"/v1.0.1/guides/error-handling#rate-limiting",[363],"Control request throughput.",{"id":809,"title":810,"titles":811,"content":812,"level":30},"/v1.0.1/guides/error-handling#basic-rate-limit","Basic Rate Limit",[363,387],"type: rate-limit\nrequests_per_second: 100.0\nburst_size: 10\nchild:\n  ref: rate-sensitive-api",{"id":814,"title":740,"titles":815,"content":816,"level":30},"/v1.0.1/guides/error-handling#configuration-3",[363,387],"FieldDefaultDescriptionrequests_per_second10.0Sustained rate limitburst_size1Allowed burst above limit",{"id":818,"title":735,"titles":819,"content":820,"level":30},"/v1.0.1/guides/error-handling#when-to-use-4",[363,387],"Calling APIs with rate limitsProtecting downstream servicesEnsuring fair resource usagePreventing thundering herd",{"id":822,"title":823,"titles":824,"content":24,"level":19},"/v1.0.1/guides/error-handling#combining-patterns","Combining Patterns",[363],{"id":826,"title":827,"titles":828,"content":829,"level":30},"/v1.0.1/guides/error-handling#resilient-external-call","Resilient External Call",[363,823],"type: circuit-breaker\nfailure_threshold: 3\nrecovery_timeout: \"30s\"\nchild:\n  type: timeout\n  duration: \"10s\"\n  child:\n    type: retry\n    attempts: 3\n    backoff: \"200ms\"\n    child:\n      ref: external-api Order matters: Circuit breaker - Fails fast if service is downTimeout - Limits total wait timeRetry - Handles transient failures",{"id":831,"title":832,"titles":833,"content":834,"level":30},"/v1.0.1/guides/error-handling#fallback-with-resilience","Fallback with Resilience",[363,823],"type: fallback\nchildren:\n  - type: circuit-breaker\n    failure_threshold: 5\n    child:\n      type: retry\n      attempts: 2\n      child:\n        ref: primary-service\n  - ref: backup-service Primary has full resilience; backup is simpler.",{"id":836,"title":837,"titles":838,"content":839,"level":30},"/v1.0.1/guides/error-handling#rate-limited-with-timeout","Rate Limited with Timeout",[363,823],"type: timeout\nduration: \"30s\"\nchild:\n  type: rate-limit\n  requests_per_second: 50.0\n  burst_size: 5\n  child:\n    type: retry\n    attempts: 3\n    child:\n      ref: rate-limited-api Total request time bounded even if queued for rate limiting.",{"id":841,"title":842,"titles":843,"content":844,"level":19},"/v1.0.1/guides/error-handling#error-types","Error Types",[363],"Understand which errors trigger which behaviour: ConnectorTriggers OnRetryAny error returnedFallbackAny error from primaryTimeoutContext deadline exceededCircuit BreakerAny error (tracks count)",{"id":846,"title":685,"titles":847,"content":24,"level":19},"/v1.0.1/guides/error-handling#best-practices",[363],{"id":849,"title":850,"titles":851,"content":852,"level":30},"/v1.0.1/guides/error-handling#_1-set-realistic-timeouts","1. Set Realistic Timeouts",[363,685],"# Too short - may fail healthy requests\nduration: \"100ms\"\n\n# Too long - poor user experience\nduration: \"5m\"\n\n# Right - based on actual service SLA\nduration: \"5s\"",{"id":854,"title":855,"titles":856,"content":857,"level":30},"/v1.0.1/guides/error-handling#_2-tune-circuit-breaker-thresholds","2. Tune Circuit Breaker Thresholds",[363,685],"# Too sensitive - opens on minor issues\nfailure_threshold: 1\n\n# Too lenient - doesn't protect\nfailure_threshold: 100\n\n# Balanced - opens after pattern emerges\nfailure_threshold: 5\nrecovery_timeout: \"30s\"",{"id":859,"title":860,"titles":861,"content":862,"level":30},"/v1.0.1/guides/error-handling#_3-use-backoff-for-rate-limits","3. Use Backoff for Rate Limits",[363,685],"type: retry\nattempts: 5\nbackoff: \"1s\"  # Gives rate limit time to reset\nchild:\n  ref: rate-limited-api",{"id":864,"title":865,"titles":866,"content":867,"level":30},"/v1.0.1/guides/error-handling#_4-dont-retry-non-retryable-errors","4. Don't Retry Non-Retryable Errors",[363,685],"Some errors shouldn't be retried. Design processors to return wrapped errors: type nonRetryableError struct {\n    error\n}\n\nfunc (e nonRetryableError) Unwrap() error { return e.error }\n\n// In processor\nif isInvalidInput(err) {\n    return data, nonRetryableError{err}\n}",{"id":869,"title":870,"titles":871,"content":872,"level":30},"/v1.0.1/guides/error-handling#_5-monitor-error-rates","5. Monitor Error Rates",[363,685],"Use Capitan events to track failures: capitan.Handle(flume.SchemaBuildFailed, logFailure)\n// Also monitor your processor errors",{"id":874,"title":150,"titles":875,"content":876,"level":19},"/v1.0.1/guides/error-handling#next-steps",[363],"Testing - Test error scenariosConnector Types Reference - All options html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}",{"id":878,"title":879,"titles":880,"content":881,"level":9},"/v1.0.1/guides/testing","Testing",[],"Testing strategies for schema-driven pipelines",{"id":883,"title":879,"titles":884,"content":885,"level":9},"/v1.0.1/guides/testing#testing",[],"Strategies for testing Flume pipelines at multiple levels.",{"id":887,"title":888,"titles":889,"content":890,"level":19},"/v1.0.1/guides/testing#testing-levels","Testing Levels",[879],"Unit Tests - Test individual processorsSchema Tests - Test schema validationIntegration Tests - Test complete pipelinesProperty Tests - Test invariants across schemas",{"id":892,"title":893,"titles":894,"content":895,"level":19},"/v1.0.1/guides/testing#unit-testing-processors","Unit Testing Processors",[879],"Test processors independently before registering: func TestValidateOrder(t *testing.T) {\n    processor := pipz.Apply(\"validate\", validateOrder)\n\n    tests := []struct {\n        name    string\n        input   Order\n        wantErr bool\n    }{\n        {\n            name:    \"valid order\",\n            input:   Order{Total: 100},\n            wantErr: false,\n        },\n        {\n            name:    \"zero total\",\n            input:   Order{Total: 0},\n            wantErr: true,\n        },\n        {\n            name:    \"negative total\",\n            input:   Order{Total: -50},\n            wantErr: true,\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            _, err := processor.Process(context.Background(), tt.input)\n            if (err != nil) != tt.wantErr {\n                t.Errorf(\"error = %v, wantErr %v\", err, tt.wantErr)\n            }\n        })\n    }\n}",{"id":897,"title":898,"titles":899,"content":900,"level":19},"/v1.0.1/guides/testing#testing-predicates","Testing Predicates",[879],"func TestIsPremium(t *testing.T) {\n    pred := func(ctx context.Context, o Order) bool {\n        return o.CustomerTier == \"premium\"\n    }\n\n    tests := []struct {\n        tier string\n        want bool\n    }{\n        {\"premium\", true},\n        {\"standard\", false},\n        {\"\", false},\n    }\n\n    for _, tt := range tests {\n        got := pred(context.Background(), Order{CustomerTier: tt.tier})\n        if got != tt.want {\n            t.Errorf(\"isPremium(%q) = %v, want %v\", tt.tier, got, tt.want)\n        }\n    }\n}",{"id":902,"title":903,"titles":904,"content":905,"level":19},"/v1.0.1/guides/testing#schema-validation-tests","Schema Validation Tests",[879],"Test that schemas are valid before deployment: func TestSchemaValidation(t *testing.T) {\n    factory := setupFactory()\n\n    tests := []struct {\n        name      string\n        schema    string\n        wantError bool\n    }{\n        {\n            name: \"valid sequence\",\n            schema: `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: process`,\n            wantError: false,\n        },\n        {\n            name: \"missing processor\",\n            schema: `\ntype: sequence\nchildren:\n  - ref: nonexistent`,\n            wantError: true,\n        },\n        {\n            name: \"missing predicate\",\n            schema: `\ntype: filter\npredicate: missing\nthen:\n  ref: validate`,\n            wantError: true,\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            _, err := factory.BuildFromYAML(tt.schema)\n            if (err != nil) != tt.wantError {\n                t.Errorf(\"BuildFromYAML() error = %v, wantError %v\", err, tt.wantError)\n            }\n        })\n    }\n}\n\nfunc setupFactory() *flume.Factory[Order] {\n    factory := flume.New[Order]()\n    factory.Add(\n        pipz.Transform(\"validate\", func(_ context.Context, o Order) Order { return o }),\n        pipz.Transform(\"process\", func(_ context.Context, o Order) Order { return o }),\n    )\n    factory.AddPredicate(flume.Predicate[Order]{\n        Name:      \"is-valid\",\n        Predicate: func(_ context.Context, o Order) bool { return o.Total > 0 },\n    })\n    return factory\n}",{"id":907,"title":908,"titles":909,"content":910,"level":19},"/v1.0.1/guides/testing#cicd-schema-linting","CI/CD Schema Linting",[879],"Use ValidateSchemaStructure for CI/CD pipelines where a configured factory is not available. This validates schema syntax without checking if processors, predicates, or other references exist.",{"id":912,"title":913,"titles":914,"content":915,"level":30},"/v1.0.1/guides/testing#lint-schema-files","Lint Schema Files",[879,908],"func TestSchemaFilesStructure(t *testing.T) {\n    files, _ := filepath.Glob(\"schemas/*.yaml\")\n\n    for _, file := range files {\n        t.Run(filepath.Base(file), func(t *testing.T) {\n            data, err := os.ReadFile(file)\n            if err != nil {\n                t.Fatalf(\"failed to read file: %v\", err)\n            }\n\n            var schema flume.Schema\n            if err := yaml.Unmarshal(data, &schema); err != nil {\n                t.Fatalf(\"failed to parse YAML: %v\", err)\n            }\n\n            // Structural validation - no factory needed\n            if err := flume.ValidateSchemaStructure(schema); err != nil {\n                t.Errorf(\"invalid schema structure: %v\", err)\n            }\n        })\n    }\n}",{"id":917,"title":918,"titles":919,"content":920,"level":30},"/v1.0.1/guides/testing#ci-pipeline-example","CI Pipeline Example",[879,908],"# .github/workflows/lint-schemas.yml\nname: Lint Schemas\non: [push, pull_request]\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version: '1.23'\n      - run: go test -v -run TestSchemaFilesStructure ./...",{"id":922,"title":923,"titles":924,"content":925,"level":30},"/v1.0.1/guides/testing#what-each-validation-checks","What Each Validation Checks",[879,908],"CheckValidateSchemaStructureValidateSchemaValid node typesYesYesRequired children/childYesYesValid durationsYesYesPositive numbersYesYesProcessor refs existNoYesPredicate refs existNoYesCondition refs existNoYesChannel refs existNoYesCircular referencesNoYes Use ValidateSchemaStructure in CI to catch syntax errors early, then ValidateSchema at runtime with a configured factory to catch reference errors.",{"id":927,"title":928,"titles":929,"content":930,"level":19},"/v1.0.1/guides/testing#integration-testing","Integration Testing",[879],"Test complete pipelines with realistic scenarios: func TestOrderPipeline(t *testing.T) {\n    factory := setupProductionFactory()\n\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: high-value\n    then:\n      ref: premium-handler\n  - ref: finalize`\n\n    pipeline, err := factory.BuildFromYAML(schema)\n    if err != nil {\n        t.Fatalf(\"failed to build: %v\", err)\n    }\n\n    tests := []struct {\n        name  string\n        order Order\n        want  Order\n    }{\n        {\n            name:  \"standard order unchanged\",\n            order: Order{Total: 50},\n            want:  Order{Total: 50, Status: \"finalized\"},\n        },\n        {\n            name:  \"high value gets premium treatment\",\n            order: Order{Total: 1000},\n            want:  Order{Total: 1000, Discount: 0.1, Status: \"finalized\"},\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            result, err := pipeline.Process(context.Background(), tt.order)\n            if err != nil {\n                t.Fatalf(\"unexpected error: %v\", err)\n            }\n            if result != tt.want {\n                t.Errorf(\"got %+v, want %+v\", result, tt.want)\n            }\n        })\n    }\n}",{"id":932,"title":933,"titles":934,"content":24,"level":19},"/v1.0.1/guides/testing#testing-error-handling","Testing Error Handling",[879],{"id":936,"title":937,"titles":938,"content":939,"level":30},"/v1.0.1/guides/testing#retry-behaviour","Retry Behaviour",[879,933],"func TestRetryBehaviour(t *testing.T) {\n    attempts := 0\n    processor := pipz.Apply(\"flaky\", func(_ context.Context, o Order) (Order, error) {\n        attempts++\n        if attempts \u003C 3 {\n            return o, errors.New(\"transient failure\")\n        }\n        return o, nil\n    })\n\n    factory := flume.New[Order]()\n    factory.Add(processor)\n\n    schema := `\ntype: retry\nattempts: 5\nchild:\n  ref: flaky`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    _, err := pipeline.Process(context.Background(), Order{})\n\n    if err != nil {\n        t.Errorf(\"expected success after retries, got: %v\", err)\n    }\n    if attempts != 3 {\n        t.Errorf(\"expected 3 attempts, got %d\", attempts)\n    }\n}",{"id":941,"title":942,"titles":943,"content":944,"level":30},"/v1.0.1/guides/testing#fallback-behaviour","Fallback Behaviour",[879,933],"func TestFallbackBehaviour(t *testing.T) {\n    factory := flume.New[Order]()\n\n    factory.Add(\n        pipz.Apply(\"failing\", func(_ context.Context, o Order) (Order, error) {\n            return o, errors.New(\"primary failed\")\n        }),\n        pipz.Transform(\"backup\", func(_ context.Context, o Order) Order {\n            o.Source = \"backup\"\n            return o\n        }),\n    )\n\n    schema := `\ntype: fallback\nchildren:\n  - ref: failing\n  - ref: backup`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    result, err := pipeline.Process(context.Background(), Order{})\n\n    if err != nil {\n        t.Errorf(\"expected success from fallback: %v\", err)\n    }\n    if result.Source != \"backup\" {\n        t.Error(\"expected fallback to be used\")\n    }\n}",{"id":946,"title":947,"titles":948,"content":949,"level":30},"/v1.0.1/guides/testing#timeout-behaviour","Timeout Behaviour",[879,933],"func TestTimeoutBehaviour(t *testing.T) {\n    factory := flume.New[Order]()\n\n    factory.Add(pipz.Apply(\"slow\", func(ctx context.Context, o Order) (Order, error) {\n        select {\n        case \u003C-time.After(5 * time.Second):\n            return o, nil\n        case \u003C-ctx.Done():\n            return o, ctx.Err()\n        }\n    }))\n\n    schema := `\ntype: timeout\nduration: \"100ms\"\nchild:\n  ref: slow`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    _, err := pipeline.Process(context.Background(), Order{})\n\n    if !errors.Is(err, context.DeadlineExceeded) {\n        t.Errorf(\"expected deadline exceeded, got: %v\", err)\n    }\n}",{"id":951,"title":952,"titles":953,"content":954,"level":19},"/v1.0.1/guides/testing#testing-hot-reload","Testing Hot Reload",[879],"func TestHotReload(t *testing.T) {\n    factory := flume.New[Order]()\n    factory.Add(\n        pipz.Transform(\"v1\", func(_ context.Context, o Order) Order {\n            o.Version = \"v1\"\n            return o\n        }),\n        pipz.Transform(\"v2\", func(_ context.Context, o Order) Order {\n            o.Version = \"v2\"\n            return o\n        }),\n    )\n\n    // Set initial schema\n    factory.SetSchema(\"test\", flume.Schema{\n        Version: \"1.0.0\",\n        Node:    flume.Node{Ref: \"v1\"},\n    })\n\n    // Create binding with auto-sync\n    pipelineID := factory.Identity(\"test-pipeline\", \"Test pipeline\")\n    binding, _ := factory.Bind(pipelineID, \"test\", flume.WithAutoSync())\n\n    // Process with v1\n    result, _ := binding.Process(context.Background(), Order{})\n    if result.Version != \"v1\" {\n        t.Error(\"expected v1\")\n    }\n\n    // Update schema - binding auto-syncs\n    factory.SetSchema(\"test\", flume.Schema{\n        Version: \"2.0.0\",\n        Node:    flume.Node{Ref: \"v2\"},\n    })\n\n    // Process with v2\n    result, _ = binding.Process(context.Background(), Order{})\n    if result.Version != \"v2\" {\n        t.Error(\"expected v2\")\n    }\n}",{"id":956,"title":957,"titles":958,"content":959,"level":19},"/v1.0.1/guides/testing#concurrent-testing","Concurrent Testing",[879],"func TestConcurrentPipelineAccess(t *testing.T) {\n    factory := setupFactory()\n    factory.SetSchema(\"test\", testSchema)\n\n    // Create binding with auto-sync\n    pipelineID := factory.Identity(\"concurrent-pipeline\", \"Concurrent test\")\n    binding, _ := factory.Bind(pipelineID, \"test\", flume.WithAutoSync())\n\n    var wg sync.WaitGroup\n    errors := make(chan error, 100)\n\n    for i := 0; i \u003C 100; i++ {\n        wg.Add(1)\n        go func(id int) {\n            defer wg.Done()\n            _, err := binding.Process(context.Background(), Order{ID: fmt.Sprint(id)})\n            if err != nil {\n                errors \u003C- err\n            }\n        }(i)\n    }\n\n    wg.Wait()\n    close(errors)\n\n    for err := range errors {\n        t.Error(err)\n    }\n}",{"id":961,"title":962,"titles":963,"content":964,"level":19},"/v1.0.1/guides/testing#test-helpers","Test Helpers",[879],"The flume/testing package provides utilities: import flumetesting \"github.com/zoobz-io/flume/testing\"\n\nfunc TestWithHelpers(t *testing.T) {\n    tf := flumetesting.NewTestFactory(t)\n\n    // Register test processors\n    tf.RegisterNoOpProcessors(\"validate\", \"process\", \"finalize\")\n\n    // Build and test\n    pipeline, err := tf.Factory.BuildFromYAML(schema)\n    tf.AssertNoError(err)\n\n    result, err := pipeline.Process(context.Background(), flumetesting.TestData{ID: 1})\n    tf.AssertNoError(err)\n}",{"id":966,"title":685,"titles":967,"content":968,"level":19},"/v1.0.1/guides/testing#best-practices",[879],"Test processors in isolation before integrationUse table-driven tests for schema variationsTest error paths explicitly - don't just test happy pathsTest concurrent access if using hot reloadKeep test factories minimal - only register what's needed",{"id":970,"title":150,"titles":971,"content":972,"level":19},"/v1.0.1/guides/testing#next-steps",[879],"Observability - Monitor in productionTesting Package Reference - Test utilities html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}",{"id":974,"title":666,"titles":975,"content":976,"level":9},"/v1.0.1/guides/observability",[],"Monitor Flume pipelines with Capitan events",{"id":978,"title":666,"titles":979,"content":980,"level":9},"/v1.0.1/guides/observability#observability",[],"Flume integrates with Capitan for comprehensive observability.",{"id":982,"title":6,"titles":983,"content":984,"level":19},"/v1.0.1/guides/observability#overview",[666],"Flume emits structured events throughout its lifecycle: Factory creation and component registrationSchema validation, building, and updatesPipeline retrieval and executionFile loading and parsing",{"id":986,"title":987,"titles":988,"content":24,"level":19},"/v1.0.1/guides/observability#event-categories","Event Categories",[666],{"id":990,"title":991,"titles":992,"content":993,"level":30},"/v1.0.1/guides/observability#factory-events","Factory Events",[666,987],"flume.FactoryCreated      // Factory instantiated\nflume.ProcessorRegistered // Processor added\nflume.PredicateRegistered // Predicate added\nflume.ConditionRegistered // Condition added\nflume.ProcessorRemoved    // Processor removed\nflume.PredicateRemoved    // Predicate removed\nflume.ConditionRemoved    // Condition removed",{"id":995,"title":996,"titles":997,"content":998,"level":30},"/v1.0.1/guides/observability#schema-events","Schema Events",[666,987],"flume.SchemaValidationStarted   // Validation began\nflume.SchemaValidationCompleted // Validation successful\nflume.SchemaValidationFailed    // Validation failed\nflume.SchemaBuildStarted        // Build began\nflume.SchemaBuildCompleted      // Build successful\nflume.SchemaBuildFailed         // Build failed",{"id":1000,"title":1001,"titles":1002,"content":1003,"level":30},"/v1.0.1/guides/observability#dynamic-schema-events","Dynamic Schema Events",[666,987],"flume.SchemaRegistered   // New schema added\nflume.SchemaUpdated      // Existing schema replaced\nflume.SchemaRemoved      // Schema deleted\nflume.PipelineRetrieved  // Pipeline accessed",{"id":1005,"title":1006,"titles":1007,"content":1008,"level":30},"/v1.0.1/guides/observability#file-events","File Events",[666,987],"flume.SchemaFileLoaded  // File read successfully\nflume.SchemaFileFailed  // File read error\nflume.SchemaYAMLParsed  // YAML parsed\nflume.SchemaJSONParsed  // JSON parsed\nflume.SchemaParseFailed // Parse error",{"id":1010,"title":1011,"titles":1012,"content":1013,"level":19},"/v1.0.1/guides/observability#event-fields","Event Fields",[666],"Events include typed fields for structured data: flume.KeyName       // string: component/schema name\nflume.KeyType       // string: data type\nflume.KeyVersion    // string: schema version\nflume.KeyOldVersion // string: previous version (updates)\nflume.KeyNewVersion // string: new version (updates)\nflume.KeyPath       // string: file path\nflume.KeyError      // string: error message\nflume.KeyDuration   // time.Duration: operation duration\nflume.KeyErrorCount // int: number of errors\nflume.KeySizeBytes  // int: file size\nflume.KeyFound      // bool: retrieval success",{"id":1015,"title":1016,"titles":1017,"content":24,"level":19},"/v1.0.1/guides/observability#setting-up-handlers","Setting Up Handlers",[666],{"id":1019,"title":1020,"titles":1021,"content":1022,"level":30},"/v1.0.1/guides/observability#basic-logging","Basic Logging",[666,1016],"import \"github.com/zoobz-io/capitan\"\n\nfunc setupLogging() {\n    // Log all schema events\n    capitan.Handle(flume.SchemaRegistered, func(ctx context.Context, fields []capitan.Field) {\n        log.Printf(\"Schema registered: %s\", extractString(fields, \"name\"))\n    })\n\n    capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n        log.Printf(\"Schema updated: %s (%s -> %s)\",\n            extractString(fields, \"name\"),\n            extractString(fields, \"old_version\"),\n            extractString(fields, \"new_version\"))\n    })\n\n    capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n        log.Printf(\"Build failed: %s\", extractString(fields, \"error\"))\n    })\n}\n\nfunc extractString(fields []capitan.Field, key string) string {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.String()\n        }\n    }\n    return \"\"\n}",{"id":1024,"title":1025,"titles":1026,"content":1027,"level":30},"/v1.0.1/guides/observability#metrics-collection","Metrics Collection",[666,1016],"import (\n    \"github.com/prometheus/client_golang/prometheus\"\n    \"github.com/zoobz-io/capitan\"\n)\n\nvar (\n    schemaUpdates = prometheus.NewCounterVec(\n        prometheus.CounterOpts{\n            Name: \"flume_schema_updates_total\",\n            Help: \"Total schema updates\",\n        },\n        []string{\"name\"},\n    )\n\n    buildDuration = prometheus.NewHistogramVec(\n        prometheus.HistogramOpts{\n            Name:    \"flume_build_duration_seconds\",\n            Help:    \"Schema build duration\",\n            Buckets: prometheus.DefBuckets,\n        },\n        []string{\"version\"},\n    )\n\n    buildFailures = prometheus.NewCounter(\n        prometheus.CounterOpts{\n            Name: \"flume_build_failures_total\",\n            Help: \"Total build failures\",\n        },\n    )\n)\n\nfunc setupMetrics() {\n    prometheus.MustRegister(schemaUpdates, buildDuration, buildFailures)\n\n    capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n        name := extractString(fields, \"name\")\n        schemaUpdates.WithLabelValues(name).Inc()\n    })\n\n    capitan.Handle(flume.SchemaBuildCompleted, func(ctx context.Context, fields []capitan.Field) {\n        version := extractString(fields, \"version\")\n        duration := extractDuration(fields, \"duration\")\n        buildDuration.WithLabelValues(version).Observe(duration.Seconds())\n    })\n\n    capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n        buildFailures.Inc()\n    })\n}",{"id":1029,"title":1030,"titles":1031,"content":1032,"level":30},"/v1.0.1/guides/observability#distributed-tracing","Distributed Tracing",[666,1016],"import \"go.opentelemetry.io/otel/trace\"\n\nfunc setupTracing(tracer trace.Tracer) {\n    capitan.Handle(flume.SchemaBuildStarted, func(ctx context.Context, fields []capitan.Field) {\n        _, span := tracer.Start(ctx, \"flume.build\")\n        version := extractString(fields, \"version\")\n        span.SetAttributes(attribute.String(\"schema.version\", version))\n        // Store span for completion handler\n    })\n\n    capitan.Handle(flume.SchemaBuildCompleted, func(ctx context.Context, fields []capitan.Field) {\n        // End span\n    })\n}",{"id":1034,"title":1035,"titles":1036,"content":24,"level":19},"/v1.0.1/guides/observability#common-monitoring-patterns","Common Monitoring Patterns",[666],{"id":1038,"title":1039,"titles":1040,"content":1041,"level":30},"/v1.0.1/guides/observability#schema-change-alerting","Schema Change Alerting",[666,1035],"capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n    name := extractString(fields, \"name\")\n    oldVersion := extractString(fields, \"old_version\")\n    newVersion := extractString(fields, \"new_version\")\n\n    if isMajorVersionChange(oldVersion, newVersion) {\n        alerting.SendAlert(alerting.Warning, fmt.Sprintf(\n            \"Major schema version change: %s from %s to %s\",\n            name, oldVersion, newVersion))\n    }\n})",{"id":1043,"title":1044,"titles":1045,"content":1046,"level":30},"/v1.0.1/guides/observability#build-performance-tracking","Build Performance Tracking",[666,1035],"capitan.Handle(flume.SchemaBuildCompleted, func(ctx context.Context, fields []capitan.Field) {\n    duration := extractDuration(fields, \"duration\")\n\n    if duration > 100*time.Millisecond {\n        log.Printf(\"Slow schema build: %v\", duration)\n    }\n})",{"id":1048,"title":1049,"titles":1050,"content":1051,"level":30},"/v1.0.1/guides/observability#validation-error-analysis","Validation Error Analysis",[666,1035],"capitan.Handle(flume.SchemaValidationFailed, func(ctx context.Context, fields []capitan.Field) {\n    errorCount := extractInt(fields, \"error_count\")\n    duration := extractDuration(fields, \"duration\")\n\n    metrics.RecordValidationFailure(errorCount, duration)\n})",{"id":1053,"title":1054,"titles":1055,"content":24,"level":19},"/v1.0.1/guides/observability#debugging-with-events","Debugging with Events",[666],{"id":1057,"title":1058,"titles":1059,"content":1060,"level":30},"/v1.0.1/guides/observability#development-logging","Development Logging",[666,1054],"func setupDevLogging() {\n    // Log everything in development\n    signals := []capitan.Signal{\n        flume.FactoryCreated,\n        flume.ProcessorRegistered,\n        flume.SchemaValidationStarted,\n        flume.SchemaBuildStarted,\n        flume.SchemaBuildCompleted,\n        // ... all signals\n    }\n\n    for _, signal := range signals {\n        s := signal\n        capitan.Handle(s, func(ctx context.Context, fields []capitan.Field) {\n            log.Printf(\"[%s] %v\", s.Name, formatFields(fields))\n        })\n    }\n}",{"id":1062,"title":1063,"titles":1064,"content":1065,"level":30},"/v1.0.1/guides/observability#pipeline-access-tracking","Pipeline Access Tracking",[666,1054],"capitan.Handle(flume.PipelineRetrieved, func(ctx context.Context, fields []capitan.Field) {\n    name := extractString(fields, \"name\")\n    found := extractBool(fields, \"found\")\n\n    if !found {\n        log.Printf(\"Pipeline not found: %s\", name)\n        metrics.PipelineMiss(name)\n    } else {\n        metrics.PipelineHit(name)\n    }\n})",{"id":1067,"title":1068,"titles":1069,"content":24,"level":19},"/v1.0.1/guides/observability#production-recommendations","Production Recommendations",[666],{"id":1071,"title":1072,"titles":1073,"content":1074,"level":30},"/v1.0.1/guides/observability#_1-monitor-build-failures","1. Monitor Build Failures",[666,1068],"Build failures indicate configuration issues: capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n    error := extractString(fields, \"error\")\n    alerting.Page(fmt.Sprintf(\"Flume build failed: %s\", error))\n})",{"id":1076,"title":1077,"titles":1078,"content":1079,"level":30},"/v1.0.1/guides/observability#_2-track-schema-versions","2. Track Schema Versions",[666,1068],"Maintain audit trail: capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n    audit.Log(audit.Entry{\n        Action:     \"schema_update\",\n        Name:       extractString(fields, \"name\"),\n        OldVersion: extractString(fields, \"old_version\"),\n        NewVersion: extractString(fields, \"new_version\"),\n        Timestamp:  time.Now(),\n    })\n})",{"id":1081,"title":1082,"titles":1083,"content":1084,"level":30},"/v1.0.1/guides/observability#_3-set-up-dashboards","3. Set Up Dashboards",[666,1068],"Key metrics to display: Schema update frequencyBuild success/failure rateBuild duration percentilesPipeline retrieval hit rateValidation error trends",{"id":1086,"title":1087,"titles":1088,"content":1089,"level":30},"/v1.0.1/guides/observability#_4-alert-on-anomalies","4. Alert on Anomalies",[666,1068],"Sudden increase in build failuresUnusually long build timesHigh pipeline miss rateValidation errors after deployment",{"id":1091,"title":150,"titles":1092,"content":1093,"level":19},"/v1.0.1/guides/observability#next-steps",[666],"Events Reference - Complete event listCapitan Documentation - Event system details html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":1095,"title":1096,"titles":1097,"content":1098,"level":9},"/v1.0.1/cookbook/common-patterns","Common Patterns",[],"Recipes and patterns for building pipelines with flume",{"id":1100,"title":1096,"titles":1101,"content":1102,"level":9},"/v1.0.1/cookbook/common-patterns#common-patterns",[],"Practical recipes for building pipelines with flume.",{"id":1104,"title":1105,"titles":1106,"content":1107,"level":19},"/v1.0.1/cookbook/common-patterns#validation-pipeline","Validation Pipeline",[1096],"A common pattern for validating input before processing: factory := flume.New[Order]()\n\nvalidateID := factory.Identity(\"validate\", \"Validates order data\")\nprocessID := factory.Identity(\"process\", \"Processes valid orders\")\nrejectID := factory.Identity(\"reject\", \"Handles invalid orders\")\nisValidID := factory.Identity(\"is-valid\", \"Checks order validity\")\n\nfactory.Add(\n    pipz.Apply(validateID, validateOrder),\n    pipz.Apply(processID, processOrder),\n    pipz.Apply(rejectID, rejectOrder),\n)\nfactory.AddPredicate(flume.Predicate[Order]{\n    Identity:  isValidID,\n    Predicate: func(ctx context.Context, o Order) bool { return o.Total > 0 },\n})\n\npipeline, _ := factory.BuildFromYAML(`\ntype: filter\npredicate: is-valid\nthen:\n  ref: process\nelse:\n  ref: reject\n`)",{"id":1109,"title":1110,"titles":1111,"content":1112,"level":19},"/v1.0.1/cookbook/common-patterns#retry-with-fallback","Retry with Fallback",[1096],"Retry an operation with a fallback on exhaustion: type: fallback\nchildren:\n  - type: retry\n    attempts: 3\n    backoff: \"100ms\"\n    child:\n      ref: primary-service\n  - ref: fallback-service",{"id":1114,"title":1115,"titles":1116,"content":1117,"level":19},"/v1.0.1/cookbook/common-patterns#fan-out-processing","Fan-Out Processing",[1096],"Process data through multiple paths concurrently: type: concurrent\nchildren:\n  - ref: save-to-database\n  - ref: send-notification\n  - ref: update-cache",{"id":1119,"title":1120,"titles":1121,"content":1122,"level":19},"/v1.0.1/cookbook/common-patterns#conditional-routing","Conditional Routing",[1096],"Route data based on type or category: type: switch\ncondition: order-type\nroutes:\n  standard:\n    ref: process-standard\n  express:\n    ref: process-express\n  priority:\n    ref: process-priority\ndefault:\n  ref: process-unknown",{"id":1124,"title":1125,"titles":1126,"content":1127,"level":19},"/v1.0.1/cookbook/common-patterns#stream-output","Stream Output",[1096],"Send processed data to a channel for async consumption: output := make(chan Order, 100)\nfactory.AddChannel(\"processed-orders\", output)\n\npipeline, _ := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n  - stream: processed-orders\n`)\n\n// Consume from channel\ngo func() {\n    for order := range output {\n        // Handle processed order\n    }\n}()",{"id":1129,"title":1130,"titles":1131,"content":1132,"level":19},"/v1.0.1/cookbook/common-patterns#circuit-breaker-protection","Circuit Breaker Protection",[1096],"Protect against cascading failures: type: circuit-breaker\nfailure_threshold: 5\nrecovery_timeout: \"30s\"\nchild:\n  ref: external-api-call",{"id":1134,"title":1135,"titles":1136,"content":1137,"level":19},"/v1.0.1/cookbook/common-patterns#rate-limited-processing","Rate-Limited Processing",[1096],"Throttle requests to downstream services: type: rate-limit\nrequests_per_second: 100\nburst_size: 10\nchild:\n  type: sequence\n  children:\n    - ref: transform\n    - ref: send-to-api html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}",{"id":1139,"title":1140,"titles":1141,"content":1142,"level":9},"/v1.0.1/reference/api","API Reference",[],"Complete reference for Flume's public API",{"id":1144,"title":1140,"titles":1145,"content":1146,"level":9},"/v1.0.1/reference/api#api-reference",[],"Complete reference for Flume's public API.",{"id":1148,"title":1149,"titles":1150,"content":24,"level":19},"/v1.0.1/reference/api#factory","Factory",[1140],{"id":1152,"title":1153,"titles":1154,"content":1155,"level":30},"/v1.0.1/reference/api#new","New",[1140,1149],"Creates a new factory for type T. func New[T pipz.Cloner[T]]() *Factory[T] Type Constraint: T must implement pipz.Cloner[T]. Example: factory := flume.New[Order]()",{"id":1157,"title":1158,"titles":1159,"content":24,"level":19},"/v1.0.1/reference/api#processor-registration","Processor Registration",[1140],{"id":1161,"title":1162,"titles":1163,"content":1164,"level":30},"/v1.0.1/reference/api#add","Add",[1140,1158],"Registers one or more processors using their intrinsic names. func (f *Factory[T]) Add(processors ...pipz.Chainable[T]) Parameters: processors - Variadic list of pipz chainables Example: factory.Add(\n    pipz.Apply(\"validate\", validateOrder),\n    pipz.Transform(\"enrich\", enrichOrder),\n)",{"id":1166,"title":1167,"titles":1168,"content":1169,"level":30},"/v1.0.1/reference/api#addwithmeta","AddWithMeta",[1140,1158],"Registers processors with metadata for introspection. func (f *Factory[T]) AddWithMeta(processors ...ProcessorMeta[T]) Parameters: processors - Variadic list of ProcessorMeta structs Example: factory.AddWithMeta(flume.ProcessorMeta[Order]{\n    Processor:   pipz.Apply(\"validate\", validateOrder),\n    Description: \"Validates order fields\",\n    Tags:        []string{\"validation\", \"required\"},\n})",{"id":1171,"title":1172,"titles":1173,"content":1174,"level":30},"/v1.0.1/reference/api#remove","Remove",[1140,1158],"Removes processors by name. func (f *Factory[T]) Remove(names ...pipz.Name) int Parameters: names - Variadic list of processor names Returns: Number of processors removed Example: removed := factory.Remove(\"old-processor\", \"deprecated\")",{"id":1176,"title":1177,"titles":1178,"content":1179,"level":30},"/v1.0.1/reference/api#hasprocessor","HasProcessor",[1140,1158],"Checks if a processor is registered. func (f *Factory[T]) HasProcessor(name pipz.Name) bool",{"id":1181,"title":1182,"titles":1183,"content":1184,"level":30},"/v1.0.1/reference/api#listprocessors","ListProcessors",[1140,1158],"Returns all registered processor names. func (f *Factory[T]) ListProcessors() []pipz.Name",{"id":1186,"title":1187,"titles":1188,"content":24,"level":19},"/v1.0.1/reference/api#predicate-registration","Predicate Registration",[1140],{"id":1190,"title":1191,"titles":1192,"content":1193,"level":30},"/v1.0.1/reference/api#addpredicate","AddPredicate",[1140,1187],"Registers predicates for filter conditions. func (f *Factory[T]) AddPredicate(predicates ...Predicate[T]) Example: factory.AddPredicate(flume.Predicate[Order]{\n    Name:        \"is-premium\",\n    Description: \"Customer has premium tier\",\n    Predicate: func(ctx context.Context, o Order) bool {\n        return o.CustomerTier == \"premium\"\n    },\n})",{"id":1195,"title":1196,"titles":1197,"content":1198,"level":30},"/v1.0.1/reference/api#removepredicate","RemovePredicate",[1140,1187],"Removes predicates by name. func (f *Factory[T]) RemovePredicate(names ...pipz.Name) int",{"id":1200,"title":1201,"titles":1202,"content":1203,"level":30},"/v1.0.1/reference/api#haspredicate","HasPredicate",[1140,1187],"Checks if a predicate is registered. func (f *Factory[T]) HasPredicate(name pipz.Name) bool",{"id":1205,"title":1206,"titles":1207,"content":1208,"level":30},"/v1.0.1/reference/api#listpredicates","ListPredicates",[1140,1187],"Returns all registered predicate names. func (f *Factory[T]) ListPredicates() []pipz.Name",{"id":1210,"title":1211,"titles":1212,"content":24,"level":19},"/v1.0.1/reference/api#condition-registration","Condition Registration",[1140],{"id":1214,"title":1215,"titles":1216,"content":1217,"level":30},"/v1.0.1/reference/api#addcondition","AddCondition",[1140,1211],"Registers conditions for switch routing. func (f *Factory[T]) AddCondition(conditions ...Condition[T]) Example: factory.AddCondition(flume.Condition[Order]{\n    Name:        \"order-status\",\n    Description: \"Returns the order status\",\n    Values:      []string{\"pending\", \"approved\", \"rejected\"},\n    Condition: func(ctx context.Context, o Order) string {\n        return o.Status\n    },\n})",{"id":1219,"title":1220,"titles":1221,"content":1222,"level":30},"/v1.0.1/reference/api#removecondition","RemoveCondition",[1140,1211],"Removes conditions by name. func (f *Factory[T]) RemoveCondition(names ...pipz.Name) int",{"id":1224,"title":1225,"titles":1226,"content":1227,"level":30},"/v1.0.1/reference/api#hascondition","HasCondition",[1140,1211],"Checks if a condition is registered. func (f *Factory[T]) HasCondition(name pipz.Name) bool",{"id":1229,"title":1230,"titles":1231,"content":1232,"level":30},"/v1.0.1/reference/api#listconditions","ListConditions",[1140,1211],"Returns all registered condition names. func (f *Factory[T]) ListConditions() []pipz.Name",{"id":1234,"title":1235,"titles":1236,"content":24,"level":19},"/v1.0.1/reference/api#channel-registration","Channel Registration",[1140],{"id":1238,"title":1239,"titles":1240,"content":1241,"level":30},"/v1.0.1/reference/api#addchannel","AddChannel",[1140,1235],"Registers a channel for stream nodes. func (f *Factory[T]) AddChannel(name string, channel chan\u003C- T) Example: ch := make(chan Order, 100)\nfactory.AddChannel(\"orders\", ch)",{"id":1243,"title":1244,"titles":1245,"content":1246,"level":30},"/v1.0.1/reference/api#getchannel","GetChannel",[1140,1235],"Retrieves a registered channel. func (f *Factory[T]) GetChannel(name string) (chan\u003C- T, bool)",{"id":1248,"title":1249,"titles":1250,"content":1251,"level":30},"/v1.0.1/reference/api#haschannel","HasChannel",[1140,1235],"Checks if a channel is registered. func (f *Factory[T]) HasChannel(name string) bool",{"id":1253,"title":1254,"titles":1255,"content":1256,"level":30},"/v1.0.1/reference/api#listchannels","ListChannels",[1140,1235],"Returns all registered channel names. func (f *Factory[T]) ListChannels() []string",{"id":1258,"title":1259,"titles":1260,"content":1261,"level":30},"/v1.0.1/reference/api#removechannel","RemoveChannel",[1140,1235],"Removes a channel from the factory. func (f *Factory[T]) RemoveChannel(name string) bool",{"id":1263,"title":209,"titles":1264,"content":24,"level":19},"/v1.0.1/reference/api#building-pipelines",[1140],{"id":1266,"title":1267,"titles":1268,"content":1269,"level":30},"/v1.0.1/reference/api#build","Build",[1140,209],"Builds a pipeline from a Schema struct. func (f *Factory[T]) Build(schema Schema) (pipz.Chainable[T], error) Example: schema := flume.Schema{\n    Version: \"1.0.0\",\n    Node: flume.Node{\n        Type: \"sequence\",\n        Children: []flume.Node{\n            {Ref: \"validate\"},\n            {Ref: \"process\"},\n        },\n    },\n}\npipeline, err := factory.Build(schema)",{"id":1271,"title":1272,"titles":1273,"content":1274,"level":30},"/v1.0.1/reference/api#buildfromyaml","BuildFromYAML",[1140,209],"Builds a pipeline from a YAML string. func (f *Factory[T]) BuildFromYAML(yamlStr string) (pipz.Chainable[T], error) Example: schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: process\n`\npipeline, err := factory.BuildFromYAML(schema)",{"id":1276,"title":1277,"titles":1278,"content":1279,"level":30},"/v1.0.1/reference/api#buildfromjson","BuildFromJSON",[1140,209],"Builds a pipeline from a JSON string. func (f *Factory[T]) BuildFromJSON(jsonStr string) (pipz.Chainable[T], error)",{"id":1281,"title":1282,"titles":1283,"content":1284,"level":30},"/v1.0.1/reference/api#buildfromfile","BuildFromFile",[1140,209],"Builds a pipeline from a file (YAML or JSON). func (f *Factory[T]) BuildFromFile(path string) (pipz.Chainable[T], error) Supported Extensions: .yaml, .yml, .json",{"id":1286,"title":1287,"titles":1288,"content":24,"level":19},"/v1.0.1/reference/api#schema-management","Schema Management",[1140],{"id":1290,"title":1291,"titles":1292,"content":1293,"level":30},"/v1.0.1/reference/api#setschema","SetSchema",[1140,1287],"Adds or updates a named schema. func (f *Factory[T]) SetSchema(name string, schema Schema) error Validates the schema, builds the pipeline, and stores both. If the schema exists, atomically updates it. Example: err := factory.SetSchema(\"order-pipeline\", schema)",{"id":1295,"title":1296,"titles":1297,"content":1298,"level":30},"/v1.0.1/reference/api#getschema","GetSchema",[1140,1287],"Retrieves a schema by name. func (f *Factory[T]) GetSchema(name string) (Schema, bool)",{"id":1300,"title":1301,"titles":1302,"content":1303,"level":30},"/v1.0.1/reference/api#removeschema","RemoveSchema",[1140,1287],"Removes a named schema. func (f *Factory[T]) RemoveSchema(name string) bool Returns: true if removed, false if not found",{"id":1305,"title":1306,"titles":1307,"content":1308,"level":30},"/v1.0.1/reference/api#listschemas","ListSchemas",[1140,1287],"Returns all registered schema names. func (f *Factory[T]) ListSchemas() []string",{"id":1310,"title":1311,"titles":1312,"content":1313,"level":30},"/v1.0.1/reference/api#bind","Bind",[1140,1287],"Creates or retrieves a binding for a schema. func (f *Factory[T]) Bind(identity pipz.Identity, schemaID string, opts ...BindingOption[T]) (*Binding[T], error) Parameters: identity - Unique identifier for this bindingschemaID - ID of schema in registry (must exist)opts - Optional configuration (e.g., WithAutoSync()) Returns: *Binding[T] on success, error if schema not found Example: pipelineID := factory.Identity(\"order-processor\", \"Processes orders\")\nbinding, err := factory.Bind(pipelineID, \"order-pipeline\", flume.WithAutoSync())\nif err != nil {\n    return err\n}\nresult, err := binding.Process(ctx, order)",{"id":1315,"title":1316,"titles":1317,"content":1318,"level":30},"/v1.0.1/reference/api#get","Get",[1140,1287],"Retrieves an existing binding by identity. func (f *Factory[T]) Get(identity pipz.Identity) *Binding[T] Returns: *Binding[T] if found, nil otherwise",{"id":1320,"title":1321,"titles":1322,"content":1323,"level":19},"/v1.0.1/reference/api#binding","Binding",[1140],"A Binding[T] represents a live pipeline bound to a schema. It provides lock-free execution via atomic.Pointer.",{"id":1325,"title":1326,"titles":1327,"content":1328,"level":30},"/v1.0.1/reference/api#process","Process",[1140,1321],"Executes the pipeline with the given data. func (b *Binding[T]) Process(ctx context.Context, data T) (T, error) Lock-free operation using atomic pointer access.",{"id":1330,"title":1331,"titles":1332,"content":1333,"level":30},"/v1.0.1/reference/api#withautosync","WithAutoSync",[1140,1321],"Option to enable automatic rebuilding when the source schema changes. flume.WithAutoSync[T]() When enabled, calls to factory.SetSchema() automatically rebuild this binding.",{"id":1335,"title":1336,"titles":1337,"content":1338,"level":30},"/v1.0.1/reference/api#binding-accessors","Binding Accessors",[1140,1321],"binding.Identity()  // Returns pipz.Identity\nbinding.SchemaID()  // Returns string (schema ID)\nbinding.AutoSync()  // Returns bool\nbinding.Pipeline()  // Returns *pipz.Pipeline[T]",{"id":1340,"title":52,"titles":1341,"content":24,"level":19},"/v1.0.1/reference/api#validation",[1140],{"id":1343,"title":1344,"titles":1345,"content":1346,"level":30},"/v1.0.1/reference/api#validateschema","ValidateSchema",[1140,52],"Validates a schema against registered components without building it. func (f *Factory[T]) ValidateSchema(schema Schema) error Returns: nil if valid, ValidationErrors otherwise Checks: Schema structure (node types, required fields)All processor references existAll predicate references existAll condition references existAll reducer references existAll error handler references existAll channel references existCircular reference detection Example: if err := factory.ValidateSchema(schema); err != nil {\n    fmt.Println(err)\n    // 3 validation errors:\n    //   1. root.children[0]: processor 'missing' not found\n    //   ...\n}",{"id":1348,"title":1349,"titles":1350,"content":1351,"level":30},"/v1.0.1/reference/api#validateschemastructure","ValidateSchemaStructure",[1140,52],"Validates schema syntax without requiring registered components. Use this for CI/CD schema linting where a configured factory is not available. func ValidateSchemaStructure(schema Schema) error Returns: nil if valid, ValidationErrors otherwise This validates: Node structure (ref vs type exclusivity, non-empty nodes)Connector constraints (required children, child counts)Configuration values (valid durations, positive numbers)Unknown node types This does NOT validate: Processor references existPredicate references existCondition references existReducer references existError handler references existChannel references exist Example: // CI/CD pipeline - validate schema files without a configured factory\nschema, _ := yaml.Unmarshal(data, &flume.Schema{})\nif err := flume.ValidateSchemaStructure(schema); err != nil {\n    log.Fatalf(\"Invalid schema: %v\", err)\n}",{"id":1353,"title":1354,"titles":1355,"content":24,"level":19},"/v1.0.1/reference/api#types","Types",[1140],{"id":1357,"title":1358,"titles":1359,"content":1360,"level":30},"/v1.0.1/reference/api#schema","Schema",[1140,1354],"type Schema struct {\n    Version string `json:\"version,omitempty\" yaml:\"version,omitempty\"`\n    Node    `yaml:\",inline\"`\n}",{"id":1362,"title":1363,"titles":1364,"content":1365,"level":30},"/v1.0.1/reference/api#node","Node",[1140,1354],"type Node struct {\n    Ref               string          // Processor reference\n    Type              string          // Connector type\n    Name              string          // Optional name override\n    Children          []Node          // For sequence, concurrent, etc.\n    Child             *Node           // For retry, timeout, etc.\n    Predicate         string          // For filter\n    Then              *Node           // For filter\n    Else              *Node           // For filter\n    Condition         string          // For switch\n    Routes            map[string]Node // For switch\n    Default           *Node           // For switch\n    Attempts          int             // For retry\n    Backoff           string          // For retry\n    Duration          string          // For timeout\n    FailureThreshold  int             // For circuit-breaker\n    RecoveryTimeout   string          // For circuit-breaker\n    RequestsPerSecond float64         // For rate-limit\n    BurstSize         int             // For rate-limit\n    Stream            string          // For stream nodes\n}",{"id":1367,"title":1368,"titles":1369,"content":1370,"level":30},"/v1.0.1/reference/api#predicate","Predicate",[1140,1354],"type Predicate[T any] struct {\n    Name        pipz.Name\n    Description string\n    Predicate   func(context.Context, T) bool\n}",{"id":1372,"title":1373,"titles":1374,"content":1375,"level":30},"/v1.0.1/reference/api#condition","Condition",[1140,1354],"type Condition[T any] struct {\n    Name        pipz.Name\n    Description string\n    Values      []string  // Possible return values\n    Condition   func(context.Context, T) string\n}",{"id":1377,"title":1378,"titles":1379,"content":1380,"level":30},"/v1.0.1/reference/api#processormeta","ProcessorMeta",[1140,1354],"type ProcessorMeta[T any] struct {\n    Processor   pipz.Chainable[T]\n    Description string\n    Tags        []string\n}",{"id":1382,"title":1383,"titles":1384,"content":1385,"level":30},"/v1.0.1/reference/api#reducer","Reducer",[1140,1354],"type Reducer[T any] struct {\n    Name        pipz.Name\n    Description string\n    Reducer     func(original T, results map[pipz.Name]T, errors map[pipz.Name]error) T\n} Used with concurrent connector to merge results from parallel execution. Example: factory.AddReducer(flume.Reducer[Order]{\n    Name:        \"merge-enrichments\",\n    Description: \"Combines data from parallel enrichment sources\",\n    Reducer: func(original Order, results map[pipz.Name]Order, errors map[pipz.Name]error) Order {\n        for _, result := range results {\n            original.Metadata = append(original.Metadata, result.Metadata...)\n        }\n        return original\n    },\n})",{"id":1387,"title":1388,"titles":1389,"content":1390,"level":30},"/v1.0.1/reference/api#errorhandler","ErrorHandler",[1140,1354],"type ErrorHandler[T any] struct {\n    Name        pipz.Name\n    Description string\n    Handler     pipz.Chainable[*pipz.Error[T]]\n} Used with handle connector to process errors from child execution. The handler receives a *pipz.Error[T] containing both the original data and the error. Error Recovery Pattern: Clear the error to indicate successful recovery: factory.AddErrorHandler(flume.ErrorHandler[Order]{\n    Name:        \"order-recovery\",\n    Description: \"Recovers failed orders by marking them for retry\",\n    Handler: pipz.Apply(\"recover\", func(ctx context.Context, e *pipz.Error[Order]) (*pipz.Error[Order], error) {\n        e.Data.Status = \"pending-retry\"\n        e.Err = nil  // Clear error - pipeline continues normally\n        return e, nil\n    }),\n}) Error Transformation Pattern: Transform the error while preserving failure state: factory.AddErrorHandler(flume.ErrorHandler[Order]{\n    Name:        \"error-enricher\",\n    Description: \"Enriches errors with context before propagating\",\n    Handler: pipz.Apply(\"enrich-error\", func(ctx context.Context, e *pipz.Error[Order]) (*pipz.Error[Order], error) {\n        e.Err = fmt.Errorf(\"order %s: %w\", e.Data.ID, e.Err)\n        return e, nil  // Error still propagates\n    }),\n}) Conditional Recovery Pattern: Recover from specific errors only: factory.AddErrorHandler(flume.ErrorHandler[Order]{\n    Name:        \"transient-recovery\",\n    Description: \"Recovers from transient errors, propagates others\",\n    Handler: pipz.Apply(\"conditional-recover\", func(ctx context.Context, e *pipz.Error[Order]) (*pipz.Error[Order], error) {\n        if errors.Is(e.Err, ErrTemporaryFailure) {\n            e.Data.Status = \"retrying\"\n            e.Err = nil  // Recover\n        }\n        // Non-transient errors propagate unchanged\n        return e, nil\n    }),\n}) Schema Usage: type: handle\nerror_handler: order-recovery\nchild:\n  ref: risky-operation",{"id":1392,"title":1393,"titles":1394,"content":1395,"level":30},"/v1.0.1/reference/api#validationerror","ValidationError",[1140,1354],"type ValidationError struct {\n    Path    []string  // Path to error in schema\n    Message string\n}\n\nfunc (e ValidationError) Error() string",{"id":1397,"title":1398,"titles":1399,"content":1400,"level":30},"/v1.0.1/reference/api#validationerrors","ValidationErrors",[1140,1354],"type ValidationErrors []ValidationError\n\nfunc (e ValidationErrors) Error() string",{"id":1402,"title":1403,"titles":1404,"content":24,"level":19},"/v1.0.1/reference/api#constants","Constants",[1140],{"id":1406,"title":1407,"titles":1408,"content":1409,"level":30},"/v1.0.1/reference/api#default-values","Default Values",[1140,1403],"const (\n    DefaultRetryAttempts           = 3\n    DefaultTimeoutDuration         = 30 * time.Second\n    DefaultCircuitBreakerThreshold = 5\n    DefaultRecoveryTimeout         = 60 * time.Second\n    DefaultRequestsPerSecond       = 10.0\n    DefaultBurstSize               = 1\n)",{"id":1411,"title":150,"titles":1412,"content":1413,"level":19},"/v1.0.1/reference/api#next-steps",[1140],"Schema Format - YAML/JSON specificationConnector Types - All connector optionsEvents - Observability signals html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sfm-E, html code.shiki .sfm-E{--shiki-default:var(--shiki-variable)}",{"id":1415,"title":1416,"titles":1417,"content":1418,"level":9},"/v1.0.1/reference/schema-format","Schema Format",[],"Complete YAML/JSON schema specification",{"id":1420,"title":1416,"titles":1421,"content":1422,"level":9},"/v1.0.1/reference/schema-format#schema-format",[],"Complete specification for Flume schema documents.",{"id":1424,"title":6,"titles":1425,"content":1426,"level":19},"/v1.0.1/reference/schema-format#overview",[1416],"Schemas can be written in YAML or JSON. This reference uses YAML examples; JSON equivalents use standard JSON syntax.",{"id":1428,"title":199,"titles":1429,"content":1430,"level":19},"/v1.0.1/reference/schema-format#schema-structure",[1416],"version: \"1.0.0\"    # Optional: schema version\ntype: sequence      # Required: connector type OR ref\nname: my-pipeline   # Optional: override connector name\nchildren:           # Depends on type\n  - ref: step1\n  - ref: step2",{"id":1432,"title":1433,"titles":1434,"content":1435,"level":19},"/v1.0.1/reference/schema-format#top-level-fields","Top-Level Fields",[1416],"FieldTypeRequiredDescriptionversionstringNoSchema version for tracking changesrefstringConditionalReference to registered processortypestringConditionalConnector typenamestringNoOverride default connector name Either ref or type is required, but not both.",{"id":1437,"title":1438,"titles":1439,"content":1440,"level":19},"/v1.0.1/reference/schema-format#processor-reference","Processor Reference",[1416],"Reference a registered processor by name: ref: validate Equivalent to calling the processor directly.",{"id":1442,"title":1443,"titles":1444,"content":24,"level":19},"/v1.0.1/reference/schema-format#connector-types","Connector Types",[1416],{"id":1446,"title":1447,"titles":1448,"content":1449,"level":30},"/v1.0.1/reference/schema-format#sequence","sequence",[1416,1443],"Sequential processing through multiple steps. type: sequence\nname: my-sequence      # Optional\nchildren:              # Required: 1+ children\n  - ref: step1\n  - ref: step2\n  - ref: step3 FieldTypeRequiredDefaultchildrenNodeYes-namestringNo\"sequence\"",{"id":1451,"title":1452,"titles":1453,"content":1454,"level":30},"/v1.0.1/reference/schema-format#concurrent","concurrent",[1416,1443],"Parallel execution with data cloning. type: concurrent\nname: parallel-steps   # Optional\nchildren:              # Required: 1+ children\n  - ref: task1\n  - ref: task2 FieldTypeRequiredDefaultchildrenNodeYes-namestringNo\"concurrent\" Note: Requires T to implement pipz.Cloner[T].",{"id":1456,"title":1457,"titles":1458,"content":1459,"level":30},"/v1.0.1/reference/schema-format#race","race",[1416,1443],"First successful result wins. type: race\nchildren:\n  - ref: fast-path\n  - ref: slow-path FieldTypeRequiredDefaultchildrenNodeYes-namestringNo\"race\" Note: Requires T to implement pipz.Cloner[T].",{"id":1461,"title":1462,"titles":1463,"content":1464,"level":30},"/v1.0.1/reference/schema-format#fallback","fallback",[1416,1443],"Try primary, use fallback on error. type: fallback\nchildren:\n  - ref: primary       # First child is primary\n  - ref: backup        # Second child is fallback FieldTypeRequiredDefaultchildrenNode (exactly 2)Yes-namestringNo\"fallback\"",{"id":1466,"title":1467,"titles":1468,"content":1469,"level":30},"/v1.0.1/reference/schema-format#retry","retry",[1416,1443],"Retry operation on failure. type: retry\nattempts: 5            # Optional\nbackoff: \"100ms\"       # Optional: enables exponential backoff\nchild:                 # Required\n  ref: flaky-operation FieldTypeRequiredDefaultchildNodeYes-attemptsintNo3backoffdurationNo(none)namestringNo\"retry\" or \"backoff\"",{"id":1471,"title":1472,"titles":1473,"content":1474,"level":30},"/v1.0.1/reference/schema-format#timeout","timeout",[1416,1443],"Enforce time limit. type: timeout\nduration: \"5s\"         # Optional\nchild:                 # Required\n  ref: slow-operation FieldTypeRequiredDefaultchildNodeYes-durationdurationNo\"30s\"namestringNo\"timeout\"",{"id":1476,"title":1477,"titles":1478,"content":1479,"level":30},"/v1.0.1/reference/schema-format#filter","filter",[1416,1443],"Conditional execution based on predicate. type: filter\npredicate: is-valid    # Required: registered predicate name\nthen:                  # Required\n  ref: process-valid\nelse:                  # Optional\n  ref: handle-invalid FieldTypeRequiredDefaultpredicatestringYes-thenNodeYes-elseNodeNo(passthrough)namestringNo\"filter-{predicate}\"",{"id":1481,"title":1482,"titles":1483,"content":1484,"level":30},"/v1.0.1/reference/schema-format#switch","switch",[1416,1443],"Multi-way routing based on condition. type: switch\ncondition: order-type  # Required: registered condition name\nroutes:                # Required: 1+ routes\n  subscription:\n    ref: handle-subscription\n  one-time:\n    ref: handle-single\ndefault:               # Optional\n  ref: handle-unknown FieldTypeRequiredDefaultconditionstringYes-routesmapstringNodeYes-defaultNodeNo(none)namestringNo\"switch-{condition}\" Default Routing: The default node is registered as a route with key \"default\". For default routing to work, your condition function must return the string \"default\" when no other route matches: factory.AddCondition(flume.Condition[Order]{\n    Name: \"order-type\",\n    Condition: func(ctx context.Context, o Order) string {\n        switch o.Type {\n        case \"subscription\":\n            return \"subscription\"\n        case \"one-time\":\n            return \"one-time\"\n        default:\n            return \"default\"  // Triggers the default route\n        }\n    },\n})",{"id":1486,"title":1487,"titles":1488,"content":1489,"level":30},"/v1.0.1/reference/schema-format#circuit-breaker","circuit-breaker",[1416,1443],"Circuit breaker pattern. type: circuit-breaker\nfailure_threshold: 5   # Optional\nrecovery_timeout: \"60s\"  # Optional\nchild:                 # Required\n  ref: external-service FieldTypeRequiredDefaultchildNodeYes-failure_thresholdintNo5recovery_timeoutdurationNo\"60s\"namestringNo\"circuit-breaker\"",{"id":1491,"title":1492,"titles":1493,"content":1494,"level":30},"/v1.0.1/reference/schema-format#rate-limit","rate-limit",[1416,1443],"Rate limiting with token bucket. type: rate-limit\nrequests_per_second: 100.0  # Optional\nburst_size: 10              # Optional\nchild:                      # Required\n  ref: rate-sensitive-api FieldTypeRequiredDefaultchildNodeYes-requests_per_secondfloatNo10.0burst_sizeintNo1namestringNo\"rate-limit\"",{"id":1496,"title":1497,"titles":1498,"content":1499,"level":30},"/v1.0.1/reference/schema-format#stream","stream",[1416,1443],"Send to registered channel. stream: output-channel  # Required: channel name\nstream_timeout: \"5s\"    # Optional: timeout for channel write\nchild:                  # Optional: continue processing\n  ref: next-step FieldTypeRequiredDefaultstreamstringYes-stream_timeoutdurationNo(blocks indefinitely)childNodeNo(none)childrenNodeNo(none)namestringNo\"stream:{name}\" Timeout Behaviour: Without stream_timeout, the stream blocks until the channel accepts the item or the context is cancelled. With stream_timeout, returns an error if the channel doesn't accept within the duration.",{"id":1501,"title":1502,"titles":1503,"content":1504,"level":30},"/v1.0.1/reference/schema-format#contest","contest",[1416,1443],"First result satisfying a predicate. type: contest\npredicate: is-valid      # Required: registered predicate name\nchildren:                # Required: 1+ children\n  - ref: source1\n  - ref: source2 FieldTypeRequiredDefaultpredicatestringYes-childrenNodeYes-namestringNo\"contest-{predicate}\" Note: Requires T to implement pipz.Cloner[T].",{"id":1506,"title":1507,"titles":1508,"content":1509,"level":30},"/v1.0.1/reference/schema-format#handle","handle",[1416,1443],"Wrap child with error handling. type: handle\nerror_handler: recovery  # Required: registered error handler name\nchild:                   # Required\n  ref: risky-operation FieldTypeRequiredDefaulterror_handlerstringYes-childNodeYes-namestringNo\"handle-{handler}\"",{"id":1511,"title":1512,"titles":1513,"content":1514,"level":30},"/v1.0.1/reference/schema-format#scaffold","scaffold",[1416,1443],"Structural grouping of children. type: scaffold\nname: validation-stage   # Optional\nchildren:                # Required: 1+ children\n  - ref: step1\n  - ref: step2 FieldTypeRequiredDefaultchildrenNodeYes-namestringNo\"scaffold\"",{"id":1516,"title":1517,"titles":1518,"content":1519,"level":30},"/v1.0.1/reference/schema-format#worker-pool","worker-pool",[1416,1443],"Bounded parallel execution. type: worker-pool\nworkers: 8               # Optional\nchildren:                # Required: 1+ children\n  - ref: task1\n  - ref: task2 FieldTypeRequiredDefaultchildrenNodeYes-workersintNo4namestringNo\"worker-pool\" Note: Requires T to implement pipz.Cloner[T].",{"id":1521,"title":1522,"titles":1523,"content":1524,"level":19},"/v1.0.1/reference/schema-format#duration-format","Duration Format",[1416],"Durations use Go's duration format: FormatExampleNanoseconds100nsMicroseconds50µs or 50usMilliseconds100msSeconds5sMinutes2mHours1hCombined1h30m, 2m30s",{"id":1526,"title":1527,"titles":1528,"content":1529,"level":19},"/v1.0.1/reference/schema-format#nesting","Nesting",[1416],"Nodes can be nested arbitrarily: type: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: is-premium\n    then:\n      type: retry\n      attempts: 3\n      child:\n        type: timeout\n        duration: \"5s\"\n        child:\n          ref: premium-process\n  - ref: finalize",{"id":1531,"title":1532,"titles":1533,"content":1534,"level":19},"/v1.0.1/reference/schema-format#json-format","JSON Format",[1416],"Equivalent JSON for the nested example: {\n  \"type\": \"sequence\",\n  \"children\": [\n    {\"ref\": \"validate\"},\n    {\n      \"type\": \"filter\",\n      \"predicate\": \"is-premium\",\n      \"then\": {\n        \"type\": \"retry\",\n        \"attempts\": 3,\n        \"child\": {\n          \"type\": \"timeout\",\n          \"duration\": \"5s\",\n          \"child\": {\"ref\": \"premium-process\"}\n        }\n      }\n    },\n    {\"ref\": \"finalize\"}\n  ]\n}",{"id":1536,"title":1537,"titles":1538,"content":1539,"level":19},"/v1.0.1/reference/schema-format#validation-rules","Validation Rules",[1416],"Either ref or type - Node must have exactly oneRequired fields - Each type has required fieldsRegistered components - All refs, predicates, conditions must existCorrect counts - fallback needs exactly 2 childrenValid durations - Duration strings must parsePositive values - attempts, threshold must be positiveNo cycles - Reference chains cannot loop",{"id":1541,"title":150,"titles":1542,"content":1543,"level":19},"/v1.0.1/reference/schema-format#next-steps",[1416],"Connector Types - Detailed connector behaviourAPI Reference - Factory methods html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}",{"id":1545,"title":1443,"titles":1546,"content":1547,"level":9},"/v1.0.1/reference/connector-types",[],"Detailed reference for all Flume connector types",{"id":1549,"title":1443,"titles":1550,"content":1551,"level":9},"/v1.0.1/reference/connector-types#connector-types",[],"Detailed reference for all Flume connector types and their behaviour.",{"id":1553,"title":1554,"titles":1555,"content":24,"level":19},"/v1.0.1/reference/connector-types#flow-control","Flow Control",[1443],{"id":1557,"title":1447,"titles":1558,"content":1559,"level":30},"/v1.0.1/reference/connector-types#sequence",[1443,1554],"Processes data through multiple steps in order. Schema: type: sequence\nchildren:\n  - ref: step1\n  - ref: step2\n  - ref: step3 Behaviour: Process step1 with input dataPass step1 output to step2Pass step2 output to step3Return step3 output Error Handling: Stops on first error, returns that error. Use Cases: Multi-stage processingPipeline compositionSequential transformations",{"id":1561,"title":1452,"titles":1562,"content":1563,"level":30},"/v1.0.1/reference/connector-types#concurrent",[1443,1554],"Executes multiple steps in parallel. Schema: type: concurrent\nchildren:\n  - ref: task1\n  - ref: task2\n  - ref: task3 Behaviour: Clone input data for each childExecute all children concurrentlyWait for all to completeMerge results Error Handling: Collects all errors, returns first error encountered. Requirements: Type T must implement pipz.Cloner[T]. Use Cases: Parallel enrichment from multiple sourcesIndependent validationsConcurrent API calls",{"id":1565,"title":1457,"titles":1566,"content":1567,"level":30},"/v1.0.1/reference/connector-types#race",[1443,1554],"Returns first successful result. Schema: type: race\nchildren:\n  - ref: fast-path\n  - ref: slow-path Behaviour: Clone input data for each childExecute all children concurrentlyReturn first successful resultCancel other executions Error Handling: Returns error only if all children fail. Requirements: Type T must implement pipz.Cloner[T]. Use Cases: Redundant data sourcesFastest-wins scenariosSpeculative execution",{"id":1569,"title":363,"titles":1570,"content":24,"level":19},"/v1.0.1/reference/connector-types#error-handling",[1443],{"id":1572,"title":1462,"titles":1573,"content":1574,"level":30},"/v1.0.1/reference/connector-types#fallback",[1443,363],"Provides backup processing on failure. Schema: type: fallback\nchildren:\n  - ref: primary\n  - ref: backup Behaviour: Execute primary with inputIf primary succeeds, return resultIf primary fails, execute backupReturn backup result or error Requirements: Exactly 2 children. Use Cases: Service redundancyGraceful degradationDefault value provision",{"id":1576,"title":1467,"titles":1577,"content":1578,"level":30},"/v1.0.1/reference/connector-types#retry",[1443,363],"Retries on transient failures. Schema: type: retry\nattempts: 3\nchild:\n  ref: operation With backoff: type: retry\nattempts: 5\nbackoff: \"100ms\"\nchild:\n  ref: operation Behaviour without backoff: Execute childIf error, retry up to attempts timesReturn success or final error Behaviour with backoff: Execute childIf error, wait backoff durationRetry with doubled wait time (exponential)Continue until success or attempts exhausted Defaults: attempts: 3backoff: none (immediate retry) Use Cases: Network timeoutsRate limit handlingTransient service failures",{"id":1580,"title":1472,"titles":1581,"content":1582,"level":30},"/v1.0.1/reference/connector-types#timeout",[1443,363],"Enforces execution time limit. Schema: type: timeout\nduration: \"5s\"\nchild:\n  ref: operation Behaviour: Start child execution with deadline contextIf completes before deadline, return resultIf deadline exceeded, cancel and return error Default: 30 seconds Error: Returns context.DeadlineExceeded Use Cases: External API callsLong-running computationsUser-facing requests",{"id":1584,"title":1487,"titles":1585,"content":1586,"level":30},"/v1.0.1/reference/connector-types#circuit-breaker",[1443,363],"Prevents repeated calls to failing services. Schema: type: circuit-breaker\nfailure_threshold: 5\nrecovery_timeout: \"30s\"\nchild:\n  ref: service States: StateBehaviourClosedNormal operation, count failuresOpenFail immediately, don't call childHalf-OpenAllow one test request Behaviour: Closed: Execute child, count failuresAfter failure_threshold failures, open circuitOpen: Return error immediatelyAfter recovery_timeout, enter half-openHalf-Open: Execute one test requestIf test succeeds, close circuitIf test fails, reopen circuit Defaults: failure_threshold: 5recovery_timeout: 60s Use Cases: External service protectionCascade failure preventionAllowing service recovery",{"id":1588,"title":1492,"titles":1589,"content":1590,"level":30},"/v1.0.1/reference/connector-types#rate-limit",[1443,363],"Controls request throughput. Schema: type: rate-limit\nrequests_per_second: 100.0\nburst_size: 10\nchild:\n  ref: operation Behaviour: Wait for token from bucketExecute childReturn result Uses token bucket algorithm: Tokens added at requests_per_second rateUp to burst_size tokens can accumulateRequest waits if no tokens available Defaults: requests_per_second: 10.0burst_size: 1 Use Cases: API rate limit complianceResource protectionFair usage enforcement",{"id":1592,"title":1593,"titles":1594,"content":24,"level":19},"/v1.0.1/reference/connector-types#routing","Routing",[1443],{"id":1596,"title":1477,"titles":1597,"content":1598,"level":30},"/v1.0.1/reference/connector-types#filter",[1443,1593],"Conditional execution based on boolean predicate. Schema: type: filter\npredicate: is-valid\nthen:\n  ref: process\nelse:\n  ref: handle-invalid  # Optional Behaviour with else: Evaluate predicateIf true, execute then branchIf false, execute else branchReturn result Behaviour without else: Evaluate predicateIf true, execute then branchIf false, pass data through unchanged Requirements: Predicate must be registered with factory. Use Cases: Conditional processingFeature flagsValidation gates",{"id":1600,"title":1482,"titles":1601,"content":1602,"level":30},"/v1.0.1/reference/connector-types#switch",[1443,1593],"Multi-way routing based on condition value. Schema: type: switch\ncondition: category\nroutes:\n  electronics:\n    ref: handle-electronics\n  clothing:\n    ref: handle-clothing\n  food:\n    ref: handle-food\ndefault:\n  ref: handle-other Behaviour: Evaluate condition functionMatch return value to route keyExecute matched routeIf no match and default exists, execute defaultIf no match and no default, pass through unchanged Default Route: The condition function should return \"default\" for default routing. Requirements: Condition must be registered with factory. Use Cases: Multi-tenant routingCategory handlingStatus-based processing",{"id":1604,"title":1605,"titles":1606,"content":24,"level":19},"/v1.0.1/reference/connector-types#streaming","Streaming",[1443],{"id":1608,"title":1497,"titles":1609,"content":1610,"level":30},"/v1.0.1/reference/connector-types#stream",[1443,1605],"Sends data to a registered channel. Schema (terminal): stream: output-channel Schema (with timeout): stream: output-channel\nstream_timeout: \"5s\" Schema (with continuation): stream: audit-channel\nchild:\n  ref: continue-processing Behaviour (terminal): Send data to channelReturn data (unchanged) Behaviour (with child): Send data to channelExecute childReturn child result Timeout Behaviour: Without stream_timeout: Blocks until channel accepts or context cancelledWith stream_timeout: Returns error if write doesn't complete within duration Requirements: Channel must be registered with factory. Use Cases: Stream processing integrationAsync event publishingAudit loggingFan-out patterns",{"id":1612,"title":1613,"titles":1614,"content":24,"level":19},"/v1.0.1/reference/connector-types#advanced","Advanced",[1443],{"id":1616,"title":1502,"titles":1617,"content":1618,"level":30},"/v1.0.1/reference/connector-types#contest",[1443,1613],"Runs children concurrently and returns the first result satisfying a predicate. Schema: type: contest\npredicate: is-valid\nchildren:\n  - ref: source1\n  - ref: source2\n  - ref: source3 Behaviour: Clone input data for each childExecute all children concurrentlyEvaluate predicate against each result as it completesReturn first result where predicate returns trueCancel remaining executions Error Handling: Returns error if no child produces a result satisfying the predicate. Requirements: Type T must implement pipz.Cloner[T]Predicate must be registered with factory Use Cases: Find first valid response from multiple sourcesSpeculative execution with validationBest-effort data retrieval",{"id":1620,"title":1507,"titles":1621,"content":1622,"level":30},"/v1.0.1/reference/connector-types#handle",[1443,1613],"Wraps a child with custom error handling logic. Schema: type: handle\nerror_handler: recovery-handler\nchild:\n  ref: risky-operation Behaviour: Execute childIf child succeeds, return resultIf child fails, pass error to handlerHandler receives *pipz.Error[T] with original data and errorReturn handler result Error Handling: Handler can recover, transform, or propagate the error. Requirements: Error handler must be registered with factory. Use Cases: Custom error recoveryError transformationContextual error handlingCompensating transactions",{"id":1624,"title":1512,"titles":1625,"content":1626,"level":30},"/v1.0.1/reference/connector-types#scaffold",[1443,1613],"Structural wrapper that groups children for organisational purposes. Schema: type: scaffold\nname: validation-stage\nchildren:\n  - ref: validate-format\n  - ref: validate-business-rules\n  - ref: validate-permissions Behaviour: Execute children in sequencePass output of each child to the nextReturn final child's output Error Handling: Stops on first error, returns that error. Use Cases: Logical grouping of related processorsPipeline organisationNamed stages for observability",{"id":1628,"title":1517,"titles":1629,"content":1630,"level":30},"/v1.0.1/reference/connector-types#worker-pool",[1443,1613],"Distributes work across a pool of workers. Schema: type: worker-pool\nworkers: 8\nchildren:\n  - ref: task1\n  - ref: task2\n  - ref: task3 Behaviour: Create pool of workers goroutinesDistribute children across workersExecute concurrently within worker limitCollect and merge results Defaults: workers: 4 Requirements: Type T must implement pipz.Cloner[T]. Use Cases: Bounded concurrencyResource-constrained parallel processingBatch processing with limits",{"id":1632,"title":1633,"titles":1634,"content":1635,"level":19},"/v1.0.1/reference/connector-types#comparison-table","Comparison Table",[1443],"TypePurposeError BehaviourCloningsequenceChain stepsStop on errorNoconcurrentParallel executionReturn first errorYesraceFirst successError if all failYesfallbackBackup processingTry backupNoretryTransient failuresRetry n timesNotimeoutTime limitCancel on timeoutNocircuit-breakerFailure protectionFail fast when openNorate-limitThroughput controlWait for tokenNofilterConditional routingFrom branchNoswitchMulti-way routingFrom routeNostreamChannel outputFrom sendNocontestFirst valid resultError if none validYeshandleError handlingFrom handlerNoscaffoldLogical groupingStop on errorNoworker-poolBounded parallelismReturn first errorYes",{"id":1637,"title":150,"titles":1638,"content":1639,"level":19},"/v1.0.1/reference/connector-types#next-steps",[1443],"Schema Format - YAML/JSON syntaxEvents - Observability signals html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}",{"id":1641,"title":1642,"titles":1643,"content":1644,"level":9},"/v1.0.1/reference/events","Events",[],"Complete reference for Flume observability events",{"id":1646,"title":1642,"titles":1647,"content":1648,"level":9},"/v1.0.1/reference/events#events",[],"Complete reference for Flume's observability events using Capitan.",{"id":1650,"title":1651,"titles":1652,"content":24,"level":19},"/v1.0.1/reference/events#signal-categories","Signal Categories",[1642],{"id":1654,"title":1655,"titles":1656,"content":1657,"level":30},"/v1.0.1/reference/events#factory-lifecycle","Factory Lifecycle",[1642,1651],"SignalDescriptionFactoryCreatedFactory instantiatedProcessorRegisteredProcessor added to factoryPredicateRegisteredPredicate added to factoryConditionRegisteredCondition added to factoryProcessorRemovedProcessor removed from factoryPredicateRemovedPredicate removed from factoryConditionRemovedCondition removed from factory",{"id":1659,"title":1660,"titles":1661,"content":1662,"level":30},"/v1.0.1/reference/events#schema-validation","Schema Validation",[1642,1651],"SignalDescriptionSchemaValidationStartedValidation beganSchemaValidationCompletedValidation successfulSchemaValidationFailedValidation found errors",{"id":1664,"title":1665,"titles":1666,"content":1667,"level":30},"/v1.0.1/reference/events#schema-building","Schema Building",[1642,1651],"SignalDescriptionSchemaBuildStartedBuild beganSchemaBuildCompletedBuild successfulSchemaBuildFailedBuild failed",{"id":1669,"title":214,"titles":1670,"content":1671,"level":30},"/v1.0.1/reference/events#dynamic-schema-management",[1642,1651],"SignalDescriptionSchemaRegisteredNew schema added via SetSchemaSchemaUpdatedExisting schema replacedSchemaRemovedSchema removedPipelineRetrievedPipeline accessed via Pipeline()",{"id":1673,"title":1674,"titles":1675,"content":1676,"level":30},"/v1.0.1/reference/events#file-operations","File Operations",[1642,1651],"SignalDescriptionSchemaFileLoadedFile read successfullySchemaFileFailedFile read failedSchemaYAMLParsedYAML parsed successfullySchemaJSONParsedJSON parsed successfullySchemaParseFailedParse failed",{"id":1678,"title":1679,"titles":1680,"content":24,"level":19},"/v1.0.1/reference/events#field-keys","Field Keys",[1642],{"id":1682,"title":1683,"titles":1684,"content":1685,"level":30},"/v1.0.1/reference/events#string-fields","String Fields",[1642,1679],"KeyTypeDescriptionKeyNamestringComponent or schema nameKeyTypestringData type (e.g., *main.Order)KeyVersionstringSchema versionKeyOldVersionstringPrevious version (on update)KeyNewVersionstringNew version (on update)KeyPathstringFile pathKeyErrorstringError message",{"id":1687,"title":1688,"titles":1689,"content":1690,"level":30},"/v1.0.1/reference/events#duration-fields","Duration Fields",[1642,1679],"KeyTypeDescriptionKeyDurationtime.DurationOperation duration",{"id":1692,"title":1693,"titles":1694,"content":1695,"level":30},"/v1.0.1/reference/events#integer-fields","Integer Fields",[1642,1679],"KeyTypeDescriptionKeyErrorCountintNumber of validation errorsKeySizeBytesintFile size in bytes",{"id":1697,"title":1698,"titles":1699,"content":1700,"level":30},"/v1.0.1/reference/events#boolean-fields","Boolean Fields",[1642,1679],"KeyTypeDescriptionKeyFoundboolWhether pipeline was found",{"id":1702,"title":1703,"titles":1704,"content":24,"level":19},"/v1.0.1/reference/events#event-details","Event Details",[1642],{"id":1706,"title":1707,"titles":1708,"content":1709,"level":30},"/v1.0.1/reference/events#factorycreated","FactoryCreated",[1642,1703],"Emitted when flume.New[T]() is called. Fields: KeyType: The type parameter T Example: capitan.Handle(flume.FactoryCreated, func(ctx context.Context, fields []capitan.Field) {\n    dataType := extractString(fields, \"type\")\n    log.Printf(\"Factory created for type: %s\", dataType)\n})",{"id":1711,"title":1712,"titles":1713,"content":1714,"level":30},"/v1.0.1/reference/events#processorregistered","ProcessorRegistered",[1642,1703],"Emitted when a processor is added. Fields: KeyName: Processor name",{"id":1716,"title":1717,"titles":1718,"content":1719,"level":30},"/v1.0.1/reference/events#schemavalidationstarted","SchemaValidationStarted",[1642,1703],"Emitted at the start of validation. Fields: None",{"id":1721,"title":1722,"titles":1723,"content":1724,"level":30},"/v1.0.1/reference/events#schemavalidationcompleted","SchemaValidationCompleted",[1642,1703],"Emitted on successful validation. Fields: KeyDuration: Validation duration",{"id":1726,"title":1727,"titles":1728,"content":1729,"level":30},"/v1.0.1/reference/events#schemavalidationfailed","SchemaValidationFailed",[1642,1703],"Emitted when validation finds errors. Fields: KeyErrorCount: Number of errorsKeyDuration: Validation duration Example: capitan.Handle(flume.SchemaValidationFailed, func(ctx context.Context, fields []capitan.Field) {\n    count := extractInt(fields, \"error_count\")\n    duration := extractDuration(fields, \"duration\")\n    log.Printf(\"Validation failed with %d errors in %v\", count, duration)\n})",{"id":1731,"title":1732,"titles":1733,"content":1734,"level":30},"/v1.0.1/reference/events#schemabuildstarted","SchemaBuildStarted",[1642,1703],"Emitted at the start of building. Fields: KeyVersion: Schema version (if present)",{"id":1736,"title":1737,"titles":1738,"content":1739,"level":30},"/v1.0.1/reference/events#schemabuildcompleted","SchemaBuildCompleted",[1642,1703],"Emitted on successful build. Fields: KeyDuration: Build durationKeyVersion: Schema version (if present)",{"id":1741,"title":1742,"titles":1743,"content":1744,"level":30},"/v1.0.1/reference/events#schemabuildfailed","SchemaBuildFailed",[1642,1703],"Emitted when build fails. Fields: KeyError: Error messageKeyDuration: Duration until failureKeyVersion: Schema version (if present)",{"id":1746,"title":1747,"titles":1748,"content":1749,"level":30},"/v1.0.1/reference/events#schemaregistered","SchemaRegistered",[1642,1703],"Emitted when a new schema is added. Fields: KeyName: Schema nameKeyVersion: Schema version (if present)",{"id":1751,"title":1752,"titles":1753,"content":1754,"level":30},"/v1.0.1/reference/events#schemaupdated","SchemaUpdated",[1642,1703],"Emitted when an existing schema is replaced. Fields: KeyName: Schema nameKeyOldVersion: Previous version (if present)KeyNewVersion: New version (if present) Example: capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n    name := extractString(fields, \"name\")\n    oldV := extractString(fields, \"old_version\")\n    newV := extractString(fields, \"new_version\")\n    log.Printf(\"Schema %s: %s -> %s\", name, oldV, newV)\n})",{"id":1756,"title":1757,"titles":1758,"content":1759,"level":30},"/v1.0.1/reference/events#pipelineretrieved","PipelineRetrieved",[1642,1703],"Emitted when Pipeline() is called. Fields: KeyName: Schema name requestedKeyFound: Whether pipeline exists Example: capitan.Handle(flume.PipelineRetrieved, func(ctx context.Context, fields []capitan.Field) {\n    name := extractString(fields, \"name\")\n    found := extractBool(fields, \"found\")\n    if !found {\n        log.Printf(\"Pipeline not found: %s\", name)\n    }\n})",{"id":1761,"title":1762,"titles":1763,"content":1764,"level":30},"/v1.0.1/reference/events#schemafileloaded","SchemaFileLoaded",[1642,1703],"Emitted when a file is read. Fields: KeyPath: File pathKeySizeBytes: File size",{"id":1766,"title":1767,"titles":1768,"content":1769,"level":30},"/v1.0.1/reference/events#schemaparsefailed","SchemaParseFailed",[1642,1703],"Emitted when parsing fails. Fields: KeyPath: File path (if from file)KeyError: Parse error message",{"id":1771,"title":1772,"titles":1773,"content":24,"level":19},"/v1.0.1/reference/events#handler-patterns","Handler Patterns",[1642],{"id":1775,"title":1776,"titles":1777,"content":1778,"level":30},"/v1.0.1/reference/events#complete-logging-handler","Complete Logging Handler",[1642,1772],"func setupLogging() {\n    signals := map[capitan.Signal]string{\n        flume.FactoryCreated:            \"Factory created\",\n        flume.ProcessorRegistered:       \"Processor registered\",\n        flume.SchemaValidationStarted:   \"Validation started\",\n        flume.SchemaValidationCompleted: \"Validation completed\",\n        flume.SchemaValidationFailed:    \"Validation failed\",\n        flume.SchemaBuildStarted:        \"Build started\",\n        flume.SchemaBuildCompleted:      \"Build completed\",\n        flume.SchemaBuildFailed:         \"Build failed\",\n        flume.SchemaRegistered:          \"Schema registered\",\n        flume.SchemaUpdated:             \"Schema updated\",\n        flume.SchemaRemoved:             \"Schema removed\",\n        flume.PipelineRetrieved:         \"Pipeline retrieved\",\n    }\n\n    for signal, message := range signals {\n        s, m := signal, message\n        capitan.Handle(s, func(ctx context.Context, fields []capitan.Field) {\n            log.Printf(\"[FLUME] %s: %v\", m, formatFields(fields))\n        })\n    }\n}\n\nfunc formatFields(fields []capitan.Field) string {\n    parts := make([]string, 0, len(fields))\n    for _, f := range fields {\n        parts = append(parts, fmt.Sprintf(\"%s=%v\", f.Key, f.Value()))\n    }\n    return strings.Join(parts, \", \")\n}",{"id":1780,"title":1781,"titles":1782,"content":1783,"level":30},"/v1.0.1/reference/events#metrics-handler","Metrics Handler",[1642,1772],"func setupMetrics() {\n    // Build latency histogram\n    capitan.Handle(flume.SchemaBuildCompleted, func(ctx context.Context, fields []capitan.Field) {\n        for _, f := range fields {\n            if f.Key == \"duration\" {\n                metrics.RecordBuildLatency(f.Duration())\n            }\n        }\n    })\n\n    // Error counter\n    capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n        metrics.IncrBuildErrors()\n    })\n\n    capitan.Handle(flume.SchemaValidationFailed, func(ctx context.Context, fields []capitan.Field) {\n        metrics.IncrValidationErrors()\n    })\n}",{"id":1785,"title":1786,"titles":1787,"content":1788,"level":30},"/v1.0.1/reference/events#alerting-handler","Alerting Handler",[1642,1772],"func setupAlerting() {\n    capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n        errMsg := extractString(fields, \"error\")\n        alerting.Send(alerting.Error, fmt.Sprintf(\"Flume build failed: %s\", errMsg))\n    })\n\n    capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n        name := extractString(fields, \"name\")\n        oldV := extractString(fields, \"old_version\")\n        newV := extractString(fields, \"new_version\")\n\n        // Alert on major version changes\n        if isMajorChange(oldV, newV) {\n            alerting.Send(alerting.Warning,\n                fmt.Sprintf(\"Major version change: %s %s->%s\", name, oldV, newV))\n        }\n    })\n}",{"id":1790,"title":1791,"titles":1792,"content":1793,"level":19},"/v1.0.1/reference/events#helper-functions","Helper Functions",[1642],"func extractString(fields []capitan.Field, key string) string {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.String()\n        }\n    }\n    return \"\"\n}\n\nfunc extractInt(fields []capitan.Field, key string) int {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.Int()\n        }\n    }\n    return 0\n}\n\nfunc extractBool(fields []capitan.Field, key string) bool {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.Bool()\n        }\n    }\n    return false\n}\n\nfunc extractDuration(fields []capitan.Field, key string) time.Duration {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.Duration()\n        }\n    }\n    return 0\n}",{"id":1795,"title":150,"titles":1796,"content":1797,"level":19},"/v1.0.1/reference/events#next-steps",[1642],"Observability Guide - Monitoring patternsCapitan Documentation - Event system html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}",[1799],{"title":1800,"path":1801,"stem":1802,"children":1803,"page":1818},"V101","/v1.0.1","v1.0.1",[1804,1806,1819,1833,1840],{"title":6,"path":5,"stem":1805,"description":8},"v1.0.1/1.overview",{"title":66,"path":1807,"stem":1808,"children":1809,"page":1818},"/v1.0.1/learn","v1.0.1/2.learn",[1810,1812,1814,1816],{"title":81,"path":80,"stem":1811,"description":83},"v1.0.1/2.learn/1.quickstart",{"title":155,"path":154,"stem":1813,"description":157},"v1.0.1/2.learn/2.core-concepts",{"title":16,"path":246,"stem":1815,"description":248},"v1.0.1/2.learn/3.architecture",{"title":209,"path":330,"stem":1817,"description":332},"v1.0.1/2.learn/4.building-pipelines",false,{"title":71,"path":1820,"stem":1821,"children":1822,"page":1818},"/v1.0.1/guides","v1.0.1/3.guides",[1823,1825,1827,1829,1831],{"title":443,"path":442,"stem":1824,"description":445},"v1.0.1/3.guides/1.schema-design",{"title":219,"path":583,"stem":1826,"description":585},"v1.0.1/3.guides/2.hot-reloading",{"title":363,"path":712,"stem":1828,"description":714},"v1.0.1/3.guides/3.error-handling",{"title":879,"path":878,"stem":1830,"description":881},"v1.0.1/3.guides/4.testing",{"title":666,"path":974,"stem":1832,"description":976},"v1.0.1/3.guides/5.observability",{"title":1834,"path":1835,"stem":1836,"children":1837,"page":1818},"Cookbook","/v1.0.1/cookbook","v1.0.1/4.cookbook",[1838],{"title":1096,"path":1095,"stem":1839,"description":1098},"v1.0.1/4.cookbook/1.common-patterns",{"title":76,"path":1841,"stem":1842,"children":1843,"page":1818},"/v1.0.1/reference","v1.0.1/5.reference",[1844,1846,1848,1850],{"title":1140,"path":1139,"stem":1845,"description":1142},"v1.0.1/5.reference/1.api",{"title":1416,"path":1415,"stem":1847,"description":1418},"v1.0.1/5.reference/2.schema-format",{"title":1443,"path":1545,"stem":1849,"description":1547},"v1.0.1/5.reference/3.connector-types",{"title":1642,"path":1641,"stem":1851,"description":1644},"v1.0.1/5.reference/4.events",[1853],{"title":1800,"path":1801,"stem":1802,"children":1854,"page":1818},[1855,1856,1862,1869,1872],{"title":6,"path":5,"stem":1805},{"title":66,"path":1807,"stem":1808,"children":1857,"page":1818},[1858,1859,1860,1861],{"title":81,"path":80,"stem":1811},{"title":155,"path":154,"stem":1813},{"title":16,"path":246,"stem":1815},{"title":209,"path":330,"stem":1817},{"title":71,"path":1820,"stem":1821,"children":1863,"page":1818},[1864,1865,1866,1867,1868],{"title":443,"path":442,"stem":1824},{"title":219,"path":583,"stem":1826},{"title":363,"path":712,"stem":1828},{"title":879,"path":878,"stem":1830},{"title":666,"path":974,"stem":1832},{"title":1834,"path":1835,"stem":1836,"children":1870,"page":1818},[1871],{"title":1096,"path":1095,"stem":1839},{"title":76,"path":1841,"stem":1842,"children":1873,"page":1818},[1874,1875,1876,1877],{"title":1140,"path":1139,"stem":1845},{"title":1416,"path":1415,"stem":1847},{"title":1443,"path":1545,"stem":1849},{"title":1642,"path":1641,"stem":1851},[1879,3704,4152],{"id":1880,"title":1881,"body":1882,"description":24,"extension":3697,"icon":3698,"meta":3699,"navigation":2360,"path":3700,"seo":3701,"stem":3702,"__hash__":3703},"resources/readme.md","README",{"type":1883,"value":1884,"toc":3680},"minimark",[1885,1890,1958,1967,1972,2485,2488,2491,2508,2512,3113,3116,3216,3220,3267,3271,3277,3280,3387,3399,3402,3405,3546,3549,3556,3560,3586,3589,3618,3621,3629,3632,3655,3659,3667,3670,3676],[1886,1887,1889],"h1",{"id":1888},"flume","Flume",[1891,1892,1893,1904,1912,1920,1928,1936,1943,1950],"p",{},[1894,1895,1899],"a",{"href":1896,"rel":1897},"https://github.com/zoobz-io/flume/actions/workflows/ci.yml",[1898],"nofollow",[1900,1901],"img",{"alt":1902,"src":1903},"CI Status","https://github.com/zoobz-io/flume/workflows/CI/badge.svg",[1894,1905,1908],{"href":1906,"rel":1907},"https://codecov.io/gh/zoobz-io/flume",[1898],[1900,1909],{"alt":1910,"src":1911},"codecov","https://codecov.io/gh/zoobz-io/flume/graph/badge.svg?branch=main",[1894,1913,1916],{"href":1914,"rel":1915},"https://goreportcard.com/report/github.com/zoobz-io/flume",[1898],[1900,1917],{"alt":1918,"src":1919},"Go Report Card","https://goreportcard.com/badge/github.com/zoobz-io/flume",[1894,1921,1924],{"href":1922,"rel":1923},"https://github.com/zoobz-io/flume/security/code-scanning",[1898],[1900,1925],{"alt":1926,"src":1927},"CodeQL","https://github.com/zoobz-io/flume/workflows/CodeQL/badge.svg",[1894,1929,1932],{"href":1930,"rel":1931},"https://pkg.go.dev/github.com/zoobz-io/flume",[1898],[1900,1933],{"alt":1934,"src":1935},"Go Reference","https://pkg.go.dev/badge/github.com/zoobz-io/flume.svg",[1894,1937,1939],{"href":1938},"LICENSE",[1900,1940],{"alt":1941,"src":1942},"License","https://img.shields.io/github/license/zoobz-io/flume",[1894,1944,1946],{"href":1945},"go.mod",[1900,1947],{"alt":1948,"src":1949},"Go Version","https://img.shields.io/github/go-mod/go-version/zoobz-io/flume",[1894,1951,1954],{"href":1952,"rel":1953},"https://github.com/zoobz-io/flume/releases",[1898],[1900,1955],{"alt":1956,"src":1957},"Release","https://img.shields.io/github/v/release/zoobz-io/flume",[1891,1959,1960,1961,1966],{},"A dynamic pipeline factory for ",[1894,1962,1965],{"href":1963,"rel":1964},"https://github.com/zoobz-io/pipz",[1898],"pipz"," that enables schema-driven pipeline construction with hot-reloading capabilities.",[1968,1969,1971],"h2",{"id":1970},"logic-in-code-structure-in-schema","Logic in Code, Structure in Schema",[1973,1974,1978],"pre",{"className":1975,"code":1976,"language":1977,"meta":24,"style":24},"language-go shiki shiki-themes","// 1. Register components\nfactory := flume.New[Order]()\nfactory.Add(\n    pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n        if o.Total \u003C= 0 {\n            return o, fmt.Errorf(\"invalid total\")\n        }\n        return o, nil\n    }),\n    pipz.Apply(\"apply-discount\", func(ctx context.Context, o Order) (Order, error) {\n        o.Total *= 0.9 // 10% discount\n        return o, nil\n    }),\n)\nfactory.AddPredicate(flume.Predicate[Order]{\n    Name:      \"is-premium\",\n    Predicate: func(ctx context.Context, o Order) bool { return o.Tier == \"premium\" },\n})\n\n// 2. Build from schema\npipeline, _ := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: is-premium\n    then:\n      ref: apply-discount\n`)\n\n// 3. Process data\nresult, err := pipeline.Process(ctx, order)\n","go",[1979,1980,1981,1989,2018,2029,2094,2117,2143,2149,2162,2168,2216,2235,2246,2251,2256,2280,2296,2349,2355,2362,2368,2393,2399,2405,2411,2417,2423,2429,2435,2443,2448,2454],"code",{"__ignoreMap":24},[1982,1983,1985],"span",{"class":1984,"line":9},"line",[1982,1986,1988],{"class":1987},"sLkEo","// 1. Register components\n",[1982,1990,1991,1995,1998,2001,2005,2008,2011,2015],{"class":1984,"line":19},[1982,1992,1994],{"class":1993},"sh8_p","factory",[1982,1996,1997],{"class":1993}," :=",[1982,1999,2000],{"class":1993}," flume",[1982,2002,2004],{"class":2003},"sq5bi",".",[1982,2006,1153],{"class":2007},"s5klm",[1982,2009,2010],{"class":2003},"[",[1982,2012,2014],{"class":2013},"sYBwO","Order",[1982,2016,2017],{"class":2003},"]()\n",[1982,2019,2020,2022,2024,2026],{"class":1984,"line":30},[1982,2021,1994],{"class":1993},[1982,2023,2004],{"class":2003},[1982,2025,1162],{"class":2007},[1982,2027,2028],{"class":2003},"(\n",[1982,2030,2032,2035,2037,2040,2043,2047,2050,2054,2056,2060,2063,2065,2068,2070,2073,2076,2079,2082,2084,2086,2089,2091],{"class":1984,"line":2031},4,[1982,2033,2034],{"class":1993},"    pipz",[1982,2036,2004],{"class":2003},[1982,2038,2039],{"class":2007},"Apply",[1982,2041,2042],{"class":2003},"(",[1982,2044,2046],{"class":2045},"sxAnc","\"validate\"",[1982,2048,2049],{"class":2003},",",[1982,2051,2053],{"class":2052},"sUt3r"," func",[1982,2055,2042],{"class":2003},[1982,2057,2059],{"class":2058},"sSYET","ctx",[1982,2061,2062],{"class":2013}," context",[1982,2064,2004],{"class":2003},[1982,2066,2067],{"class":2013},"Context",[1982,2069,2049],{"class":2003},[1982,2071,2072],{"class":2058}," o",[1982,2074,2075],{"class":2013}," Order",[1982,2077,2078],{"class":2003},")",[1982,2080,2081],{"class":2003}," (",[1982,2083,2014],{"class":2013},[1982,2085,2049],{"class":2003},[1982,2087,2088],{"class":2013}," error",[1982,2090,2078],{"class":2003},[1982,2092,2093],{"class":2003}," {\n",[1982,2095,2097,2101,2103,2105,2108,2111,2115],{"class":1984,"line":2096},5,[1982,2098,2100],{"class":2099},"sW3Qg","        if",[1982,2102,2072],{"class":1993},[1982,2104,2004],{"class":2003},[1982,2106,2107],{"class":1993},"Total",[1982,2109,2110],{"class":2099}," \u003C=",[1982,2112,2114],{"class":2113},"sMAmT"," 0",[1982,2116,2093],{"class":2003},[1982,2118,2120,2123,2125,2127,2130,2132,2135,2137,2140],{"class":1984,"line":2119},6,[1982,2121,2122],{"class":2099},"            return",[1982,2124,2072],{"class":1993},[1982,2126,2049],{"class":2003},[1982,2128,2129],{"class":1993}," fmt",[1982,2131,2004],{"class":2003},[1982,2133,2134],{"class":2007},"Errorf",[1982,2136,2042],{"class":2003},[1982,2138,2139],{"class":2045},"\"invalid total\"",[1982,2141,2142],{"class":2003},")\n",[1982,2144,2146],{"class":1984,"line":2145},7,[1982,2147,2148],{"class":2003},"        }\n",[1982,2150,2152,2155,2157,2159],{"class":1984,"line":2151},8,[1982,2153,2154],{"class":2099},"        return",[1982,2156,2072],{"class":1993},[1982,2158,2049],{"class":2003},[1982,2160,2161],{"class":2052}," nil\n",[1982,2163,2165],{"class":1984,"line":2164},9,[1982,2166,2167],{"class":2003},"    }),\n",[1982,2169,2171,2173,2175,2177,2179,2182,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202,2204,2206,2208,2210,2212,2214],{"class":1984,"line":2170},10,[1982,2172,2034],{"class":1993},[1982,2174,2004],{"class":2003},[1982,2176,2039],{"class":2007},[1982,2178,2042],{"class":2003},[1982,2180,2181],{"class":2045},"\"apply-discount\"",[1982,2183,2049],{"class":2003},[1982,2185,2053],{"class":2052},[1982,2187,2042],{"class":2003},[1982,2189,2059],{"class":2058},[1982,2191,2062],{"class":2013},[1982,2193,2004],{"class":2003},[1982,2195,2067],{"class":2013},[1982,2197,2049],{"class":2003},[1982,2199,2072],{"class":2058},[1982,2201,2075],{"class":2013},[1982,2203,2078],{"class":2003},[1982,2205,2081],{"class":2003},[1982,2207,2014],{"class":2013},[1982,2209,2049],{"class":2003},[1982,2211,2088],{"class":2013},[1982,2213,2078],{"class":2003},[1982,2215,2093],{"class":2003},[1982,2217,2219,2222,2224,2226,2229,2232],{"class":1984,"line":2218},11,[1982,2220,2221],{"class":1993},"        o",[1982,2223,2004],{"class":2003},[1982,2225,2107],{"class":1993},[1982,2227,2228],{"class":1993}," *=",[1982,2230,2231],{"class":2113}," 0.9",[1982,2233,2234],{"class":1987}," // 10% discount\n",[1982,2236,2238,2240,2242,2244],{"class":1984,"line":2237},12,[1982,2239,2154],{"class":2099},[1982,2241,2072],{"class":1993},[1982,2243,2049],{"class":2003},[1982,2245,2161],{"class":2052},[1982,2247,2249],{"class":1984,"line":2248},13,[1982,2250,2167],{"class":2003},[1982,2252,2254],{"class":1984,"line":2253},14,[1982,2255,2142],{"class":2003},[1982,2257,2259,2261,2263,2265,2267,2269,2271,2273,2275,2277],{"class":1984,"line":2258},15,[1982,2260,1994],{"class":1993},[1982,2262,2004],{"class":2003},[1982,2264,1191],{"class":2007},[1982,2266,2042],{"class":2003},[1982,2268,1888],{"class":2013},[1982,2270,2004],{"class":2003},[1982,2272,1368],{"class":2013},[1982,2274,2010],{"class":2003},[1982,2276,2014],{"class":2013},[1982,2278,2279],{"class":2003},"]{\n",[1982,2281,2283,2287,2290,2293],{"class":1984,"line":2282},16,[1982,2284,2286],{"class":2285},"sBGCq","    Name",[1982,2288,2289],{"class":2003},":",[1982,2291,2292],{"class":2045},"      \"is-premium\"",[1982,2294,2295],{"class":2003},",\n",[1982,2297,2299,2302,2304,2306,2308,2310,2312,2314,2316,2318,2320,2322,2324,2327,2330,2333,2335,2337,2340,2343,2346],{"class":1984,"line":2298},17,[1982,2300,2301],{"class":2285},"    Predicate",[1982,2303,2289],{"class":2003},[1982,2305,2053],{"class":2052},[1982,2307,2042],{"class":2003},[1982,2309,2059],{"class":2058},[1982,2311,2062],{"class":2013},[1982,2313,2004],{"class":2003},[1982,2315,2067],{"class":2013},[1982,2317,2049],{"class":2003},[1982,2319,2072],{"class":2058},[1982,2321,2075],{"class":2013},[1982,2323,2078],{"class":2003},[1982,2325,2326],{"class":2013}," bool",[1982,2328,2329],{"class":2003}," {",[1982,2331,2332],{"class":2099}," return",[1982,2334,2072],{"class":1993},[1982,2336,2004],{"class":2003},[1982,2338,2339],{"class":1993},"Tier",[1982,2341,2342],{"class":2099}," ==",[1982,2344,2345],{"class":2045}," \"premium\"",[1982,2347,2348],{"class":2003}," },\n",[1982,2350,2352],{"class":1984,"line":2351},18,[1982,2353,2354],{"class":2003},"})\n",[1982,2356,2358],{"class":1984,"line":2357},19,[1982,2359,2361],{"emptyLinePlaceholder":2360},true,"\n",[1982,2363,2365],{"class":1984,"line":2364},20,[1982,2366,2367],{"class":1987},"// 2. Build from schema\n",[1982,2369,2371,2374,2376,2379,2381,2384,2386,2388,2390],{"class":1984,"line":2370},21,[1982,2372,2373],{"class":1993},"pipeline",[1982,2375,2049],{"class":2003},[1982,2377,2378],{"class":1993}," _",[1982,2380,1997],{"class":1993},[1982,2382,2383],{"class":1993}," factory",[1982,2385,2004],{"class":2003},[1982,2387,1272],{"class":2007},[1982,2389,2042],{"class":2003},[1982,2391,2392],{"class":2045},"`\n",[1982,2394,2396],{"class":1984,"line":2395},22,[1982,2397,2398],{"class":2045},"type: sequence\n",[1982,2400,2402],{"class":1984,"line":2401},23,[1982,2403,2404],{"class":2045},"children:\n",[1982,2406,2408],{"class":1984,"line":2407},24,[1982,2409,2410],{"class":2045},"  - ref: validate\n",[1982,2412,2414],{"class":1984,"line":2413},25,[1982,2415,2416],{"class":2045},"  - type: filter\n",[1982,2418,2420],{"class":1984,"line":2419},26,[1982,2421,2422],{"class":2045},"    predicate: is-premium\n",[1982,2424,2426],{"class":1984,"line":2425},27,[1982,2427,2428],{"class":2045},"    then:\n",[1982,2430,2432],{"class":1984,"line":2431},28,[1982,2433,2434],{"class":2045},"      ref: apply-discount\n",[1982,2436,2438,2441],{"class":1984,"line":2437},29,[1982,2439,2440],{"class":2045},"`",[1982,2442,2142],{"class":2003},[1982,2444,2446],{"class":1984,"line":2445},30,[1982,2447,2361],{"emptyLinePlaceholder":2360},[1982,2449,2451],{"class":1984,"line":2450},31,[1982,2452,2453],{"class":1987},"// 3. Process data\n",[1982,2455,2457,2460,2462,2465,2467,2470,2472,2474,2476,2478,2480,2483],{"class":1984,"line":2456},32,[1982,2458,2459],{"class":1993},"result",[1982,2461,2049],{"class":2003},[1982,2463,2464],{"class":1993}," err",[1982,2466,1997],{"class":1993},[1982,2468,2469],{"class":1993}," pipeline",[1982,2471,2004],{"class":2003},[1982,2473,1326],{"class":2007},[1982,2475,2042],{"class":2003},[1982,2477,2059],{"class":1993},[1982,2479,2049],{"class":2003},[1982,2481,2482],{"class":1993}," order",[1982,2484,2142],{"class":2003},[1968,2486,90],{"id":2487},"installation",[1891,2489,2490],{},"Requires Go 1.24+",[1973,2492,2496],{"className":2493,"code":2494,"language":2495,"meta":24,"style":24},"language-bash shiki shiki-themes","go get github.com/zoobz-io/flume\n","bash",[1979,2497,2498],{"__ignoreMap":24},[1982,2499,2500,2502,2505],{"class":1984,"line":9},[1982,2501,1977],{"class":2007},[1982,2503,2504],{"class":2045}," get",[1982,2506,2507],{"class":2045}," github.com/zoobz-io/flume\n",[1968,2509,2511],{"id":2510},"quick-start","Quick Start",[1973,2513,2515],{"className":1975,"code":2514,"language":1977,"meta":24,"style":24},"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"github.com/zoobz-io/flume\"\n    \"github.com/zoobz-io/pipz\"\n)\n\ntype Order struct {\n    ID    string\n    Total float64\n}\n\nfunc (o Order) Clone() Order { return Order{ID: o.ID, Total: o.Total} }\n\nfunc main() {\n    factory := flume.New[Order]()\n\n    // Register processors\n    factory.Add(\n        pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n            if o.Total \u003C= 0 {\n                return o, fmt.Errorf(\"invalid total\")\n            }\n            return o, nil\n        }),\n        pipz.Transform(\"enrich\", func(ctx context.Context, o Order) Order {\n            o.ID = \"ORD-\" + o.ID\n            return o\n        }),\n    )\n\n    // Build pipeline from YAML\n    pipeline, err := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n`)\n    if err != nil {\n        panic(err)\n    }\n\n    // Process\n    result, err := pipeline.Process(context.Background(), Order{ID: \"123\", Total: 99.99})\n    fmt.Printf(\"Result: %+v, Error: %v\\n\", result, err)\n}\n",[1979,2516,2517,2525,2529,2538,2543,2548,2553,2558,2562,2566,2578,2586,2594,2599,2603,2664,2668,2679,2698,2702,2707,2717,2764,2781,2802,2807,2817,2822,2862,2887,2894,2898,2903,2908,2914,2936,2941,2946,2951,2957,2964,2980,2994,3000,3005,3011,3064,3108],{"__ignoreMap":24},[1982,2518,2519,2522],{"class":1984,"line":9},[1982,2520,2521],{"class":2052},"package",[1982,2523,2524],{"class":2013}," main\n",[1982,2526,2527],{"class":1984,"line":19},[1982,2528,2361],{"emptyLinePlaceholder":2360},[1982,2530,2531,2534],{"class":1984,"line":30},[1982,2532,2533],{"class":2052},"import",[1982,2535,2537],{"class":2536},"soy-K"," (\n",[1982,2539,2540],{"class":1984,"line":2031},[1982,2541,2542],{"class":2045},"    \"context\"\n",[1982,2544,2545],{"class":1984,"line":2096},[1982,2546,2547],{"class":2045},"    \"fmt\"\n",[1982,2549,2550],{"class":1984,"line":2119},[1982,2551,2552],{"class":2045},"    \"github.com/zoobz-io/flume\"\n",[1982,2554,2555],{"class":1984,"line":2145},[1982,2556,2557],{"class":2045},"    \"github.com/zoobz-io/pipz\"\n",[1982,2559,2560],{"class":1984,"line":2151},[1982,2561,2142],{"class":2536},[1982,2563,2564],{"class":1984,"line":2164},[1982,2565,2361],{"emptyLinePlaceholder":2360},[1982,2567,2568,2571,2573,2576],{"class":1984,"line":2170},[1982,2569,2570],{"class":2052},"type",[1982,2572,2075],{"class":2013},[1982,2574,2575],{"class":2052}," struct",[1982,2577,2093],{"class":2003},[1982,2579,2580,2583],{"class":1984,"line":2218},[1982,2581,2582],{"class":2285},"    ID",[1982,2584,2585],{"class":2013},"    string\n",[1982,2587,2588,2591],{"class":1984,"line":2237},[1982,2589,2590],{"class":2285},"    Total",[1982,2592,2593],{"class":2013}," float64\n",[1982,2595,2596],{"class":1984,"line":2248},[1982,2597,2598],{"class":2003},"}\n",[1982,2600,2601],{"class":1984,"line":2253},[1982,2602,2361],{"emptyLinePlaceholder":2360},[1982,2604,2605,2608,2610,2613,2615,2617,2620,2623,2625,2627,2629,2631,2634,2637,2639,2641,2643,2645,2647,2650,2652,2654,2656,2658,2661],{"class":1984,"line":2258},[1982,2606,2607],{"class":2052},"func",[1982,2609,2081],{"class":2003},[1982,2611,2612],{"class":2058},"o ",[1982,2614,2014],{"class":2013},[1982,2616,2078],{"class":2003},[1982,2618,2619],{"class":2007}," Clone",[1982,2621,2622],{"class":2003},"()",[1982,2624,2075],{"class":2013},[1982,2626,2329],{"class":2003},[1982,2628,2332],{"class":2099},[1982,2630,2075],{"class":2013},[1982,2632,2633],{"class":2003},"{",[1982,2635,2636],{"class":2285},"ID",[1982,2638,2289],{"class":2003},[1982,2640,2072],{"class":1993},[1982,2642,2004],{"class":2003},[1982,2644,2636],{"class":1993},[1982,2646,2049],{"class":2003},[1982,2648,2649],{"class":2285}," Total",[1982,2651,2289],{"class":2003},[1982,2653,2072],{"class":1993},[1982,2655,2004],{"class":2003},[1982,2657,2107],{"class":1993},[1982,2659,2660],{"class":2003},"}",[1982,2662,2663],{"class":2003}," }\n",[1982,2665,2666],{"class":1984,"line":2282},[1982,2667,2361],{"emptyLinePlaceholder":2360},[1982,2669,2670,2672,2675,2677],{"class":1984,"line":2298},[1982,2671,2607],{"class":2052},[1982,2673,2674],{"class":2007}," main",[1982,2676,2622],{"class":2003},[1982,2678,2093],{"class":2003},[1982,2680,2681,2684,2686,2688,2690,2692,2694,2696],{"class":1984,"line":2351},[1982,2682,2683],{"class":1993},"    factory",[1982,2685,1997],{"class":1993},[1982,2687,2000],{"class":1993},[1982,2689,2004],{"class":2003},[1982,2691,1153],{"class":2007},[1982,2693,2010],{"class":2003},[1982,2695,2014],{"class":2013},[1982,2697,2017],{"class":2003},[1982,2699,2700],{"class":1984,"line":2357},[1982,2701,2361],{"emptyLinePlaceholder":2360},[1982,2703,2704],{"class":1984,"line":2364},[1982,2705,2706],{"class":1987},"    // Register processors\n",[1982,2708,2709,2711,2713,2715],{"class":1984,"line":2370},[1982,2710,2683],{"class":1993},[1982,2712,2004],{"class":2003},[1982,2714,1162],{"class":2007},[1982,2716,2028],{"class":2003},[1982,2718,2719,2722,2724,2726,2728,2730,2732,2734,2736,2738,2740,2742,2744,2746,2748,2750,2752,2754,2756,2758,2760,2762],{"class":1984,"line":2395},[1982,2720,2721],{"class":1993},"        pipz",[1982,2723,2004],{"class":2003},[1982,2725,2039],{"class":2007},[1982,2727,2042],{"class":2003},[1982,2729,2046],{"class":2045},[1982,2731,2049],{"class":2003},[1982,2733,2053],{"class":2052},[1982,2735,2042],{"class":2003},[1982,2737,2059],{"class":2058},[1982,2739,2062],{"class":2013},[1982,2741,2004],{"class":2003},[1982,2743,2067],{"class":2013},[1982,2745,2049],{"class":2003},[1982,2747,2072],{"class":2058},[1982,2749,2075],{"class":2013},[1982,2751,2078],{"class":2003},[1982,2753,2081],{"class":2003},[1982,2755,2014],{"class":2013},[1982,2757,2049],{"class":2003},[1982,2759,2088],{"class":2013},[1982,2761,2078],{"class":2003},[1982,2763,2093],{"class":2003},[1982,2765,2766,2769,2771,2773,2775,2777,2779],{"class":1984,"line":2401},[1982,2767,2768],{"class":2099},"            if",[1982,2770,2072],{"class":1993},[1982,2772,2004],{"class":2003},[1982,2774,2107],{"class":1993},[1982,2776,2110],{"class":2099},[1982,2778,2114],{"class":2113},[1982,2780,2093],{"class":2003},[1982,2782,2783,2786,2788,2790,2792,2794,2796,2798,2800],{"class":1984,"line":2407},[1982,2784,2785],{"class":2099},"                return",[1982,2787,2072],{"class":1993},[1982,2789,2049],{"class":2003},[1982,2791,2129],{"class":1993},[1982,2793,2004],{"class":2003},[1982,2795,2134],{"class":2007},[1982,2797,2042],{"class":2003},[1982,2799,2139],{"class":2045},[1982,2801,2142],{"class":2003},[1982,2803,2804],{"class":1984,"line":2413},[1982,2805,2806],{"class":2003},"            }\n",[1982,2808,2809,2811,2813,2815],{"class":1984,"line":2419},[1982,2810,2122],{"class":2099},[1982,2812,2072],{"class":1993},[1982,2814,2049],{"class":2003},[1982,2816,2161],{"class":2052},[1982,2818,2819],{"class":1984,"line":2425},[1982,2820,2821],{"class":2003},"        }),\n",[1982,2823,2824,2826,2828,2831,2833,2836,2838,2840,2842,2844,2846,2848,2850,2852,2854,2856,2858,2860],{"class":1984,"line":2431},[1982,2825,2721],{"class":1993},[1982,2827,2004],{"class":2003},[1982,2829,2830],{"class":2007},"Transform",[1982,2832,2042],{"class":2003},[1982,2834,2835],{"class":2045},"\"enrich\"",[1982,2837,2049],{"class":2003},[1982,2839,2053],{"class":2052},[1982,2841,2042],{"class":2003},[1982,2843,2059],{"class":2058},[1982,2845,2062],{"class":2013},[1982,2847,2004],{"class":2003},[1982,2849,2067],{"class":2013},[1982,2851,2049],{"class":2003},[1982,2853,2072],{"class":2058},[1982,2855,2075],{"class":2013},[1982,2857,2078],{"class":2003},[1982,2859,2075],{"class":2013},[1982,2861,2093],{"class":2003},[1982,2863,2864,2867,2869,2871,2874,2877,2880,2882,2884],{"class":1984,"line":2437},[1982,2865,2866],{"class":1993},"            o",[1982,2868,2004],{"class":2003},[1982,2870,2636],{"class":1993},[1982,2872,2873],{"class":1993}," =",[1982,2875,2876],{"class":2045}," \"ORD-\"",[1982,2878,2879],{"class":1993}," +",[1982,2881,2072],{"class":1993},[1982,2883,2004],{"class":2003},[1982,2885,2886],{"class":1993},"ID\n",[1982,2888,2889,2891],{"class":1984,"line":2445},[1982,2890,2122],{"class":2099},[1982,2892,2893],{"class":1993}," o\n",[1982,2895,2896],{"class":1984,"line":2450},[1982,2897,2821],{"class":2003},[1982,2899,2900],{"class":1984,"line":2456},[1982,2901,2902],{"class":2003},"    )\n",[1982,2904,2906],{"class":1984,"line":2905},33,[1982,2907,2361],{"emptyLinePlaceholder":2360},[1982,2909,2911],{"class":1984,"line":2910},34,[1982,2912,2913],{"class":1987},"    // Build pipeline from YAML\n",[1982,2915,2917,2920,2922,2924,2926,2928,2930,2932,2934],{"class":1984,"line":2916},35,[1982,2918,2919],{"class":1993},"    pipeline",[1982,2921,2049],{"class":2003},[1982,2923,2464],{"class":1993},[1982,2925,1997],{"class":1993},[1982,2927,2383],{"class":1993},[1982,2929,2004],{"class":2003},[1982,2931,1272],{"class":2007},[1982,2933,2042],{"class":2003},[1982,2935,2392],{"class":2045},[1982,2937,2939],{"class":1984,"line":2938},36,[1982,2940,2398],{"class":2045},[1982,2942,2944],{"class":1984,"line":2943},37,[1982,2945,2404],{"class":2045},[1982,2947,2949],{"class":1984,"line":2948},38,[1982,2950,2410],{"class":2045},[1982,2952,2954],{"class":1984,"line":2953},39,[1982,2955,2956],{"class":2045},"  - ref: enrich\n",[1982,2958,2960,2962],{"class":1984,"line":2959},40,[1982,2961,2440],{"class":2045},[1982,2963,2142],{"class":2003},[1982,2965,2967,2970,2972,2975,2978],{"class":1984,"line":2966},41,[1982,2968,2969],{"class":2099},"    if",[1982,2971,2464],{"class":1993},[1982,2973,2974],{"class":2099}," !=",[1982,2976,2977],{"class":2052}," nil",[1982,2979,2093],{"class":2003},[1982,2981,2983,2987,2989,2992],{"class":1984,"line":2982},42,[1982,2984,2986],{"class":2985},"skxcq","        panic",[1982,2988,2042],{"class":2003},[1982,2990,2991],{"class":1993},"err",[1982,2993,2142],{"class":2003},[1982,2995,2997],{"class":1984,"line":2996},43,[1982,2998,2999],{"class":2003},"    }\n",[1982,3001,3003],{"class":1984,"line":3002},44,[1982,3004,2361],{"emptyLinePlaceholder":2360},[1982,3006,3008],{"class":1984,"line":3007},45,[1982,3009,3010],{"class":1987},"    // Process\n",[1982,3012,3014,3017,3019,3021,3023,3025,3027,3029,3031,3034,3036,3039,3042,3044,3046,3048,3050,3053,3055,3057,3059,3062],{"class":1984,"line":3013},46,[1982,3015,3016],{"class":1993},"    result",[1982,3018,2049],{"class":2003},[1982,3020,2464],{"class":1993},[1982,3022,1997],{"class":1993},[1982,3024,2469],{"class":1993},[1982,3026,2004],{"class":2003},[1982,3028,1326],{"class":2007},[1982,3030,2042],{"class":2003},[1982,3032,3033],{"class":1993},"context",[1982,3035,2004],{"class":2003},[1982,3037,3038],{"class":2007},"Background",[1982,3040,3041],{"class":2003},"(),",[1982,3043,2075],{"class":2013},[1982,3045,2633],{"class":2003},[1982,3047,2636],{"class":2285},[1982,3049,2289],{"class":2003},[1982,3051,3052],{"class":2045}," \"123\"",[1982,3054,2049],{"class":2003},[1982,3056,2649],{"class":2285},[1982,3058,2289],{"class":2003},[1982,3060,3061],{"class":2113}," 99.99",[1982,3063,2354],{"class":2003},[1982,3065,3067,3070,3072,3075,3077,3080,3084,3087,3090,3094,3097,3099,3102,3104,3106],{"class":1984,"line":3066},47,[1982,3068,3069],{"class":1993},"    fmt",[1982,3071,2004],{"class":2003},[1982,3073,3074],{"class":2007},"Printf",[1982,3076,2042],{"class":2003},[1982,3078,3079],{"class":2045},"\"Result: ",[1982,3081,3083],{"class":3082},"scyPU","%+v",[1982,3085,3086],{"class":2045},", Error: ",[1982,3088,3089],{"class":3082},"%v",[1982,3091,3093],{"class":3092},"suWN2","\\n",[1982,3095,3096],{"class":2045},"\"",[1982,3098,2049],{"class":2003},[1982,3100,3101],{"class":1993}," result",[1982,3103,2049],{"class":2003},[1982,3105,2464],{"class":1993},[1982,3107,2142],{"class":2003},[1982,3109,3111],{"class":1984,"line":3110},48,[1982,3112,2598],{"class":2003},[1968,3114,38],{"id":3115},"capabilities",[3117,3118,3119,3135],"table",{},[3120,3121,3122],"thead",{},[3123,3124,3125,3129,3132],"tr",{},[3126,3127,3128],"th",{},"Feature",[3126,3130,3131],{},"Description",[3126,3133,3134],{},"Docs",[3136,3137,3138,3152,3164,3177,3190,3203],"tbody",{},[3123,3139,3140,3144,3147],{},[3141,3142,3143],"td",{},"Schema-Driven Construction",[3141,3145,3146],{},"Define pipelines in YAML/JSON, build at runtime",[3141,3148,3149],{},[1894,3150,1416],{"href":3151},"docs/reference/schema-format",[3123,3153,3154,3156,3159],{},[3141,3155,219],{},[3141,3157,3158],{},"Update pipeline behavior without restarts",[3141,3160,3161],{},[1894,3162,219],{"href":3163},"docs/guides/hot-reloading",[3123,3165,3166,3169,3172],{},[3141,3167,3168],{},"Lock-Free Bindings",[3141,3170,3171],{},"Concurrent-safe pipeline access with auto-sync",[3141,3173,3174],{},[1894,3175,1140],{"href":3176},"docs/reference/api",[3123,3178,3179,3182,3185],{},[3141,3180,3181],{},"Comprehensive Validation",[3141,3183,3184],{},"Schema validation with detailed error messages",[3141,3186,3187],{},[1894,3188,443],{"href":3189},"docs/guides/schema-design",[3123,3191,3192,3195,3198],{},[3141,3193,3194],{},"14 Connector Types",[3141,3196,3197],{},"Sequence, filter, retry, timeout, circuit breaker, and more",[3141,3199,3200],{},[1894,3201,1443],{"href":3202},"docs/reference/connector-types",[3123,3204,3205,3208,3211],{},[3141,3206,3207],{},"Event Emission",[3141,3209,3210],{},"Built-in observability signals",[3141,3212,3213],{},[1894,3214,666],{"href":3215},"docs/guides/observability",[1968,3217,3219],{"id":3218},"why-flume","Why Flume?",[3221,3222,3223,3231,3237,3243,3249,3261],"ul",{},[3224,3225,3226,3230],"li",{},[3227,3228,3229],"strong",{},"Schema-driven",": Define pipelines in YAML/JSON, not code",[3224,3232,3233,3236],{},[3227,3234,3235],{},"Hot-reloadable",": Update pipeline behavior without restarts",[3224,3238,3239,3242],{},[3227,3240,3241],{},"Type-safe",": Full generics support with compile-time safety",[3224,3244,3245,3248],{},[3227,3246,3247],{},"Composable",": Build complex flows from simple, tested components",[3224,3250,3251,3254,3255,3260],{},[3227,3252,3253],{},"Observable",": Built-in ",[1894,3256,3259],{"href":3257,"rel":3258},"https://github.com/zoobz-io/capitan",[1898],"capitan"," event emission",[3224,3262,3263,3266],{},[3227,3264,3265],{},"Validated",": Comprehensive schema validation with detailed error messages",[1968,3268,3270],{"id":3269},"configuration-as-code","Configuration as Code",[1891,3272,3273,3274,2004],{},"Flume enables a pattern: ",[3227,3275,3276],{},"define once, reconfigure anywhere",[1891,3278,3279],{},"Register your processing components at startup. Define pipeline structure in configuration files. Update behavior at runtime without redeployment.",[1973,3281,3283],{"className":1975,"code":3282,"language":1977,"meta":24,"style":24},"// Components registered once\nfactory.Add(validate, enrich, notify, discount)\n\n// Structure defined in config\nfactory.SetSchema(\"checkout\", loadYAML(\"pipelines/checkout.yaml\"))\n\n// Behavior changes without restart\nfactory.SetSchema(\"checkout\", loadYAML(\"pipelines/checkout-v2.yaml\"))\n",[1979,3284,3285,3290,3320,3324,3329,3355,3359,3364],{"__ignoreMap":24},[1982,3286,3287],{"class":1984,"line":9},[1982,3288,3289],{"class":1987},"// Components registered once\n",[1982,3291,3292,3294,3296,3298,3300,3303,3305,3308,3310,3313,3315,3318],{"class":1984,"line":19},[1982,3293,1994],{"class":1993},[1982,3295,2004],{"class":2003},[1982,3297,1162],{"class":2007},[1982,3299,2042],{"class":2003},[1982,3301,3302],{"class":1993},"validate",[1982,3304,2049],{"class":2003},[1982,3306,3307],{"class":1993}," enrich",[1982,3309,2049],{"class":2003},[1982,3311,3312],{"class":1993}," notify",[1982,3314,2049],{"class":2003},[1982,3316,3317],{"class":1993}," discount",[1982,3319,2142],{"class":2003},[1982,3321,3322],{"class":1984,"line":30},[1982,3323,2361],{"emptyLinePlaceholder":2360},[1982,3325,3326],{"class":1984,"line":2031},[1982,3327,3328],{"class":1987},"// Structure defined in config\n",[1982,3330,3331,3333,3335,3337,3339,3342,3344,3347,3349,3352],{"class":1984,"line":2096},[1982,3332,1994],{"class":1993},[1982,3334,2004],{"class":2003},[1982,3336,1291],{"class":2007},[1982,3338,2042],{"class":2003},[1982,3340,3341],{"class":2045},"\"checkout\"",[1982,3343,2049],{"class":2003},[1982,3345,3346],{"class":2007}," loadYAML",[1982,3348,2042],{"class":2003},[1982,3350,3351],{"class":2045},"\"pipelines/checkout.yaml\"",[1982,3353,3354],{"class":2003},"))\n",[1982,3356,3357],{"class":1984,"line":2119},[1982,3358,2361],{"emptyLinePlaceholder":2360},[1982,3360,3361],{"class":1984,"line":2145},[1982,3362,3363],{"class":1987},"// Behavior changes without restart\n",[1982,3365,3366,3368,3370,3372,3374,3376,3378,3380,3382,3385],{"class":1984,"line":2151},[1982,3367,1994],{"class":1993},[1982,3369,2004],{"class":2003},[1982,3371,1291],{"class":2007},[1982,3373,2042],{"class":2003},[1982,3375,3341],{"class":2045},[1982,3377,2049],{"class":2003},[1982,3379,3346],{"class":2007},[1982,3381,2042],{"class":2003},[1982,3383,3384],{"class":2045},"\"pipelines/checkout-v2.yaml\"",[1982,3386,3354],{"class":2003},[1891,3388,3389,3390,3394,3395,3398],{},"The code defines ",[3391,3392,3393],"em",{},"what"," processors do. Configuration defines ",[3391,3396,3397],{},"how"," they combine.",[1968,3400,219],{"id":3401},"hot-reloading",[1891,3403,3404],{},"Update pipelines at runtime without restarts:",[1973,3406,3408],{"className":1975,"code":3407,"language":1977,"meta":24,"style":24},"// Register a named schema\nfactory.SetSchema(\"order-pipeline\", schema)\n\n// Create a binding with auto-sync enabled\nbinding, _ := factory.Bind(pipelineID, \"order-pipeline\", flume.WithAutoSync())\n\n// Process requests (lock-free)\nresult, _ := binding.Process(ctx, order)\n\n// Update schema - all auto-sync bindings rebuild automatically\nfactory.SetSchema(\"order-pipeline\", newSchema)\n",[1979,3409,3410,3415,3435,3439,3444,3482,3486,3491,3518,3522,3527],{"__ignoreMap":24},[1982,3411,3412],{"class":1984,"line":9},[1982,3413,3414],{"class":1987},"// Register a named schema\n",[1982,3416,3417,3419,3421,3423,3425,3428,3430,3433],{"class":1984,"line":19},[1982,3418,1994],{"class":1993},[1982,3420,2004],{"class":2003},[1982,3422,1291],{"class":2007},[1982,3424,2042],{"class":2003},[1982,3426,3427],{"class":2045},"\"order-pipeline\"",[1982,3429,2049],{"class":2003},[1982,3431,3432],{"class":1993}," schema",[1982,3434,2142],{"class":2003},[1982,3436,3437],{"class":1984,"line":30},[1982,3438,2361],{"emptyLinePlaceholder":2360},[1982,3440,3441],{"class":1984,"line":2031},[1982,3442,3443],{"class":1987},"// Create a binding with auto-sync enabled\n",[1982,3445,3446,3449,3451,3453,3455,3457,3459,3461,3463,3466,3468,3471,3473,3475,3477,3479],{"class":1984,"line":2096},[1982,3447,3448],{"class":1993},"binding",[1982,3450,2049],{"class":2003},[1982,3452,2378],{"class":1993},[1982,3454,1997],{"class":1993},[1982,3456,2383],{"class":1993},[1982,3458,2004],{"class":2003},[1982,3460,1311],{"class":2007},[1982,3462,2042],{"class":2003},[1982,3464,3465],{"class":1993},"pipelineID",[1982,3467,2049],{"class":2003},[1982,3469,3470],{"class":2045}," \"order-pipeline\"",[1982,3472,2049],{"class":2003},[1982,3474,2000],{"class":1993},[1982,3476,2004],{"class":2003},[1982,3478,1331],{"class":2007},[1982,3480,3481],{"class":2003},"())\n",[1982,3483,3484],{"class":1984,"line":2119},[1982,3485,2361],{"emptyLinePlaceholder":2360},[1982,3487,3488],{"class":1984,"line":2145},[1982,3489,3490],{"class":1987},"// Process requests (lock-free)\n",[1982,3492,3493,3495,3497,3499,3501,3504,3506,3508,3510,3512,3514,3516],{"class":1984,"line":2151},[1982,3494,2459],{"class":1993},[1982,3496,2049],{"class":2003},[1982,3498,2378],{"class":1993},[1982,3500,1997],{"class":1993},[1982,3502,3503],{"class":1993}," binding",[1982,3505,2004],{"class":2003},[1982,3507,1326],{"class":2007},[1982,3509,2042],{"class":2003},[1982,3511,2059],{"class":1993},[1982,3513,2049],{"class":2003},[1982,3515,2482],{"class":1993},[1982,3517,2142],{"class":2003},[1982,3519,3520],{"class":1984,"line":2164},[1982,3521,2361],{"emptyLinePlaceholder":2360},[1982,3523,3524],{"class":1984,"line":2170},[1982,3525,3526],{"class":1987},"// Update schema - all auto-sync bindings rebuild automatically\n",[1982,3528,3529,3531,3533,3535,3537,3539,3541,3544],{"class":1984,"line":2218},[1982,3530,1994],{"class":1993},[1982,3532,2004],{"class":2003},[1982,3534,1291],{"class":2007},[1982,3536,2042],{"class":2003},[1982,3538,3427],{"class":2045},[1982,3540,2049],{"class":2003},[1982,3542,3543],{"class":1993}," newSchema",[1982,3545,2142],{"class":2003},[1968,3547,62],{"id":3548},"documentation",[1891,3550,3551,3552,3555],{},"Full documentation is available in the ",[1894,3553,3554],{"href":3554},"docs/"," directory:",[3557,3558,66],"h3",{"id":3559},"learn",[3221,3561,3562,3568,3574,3580],{},[3224,3563,3564,3567],{},[1894,3565,81],{"href":3566},"docs/learn/quickstart"," — Your first pipeline in 5 minutes",[3224,3569,3570,3573],{},[1894,3571,155],{"href":3572},"docs/learn/core-concepts"," — Factories, schemas, and components",[3224,3575,3576,3579],{},[1894,3577,16],{"href":3578},"docs/learn/architecture"," — How Flume works under the hood",[3224,3581,3582,3585],{},[1894,3583,209],{"href":3584},"docs/learn/building-pipelines"," — From simple to complex",[3557,3587,71],{"id":3588},"guides",[3221,3590,3591,3596,3601,3607,3613],{},[3224,3592,3593,3595],{},[1894,3594,443],{"href":3189}," — Best practices for schema structure",[3224,3597,3598,3600],{},[1894,3599,219],{"href":3163}," — Runtime pipeline updates",[3224,3602,3603,3606],{},[1894,3604,363],{"href":3605},"docs/guides/error-handling"," — Retry, fallback, circuit breakers",[3224,3608,3609,3612],{},[1894,3610,879],{"href":3611},"docs/guides/testing"," — Testing strategies and CI/CD linting",[3224,3614,3615,3617],{},[1894,3616,666],{"href":3215}," — Monitoring with capitan events",[3557,3619,1834],{"id":3620},"cookbook",[3221,3622,3623],{},[3224,3624,3625,3628],{},[1894,3626,1096],{"href":3627},"docs/cookbook/common-patterns"," — Recipes and patterns",[3557,3630,76],{"id":3631},"reference",[3221,3633,3634,3639,3644,3649],{},[3224,3635,3636,3638],{},[1894,3637,1140],{"href":3176}," — Complete API documentation",[3224,3640,3641,3643],{},[1894,3642,1416],{"href":3151}," — YAML/JSON specification",[3224,3645,3646,3648],{},[1894,3647,1443],{"href":3202}," — All 14 connectors",[3224,3650,3651,3654],{},[1894,3652,1642],{"href":3653},"docs/reference/events"," — Observability signals",[1968,3656,3658],{"id":3657},"contributing","Contributing",[1891,3660,3661,3662,3666],{},"See ",[1894,3663,3665],{"href":3664},"CONTRIBUTING","CONTRIBUTING.md"," for development guidelines.",[1968,3668,1941],{"id":3669},"license",[1891,3671,3672,3673,3675],{},"MIT License - see ",[1894,3674,1938],{"href":1938}," file.",[3677,3678,3679],"style",{},"html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .suWN2, html code.shiki .suWN2{--shiki-default:var(--shiki-tag)}",{"title":24,"searchDepth":19,"depth":19,"links":3681},[3682,3683,3684,3685,3686,3687,3688,3689,3695,3696],{"id":1970,"depth":19,"text":1971},{"id":2487,"depth":19,"text":90},{"id":2510,"depth":19,"text":2511},{"id":3115,"depth":19,"text":38},{"id":3218,"depth":19,"text":3219},{"id":3269,"depth":19,"text":3270},{"id":3401,"depth":19,"text":219},{"id":3548,"depth":19,"text":62,"children":3690},[3691,3692,3693,3694],{"id":3559,"depth":30,"text":66},{"id":3588,"depth":30,"text":71},{"id":3620,"depth":30,"text":1834},{"id":3631,"depth":30,"text":76},{"id":3657,"depth":19,"text":3658},{"id":3669,"depth":19,"text":1941},"md","book-open",{},"/readme",{"title":1881,"description":24},"readme","LjAqx_lMY-Zlq3kuqe9-dcIyrawIt1pBffmeMtv78rE",{"id":3705,"title":3706,"body":3707,"description":24,"extension":3697,"icon":4146,"meta":4147,"navigation":2360,"path":4148,"seo":4149,"stem":4150,"__hash__":4151},"resources/security.md","Security",{"type":1883,"value":3708,"toc":4132},[3709,3713,3717,3720,3759,3763,3766,3770,3775,3778,3817,3821,3824,3873,3877,3903,3907,3910,3914,3917,4012,4016,4019,4054,4058,4061,4090,4094,4108,4112,4115,4120,4123,4129],[1886,3710,3712],{"id":3711},"security-policy","Security Policy",[1968,3714,3716],{"id":3715},"supported-versions","Supported Versions",[1891,3718,3719],{},"We release patches for security vulnerabilities. Which versions are eligible for receiving such patches depends on the CVSS v3.0 Rating:",[3117,3721,3722,3735],{},[3120,3723,3724],{},[3123,3725,3726,3729,3732],{},[3126,3727,3728],{},"Version",[3126,3730,3731],{},"Supported",[3126,3733,3734],{},"Status",[3136,3736,3737,3748],{},[3123,3738,3739,3742,3745],{},[3141,3740,3741],{},"latest",[3141,3743,3744],{},"✅",[3141,3746,3747],{},"Active development",[3123,3749,3750,3753,3756],{},[3141,3751,3752],{},"\u003C latest",[3141,3754,3755],{},"❌",[3141,3757,3758],{},"Security fixes only for critical issues",[1968,3760,3762],{"id":3761},"reporting-a-vulnerability","Reporting a Vulnerability",[1891,3764,3765],{},"We take the security of flume seriously. If you have discovered a security vulnerability in this project, please report it responsibly.",[3557,3767,3769],{"id":3768},"how-to-report","How to Report",[1891,3771,3772],{},[3227,3773,3774],{},"Please DO NOT report security vulnerabilities through public GitHub issues.",[1891,3776,3777],{},"Instead, please report them via one of the following methods:",[3779,3780,3781,3804],"ol",{},[3224,3782,3783,3786,3787],{},[3227,3784,3785],{},"GitHub Security Advisories"," (Preferred)",[3221,3788,3789,3798,3801],{},[3224,3790,3791,3792,3797],{},"Go to the ",[1894,3793,3796],{"href":3794,"rel":3795},"https://github.com/zoobz-io/flume/security",[1898],"Security tab"," of this repository",[3224,3799,3800],{},"Click \"Report a vulnerability\"",[3224,3802,3803],{},"Fill out the form with details about the vulnerability",[3224,3805,3806,3809],{},[3227,3807,3808],{},"Email",[3221,3810,3811,3814],{},[3224,3812,3813],{},"Send details to the repository maintainer through GitHub profile contact information",[3224,3815,3816],{},"Use PGP encryption if possible for sensitive details",[3557,3818,3820],{"id":3819},"what-to-include","What to Include",[1891,3822,3823],{},"Please include the following information (as much as you can provide) to help us better understand the nature and scope of the possible issue:",[3221,3825,3826,3832,3838,3844,3850,3855,3861,3867],{},[3224,3827,3828,3831],{},[3227,3829,3830],{},"Type of issue"," (e.g., race condition, schema injection, validation bypass, etc.)",[3224,3833,3834,3837],{},[3227,3835,3836],{},"Full paths of source file(s)"," related to the manifestation of the issue",[3224,3839,3840,3843],{},[3227,3841,3842],{},"The location of the affected source code"," (tag/branch/commit or direct URL)",[3224,3845,3846,3849],{},[3227,3847,3848],{},"Any special configuration required"," to reproduce the issue",[3224,3851,3852,3849],{},[3227,3853,3854],{},"Step-by-step instructions",[3224,3856,3857,3860],{},[3227,3858,3859],{},"Proof-of-concept or exploit code"," (if possible)",[3224,3862,3863,3866],{},[3227,3864,3865],{},"Impact of the issue",", including how an attacker might exploit the issue",[3224,3868,3869,3872],{},[3227,3870,3871],{},"Your name and affiliation"," (optional)",[3557,3874,3876],{"id":3875},"what-to-expect","What to Expect",[3221,3878,3879,3885,3891,3897],{},[3224,3880,3881,3884],{},[3227,3882,3883],{},"Acknowledgment",": We will acknowledge receipt of your vulnerability report within 48 hours",[3224,3886,3887,3890],{},[3227,3888,3889],{},"Initial Assessment",": Within 7 days, we will provide an initial assessment of the report",[3224,3892,3893,3896],{},[3227,3894,3895],{},"Resolution Timeline",": We aim to resolve critical issues within 30 days",[3224,3898,3899,3902],{},[3227,3900,3901],{},"Disclosure",": We will coordinate with you on the disclosure timeline",[3557,3904,3906],{"id":3905},"preferred-languages","Preferred Languages",[1891,3908,3909],{},"We prefer all communications to be in English.",[1968,3911,3913],{"id":3912},"security-best-practices","Security Best Practices",[1891,3915,3916],{},"When using flume in your applications, we recommend:",[3779,3918,3919,3940,3960,3976,3992],{},[3224,3920,3921,3924],{},[3227,3922,3923],{},"Keep Dependencies Updated",[1973,3925,3927],{"className":2493,"code":3926,"language":2495,"meta":24,"style":24},"go get -u github.com/zoobz-io/flume\n",[1979,3928,3929],{"__ignoreMap":24},[1982,3930,3931,3933,3935,3938],{"class":1984,"line":9},[1982,3932,1977],{"class":2007},[1982,3934,2504],{"class":2045},[1982,3936,3937],{"class":2052}," -u",[1982,3939,2507],{"class":2045},[3224,3941,3942,3944],{},[3227,3943,1660],{},[3221,3945,3946,3951,3957],{},[3224,3947,3948,3949],{},"Always validate schemas before deployment using ",[1979,3950,1349],{},[3224,3952,3953,3954,3956],{},"Use ",[1979,3955,1344],{}," at runtime with a configured factory",[3224,3958,3959],{},"Don't load schemas from untrusted sources without validation",[3224,3961,3962,3965],{},[3227,3963,3964],{},"Hot Reload Security",[3221,3966,3967,3970,3973],{},[3224,3968,3969],{},"Secure the source of schema updates (e.g., authenticated API endpoints)",[3224,3971,3972],{},"Log all schema changes for audit purposes",[3224,3974,3975],{},"Consider schema versioning for rollback capability",[3224,3977,3978,3981],{},[3227,3979,3980],{},"Resource Management",[3221,3982,3983,3986,3989],{},[3224,3984,3985],{},"Close channels when no longer needed",[3224,3987,3988],{},"Set appropriate timeouts for pipeline operations",[3224,3990,3991],{},"Configure circuit breakers for external dependencies",[3224,3993,3994,3997],{},[3227,3995,3996],{},"Concurrency Safety",[3221,3998,3999,4006,4009],{},[3224,4000,4001,4002,4005],{},"Ensure your data type's ",[1979,4003,4004],{},"Clone()"," method creates deep copies",[3224,4007,4008],{},"Don't share mutable state across processors without synchronization",[3224,4010,4011],{},"Be aware that concurrent/race nodes run in parallel",[1968,4013,4015],{"id":4014},"security-features","Security Features",[1891,4017,4018],{},"flume includes several built-in security features:",[3221,4020,4021,4026,4031,4037,4042,4048],{},[3224,4022,4023,4025],{},[3227,4024,47],{},": Go generics ensure compile-time type checking",[3224,4027,4028,4030],{},[3227,4029,1660],{},": Comprehensive validation catches errors before building",[3224,4032,4033,4036],{},[3227,4034,4035],{},"Reference Validation",": All processor/predicate/condition references verified",[3224,4038,4039,4041],{},[3227,4040,264],{},": Atomic operations for hot-reload scenarios",[3224,4043,4044,4047],{},[3227,4045,4046],{},"Timeout Enforcement",": Built-in timeout connector prevents runaway operations",[3224,4049,4050,4053],{},[3227,4051,4052],{},"Circuit Breakers",": Built-in circuit breaker pattern for fault isolation",[1968,4055,4057],{"id":4056},"automated-security-scanning","Automated Security Scanning",[1891,4059,4060],{},"This project uses:",[3221,4062,4063,4068,4074,4080],{},[3224,4064,4065,4067],{},[3227,4066,1926],{},": GitHub's semantic code analysis for security vulnerabilities",[3224,4069,4070,4073],{},[3227,4071,4072],{},"golangci-lint",": Static analysis including security linters (gosec)",[3224,4075,4076,4079],{},[3227,4077,4078],{},"Codecov",": Coverage tracking to ensure security-critical code is tested",[3224,4081,4082,4085,4086,4089],{},[3227,4083,4084],{},"Race Detection",": Tests run with ",[1979,4087,4088],{},"-race"," flag to detect data races",[1968,4091,4093],{"id":4092},"vulnerability-disclosure-policy","Vulnerability Disclosure Policy",[3221,4095,4096,4099,4102,4105],{},[3224,4097,4098],{},"Security vulnerabilities will be disclosed via GitHub Security Advisories",[3224,4100,4101],{},"We follow a 90-day disclosure timeline for non-critical issues",[3224,4103,4104],{},"Critical vulnerabilities may be disclosed sooner after patches are available",[3224,4106,4107],{},"We will credit reporters who follow responsible disclosure practices",[1968,4109,4111],{"id":4110},"credits","Credits",[1891,4113,4114],{},"We thank the following individuals for responsibly disclosing security issues:",[1891,4116,4117],{},[3391,4118,4119],{},"This list is currently empty. Be the first to help improve our security!",[4121,4122],"hr",{},[1891,4124,4125,4128],{},[3227,4126,4127],{},"Last Updated",": 2025-12-12",[3677,4130,4131],{},"html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":24,"searchDepth":19,"depth":19,"links":4133},[4134,4135,4141,4142,4143,4144,4145],{"id":3715,"depth":19,"text":3716},{"id":3761,"depth":19,"text":3762,"children":4136},[4137,4138,4139,4140],{"id":3768,"depth":30,"text":3769},{"id":3819,"depth":30,"text":3820},{"id":3875,"depth":30,"text":3876},{"id":3905,"depth":30,"text":3906},{"id":3912,"depth":19,"text":3913},{"id":4014,"depth":19,"text":4015},{"id":4056,"depth":19,"text":4057},{"id":4092,"depth":19,"text":4093},{"id":4110,"depth":19,"text":4111},"shield",{},"/security",{"title":3706,"description":24},"security","8Hgch7Pp-e-NyfBxgZdJF8RyzhItCJT0gGPopLjI8Wk",{"id":4153,"title":3658,"body":4154,"description":4162,"extension":3697,"icon":1979,"meta":4727,"navigation":2360,"path":4728,"seo":4729,"stem":3657,"__hash__":4730},"resources/contributing.md",{"type":1883,"value":4155,"toc":4702},[4156,4160,4163,4167,4170,4174,4212,4216,4220,4238,4241,4257,4259,4270,4274,4278,4292,4296,4307,4311,4316,4319,4336,4340,4343,4360,4364,4367,4381,4385,4413,4416,4419,4434,4437,4453,4456,4472,4475,4488,4492,4500,4504,4507,4551,4555,4559,4562,4573,4576,4590,4594,4597,4625,4629,4657,4663,4667,4670,4681,4685,4696,4699],[1886,4157,4159],{"id":4158},"contributing-to-flume","Contributing to flume",[1891,4161,4162],{},"Thank you for your interest in contributing to flume! This guide will help you get started.",[1968,4164,4166],{"id":4165},"code-of-conduct","Code of Conduct",[1891,4168,4169],{},"By participating in this project, you agree to maintain a respectful and inclusive environment for all contributors.",[1968,4171,4173],{"id":4172},"getting-started","Getting Started",[3779,4175,4176,4179,4185,4191,4194,4200,4203,4209],{},[3224,4177,4178],{},"Fork the repository",[3224,4180,4181,4182],{},"Clone your fork: ",[1979,4183,4184],{},"git clone https://github.com/yourusername/flume.git",[3224,4186,4187,4188],{},"Create a feature branch: ",[1979,4189,4190],{},"git checkout -b feature/your-feature-name",[3224,4192,4193],{},"Make your changes",[3224,4195,4196,4197],{},"Run tests: ",[1979,4198,4199],{},"go test ./...",[3224,4201,4202],{},"Commit your changes with a descriptive message",[3224,4204,4205,4206],{},"Push to your fork: ",[1979,4207,4208],{},"git push origin feature/your-feature-name",[3224,4210,4211],{},"Create a Pull Request",[1968,4213,4215],{"id":4214},"development-guidelines","Development Guidelines",[3557,4217,4219],{"id":4218},"code-style","Code Style",[3221,4221,4222,4225,4232,4235],{},[3224,4223,4224],{},"Follow standard Go conventions",[3224,4226,4227,4228,4231],{},"Run ",[1979,4229,4230],{},"go fmt"," before committing",[3224,4233,4234],{},"Add comments for exported functions and types",[3224,4236,4237],{},"Keep functions small and focused",[3557,4239,879],{"id":4240},"testing",[3221,4242,4243,4246,4251,4254],{},[3224,4244,4245],{},"Write tests for new functionality",[3224,4247,4248,4249],{},"Ensure all tests pass: ",[1979,4250,4199],{},[3224,4252,4253],{},"Include benchmarks for performance-critical code",[3224,4255,4256],{},"Aim for good test coverage",[3557,4258,62],{"id":3548},[3221,4260,4261,4264,4267],{},[3224,4262,4263],{},"Update documentation for API changes",[3224,4265,4266],{},"Add examples for new features",[3224,4268,4269],{},"Keep doc comments clear and concise",[1968,4271,4273],{"id":4272},"types-of-contributions","Types of Contributions",[3557,4275,4277],{"id":4276},"bug-reports","Bug Reports",[3221,4279,4280,4283,4286,4289],{},[3224,4281,4282],{},"Use GitHub Issues",[3224,4284,4285],{},"Include minimal reproduction code",[3224,4287,4288],{},"Describe expected vs actual behavior",[3224,4290,4291],{},"Include Go version and OS",[3557,4293,4295],{"id":4294},"feature-requests","Feature Requests",[3221,4297,4298,4301,4304],{},[3224,4299,4300],{},"Open an issue for discussion first",[3224,4302,4303],{},"Explain the use case",[3224,4305,4306],{},"Consider backwards compatibility",[3557,4308,4310],{"id":4309},"code-contributions","Code Contributions",[4312,4313,4315],"h4",{"id":4314},"adding-processors","Adding Processors",[1891,4317,4318],{},"New processor builders should:",[3221,4320,4321,4327,4330,4333],{},[3224,4322,4323,4324],{},"Follow the existing pattern in ",[1979,4325,4326],{},"builders.go",[3224,4328,4329],{},"Include comprehensive tests",[3224,4331,4332],{},"Add documentation with examples",[3224,4334,4335],{},"Update schema validation if needed",[4312,4337,4339],{"id":4338},"adding-schema-features","Adding Schema Features",[1891,4341,4342],{},"New schema features should:",[3221,4344,4345,4351,4354,4357],{},[3224,4346,4347,4348,4350],{},"Extend the ",[1979,4349,1363],{}," type appropriately",[3224,4352,4353],{},"Include validation rules",[3224,4355,4356],{},"Add builder support",[3224,4358,4359],{},"Document the YAML/JSON format",[4312,4361,4363],{"id":4362},"examples","Examples",[1891,4365,4366],{},"New examples should:",[3221,4368,4369,4372,4375,4378],{},[3224,4370,4371],{},"Solve a real-world problem",[3224,4373,4374],{},"Include tests",[3224,4376,4377],{},"Have clear documentation",[3224,4379,4380],{},"Follow the existing structure",[1968,4382,4384],{"id":4383},"pull-request-process","Pull Request Process",[3779,4386,4387,4393,4398,4403,4408],{},[3224,4388,4389,4392],{},[3227,4390,4391],{},"Keep PRs focused"," - One feature/fix per PR",[3224,4394,4395],{},[3227,4396,4397],{},"Write descriptive commit messages",[3224,4399,4400],{},[3227,4401,4402],{},"Update tests and documentation",[3224,4404,4405],{},[3227,4406,4407],{},"Ensure CI passes",[3224,4409,4410],{},[3227,4411,4412],{},"Respond to review feedback",[1968,4414,879],{"id":4415},"testing-1",[1891,4417,4418],{},"Run the full test suite:",[1973,4420,4422],{"className":2493,"code":4421,"language":2495,"meta":24,"style":24},"go test ./...\n",[1979,4423,4424],{"__ignoreMap":24},[1982,4425,4426,4428,4431],{"class":1984,"line":9},[1982,4427,1977],{"class":2007},[1982,4429,4430],{"class":2045}," test",[1982,4432,4433],{"class":2045}," ./...\n",[1891,4435,4436],{},"Run with race detection:",[1973,4438,4440],{"className":2493,"code":4439,"language":2495,"meta":24,"style":24},"go test -race ./...\n",[1979,4441,4442],{"__ignoreMap":24},[1982,4443,4444,4446,4448,4451],{"class":1984,"line":9},[1982,4445,1977],{"class":2007},[1982,4447,4430],{"class":2045},[1982,4449,4450],{"class":2052}," -race",[1982,4452,4433],{"class":2045},[1891,4454,4455],{},"Run benchmarks:",[1973,4457,4459],{"className":2493,"code":4458,"language":2495,"meta":24,"style":24},"go test -bench=. ./...\n",[1979,4460,4461],{"__ignoreMap":24},[1982,4462,4463,4465,4467,4470],{"class":1984,"line":9},[1982,4464,1977],{"class":2007},[1982,4466,4430],{"class":2045},[1982,4468,4469],{"class":2052}," -bench=.",[1982,4471,4433],{"class":2045},[1891,4473,4474],{},"Run linter:",[1973,4476,4478],{"className":2493,"code":4477,"language":2495,"meta":24,"style":24},"make lint\n",[1979,4479,4480],{"__ignoreMap":24},[1982,4481,4482,4485],{"class":1984,"line":9},[1982,4483,4484],{"class":2007},"make",[1982,4486,4487],{"class":2045}," lint\n",[1968,4489,4491],{"id":4490},"project-structure","Project Structure",[1973,4493,4498],{"className":4494,"code":4496,"language":4497},[4495],"language-text","flume/\n├── factory.go        # Core factory type and registration\n├── builders.go       # Schema node to pipeline builders\n├── schema.go         # Schema types and parsing\n├── validation.go     # Schema validation\n├── loader.go         # File/JSON/YAML loading\n├── observability.go  # Event emission\n├── spec.go           # Factory introspection\n└── *_test.go         # Tests\n","text",[1979,4499,4496],{"__ignoreMap":24},[1968,4501,4503],{"id":4502},"commit-messages","Commit Messages",[1891,4505,4506],{},"Follow conventional commits:",[3221,4508,4509,4515,4521,4527,4533,4539,4545],{},[3224,4510,4511,4514],{},[1979,4512,4513],{},"feat:"," New feature",[3224,4516,4517,4520],{},[1979,4518,4519],{},"fix:"," Bug fix",[3224,4522,4523,4526],{},[1979,4524,4525],{},"docs:"," Documentation changes",[3224,4528,4529,4532],{},[1979,4530,4531],{},"test:"," Test additions/changes",[3224,4534,4535,4538],{},[1979,4536,4537],{},"refactor:"," Code refactoring",[3224,4540,4541,4544],{},[1979,4542,4543],{},"perf:"," Performance improvements",[3224,4546,4547,4550],{},[1979,4548,4549],{},"chore:"," Maintenance tasks",[1968,4552,4554],{"id":4553},"release-process","Release Process",[3557,4556,4558],{"id":4557},"automated-releases","Automated Releases",[1891,4560,4561],{},"This project uses automated release versioning. To create a release:",[3779,4563,4564,4567,4570],{},[3224,4565,4566],{},"Go to Actions -> Release -> Run workflow",[3224,4568,4569],{},"Leave \"Version override\" empty for automatic version inference",[3224,4571,4572],{},"Click \"Run workflow\"",[1891,4574,4575],{},"The system will:",[3221,4577,4578,4581,4584,4587],{},[3224,4579,4580],{},"Automatically determine the next version from conventional commits",[3224,4582,4583],{},"Create a git tag",[3224,4585,4586],{},"Generate release notes via GoReleaser",[3224,4588,4589],{},"Publish the release to GitHub",[3557,4591,4593],{"id":4592},"manual-release-legacy","Manual Release (Legacy)",[1891,4595,4596],{},"You can still create releases manually:",[1973,4598,4600],{"className":2493,"code":4599,"language":2495,"meta":24,"style":24},"git tag v1.2.3\ngit push origin v1.2.3\n",[1979,4601,4602,4613],{"__ignoreMap":24},[1982,4603,4604,4607,4610],{"class":1984,"line":9},[1982,4605,4606],{"class":2007},"git",[1982,4608,4609],{"class":2045}," tag",[1982,4611,4612],{"class":2045}," v1.2.3\n",[1982,4614,4615,4617,4620,4623],{"class":1984,"line":19},[1982,4616,4606],{"class":2007},[1982,4618,4619],{"class":2045}," push",[1982,4621,4622],{"class":2045}," origin",[1982,4624,4612],{"class":2045},[3557,4626,4628],{"id":4627},"commit-conventions-for-versioning","Commit Conventions for Versioning",[3221,4630,4631,4636,4641,4647],{},[3224,4632,4633,4635],{},[1979,4634,4513],{}," new features (minor version: 1.2.0 -> 1.3.0)",[3224,4637,4638,4640],{},[1979,4639,4519],{}," bug fixes (patch version: 1.2.0 -> 1.2.1)",[3224,4642,4643,4646],{},[1979,4644,4645],{},"feat!:"," breaking changes (major version: 1.2.0 -> 2.0.0)",[3224,4648,4649,4651,4652,4651,4654,4656],{},[1979,4650,4525],{},", ",[1979,4653,4531],{},[1979,4655,4549],{}," no version change",[1891,4658,4659,4660],{},"Example: ",[1979,4661,4662],{},"feat(schema): add support for custom connector types",[3557,4664,4666],{"id":4665},"version-preview-on-pull-requests","Version Preview on Pull Requests",[1891,4668,4669],{},"Every PR automatically shows the next version that will be created:",[3221,4671,4672,4675,4678],{},[3224,4673,4674],{},"Check PR comments for \"Version Preview\"",[3224,4676,4677],{},"Updates automatically as you add commits",[3224,4679,4680],{},"Helps verify your commits have the intended effect",[1968,4682,4684],{"id":4683},"questions","Questions?",[3221,4686,4687,4690,4693],{},[3224,4688,4689],{},"Open an issue for questions",[3224,4691,4692],{},"Check existing issues first",[3224,4694,4695],{},"Be patient and respectful",[1891,4697,4698],{},"Thank you for contributing to flume!",[3677,4700,4701],{},"html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}",{"title":24,"searchDepth":19,"depth":19,"links":4703},[4704,4705,4706,4711,4716,4717,4718,4719,4720,4726],{"id":4165,"depth":19,"text":4166},{"id":4172,"depth":19,"text":4173},{"id":4214,"depth":19,"text":4215,"children":4707},[4708,4709,4710],{"id":4218,"depth":30,"text":4219},{"id":4240,"depth":30,"text":879},{"id":3548,"depth":30,"text":62},{"id":4272,"depth":19,"text":4273,"children":4712},[4713,4714,4715],{"id":4276,"depth":30,"text":4277},{"id":4294,"depth":30,"text":4295},{"id":4309,"depth":30,"text":4310},{"id":4383,"depth":19,"text":4384},{"id":4415,"depth":19,"text":879},{"id":4490,"depth":19,"text":4491},{"id":4502,"depth":19,"text":4503},{"id":4553,"depth":19,"text":4554,"children":4721},[4722,4723,4724,4725],{"id":4557,"depth":30,"text":4558},{"id":4592,"depth":30,"text":4593},{"id":4627,"depth":30,"text":4628},{"id":4665,"depth":30,"text":4666},{"id":4683,"depth":19,"text":4684},{},"/contributing",{"title":3658,"description":4162},"XNSK9mlai_COIso6Z9bL54kGavHd1YbB2SBaSuGIqdk",{"id":4732,"title":6,"author":4733,"body":4734,"description":8,"extension":3697,"meta":5540,"navigation":2360,"path":5,"published":5541,"readtime":5542,"seo":5543,"stem":1805,"tags":5544,"updated":5546,"__hash__":5547},"flume/v1.0.1/1.overview.md","zoobzio",{"type":1883,"value":4735,"toc":5522},[4736,4739,4742,4745,5007,5010,5013,5019,5022,5025,5028,5031,5085,5206,5209,5226,5228,5231,5239,5245,5250,5259,5262,5265,5268,5271,5368,5371,5374,5380,5383,5390,5420,5423,5425,5430,5455,5460,5489,5494,5519],[1886,4737,6],{"id":4738},"overview",[1891,4740,4741],{},"Building data pipelines in Go typically means hardcoding structure at compile time. Change the flow? Rebuild and redeploy.",[1891,4743,4744],{},"Flume offers a different approach: define pipeline structure in configuration, update it at runtime.",[1973,4746,4748],{"className":1975,"code":4747,"language":1977,"meta":24,"style":24},"factory := flume.New[Order]()\n\n// Register reusable components\nfactory.Add(pipz.Apply(\"validate\", validateOrder))\nfactory.Add(pipz.Transform(\"enrich\", enrichOrder))\nfactory.AddPredicate(flume.Predicate[Order]{\n    Name:      \"high-value\",\n    Predicate: func(ctx context.Context, o Order) bool { return o.Total > 1000 },\n})\n\n// Build from schema\npipeline, _ := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: high-value\n    then:\n      ref: enrich\n`)\n\n// Update at runtime - no restart required\nfactory.SetSchema(\"orders\", newSchema)\n",[1979,4749,4750,4768,4772,4777,4804,4831,4853,4864,4910,4914,4918,4923,4943,4947,4951,4955,4959,4964,4968,4973,4979,4983,4988],{"__ignoreMap":24},[1982,4751,4752,4754,4756,4758,4760,4762,4764,4766],{"class":1984,"line":9},[1982,4753,1994],{"class":1993},[1982,4755,1997],{"class":1993},[1982,4757,2000],{"class":1993},[1982,4759,2004],{"class":2003},[1982,4761,1153],{"class":2007},[1982,4763,2010],{"class":2003},[1982,4765,2014],{"class":2013},[1982,4767,2017],{"class":2003},[1982,4769,4770],{"class":1984,"line":19},[1982,4771,2361],{"emptyLinePlaceholder":2360},[1982,4773,4774],{"class":1984,"line":30},[1982,4775,4776],{"class":1987},"// Register reusable components\n",[1982,4778,4779,4781,4783,4785,4787,4789,4791,4793,4795,4797,4799,4802],{"class":1984,"line":2031},[1982,4780,1994],{"class":1993},[1982,4782,2004],{"class":2003},[1982,4784,1162],{"class":2007},[1982,4786,2042],{"class":2003},[1982,4788,1965],{"class":1993},[1982,4790,2004],{"class":2003},[1982,4792,2039],{"class":2007},[1982,4794,2042],{"class":2003},[1982,4796,2046],{"class":2045},[1982,4798,2049],{"class":2003},[1982,4800,4801],{"class":1993}," validateOrder",[1982,4803,3354],{"class":2003},[1982,4805,4806,4808,4810,4812,4814,4816,4818,4820,4822,4824,4826,4829],{"class":1984,"line":2096},[1982,4807,1994],{"class":1993},[1982,4809,2004],{"class":2003},[1982,4811,1162],{"class":2007},[1982,4813,2042],{"class":2003},[1982,4815,1965],{"class":1993},[1982,4817,2004],{"class":2003},[1982,4819,2830],{"class":2007},[1982,4821,2042],{"class":2003},[1982,4823,2835],{"class":2045},[1982,4825,2049],{"class":2003},[1982,4827,4828],{"class":1993}," enrichOrder",[1982,4830,3354],{"class":2003},[1982,4832,4833,4835,4837,4839,4841,4843,4845,4847,4849,4851],{"class":1984,"line":2119},[1982,4834,1994],{"class":1993},[1982,4836,2004],{"class":2003},[1982,4838,1191],{"class":2007},[1982,4840,2042],{"class":2003},[1982,4842,1888],{"class":2013},[1982,4844,2004],{"class":2003},[1982,4846,1368],{"class":2013},[1982,4848,2010],{"class":2003},[1982,4850,2014],{"class":2013},[1982,4852,2279],{"class":2003},[1982,4854,4855,4857,4859,4862],{"class":1984,"line":2145},[1982,4856,2286],{"class":2285},[1982,4858,2289],{"class":2003},[1982,4860,4861],{"class":2045},"      \"high-value\"",[1982,4863,2295],{"class":2003},[1982,4865,4866,4868,4870,4872,4874,4876,4878,4880,4882,4884,4886,4888,4890,4892,4894,4896,4898,4900,4902,4905,4908],{"class":1984,"line":2151},[1982,4867,2301],{"class":2285},[1982,4869,2289],{"class":2003},[1982,4871,2053],{"class":2052},[1982,4873,2042],{"class":2003},[1982,4875,2059],{"class":2058},[1982,4877,2062],{"class":2013},[1982,4879,2004],{"class":2003},[1982,4881,2067],{"class":2013},[1982,4883,2049],{"class":2003},[1982,4885,2072],{"class":2058},[1982,4887,2075],{"class":2013},[1982,4889,2078],{"class":2003},[1982,4891,2326],{"class":2013},[1982,4893,2329],{"class":2003},[1982,4895,2332],{"class":2099},[1982,4897,2072],{"class":1993},[1982,4899,2004],{"class":2003},[1982,4901,2107],{"class":1993},[1982,4903,4904],{"class":2099}," >",[1982,4906,4907],{"class":2113}," 1000",[1982,4909,2348],{"class":2003},[1982,4911,4912],{"class":1984,"line":2164},[1982,4913,2354],{"class":2003},[1982,4915,4916],{"class":1984,"line":2170},[1982,4917,2361],{"emptyLinePlaceholder":2360},[1982,4919,4920],{"class":1984,"line":2218},[1982,4921,4922],{"class":1987},"// Build from schema\n",[1982,4924,4925,4927,4929,4931,4933,4935,4937,4939,4941],{"class":1984,"line":2237},[1982,4926,2373],{"class":1993},[1982,4928,2049],{"class":2003},[1982,4930,2378],{"class":1993},[1982,4932,1997],{"class":1993},[1982,4934,2383],{"class":1993},[1982,4936,2004],{"class":2003},[1982,4938,1272],{"class":2007},[1982,4940,2042],{"class":2003},[1982,4942,2392],{"class":2045},[1982,4944,4945],{"class":1984,"line":2248},[1982,4946,2398],{"class":2045},[1982,4948,4949],{"class":1984,"line":2253},[1982,4950,2404],{"class":2045},[1982,4952,4953],{"class":1984,"line":2258},[1982,4954,2410],{"class":2045},[1982,4956,4957],{"class":1984,"line":2282},[1982,4958,2416],{"class":2045},[1982,4960,4961],{"class":1984,"line":2298},[1982,4962,4963],{"class":2045},"    predicate: high-value\n",[1982,4965,4966],{"class":1984,"line":2351},[1982,4967,2428],{"class":2045},[1982,4969,4970],{"class":1984,"line":2357},[1982,4971,4972],{"class":2045},"      ref: enrich\n",[1982,4974,4975,4977],{"class":1984,"line":2364},[1982,4976,2440],{"class":2045},[1982,4978,2142],{"class":2003},[1982,4980,4981],{"class":1984,"line":2370},[1982,4982,2361],{"emptyLinePlaceholder":2360},[1982,4984,4985],{"class":1984,"line":2395},[1982,4986,4987],{"class":1987},"// Update at runtime - no restart required\n",[1982,4989,4990,4992,4994,4996,4998,5001,5003,5005],{"class":1984,"line":2401},[1982,4991,1994],{"class":1993},[1982,4993,2004],{"class":2003},[1982,4995,1291],{"class":2007},[1982,4997,2042],{"class":2003},[1982,4999,5000],{"class":2045},"\"orders\"",[1982,5002,2049],{"class":2003},[1982,5004,3543],{"class":1993},[1982,5006,2142],{"class":2003},[1891,5008,5009],{},"Type-safe, hot-reloadable, zero external dependencies.",[1968,5011,16],{"id":5012},"architecture",[1973,5014,5017],{"className":5015,"code":5016,"language":4497},[4495],"┌──────────────────────────────────────────────────────────────┐\n│                         Factory[T]                           │\n│                                                              │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │\n│  │ Processors  │  │ Predicates  │  │ Conditions  │          │\n│  │ (Chainable) │  │  (bool fn)  │  │ (string fn) │          │\n│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │\n│         │                │                │                  │\n│         └────────────────┼────────────────┘                  │\n│                          ▼                                   │\n│  ┌───────────────────────────────────────────────────────┐  │\n│  │                   Schema (YAML/JSON)                  │  │\n│  │   type: sequence                                      │  │\n│  │   children:                                           │  │\n│  │     - ref: validate                                   │  │\n│  │     - type: filter ...                                │  │\n│  └───────────────────────────────────────────────────────┘  │\n│                          │                                   │\n│                    Build │ Validate                          │\n│                          ▼                                   │\n│  ┌───────────────────────────────────────────────────────┐  │\n│  │              pipz.Chainable[T] Pipeline               │  │\n│  └───────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────┘\n",[1979,5018,5016],{"__ignoreMap":24},[1891,5020,5021],{},"Register components once, compose them via schemas, build executable pipelines. Schemas validate against registered components before building.",[1968,5023,22],{"id":5024},"philosophy",[3557,5026,27],{"id":5027},"configuration-over-code",[1891,5029,5030],{},"Pipeline structure belongs in configuration. Business logic belongs in code.",[1973,5032,5036],{"className":5033,"code":5034,"language":5035,"meta":24,"style":24},"language-yaml shiki shiki-themes","# Configuration: structure\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: process\n","yaml",[1979,5037,5038,5043,5053,5061,5074],{"__ignoreMap":24},[1982,5039,5040],{"class":1984,"line":9},[1982,5041,5042],{"class":1987},"# Configuration: structure\n",[1982,5044,5045,5047,5050],{"class":1984,"line":19},[1982,5046,2570],{"class":2052},[1982,5048,5049],{"class":2536},": ",[1982,5051,5052],{"class":2045},"sequence\n",[1982,5054,5055,5058],{"class":1984,"line":30},[1982,5056,5057],{"class":2052},"children",[1982,5059,5060],{"class":2536},":\n",[1982,5062,5063,5066,5069,5071],{"class":1984,"line":2031},[1982,5064,5065],{"class":2536},"  - ",[1982,5067,5068],{"class":2052},"ref",[1982,5070,5049],{"class":2536},[1982,5072,5073],{"class":2045},"validate\n",[1982,5075,5076,5078,5080,5082],{"class":1984,"line":2096},[1982,5077,5065],{"class":2536},[1982,5079,5068],{"class":2052},[1982,5081,5049],{"class":2536},[1982,5083,5084],{"class":2045},"process\n",[1973,5086,5088],{"className":1975,"code":5087,"language":1977,"meta":24,"style":24},"// Code: behaviour\nfactory.Add(pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n    if o.Total \u003C= 0 {\n        return o, errors.New(\"invalid total\")\n    }\n    return o, nil\n}))\n",[1979,5089,5090,5095,5149,5165,5186,5190,5201],{"__ignoreMap":24},[1982,5091,5092],{"class":1984,"line":9},[1982,5093,5094],{"class":1987},"// Code: behaviour\n",[1982,5096,5097,5099,5101,5103,5105,5107,5109,5111,5113,5115,5117,5119,5121,5123,5125,5127,5129,5131,5133,5135,5137,5139,5141,5143,5145,5147],{"class":1984,"line":19},[1982,5098,1994],{"class":1993},[1982,5100,2004],{"class":2003},[1982,5102,1162],{"class":2007},[1982,5104,2042],{"class":2003},[1982,5106,1965],{"class":1993},[1982,5108,2004],{"class":2003},[1982,5110,2039],{"class":2007},[1982,5112,2042],{"class":2003},[1982,5114,2046],{"class":2045},[1982,5116,2049],{"class":2003},[1982,5118,2053],{"class":2052},[1982,5120,2042],{"class":2003},[1982,5122,2059],{"class":2058},[1982,5124,2062],{"class":2013},[1982,5126,2004],{"class":2003},[1982,5128,2067],{"class":2013},[1982,5130,2049],{"class":2003},[1982,5132,2072],{"class":2058},[1982,5134,2075],{"class":2013},[1982,5136,2078],{"class":2003},[1982,5138,2081],{"class":2003},[1982,5140,2014],{"class":2013},[1982,5142,2049],{"class":2003},[1982,5144,2088],{"class":2013},[1982,5146,2078],{"class":2003},[1982,5148,2093],{"class":2003},[1982,5150,5151,5153,5155,5157,5159,5161,5163],{"class":1984,"line":30},[1982,5152,2969],{"class":2099},[1982,5154,2072],{"class":1993},[1982,5156,2004],{"class":2003},[1982,5158,2107],{"class":1993},[1982,5160,2110],{"class":2099},[1982,5162,2114],{"class":2113},[1982,5164,2093],{"class":2003},[1982,5166,5167,5169,5171,5173,5176,5178,5180,5182,5184],{"class":1984,"line":2031},[1982,5168,2154],{"class":2099},[1982,5170,2072],{"class":1993},[1982,5172,2049],{"class":2003},[1982,5174,5175],{"class":1993}," errors",[1982,5177,2004],{"class":2003},[1982,5179,1153],{"class":2007},[1982,5181,2042],{"class":2003},[1982,5183,2139],{"class":2045},[1982,5185,2142],{"class":2003},[1982,5187,5188],{"class":1984,"line":2096},[1982,5189,2999],{"class":2003},[1982,5191,5192,5195,5197,5199],{"class":1984,"line":2119},[1982,5193,5194],{"class":2099},"    return",[1982,5196,2072],{"class":1993},[1982,5198,2049],{"class":2003},[1982,5200,2161],{"class":2052},[1982,5202,5203],{"class":1984,"line":2145},[1982,5204,5205],{"class":2003},"}))\n",[3557,5207,33],{"id":5208},"zero-magic",[3221,5210,5211,5217,5220,5223],{},[3224,5212,5213,5214],{},"Processors name themselves via ",[1979,5215,5216],{},"pipz.Name",[3224,5218,5219],{},"Schemas are plain YAML/JSON",[3224,5221,5222],{},"Validation errors include full paths",[3224,5224,5225],{},"No reflection at runtime",[1968,5227,38],{"id":3115},[1891,5229,5230],{},"Schema-driven pipelines open possibilities:",[1891,5232,5233,5238],{},[3227,5234,5235],{},[1894,5236,219],{"href":5237},"guides/hot-reloading"," - Update pipeline behaviour without restarts. A/B test processing logic, toggle features, respond to changing requirements.",[1891,5240,5241,5244],{},[3227,5242,5243],{},"Multi-tenant Processing"," - Different schemas per tenant. Same registered components, different compositions based on customer tier or configuration.",[1891,5246,5247,5249],{},[3227,5248,303],{}," - Route pipeline outputs to Go channels. Fan-out to multiple streams, integrate with async consumers.",[1891,5251,5252,5258],{},[3227,5253,5254],{},[1894,5255,5257],{"href":5256},"guides/error-handling","Resilience Patterns"," - Retry, timeout, circuit breaker, rate limiting - all declarative in schema. Change resilience strategy without code changes.",[1891,5260,5261],{},"Flume provides the composition layer. What pipelines you build is up to you.",[1968,5263,43],{"id":5264},"priorities",[3557,5266,47],{"id":5267},"type-safety",[1891,5269,5270],{},"Full generics from factory to pipeline. The type flows through:",[1973,5272,5274],{"className":1975,"code":5273,"language":1977,"meta":24,"style":24},"factory := flume.New[Order]()      // Factory[Order]\nfactory.Add(orderProcessor)         // Only accepts Chainable[Order]\npipeline, _ := factory.Build(schema)\nresult, _ := pipeline.Process(ctx, order) // Returns (Order, error)\n",[1979,5275,5276,5298,5316,5339],{"__ignoreMap":24},[1982,5277,5278,5280,5282,5284,5286,5288,5290,5292,5295],{"class":1984,"line":9},[1982,5279,1994],{"class":1993},[1982,5281,1997],{"class":1993},[1982,5283,2000],{"class":1993},[1982,5285,2004],{"class":2003},[1982,5287,1153],{"class":2007},[1982,5289,2010],{"class":2003},[1982,5291,2014],{"class":2013},[1982,5293,5294],{"class":2003},"]()",[1982,5296,5297],{"class":1987},"      // Factory[Order]\n",[1982,5299,5300,5302,5304,5306,5308,5311,5313],{"class":1984,"line":19},[1982,5301,1994],{"class":1993},[1982,5303,2004],{"class":2003},[1982,5305,1162],{"class":2007},[1982,5307,2042],{"class":2003},[1982,5309,5310],{"class":1993},"orderProcessor",[1982,5312,2078],{"class":2003},[1982,5314,5315],{"class":1987},"         // Only accepts Chainable[Order]\n",[1982,5317,5318,5320,5322,5324,5326,5328,5330,5332,5334,5337],{"class":1984,"line":30},[1982,5319,2373],{"class":1993},[1982,5321,2049],{"class":2003},[1982,5323,2378],{"class":1993},[1982,5325,1997],{"class":1993},[1982,5327,2383],{"class":1993},[1982,5329,2004],{"class":2003},[1982,5331,1267],{"class":2007},[1982,5333,2042],{"class":2003},[1982,5335,5336],{"class":1993},"schema",[1982,5338,2142],{"class":2003},[1982,5340,5341,5343,5345,5347,5349,5351,5353,5355,5357,5359,5361,5363,5365],{"class":1984,"line":2031},[1982,5342,2459],{"class":1993},[1982,5344,2049],{"class":2003},[1982,5346,2378],{"class":1993},[1982,5348,1997],{"class":1993},[1982,5350,2469],{"class":1993},[1982,5352,2004],{"class":2003},[1982,5354,1326],{"class":2007},[1982,5356,2042],{"class":2003},[1982,5358,2059],{"class":1993},[1982,5360,2049],{"class":2003},[1982,5362,2482],{"class":1993},[1982,5364,2078],{"class":2003},[1982,5366,5367],{"class":1987}," // Returns (Order, error)\n",[3557,5369,52],{"id":5370},"validation",[1891,5372,5373],{},"Schemas validate before building. Missing references, invalid configurations, structural errors - caught early with clear messages:",[1973,5375,5378],{"className":5376,"code":5377,"language":4497},[4495],"3 validation errors:\n  1. root.children[0]: processor 'missing' not found\n  2. root.children[1]: predicate 'unknown' not found\n  3. root.children[2].timeout: invalid duration \"bad\"\n",[1979,5379,5377],{"__ignoreMap":24},[3557,5381,57],{"id":5382},"performance",[1891,5384,5385,5386,5389],{},"Built pipelines execute with zero overhead - the result ",[3391,5387,5388],{},"is"," a pipz pipeline. Cost is only at build time:",[3117,5391,5392,5402],{},[3120,5393,5394],{},[3123,5395,5396,5399],{},[3126,5397,5398],{},"Operation",[3126,5400,5401],{},"Time",[3136,5403,5404,5412],{},[3123,5405,5406,5409],{},[3141,5407,5408],{},"Pipeline execution (3-step sequence)",[3141,5410,5411],{},"~459 ns",[3123,5413,5414,5417],{},[3141,5415,5416],{},"Schema build (10-step sequence)",[3141,5418,5419],{},"~6.7 µs",[1891,5421,5422],{},"Build once, execute many times.",[1968,5424,62],{"id":3548},[3557,5426,5427],{"id":3559},[1894,5428,66],{"href":5429},"learn/quickstart",[3221,5431,5432,5437,5443,5449],{},[3224,5433,5434,5436],{},[1894,5435,81],{"href":5429}," - Your first pipeline in 5 minutes",[3224,5438,5439,5442],{},[1894,5440,155],{"href":5441},"learn/core-concepts"," - Factories, schemas, and components",[3224,5444,5445,5448],{},[1894,5446,16],{"href":5447},"learn/architecture"," - How Flume works under the hood",[3224,5450,5451,5454],{},[1894,5452,209],{"href":5453},"learn/building-pipelines"," - From simple to complex",[3557,5456,5457],{"id":3588},[1894,5458,71],{"href":5459},"guides/schema-design",[3221,5461,5462,5467,5472,5477,5483],{},[3224,5463,5464,5466],{},[1894,5465,443],{"href":5459}," - Best practices for schema structure",[3224,5468,5469,5471],{},[1894,5470,219],{"href":5237}," - Update pipelines without restarts",[3224,5473,5474,5476],{},[1894,5475,363],{"href":5256}," - Retry, fallback, circuit breakers",[3224,5478,5479,5482],{},[1894,5480,879],{"href":5481},"guides/testing"," - Testing schema-driven pipelines",[3224,5484,5485,5488],{},[1894,5486,666],{"href":5487},"guides/observability"," - Monitoring with capitan events",[3557,5490,5491],{"id":3631},[1894,5492,76],{"href":5493},"reference/api",[3221,5495,5496,5501,5507,5513],{},[3224,5497,5498,5500],{},[1894,5499,1140],{"href":5493}," - Factory methods and types",[3224,5502,5503,5506],{},[1894,5504,1416],{"href":5505},"reference/schema-format"," - YAML/JSON specification",[3224,5508,5509,5512],{},[1894,5510,1443],{"href":5511},"reference/connector-types"," - All 14 connectors",[3224,5514,5515,5518],{},[1894,5516,1642],{"href":5517},"reference/events"," - Observability signals",[3677,5520,5521],{},"html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}",{"title":24,"searchDepth":19,"depth":19,"links":5523},[5524,5525,5529,5530,5535],{"id":5012,"depth":19,"text":16},{"id":5024,"depth":19,"text":22,"children":5526},[5527,5528],{"id":5027,"depth":30,"text":27},{"id":5208,"depth":30,"text":33},{"id":3115,"depth":19,"text":38},{"id":5264,"depth":19,"text":43,"children":5531},[5532,5533,5534],{"id":5267,"depth":30,"text":47},{"id":5370,"depth":30,"text":52},{"id":5382,"depth":30,"text":57},{"id":3548,"depth":19,"text":62,"children":5536},[5537,5538,5539],{"id":3559,"depth":30,"text":66},{"id":3588,"depth":30,"text":71},{"id":3631,"depth":30,"text":76},{},"2025-12-03T00:00:00.000Z",null,{"title":6,"description":8},[6,5545],"Introduction","2025-12-12T00:00:00.000Z","B_kGL0c_OIjClD8fBXBO7iS2R4jaCcX2yV75zsgyH1s",[5542,5549],{"title":81,"path":80,"stem":1811,"description":83,"children":-1},1776189694725]