{"id":17647,"library":"farrow-pipeline","title":"Farrow Pipeline","description":"Farrow Pipeline (`farrow-pipeline`) is a core module within the Farrow.js ecosystem, designed as a type-friendly middleware composition library for TypeScript and Node.js environments. It enables developers to construct highly extensible and declarative data processing flows by defining pipelines and middleware with strict input and output typing. Currently stable at version 2.3.0, the package follows a moderate release cadence as part of the broader Farrow.js framework development. A key differentiator is its emphasis on strong type safety, guiding developers to build predictable and composable logic without the common pitfalls of implicit context mutation found in some other middleware paradigms. It provides primitives like `createPipeline` and `defineMiddleware` to facilitate a functional approach to handling sequential operations, forming the foundation for request handling in web applications and other data transformation tasks.","status":"active","version":"2.3.0","language":"javascript","source_language":"en","source_url":"https://github.com/farrow-js/farrow","tags":["javascript","Web Framework","TypeScript","Functional Programming","typescript"],"install":[{"cmd":"npm install farrow-pipeline","lang":"bash","label":"npm"},{"cmd":"yarn add farrow-pipeline","lang":"bash","label":"yarn"},{"cmd":"pnpm add farrow-pipeline","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Farrow.js ecosystem strongly favors ES Modules. While CommonJS `require` might work with transpilation, direct usage can lead to module resolution errors or type inference issues in newer Node.js environments.","wrong":"const { createPipeline } = require('farrow-pipeline')","symbol":"createPipeline","correct":"import { createPipeline } from 'farrow-pipeline'"},{"note":"This is a named export, not a default export. Incorrectly importing it as a default will result in `undefined` at runtime and potential type errors.","wrong":"import defineMiddleware from 'farrow-pipeline'","symbol":"defineMiddleware","correct":"import { defineMiddleware } from 'farrow-pipeline'"},{"note":"While conceptually similar to `compose` functions in other libraries, the specific named export for combining multiple pipelines or middlewares in `farrow-pipeline` is `composePipeline`.","wrong":"import { compose } from 'farrow-pipeline'","symbol":"composePipeline","correct":"import { composePipeline } from 'farrow-pipeline'"}],"quickstart":{"code":"import { createPipeline, defineMiddleware, composePipeline } from 'farrow-pipeline';\n\n// Define a simple logging middleware that enriches the output\nconst loggerMiddleware = defineMiddleware<{ name: string }, { name: string, loggedAt: number }>((input, next) => {\n  console.log(`[Logger] Processing input for: ${input.name}`);\n  const result = next(input);\n  return { ...result, loggedAt: Date.now() };\n});\n\n// Define a validation middleware for the name property\nconst validatorMiddleware = defineMiddleware<{ name: string }, { name: string }>((input, next) => {\n  if (!input.name || input.name.length < 3) {\n    throw new Error('Validation Error: Name must be at least 3 characters long.');\n  }\n  console.log(`[Validator] Input name \"${input.name}\" is valid.`);\n  return next(input);\n});\n\n// Define a data processing middleware that transforms the data\nconst dataProcessorMiddleware = defineMiddleware<{ name: string, data?: any }, { processedData: string }>((input, next) => {\n  console.log(`[Processor] Handling data for: ${input.name}`);\n  const processed = `Transformed data for ${input.name} at ${new Date().toISOString()}`;\n  const nextResult = next(input);\n  return { ...nextResult, processedData: processed };\n});\n\n// Create a pipeline composed of these synchronous middlewares\nconst myPipeline = createPipeline()\n  .use(loggerMiddleware)\n  .use(validatorMiddleware)\n  .use(dataProcessorMiddleware);\n\n// Define an asynchronous middleware for demonstration purposes\nconst asyncMiddleware = defineMiddleware<{ id: number }, { id: number, fetchedData: string }>(async (input, next) => {\n  console.log(`[Async] Starting async operation for ID: ${input.id}`);\n  await new Promise(resolve => setTimeout(resolve, 100)); // Simulate async work\n  const fetchedData = `Data for item ${input.id} from external API`;\n  console.log(`[Async] Finished async operation for ID: ${input.id}`);\n  const result = await next(input); // Await the result of the next middleware\n  return { ...result, fetchedData };\n});\n\n// Compose multiple middlewares (including async ones) into a single pipeline\nconst complexPipeline = composePipeline(\n  asyncMiddleware,\n  defineMiddleware<{ id: number, fetchedData?: string }, { finalResult: string }>(async (input) => {\n    console.log(`[Final] Processing final stage for ID: ${input.id} with fetched data: ${input.fetchedData}`);\n    return { finalResult: `Final output for ID ${input.id} based on: ${input.fetchedData}` };\n  })\n);\n\n// Run the pipelines\nasync function runExamples() {\n  try {\n    console.log('\\n--- Running Simple Pipeline (Valid Input) ---');\n    const result1 = await myPipeline.run({ name: 'Alice' });\n    console.log('Pipeline Result 1:', result1);\n    // Expected: { name: 'Alice', loggedAt: <timestamp>, processedData: 'Transformed data for Alice...' }\n\n    console.log('\\n--- Running Simple Pipeline (Invalid Input) ---');\n    try {\n      await myPipeline.run({ name: 'Bo' }); // This should throw due to validation\n    } catch (error: any) {\n      console.error('Pipeline Error:', error.message);\n      // Expected: 'Validation Error: Name must be at least 3 characters long.'\n    }\n\n    console.log('\\n--- Running Complex Pipeline ---');\n    const result2 = await complexPipeline.run({ id: 123 });\n    console.log('Complex Pipeline Result 2:', result2);\n    // Expected: { id: 123, fetchedData: 'Data for item 123 from external API', finalResult: 'Final output for ID 123...' }\n\n  } catch (e: any) {\n    console.error(\"An unexpected error occurred during example execution:\", e.message);\n  }\n}\n\nrunExamples();","lang":"typescript","description":"This example demonstrates creating and running `farrow-pipeline` instances. It showcases defining synchronous and asynchronous type-safe middlewares with `defineMiddleware`, composing them using `createPipeline().use()` and `composePipeline()`, and handling input/output transformation and errors within the pipeline."},"warnings":[{"fix":"Consult the official Farrow.js documentation and examples for Farrow 2.x to update your pipeline and middleware definitions. There are no direct migration scripts for v1 to v2 due to the fundamental shifts.","message":"The Farrow.js ecosystem, including `farrow-pipeline`, underwent significant architectural and API changes between version 1.x and 2.x, primarily to enhance type safety and introduce new patterns. Direct upgrades from v1 to v2 often require substantial code refactoring.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure your project's `tsconfig.json` specifies a `target` compatible with modern Node.js (e.g., `es2020`) and that your `devDependencies` include `\"typescript\": \"^4.3.0\"` or higher. Always use the latest stable TypeScript version for optimal type checking.","message":"Using `farrow-pipeline` with TypeScript versions older than 4.3 can lead to complex and hard-to-debug type inference errors. The library heavily relies on advanced TypeScript features, particularly generics and conditional types, which were significantly improved in TS 4.3 and later.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Explicitly declare input and output types for `defineMiddleware` where inference becomes ambiguous. Consider breaking down complex pipelines into smaller, explicitly typed sub-pipelines or leveraging utility types provided by Farrow to guide inference.","message":"When chaining many middlewares, especially with intricate generic types or conditional type transformations, TypeScript's inference can sometimes struggle. This may result in overly broad `any` types being inferred for pipeline inputs/outputs, or incorrect type assertions, diminishing type safety.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Always call `next(input)` or `await next(input)` to pass control to the subsequent middleware. Ensure you explicitly `return` the result of `next()` if you intend for subsequent middleware's output to propagate, or return a final value if the middleware is meant to terminate the pipeline.","message":"Misunderstanding the `next` function's role in middleware (e.g., failing to call it, not `await`ing it in async contexts, or not returning its result) can lead to middlewares not executing, pipelines short-circuiting unexpectedly, or incorrect final return values.","severity":"gotcha","affected_versions":">=2.0.0"}],"env_vars":null,"last_verified":"2026-04-23T00:00:00.000Z","next_check":"2026-07-22T00:00:00.000Z","problems":[{"fix":"Always use `defineMiddleware<InputType, OutputType>((input, next) => { ... })` to correctly type and construct your middleware functions, ensuring type compatibility with the pipeline.","cause":"Attempting to pass a plain JavaScript function directly into a pipeline's `.use()` method without wrapping it in `defineMiddleware`, or without correctly specifying generic types for `defineMiddleware`.","error":"Argument of type '(...args: any) => any' is not assignable to parameter of type 'Middleware<any, any>'."},{"fix":"Carefully review the type flow (`InputType` and `OutputType`) between your chained middlewares. Ensure that each middleware explicitly passes the required properties to the next in the chain via its `OutputType` or by modifying the `input` object before calling `next()`.","cause":"A middleware expected a certain property on the `input` object that was not provided by the previous middleware or the initial pipeline run, often due to an incorrect type definition or a middleware short-circuiting.","error":"TypeError: Cannot read properties of undefined (reading 'property')"},{"fix":"Ensure your Node.js project is configured for ES Modules by adding `\"type\": \"module\"` to your `package.json` and using `import` statements. Verify the package is installed and the import path `farrow-pipeline` is correct.","cause":"This typically occurs when trying to use `farrow-pipeline` (which is designed for ES Modules) within a CommonJS environment without proper configuration, or due to incorrect import paths.","error":"Module not found: Can't resolve 'farrow-pipeline' in '...' OR ReferenceError: require is not defined"}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}