{"id":36603955,"url":"https://github.com/hypercore-protocol/hypercore-protocol","last_synced_at":"2026-01-12T08:41:51.530Z","repository":{"id":57151688,"uuid":"52331136","full_name":"hypercore-protocol/hypercore-protocol","owner":"hypercore-protocol","description":"Stream that implements the hypercore protocol","archived":false,"fork":false,"pushed_at":"2020-10-09T12:27:22.000Z","size":152,"stargazers_count":109,"open_issues_count":5,"forks_count":46,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-10-08T20:27:05.655Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hypercore-protocol.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}},"created_at":"2016-02-23T04:52:09.000Z","updated_at":"2025-07-23T21:22:50.000Z","dependencies_parsed_at":"2022-08-31T04:40:35.607Z","dependency_job_id":null,"html_url":"https://github.com/hypercore-protocol/hypercore-protocol","commit_stats":null,"previous_names":["mafintosh/hypercore-protocol"],"tags_count":75,"template":false,"template_full_name":null,"purl":"pkg:github/hypercore-protocol/hypercore-protocol","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypercore-protocol%2Fhypercore-protocol","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypercore-protocol%2Fhypercore-protocol/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypercore-protocol%2Fhypercore-protocol/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypercore-protocol%2Fhypercore-protocol/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hypercore-protocol","download_url":"https://codeload.github.com/hypercore-protocol/hypercore-protocol/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypercore-protocol%2Fhypercore-protocol/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28337599,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"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":"2026-01-12T08:41:50.943Z","updated_at":"2026-01-12T08:41:51.521Z","avatar_url":"https://github.com/hypercore-protocol.png","language":"JavaScript","readme":"# hypercore-protocol\n\nStream that implements the [hypercore](https://github.com/hypercore-protocol/hypercore) protocol\n\n```\nnpm install hypercore-protocol\n```\n\n[![build status](https://travis-ci.org/hypercore-protocol/hypercore-protocol.svg?branch=master)](https://travis-ci.org/hypercore-protocol/hypercore-protocol)\n\nFor detailed info on the messages sent on each channel see [simple-hypercore-protocol](https://github.com/mafintosh/simple-hypercore-protocol)\n\nNote that the latest version of this is Hypercore Wire Protocol 7, which is not compatible with earlier versions.\n\n## Usage\n\n``` js\nconst Protocol = require('hypercore-protocol')\n\n// create two streams with hypercore protocol\nconst streamA = new Protocol(true) // true indicates this is the initiator\nconst streamB = new Protocol(false) // false indicates this is not the initiator\n\n// open two feeds specified by a 32 byte key\nconst key = Buffer.from('deadbeefdeadbeefdeadbeefdeadbeef')\nconst channel = streamA.open(key)\nconst remoteFeed = streamB.open(key, {\n  // listen for data in remote feed\n  ondata (message) {\n    console.log(message.value.toString())\n  }\n})\n\n// add data to feed\nchannel.data({ index: 1, value: '{ block: 42 }'})\n\nstreamA.pipe(streamB).pipe(streamA)\n```\n\n`output =\u003e { block: 42 }`\n\n## API\n\n#### `const stream = new Protocol(initiator, [options])`\n\nCreate a new protocol duplex stream.\n\nOptions include:\n\n``` js\n{\n  encrypted: true, // set to false to disable encryption if you are already piping through a encrypted stream\n  noise: true, // set to false to disable the NOISE handshake completely. Requires encrypted = false, and also disables the capability verification\n  timeout: 20000, // stream timeout. set to 0 or false to disable.\n  keyPair: { publicKey, secretKey }, // use this keypair for the stream authentication\n  onauthenticate (remotePublicKey, done) { }, // hook to verify the remotes public key\n  onhandshake () { }, // function called when the stream handshake has finished\n  ondiscoverykey (discoveryKey) { }, // function called when the remote stream opens a channel you have not\n  onchannelclose (discoveryKey, publicKey) { } // function called when a feed-channel closes\n}\n```\n\n#### `stream.on('discovery-key', discoveryKey)`\n\nEmitted when the remote opens a feed you have not opened.\nAlso calls `stream.handlers.ondiscoverykey(discoveryKey)`\n\n#### `stream.on('timeout')`\n\nEmitted when the stream times out.\nPer default a timeout triggers a destruction of the stream, unless you disable timeout handling in the constructor.\n\n#### `stream.setTimeout(ms, ontimeout)`\n\nSet a stream timeout.\n\n#### `stream.setKeepAlive(ms)`\n\nSend a keep alive ping every ms, if no other message has been sent.\nThis is enabled per default every timeout / 2 ms unless you disable timeout handling in the constructor.\n\n#### `stream.prefinalize`\n\nA [nanoguard](https://github.com/mafintosh/nanoguard) instance that is used to guard the final closing of the stream.\nInternally this guard is ready'ed before the stream checks if all channels have been closed and the stream is finalised.\nCall wait/continue on this guard if need asynchrously add more channels and don't want to stream to finalise underneath you.\n\n#### `stream.remotePublicKey`\n\nThe remotes public key.\n\n#### `stream.publicKey`\n\nYour public key.\n\n#### `stream.remoteAddress`\n\nThe remote peers IP if piped over a TCP or UTP stream.\n\n#### `stream.remoteType`\n\nThe remote peers connection type. Either 'tcp', 'utp', or 'unknown'.\n\n#### `const bool = stream.remoteVerified(key)`\n\nReturns true if the remote sent a valid capability for the key when they opened the channel.\nUse this in `ondiscoverykey` to check that the remote has the key corresponding to the discovery key.\n\n#### `const bool = Protocol.isProtocolStream(stream)`\n\nStatic method to check if an object is a hypercore protocol stream.\n\n#### `const keyPair = Protocol.keyPair([seed])`\n\nStatic method to generate an static authentication key pair.\n\n#### `const channel = stream.open(key, handlers)`\n\nSignal the other end that you want to share a hypercore feed.\n\nThe feed key will be hashed and sent as the \"discovery key\" which protects the feed key from being learned by a remote peer who does not already possess it. Also includes a cryptographic proof that the local possesses the feed key, which can be implicitly verified using the above `remoteVerified` api.\n\n[See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L7)\n\nThe `handlers` is an object of functions for handling incoming messages and is described below.\n\n#### `stream.close(discoveryKey)`\n\nYou can call this method to signal to the other side that you do not have the key\ncorresponding to the discoveryKey. Normally you would use this together with the `ondiscoverykey` hook.\n\n#### `stream.destroy([error])`\n\nDestroy the stream. Closes all feeds as well.\n\n#### `stream.finalize()`\n\nGracefully end the stream. Closes all feeds as well.\nThis is automatically called after the prefinalise guard and all channels have been closed.\n\n#### `channel.options(message)`\n\nSend an `options` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L13)\n\n#### `channel.handlers.onoptions(message)`\n\nCalled when a options message has been received.\n\n#### `channel.status(message)`\n\nSend an `status` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L20)\n\n#### `channel.handlers.onstatus(message)`\n\nCalled when a status message has been received.\n\n#### `channel.have(message)`\n\nSend a `have` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L26)\n\n#### `channel.handlers.onhave(message)`\n\nCalled when a `have` message has been received.\n\n#### `channel.unhave(message)`\n\nSend a `unhave` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L34)\n\n\n#### `channel.handlers.onunhave(message)`\n\nCalled when a `unhave` message has been received.\n\n#### `channel.want(want)`\n\nSend a `want` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L40)\n\n#### `channel.handlers.onwant(want)`\n\nCalled when a `want` message has been received.\n\n#### `channel.unwant(unwant)`\n\nSend a `unwant` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L46)\n\n#### `channel.handlers.onunwant(unwant)`\n\nCalled when a `unwant` message has been received.\n\n#### `channel.request(request)`\n\nSend a `request` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L52)\n\n\n#### `channel.handlers.onrequest(request)`\n\nCalled when a `request` message has been received.\n\n#### `channel.cancel(cancel)`\n\nSend a `cancel` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L60)\n\n#### `channel.handlers.oncancel(cancel)`\n\nCalled when a `cancel` message has been received.\n\n#### `channel.data(data)`\n\nSend a `data` message. [See the protobuf schema for more info on this messsage](https://github.com/mafintosh/simple-hypercore-protocol/blob/master/schema.proto#L67)\n\n#### `channel.handlers.ondata(data)`\n\nCalled when a `data` message has been received.\n\n#### `channel.extension(id, buffer)`\n\nSend an `extension` message. `id` should be the index an extension name in the `extensions` list sent in a previous `options` message for this channel.\n\n#### `channel.handlers.onextension(id, buffer)`\n\nCalled when an `extension` message has been received. `id` is the index of an extension name received in an extension list in a previous `options` message for this channel.\n\n#### `channel.close()`\n\nClose this channel. You only need to call this if you are sharing a lot of feeds and want to garbage collect some old unused ones.\n\n#### `channel.handlers.onclose()`\n\nCalled when this feed has been closed. All feeds are automatically closed when the stream ends or is destroyed.\n\n#### `channel.destroy(err)`\n\nAn alias to `stream.destroy`.\n\n## Stream message extensions\n\nYou can also send custom messages over the stream unrelated to any channel or hypercore feed.\nYou usually don't need this but can be useful if you are bootstrapping a specific protocol on top.\n\n#### `const ext = stream.registerExtension(name, handlers)`\n\nRegister a new stream extension named `name`.\n\n* `handlers.onmessage(message)` is called when an unchanneled extension message is received for this extension.\n* `handlers.onerror(error)` in case there was an encoding error.\n* `handlers.encoding` can be set to `json`, `utf-8`, `binary` or any abstract encoding to automatically decode/encode messages.\n\n#### `ext.send(message)`\n\nSend an extension message.\n\n#### `ext.destroy()`\n\nDestroy this extension. Unregisters it from the stream as well.\n\n## Wire protocol\n\nThe hypercore protocol consists of two phases.\nA handshake phase and a message exchange phage.\n\nFor the handshake Noise is used with the XX pattern. Each Noise message is sent with varint framing.\nAfter the handshake a message exchange phased is started.\n\nThis uses a basic varint length prefixed format to send messages over the wire.\n\nAll messages contains a header indicating the type and feed id, and a protobuf encoded payload.\n\n```\nmessage = header + payload\n```\n\nA header is a varint that looks like this\n\n```\nheader = numeric-feed-id \u003c\u003c 4 | numeric-type\n```\n\nThe feed id is just an incrementing number for every feed shared and the type corresponds to which protobuf schema should be used to decode the payload.\n\nThe message is then wrapped in another varint containing the length of the message\n\n```\nwire = length(message) + message + length(message2) + message2 + ...\n```\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypercore-protocol%2Fhypercore-protocol","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhypercore-protocol%2Fhypercore-protocol","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypercore-protocol%2Fhypercore-protocol/lists"}