{"id":15013024,"url":"https://github.com/sinclairzx81/sidewinder","last_synced_at":"2025-07-12T12:33:44.247Z","repository":{"id":40301997,"uuid":"455552109","full_name":"sinclairzx81/sidewinder","owner":"sinclairzx81","description":"Type Safe Micro Services for Node","archived":false,"fork":false,"pushed_at":"2024-06-26T20:24:13.000Z","size":9350,"stargazers_count":63,"open_issues_count":2,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-04T11:09:06.124Z","etag":null,"topics":["channels","jsonrpc","jsonschema","microservices","mongodb","node","redis","websockets"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sinclairzx81.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":"2022-02-04T13:11:43.000Z","updated_at":"2025-05-29T20:37:28.000Z","dependencies_parsed_at":"2024-05-20T07:27:25.297Z","dependency_job_id":"747d81d4-181e-4043-9af6-3e73e71a4572","html_url":"https://github.com/sinclairzx81/sidewinder","commit_stats":{"total_commits":400,"total_committers":3,"mean_commits":"133.33333333333334","dds":"0.010000000000000009","last_synced_commit":"b828d89bb92aac9dcba8169c70620603c01fc0b9"},"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"purl":"pkg:github/sinclairzx81/sidewinder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Fsidewinder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Fsidewinder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Fsidewinder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Fsidewinder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sinclairzx81","download_url":"https://codeload.github.com/sinclairzx81/sidewinder/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Fsidewinder/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263489883,"owners_count":23474536,"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":["channels","jsonrpc","jsonschema","microservices","mongodb","node","redis","websockets"],"created_at":"2024-09-24T19:43:37.132Z","updated_at":"2025-07-12T12:33:44.194Z","avatar_url":"https://github.com/sinclairzx81.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align='center'\u003e\n\n\u003ch1\u003eSidewinder\u003c/h1\u003e\n\n\u003cp\u003eType Safe Micro Services for Node\u003c/p\u003e\n\n\u003cimg src='./build/assets/sidewinder.png' /\u003e\n\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n[\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/async?label=%40sidewinder%2Fasync\"\u003e](https://www.npmjs.com/package/@sidewinder/async) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/buffer?label=%40sidewinder%2Fbuffer\"\u003e](https://www.npmjs.com/package/@sidewinder/buffer) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/channel?label=%40sidewinder%2Fchannel\"\u003e](https://www.npmjs.com/package/@sidewinder/channel) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/client?label=%40sidewinder%2Fclient\"\u003e](https://www.npmjs.com/package/@sidewinder/client) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/config?label=%40sidewinder%2Fconfig\"\u003e](https://www.npmjs.com/package/@sidewinder/config) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/contract?label=%40sidewinder%2Fcontract\"\u003e](https://www.npmjs.com/package/@sidewinder/contract) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/events?label=%40sidewinder%2Fevents\"\u003e](https://www.npmjs.com/package/@sidewinder/events) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/hash?label=%40sidewinder%2Fhash\"\u003e](https://www.npmjs.com/package/@sidewinder/hash) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/mime?label=%40sidewinder%2Fmime\"\u003e](https://www.npmjs.com/package/@sidewinder/mime) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/mongo?label=%40sidewinder%2Fmongo\"\u003e](https://www.npmjs.com/package/@sidewinder/mongo) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/path?label=%40sidewinder%2Fpath\"\u003e](https://www.npmjs.com/package/@sidewinder/path) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/platform?label=%40sidewinder%2Fplatform\"\u003e](https://www.npmjs.com/package/@sidewinder/platform) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/query?label=%40sidewinder%2Fquery\"\u003e](https://www.npmjs.com/package/@sidewinder/query) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/redis?label=%40sidewinder%2Fredis\"\u003e](https://www.npmjs.com/package/@sidewinder/redis) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/server?label=%40sidewinder%2Fserver\"\u003e](https://www.npmjs.com/package/@sidewinder/server) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/token?label=%40sidewinder%2Ftoken\"\u003e](https://www.npmjs.com/package/@sidewinder/token) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/type?label=%40sidewinder%2Ftype\"\u003e](https://www.npmjs.com/package/@sidewinder/type) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/validator?label=%40sidewinder%2Fvalidator\"\u003e](https://www.npmjs.com/package/@sidewinder/validator) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/validator?label=%40sidewinder%2Fvalue\"\u003e](https://www.npmjs.com/package/@sidewinder/value) [\u003cimg src=\"https://img.shields.io/npm/v/@sidewinder/web?label=%40sidewinder%2Fweb\"\u003e](https://www.npmjs.com/package/@sidewinder/web) [![GitHub CI](https://github.com/sinclairzx81/sidewinder/workflows/GitHub%20CI/badge.svg)](https://github.com/sinclairzx81/sidewinder/actions) \n\n\n\n\u003c/div\u003e\n\n## Overview\n\nSidewinder is a strictly typed and runtime validated micro service framework built for Node and Browser environments. It is designed for web service architectures where each service needs to communicate with other services in complex ways and where challenges often arise verifying each service is communicating using strict communication contracts. \n\nSidewinder is developed primarily around a [runtime type system](https://github.com/sinclairzx81/typebox) based on JSON Schema. It encodes runtime type information into JavaScript directly then leverages the TypeScript language to statically infer associated static types at compile time. This approach enables distributed services to be statically checked with the TypeScript compiler, with the same runtime data assertions handled automatically by Sidewinder packages using standard JSON Schema validation.\n\nLicense MIT\n\n## Contents\n\n- [Overview](#Overview)\n- [Install](#Install)\n- [Static and Runtime Safe](#TypeSafety)\n- [Services and Clients](#ServicesAndClients)\n- [Services and Metadata](#ServiceAndMetadata)\n- [Build Local](#BuildLocal)\n\n### Packages\n\n- [Async](libs/async)\n- [Buffer](libs/buffer)\n- [Channel](libs/channel)\n- [Client](libs/client)\n- [Config](libs/config)\n- [Contract](libs/contract)\n- [Event](libs/events)\n- [Hash](libs/hash)\n- [Mime](libs/mime)\n- [Mongo](libs/mongo)\n- [Path](libs/path)\n- [Platform](libs/platform)\n- [Query](libs/query)\n- [Redis](libs/redis)\n- [Server](libs/server)\n- [Token](libs/token)\n- [Type](libs/type)\n- [Validator](libs/validator)\n- [Value](libs/value)\n- [Web](libs/web)\n\n## Install\n\nSidewinder consists of a number of packages that target various facets of micro service development. Each package is orientated towards type safe interactions with services and common Node infrastructure.\n\n```bash\n# Runtime Type System\n$ npm install @sidewinder/type       # Json Schema Runtime Type Builder\n$ npm install @sidewinder/validator  # Json Schema Validator\n\n# Service Packages\n$ npm install @sidewinder/contract   # Service Descriptions Contracts\n$ npm install @sidewinder/client     # Http and Web Socket Clients\n$ npm install @sidewinder/server     # Http and Web Socket Services and Hosting\n\n# Database and Infrastructure\n$ npm install @sidewinder/query      # Query Filter Syntax for Mongo\n$ npm install @sidewinder/mongo      # Type Safe Mongo\n$ npm install @sidewinder/redis      # Type Safe Redis\n\n# Application Messaging\n$ npm install @sidewinder/async      # Asynchronous Primitives\n$ npm install @sidewinder/channel    # Asynchronous Channels\n$ npm install @sidewinder/events     # Portable Event Emitter\n\n# Hashing and Signing\n$ npm install @sidewinder/hash       # Hashing Functions\n$ npm install @sidewinder/token      # Type Safe Json Web Token\n\n# Environment\n$ npm install @sidewinder/buffer     # Operations on type Uint8Array\n$ npm install @sidewinder/config     # Type Safe Configurations\n$ npm install @sidewinder/path       # File System Pathing Utility\n$ npm install @sidewinder/platform   # Runtime Environment Checks\n```\n\n\u003ca name=\"TypeSafety\"\u003e\u003c/a\u003e\n\n## Static and Runtime Safe\n\n[TypeScript Example Link](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgFQJ5gKZwL5wGZQQhwDkAAgM7AAmGA7sAHa1QD0AxhIzFAIbswSAKFCRYiOAHUMAIwDKGKADdg7LLgJFSlGvSYtWFRUsXDR0eEmkyAwgBtgGbjnyFi5KrQbNFHB08EhIVZWOABaCMio6JjYuPiExPjg0JsuHn4YFPCk3Lz8gqigzkYKeDTuPgE4AF4UdAwAOgqMgQAKBCE4brgjZUUALkQuntGSXmpqEiG0TEaAMQBXRgFgLjaAbVmmgDlFkBlFNoBKABp6ub2Do+OAXXPtxqvDqBPjke7sIWx37ML-gGAsLZBTKVQYP5AqHQuLFLhlXrGcG1OCMehSWSglRqNotKowX59bFNEAYGAACwg1Da40mJHObXY-m4AElqOdeOcZMdagA+YajEKjUYAH2F4rFwpFHzgQvFcEl8u6ip6AGpInAwLw+CAKHA2rwhox9i8uUaTYp3oLQvKVbaZXKJUq1RrlsAAI6LLBMxzOXTcYB4RxQB02iWhpXqiJwUkUqmo3ikuBMPCKKAYaiuLQlVpZa2hiOjKNhODpmCLKCMZOMVNQdOZ3h6gAGxuuUCbhZ60tGZYrVd4cFVcBkcG+vyFMMnU+y9l9WQnU8XQLhpXgPoCKLRdAxtmZMFx6Xx5xI5JgMDAAxCjWvjRIvxKCPTFEWdngdV4dF4wDXe8a7F4dh2DSExTOcACM4HvI6CrOrBTpKtK0F2nBzrIS60bagA5vsAR6o2+qxpS1BDGUUBMJhHLmm2ZqohaUBQWGMEoShYrZF2zEocWMZkkRCZJimaYZlmxA5vibHKuJg4ak+L7wMAzati8TZAA)\n\nSidewinder provides both runtime and static type safety derived from Contract definitions encoded in JavaScript. It makes heavy use of TypeScript's type inference capabilities to statically infer Client and Service method signatures for defined Contracts; with data received over the network runtime checked to ensure it matches the expected parameter and return types defined for each method.\n\n```typescript\n// ---------------------------------------------------------------------------\n// Contract\n// ---------------------------------------------------------------------------\n\nconst Contract = Type.Contract({\n    server: {\n        'add': Type.Function([Type.Number(), Type.Number()], Type.Number())\n    }\n})\n\n// ---------------------------------------------------------------------------\n// Service\n// ---------------------------------------------------------------------------\n\nconst service = new WebService(Contract)\n\nservice.method('add', (clientId, a, b) =\u003e {\n    //        │           │      │\n    //        │           │      └─── params (a: number, b: number)\n    //        │           │\n    //        │           └─── unique client identifier\n    //        │\n    //        └─── method name inferred from contract\n    //\n    //\n    //     ┌─── return inferred as `number`\n    //     │\n    return a + b \n})\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nconst client = new WebClient(Contract, 'http://....')\n\nconst result = await client.call('add', 1, 1)\n//    │                         │         │\n//    │                         │         └─── arguments as (method: string, a: number, b: number)\n//    │                         │ \n//    │                         └─── method name inferred from contract\n//    │\n//    └─── result is `number`\n```\n\n\u003ca name=\"ServicesAndClients\"\u003e\u003c/a\u003e\n\n## Services and Clients\n\n[TypeScript Example Link](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgFQJ5gKZwL5z-g-AMyghDgHIABAZ2ABMMB3YAO0agHoBjCVmKAENuMCgFgAUKEixEcABIQaMADRwA6hgBGAZQxQAbsG5ZcJMpVoNmbDpxr6D+8VPDR4STVoDCAG2AY-DiExKTk1HSMLOz6PP6BopKSnJxwALQZmVnZObl5+QWF+cmp3nwCwjAlJXBl-EIiNHCCUFgOhsZYbDD6RMJYjDTcUMBgMMB8TTAAFoLwg8PAWliCcA7wEERw3IK+voJavhg1RACurCITrE2C7M2scBBjV7twgbz0bADmcETQIHMAHRwHTWaIcOCnBxNOoVRpwGAQOA1Ay7BhzAZzVYOIIQJxQZpwVgYGBMaAAa2aTSYGD2VIRSOUc2Mu18qDgbCI+lq8SCNVu9BBjm5IBJ0wg9CabBQ6AwOkWY2ByCg7O4s1YX2+COmWDALUEop6UBud1aMFOUAeNRgsqafwJMywZwu40mcGWvggTAZHNYqP89AxPICQQFQsMIrFEpogOqEhS6SKSeTKdTWSSEl413gsIa8AAvDLMIDc5UABQISQEe0AmAALkoACsaHwKCoq-h2viG5WJCE8BRBPR6BQG2hiwAxc6XPhlgDa44wgIAcqcQMsoGWAJRqRcrtcb7cAXV3sv36-0253HZCFBopy0o6LS6nLqu873q4vm53z-Ph63E8-y-ADrz7fsKBAU5fCfPdXxnVgPzPEDL1-T8D1QoD0O-K923A29PgMWCz3g11EIXZCMJ-U9ixQn8sMonCtzAghsEkbAtwzBM0x43i+LSGo9A6Ew4wTISjBMJowFIIxGG2PhhhJLpwCOUV+GZN17Vqco8xjcMJKwQ1xUlGpWhMYAnEJLMegAD3gXY+B+FgZgRWVBT1IRDX0JpGCINgMEFR1tUMqN6CVHUaiZcZuFczBfRrDSHmAHz9AsgLfjCYLtPqSpY3jTgan4oriuKCRJCzZQ1kcTo4ELYlvS8cTOjLUsRE4iQu06QEjIlMtB2HNs4DLayMDstRBDULQt1qgA+QkAGp3XazqTG60K+vvR81GG8pRtUZpJum-M5tWNIlskFalx6+g+qgmDtpGsaDqW2bCQAKnOjrqtW66+sIwadv4PbxsO17VlSKaMwq+BxUqurmAUJQYG3SRYZgQEoQwMtLvatHAX8ZRAjLABWAAGcn2sKkrqepmo-BDKp8rp3kYCaLNiREH0msk4FQSiWxuWkvFrCmMlthZ2KMD05AdWRfLfmAY14GSwkvHphI4CYaZjGmeTWA51mfUa77lLAVSEkSpo8W5Gp5BgGAwHGu4gocLNBRV1ZGogbhyRJdWgi1nW9YNqYkS9n2SW5rAamkc31LIq38VV7QQW9330ZQWW-j2L0tUUjEbg0bR-fgRE5YTCq1ywF2TeaLRrbylIqZplu+KhyZ4G4CX4Ya4uWZanTKjUChpntsA6xST0dl8NG6zJ8nOAodroeaYdauaJhBGATuWcBaffD6ocRzUABGNQACZl47tYH3XwRN+38WGb31kNofQaz7gS-yuvu674fnez9963Wgh-C+V9sxwEIv-LegCEgvz2H9CyYCv4QJbEcfGEAvjziPmoTaag7pqEIkeaaCY5wAGY1BpE-ufNQpNATEyPEAA)\n\nSidewinder services consist of three main components, a [Contract](libs/contract/readme.md), [Service](libs/server/readme.md) and [Client](libs/client/readme.md). A Contract defines a set of callable RPC methods and is shared between both Client and Server. A Service provides an implementation for a Contract; and a Client calls methods implemented on the Service. Contracts are used to infer type safe functions on Services and Clients, well as validate method calls made over the network.\n\nThe following shows general usage.\n\n```typescript\nimport { Type }             from '@sidewinder/contract'\nimport { Host, WebService } from '@sidewinder/server'\nimport { WebClient }        from '@sidewinder/client'\n\n// ---------------------------------------------------------------------------\n// Contract\n//\n// Contracts are service interface descriptions that describe a set of callable\n// functions and an optional encoding format. Sidewinder uses Contracts to \n// validate data sent over a network as well as to statically infer Client \n// and Server methods in TypeScript. Try changing the parameters and return \n// types for the functions below to invalidate Client and Server methods.\n//\n// ---------------------------------------------------------------------------\n\nconst Contract = Type.Contract({\n    format: 'json',\n    server: {\n        'add': Type.Function([Type.Number(), Type.Number()], Type.Number()),\n        'sub': Type.Function([Type.Number(), Type.Number()], Type.Number()),\n        'mul': Type.Function([Type.Number(), Type.Number()], Type.Number()),\n        'div': Type.Function([Type.Number(), Type.Number()], Type.Number()),\n    }\n})\n\n// ---------------------------------------------------------------------------\n// Service\n//\n// Services provide concrete implementations for Contracts. Service methods\n// receive a context along with typed parameters defined the the method. The\n// static type information is derived from the Contract.\n//\n// ---------------------------------------------------------------------------\n\nconst service = new WebService(Contract)\nservice.method('add', (context, a, b) =\u003e a + b)\nservice.method('sub', (context, a, b) =\u003e a - b)\nservice.method('mul', (context, a, b) =\u003e a * b)\nservice.method('div', (context, a, b) =\u003e a / b)\n\nconst host = new Host()\nhost.use(service)\nhost.listen(5000)\n\n// ---------------------------------------------------------------------------\n// Client\n//\n// Clients connect to Services. Sidewinder provides two client types. The \n// first is a WebClient which connects to WebService implementations over \n// Http, and the second is a WebSocketClient which connects to WebSocketService \n// implementations over a Web Socket. The following creates a WebClient to \n// consume the service above.\n//\n// ---------------------------------------------------------------------------\n\nconst client = new WebClient(Contract, 'http://localhost:5000/')\nconst add = await client.call('add', 1, 2)\nconst sub = await client.call('sub', 1, 2)\nconst mul = await client.call('mul', 1, 2)\nconst div = await client.call('div', 1, 2)\nconsole.log([add, sub, mul, div]) // [3, -1, 2, 0.5]\n```\n\n\n\n\n\n\u003ca name=\"ServiceAndMetadata\"\u003e\u003c/a\u003e\n\n## Service And Metadata\n\nSidewinder Contracts are expressed as serializable JavaScript objects with embedded JSON schema used to represent method parameter and return types. Contracts can be used for machine readable schematics and published to remote systems, or used to generate human readable documentation.\n\n```typescript\n\n// ---------------------------------------------------------------------------\n// This definition ...\n// ---------------------------------------------------------------------------\n\nconst Contract = Type.Contract({\n    format: 'json',\n    server: {\n        'add': Type.Function([Type.Number(), Type.Number()], Type.Number()),\n        'sub': Type.Function([Type.Number(), Type.Number()], Type.Number()),\n        'mul': Type.Function([Type.Number(), Type.Number()], Type.Number()),\n        'div': Type.Function([Type.Number(), Type.Number()], Type.Number()),\n    }\n})\n\n// ---------------------------------------------------------------------------\n// is equivalent to ...\n// ---------------------------------------------------------------------------\n\nconst Contract = {\n  type: 'contract',\n  format: 'json',\n  server: {\n    'add': {\n      type: 'function',\n      returns: { type: 'number' },\n      parameters: [\n        { type: 'number' },\n        { type: 'number' }\n      ]\n    },\n    'sub': {\n      type: 'function',\n      returns: { type: 'number' },\n      parameters: [\n        { type: 'number' },\n        { type: 'number' }\n      ]\n    },\n    'mul': {\n      type: 'function',\n      returns: { type: 'number' },\n      parameters: [\n        { type: 'number' },\n        { type: 'number' }\n      ]\n    },\n    'div': {\n      type: 'function',\n      returns: { type: 'number' },\n      parameters: [\n        { type: 'number' },\n        { type: 'number' }\n      ]\n    }\n  }\n}\n```\n\n\u003ca name=\"BuildLocal\"\u003e\u003c/a\u003e\n\n## Build Local\n\nSidewinder is built as a mono repository with each publishable package located under the libs directory. Sidewinder uses the [Hammer](https://github.com/sinclairzx81/hammer) build tooling for automated tests, builds and publishing. Sidewinder requires Node 14 LTS. The following shell commands clone the project and outline the commands provide through npm scripts.\n\n```bash\n# clone\n$ git clone git@github.com:sinclairzx81/sidewinder.git\n$ cd sidewinder\n$ npm install\n\n# tasks\n$ npm start         # starts the example project\n$ npm test          # runs the full sidewinder test suite\n$ npm test channel  # runs the sidewinder channel test suite only\n$ npm run format    # runs code formatting across the project\n$ npm run build     # builds all packages to target/build\n$ npm run clean     # cleans all build artifacts\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsinclairzx81%2Fsidewinder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsinclairzx81%2Fsidewinder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsinclairzx81%2Fsidewinder/lists"}