{"id":21354478,"url":"https://github.com/ya-kostik/redbone","last_synced_at":"2025-07-12T22:31:59.255Z","repository":{"id":17880580,"uuid":"82810516","full_name":"ya-kostik/redbone","owner":"ya-kostik","description":"Library for client → server → client dispatching","archived":false,"fork":false,"pushed_at":"2022-12-09T08:14:33.000Z","size":709,"stargazers_count":3,"open_issues_count":8,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-07T01:43:20.225Z","etag":null,"topics":["client","dispatch","library","redux","server","socket"],"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/ya-kostik.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":"2017-02-22T13:58:25.000Z","updated_at":"2024-01-29T18:32:34.000Z","dependencies_parsed_at":"2023-01-11T20:27:33.193Z","dependency_job_id":null,"html_url":"https://github.com/ya-kostik/redbone","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"purl":"pkg:github/ya-kostik/redbone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ya-kostik%2Fredbone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ya-kostik%2Fredbone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ya-kostik%2Fredbone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ya-kostik%2Fredbone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ya-kostik","download_url":"https://codeload.github.com/ya-kostik/redbone/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ya-kostik%2Fredbone/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265066119,"owners_count":23706062,"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":["client","dispatch","library","redux","server","socket"],"created_at":"2024-11-22T04:13:31.397Z","updated_at":"2025-07-12T22:31:58.993Z","avatar_url":"https://github.com/ya-kostik.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redbone\nBackend for your application. Inspired by Redux.\nBut you can use it with Vuex, or any Flux library.\n\nYou can use it with any transport you want, but by default Redbone has only socket.io support.\n\n## Install\n\n### npm\n```\nnpm install redbone\n```\n\n### yarn\n```\nyarn add redbone\n```\n\n## Quick start with socket.io\n\n### Server side\n```js\n//... io — is a socket.io server instance\nconst Redbone = require('redbone');\nconst SocketIOConnector = Redbone.connectors.SocketIO;\n\nconst connector = new SocketIOConnector(io);\nconst redbone = new Redbone(connector);\n\n//Watch to client action\nredbone.watch('@@server/user/GET', async function(client, action) {\n  if (!action.user) throw new Error('User not found');\n  //Your logic here, getUser — just example\n  const user = await Model.getUser(action.user);\n  if (!user) throw new Error('User not found');\n  //dispatch action to client\n  client.dispatch({ '@@user/current/SET', user });\n});\n\nredbone.watch('@@server/user/SET', async function(client, action) {\n  if (!action.user) throw new Error('User is undefined');\n  const user = await Model.setUser(action.user);\n  client.dispatch({ type: '@@system/SUCCESS_SAVE', user });\n})\n\nredbone.catch((client, action, err) =\u003e {\n  if (action.type === '@@server/user/GET') {\n    if (err.message === 'User not found') {\n      return client.dispatch({\n        type: '@@system/SHOW_ERROR_MODAL',\n        title: 'User not found'\n      });\n    }\n  }\n  client.dispatch({\n    type: '@@system/SHOW_ERROR_MODAL',\n    title: 'Server Error',\n    err\n  });\n});\n\n```\n\n### Client side with Redux\nAfter create your store, just add\n```js\n// io — your socket.io connection to server\n// dispatch — your choisen event name, default is “dispatch”\n// you can change it on the server side\n// new SocketIOConnector(io, inEvent, outEvent)\n// inEvent — event for input events — defaults is “dispatch”\n// outEvent — event for output events — events for client  — defaults is inEvent value\nio.on('dispatch', store.dispatch);\n```\nAll `client.dispatch(action)` at redbone watcher will perform action to client\n\n## Watchers\n\nIf you want process some of `action.type`, you can use `redbone.watch`:\n```javascript\nredbone.watch(TYPE, fn);\n```\n`TYPE` — is the `action.type`\n`fn` — function to process this `TYPE`.\n`fn` receive 2 params:\n- `client` is a connection to client side, creates by connector\n- `action` from client with `{ type: TYPE }` schema.\n\n\nFor quick load folder with watchers you can use `readWatchers(dir)` or `readWatchersSync(dir)`:\n\n**./watchers/user.js**\n```javascript\n// Easy errors process\nconst HttpError = require('redbone/Errors/HttpError');\nconst db = require('../db');\nasync load(client, action) {\n  if (!action.id) throw new HttpError(400, 'User is is not defined');\n  const user = await db.User.findOne({ id: action.id });\n  client.dispatch({ type: '@@client/user/SETUP', user });\n}\n\nmodule.exports = [\n  { type: \"@@server/user/LOAD\", action: load }\n];\n```\n**./socket.js**\n```js\n// ...\n// scan all watchers directory and set watchers\nredbone.readWatchersSync(path.join(__dirname, './watchers/'));\n// ...\n```\n\nMaybe you want use your custom logic for setup several watchers? Ok, just use `processWatchers(watchers)` method\n\n## Middlewares\nJust use `use` method of Redbone instance =).\n```js\nredbone.use((client, action) =\u003e {\n  if (!action.token) throw new HttpError(403, 'Invalid token');\n});\n```\n\nIf you want stop middleware, just `return false` from it:\n```js\nredbone.use((client, action) =\u003e {\n  if (action.type === '@@server/CONSOLE_LOG') {\n    console.info(action.log);\n    // Stop middlewares and watchers\n    return false;\n  }\n});\n```\n\nYou want to throw Error? Just do it:\n```js\nconst HttpError = require('redbone/Errors/HttpError');\nredbone.use((client, action) =\u003e {\n  if (!action.token) throw new HttpError(403, 'Your token is Invalid');\n});\n```\nErrors from middlewares and watchers will be caught by a special function, which you can set as follows:\n```js\nredbone.catch((client, action, err) =\u003e {\n  // ...your error logic here\n});\n```\n\n## RRPC\n\nRRPC — is Redbone's Remote Procedure Call\n\nYou can call any method of any object you want directly from a client.\n\n### Add RPC to the Redbone on the server side\n\n```js\n// ...\nconst Redbone = require('redbone');\nconst RPC = Redbone.extensions.RPC;\n\nconst redbone = new Redbone(connector);\nconst rpc = new RPC();\n\nredbone.extension(rpc);\n\n// add mongoose models to the rpc\nrpc.setLib('mongoose', mongoose.models);\n```\n\n### Call from client side with socket.io and default input event\n```js\nio.emit('dispatch', {\n  type: '@@server/rpc/CALL',\n  lib: 'mongoose',\n  module: 'User',\n  method: 'getUserAvararLink',\n  arguments: userToken,\n  backType: '@@client/user/SET_USER_PROFILE'\n});\n/**\n * Output example\n * {\n *   type: '@@client/user/SET_USER_PROFILE',\n *   payload: {\n *     avatar: 'http://example.com/user/134/avatar.jpg'\n *   }\n * }\n */\n```\n- `lib` — library in RPC\n- `module` — field in library\n- `method` — method of field\n- `arguments` — the first argument of method\n- `flat` — Boolean, if it is true, and arguments is an array, arguments will be send to method with spread operator (`...arguments`)\n- `merge` — Boolean, if if is true, and the method of module return object — will assign result into the root of action, instead of payload field\n- `backType` — type for back action, default is “`@@client/rpc/RETURN`”\n\n### Publish/Subscribe\n\nSome of your modules can be an instance of `EventEmitter`.\nIf you want to subscribe to some events, you can do it with following action:\n```js\nio.emit('dispatch', {\n  type: '@@server/rpc/SUB',\n  lib: 'mongoose',\n  module: 'User',\n  event: 'change_id-1',\n  payload: userToken,\n  backType: '@@client/user/SET_USER_PROFILE'\n});\n```\n\nNow all `change_id-1` events will be dispatched to the client side with `backType`\n\nIf you want to unsubscribe, just use `@@server/rpc/UNSUB` type with `lib`, `module`, `event` fields.\n\nAll your listeners will be removed automaticaly, when client connection lost.\n\n## Other documentation, and grammar fixes comming soon\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fya-kostik%2Fredbone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fya-kostik%2Fredbone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fya-kostik%2Fredbone/lists"}