{"id":15316,"library":"electrode-hapi-compat","title":"Electrode Hapi Compatibility Utility","description":"The `electrode-hapi-compat` utility provides functions to simplify the creation and detection of Hapi.js plugins compatible across different major versions, specifically Hapi 16 and Hapi 17/18+. It directly addresses the breaking change in Hapi plugin signatures introduced with Hapi 17, offering a `universalHapiPlugin` function. This function allows developers to define distinct plugin implementations for Hapi 16 and Hapi 17+ environments, automatically serving the correct version based on the Hapi framework detected in the host application. The package also includes helper functions such as `isHapi17OrUp` and `isHapi18OrUp` for conditional logic and offers a mechanism to manually set the Hapi version for testing. The current stable version is 1.3.3. While not on a strict regular cadence, it receives updates for broader utility, such as supporting other frameworks like Fastify in earlier minor versions. Its primary differentiator is providing a concise, focused solution for Hapi plugin compatibility across significant framework version boundaries.","status":"maintenance","version":"1.3.3","language":"javascript","source_language":"en","source_url":"https://github.com/electrode-io/electrode-hapi-compat","tags":["javascript","electrode","hapi","plugin"],"install":[{"cmd":"npm install electrode-hapi-compat","lang":"bash","label":"npm"},{"cmd":"yarn add electrode-hapi-compat","lang":"bash","label":"yarn"},{"cmd":"pnpm add electrode-hapi-compat","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Runtime peer dependency: The utility detects and adapts to the installed version of Hapi (v16) in the host application.","package":"hapi","optional":false},{"reason":"Runtime peer dependency: The utility detects and adapts to the installed version of Hapi (v17+) in the host application.","package":"@hapi/hapi","optional":false}],"imports":[{"note":"This library primarily uses and exemplifies CommonJS `require()` syntax, common in Hapi plugin development. Direct ESM `import` for named exports may require specific tooling or not work as expected.","wrong":"import { universalHapiPlugin } from 'electrode-hapi-compat';","symbol":"universalHapiPlugin","correct":"const { universalHapiPlugin } = require(\"electrode-hapi-compat\");"},{"note":"A named export from the CommonJS module, used for runtime Hapi version detection.","wrong":"import { isHapi17OrUp } from 'electrode-hapi-compat';","symbol":"isHapi17OrUp","correct":"const { isHapi17OrUp } = require(\"electrode-hapi-compat\");"},{"note":"A named export from the CommonJS module, useful for distinguishing newer Hapi versions.","wrong":"import { isHapi18OrUp } from 'electrode-hapi-compat';","symbol":"isHapi18OrUp","correct":"const { isHapi18OrUp } = require(\"electrode-hapi-compat\");"},{"note":"This is a property on the module's default export when using `require()`, not a named export. It can be used to manually set or retrieve the detected Hapi major version for testing or debugging.","wrong":"import { hapiVersion } from 'electrode-hapi-compat';","symbol":"hapiVersion","correct":"require(\"electrode-hapi-compat\").hapiVersion;"}],"quickstart":{"code":"const { universalHapiPlugin, isHapi17OrUp } = require(\"electrode-hapi-compat\");\nconst Hapi = require('@hapi/hapi'); // Ensure Hapi is installed (e.g., npm i @hapi/hapi)\n\nconst registers = {\n  hapi16: (server, options, next) => {\n    console.log(\"Registering Hapi 16 plugin for:\", pkg.name);\n    server.decorate('server', 'myHapi16Feature', 'Hapi16 Specific Value');\n    next();\n  },\n  hapi17OrUp: (server, options) => {\n    console.log(\"Registering Hapi 17+ plugin for:\", pkg.name);\n    server.decorate('server', 'myHapi17Feature', 'Hapi17+ Specific Value');\n  }\n};\n\nconst pkg = {\n  name: \"MyUniversalCompatPlugin\",\n  version: \"1.0.0\"\n};\n\nconst myUniversalPlugin = universalHapiPlugin(registers, pkg);\n\nasync function startServer() {\n  const server = Hapi.server({ port: 3000, host: 'localhost' });\n\n  // For demonstration, manually set hapiVersion if Hapi is not installed or detected\n  // For example, to simulate Hapi 16:\n  // require(\"electrode-hapi-compat\").hapiVersion = 16;\n\n  await server.register({\n    plugin: myUniversalPlugin,\n    options: {}\n  });\n\n  const detectedVersion = require(\"electrode-hapi-compat\").hapiVersion;\n  console.log(`Hapi version detected by electrode-hapi-compat: ${detectedVersion}`);\n  \n  if (isHapi17OrUp()) {\n    console.log(\"Server has myHapi17Feature:\", server.myHapi17Feature);\n  } else {\n    console.log(\"Server has myHapi16Feature:\", server.myHapi16Feature);\n  }\n\n  await server.start();\n  console.log('Server running on %s', server.info.uri);\n}\n\nstartServer();","lang":"javascript","description":"Demonstrates how to create a Hapi plugin compatible with both Hapi 16 and Hapi 17+ using `universalHapiPlugin`, and how to check the currently detected Hapi version."},"warnings":[{"fix":"Utilize `electrode-hapi-compat`'s `universalHapiPlugin` to provide separate plugin implementations for Hapi 16 and Hapi 17+, handling each version's API signature correctly.","message":"Hapi.js version 17 introduced a breaking change in plugin registration signatures, moving from a `(server, options, next)` callback pattern to an `(server, options)` async/await pattern. This utility exists specifically to bridge this gap, meaning direct porting of Hapi 16 plugins to Hapi 17+ without adaptation will fail.","severity":"breaking","affected_versions":"Hapi >= 17.0.0"},{"fix":"Only use `hapiVersion` for explicit, controlled testing scenarios where global state manipulation is acceptable and managed. Avoid using it in production code or shared contexts. For isolated testing, consider mocking the utility's behavior rather than modifying its global state.","message":"Manually setting `hapiVersion` using `require('electrode-hapi-compat').hapiVersion = N` modifies a global state. This can lead to unexpected behavior in complex testing environments or applications where multiple modules might inadvertently affect or rely on this global setting, especially in concurrent test runs or if not properly reset.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Prefer `const { namedExport } = require('electrode-hapi-compat');` for consistency and compatibility. If working strictly in an ESM environment, consider dynamic `import('electrode-hapi-compat')` and destructuring the resulting Promise, or ensure your build setup correctly handles CommonJS module interoperability.","message":"This library primarily uses and showcases CommonJS `require()` syntax in its examples. While Node.js generally supports `require()` for CJS modules in an ESM context, direct `import` statements for named exports like `universalHapiPlugin` may not work as expected without specific transpilation or configuration, given the historical context of Hapi's ecosystem.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Ensure your `hapi16` and `hapi17OrUp` plugin implementations provided to `universalHapiPlugin` correctly match the API for their respective Hapi versions. Verify `electrode-hapi-compat` is detecting the Hapi version correctly, or explicitly set `require('electrode-hapi-compat').hapiVersion` for focused testing.","cause":"Attempting to use `server.decorate` (or other Hapi API methods) in a plugin implementation that does not match the detected Hapi version (e.g., using a Hapi 17+ feature in a Hapi 16 plugin, or vice-versa).","error":"TypeError: server.decorate is not a function"},{"fix":"Check that the `registers` object contains valid `hapi16` and `hapi17OrUp` functions, and that the `pkg` object has at least `name` and `version` properties as shown in the `universalHapiPlugin` examples in the documentation. Ensure `universalHapiPlugin` is called correctly and its result is used as the plugin.","cause":"This error typically occurs if `universalHapiPlugin` is not returning a valid Hapi plugin function, or if the `registers` object or `pkg` object passed to it are malformed or missing required properties.","error":"Plugin registration failed: The plugin must be a function"},{"fix":"For compatibility with this library's CommonJS-oriented examples, ensure your file is treated as CommonJS (e.g., `.js` file with `\"type\": \"commonjs\"` in `package.json`, or using a `.cjs` file extension). If you must use ESM, consider dynamic `import('electrode-hapi-compat')` to load the module asynchronously.","cause":"You are attempting to use the CommonJS `require()` syntax directly within an ECMAScript Module (ESM) file, which is not supported by default without specific Node.js loader configurations or bundler setups.","error":"ReferenceError: require is not defined in ES module scope"}],"ecosystem":"npm"}