JSGI Middleware Adapter for Node.js

raw JSON →
0.3.3 verified Thu Apr 23 auth: no javascript abandoned

This package, `jsgi-node`, functions as an adapter to execute JSGI (JavaScript Gateway Interface) middleware within the Node.js environment. It specifically implements the JSGI 0.3 specification, which includes support for promise-based asynchronous operations, aligning with Node.js's non-blocking I/O model. JSGI is an asynchronous middleware interface conceived with design principles akin to WSGI in Python or Rack in Ruby, promoting straightforward and efficient middleware connectivity through JavaScript closures. While `jsgi-node` itself does not bundle JSGI components, it provides the runtime necessary for existing JSGI middleware stacks, often found in older projects such as Pintura. The package, currently at version 0.3.3, received its last significant updates over a decade ago. It is considered an abandoned project, primarily of historical interest, and is generally unsuitable for contemporary Node.js application development due to its reliance on an outdated CommonJS draft specification.

error Error: Cannot find module 'jsgi-node'
cause The `jsgi-node` package has not been installed or is not resolvable in the current Node.js environment.
fix
Run npm install jsgi-node in your project directory.
error TypeError: require(...) is not a function
cause Attempting to use `require()` in an ES module context (e.g., a file ending in `.mjs` or when `"type": "module"` is set in `package.json`), or attempting to use `import` for this CommonJS-only package.
fix
Ensure your file is a CommonJS module (e.g., a .js file without "type": "module" in package.json) and use const jsgiNode = require('jsgi-node');.
error TypeError: request.body.join is not a function
cause The `request.body` object (expected to be an array of buffers/strings that can be joined or a promise resolving to one) is not in the expected format or the promise has not resolved.
fix
Ensure the incoming request body is correctly parsed and passed to the JSGI app, and that any promise for request.body resolves to an iterable suitable for join(). This often implies issues with how input streams are handled or promised.
error (node:XXXXX) UnhandledPromiseRejectionWarning: Unhandled promise rejection.
cause A promise returned by the JSGI application or an internal component rejected without a `.catch()` handler, which is common in older promise patterns not fully compatible with modern Node.js's strict unhandled rejection warnings.
fix
Ensure all promises, especially those returned by your JSGI application, include .catch() handlers to explicitly manage errors. Review the promise implementation if promised-io or similar is not explicitly used.
breaking This package is built for an ancient Node.js environment (likely Node.js 0.x - 0.10) and the CommonJS JSGI 0.3 draft specification. It is fundamentally incompatible with modern Node.js versions (e.g., Node.js 14+) without significant polyfills, transpilation, or direct code modification, especially regarding `Buffer` and stream APIs.
fix Migrate to a modern middleware framework like Express, Koa, or Fastify. This package is not viable for contemporary development.
gotcha `jsgi-node` is a CommonJS-only package. Attempting to `import` it in an ES module context will result in errors. Direct interop with modern ESM projects will require bundlers or explicit `createRequire` usage.
fix Use `const pkg = require('jsgi-node')` in CommonJS modules. For ESM, consider using `import pkg from 'jsgi-node'` after configuring `node`'s `--experimental-json-modules` or `createRequire` for interoperability, though compatibility issues with the underlying code will persist.
deprecated The underlying JSGI specification itself is a deprecated, unmaintained draft standard from the early CommonJS era. There is no active community support or development for JSGI middleware, severely limiting available components and expertise.
fix Adopt modern, actively maintained middleware standards and frameworks (e.g., Express, Koa).
breaking The package is abandoned and has not been updated in over a decade. It contains unpatched bugs, security vulnerabilities (CVEs), and design patterns that are likely insecure or inefficient by modern standards. Do not use in production.
fix Replace with an actively maintained HTTP server or middleware solution.
gotcha The promise implementation expected by JSGI 0.3 for request bodies and asynchronous responses may not be fully compatible with native `Promise` in modern Node.js, potentially leading to `UnhandledPromiseRejectionWarning` or unexpected behavior if not using a specific A+ compatible library like `promised-io`.
fix Ensure the promise library used (e.g., `promised-io`) is present and correctly integrated. For custom promise objects, verify they strictly adhere to Promises/A+ specification.
npm install jsgi-node
yarn add jsgi-node
pnpm add jsgi-node

Demonstrates how to create a basic "Hello World" JSGI application and host it as a standard Node.js HTTP server using `jsgi-node`'s `Listener` function, including server startup and graceful shutdown.

const http = require("http");
const jsgiNode = require("jsgi-node");

// Define a simple JSGI application that responds with "Hello World!"
// A JSGI application is a function that takes a request object and returns a promise
// that resolves to a response object.
const myJsgiApp = function(request){
  console.log(`[${new Date().toISOString()}] Received request: ${request.method} ${request.url}`);
  return Promise.resolve({
    status: 200,
    headers: { "Content-Type": "text/plain" },
    body: ["Hello World from JSGI-Node! Your path was: " + request.pathInfo]
  });
};

// Use jsgi-node's Listener to adapt the JSGI app for Node.js's http.createServer
const server = http.createServer(jsgiNode.Listener(myJsgiApp));

const PORT = process.env.PORT ?? 3000;
server.listen(PORT, () => {
  console.log(`JSGI-Node server listening on http://localhost:${PORT}`);
  console.log("Access the server in your browser or with curl.");
});

// To gracefully shut down the server in a real application
process.on('SIGINT', () => {
  console.log('Server shutting down...');
  server.close(() => {
    console.log('Server gracefully stopped.');
    process.exit(0);
  });
});