[{"data":1,"prerenderedAt":8299},["ShallowReactive",2],{"search-sections-flume":3,"nav-flume":1798,"content-tree-flume":1852,"footer-resources":1878,"content-/v1.0.1/guides/hot-reloading":4731,"surround-/v1.0.1/guides/hot-reloading":8296},[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":219,"author":4733,"body":4734,"description":585,"extension":3697,"meta":8286,"navigation":2360,"path":583,"published":8287,"readtime":8288,"seo":8289,"stem":1826,"tags":8290,"updated":8294,"__hash__":8295},"flume/v1.0.1/3.guides/2.hot-reloading.md","zoobzio",{"type":1883,"value":4735,"toc":8251},[4736,4738,4740,4743,4746,4772,4775,4778,4996,4999,5145,5148,5303,5306,5309,5421,5424,5438,5441,5444,5447,5918,5921,6317,6320,6323,6744,6747,7128,7131,7134,7224,7227,7230,7474,7477,7480,7483,7572,7575,7852,7855,7858,7878,7881,7922,7925,7928,8037,8040,8043,8226,8229,8248],[1886,4737,219],{"id":3401},[1891,4739,589],{},[1968,4741,6],{"id":4742},"overview",[1891,4744,4745],{},"Flume's hot reloading enables:",[3221,4747,4748,4754,4760,4766],{},[3224,4749,4750,4753],{},[3227,4751,4752],{},"Zero-downtime updates"," - Swap pipelines while requests continue",[3224,4755,4756,4759],{},[3227,4757,4758],{},"A/B testing"," - Switch between pipeline variants",[3224,4761,4762,4765],{},[3227,4763,4764],{},"Feature flags"," - Enable/disable pipeline stages dynamically",[3224,4767,4768,4771],{},[3227,4769,4770],{},"Configuration-driven behaviour"," - Operators modify pipelines without deploys",[1968,4773,596],{"id":4774},"basic-usage",[3557,4776,600],{"id":4777},"register-named-schemas",[1973,4779,4781],{"className":1975,"code":4780,"language":1977,"meta":24,"style":24},"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)\n",[1979,4782,4783,4801,4805,4810,4828,4845,4849,4854,4870,4882,4897,4909,4927,4943,4956,4961,4966,4970,4974],{"__ignoreMap":24},[1982,4784,4785,4787,4789,4791,4793,4795,4797,4799],{"class":1984,"line":9},[1982,4786,1994],{"class":1993},[1982,4788,1997],{"class":1993},[1982,4790,2000],{"class":1993},[1982,4792,2004],{"class":2003},[1982,4794,1153],{"class":2007},[1982,4796,2010],{"class":2003},[1982,4798,2014],{"class":2013},[1982,4800,2017],{"class":2003},[1982,4802,4803],{"class":1984,"line":19},[1982,4804,2361],{"emptyLinePlaceholder":2360},[1982,4806,4807],{"class":1984,"line":30},[1982,4808,4809],{"class":1987},"// Register components\n",[1982,4811,4812,4814,4816,4818,4820,4823,4826],{"class":1984,"line":2031},[1982,4813,1994],{"class":1993},[1982,4815,2004],{"class":2003},[1982,4817,1162],{"class":2007},[1982,4819,2042],{"class":2003},[1982,4821,4822],{"class":1993},"processors",[1982,4824,4825],{"class":2099},"...",[1982,4827,2142],{"class":2003},[1982,4829,4830,4832,4834,4836,4838,4841,4843],{"class":1984,"line":2096},[1982,4831,1994],{"class":1993},[1982,4833,2004],{"class":2003},[1982,4835,1191],{"class":2007},[1982,4837,2042],{"class":2003},[1982,4839,4840],{"class":1993},"predicates",[1982,4842,4825],{"class":2099},[1982,4844,2142],{"class":2003},[1982,4846,4847],{"class":1984,"line":2119},[1982,4848,2361],{"emptyLinePlaceholder":2360},[1982,4850,4851],{"class":1984,"line":2145},[1982,4852,4853],{"class":1987},"// Register named schema\n",[1982,4855,4856,4859,4861,4863,4865,4867],{"class":1984,"line":2151},[1982,4857,4858],{"class":1993},"schema",[1982,4860,1997],{"class":1993},[1982,4862,2000],{"class":2013},[1982,4864,2004],{"class":2003},[1982,4866,1358],{"class":2013},[1982,4868,4869],{"class":2003},"{\n",[1982,4871,4872,4875,4877,4880],{"class":1984,"line":2164},[1982,4873,4874],{"class":2285},"    Version",[1982,4876,2289],{"class":2003},[1982,4878,4879],{"class":2045}," \"1.0.0\"",[1982,4881,2295],{"class":2003},[1982,4883,4884,4887,4889,4891,4893,4895],{"class":1984,"line":2170},[1982,4885,4886],{"class":2285},"    Node",[1982,4888,2289],{"class":2003},[1982,4890,2000],{"class":2013},[1982,4892,2004],{"class":2003},[1982,4894,1363],{"class":2013},[1982,4896,4869],{"class":2003},[1982,4898,4899,4902,4904,4907],{"class":1984,"line":2218},[1982,4900,4901],{"class":2285},"        Type",[1982,4903,2289],{"class":2003},[1982,4905,4906],{"class":2045}," \"sequence\"",[1982,4908,2295],{"class":2003},[1982,4910,4911,4914,4916,4919,4921,4923,4925],{"class":1984,"line":2237},[1982,4912,4913],{"class":2285},"        Children",[1982,4915,2289],{"class":2003},[1982,4917,4918],{"class":2003}," []",[1982,4920,1888],{"class":2013},[1982,4922,2004],{"class":2003},[1982,4924,1363],{"class":2013},[1982,4926,4869],{"class":2003},[1982,4928,4929,4932,4935,4937,4940],{"class":1984,"line":2248},[1982,4930,4931],{"class":2003},"            {",[1982,4933,4934],{"class":2285},"Ref",[1982,4936,2289],{"class":2003},[1982,4938,4939],{"class":2045}," \"validate\"",[1982,4941,4942],{"class":2003},"},\n",[1982,4944,4945,4947,4949,4951,4954],{"class":1984,"line":2253},[1982,4946,4931],{"class":2003},[1982,4948,4934],{"class":2285},[1982,4950,2289],{"class":2003},[1982,4952,4953],{"class":2045}," \"process\"",[1982,4955,4942],{"class":2003},[1982,4957,4958],{"class":1984,"line":2258},[1982,4959,4960],{"class":2003},"        },\n",[1982,4962,4963],{"class":1984,"line":2282},[1982,4964,4965],{"class":2003},"    },\n",[1982,4967,4968],{"class":1984,"line":2298},[1982,4969,2598],{"class":2003},[1982,4971,4972],{"class":1984,"line":2351},[1982,4973,2361],{"emptyLinePlaceholder":2360},[1982,4975,4976,4978,4980,4982,4984,4986,4988,4990,4992,4994],{"class":1984,"line":2357},[1982,4977,2991],{"class":1993},[1982,4979,1997],{"class":1993},[1982,4981,2383],{"class":1993},[1982,4983,2004],{"class":2003},[1982,4985,1291],{"class":2007},[1982,4987,2042],{"class":2003},[1982,4989,3427],{"class":2045},[1982,4991,2049],{"class":2003},[1982,4993,3432],{"class":1993},[1982,4995,2142],{"class":2003},[3557,4997,605],{"id":4998},"create-a-binding",[1973,5000,5002],{"className":1975,"code":5001,"language":1977,"meta":24,"style":24},"// 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)\n",[1979,5003,5004,5008,5033,5067,5080,5107,5111,5115,5119],{"__ignoreMap":24},[1982,5005,5006],{"class":1984,"line":9},[1982,5007,3443],{"class":1987},[1982,5009,5010,5012,5014,5016,5018,5021,5023,5026,5028,5031],{"class":1984,"line":19},[1982,5011,3465],{"class":1993},[1982,5013,1997],{"class":1993},[1982,5015,2383],{"class":1993},[1982,5017,2004],{"class":2003},[1982,5019,5020],{"class":2007},"Identity",[1982,5022,2042],{"class":2003},[1982,5024,5025],{"class":2045},"\"order-processor\"",[1982,5027,2049],{"class":2003},[1982,5029,5030],{"class":2045}," \"Processes incoming orders\"",[1982,5032,2142],{"class":2003},[1982,5034,5035,5037,5039,5041,5043,5045,5047,5049,5051,5053,5055,5057,5059,5061,5063,5065],{"class":1984,"line":30},[1982,5036,3448],{"class":1993},[1982,5038,2049],{"class":2003},[1982,5040,2464],{"class":1993},[1982,5042,1997],{"class":1993},[1982,5044,2383],{"class":1993},[1982,5046,2004],{"class":2003},[1982,5048,1311],{"class":2007},[1982,5050,2042],{"class":2003},[1982,5052,3465],{"class":1993},[1982,5054,2049],{"class":2003},[1982,5056,3470],{"class":2045},[1982,5058,2049],{"class":2003},[1982,5060,2000],{"class":1993},[1982,5062,2004],{"class":2003},[1982,5064,1331],{"class":2007},[1982,5066,3481],{"class":2003},[1982,5068,5069,5072,5074,5076,5078],{"class":1984,"line":2031},[1982,5070,5071],{"class":2099},"if",[1982,5073,2464],{"class":1993},[1982,5075,2974],{"class":2099},[1982,5077,2977],{"class":2052},[1982,5079,2093],{"class":2003},[1982,5081,5082,5085,5087,5089,5091,5093,5096,5099,5101,5103,5105],{"class":1984,"line":2096},[1982,5083,5084],{"class":2099},"    return",[1982,5086,2129],{"class":1993},[1982,5088,2004],{"class":2003},[1982,5090,2134],{"class":2007},[1982,5092,2042],{"class":2003},[1982,5094,5095],{"class":2045},"\"failed to bind: ",[1982,5097,5098],{"class":3082},"%w",[1982,5100,3096],{"class":2045},[1982,5102,2049],{"class":2003},[1982,5104,2464],{"class":1993},[1982,5106,2142],{"class":2003},[1982,5108,5109],{"class":1984,"line":2119},[1982,5110,2598],{"class":2003},[1982,5112,5113],{"class":1984,"line":2145},[1982,5114,2361],{"emptyLinePlaceholder":2360},[1982,5116,5117],{"class":1984,"line":2151},[1982,5118,3490],{"class":1987},[1982,5120,5121,5123,5125,5127,5129,5131,5133,5135,5137,5139,5141,5143],{"class":1984,"line":2164},[1982,5122,2459],{"class":1993},[1982,5124,2049],{"class":2003},[1982,5126,2464],{"class":1993},[1982,5128,1997],{"class":1993},[1982,5130,3503],{"class":1993},[1982,5132,2004],{"class":2003},[1982,5134,1326],{"class":2007},[1982,5136,2042],{"class":2003},[1982,5138,2059],{"class":1993},[1982,5140,2049],{"class":2003},[1982,5142,2482],{"class":1993},[1982,5144,2142],{"class":2003},[3557,5146,610],{"id":5147},"update-at-runtime",[1973,5149,5151],{"className":1975,"code":5150,"language":1977,"meta":24,"style":24},"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\n",[1979,5152,5153,5168,5179,5193,5203,5219,5231,5248,5260,5264,5268,5272,5276,5298],{"__ignoreMap":24},[1982,5154,5155,5158,5160,5162,5164,5166],{"class":1984,"line":9},[1982,5156,5157],{"class":1993},"newSchema",[1982,5159,1997],{"class":1993},[1982,5161,2000],{"class":2013},[1982,5163,2004],{"class":2003},[1982,5165,1358],{"class":2013},[1982,5167,4869],{"class":2003},[1982,5169,5170,5172,5174,5177],{"class":1984,"line":19},[1982,5171,4874],{"class":2285},[1982,5173,2289],{"class":2003},[1982,5175,5176],{"class":2045}," \"1.1.0\"",[1982,5178,2295],{"class":2003},[1982,5180,5181,5183,5185,5187,5189,5191],{"class":1984,"line":30},[1982,5182,4886],{"class":2285},[1982,5184,2289],{"class":2003},[1982,5186,2000],{"class":2013},[1982,5188,2004],{"class":2003},[1982,5190,1363],{"class":2013},[1982,5192,4869],{"class":2003},[1982,5194,5195,5197,5199,5201],{"class":1984,"line":2031},[1982,5196,4901],{"class":2285},[1982,5198,2289],{"class":2003},[1982,5200,4906],{"class":2045},[1982,5202,2295],{"class":2003},[1982,5204,5205,5207,5209,5211,5213,5215,5217],{"class":1984,"line":2096},[1982,5206,4913],{"class":2285},[1982,5208,2289],{"class":2003},[1982,5210,4918],{"class":2003},[1982,5212,1888],{"class":2013},[1982,5214,2004],{"class":2003},[1982,5216,1363],{"class":2013},[1982,5218,4869],{"class":2003},[1982,5220,5221,5223,5225,5227,5229],{"class":1984,"line":2119},[1982,5222,4931],{"class":2003},[1982,5224,4934],{"class":2285},[1982,5226,2289],{"class":2003},[1982,5228,4939],{"class":2045},[1982,5230,4942],{"class":2003},[1982,5232,5233,5235,5237,5239,5242,5245],{"class":1984,"line":2145},[1982,5234,4931],{"class":2003},[1982,5236,4934],{"class":2285},[1982,5238,2289],{"class":2003},[1982,5240,5241],{"class":2045}," \"enrich\"",[1982,5243,5244],{"class":2003},"},",[1982,5246,5247],{"class":1987},"  // Added step\n",[1982,5249,5250,5252,5254,5256,5258],{"class":1984,"line":2151},[1982,5251,4931],{"class":2003},[1982,5253,4934],{"class":2285},[1982,5255,2289],{"class":2003},[1982,5257,4953],{"class":2045},[1982,5259,4942],{"class":2003},[1982,5261,5262],{"class":1984,"line":2164},[1982,5263,4960],{"class":2003},[1982,5265,5266],{"class":1984,"line":2170},[1982,5267,4965],{"class":2003},[1982,5269,5270],{"class":1984,"line":2218},[1982,5271,2598],{"class":2003},[1982,5273,5274],{"class":1984,"line":2237},[1982,5275,2361],{"emptyLinePlaceholder":2360},[1982,5277,5278,5280,5282,5284,5286,5288,5290,5292,5294,5296],{"class":1984,"line":2248},[1982,5279,2991],{"class":1993},[1982,5281,1997],{"class":1993},[1982,5283,2383],{"class":1993},[1982,5285,2004],{"class":2003},[1982,5287,1291],{"class":2007},[1982,5289,2042],{"class":2003},[1982,5291,3427],{"class":2045},[1982,5293,2049],{"class":2003},[1982,5295,3543],{"class":1993},[1982,5297,2142],{"class":2003},[1982,5299,5300],{"class":1984,"line":2253},[1982,5301,5302],{"class":1987},"// New requests immediately use updated pipeline\n",[1968,5304,615],{"id":5305},"how-it-works",[3557,5307,619],{"id":5308},"atomic-pointer-swap",[1973,5310,5312],{"className":1975,"code":5311,"language":1977,"meta":24,"style":24},"// 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\n",[1979,5313,5314,5319,5363,5367,5372,5392,5396,5401],{"__ignoreMap":24},[1982,5315,5316],{"class":1984,"line":9},[1982,5317,5318],{"class":1987},"// Internally, pipelines are stored as atomic pointers\n",[1982,5320,5321,5324,5327,5329,5332,5335,5338,5341,5343,5346,5348,5350,5352,5355,5357,5360],{"class":1984,"line":19},[1982,5322,5323],{"class":1993},"pipelines",[1982,5325,5326],{"class":2052}," map",[1982,5328,2010],{"class":2003},[1982,5330,5331],{"class":2013},"string",[1982,5333,5334],{"class":2003},"]",[1982,5336,5337],{"class":2099},"*",[1982,5339,5340],{"class":2013},"atomic",[1982,5342,2004],{"class":2003},[1982,5344,5345],{"class":2013},"Pointer",[1982,5347,2010],{"class":2003},[1982,5349,1965],{"class":2013},[1982,5351,2004],{"class":2003},[1982,5353,5354],{"class":2013},"Chainable",[1982,5356,2010],{"class":2003},[1982,5358,5359],{"class":2013},"T",[1982,5361,5362],{"class":2003},"]]\n",[1982,5364,5365],{"class":1984,"line":30},[1982,5366,2361],{"emptyLinePlaceholder":2360},[1982,5368,5369],{"class":1984,"line":2031},[1982,5370,5371],{"class":1987},"// Update atomically swaps the pointer\n",[1982,5373,5374,5377,5379,5382,5384,5387,5390],{"class":1984,"line":2096},[1982,5375,5376],{"class":1993},"ptr",[1982,5378,2004],{"class":2003},[1982,5380,5381],{"class":2007},"Store",[1982,5383,2042],{"class":2003},[1982,5385,5386],{"class":2099},"&",[1982,5388,5389],{"class":1993},"newPipeline",[1982,5391,2142],{"class":2003},[1982,5393,5394],{"class":1984,"line":2119},[1982,5395,2361],{"emptyLinePlaceholder":2360},[1982,5397,5398],{"class":1984,"line":2145},[1982,5399,5400],{"class":1987},"// Retrieval loads atomically\n",[1982,5402,5403,5406,5409,5411,5413,5416,5418],{"class":1984,"line":2151},[1982,5404,5405],{"class":2099},"return",[1982,5407,5408],{"class":2099}," *",[1982,5410,5376],{"class":1993},[1982,5412,2004],{"class":2003},[1982,5414,5415],{"class":2007},"Load",[1982,5417,3041],{"class":2003},[1982,5419,5420],{"class":2052}," true\n",[3557,5422,624],{"id":5423},"request-continuity",[3779,5425,5426,5429,5432,5435],{},[3224,5427,5428],{},"Request A starts with pipeline v1",[3224,5430,5431],{},"Schema updates to v2",[3224,5433,5434],{},"Request A completes with v1 (unaffected)",[3224,5436,5437],{},"Request B starts with v2",[1891,5439,5440],{},"No locks are held during processing - updates don't block requests.",[1968,5442,629],{"id":5443},"file-based-reloading",[3557,5445,633],{"id":5446},"watch-for-changes",[1973,5448,5450],{"className":1975,"code":5449,"language":1977,"meta":24,"style":24},"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}\n",[1979,5451,5452,5498,5520,5535,5539,5554,5558,5565,5572,5590,5595,5616,5642,5657,5661,5665,5669,5673,5677,5710,5732,5744,5768,5773,5777,5781,5786,5811,5825,5849,5853,5887,5910,5914],{"__ignoreMap":24},[1982,5453,5454,5456,5459,5461,5463,5465,5467,5469,5471,5473,5475,5477,5479,5481,5483,5485,5488,5491,5494,5496],{"class":1984,"line":9},[1982,5455,2607],{"class":2052},[1982,5457,5458],{"class":2007}," watchSchemaFile",[1982,5460,2042],{"class":2003},[1982,5462,2059],{"class":2058},[1982,5464,2062],{"class":2013},[1982,5466,2004],{"class":2003},[1982,5468,2067],{"class":2013},[1982,5470,2049],{"class":2003},[1982,5472,2383],{"class":2058},[1982,5474,5408],{"class":2099},[1982,5476,1888],{"class":2013},[1982,5478,2004],{"class":2003},[1982,5480,1149],{"class":2013},[1982,5482,2010],{"class":2003},[1982,5484,2014],{"class":2013},[1982,5486,5487],{"class":2003},"],",[1982,5489,5490],{"class":2058}," path",[1982,5492,5493],{"class":2013}," string",[1982,5495,2078],{"class":2003},[1982,5497,2093],{"class":2003},[1982,5499,5500,5503,5505,5507,5509,5512,5514,5517],{"class":1984,"line":19},[1982,5501,5502],{"class":1993},"    watcher",[1982,5504,2049],{"class":2003},[1982,5506,2378],{"class":1993},[1982,5508,1997],{"class":1993},[1982,5510,5511],{"class":1993}," fsnotify",[1982,5513,2004],{"class":2003},[1982,5515,5516],{"class":2007},"NewWatcher",[1982,5518,5519],{"class":2003},"()\n",[1982,5521,5522,5525,5528,5530,5533],{"class":1984,"line":30},[1982,5523,5524],{"class":2099},"    defer",[1982,5526,5527],{"class":1993}," watcher",[1982,5529,2004],{"class":2003},[1982,5531,5532],{"class":2007},"Close",[1982,5534,5519],{"class":2003},[1982,5536,5537],{"class":1984,"line":2031},[1982,5538,2361],{"emptyLinePlaceholder":2360},[1982,5540,5541,5543,5545,5547,5549,5552],{"class":1984,"line":2096},[1982,5542,5502],{"class":1993},[1982,5544,2004],{"class":2003},[1982,5546,1162],{"class":2007},[1982,5548,2042],{"class":2003},[1982,5550,5551],{"class":1993},"path",[1982,5553,2142],{"class":2003},[1982,5555,5556],{"class":1984,"line":2119},[1982,5557,2361],{"emptyLinePlaceholder":2360},[1982,5559,5560,5563],{"class":1984,"line":2145},[1982,5561,5562],{"class":2099},"    for",[1982,5564,2093],{"class":2003},[1982,5566,5567,5570],{"class":1984,"line":2151},[1982,5568,5569],{"class":2099},"        select",[1982,5571,2093],{"class":2003},[1982,5573,5574,5577,5580,5582,5584,5587],{"class":1984,"line":2164},[1982,5575,5576],{"class":2099},"        case",[1982,5578,5579],{"class":2099}," \u003C-",[1982,5581,2059],{"class":1993},[1982,5583,2004],{"class":2003},[1982,5585,5586],{"class":2007},"Done",[1982,5588,5589],{"class":2003},"():\n",[1982,5591,5592],{"class":1984,"line":2170},[1982,5593,5594],{"class":2099},"            return\n",[1982,5596,5597,5599,5602,5604,5606,5609,5611,5613],{"class":1984,"line":2218},[1982,5598,5576],{"class":2099},[1982,5600,5601],{"class":1993}," event",[1982,5603,1997],{"class":1993},[1982,5605,5579],{"class":2099},[1982,5607,5608],{"class":1993},"watcher",[1982,5610,2004],{"class":2003},[1982,5612,1642],{"class":1993},[1982,5614,5615],{"class":2003},":\n",[1982,5617,5618,5620,5622,5624,5627,5629,5632,5634,5636,5638,5640],{"class":1984,"line":2237},[1982,5619,2768],{"class":2099},[1982,5621,5601],{"class":1993},[1982,5623,2004],{"class":2003},[1982,5625,5626],{"class":1993},"Op&fsnotify",[1982,5628,2004],{"class":2003},[1982,5630,5631],{"class":1993},"Write",[1982,5633,2342],{"class":2099},[1982,5635,5511],{"class":1993},[1982,5637,2004],{"class":2003},[1982,5639,5631],{"class":1993},[1982,5641,2093],{"class":2003},[1982,5643,5644,5647,5649,5651,5653,5655],{"class":1984,"line":2248},[1982,5645,5646],{"class":2007},"                reloadSchema",[1982,5648,2042],{"class":2003},[1982,5650,1994],{"class":1993},[1982,5652,2049],{"class":2003},[1982,5654,5490],{"class":1993},[1982,5656,2142],{"class":2003},[1982,5658,5659],{"class":1984,"line":2253},[1982,5660,2806],{"class":2003},[1982,5662,5663],{"class":1984,"line":2258},[1982,5664,2148],{"class":2003},[1982,5666,5667],{"class":1984,"line":2282},[1982,5668,2999],{"class":2003},[1982,5670,5671],{"class":1984,"line":2298},[1982,5672,2598],{"class":2003},[1982,5674,5675],{"class":1984,"line":2351},[1982,5676,2361],{"emptyLinePlaceholder":2360},[1982,5678,5679,5681,5684,5686,5688,5690,5692,5694,5696,5698,5700,5702,5704,5706,5708],{"class":1984,"line":2357},[1982,5680,2607],{"class":2052},[1982,5682,5683],{"class":2007}," reloadSchema",[1982,5685,2042],{"class":2003},[1982,5687,1994],{"class":2058},[1982,5689,5408],{"class":2099},[1982,5691,1888],{"class":2013},[1982,5693,2004],{"class":2003},[1982,5695,1149],{"class":2013},[1982,5697,2010],{"class":2003},[1982,5699,2014],{"class":2013},[1982,5701,5487],{"class":2003},[1982,5703,5490],{"class":2058},[1982,5705,5493],{"class":2013},[1982,5707,2078],{"class":2003},[1982,5709,2093],{"class":2003},[1982,5711,5712,5714,5716,5718,5720,5722,5724,5726,5728,5730],{"class":1984,"line":2364},[1982,5713,2919],{"class":1993},[1982,5715,2049],{"class":2003},[1982,5717,2464],{"class":1993},[1982,5719,1997],{"class":1993},[1982,5721,2383],{"class":1993},[1982,5723,2004],{"class":2003},[1982,5725,1282],{"class":2007},[1982,5727,2042],{"class":2003},[1982,5729,5551],{"class":1993},[1982,5731,2142],{"class":2003},[1982,5733,5734,5736,5738,5740,5742],{"class":1984,"line":2370},[1982,5735,2969],{"class":2099},[1982,5737,2464],{"class":1993},[1982,5739,2974],{"class":2099},[1982,5741,2977],{"class":2052},[1982,5743,2093],{"class":2003},[1982,5745,5746,5749,5751,5753,5755,5758,5760,5762,5764,5766],{"class":1984,"line":2395},[1982,5747,5748],{"class":1993},"        log",[1982,5750,2004],{"class":2003},[1982,5752,3074],{"class":2007},[1982,5754,2042],{"class":2003},[1982,5756,5757],{"class":2045},"\"failed to reload schema: ",[1982,5759,3089],{"class":3082},[1982,5761,3096],{"class":2045},[1982,5763,2049],{"class":2003},[1982,5765,2464],{"class":1993},[1982,5767,2142],{"class":2003},[1982,5769,5770],{"class":1984,"line":2401},[1982,5771,5772],{"class":2099},"        return\n",[1982,5774,5775],{"class":1984,"line":2407},[1982,5776,2999],{"class":2003},[1982,5778,5779],{"class":1984,"line":2413},[1982,5780,2361],{"emptyLinePlaceholder":2360},[1982,5782,5783],{"class":1984,"line":2419},[1982,5784,5785],{"class":1987},"    // Read file to get schema for SetSchema\n",[1982,5787,5788,5791,5793,5795,5797,5800,5802,5805,5807,5809],{"class":1984,"line":2425},[1982,5789,5790],{"class":1993},"    data",[1982,5792,2049],{"class":2003},[1982,5794,2378],{"class":1993},[1982,5796,1997],{"class":1993},[1982,5798,5799],{"class":1993}," os",[1982,5801,2004],{"class":2003},[1982,5803,5804],{"class":2007},"ReadFile",[1982,5806,2042],{"class":2003},[1982,5808,5551],{"class":1993},[1982,5810,2142],{"class":2003},[1982,5812,5813,5816,5818,5820,5822],{"class":1984,"line":2431},[1982,5814,5815],{"class":2052},"    var",[1982,5817,3432],{"class":1993},[1982,5819,2000],{"class":2013},[1982,5821,2004],{"class":2003},[1982,5823,5824],{"class":2013},"Schema\n",[1982,5826,5827,5830,5832,5835,5837,5840,5842,5845,5847],{"class":1984,"line":2437},[1982,5828,5829],{"class":1993},"    yaml",[1982,5831,2004],{"class":2003},[1982,5833,5834],{"class":2007},"Unmarshal",[1982,5836,2042],{"class":2003},[1982,5838,5839],{"class":1993},"data",[1982,5841,2049],{"class":2003},[1982,5843,5844],{"class":2099}," &",[1982,5846,4858],{"class":1993},[1982,5848,2142],{"class":2003},[1982,5850,5851],{"class":1984,"line":2445},[1982,5852,2361],{"emptyLinePlaceholder":2360},[1982,5854,5855,5857,5859,5861,5863,5865,5867,5869,5872,5874,5876,5879,5881,5883,5885],{"class":1984,"line":2450},[1982,5856,2969],{"class":2099},[1982,5858,2464],{"class":1993},[1982,5860,1997],{"class":1993},[1982,5862,2383],{"class":1993},[1982,5864,2004],{"class":2003},[1982,5866,1291],{"class":2007},[1982,5868,2042],{"class":2003},[1982,5870,5871],{"class":2045},"\"main\"",[1982,5873,2049],{"class":2003},[1982,5875,3432],{"class":1993},[1982,5877,5878],{"class":2003},");",[1982,5880,2464],{"class":1993},[1982,5882,2974],{"class":2099},[1982,5884,2977],{"class":2052},[1982,5886,2093],{"class":2003},[1982,5888,5889,5891,5893,5895,5897,5900,5902,5904,5906,5908],{"class":1984,"line":2456},[1982,5890,5748],{"class":1993},[1982,5892,2004],{"class":2003},[1982,5894,3074],{"class":2007},[1982,5896,2042],{"class":2003},[1982,5898,5899],{"class":2045},"\"failed to set schema: ",[1982,5901,3089],{"class":3082},[1982,5903,3096],{"class":2045},[1982,5905,2049],{"class":2003},[1982,5907,2464],{"class":1993},[1982,5909,2142],{"class":2003},[1982,5911,5912],{"class":1984,"line":2905},[1982,5913,2999],{"class":2003},[1982,5915,5916],{"class":1984,"line":2910},[1982,5917,2598],{"class":2003},[3557,5919,638],{"id":5920},"multi-schema-directory",[1973,5922,5924],{"className":1975,"code":5923,"language":1977,"meta":24,"style":24},"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}\n",[1979,5925,5926,5970,5988,6003,6007,6026,6046,6051,6055,6059,6115,6119,6146,6159,6194,6229,6233,6237,6241,6274,6305,6309,6313],{"__ignoreMap":24},[1982,5927,5928,5930,5933,5935,5937,5939,5941,5943,5945,5947,5949,5951,5953,5955,5957,5959,5961,5964,5966,5968],{"class":1984,"line":9},[1982,5929,2607],{"class":2052},[1982,5931,5932],{"class":2007}," watchSchemaDir",[1982,5934,2042],{"class":2003},[1982,5936,2059],{"class":2058},[1982,5938,2062],{"class":2013},[1982,5940,2004],{"class":2003},[1982,5942,2067],{"class":2013},[1982,5944,2049],{"class":2003},[1982,5946,2383],{"class":2058},[1982,5948,5408],{"class":2099},[1982,5950,1888],{"class":2013},[1982,5952,2004],{"class":2003},[1982,5954,1149],{"class":2013},[1982,5956,2010],{"class":2003},[1982,5958,2014],{"class":2013},[1982,5960,5487],{"class":2003},[1982,5962,5963],{"class":2058}," dir",[1982,5965,5493],{"class":2013},[1982,5967,2078],{"class":2003},[1982,5969,2093],{"class":2003},[1982,5971,5972,5974,5976,5978,5980,5982,5984,5986],{"class":1984,"line":19},[1982,5973,5502],{"class":1993},[1982,5975,2049],{"class":2003},[1982,5977,2378],{"class":1993},[1982,5979,1997],{"class":1993},[1982,5981,5511],{"class":1993},[1982,5983,2004],{"class":2003},[1982,5985,5516],{"class":2007},[1982,5987,5519],{"class":2003},[1982,5989,5990,5992,5994,5996,5998,6001],{"class":1984,"line":30},[1982,5991,5502],{"class":1993},[1982,5993,2004],{"class":2003},[1982,5995,1162],{"class":2007},[1982,5997,2042],{"class":2003},[1982,5999,6000],{"class":1993},"dir",[1982,6002,2142],{"class":2003},[1982,6004,6005],{"class":1984,"line":2031},[1982,6006,2361],{"emptyLinePlaceholder":2360},[1982,6008,6009,6011,6013,6015,6018,6020,6022,6024],{"class":1984,"line":2096},[1982,6010,5562],{"class":2099},[1982,6012,5601],{"class":1993},[1982,6014,1997],{"class":1993},[1982,6016,6017],{"class":2099}," range",[1982,6019,5527],{"class":1993},[1982,6021,2004],{"class":2003},[1982,6023,1642],{"class":1993},[1982,6025,2093],{"class":2003},[1982,6027,6028,6030,6032,6034,6036,6038,6040,6042,6044],{"class":1984,"line":2119},[1982,6029,2100],{"class":2099},[1982,6031,5601],{"class":1993},[1982,6033,2004],{"class":2003},[1982,6035,5626],{"class":1993},[1982,6037,2004],{"class":2003},[1982,6039,5631],{"class":1993},[1982,6041,2342],{"class":2099},[1982,6043,2114],{"class":2113},[1982,6045,2093],{"class":2003},[1982,6047,6048],{"class":1984,"line":2145},[1982,6049,6050],{"class":2099},"            continue\n",[1982,6052,6053],{"class":1984,"line":2151},[1982,6054,2148],{"class":2003},[1982,6056,6057],{"class":1984,"line":2164},[1982,6058,2361],{"emptyLinePlaceholder":2360},[1982,6060,6061,6064,6066,6069,6071,6074,6076,6079,6081,6084,6086,6089,6091,6094,6097,6100,6102,6105,6107,6109,6111,6113],{"class":1984,"line":2170},[1982,6062,6063],{"class":1993},"        name",[1982,6065,1997],{"class":1993},[1982,6067,6068],{"class":1993}," strings",[1982,6070,2004],{"class":2003},[1982,6072,6073],{"class":2007},"TrimSuffix",[1982,6075,2042],{"class":2003},[1982,6077,6078],{"class":1993},"filepath",[1982,6080,2004],{"class":2003},[1982,6082,6083],{"class":2007},"Base",[1982,6085,2042],{"class":2003},[1982,6087,6088],{"class":1993},"event",[1982,6090,2004],{"class":2003},[1982,6092,6093],{"class":1993},"Name",[1982,6095,6096],{"class":2003},"),",[1982,6098,6099],{"class":1993}," filepath",[1982,6101,2004],{"class":2003},[1982,6103,6104],{"class":2007},"Ext",[1982,6106,2042],{"class":2003},[1982,6108,6088],{"class":1993},[1982,6110,2004],{"class":2003},[1982,6112,6093],{"class":1993},[1982,6114,3354],{"class":2003},[1982,6116,6117],{"class":1984,"line":2218},[1982,6118,2361],{"emptyLinePlaceholder":2360},[1982,6120,6121,6124,6126,6128,6130,6132,6134,6136,6138,6140,6142,6144],{"class":1984,"line":2237},[1982,6122,6123],{"class":1993},"        data",[1982,6125,2049],{"class":2003},[1982,6127,2378],{"class":1993},[1982,6129,1997],{"class":1993},[1982,6131,5799],{"class":1993},[1982,6133,2004],{"class":2003},[1982,6135,5804],{"class":2007},[1982,6137,2042],{"class":2003},[1982,6139,6088],{"class":1993},[1982,6141,2004],{"class":2003},[1982,6143,6093],{"class":1993},[1982,6145,2142],{"class":2003},[1982,6147,6148,6151,6153,6155,6157],{"class":1984,"line":2248},[1982,6149,6150],{"class":2052},"        var",[1982,6152,3432],{"class":1993},[1982,6154,2000],{"class":2013},[1982,6156,2004],{"class":2003},[1982,6158,5824],{"class":2013},[1982,6160,6161,6163,6165,6167,6170,6172,6174,6176,6178,6180,6182,6184,6186,6188,6190,6192],{"class":1984,"line":2253},[1982,6162,2100],{"class":2099},[1982,6164,2464],{"class":1993},[1982,6166,1997],{"class":1993},[1982,6168,6169],{"class":1993}," yaml",[1982,6171,2004],{"class":2003},[1982,6173,5834],{"class":2007},[1982,6175,2042],{"class":2003},[1982,6177,5839],{"class":1993},[1982,6179,2049],{"class":2003},[1982,6181,5844],{"class":2099},[1982,6183,4858],{"class":1993},[1982,6185,5878],{"class":2003},[1982,6187,2464],{"class":1993},[1982,6189,2974],{"class":2099},[1982,6191,2977],{"class":2052},[1982,6193,2093],{"class":2003},[1982,6195,6196,6199,6201,6203,6205,6208,6211,6214,6216,6218,6220,6223,6225,6227],{"class":1984,"line":2258},[1982,6197,6198],{"class":1993},"            log",[1982,6200,2004],{"class":2003},[1982,6202,3074],{"class":2007},[1982,6204,2042],{"class":2003},[1982,6206,6207],{"class":2045},"\"invalid schema ",[1982,6209,6210],{"class":3082},"%s",[1982,6212,6213],{"class":2045},": ",[1982,6215,3089],{"class":3082},[1982,6217,3096],{"class":2045},[1982,6219,2049],{"class":2003},[1982,6221,6222],{"class":1993}," name",[1982,6224,2049],{"class":2003},[1982,6226,2464],{"class":1993},[1982,6228,2142],{"class":2003},[1982,6230,6231],{"class":1984,"line":2282},[1982,6232,6050],{"class":2099},[1982,6234,6235],{"class":1984,"line":2298},[1982,6236,2148],{"class":2003},[1982,6238,6239],{"class":1984,"line":2351},[1982,6240,2361],{"emptyLinePlaceholder":2360},[1982,6242,6243,6245,6247,6249,6251,6253,6255,6257,6260,6262,6264,6266,6268,6270,6272],{"class":1984,"line":2357},[1982,6244,2100],{"class":2099},[1982,6246,2464],{"class":1993},[1982,6248,1997],{"class":1993},[1982,6250,2383],{"class":1993},[1982,6252,2004],{"class":2003},[1982,6254,1291],{"class":2007},[1982,6256,2042],{"class":2003},[1982,6258,6259],{"class":1993},"name",[1982,6261,2049],{"class":2003},[1982,6263,3432],{"class":1993},[1982,6265,5878],{"class":2003},[1982,6267,2464],{"class":1993},[1982,6269,2974],{"class":2099},[1982,6271,2977],{"class":2052},[1982,6273,2093],{"class":2003},[1982,6275,6276,6278,6280,6282,6284,6287,6289,6291,6293,6295,6297,6299,6301,6303],{"class":1984,"line":2364},[1982,6277,6198],{"class":1993},[1982,6279,2004],{"class":2003},[1982,6281,3074],{"class":2007},[1982,6283,2042],{"class":2003},[1982,6285,6286],{"class":2045},"\"failed to update ",[1982,6288,6210],{"class":3082},[1982,6290,6213],{"class":2045},[1982,6292,3089],{"class":3082},[1982,6294,3096],{"class":2045},[1982,6296,2049],{"class":2003},[1982,6298,6222],{"class":1993},[1982,6300,2049],{"class":2003},[1982,6302,2464],{"class":1993},[1982,6304,2142],{"class":2003},[1982,6306,6307],{"class":1984,"line":2370},[1982,6308,2148],{"class":2003},[1982,6310,6311],{"class":1984,"line":2395},[1982,6312,2999],{"class":2003},[1982,6314,6315],{"class":1984,"line":2401},[1982,6316,2598],{"class":2003},[1968,6318,643],{"id":6319},"remote-configuration",[3557,6321,647],{"id":6322},"http-endpoint",[1973,6324,6326],{"className":1975,"code":6325,"language":1977,"meta":24,"style":24},"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})\n",[1979,6327,6328,6378,6399,6403,6417,6427,6451,6463,6483,6487,6491,6517,6521,6530,6542,6574,6578,6610,6638,6642,6646,6663,6667,6676,6696,6714,6718,6722,6736,6740],{"__ignoreMap":24},[1982,6329,6330,6333,6335,6338,6340,6343,6345,6347,6349,6352,6355,6357,6360,6362,6365,6367,6369,6371,6374,6376],{"class":1984,"line":9},[1982,6331,6332],{"class":1993},"http",[1982,6334,2004],{"class":2003},[1982,6336,6337],{"class":2007},"HandleFunc",[1982,6339,2042],{"class":2003},[1982,6341,6342],{"class":2045},"\"/schemas/{name}\"",[1982,6344,2049],{"class":2003},[1982,6346,2053],{"class":2052},[1982,6348,2042],{"class":2003},[1982,6350,6351],{"class":2058},"w",[1982,6353,6354],{"class":2013}," http",[1982,6356,2004],{"class":2003},[1982,6358,6359],{"class":2013},"ResponseWriter",[1982,6361,2049],{"class":2003},[1982,6363,6364],{"class":2058}," r",[1982,6366,5408],{"class":2099},[1982,6368,6332],{"class":2013},[1982,6370,2004],{"class":2003},[1982,6372,6373],{"class":2013},"Request",[1982,6375,2078],{"class":2003},[1982,6377,2093],{"class":2003},[1982,6379,6380,6383,6385,6387,6389,6392,6394,6397],{"class":1984,"line":19},[1982,6381,6382],{"class":1993},"    name",[1982,6384,1997],{"class":1993},[1982,6386,6364],{"class":1993},[1982,6388,2004],{"class":2003},[1982,6390,6391],{"class":2007},"PathValue",[1982,6393,2042],{"class":2003},[1982,6395,6396],{"class":2045},"\"name\"",[1982,6398,2142],{"class":2003},[1982,6400,6401],{"class":1984,"line":30},[1982,6402,2361],{"emptyLinePlaceholder":2360},[1982,6404,6405,6408,6410,6412,6415],{"class":1984,"line":2031},[1982,6406,6407],{"class":2099},"    switch",[1982,6409,6364],{"class":1993},[1982,6411,2004],{"class":2003},[1982,6413,6414],{"class":1993},"Method",[1982,6416,2093],{"class":2003},[1982,6418,6419,6422,6425],{"class":1984,"line":2096},[1982,6420,6421],{"class":2099},"    case",[1982,6423,6424],{"class":2045}," \"GET\"",[1982,6426,5615],{"class":2003},[1982,6428,6429,6432,6434,6437,6439,6441,6443,6445,6447,6449],{"class":1984,"line":2119},[1982,6430,6431],{"class":1993},"        schema",[1982,6433,2049],{"class":2003},[1982,6435,6436],{"class":1993}," ok",[1982,6438,1997],{"class":1993},[1982,6440,2383],{"class":1993},[1982,6442,2004],{"class":2003},[1982,6444,1296],{"class":2007},[1982,6446,2042],{"class":2003},[1982,6448,6259],{"class":1993},[1982,6450,2142],{"class":2003},[1982,6452,6453,6455,6458,6461],{"class":1984,"line":2145},[1982,6454,2100],{"class":2099},[1982,6456,6457],{"class":2099}," !",[1982,6459,6460],{"class":1993},"ok",[1982,6462,2093],{"class":2003},[1982,6464,6465,6468,6470,6473,6475,6477,6479,6481],{"class":1984,"line":2151},[1982,6466,6467],{"class":1993},"            http",[1982,6469,2004],{"class":2003},[1982,6471,6472],{"class":2007},"NotFound",[1982,6474,2042],{"class":2003},[1982,6476,6351],{"class":1993},[1982,6478,2049],{"class":2003},[1982,6480,6364],{"class":1993},[1982,6482,2142],{"class":2003},[1982,6484,6485],{"class":1984,"line":2164},[1982,6486,5594],{"class":2099},[1982,6488,6489],{"class":1984,"line":2170},[1982,6490,2148],{"class":2003},[1982,6492,6493,6496,6498,6501,6503,6505,6508,6511,6513,6515],{"class":1984,"line":2218},[1982,6494,6495],{"class":1993},"        json",[1982,6497,2004],{"class":2003},[1982,6499,6500],{"class":2007},"NewEncoder",[1982,6502,2042],{"class":2003},[1982,6504,6351],{"class":1993},[1982,6506,6507],{"class":2003},").",[1982,6509,6510],{"class":2007},"Encode",[1982,6512,2042],{"class":2003},[1982,6514,4858],{"class":1993},[1982,6516,2142],{"class":2003},[1982,6518,6519],{"class":1984,"line":2237},[1982,6520,2361],{"emptyLinePlaceholder":2360},[1982,6522,6523,6525,6528],{"class":1984,"line":2248},[1982,6524,6421],{"class":2099},[1982,6526,6527],{"class":2045}," \"PUT\"",[1982,6529,5615],{"class":2003},[1982,6531,6532,6534,6536,6538,6540],{"class":1984,"line":2253},[1982,6533,6150],{"class":2052},[1982,6535,3432],{"class":1993},[1982,6537,2000],{"class":2013},[1982,6539,2004],{"class":2003},[1982,6541,5824],{"class":2013},[1982,6543,6544,6546,6548,6551,6553,6556,6558,6561,6563,6566,6568,6570,6572],{"class":1984,"line":2258},[1982,6545,6495],{"class":1993},[1982,6547,2004],{"class":2003},[1982,6549,6550],{"class":2007},"NewDecoder",[1982,6552,2042],{"class":2003},[1982,6554,6555],{"class":1993},"r",[1982,6557,2004],{"class":2003},[1982,6559,6560],{"class":1993},"Body",[1982,6562,6507],{"class":2003},[1982,6564,6565],{"class":2007},"Decode",[1982,6567,2042],{"class":2003},[1982,6569,5386],{"class":2099},[1982,6571,4858],{"class":1993},[1982,6573,2142],{"class":2003},[1982,6575,6576],{"class":1984,"line":2282},[1982,6577,2361],{"emptyLinePlaceholder":2360},[1982,6579,6580,6582,6584,6586,6588,6590,6592,6594,6596,6598,6600,6602,6604,6606,6608],{"class":1984,"line":2298},[1982,6581,2100],{"class":2099},[1982,6583,2464],{"class":1993},[1982,6585,1997],{"class":1993},[1982,6587,2383],{"class":1993},[1982,6589,2004],{"class":2003},[1982,6591,1291],{"class":2007},[1982,6593,2042],{"class":2003},[1982,6595,6259],{"class":1993},[1982,6597,2049],{"class":2003},[1982,6599,3432],{"class":1993},[1982,6601,5878],{"class":2003},[1982,6603,2464],{"class":1993},[1982,6605,2974],{"class":2099},[1982,6607,2977],{"class":2052},[1982,6609,2093],{"class":2003},[1982,6611,6612,6614,6616,6619,6621,6623,6625,6627,6629,6631,6633,6636],{"class":1984,"line":2351},[1982,6613,6467],{"class":1993},[1982,6615,2004],{"class":2003},[1982,6617,6618],{"class":2007},"Error",[1982,6620,2042],{"class":2003},[1982,6622,6351],{"class":1993},[1982,6624,2049],{"class":2003},[1982,6626,2464],{"class":1993},[1982,6628,2004],{"class":2003},[1982,6630,6618],{"class":2007},[1982,6632,3041],{"class":2003},[1982,6634,6635],{"class":2113}," 400",[1982,6637,2142],{"class":2003},[1982,6639,6640],{"class":1984,"line":2357},[1982,6641,5594],{"class":2099},[1982,6643,6644],{"class":1984,"line":2364},[1982,6645,2148],{"class":2003},[1982,6647,6648,6651,6653,6656,6658,6661],{"class":1984,"line":2370},[1982,6649,6650],{"class":1993},"        w",[1982,6652,2004],{"class":2003},[1982,6654,6655],{"class":2007},"WriteHeader",[1982,6657,2042],{"class":2003},[1982,6659,6660],{"class":2113},"204",[1982,6662,2142],{"class":2003},[1982,6664,6665],{"class":1984,"line":2395},[1982,6666,2361],{"emptyLinePlaceholder":2360},[1982,6668,6669,6671,6674],{"class":1984,"line":2401},[1982,6670,6421],{"class":2099},[1982,6672,6673],{"class":2045}," \"DELETE\"",[1982,6675,5615],{"class":2003},[1982,6677,6678,6680,6682,6684,6686,6688,6690,6692,6694],{"class":1984,"line":2407},[1982,6679,2100],{"class":2099},[1982,6681,6457],{"class":2099},[1982,6683,1994],{"class":1993},[1982,6685,2004],{"class":2003},[1982,6687,1301],{"class":2007},[1982,6689,2042],{"class":2003},[1982,6691,6259],{"class":1993},[1982,6693,2078],{"class":2003},[1982,6695,2093],{"class":2003},[1982,6697,6698,6700,6702,6704,6706,6708,6710,6712],{"class":1984,"line":2413},[1982,6699,6467],{"class":1993},[1982,6701,2004],{"class":2003},[1982,6703,6472],{"class":2007},[1982,6705,2042],{"class":2003},[1982,6707,6351],{"class":1993},[1982,6709,2049],{"class":2003},[1982,6711,6364],{"class":1993},[1982,6713,2142],{"class":2003},[1982,6715,6716],{"class":1984,"line":2419},[1982,6717,5594],{"class":2099},[1982,6719,6720],{"class":1984,"line":2425},[1982,6721,2148],{"class":2003},[1982,6723,6724,6726,6728,6730,6732,6734],{"class":1984,"line":2431},[1982,6725,6650],{"class":1993},[1982,6727,2004],{"class":2003},[1982,6729,6655],{"class":2007},[1982,6731,2042],{"class":2003},[1982,6733,6660],{"class":2113},[1982,6735,2142],{"class":2003},[1982,6737,6738],{"class":1984,"line":2437},[1982,6739,2999],{"class":2003},[1982,6741,6742],{"class":1984,"line":2445},[1982,6743,2354],{"class":2003},[3557,6745,652],{"id":6746},"polling",[1973,6748,6750],{"className":1975,"code":6749,"language":1977,"meta":24,"style":24},"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}\n",[1979,6751,6752,6796,6827,6841,6845,6851,6857,6871,6875,6891,6915,6927,6932,6936,6940,6962,6993,7007,7011,7030,7053,7080,7088,7093,7112,7116,7120,7124],{"__ignoreMap":24},[1982,6753,6754,6756,6759,6761,6763,6765,6767,6769,6771,6773,6775,6777,6779,6781,6783,6785,6787,6790,6792,6794],{"class":1984,"line":9},[1982,6755,2607],{"class":2052},[1982,6757,6758],{"class":2007}," pollSchemas",[1982,6760,2042],{"class":2003},[1982,6762,2059],{"class":2058},[1982,6764,2062],{"class":2013},[1982,6766,2004],{"class":2003},[1982,6768,2067],{"class":2013},[1982,6770,2049],{"class":2003},[1982,6772,2383],{"class":2058},[1982,6774,5408],{"class":2099},[1982,6776,1888],{"class":2013},[1982,6778,2004],{"class":2003},[1982,6780,1149],{"class":2013},[1982,6782,2010],{"class":2003},[1982,6784,2014],{"class":2013},[1982,6786,5487],{"class":2003},[1982,6788,6789],{"class":2058}," url",[1982,6791,5493],{"class":2013},[1982,6793,2078],{"class":2003},[1982,6795,2093],{"class":2003},[1982,6797,6798,6801,6803,6806,6808,6811,6813,6816,6818,6820,6822,6825],{"class":1984,"line":19},[1982,6799,6800],{"class":1993},"    ticker",[1982,6802,1997],{"class":1993},[1982,6804,6805],{"class":1993}," time",[1982,6807,2004],{"class":2003},[1982,6809,6810],{"class":2007},"NewTicker",[1982,6812,2042],{"class":2003},[1982,6814,6815],{"class":2113},"30",[1982,6817,5408],{"class":1993},[1982,6819,6805],{"class":1993},[1982,6821,2004],{"class":2003},[1982,6823,6824],{"class":1993},"Second",[1982,6826,2142],{"class":2003},[1982,6828,6829,6831,6834,6836,6839],{"class":1984,"line":30},[1982,6830,5524],{"class":2099},[1982,6832,6833],{"class":1993}," ticker",[1982,6835,2004],{"class":2003},[1982,6837,6838],{"class":2007},"Stop",[1982,6840,5519],{"class":2003},[1982,6842,6843],{"class":1984,"line":2031},[1982,6844,2361],{"emptyLinePlaceholder":2360},[1982,6846,6847,6849],{"class":1984,"line":2096},[1982,6848,5562],{"class":2099},[1982,6850,2093],{"class":2003},[1982,6852,6853,6855],{"class":1984,"line":2119},[1982,6854,5569],{"class":2099},[1982,6856,2093],{"class":2003},[1982,6858,6859,6861,6863,6865,6867,6869],{"class":1984,"line":2145},[1982,6860,5576],{"class":2099},[1982,6862,5579],{"class":2099},[1982,6864,2059],{"class":1993},[1982,6866,2004],{"class":2003},[1982,6868,5586],{"class":2007},[1982,6870,5589],{"class":2003},[1982,6872,6873],{"class":1984,"line":2151},[1982,6874,5594],{"class":2099},[1982,6876,6877,6879,6881,6884,6886,6889],{"class":1984,"line":2164},[1982,6878,5576],{"class":2099},[1982,6880,5579],{"class":2099},[1982,6882,6883],{"class":1993},"ticker",[1982,6885,2004],{"class":2003},[1982,6887,6888],{"class":1993},"C",[1982,6890,5615],{"class":2003},[1982,6892,6893,6896,6898,6900,6902,6904,6906,6908,6910,6913],{"class":1984,"line":2170},[1982,6894,6895],{"class":1993},"            resp",[1982,6897,2049],{"class":2003},[1982,6899,2464],{"class":1993},[1982,6901,1997],{"class":1993},[1982,6903,6354],{"class":1993},[1982,6905,2004],{"class":2003},[1982,6907,1316],{"class":2007},[1982,6909,2042],{"class":2003},[1982,6911,6912],{"class":1993},"url",[1982,6914,2142],{"class":2003},[1982,6916,6917,6919,6921,6923,6925],{"class":1984,"line":2218},[1982,6918,2768],{"class":2099},[1982,6920,2464],{"class":1993},[1982,6922,2974],{"class":2099},[1982,6924,2977],{"class":2052},[1982,6926,2093],{"class":2003},[1982,6928,6929],{"class":1984,"line":2237},[1982,6930,6931],{"class":2099},"                continue\n",[1982,6933,6934],{"class":1984,"line":2248},[1982,6935,2806],{"class":2003},[1982,6937,6938],{"class":1984,"line":2253},[1982,6939,2361],{"emptyLinePlaceholder":2360},[1982,6941,6942,6945,6948,6950,6952,6954,6956,6958,6960],{"class":1984,"line":2258},[1982,6943,6944],{"class":2052},"            var",[1982,6946,6947],{"class":1993}," schemas",[1982,6949,5326],{"class":2052},[1982,6951,2010],{"class":2003},[1982,6953,5331],{"class":2013},[1982,6955,5334],{"class":2003},[1982,6957,1888],{"class":2013},[1982,6959,2004],{"class":2003},[1982,6961,5824],{"class":2013},[1982,6963,6964,6967,6969,6971,6973,6976,6978,6980,6982,6984,6986,6988,6991],{"class":1984,"line":2282},[1982,6965,6966],{"class":1993},"            json",[1982,6968,2004],{"class":2003},[1982,6970,6550],{"class":2007},[1982,6972,2042],{"class":2003},[1982,6974,6975],{"class":1993},"resp",[1982,6977,2004],{"class":2003},[1982,6979,6560],{"class":1993},[1982,6981,6507],{"class":2003},[1982,6983,6565],{"class":2007},[1982,6985,2042],{"class":2003},[1982,6987,5386],{"class":2099},[1982,6989,6990],{"class":1993},"schemas",[1982,6992,2142],{"class":2003},[1982,6994,6995,6997,6999,7001,7003,7005],{"class":1984,"line":2298},[1982,6996,6895],{"class":1993},[1982,6998,2004],{"class":2003},[1982,7000,6560],{"class":1993},[1982,7002,2004],{"class":2003},[1982,7004,5532],{"class":2007},[1982,7006,5519],{"class":2003},[1982,7008,7009],{"class":1984,"line":2351},[1982,7010,2361],{"emptyLinePlaceholder":2360},[1982,7012,7013,7016,7018,7020,7022,7024,7026,7028],{"class":1984,"line":2357},[1982,7014,7015],{"class":2099},"            for",[1982,7017,6222],{"class":1993},[1982,7019,2049],{"class":2003},[1982,7021,3432],{"class":1993},[1982,7023,1997],{"class":1993},[1982,7025,6017],{"class":2099},[1982,7027,6947],{"class":1993},[1982,7029,2093],{"class":2003},[1982,7031,7032,7035,7037,7039,7041,7043,7045,7047,7049,7051],{"class":1984,"line":2364},[1982,7033,7034],{"class":1993},"                existing",[1982,7036,2049],{"class":2003},[1982,7038,6436],{"class":1993},[1982,7040,1997],{"class":1993},[1982,7042,2383],{"class":1993},[1982,7044,2004],{"class":2003},[1982,7046,1296],{"class":2007},[1982,7048,2042],{"class":2003},[1982,7050,6259],{"class":1993},[1982,7052,2142],{"class":2003},[1982,7054,7055,7058,7060,7063,7066,7068,7070,7072,7074,7076,7078],{"class":1984,"line":2370},[1982,7056,7057],{"class":2099},"                if",[1982,7059,6436],{"class":1993},[1982,7061,7062],{"class":2099}," &&",[1982,7064,7065],{"class":1993}," existing",[1982,7067,2004],{"class":2003},[1982,7069,3728],{"class":1993},[1982,7071,2342],{"class":2099},[1982,7073,3432],{"class":1993},[1982,7075,2004],{"class":2003},[1982,7077,3728],{"class":1993},[1982,7079,2093],{"class":2003},[1982,7081,7082,7085],{"class":1984,"line":2395},[1982,7083,7084],{"class":2099},"                    continue",[1982,7086,7087],{"class":1987}," // No change\n",[1982,7089,7090],{"class":1984,"line":2401},[1982,7091,7092],{"class":2003},"                }\n",[1982,7094,7095,7098,7100,7102,7104,7106,7108,7110],{"class":1984,"line":2407},[1982,7096,7097],{"class":1993},"                factory",[1982,7099,2004],{"class":2003},[1982,7101,1291],{"class":2007},[1982,7103,2042],{"class":2003},[1982,7105,6259],{"class":1993},[1982,7107,2049],{"class":2003},[1982,7109,3432],{"class":1993},[1982,7111,2142],{"class":2003},[1982,7113,7114],{"class":1984,"line":2413},[1982,7115,2806],{"class":2003},[1982,7117,7118],{"class":1984,"line":2419},[1982,7119,2148],{"class":2003},[1982,7121,7122],{"class":1984,"line":2425},[1982,7123,2999],{"class":2003},[1982,7125,7126],{"class":1984,"line":2431},[1982,7127,2598],{"class":2003},[1968,7129,657],{"id":7130},"version-tracking",[3557,7132,661],{"id":7133},"compare-versions",[1973,7135,7137],{"className":1975,"code":7136,"language":1977,"meta":24,"style":24},"existing, ok := factory.GetSchema(\"pipeline\")\nif ok && existing.Version == newSchema.Version {\n    return // Already up to date\n}\n\nerr := factory.SetSchema(\"pipeline\", newSchema)\n",[1979,7138,7139,7163,7187,7194,7198,7202],{"__ignoreMap":24},[1982,7140,7141,7144,7146,7148,7150,7152,7154,7156,7158,7161],{"class":1984,"line":9},[1982,7142,7143],{"class":1993},"existing",[1982,7145,2049],{"class":2003},[1982,7147,6436],{"class":1993},[1982,7149,1997],{"class":1993},[1982,7151,2383],{"class":1993},[1982,7153,2004],{"class":2003},[1982,7155,1296],{"class":2007},[1982,7157,2042],{"class":2003},[1982,7159,7160],{"class":2045},"\"pipeline\"",[1982,7162,2142],{"class":2003},[1982,7164,7165,7167,7169,7171,7173,7175,7177,7179,7181,7183,7185],{"class":1984,"line":19},[1982,7166,5071],{"class":2099},[1982,7168,6436],{"class":1993},[1982,7170,7062],{"class":2099},[1982,7172,7065],{"class":1993},[1982,7174,2004],{"class":2003},[1982,7176,3728],{"class":1993},[1982,7178,2342],{"class":2099},[1982,7180,3543],{"class":1993},[1982,7182,2004],{"class":2003},[1982,7184,3728],{"class":1993},[1982,7186,2093],{"class":2003},[1982,7188,7189,7191],{"class":1984,"line":30},[1982,7190,5084],{"class":2099},[1982,7192,7193],{"class":1987}," // Already up to date\n",[1982,7195,7196],{"class":1984,"line":2031},[1982,7197,2598],{"class":2003},[1982,7199,7200],{"class":1984,"line":2096},[1982,7201,2361],{"emptyLinePlaceholder":2360},[1982,7203,7204,7206,7208,7210,7212,7214,7216,7218,7220,7222],{"class":1984,"line":2119},[1982,7205,2991],{"class":1993},[1982,7207,1997],{"class":1993},[1982,7209,2383],{"class":1993},[1982,7211,2004],{"class":2003},[1982,7213,1291],{"class":2007},[1982,7215,2042],{"class":2003},[1982,7217,7160],{"class":2045},[1982,7219,2049],{"class":2003},[1982,7221,3543],{"class":1993},[1982,7223,2142],{"class":2003},[3557,7225,666],{"id":7226},"observability",[1891,7228,7229],{},"Flume emits events on schema changes:",[1973,7231,7233],{"className":1975,"code":7232,"language":1977,"meta":24,"style":24},"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})\n",[1979,7234,7235,7242,7246,7295,7314,7333,7347,7356,7372,7381,7396,7405,7420,7424,7428,7470],{"__ignoreMap":24},[1982,7236,7237,7239],{"class":1984,"line":9},[1982,7238,2533],{"class":2052},[1982,7240,7241],{"class":2045}," \"github.com/zoobz-io/capitan\"\n",[1982,7243,7244],{"class":1984,"line":19},[1982,7245,2361],{"emptyLinePlaceholder":2360},[1982,7247,7248,7250,7252,7255,7257,7259,7261,7263,7265,7267,7269,7271,7273,7275,7277,7279,7282,7284,7286,7288,7291,7293],{"class":1984,"line":30},[1982,7249,3259],{"class":1993},[1982,7251,2004],{"class":2003},[1982,7253,7254],{"class":2007},"Handle",[1982,7256,2042],{"class":2003},[1982,7258,1888],{"class":1993},[1982,7260,2004],{"class":2003},[1982,7262,1752],{"class":1993},[1982,7264,2049],{"class":2003},[1982,7266,2053],{"class":2052},[1982,7268,2042],{"class":2003},[1982,7270,2059],{"class":2058},[1982,7272,2062],{"class":2013},[1982,7274,2004],{"class":2003},[1982,7276,2067],{"class":2013},[1982,7278,2049],{"class":2003},[1982,7280,7281],{"class":2058}," fields",[1982,7283,4918],{"class":2003},[1982,7285,3259],{"class":2013},[1982,7287,2004],{"class":2003},[1982,7289,7290],{"class":2013},"Field",[1982,7292,2078],{"class":2003},[1982,7294,2093],{"class":2003},[1982,7296,7297,7299,7301,7303,7306,7308,7311],{"class":1984,"line":2031},[1982,7298,5815],{"class":2052},[1982,7300,6222],{"class":1993},[1982,7302,2049],{"class":2003},[1982,7304,7305],{"class":1993}," oldVersion",[1982,7307,2049],{"class":2003},[1982,7309,7310],{"class":1993}," newVersion",[1982,7312,7313],{"class":2013}," string\n",[1982,7315,7316,7318,7320,7322,7325,7327,7329,7331],{"class":1984,"line":2096},[1982,7317,5562],{"class":2099},[1982,7319,2378],{"class":1993},[1982,7321,2049],{"class":2003},[1982,7323,7324],{"class":1993}," f",[1982,7326,1997],{"class":1993},[1982,7328,6017],{"class":2099},[1982,7330,7281],{"class":1993},[1982,7332,2093],{"class":2003},[1982,7334,7335,7338,7340,7342,7345],{"class":1984,"line":2119},[1982,7336,7337],{"class":2099},"        switch",[1982,7339,7324],{"class":1993},[1982,7341,2004],{"class":2003},[1982,7343,7344],{"class":1993},"Key",[1982,7346,2093],{"class":2003},[1982,7348,7349,7351,7354],{"class":1984,"line":2145},[1982,7350,5576],{"class":2099},[1982,7352,7353],{"class":2045}," \"name\"",[1982,7355,5615],{"class":2003},[1982,7357,7358,7361,7363,7365,7367,7370],{"class":1984,"line":2151},[1982,7359,7360],{"class":1993},"            name",[1982,7362,2873],{"class":1993},[1982,7364,7324],{"class":1993},[1982,7366,2004],{"class":2003},[1982,7368,7369],{"class":2007},"String",[1982,7371,5519],{"class":2003},[1982,7373,7374,7376,7379],{"class":1984,"line":2164},[1982,7375,5576],{"class":2099},[1982,7377,7378],{"class":2045}," \"old_version\"",[1982,7380,5615],{"class":2003},[1982,7382,7383,7386,7388,7390,7392,7394],{"class":1984,"line":2170},[1982,7384,7385],{"class":1993},"            oldVersion",[1982,7387,2873],{"class":1993},[1982,7389,7324],{"class":1993},[1982,7391,2004],{"class":2003},[1982,7393,7369],{"class":2007},[1982,7395,5519],{"class":2003},[1982,7397,7398,7400,7403],{"class":1984,"line":2218},[1982,7399,5576],{"class":2099},[1982,7401,7402],{"class":2045}," \"new_version\"",[1982,7404,5615],{"class":2003},[1982,7406,7407,7410,7412,7414,7416,7418],{"class":1984,"line":2237},[1982,7408,7409],{"class":1993},"            newVersion",[1982,7411,2873],{"class":1993},[1982,7413,7324],{"class":1993},[1982,7415,2004],{"class":2003},[1982,7417,7369],{"class":2007},[1982,7419,5519],{"class":2003},[1982,7421,7422],{"class":1984,"line":2248},[1982,7423,2148],{"class":2003},[1982,7425,7426],{"class":1984,"line":2253},[1982,7427,2999],{"class":2003},[1982,7429,7430,7433,7435,7437,7439,7442,7444,7447,7449,7452,7454,7456,7458,7460,7462,7464,7466,7468],{"class":1984,"line":2258},[1982,7431,7432],{"class":1993},"    log",[1982,7434,2004],{"class":2003},[1982,7436,3074],{"class":2007},[1982,7438,2042],{"class":2003},[1982,7440,7441],{"class":2045},"\"schema ",[1982,7443,6210],{"class":3082},[1982,7445,7446],{"class":2045}," updated: ",[1982,7448,6210],{"class":3082},[1982,7450,7451],{"class":2045}," -> ",[1982,7453,6210],{"class":3082},[1982,7455,3096],{"class":2045},[1982,7457,2049],{"class":2003},[1982,7459,6222],{"class":1993},[1982,7461,2049],{"class":2003},[1982,7463,7305],{"class":1993},[1982,7465,2049],{"class":2003},[1982,7467,7310],{"class":1993},[1982,7469,2142],{"class":2003},[1982,7471,7472],{"class":1984,"line":2282},[1982,7473,2354],{"class":2003},[1968,7475,671],{"id":7476},"graceful-updates",[3557,7478,675],{"id":7479},"validation-first",[1891,7481,7482],{},"Always validate before applying:",[1973,7484,7486],{"className":1975,"code":7485,"language":1977,"meta":24,"style":24},"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)\n",[1979,7487,7488,7516,7541,7545,7549,7554],{"__ignoreMap":24},[1982,7489,7490,7492,7494,7496,7498,7500,7502,7504,7506,7508,7510,7512,7514],{"class":1984,"line":9},[1982,7491,5071],{"class":2099},[1982,7493,2464],{"class":1993},[1982,7495,1997],{"class":1993},[1982,7497,2383],{"class":1993},[1982,7499,2004],{"class":2003},[1982,7501,1344],{"class":2007},[1982,7503,2042],{"class":2003},[1982,7505,5157],{"class":1993},[1982,7507,5878],{"class":2003},[1982,7509,2464],{"class":1993},[1982,7511,2974],{"class":2099},[1982,7513,2977],{"class":2052},[1982,7515,2093],{"class":2003},[1982,7517,7518,7520,7522,7524,7526,7528,7531,7533,7535,7537,7539],{"class":1984,"line":19},[1982,7519,5084],{"class":2099},[1982,7521,2129],{"class":1993},[1982,7523,2004],{"class":2003},[1982,7525,2134],{"class":2007},[1982,7527,2042],{"class":2003},[1982,7529,7530],{"class":2045},"\"invalid schema: ",[1982,7532,5098],{"class":3082},[1982,7534,3096],{"class":2045},[1982,7536,2049],{"class":2003},[1982,7538,2464],{"class":1993},[1982,7540,2142],{"class":2003},[1982,7542,7543],{"class":1984,"line":30},[1982,7544,2598],{"class":2003},[1982,7546,7547],{"class":1984,"line":2031},[1982,7548,2361],{"emptyLinePlaceholder":2360},[1982,7550,7551],{"class":1984,"line":2096},[1982,7552,7553],{"class":1987},"// Schema is valid, safe to apply\n",[1982,7555,7556,7558,7560,7562,7564,7566,7568,7570],{"class":1984,"line":2119},[1982,7557,1994],{"class":1993},[1982,7559,2004],{"class":2003},[1982,7561,1291],{"class":2007},[1982,7563,2042],{"class":2003},[1982,7565,6259],{"class":1993},[1982,7567,2049],{"class":2003},[1982,7569,3543],{"class":1993},[1982,7571,2142],{"class":2003},[3557,7573,680],{"id":7574},"rollback-pattern",[1973,7576,7578],{"className":1975,"code":7577,"language":1977,"meta":24,"style":24},"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}\n",[1979,7579,7580,7642,7647,7671,7675,7680,7712,7719,7723,7727,7732,7764,7768,7784,7789,7809,7834,7838,7842,7848],{"__ignoreMap":24},[1982,7581,7582,7584,7587,7589,7591,7593,7595,7597,7599,7601,7603,7605,7607,7609,7611,7613,7615,7617,7619,7621,7623,7625,7627,7629,7631,7633,7635,7638,7640],{"class":1984,"line":9},[1982,7583,2607],{"class":2052},[1982,7585,7586],{"class":2007}," updateWithRollback",[1982,7588,2042],{"class":2003},[1982,7590,1994],{"class":2058},[1982,7592,5408],{"class":2099},[1982,7594,1888],{"class":2013},[1982,7596,2004],{"class":2003},[1982,7598,1149],{"class":2013},[1982,7600,2010],{"class":2003},[1982,7602,2014],{"class":2013},[1982,7604,5487],{"class":2003},[1982,7606,6222],{"class":2058},[1982,7608,5493],{"class":2013},[1982,7610,2049],{"class":2003},[1982,7612,3543],{"class":2058},[1982,7614,2000],{"class":2013},[1982,7616,2004],{"class":2003},[1982,7618,1358],{"class":2013},[1982,7620,2049],{"class":2003},[1982,7622,3503],{"class":2058},[1982,7624,5408],{"class":2099},[1982,7626,1888],{"class":2013},[1982,7628,2004],{"class":2003},[1982,7630,1321],{"class":2013},[1982,7632,2010],{"class":2003},[1982,7634,2014],{"class":2013},[1982,7636,7637],{"class":2003},"])",[1982,7639,2088],{"class":2013},[1982,7641,2093],{"class":2003},[1982,7643,7644],{"class":1984,"line":19},[1982,7645,7646],{"class":1987},"    // Save current\n",[1982,7648,7649,7652,7654,7657,7659,7661,7663,7665,7667,7669],{"class":1984,"line":30},[1982,7650,7651],{"class":1993},"    oldSchema",[1982,7653,2049],{"class":2003},[1982,7655,7656],{"class":1993}," hadOld",[1982,7658,1997],{"class":1993},[1982,7660,2383],{"class":1993},[1982,7662,2004],{"class":2003},[1982,7664,1296],{"class":2007},[1982,7666,2042],{"class":2003},[1982,7668,6259],{"class":1993},[1982,7670,2142],{"class":2003},[1982,7672,7673],{"class":1984,"line":2031},[1982,7674,2361],{"emptyLinePlaceholder":2360},[1982,7676,7677],{"class":1984,"line":2096},[1982,7678,7679],{"class":1987},"    // Apply new (auto-sync bindings rebuild automatically)\n",[1982,7681,7682,7684,7686,7688,7690,7692,7694,7696,7698,7700,7702,7704,7706,7708,7710],{"class":1984,"line":2119},[1982,7683,2969],{"class":2099},[1982,7685,2464],{"class":1993},[1982,7687,1997],{"class":1993},[1982,7689,2383],{"class":1993},[1982,7691,2004],{"class":2003},[1982,7693,1291],{"class":2007},[1982,7695,2042],{"class":2003},[1982,7697,6259],{"class":1993},[1982,7699,2049],{"class":2003},[1982,7701,3543],{"class":1993},[1982,7703,5878],{"class":2003},[1982,7705,2464],{"class":1993},[1982,7707,2974],{"class":2099},[1982,7709,2977],{"class":2052},[1982,7711,2093],{"class":2003},[1982,7713,7714,7716],{"class":1984,"line":2145},[1982,7715,2154],{"class":2099},[1982,7717,7718],{"class":1993}," err\n",[1982,7720,7721],{"class":1984,"line":2151},[1982,7722,2999],{"class":2003},[1982,7724,7725],{"class":1984,"line":2164},[1982,7726,2361],{"emptyLinePlaceholder":2360},[1982,7728,7729],{"class":1984,"line":2170},[1982,7730,7731],{"class":1987},"    // Test with canary request\n",[1982,7733,7734,7737,7739,7741,7743,7745,7747,7749,7751,7753,7755,7757,7759,7762],{"class":1984,"line":2218},[1982,7735,7736],{"class":1993},"    _",[1982,7738,2049],{"class":2003},[1982,7740,2464],{"class":1993},[1982,7742,1997],{"class":1993},[1982,7744,3503],{"class":1993},[1982,7746,2004],{"class":2003},[1982,7748,1326],{"class":2007},[1982,7750,2042],{"class":2003},[1982,7752,3033],{"class":1993},[1982,7754,2004],{"class":2003},[1982,7756,3038],{"class":2007},[1982,7758,3041],{"class":2003},[1982,7760,7761],{"class":1993}," canaryOrder",[1982,7763,2142],{"class":2003},[1982,7765,7766],{"class":1984,"line":2237},[1982,7767,2361],{"emptyLinePlaceholder":2360},[1982,7769,7770,7772,7774,7776,7778,7780,7782],{"class":1984,"line":2248},[1982,7771,2969],{"class":2099},[1982,7773,2464],{"class":1993},[1982,7775,2974],{"class":2099},[1982,7777,2977],{"class":2052},[1982,7779,7062],{"class":2099},[1982,7781,7656],{"class":1993},[1982,7783,2093],{"class":2003},[1982,7785,7786],{"class":1984,"line":2253},[1982,7787,7788],{"class":1987},"        // Rollback to previous schema\n",[1982,7790,7791,7794,7796,7798,7800,7802,7804,7807],{"class":1984,"line":2258},[1982,7792,7793],{"class":1993},"        factory",[1982,7795,2004],{"class":2003},[1982,7797,1291],{"class":2007},[1982,7799,2042],{"class":2003},[1982,7801,6259],{"class":1993},[1982,7803,2049],{"class":2003},[1982,7805,7806],{"class":1993}," oldSchema",[1982,7808,2142],{"class":2003},[1982,7810,7811,7813,7815,7817,7819,7821,7824,7826,7828,7830,7832],{"class":1984,"line":2282},[1982,7812,2154],{"class":2099},[1982,7814,2129],{"class":1993},[1982,7816,2004],{"class":2003},[1982,7818,2134],{"class":2007},[1982,7820,2042],{"class":2003},[1982,7822,7823],{"class":2045},"\"canary failed, rolled back: ",[1982,7825,5098],{"class":3082},[1982,7827,3096],{"class":2045},[1982,7829,2049],{"class":2003},[1982,7831,2464],{"class":1993},[1982,7833,2142],{"class":2003},[1982,7835,7836],{"class":1984,"line":2298},[1982,7837,2999],{"class":2003},[1982,7839,7840],{"class":1984,"line":2351},[1982,7841,2361],{"emptyLinePlaceholder":2360},[1982,7843,7844,7846],{"class":1984,"line":2357},[1982,7845,5084],{"class":2099},[1982,7847,2161],{"class":2052},[1982,7849,7850],{"class":1984,"line":2364},[1982,7851,2598],{"class":2003},[1968,7853,685],{"id":7854},"best-practices",[3557,7856,689],{"id":7857},"_1-use-semantic-versioning",[1973,7859,7863],{"className":7860,"code":7861,"language":7862,"meta":24,"style":24},"language-yaml shiki shiki-themes","version: \"1.2.3\"  # MAJOR.MINOR.PATCH\n","yaml",[1979,7864,7865],{"__ignoreMap":24},[1982,7866,7867,7870,7872,7875],{"class":1984,"line":9},[1982,7868,7869],{"class":2052},"version",[1982,7871,6213],{"class":2536},[1982,7873,7874],{"class":2045},"\"1.2.3\"",[1982,7876,7877],{"class":1987},"  # MAJOR.MINOR.PATCH\n",[3557,7879,694],{"id":7880},"_2-log-all-changes",[1973,7882,7884],{"className":1975,"code":7883,"language":1977,"meta":24,"style":24},"log.Printf(\"schema %s updated to version %s\", name, schema.Version)\n",[1979,7885,7886],{"__ignoreMap":24},[1982,7887,7888,7891,7893,7895,7897,7899,7901,7904,7906,7908,7910,7912,7914,7916,7918,7920],{"class":1984,"line":9},[1982,7889,7890],{"class":1993},"log",[1982,7892,2004],{"class":2003},[1982,7894,3074],{"class":2007},[1982,7896,2042],{"class":2003},[1982,7898,7441],{"class":2045},[1982,7900,6210],{"class":3082},[1982,7902,7903],{"class":2045}," updated to version ",[1982,7905,6210],{"class":3082},[1982,7907,3096],{"class":2045},[1982,7909,2049],{"class":2003},[1982,7911,6222],{"class":1993},[1982,7913,2049],{"class":2003},[1982,7915,3432],{"class":1993},[1982,7917,2004],{"class":2003},[1982,7919,3728],{"class":1993},[1982,7921,2142],{"class":2003},[3557,7923,699],{"id":7924},"_3-validate-component-dependencies",[1891,7926,7927],{},"Before removing a processor, check if schemas reference it:",[1973,7929,7931],{"className":1975,"code":7930,"language":1977,"meta":24,"style":24},"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}\n",[1979,7932,7933,7959,7983,8003,8029,8033],{"__ignoreMap":24},[1982,7934,7935,7938,7940,7942,7945,7947,7949,7951,7953,7955,7957],{"class":1984,"line":9},[1982,7936,7937],{"class":2099},"for",[1982,7939,2378],{"class":1993},[1982,7941,2049],{"class":2003},[1982,7943,7944],{"class":1993}," schemaName",[1982,7946,1997],{"class":1993},[1982,7948,6017],{"class":2099},[1982,7950,2383],{"class":1993},[1982,7952,2004],{"class":2003},[1982,7954,1306],{"class":2007},[1982,7956,2622],{"class":2003},[1982,7958,2093],{"class":2003},[1982,7960,7961,7964,7966,7968,7970,7972,7974,7976,7978,7981],{"class":1984,"line":19},[1982,7962,7963],{"class":1993},"    schema",[1982,7965,2049],{"class":2003},[1982,7967,2378],{"class":1993},[1982,7969,1997],{"class":1993},[1982,7971,2383],{"class":1993},[1982,7973,2004],{"class":2003},[1982,7975,1296],{"class":2007},[1982,7977,2042],{"class":2003},[1982,7979,7980],{"class":1993},"schemaName",[1982,7982,2142],{"class":2003},[1982,7984,7985,7987,7990,7992,7994,7996,7999,8001],{"class":1984,"line":30},[1982,7986,2969],{"class":2099},[1982,7988,7989],{"class":2007}," schemaReferencesProcessor",[1982,7991,2042],{"class":2003},[1982,7993,4858],{"class":1993},[1982,7995,2049],{"class":2003},[1982,7997,7998],{"class":2045}," \"old-processor\"",[1982,8000,2078],{"class":2003},[1982,8002,2093],{"class":2003},[1982,8004,8005,8007,8009,8011,8013,8015,8018,8020,8023,8025,8027],{"class":1984,"line":2031},[1982,8006,2154],{"class":2099},[1982,8008,2129],{"class":1993},[1982,8010,2004],{"class":2003},[1982,8012,2134],{"class":2007},[1982,8014,2042],{"class":2003},[1982,8016,8017],{"class":2045},"\"cannot remove: schema ",[1982,8019,6210],{"class":3082},[1982,8021,8022],{"class":2045}," uses it\"",[1982,8024,2049],{"class":2003},[1982,8026,7944],{"class":1993},[1982,8028,2142],{"class":2003},[1982,8030,8031],{"class":1984,"line":2096},[1982,8032,2999],{"class":2003},[1982,8034,8035],{"class":1984,"line":2119},[1982,8036,2598],{"class":2003},[3557,8038,704],{"id":8039},"_4-consider-circuit-breakers",[1891,8041,8042],{},"Protect against bad schema updates:",[1973,8044,8046],{"className":1975,"code":8045,"language":1977,"meta":24,"style":24},"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}\n",[1979,8047,8048,8078,8098,8113,8117,8121,8166,8193,8217,8222],{"__ignoreMap":24},[1982,8049,8050,8052,8055,8057,8059,8062,8064,8067,8069,8071,8074,8076],{"class":1984,"line":9},[1982,8051,2570],{"class":2052},[1982,8053,8054],{"class":2013}," GuardedFactory",[1982,8056,2010],{"class":2003},[1982,8058,5359],{"class":2058},[1982,8060,8061],{"class":2013}," pipz",[1982,8063,2004],{"class":2003},[1982,8065,8066],{"class":2013},"Cloner",[1982,8068,2010],{"class":2003},[1982,8070,5359],{"class":2013},[1982,8072,8073],{"class":2003},"]]",[1982,8075,2575],{"class":2052},[1982,8077,2093],{"class":2003},[1982,8079,8080,8082,8085,8087,8089,8091,8093,8095],{"class":1984,"line":19},[1982,8081,2683],{"class":2285},[1982,8083,8084],{"class":2099},"       *",[1982,8086,1888],{"class":2013},[1982,8088,2004],{"class":2003},[1982,8090,1149],{"class":2013},[1982,8092,2010],{"class":2003},[1982,8094,5359],{"class":2013},[1982,8096,8097],{"class":2003},"]\n",[1982,8099,8100,8103,8105,8108,8110],{"class":1984,"line":30},[1982,8101,8102],{"class":2285},"    updateBreaker",[1982,8104,5408],{"class":2099},[1982,8106,8107],{"class":2013},"circuitbreaker",[1982,8109,2004],{"class":2003},[1982,8111,8112],{"class":2013},"CircuitBreaker\n",[1982,8114,8115],{"class":1984,"line":2031},[1982,8116,2598],{"class":2003},[1982,8118,8119],{"class":1984,"line":2096},[1982,8120,2361],{"emptyLinePlaceholder":2360},[1982,8122,8123,8125,8127,8130,8132,8135,8137,8139,8141,8144,8146,8148,8150,8152,8154,8156,8158,8160,8162,8164],{"class":1984,"line":2119},[1982,8124,2607],{"class":2052},[1982,8126,2081],{"class":2003},[1982,8128,8129],{"class":2058},"g ",[1982,8131,5337],{"class":2099},[1982,8133,8134],{"class":2013},"GuardedFactory",[1982,8136,2010],{"class":2003},[1982,8138,5359],{"class":2013},[1982,8140,7637],{"class":2003},[1982,8142,8143],{"class":2007}," SetSchema",[1982,8145,2042],{"class":2003},[1982,8147,6259],{"class":2058},[1982,8149,5493],{"class":2013},[1982,8151,2049],{"class":2003},[1982,8153,3432],{"class":2058},[1982,8155,2000],{"class":2013},[1982,8157,2004],{"class":2003},[1982,8159,1358],{"class":2013},[1982,8161,2078],{"class":2003},[1982,8163,2088],{"class":2013},[1982,8165,2093],{"class":2003},[1982,8167,8168,8170,8173,8175,8178,8180,8183,8185,8187,8189,8191],{"class":1984,"line":2145},[1982,8169,5084],{"class":2099},[1982,8171,8172],{"class":1993}," g",[1982,8174,2004],{"class":2003},[1982,8176,8177],{"class":1993},"updateBreaker",[1982,8179,2004],{"class":2003},[1982,8181,8182],{"class":2007},"Execute",[1982,8184,2042],{"class":2003},[1982,8186,2607],{"class":2052},[1982,8188,2622],{"class":2003},[1982,8190,2088],{"class":2013},[1982,8192,2093],{"class":2003},[1982,8194,8195,8197,8199,8201,8203,8205,8207,8209,8211,8213,8215],{"class":1984,"line":2151},[1982,8196,2154],{"class":2099},[1982,8198,8172],{"class":1993},[1982,8200,2004],{"class":2003},[1982,8202,1994],{"class":1993},[1982,8204,2004],{"class":2003},[1982,8206,1291],{"class":2007},[1982,8208,2042],{"class":2003},[1982,8210,6259],{"class":1993},[1982,8212,2049],{"class":2003},[1982,8214,3432],{"class":1993},[1982,8216,2142],{"class":2003},[1982,8218,8219],{"class":1984,"line":2164},[1982,8220,8221],{"class":2003},"    })\n",[1982,8223,8224],{"class":1984,"line":2170},[1982,8225,2598],{"class":2003},[1968,8227,150],{"id":8228},"next-steps",[3221,8230,8231,8236,8241],{},[3224,8232,8233,8235],{},[1894,8234,879],{"href":4240}," - Test hot reload scenarios",[3224,8237,8238,8240],{},[1894,8239,666],{"href":7226}," - Monitor schema changes",[3224,8242,8243,8247],{},[1894,8244,8246],{"href":8245},"../reference/events","Events Reference"," - All schema events",[3677,8249,8250],{},"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}",{"title":24,"searchDepth":19,"depth":19,"links":8252},[8253,8254,8259,8263,8267,8271,8275,8279,8285],{"id":4742,"depth":19,"text":6},{"id":4774,"depth":19,"text":596,"children":8255},[8256,8257,8258],{"id":4777,"depth":30,"text":600},{"id":4998,"depth":30,"text":605},{"id":5147,"depth":30,"text":610},{"id":5305,"depth":19,"text":615,"children":8260},[8261,8262],{"id":5308,"depth":30,"text":619},{"id":5423,"depth":30,"text":624},{"id":5443,"depth":19,"text":629,"children":8264},[8265,8266],{"id":5446,"depth":30,"text":633},{"id":5920,"depth":30,"text":638},{"id":6319,"depth":19,"text":643,"children":8268},[8269,8270],{"id":6322,"depth":30,"text":647},{"id":6746,"depth":30,"text":652},{"id":7130,"depth":19,"text":657,"children":8272},[8273,8274],{"id":7133,"depth":30,"text":661},{"id":7226,"depth":30,"text":666},{"id":7476,"depth":19,"text":671,"children":8276},[8277,8278],{"id":7479,"depth":30,"text":675},{"id":7574,"depth":30,"text":680},{"id":7854,"depth":19,"text":685,"children":8280},[8281,8282,8283,8284],{"id":7857,"depth":30,"text":689},{"id":7880,"depth":30,"text":694},{"id":7924,"depth":30,"text":699},{"id":8039,"depth":30,"text":704},{"id":8228,"depth":19,"text":150},{},"2025-12-03T00:00:00.000Z",null,{"title":219,"description":585},[8291,8292,8293],"Guide","Hot Reload","Dynamic","2025-12-12T00:00:00.000Z","H-0AXBuNVIEF2jbj4bKxThFfvqAClvfYChXIyo3yaGo",[8297,8298],{"title":443,"path":442,"stem":1824,"description":445,"children":-1},{"title":363,"path":712,"stem":1828,"description":714,"children":-1},1776189694725]