{"id":16432,"library":"many-level","title":"many-level","description":"many-level is a JavaScript library designed to share an abstract-level compatible database over network streams, acting as the spiritual successor to `multileveldown`. Currently at version 2.0.0, it allows a 'host' to expose a LevelDB-like database over any binary stream (e.g., TCP), while 'guests' can connect and interact with it as if it were a local `abstract-level` database instance. It leverages compact Protocol Buffers for efficient message encoding. The project follows a steady release cadence with significant updates marked by major version bumps addressing underlying stream mechanisms and protocol versions. A key differentiator is its optional seamless retry mechanism for guests, which helps maintain connectivity and resume operations, though it comes with a trade-off regarding snapshot guarantees. It ships with TypeScript types, providing a robust development experience.","status":"active","version":"2.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/Level/many-level","tags":["javascript","typescript"],"install":[{"cmd":"npm install many-level","lang":"bash","label":"npm"},{"cmd":"yarn add many-level","lang":"bash","label":"yarn"},{"cmd":"pnpm add many-level","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core internal dependency for stream handling, particularly in v2.0.0+ where it replaced `duplexify`.","package":"readable-stream","optional":false},{"reason":"Used internally for efficient encoding and decoding of database operations over the network.","package":"protocol-buffers","optional":false},{"reason":"Provides the interface contract for both host and guest database instances, though not a direct npm dependency of `many-level` itself, it defines the expected API.","package":"abstract-level","optional":true}],"imports":[{"note":"While CommonJS `require` still works in Node.js, prefer ESM `import` for modern applications and consistent type inference. TypeScript users should always use `import`.","wrong":"const { ManyLevelHost } = require('many-level')","symbol":"ManyLevelHost","correct":"import { ManyLevelHost } from 'many-level'"},{"note":"ManyLevelGuest is a named export, not a default export. Ensure correct destructuring.","wrong":"import ManyLevelGuest from 'many-level'","symbol":"ManyLevelGuest","correct":"import { ManyLevelGuest } from 'many-level'"},{"note":"The `Level` class from the `level` package is commonly used with `many-level` for the host database. It's a named export.","wrong":"import Level from 'level'","symbol":"Level","correct":"import { Level } from 'level'"}],"quickstart":{"code":"import { ManyLevelHost, ManyLevelGuest } from 'many-level';\nimport { Level } from 'level';\nimport { pipeline } from 'readable-stream';\nimport { createServer, connect } from 'net';\nimport { rmSync } from 'fs';\n\n// Clean up previous test database if it exists\ntry {\n  rmSync('./db', { recursive: true, force: true });\n} catch (e) {\n  // ignore\n}\n\nconst dbPath = './db';\nconst hostDb = new Level(dbPath);\nconst host = new ManyLevelHost(hostDb);\n\nconst PORT = 9001;\n\nconst server = createServer(function (socket) {\n  pipeline(socket, host.createRpcStream(), socket, (err) => {\n    if (err) console.error('Host pipeline error:', err.message);\n    console.log('Host: Client disconnected.');\n  });\n});\n\nserver.listen(PORT, async () => {\n  console.log(`Host server listening on port ${PORT}`);\n\n  const guestDb = new ManyLevelGuest();\n  const guestSocket = connect(PORT);\n\n  pipeline(guestSocket, guestDb.createRpcStream(), guestSocket, (err) => {\n    if (err) console.error('Guest pipeline error:', err.message);\n    console.log('Guest: Disconnected from host.');\n  });\n\n  try {\n    await guestDb.put('hello', 'world');\n    console.log(`Guest: Successfully put 'hello': 'world'`);\n    const value = await guestDb.get('hello');\n    console.log(`Guest: Retrieved 'hello': '${value}'`);\n\n    await guestDb.del('hello');\n    console.log(`Guest: Successfully deleted 'hello'.`);\n\n    const hostValue = await hostDb.get('hello');\n    console.log(`Host: Value after guest operation: '${hostValue}'`);\n  } catch (error) {\n    console.error('Guest operation failed:', error.message);\n  } finally {\n    server.close(() => console.log('Host server closed.'));\n    await hostDb.close();\n    console.log('Host database closed.');\n    try {\n        rmSync(dbPath, { recursive: true, force: true });\n        console.log('Cleaned up database files.');\n    } catch (e) {\n        console.warn('Failed to clean up database files:', e.message);\n    }\n  }\n});","lang":"typescript","description":"This quickstart demonstrates setting up a `ManyLevelHost` server and connecting a `ManyLevelGuest` client, performing basic put/get/del operations, and ensuring proper shutdown."},"warnings":[{"fix":"Review custom stream pipelines and ensure compatibility with `readable-stream` v4 if directly interacting with `many-level`'s internal streams beyond `createRpcStream()`.","message":"Version 2.0.0 replaced `duplexify` and related stream utilities with `readable-stream` v4. This is an internal change but could affect custom stream handling or integrations that relied on specific `duplexify` behaviors.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Consult the `UPGRADING.md` guide in the `many-level` repository for a detailed migration path from `multileveldown`.","message":"Upgrading from `multileveldown` to `many-level` (version 1.0.0+) requires significant changes as `many-level` is a complete successor, not a drop-in replacement. The API surface, particularly around stream creation and options, has changed.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Understand the trade-off between seamless retry and snapshot consistency. If snapshot guarantees are critical for your application, avoid `retry: true` and implement manual reconnection logic or handle potential iterator failures.","message":"Using the `retry: true` option for `ManyLevelGuest` enables seamless reconnection but disables snapshot guarantees for iterators. New iterators will be created upon reconnect, meaning `db.supports.snapshots` will be `false`.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure all `many-level` instances (host and guest) are on compatible versions to avoid protocol mismatch issues. Upgrade clients and servers in tandem.","message":"The internal `protocol-buffers` dependency was bumped from v4 to v5 in v2.0.0. While typically an internal concern, this could subtly affect wire compatibility or performance characteristics if you are interacting with the raw protocol buffer messages.","severity":"breaking","affected_versions":">=2.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure the key exists before attempting to retrieve it, or implement error handling for `NotFound` errors. Verify network connectivity between guest and host.","cause":"A `get` operation was attempted for a key that does not exist in the underlying LevelDB instance, or the connection to the host was interrupted.","error":"Error: Not found"},{"fix":"Ensure you are calling `createRpcStream()` on an instance created with `new ManyLevelHost(db)` or `new ManyLevelGuest()`. Double-check import paths and object instantiation.","cause":"Attempting to call `createRpcStream()` on an object that is not a `ManyLevelHost` or `ManyLevelGuest` instance, or before the object is properly initialized.","error":"TypeError: db.createRpcStream is not a function"},{"fix":"Implement robust error handling for stream pipelines, ensuring that operations are only attempted on active connections. The quickstart example demonstrates basic pipeline error handling.","cause":"Attempting to write data to a stream that has already been closed or ended, typically due to a broken or closed network connection.","error":"Error: write after end"}],"ecosystem":"npm"}