{"id":17981531,"url":"https://github.com/francisrstokes/hexnut","last_synced_at":"2025-03-25T18:31:18.119Z","repository":{"id":34329317,"uuid":"171489162","full_name":"francisrstokes/hexnut","owner":"francisrstokes","description":"🔩  Hexnut is a middleware based, express/koa like framework for web sockets","archived":false,"fork":false,"pushed_at":"2022-12-30T17:15:19.000Z","size":277,"stargazers_count":205,"open_issues_count":10,"forks_count":16,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-20T17:07:07.010Z","etag":null,"topics":["framework","javascript","node","nodejs","web-sockets","websockets"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/francisrstokes.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-19T14:33:43.000Z","updated_at":"2024-04-11T17:03:49.000Z","dependencies_parsed_at":"2023-01-15T06:21:49.227Z","dependency_job_id":null,"html_url":"https://github.com/francisrstokes/hexnut","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francisrstokes%2Fhexnut","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francisrstokes%2Fhexnut/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francisrstokes%2Fhexnut/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francisrstokes%2Fhexnut/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/francisrstokes","download_url":"https://codeload.github.com/francisrstokes/hexnut/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245519959,"owners_count":20628807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["framework","javascript","node","nodejs","web-sockets","websockets"],"created_at":"2024-10-29T18:10:47.294Z","updated_at":"2025-03-25T18:31:17.784Z","avatar_url":"https://github.com/francisrstokes.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Hexnut\n\n\u003cimg width=\"639\" height=\"247\" align=\"center\" src=\"docs/logo.png\" /\u003e\n\nHexnut is a middleware based, express/koa like framework for web sockets.\n\n[![npm version](https://badge.fury.io/js/hexnut.svg)]()\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg)]()\n[![CircleCI](https://circleci.com/gh/francisrstokes/hexnut/tree/master.svg?style=svg)](https://circleci.com/gh/francisrstokes/hexnut/tree/master)\n\n\u003ca href=\"docs/index.md\"\u003eFor an introduction, and API documentation, please check out the docs.\u003c/a\u003e\n\n## Middleware\n\n* \u003ca href=\"https://github.com/francisrstokes/hexnut-handle\"\u003ehexnut-handle\u003c/a\u003e: Basic middleware abstraction for handling connections and messages\n* \u003ca href=\"https://github.com/francisrstokes/hexnut-bodyparser\"\u003ehexnut-bodyparser\u003c/a\u003e: Automatically parse JSON messages\n* \u003ca href=\"https://github.com/francisrstokes/hexnut-sequence\"\u003ehexnut-sequence\u003c/a\u003e: Create sequenced conversations between client and server\n* \u003ca href=\"https://github.com/francisrstokes/hexnut-with-observable\"\u003ehexnut-with-observable\u003c/a\u003e: Integration with `rxjs`\n* \u003ca href=\"https://github.com/francisrstokes/hexnut-restore-connection\"\u003ehexnut-restore-connection\u003c/a\u003e: Allow the client to restore a connection state if connectivity is lost\n* \u003ca href=\"https://github.com/francisrstokes/hexnut-router\"\u003ehexnut-router\u003c/a\u003e: Respond differently when sockets connect and communicate on different URLs. Great for versioning!\n\n## Client side\n\nYou can use hexnut as a client in the frontend with \u003ca href=\"https://github.com/francisrstokes/hexnut-client\"\u003e`hexnut-client`\u003c/a\u003e. It is also middleware based and can use many of the server middlewares directly, such as `hexnut-bodyparser` and `hexnut-sequence`.\n\n## Examples\n\n### Trivial Example\n\n```javascript\nconst Hexnut = require('hexnut');\nconst errorService = require(/* some error logging service */);\nconst app = new Hexnut({ port: 8080 });\n\napp.onerror = async (err, ctx) =\u003e {\n  await errorService(err);\n  ctx.send(`Error! ${err.message}`);\n};\n\napp.use(ctx =\u003e {\n  if (ctx.isConnection) {\n    ctx.state = { count: 0 };\n    return ctx.send('Hello, and welcome to the socket!');\n  }\n\n  ctx.state.count++;\n  ctx.send(`Message No. ${ctx.state.count}: ${ctx.message}`);\n});\n\napp.start();\n```\n\n### Parsing JSON automatically\n\n```javascript\nconst Hexnut = require('hexnut');\nconst bodyParser = require('hexnut-bodyparser');\nconst app = new Hexnut({ port: 8080 });\n\napp.use(bodyParser.json());\n\napp.use(ctx =\u003e {\n  if (ctx.isConnection) {\n    ctx.state = { count: 0 };\n    return ctx.send('Hello, and welcome to the socket!');\n  }\n\n  if (ctx.message.type) {\n    ctx.state.count++;\n    ctx.send(`Message No. ${ctx.state.count}: ${ctx.message.type}`);\n  } else {\n    ctx.send(`Invalid message format, expecting JSON with a \"type\" key`);\n  }\n});\n\napp.start();\n```\n\n### Handling messages by type\n\n```javascript\nconst Hexnut = require('hexnut');\nconst handle = require('hexnut-handle');\nconst app = new Hexnut({ port: 8080 });\n\napp.use(handle.connect(ctx =\u003e {\n  ctx.count = 0;\n}));\n\napp.use(handle.matchMessage(\n  msg =\u003e msg === 'incCount',\n  ctx =\u003e ctx.count++\n));\n\napp.use(handle.matchMessage(\n  msg =\u003e msg === 'decCount',\n  ctx =\u003e ctx.count--\n));\n\napp.use(handle.matchMessage(\n  msg =\u003e msg === 'getCount',\n  ctx =\u003e ctx.send(ctx.count)\n));\n\napp.start();\n```\n\n\n### Sequencing Interactions\n\n```javascript\nconst Hexnut = require('hexnut');\nconst bodyParser = require('hexnut-bodyparser');\nconst sequence = require('hexnut-sequence');\nconst app = new Hexnut({ port: 8080 });\n\napp.use(bodyParser.json());\n\n// This sequence happens when the user connects\napp.use(sequence.onConnect(function* (ctx) {\n  ctx.send(`Welcome, ${ctx.ip}`);\n  const name = yield sequence.getMessage();\n  ctx.clientName = name;\n  return;\n}));\n\napp.use(sequence.interruptible(function* (ctx) {\n  // In order to use this sequence, we assert that we must have a clientName on the ctx\n  yield sequence.assert(() =\u003e 'clientName' in ctx);\n\n  // We first expect a message with type == greeting\n  const greeting = yield sequence.matchMessage(msg =\u003e msg.type === 'greeting');\n\n  // Then a message that has type == timeOfDay\n  const timeOfDay = yield sequence.matchMessage(msg =\u003e msg.type === 'timeOfDay');\n\n  return ctx\n    .send(`And a ${greeting.value} to you too, ${ctx.clientName} on this fine ${timeOfDay.value}`);\n}));\n\napp.start();\n```\n\n### Integrating with rxjs\n\n```javascript\nconst Hexnut = require('hexnut');\nconst { withObservable, filterMessages } = require('hexnut-with-observable');\n\nconst { tap, filter } = require('rxjs/operators');\nconst { pipe } = require('rxjs');\n\nconst app = new Hexnut({ port: 8181 });\n\napp.use(withObservable(pipe(\n  // Do setup operations here...\n  tap(({ctx}) =\u003e {\n    if (ctx.isConnection) {\n      console.log(`[${ctx.ip}] Connection started`);\n    }\n  }),\n\n  // Filter to only messages\n  filterMessages(msg =\u003e msg !== 'skip'),\n\n  // Process messages\n  tap(({ctx, next}) =\u003e {\n    ctx.send(`You sent: ${ctx.message}`);\n  })\n)));\n\n\napp.start();\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrancisrstokes%2Fhexnut","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrancisrstokes%2Fhexnut","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrancisrstokes%2Fhexnut/lists"}