{"_id":"@ada-anvil/barrow","_rev":"6-c130d72868513c1f8329bc3c1c7e7cb9","name":"@ada-anvil/barrow","dist-tags":{"latest":"0.1.2"},"versions":{"0.0.1":{"name":"@ada-anvil/barrow","version":"0.0.1","keywords":["javascript","typescript","typesafe","ogmios","blockchain","cardano","chain","indexing","indexer","websocket","web3"],"author":{"name":"Ada anvil"},"license":"Apache-2.0","_id":"@ada-anvil/barrow@0.0.1","maintainers":[{"name":"pabz-anvil","email":"pabz@ada-anvil.io"},{"name":"tqueri","email":"tqueri@ada-anvil.io"},{"name":"dodilanne","email":"vincaudet@gmail.com"},{"name":"mrabdibdi-anvil","email":"mrabdibdi@ada-anvil.io"}],"homepage":"https://github.com/Cardano-Forge/barrow","bugs":{"url":"https://github.com/Cardano-Forge/barrow/issues"},"dist":{"shasum":"5dbf13b555fc7ccfd546a23dc26828f5c5593b8e","tarball":"https://registry.npmjs.org/@ada-anvil/barrow/-/barrow-0.0.1.tgz","fileCount":54,"integrity":"sha512-rY1J8ZC6bLi0OHka0RURFPcF9FUK1kVt4nX8eIk05eGIDFRC6/D9ZV9Co0mvyBngm3OjdRr9b3TJPaw7TB5nag==","signatures":[{"sig":"MEYCIQD4L3F+F64s6wbafOG2h+sqXeHF6qpyQHUSBfzSOLGiuwIhAKS+5FXGjY1ql7a/WpPJQLrtMDflNqkqhKtaxMY57WR/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":202986},"main":"./index.js","types":"./index.d.mts","module":"./index.mjs","exports":{".":{"import":{"types":"./index.d.mts","import":"./index.mjs"},"require":{"types":"./index.d.ts","require":"./index.js"}},"./otel":{"import":{"types":"./dep/otel.d.mts","import":"./dep/otel.mjs"},"require":{"types":"./dep/otel.d.ts","require":"./dep/otel.js"}},"./pino":{"import":{"types":"./dep/pino.d.mts","import":"./dep/pino.mjs"},"require":{"types":"./dep/pino.d.ts","require":"./dep/pino.js"}},"./ogmios":{"import":{"types":"./dep/ogmios.d.mts","import":"./dep/ogmios.mjs"},"require":{"types":"./dep/ogmios.d.ts","require":"./dep/ogmios.js"}},"./package.json":"./package.json"},"gitHead":"da5117d217c05ed8e933a8e213abff34b038c6fb","scripts":{"pre":"npm run lint && npm run check && npm run build && npm run test","lint":"biome check --write .","test":"vitest --run --passWithNoTests","build":"tsup","check":"tsc --noEmit","example":"node --import=tsx --env-file=.env src/examples/index.ts","test:watch":"vitest"},"_npmUser":{"name":"pabz-anvil","email":"pabz@ada-anvil.io"},"repository":{"url":"git+https://github.com/Cardano-Forge/barrow.git","type":"git"},"_npmVersion":"10.9.2","description":"Chain indexing tools for the Cardano blockchain.","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","dependencies":{"trynot":"^0.0.2"},"publishConfig":{"registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","pino":"^9.9.2","tsup":"^8.5.0","vitest":"^3.2.4","@types/ws":"^8.18.1","typescript":"^5.9.2","@types/node":"^24.3.0","pino-pretty":"^11.3.0","@biomejs/biome":"^2.2.2","@opentelemetry/api":"^1.9.0","@cardano-ogmios/client":"^6.13.0","@opentelemetry/sdk-node":"^0.205.0","@opentelemetry/sdk-metrics":"^2.1.0","pino-opentelemetry-transport":"^1.0.1","@opentelemetry/exporter-metrics-otlp-http":"^0.205.0"},"peerDependencies":{"pino":">=8.0.0","@opentelemetry/api":">=1.0.0","@cardano-ogmios/client":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/barrow_0.0.1_1772814143003_0.29592954307759367","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@ada-anvil/barrow","version":"0.0.2","keywords":["javascript","typescript","typesafe","ogmios","blockchain","cardano","chain","indexing","indexer","websocket","web3"],"author":{"name":"Ada anvil"},"license":"Apache-2.0","_id":"@ada-anvil/barrow@0.0.2","maintainers":[{"name":"pabz-anvil","email":"pabz@ada-anvil.io"},{"name":"tqueri","email":"tqueri@ada-anvil.io"},{"name":"dodilanne","email":"vincaudet@gmail.com"},{"name":"mrabdibdi-anvil","email":"mrabdibdi@ada-anvil.io"}],"homepage":"https://github.com/Cardano-Forge/anvil-barrow","bugs":{"url":"https://github.com/Cardano-Forge/anvil-barrow/issues"},"dist":{"shasum":"32a63a021a02d3f9f8fbbf9d2793107ddb189495","tarball":"https://registry.npmjs.org/@ada-anvil/barrow/-/barrow-0.0.2.tgz","fileCount":27,"integrity":"sha512-MWEV9zZnskfQaYjvp2ktDETYCg53Q2+PWnWUqUYYm8L/+jOTZaTPhagh8dkz2cOwYFVPWiFB+CInbjxiLTt8EA==","signatures":[{"sig":"MEUCIQDcLXSpWRujDr9OWiijMYuIC0JIQmajjLoyfVdcdX+KxwIgUDeY97goBL9Btxh9nqFS8i/lBKdd4QeGH2BUw3rA3Xo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ada-anvil%2fbarrow@0.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":95514},"main":"./index.js","types":"./index.d.mts","module":"./index.mjs","exports":{".":{"import":{"types":"./index.d.mts","import":"./index.mjs"},"require":{"types":"./index.d.ts","require":"./index.js"}},"./otel":{"import":{"types":"./dep/otel.d.mts","import":"./dep/otel.mjs"},"require":{"types":"./dep/otel.d.ts","require":"./dep/otel.js"}},"./pino":{"import":{"types":"./dep/pino.d.mts","import":"./dep/pino.mjs"},"require":{"types":"./dep/pino.d.ts","require":"./dep/pino.js"}},"./ogmios":{"import":{"types":"./dep/ogmios.d.mts","import":"./dep/ogmios.mjs"},"require":{"types":"./dep/ogmios.d.ts","require":"./dep/ogmios.js"}},"./package.json":"./package.json"},"gitHead":"d6a690cdcc9f1cac5a33291cb10897207370d0ec","scripts":{"pre":"npm run lint && npm run check && npm run build && npm run test","lint":"biome check --write .","test":"vitest --run --passWithNoTests","build":"tsup","check":"tsc --noEmit","example":"node --import=tsx --env-file=.env src/examples/index.ts","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:58a364d3-5987-4210-b169-7146fc89e214"}},"repository":{"url":"git+https://github.com/Cardano-Forge/anvil-barrow.git","type":"git"},"_npmVersion":"11.9.0","description":"Chain indexing tools for the Cardano blockchain.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","dependencies":{"trynot":"^0.0.2"},"publishConfig":{"registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","pino":"^9.9.2","tsup":"^8.5.0","vitest":"^3.2.4","@types/ws":"^8.18.1","typescript":"^5.9.2","@types/node":"^24.3.0","pino-pretty":"^11.3.0","@biomejs/biome":"^2.2.2","@opentelemetry/api":"^1.9.0","@cardano-ogmios/client":"^6.13.0","@opentelemetry/sdk-node":"^0.205.0","@opentelemetry/sdk-metrics":"^2.1.0","pino-opentelemetry-transport":"^1.0.1","@opentelemetry/exporter-metrics-otlp-http":"^0.205.0"},"peerDependencies":{"pino":">=8.0.0","@opentelemetry/api":">=1.0.0","@cardano-ogmios/client":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/barrow_0.0.2_1772820202282_0.788450517887819","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@ada-anvil/barrow","version":"0.1.0","keywords":["javascript","typescript","typesafe","ogmios","blockchain","cardano","chain","indexing","indexer","websocket","web3"],"author":{"name":"Anvil Development Agency"},"license":"Apache-2.0","_id":"@ada-anvil/barrow@0.1.0","maintainers":[{"name":"tqueri","email":"tqueri@ada-anvil.io"},{"name":"dodilanne","email":"vincaudet@gmail.com"},{"name":"mrabdibdi-anvil","email":"mrabdibdi@ada-anvil.io"}],"homepage":"https://github.com/Cardano-Forge/anvil-barrow","bugs":{"url":"https://github.com/Cardano-Forge/anvil-barrow/issues"},"dist":{"shasum":"50a0f8756c486e401653a924946c781b2b0abe0a","tarball":"https://registry.npmjs.org/@ada-anvil/barrow/-/barrow-0.1.0.tgz","fileCount":25,"integrity":"sha512-kxKDaJQv0EqjCPM8qJD5rFt+OusQI7iHhLqsNh1gtfegkNRX30lBgTj2ru8Pqjkt54/RSDzWdZGJxcs+4TlyoQ==","signatures":[{"sig":"MEUCIQD/oseAOQDcMm+3pNnlDSFAdMB9MR/xDrBW3ZgtAClC6AIged7AhvYMDxDZRI1YFWwmWHnO9GJ61JHFll6DKcOrMeg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ada-anvil%2fbarrow@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":111756},"main":"./index.js","types":"./index.d.mts","module":"./index.mjs","exports":{".":{"import":{"types":"./index.d.mts","import":"./index.mjs"},"require":{"types":"./index.d.ts","require":"./index.js"}},"./otel":{"import":{"types":"./otel.d.mts","import":"./otel.mjs"},"require":{"types":"./otel.d.ts","require":"./otel.js"}},"./pino":{"import":{"types":"./pino.d.mts","import":"./pino.mjs"},"require":{"types":"./pino.d.ts","require":"./pino.js"}},"./ogmios":{"import":{"types":"./ogmios.d.mts","import":"./ogmios.mjs"},"require":{"types":"./ogmios.d.ts","require":"./ogmios.js"}},"./package.json":"./package.json"},"gitHead":"f305350b1b3108f3ce7eb02a1b46df7d36ed9972","scripts":{"pre":"npm run lint && npm run check && npm run build && npm run test","lint":"biome check --write .","test":"vitest --run --passWithNoTests","build":"tsup","check":"tsc --noEmit","example":"node --import=tsx --env-file=.env src/examples/index.ts","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:58a364d3-5987-4210-b169-7146fc89e214"}},"repository":{"url":"git+https://github.com/Cardano-Forge/anvil-barrow.git","type":"git"},"_npmVersion":"11.12.1","description":"A framework for building event processing tools","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","dependencies":{"trynot":"^0.0.2"},"publishConfig":{"registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","pino":"^9.9.2","tsup":"^8.5.0","vitest":"^3.2.4","@types/ws":"^8.18.1","typescript":"^5.9.2","@types/node":"^24.3.0","pino-pretty":"^11.3.0","@biomejs/biome":"^2.2.2","@opentelemetry/api":"^1.9.0","@cardano-ogmios/client":"^6.13.0","@opentelemetry/sdk-node":"^0.205.0","@opentelemetry/sdk-metrics":"^2.1.0","pino-opentelemetry-transport":"^1.0.1","@opentelemetry/exporter-metrics-otlp-http":"^0.205.0"},"peerDependencies":{"pino":">=8.0.0","@opentelemetry/api":">=1.0.0","@cardano-ogmios/client":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/barrow_0.1.0_1779203934028_0.6329255685597726","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@ada-anvil/barrow","version":"0.1.1","keywords":["javascript","typescript","typesafe","ogmios","blockchain","cardano","chain","indexing","indexer","websocket","web3"],"author":{"name":"Anvil Development Agency"},"license":"Apache-2.0","_id":"@ada-anvil/barrow@0.1.1","maintainers":[{"name":"tqueri","email":"tqueri@ada-anvil.io"},{"name":"dodilanne","email":"vincaudet@gmail.com"},{"name":"mrabdibdi-anvil","email":"mrabdibdi@ada-anvil.io"}],"homepage":"https://github.com/Cardano-Forge/anvil-barrow","bugs":{"url":"https://github.com/Cardano-Forge/anvil-barrow/issues"},"dist":{"shasum":"d4d8f761d03cc98ea8c53ac7dae9ca412f7c0f23","tarball":"https://registry.npmjs.org/@ada-anvil/barrow/-/barrow-0.1.1.tgz","fileCount":28,"integrity":"sha512-RtwWNYInVq5/C3WFbBupeTXW4o8bLXqnRKPds/xZdrr8d0yXvjmprbvKdGWSPq/og7kqT98Q/jDQi6d9CLJuIw==","signatures":[{"sig":"MEYCIQC0ztApMe9ulgrpvW8nx+jEgW8kqvcLEhAJzVWaKAt5DwIhAKcj9Y9EZtd0/I+wHV5hmA9iAzZwbA6gVbE8RLvYOf1a","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ada-anvil%2fbarrow@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":132845},"main":"./index.js","types":"./index.d.mts","module":"./index.mjs","exports":{".":{"import":{"types":"./index.d.mts","import":"./index.mjs"},"require":{"types":"./index.d.ts","require":"./index.js"}},"./otel":{"import":{"types":"./otel.d.mts","import":"./otel.mjs"},"require":{"types":"./otel.d.ts","require":"./otel.js"}},"./pino":{"import":{"types":"./pino.d.mts","import":"./pino.mjs"},"require":{"types":"./pino.d.ts","require":"./pino.js"}},"./ogmios":{"import":{"types":"./ogmios.d.mts","import":"./ogmios.mjs"},"require":{"types":"./ogmios.d.ts","require":"./ogmios.js"}},"./package.json":"./package.json"},"gitHead":"2fc25574077307d83411719a5b224e298821d5f2","scripts":{"pre":"npm run lint && npm run check && npm run build && npm run test","lint":"biome check --write .","test":"vitest --run --passWithNoTests","build":"tsup","check":"tsc --noEmit","example":"node --import=tsx --env-file=.env src/examples/index.ts","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:58a364d3-5987-4210-b169-7146fc89e214"}},"repository":{"url":"git+https://github.com/Cardano-Forge/anvil-barrow.git","type":"git"},"_npmVersion":"11.13.0","description":"A framework for building event processing tools","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"trynot":"^0.0.2"},"publishConfig":{"registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","pino":"^9.9.2","tsup":"^8.5.0","vitest":"^3.2.4","@types/ws":"^8.18.1","typescript":"^5.9.2","@types/node":"^24.3.0","pino-pretty":"^11.3.0","@biomejs/biome":"^2.2.2","@opentelemetry/api":"^1.9.0","@cardano-ogmios/client":"^6.13.0","@opentelemetry/sdk-node":"^0.205.0","@opentelemetry/sdk-metrics":"^2.1.0","pino-opentelemetry-transport":"^1.0.1","@opentelemetry/exporter-metrics-otlp-http":"^0.205.0"},"peerDependencies":{"pino":">=8.0.0","@opentelemetry/api":">=1.0.0","@cardano-ogmios/client":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/barrow_0.1.1_1780010368282_0.8555057441206269","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@ada-anvil/barrow","description":"A framework for building event processing tools","version":"0.1.2","author":{"name":"Anvil Development Agency"},"license":"Apache-2.0","publishConfig":{"registry":"https://registry.npmjs.org/"},"bugs":{"url":"https://github.com/Cardano-Forge/anvil-barrow/issues"},"homepage":"https://github.com/Cardano-Forge/anvil-barrow","repository":{"type":"git","url":"git+https://github.com/Cardano-Forge/anvil-barrow.git"},"keywords":["javascript","typescript","typesafe","ogmios","blockchain","cardano","chain","indexing","indexer","websocket","web3"],"sideEffects":false,"main":"./index.js","module":"./index.mjs","types":"./index.d.mts","scripts":{"build":"tsup","check":"tsc --noEmit","lint":"biome check --write .","test":"vitest --run --passWithNoTests","test:watch":"vitest","pre":"npm run lint && npm run check && npm run build && npm run test","example":"node --import=tsx --env-file=.env src/examples/index.ts"},"devDependencies":{"@biomejs/biome":"^2.2.2","@cardano-ogmios/client":"^6.13.0","@opentelemetry/api":"^1.9.0","@types/node":"^24.3.0","@types/ws":"^8.18.1","pino":"^9.9.2","tsup":"^8.5.0","tsx":"^4.20.6","typescript":"^5.9.2","vitest":"^3.2.4","@opentelemetry/exporter-metrics-otlp-http":"^0.205.0","@opentelemetry/sdk-metrics":"^2.1.0","@opentelemetry/sdk-node":"^0.205.0","pino-opentelemetry-transport":"^1.0.1","pino-pretty":"^11.3.0"},"peerDependencies":{"@cardano-ogmios/client":">=6.0.0","@opentelemetry/api":">=1.0.0","pino":">=8.0.0"},"dependencies":{"trynot":"^0.0.2"},"exports":{"./package.json":"./package.json",".":{"require":{"types":"./index.d.ts","require":"./index.js"},"import":{"types":"./index.d.mts","import":"./index.mjs"}},"./otel":{"require":{"types":"./otel.d.ts","require":"./otel.js"},"import":{"types":"./otel.d.mts","import":"./otel.mjs"}},"./pino":{"require":{"types":"./pino.d.ts","require":"./pino.js"},"import":{"types":"./pino.d.mts","import":"./pino.mjs"}},"./ogmios":{"require":{"types":"./ogmios.d.ts","require":"./ogmios.js"},"import":{"types":"./ogmios.d.mts","import":"./ogmios.mjs"}}},"gitHead":"6c22a75bfc0a5226a0817b3707ee62bbb5857c5c","_id":"@ada-anvil/barrow@0.1.2","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-KzS+icT5swbUs99jkYvbCGpLu1bEsoTuvnroOz7UUE0E70w1rZ1a2AgNm/RG5pmS4hWQHCrDpONzw0tygPEc8A==","shasum":"afe8e3bec98247c0508daf108379e0baca70c50e","tarball":"https://registry.npmjs.org/@ada-anvil/barrow/-/barrow-0.1.2.tgz","fileCount":28,"unpackedSize":132845,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ada-anvil%2fbarrow@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDlvUsUpG6uYJSEQDfFPfb+rEyT4jjZ3C5z+ZSQ+etLPAiEApngfmIccEgLpnbpjWhJMbyHfhFxX5LvRmHGevYUGlSo="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:58a364d3-5987-4210-b169-7146fc89e214"}},"directories":{},"maintainers":[{"name":"tqueri","email":"tqueri@ada-anvil.io"},{"name":"dodilanne","email":"vincaudet@gmail.com"},{"name":"mrabdibdi-anvil","email":"mrabdibdi@ada-anvil.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/barrow_0.1.2_1780010870158_0.6625267186192039"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-06T16:22:22.934Z","modified":"2026-05-28T23:27:50.551Z","0.0.1":"2026-03-06T16:22:23.153Z","0.0.2":"2026-03-06T18:03:22.448Z","0.1.0":"2026-05-19T15:18:54.173Z","0.1.1":"2026-05-28T23:19:28.452Z","0.1.2":"2026-05-28T23:27:50.278Z"},"bugs":{"url":"https://github.com/Cardano-Forge/anvil-barrow/issues"},"author":{"name":"Anvil Development Agency"},"license":"Apache-2.0","homepage":"https://github.com/Cardano-Forge/anvil-barrow","keywords":["javascript","typescript","typesafe","ogmios","blockchain","cardano","chain","indexing","indexer","websocket","web3"],"repository":{"type":"git","url":"git+https://github.com/Cardano-Forge/anvil-barrow.git"},"description":"A framework for building event processing tools","maintainers":[{"name":"tqueri","email":"tqueri@ada-anvil.io"},{"name":"dodilanne","email":"vincaudet@gmail.com"},{"name":"mrabdibdi-anvil","email":"mrabdibdi@ada-anvil.io"}],"readme":"# Barrow [![Version](https://img.shields.io/npm/v/@ada-anvil/barrow?colorB=blue)](https://www.npmjs.com/package/@ada-anvil/barrow)\n\nBarrow is a framework for building event processing tools. It provides a `Controller` class that manages any event-producing service through a simple `Runner` interface.\n\n## Installation\n\n```bash\nnpm i @ada-anvil/barrow\n```\n\n## Architecture\n\nBarrow is built around two core abstractions:\n\n- **Controller**: Manages the lifecycle of event processing (start, pause, resume, error handling, throttling, filtering)\n- **Runner**: Produces events via an async generator. Any service that implements the `Runner` interface can be controlled\n\n```\n┌─────────────────────────────────────┐\n│            Controller               │\n│  ┌─────────────────────────────┐    │\n│  │  lifecycle management       │    │\n│  │  error handling / retry     │◄──►│  Runner (any implementation)\n│  │  filtering / throttling     │    │  ┌───────────────────┐\n│  │  tracing / logging          │    │  │ run() → events    │\n│  └─────────────────────────────┘    │  │ resume() → events │\n└─────────────────────────────────────┘  └───────────────────┘\n```\n\n## Usage\n\n### Controller\n\nThe `Controller` class is the main entry point for defining and running event processing jobs.\n\n**Constructor:**\n\n```typescript\nnew Controller<TRunner>(config, startOpts?)\n```\n\n**Parameters:**\n\n1. `config` (required): Configuration object with the following properties:\n   - `runner`: An instance implementing the `Runner` interface\n   - `errorHandler` (optional): An instance of `ErrorHandler` that handles errors during event processing\n   - `logger` (optional): A function that handles log events\n   - `tracing` (optional): An instance of `ControllerTracer` for metrics and tracing\n\n2. `startOpts` (optional): Default options to use for all `start()` calls. These will be merged with options passed to `start()`, with `start()` options taking precedence. See [Job Configuration](#job-configuration) for available options.\n\n#### Runner Interface\n\nAny class can be a runner by implementing this interface:\n\n```typescript\ninterface Runner<Def extends RunnerDef> {\n  run(opts: Def[\"opts\"]): AsyncGenerator<Def[\"event\"], void>;\n  resume(meta: Def[\"meta\"]): AsyncGenerator<Def[\"event\"], void>;\n  createMeta(opts: Def[\"opts\"]): Def[\"meta\"];\n  createCounters(opts: Def[\"opts\"]): Counters<Def[\"event\"]>;\n  onEventProcessed?(event: Def[\"event\"], mut: { meta: Def[\"meta\"] }): void;\n}\n```\n\nWhere `RunnerDef` defines the types for your runner:\n\n```typescript\ninterface RunnerDef<TMeta, TOpts, TEvent> {\n  meta: TMeta;\n  opts: TOpts;\n  event: TEvent;\n}\n```\n\n### Available Runners\n\n#### OgmiosIndexer (Chain Synchronization)\n\nSyncs blocks from the Cardano blockchain using Ogmios. Extends `IndexerRunner` which provides common indexer functionality.\n\n```typescript\nimport { OgmiosIndexer } from \"@ada-anvil/barrow/ogmios\";\n\nconst runner = new OgmiosIndexer({\n  connection: { host: \"localhost\", port: 1337, tls: false },\n  beforeRun: async (ctx) => { /* optional setup before the generator starts */ },\n  afterRun: async (ctx) => { /* optional cleanup after the generator returns */ },\n});\n```\n\nEvents: `{ type: \"apply\", block, tip }` | `{ type: \"reset\", point, tip }`\n\nThe internal generator and client creation are exposed as standalone exported functions (`createIndexerGenerator`, `createIndexerClient`) and can be overridden by passing a custom `createGenerator` to `run()`.\n\n#### OgmiosMempool (Mempool Monitoring)\n\nMonitors the Cardano mempool for pending transactions. Generic over the parsed transaction type (`TParsedTx`, defaults to `Schema.Transaction`).\n\n```typescript\nimport { OgmiosMempool, getIdentityTxParser } from \"@ada-anvil/barrow/ogmios\";\n\nconst runner = new OgmiosMempool({\n  connection: { host: \"localhost\", port: 1337, tls: false },\n  parser: getIdentityTxParser(),\n  beforeRun: async (ctx) => { /* optional setup before the generator starts */ },\n  afterRun: async (ctx) => { /* optional cleanup after the generator returns */ },\n  getExistingTxs: async (ctx) => [], // optional: seed known txs to detect drops\n});\n```\n\nEvents: `{ type: \"txs\", added: TParsedTx[], dropped: TParsedTx[] }`\n\nSupply a custom `parser` to transform raw `Schema.Transaction` objects into your domain type:\n\n```typescript\ntype MyTx = { hash: string; fee: bigint };\n\nconst runner = new OgmiosMempool<MyTx>({\n  connection: { host: \"localhost\", port: 1337, tls: false },\n  parser: {\n    parseTx: (tx) => ({ hash: tx.id, fee: tx.fee.ada.lovelace }),\n    getTxHash: (tx) => tx.hash,\n  },\n});\n```\n\nThe internal generator and client creation are exposed as standalone exported functions (`createMempoolGenerator`, `createMempoolClient`) and can be overridden by passing a custom `createGenerator` to `run()`.\n\n### Getting Started\n\n#### Step 1: Install Dependencies\n\n```bash\nnpm i @cardano-ogmios/client\n```\n\n#### Step 2: Create a Runner\n\nFor chain indexing:\n\n```typescript\nimport { OgmiosIndexer, type IndexerRunnerDef, type OgmiosSchema } from \"@ada-anvil/barrow/ogmios\";\n\nconst runner = new OgmiosIndexer({\n  connection: { host: \"localhost\", port: 1337, tls: false },\n});\n```\n\nFor mempool monitoring:\n\n```typescript\nimport { OgmiosMempool, getIdentityTxParser, type MempoolRunnerDef } from \"@ada-anvil/barrow/ogmios\";\n\nconst runner = new OgmiosMempool({\n  connection: { host: \"localhost\", port: 1337, tls: false },\n  parser: getIdentityTxParser(),\n});\n```\n\n#### Step 3: Create a Controller\n\n```typescript\nimport { Controller, ErrorHandler } from \"@ada-anvil/barrow\";\n\nconst controller = new Controller<IndexerRunnerDef<OgmiosSchema>>({\n  runner,\n  errorHandler: new ErrorHandler(),\n});\n```\n\nYou can optionally provide default start options as a second parameter:\n\n```typescript\nconst controller = new Controller<IndexerRunnerDef<OgmiosSchema>>(\n  {\n    runner,\n    errorHandler: new ErrorHandler(),\n  },\n  {\n    throttle: [100, \"milliseconds\"],\n    fn: (event) => {\n      console.log(event);\n    },\n  },\n);\n```\n\n#### Step 4: Start Processing\n\n```typescript\nawait controller.start({\n  fn: (event) => {\n    console.log(event);\n  },\n  point: {\n    slot: 101163751,\n    id: \"fa5a6a51632b90557665fcb33970f4fb372dff6ad0191e083ff3b6b221f2b87e\",\n  },\n  throttle: [100, \"milliseconds\"],\n});\n\n// Wait for completion\nawait controller.waitForCompletion();\n```\n\n#### Controlling Jobs\n\n**Pause and Resume:**\n\n```typescript\nawait controller.pause();\nawait controller.resume();\n```\n\n**Restart:**\n\nCalling `start()` on a paused job resets the state and starts from scratch.\n\n#### Job Completion\n\nA job can complete in two ways:\n\n1. **Using `takeUntil`**: The function returns `true`\n\n   ```typescript\n   await controller.start({\n     fn: (event) => { /* process event */ },\n     point: startPoint,\n     takeUntil: ({ state }) => state.meta.syncTip?.slot >= targetSlot,\n   });\n   ```\n\n2. **Using handler return value**: The `fn` handler returns `{ done: true }`\n   ```typescript\n   await controller.start({\n     fn: (event) => {\n       if (someCondition) {\n         return { done: true };\n       }\n     },\n     point: startPoint,\n   });\n   ```\n\n#### Throttling and Filtering\n\nThrottle and filter apply to ALL events, including filtered ones:\n\n```typescript\nawait controller.start({\n  fn: (event) => { /* process event */ },\n  filter: (event) => event.type === \"apply\",\n  point: startPoint,\n  throttle: [100, \"milliseconds\"],\n});\n```\n\n### Job Configuration\n\nConfiguration properties:\n\n- `fn` (optional): Function that handles events\n- `throttle` (optional): Delay between events `[value, unit]`\n- `filter` (optional): Function to filter events (returns boolean)\n- `takeUntil` (optional): Function that returns true to stop processing\n\nRunners may have additional required options (e.g., `point` for indexers).\n\n### Data Structures\n\nEvent shapes depend on the runner. Built-in runners emit:\n\n**OgmiosIndexer events:**\n\n- `apply`: `{ type: \"apply\", block, tip }`\n- `reset`: `{ type: \"reset\", point, tip }`\n\n**OgmiosMempool events:**\n\n- `txs`: `{ type: \"txs\", added: TParsedTx[], dropped: TParsedTx[] }`\n\n**Point (IndexerRunner):**\n\n- `slot`: Slot number\n- `id`: Block hash\n\n## ErrorHandler\n\n`ErrorHandler` defines how errors are handled during event processing. Pass an instance to `Controller` via the `errorHandler` config option.\n\n```typescript\nimport { Controller, ErrorHandler } from \"@ada-anvil/barrow\";\n\nconst errorHandler = new ErrorHandler(\n  ErrorHandler.retry({ maxRetries: 3, baseDelay: 1000 }),\n);\n```\n\n### Registering handlers\n\nHandlers can be registered in the constructor or via `.register()`. Each handler is called in order until one returns a result.\n\n```typescript\nerrorHandler.register((error) => {\n  if (error instanceof MyTransientError) return { retry: { delay: 500 } };\n});\n```\n\nFilter by error type (constructor) or predicate:\n\n```typescript\nerrorHandler.register(MyTransientError, ErrorHandler.retry({ maxRetries: 5 }));\nerrorHandler.register(\n  (e) => e instanceof Error && e.message.includes(\"timeout\"),\n  ErrorHandler.retryWithBackoff({ maxRetries: 4, baseDelay: 200 }),\n);\n```\n\n### Built-in policies\n\n`ErrorHandler.retry(opts)` and `ErrorHandler.retryWithBackoff(opts)` return retry policies:\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `maxRetries` | `number` | required | Maximum number of retry attempts |\n| `baseDelay` | `number` | `0` | Milliseconds between retries |\n| `backoff` | `boolean` | `false` | Double the delay on each attempt |\n| `persistent` | `boolean` | `false` | Preserve retry count across job restarts |\n\n### Handler result\n\nA handler function should return `{ retry: { delay?: number } }` to trigger a retry, or `undefined`/`void` to pass to the next handler. If no handler returns a result, the error is rethrown.\n\n## EventQueue\n\n`EventQueue` is a bounded async queue with abort signal support. It is used internally by the built-in runners but is also exported for use in custom runners.\n\n```typescript\nimport { EventQueue } from \"@ada-anvil/barrow\";\n\nconst queue = new EventQueue<MyEvent>({ capacity: 100, signal: abortController.signal });\n\nawait queue.push(event);         // blocks when full\nconst result = await queue.next(); // blocks when empty\n// result is the event, or an AbortError if the signal was aborted\n```\n\nConfiguration:\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `capacity` | `number` | `Infinity` | Max queued items before `push` blocks |\n| `signal` | `AbortSignal` | none | Signal to abort waiting producers/consumers |\n\n## Logger\n\nBarrow provides built-in logging support using [Pino](https://getpino.io).\n\n### Setup\n\n```bash\nnpm i pino\n```\n\n```typescript\nimport { pinoLogger } from \"@ada-anvil/barrow/pino\";\nimport { pino } from \"pino\";\n\nconst controller = new Controller<IndexerRunnerDef<OgmiosSchema>>({\n  runner: new OgmiosIndexer({ connection: { host: \"localhost\", port: 1337, tls: false } }),\n  logger: pinoLogger(pino()),\n});\n```\n\n## Tracing\n\nBarrow supports [OpenTelemetry](https://opentelemetry.io) for metrics and tracing.\n\n### Setup\n\n```bash\nnpm i @opentelemetry/api\n```\n\n```typescript\nimport { otelTracingConfig } from \"@ada-anvil/barrow/otel\";\nimport { ControllerTracer } from \"@ada-anvil/barrow\";\n\nconst controller = new Controller<MempoolRunnerDef>({\n  runner: new OgmiosMempool({\n    connection: { host: \"localhost\", port: 1337, tls: false },\n    parser: getIdentityTxParser(),\n  }),\n  tracing: new ControllerTracer(otelTracingConfig()),\n});\n```\n\nFor indexer-specific metrics (sync tip, chain tip, is_synced, apply/reset counts), use `IndexerControllerTracer`:\n\n```typescript\nimport { IndexerControllerTracer, indexerMetricDefs } from \"@ada-anvil/barrow/indexer\";\n\nconst tracing = new IndexerControllerTracer(\n  otelTracingConfig({ metrics: indexerMetricDefs })\n);\n```\n\n### Core Metrics\n\nAvailable on all runners via `ControllerTracer`:\n\n| Metric Key     | Type      | Name             | Description                       | Unit         |\n| -------------- | --------- | ---------------- | --------------------------------- | ------------ |\n| status         | gauge     | status           | Controller status                 | -            |\n| processingTime | histogram | processing_time  | Time to process an event          | milliseconds |\n| arrivalTime    | histogram | arrival_time     | Time to receive an event          | milliseconds |\n| filterCount    | gauge     | filter_count     | Number of filtered events         | -            |\n| errorCount     | gauge     | error_count      | Number of errors                  | -            |\n\n### Indexer-Specific Metrics\n\nAvailable when using `IndexerControllerTracer`:\n\n| Metric Key     | Type      | Name             | Description                       |\n| -------------- | --------- | ---------------- | --------------------------------- |\n| syncTipSlot    | gauge     | sync_tip_slot    | Sync tip slot                     |\n| syncTipHeight  | gauge     | sync_tip_height  | Sync tip height                   |\n| chainTipSlot   | gauge     | chain_tip_slot   | Chain tip slot                    |\n| chainTipHeight | gauge     | chain_tip_height | Chain tip height                  |\n| isSynced       | gauge     | is_synced        | Is synced (1 = yes, 0 = no)       |\n| applyCount     | gauge     | apply_count      | Number of apply events            |\n| resetCount     | gauge     | reset_count      | Number of reset events            |\n\n## Examples\n\nExample implementations are available in the `src/examples` directory.\n\n### Running Examples\n\n1. Install dependencies:\n\n   ```bash\n   npm i\n   ```\n\n2. Create a `.env` file:\n\n   ```dotenv\n   OGMIOS_NODE_HOST=<ogmios-node-host>\n   OGMIOS_NODE_PORT=<ogmios-node-port>\n   OGMIOS_NODE_TLS=<ogmios-node-tls>\n   ```\n\n3. Run an example:\n   ```bash\n   npm run example ogmios-indexer\n   npm run example ogmios-mempool\n   ```\n","readmeFilename":"README.md"}