{"id":26582968,"url":"https://github.com/capybara003/firecomm","last_synced_at":"2026-04-24T12:34:08.901Z","repository":{"id":281890923,"uuid":"946493134","full_name":"Capybara003/firecomm","owner":"Capybara003","description":null,"archived":false,"fork":false,"pushed_at":"2025-03-11T08:27:02.000Z","size":356,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-01T12:46:00.677Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Capybara003.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-11T08:21:04.000Z","updated_at":"2025-03-11T08:27:22.000Z","dependencies_parsed_at":"2025-03-11T17:54:12.436Z","dependency_job_id":"b9dafd73-d17f-4876-bb98-22d6ff716ef6","html_url":"https://github.com/Capybara003/firecomm","commit_stats":null,"previous_names":["capybara003/firecomm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Capybara003/firecomm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Capybara003%2Ffirecomm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Capybara003%2Ffirecomm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Capybara003%2Ffirecomm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Capybara003%2Ffirecomm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Capybara003","download_url":"https://codeload.github.com/Capybara003/firecomm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Capybara003%2Ffirecomm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32224205,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T10:26:35.452Z","status":"ssl_error","status_checked_at":"2026-04-24T10:25:27.643Z","response_time":64,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-23T08:19:12.769Z","updated_at":"2026-04-24T12:34:08.887Z","avatar_url":"https://github.com/Capybara003.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FIRECOMM\r\n![badge](https://img.shields.io/badge/version-v2.0.3.beta%20release-brightgreen)\r\n![badge](https://img.shields.io/badge/build-passing-green?labelColor=444444)\r\n![badge](https://img.shields.io/badge/license-Apache--2.0-green)\r\n\r\nFeature library for gRPC-Node. Core functions for packaging a .proto file, creating Servers and client Stubs, and a unified API of chainable RPC call methods, client-side and server-side event listeners for data, metadata, cancellation, errors, and status changes, and support for Express-like middleware, client-side interceptors, granular error handling, access to all 74 gRPC channel configurations, as well as idempotent, cacheable, corked and waitForReady requests. \r\n\r\nCheck out the [documentation website](https://firecomm.github.io)!\r\n\r\n# Getting Started\r\n## Install\r\n``` \r\nnpm install --save firecomm\r\n```\r\n\r\n## 1. Define a .proto file\r\nThe .proto file is the schema for your Servers and client Stubs. It defines the package you will build which will give your Server and Client superpowers -- Remote Procedure Call (RPC) methods. RPC methods define what Message the client Stubs send and receive from the server Handlers.\r\n```protobuf\r\n// proto/exampleAPI.proto\r\nsyntax = \"proto3\";\r\n\r\npackage exampleAPI;\r\n\r\nservice ChattyMath {\r\n  rpc BidiMath (stream Benchmark) returns (stream Benchmark) {};\r\n}\r\n\r\nmessage Benchmark {\r\n  double requests = 1;\r\n  double responses = 2;\r\n}\r\n```\r\n\r\n\u003e In our example, the RPC method BidiMath is fully bidirectional. The Benchmark message received on either side will be an Object with the properties `requests` and `responses`. The values of `requests` and `responses` will be doubles, or potentially very large numbers. You can read more about protobufs and all of the possible Message fields at Google's developer docs [here](https://developers.google.com/protocol-buffers/docs/proto3).\r\n\r\n## 2. Build a package\r\n\r\nIn order to pass superpowers to our Server and client Stubs, we first need to package our .proto file. We will use the core `build` function imported from the firecomm library to build our package.\r\n\r\n```javascript\r\n// /proto/package.js\r\nconst { build } = require( 'firecomm' );\r\nconst path = require( 'path' );\r\nconst PROTO_PATH = path.join( __dirname, './exampleAPI.proto' );\r\n\r\nconst CONFIG_OBJECT = {\r\n  keepCase: true, // keeps our RPC methods camelCased on Stub\r\n  longs: Number, // compiles the potentially enormous `double`s for our Benchmark requests and responses into a Number rather than a String\r\n}\r\nconst package = build( PROTO_PATH, CONFIG_OBJECT );\r\nmodule.exports = package;\r\n```\r\n\r\n\u003e Under the hood, the config object is passed all the way to the protobufjs loader. For a clearer low-level understanding of the possible configurations, see their npm package documentation [here](https://www.npmjs.com/package/protobufjs).\r\n\r\n## 3. Create a server\r\nNow that we have our package, we need a Server. Let's import the `Server` class from the Firecomm library.\r\n\r\n```javascript\r\n// /server/server.js\r\nconst { Server } = require( 'firecomm' );\r\nconst server = new Server();\r\n```\r\n\r\n\u003e Under the hood, Firecomm extends Google's gRPC core channel configurations. You can pass an Object to the Server as the first argument to configure advanced options. You can see all of the Object properties and the values you can set them to in the gRPC core docs [here](https://grpc.github.io/grpc/core/group__grpc__arg__keys.html).\r\n\r\n## 4. Define the server-side Handler\r\n\r\nBefore we can interact with a client, our Server needs Handlers. Handlers are usually unique to each RPC Method. In order to demonstrate the power of gRPCs, we will be listening for client requests and immediately sending back server responses in a ping-pong pattern. Metadata is sent only once at the start of the exchange, which will trigger Node's built in timers to start clocking the nanoseconds between responses and requests.\r\n\r\n```javascript\r\n// /server/chattyMathHandlers.js\r\nfunction BidiMathHandler(bidi) {\r\n  let start;\r\n  let current;\r\n  let perReq;\r\n  let perSec;\r\n  bidi\r\n    .on('metadata', (metadata) =\u003e {\r\n      start = Number(process.hrtime.bigint()); // marks a start time in nanoseconds\r\n      bidi.set({thisSetsMetadata: 'responses incoming'})\r\n      console.log(metadata.getMap()); // maps the special metadata object as a simple Object\r\n    })\r\n    .on('error', (err) =\u003e {\r\n      console.error(err)\r\n    })\r\n    .on('data', (benchmark) =\u003e {\r\n      bidi.send(\r\n        {\r\n          requests: benchmark.requests, \r\n          responses: benchmark.responses + 1\r\n        }\r\n      );\r\n      if (benchmark.requests % 10000 === 0) {\r\n        current = Number(process.hrtime.bigint()); // marks the current time in nanoseconds\r\n        perReq = ((current - start) /1000000) / benchmark.requests; // finds the difference in time from start to current, converts nanoseconds to milliseconds, and averages the time per request from total requests\r\n        perSec = 1 / (perReq / 1000); // inverts milliseconds per request to requests per second\r\n      console.log(\r\n        '\\nclient address:', bidi.getPeer(), // returns the client address\r\n        '\\nnumber of requests:', benchmark.requests, // total requests\r\n        '\\navg millisecond speed per request:', perReq,\r\n        '\\nrequests per second:', perSec,\r\n      );\r\n    }\r\n  })\r\n}\r\n\r\nmodule.exports = { \r\n\tBidiMathHandler,\r\n}\r\n```\r\n\r\n\u003e As I'm sure you've noticed, the Objects we are receiving and sending have exactly the properties and value-types we defined in the Benchmark message in the .proto file. If you attempt to send an incorrectly formatted Object, the RPC Method will coerce the Object into a Message with the correct formatting. Values will be coerced to a default falsey value: `{ aString: '' }`, `{ someObject: {}, anArray: [] }`, or in our BidiMath example `{ requests: 0, responses: 0 }`.\r\n\r\n## 5. Add the Services\r\n\r\nLet's import the Handler and the package and add each Service to our Server alongside an Object mapping the name of the RPC Method with the Handler we created.\r\n\r\n```javascript\r\n// /server/server.js\r\nconst { Server } = require( 'firecomm' );\r\nconst package = require( '../proto/package.js' );\r\nconst { BidiMathHandler } = require ( './chattyMathHandlers.js' );\r\n\r\nnew Server()\r\n  .addService( package.ChattyMath,   {\r\n  BidiMath: BidiMathHandler,\r\n})\r\n```\r\n\u003e Servers can chain the .addService method as many times as they wish for each Service that we defined in the .proto file. If you have multiple RPC methods in a Service, each should be mapped as a property on the Object with a Handler function as the value. Not mapping all of your RPC Methods will cause a Server error.\r\n\r\n## 6. Bind the server to addresses\r\n\r\n```javascript\r\n// /server/server.js\r\nconst { Server } = require( 'firecomm' );\r\nconst package = require( '../proto/package.js' );\r\nconst { BidiMathHandler } = require ( './chattyMathHandlers.js' );\r\n\r\nnew Server()\r\n  .addService( package.ChattyMath,   {\r\n  BidiMath: BidiMathHandler,\r\n})\r\n  .bind('0.0.0.0: 3000')\r\n```\r\n\u003e The .bind method can be passed an array of strings to accept requests at any number of addresses. For example:\r\n\u003e ```javascript\r\n\u003e server.bind( [ \r\n\u003e   '0.0.0.0: 3000', \r\n\u003e   '0.0.0.0: 8080', \r\n\u003e   '0.0.0.0: 9900',\r\n\u003e ] );\r\n\u003e ```\r\n## 7. Start the server\r\n```javascript\r\n// /server/server.js\r\nconst { Server } = require( 'firecomm' );\r\nconst package = require( '../proto/package.js' );\r\nconst { BidiMathHandler } = require ( './chattyMathHandlers.js' );\r\n\r\nnew Server()\r\n  .addService( \r\n    package.ChattyMath,   \r\n    { BidiMath: BidiMathHandler }\r\n  )\r\n  .bind('0.0.0.0: 3000')\r\n  .start();\r\n```\r\n\u003e Run your new firecomm/gRPC-Node server with: `node server/server.js`. It may also be worthwhile to map this command to `npm start` in your `package.json`.\r\n\r\n## 8.  Create a client Stub for each Service:\r\nNow that the server is up and running, we have to pass superpowers to the client-side. We open channels by connecting each Stub to the same address as a Server is bound to. In order for the Stub to be able to make RPC Method requests we need to pass the package.Service into a newly constructed `Stub`.\r\n```javascript\r\n// /clients/chattyMath.js\r\nconst { Stub } = require( 'firecomm' );\r\nconst package = require( '../proto/package.js' )\r\nconst stub = new Stub( \r\n\tpackage.ChattyMath, \r\n\t'localhost: 3000', // also can be '0.0.0.0: 3000'\r\n);\r\n```\r\n\u003e Under the hood, Firecomm extends Google's gRPC core channel configurations. You can pass an Object to the Stub as the second argument to configure advanced options. **Note: Any channel configurations on the client Stub should match the configurations on the server it is requesting to.** You can see all of the Object properties and the values you can set them to in the gRPC core docs [here](https://grpc.github.io/grpc/core/group__grpc__arg__keys.html).\r\n\r\n## 9. Make requests from the Stub and see how many requests and responses a duplex can make!\r\nBefore we can interact with a server, our client Stub needs to invoke the RPC Method. We can also pass any metadata we would like to send at this point as the first argument of the RPC Method. RPC Methods now exist on the Stub just like it was defined in the .proto file because we passed the package.Service into the Stub constructor. Because we defined the RPC Method to send a stream of messages and return a stream of messages, both the client Stub and the server can send and listen for any number of messages over a long-living TCP connection. \r\n\r\nOnce the RPC Method is invoked, the client Stub always sends the first request. As soon as the server Handler receives the request, the ping-pong will begin. Similarly to the server Handler, now on the client-side, we will begin listening for server requests and immediately sending back client responses. Again, metadata is received from the server only once at the start of the exchange, which will trigger Node's built in timers to start clocking the nanoseconds between requests and responses.\r\n```javascript\r\n// /clients/chattyMath.js\r\nconst { Stub } = require( 'firecomm' );\r\nconst package = require( '../proto/package.js' )\r\nconst stub = new Stub( \r\n  package.ChattyMath, \r\n  'localhost: 3000',\r\n);\r\n\r\nlet start;\r\nlet current;\r\nlet perRes;\r\nlet perSec;\r\nconst bidi = stub.bidiMath({thisIsMetadata: 'let the races begin'})\r\n  .send({requests: 1, responses: 0})\r\n  .on( 'metadata', (metadata) =\u003e {\r\n    start = Number(process.hrtime.bigint()); // marks a start time in nanoseconds \r\n    console.log(metadata.getMap()) // maps the special metadata object as a simple Object\r\n  })\r\n  .on( 'error', (err) =\u003e console.error(err))\r\n  .on( 'data', (benchmark) =\u003e {\r\n    bidi.send(\r\n      {\r\n        requests: benchmark.requests + 1, \r\n        responses: benchmark.responses\r\n      }\r\n    )\r\n    if (benchmark.responses % 10000 === 0) {\r\n      current = Number(process.hrtime.bigint()); // marks the current time in nanoseconds \r\n      perRes = ((current - start) / 1000000) / benchmark.responses; // finds the difference in time from start to current, converts nanoseconds to milliseconds, and averages the time per response from total responses\r\n      perSec = 1 / (perRes / 1000); // inverts milliseconds per response to responses per second\r\n    console.log(\r\n      'server address:', bidi.getPeer(), // returns the server address\r\n      '\\ntotal number of responses:', benchmark.responses, // total responses\r\n      '\\navg millisecond speed per response:', perRes,\r\n      '\\nresponses per second:', perSec,\r\n    )\r\n  }\r\n});\r\n```\r\n\u003e Run your new firecomm/gRPC-Node client with: `node clients/chattyMath.js`. It may also be worthwhile to map this command to a script like `npm run client` in your `package.json`.\r\n\r\nNow enjoy the power of gRPCs! See how many requests and responses you can make per second with one duplex RPC method! \r\n\r\nExplore the flexible possibilities! Creatively modify the bidiMath to be full duplex instead of ping-ponging. Add more client Stubs to run services in parallel to one server address, bind multiple addresses to the Server, run multiple clients with their own Stubs requesting from separate addresses, etc. And once you feel comfortable with the clients and servers, dive into modifying the .proto file to change the message fields or add multiple messages with different fields to send and receive, add multiple RPC methods to one Service, or add multiple Services to the package. Then, build the new .proto, add each package.Service to a server, create a Stub with the each matching package.Service and a server address, and explore the endless potential of gRPCs!\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapybara003%2Ffirecomm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcapybara003%2Ffirecomm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapybara003%2Ffirecomm/lists"}