{"_id":"@asoltys/nostr-tools","name":"@asoltys/nostr-tools","dist-tags":{"latest":"2.1.7"},"versions":{"2.1.7":{"type":"module","name":"@asoltys/nostr-tools","version":"2.1.7","description":"Tools for making a Nostr client.","repository":{"type":"git","url":"git+https://github.com/nbd-wtf/nostr-tools.git"},"sideEffects":false,"module":"./lib/esm/index.js","main":"./lib/cjs/index.js","types":"./lib/types/index.d.ts","exports":{".":{"import":"./lib/esm/index.js","require":"./lib/cjs/index.js","types":"./lib/types/index.d.ts"},"./pure":{"import":"./lib/esm/pure.js","require":"./lib/cjs/pure.js","types":"./lib/types/pure.d.ts"},"./wasm":{"import":"./lib/esm/wasm.js","require":"./lib/cjs/wasm.js","types":"./lib/types/wasm.d.ts"},"./kinds":{"import":"./lib/esm/kinds.js","require":"./lib/cjs/kinds.js","types":"./lib/types/kinds.d.ts"},"./filter":{"import":"./lib/esm/filter.js","require":"./lib/cjs/filter.js","types":"./lib/types/filter.d.ts"},"./abstract-relay":{"import":"./lib/esm/abstract-relay.js","require":"./lib/cjs/abstract-relay.js","types":"./lib/types/abstract-relay.d.ts"},"./relay":{"import":"./lib/esm/relay.js","require":"./lib/cjs/relay.js","types":"./lib/types/relay.d.ts"},"./abstract-pool":{"import":"./lib/esm/abstract-pool.js","require":"./lib/cjs/abstract-pool.js","types":"./lib/types/abstract-pool.d.ts"},"./pool":{"import":"./lib/esm/pool.js","require":"./lib/cjs/pool.js","types":"./lib/types/pool.d.ts"},"./references":{"import":"./lib/esm/references.js","require":"./lib/cjs/references.js","types":"./lib/types/references.d.ts"},"./nip04":{"import":"./lib/esm/nip04.js","require":"./lib/cjs/nip04.js","types":"./lib/types/nip04.d.ts"},"./nip05":{"import":"./lib/esm/nip05.js","require":"./lib/cjs/nip05.js","types":"./lib/types/nip05.d.ts"},"./nip06":{"import":"./lib/esm/nip06.js","require":"./lib/cjs/nip06.js","types":"./lib/types/nip06.d.ts"},"./nip10":{"import":"./lib/esm/nip10.js","require":"./lib/cjs/nip10.js","types":"./lib/types/nip10.d.ts"},"./nip11":{"import":"./lib/esm/nip11.js","require":"./lib/cjs/nip11.js","types":"./lib/types/nip11.d.ts"},"./nip13":{"import":"./lib/esm/nip13.js","require":"./lib/cjs/nip13.js","types":"./lib/types/nip13.d.ts"},"./nip18":{"import":"./lib/esm/nip18.js","require":"./lib/cjs/nip18.js","types":"./lib/types/nip18.d.ts"},"./nip19":{"import":"./lib/esm/nip19.js","require":"./lib/cjs/nip19.js","types":"./lib/types/nip19.d.ts"},"./nip21":{"import":"./lib/esm/nip21.js","require":"./lib/cjs/nip21.js","types":"./lib/types/nip21.d.ts"},"./nip25":{"import":"./lib/esm/nip25.js","require":"./lib/cjs/nip25.js","types":"./lib/types/nip25.d.ts"},"./nip27":{"import":"./lib/esm/nip27.js","require":"./lib/cjs/nip27.js","types":"./lib/types/nip27.d.ts"},"./nip28":{"import":"./lib/esm/nip28.js","require":"./lib/cjs/nip28.js","types":"./lib/types/nip28.d.ts"},"./nip29":{"import":"./lib/esm/nip29.js","require":"./lib/cjs/nip29.js","types":"./lib/types/nip29.d.ts"},"./nip30":{"import":"./lib/esm/nip30.js","require":"./lib/cjs/nip30.js","types":"./lib/types/nip30.d.ts"},"./nip39":{"import":"./lib/esm/nip39.js","require":"./lib/cjs/nip39.js","types":"./lib/types/nip39.d.ts"},"./nip42":{"import":"./lib/esm/nip42.js","require":"./lib/cjs/nip42.js","types":"./lib/types/nip42.d.ts"},"./nip44":{"import":"./lib/esm/nip44.js","require":"./lib/cjs/nip44.js","types":"./lib/types/nip44.d.ts"},"./nip49":{"import":"./lib/esm/nip49.js","require":"./lib/cjs/nip49.js","types":"./lib/types/nip49.d.ts"},"./nip57":{"import":"./lib/esm/nip57.js","require":"./lib/cjs/nip57.js","types":"./lib/types/nip57.d.ts"},"./nip94":{"import":"./lib/esm/nip94.js","require":"./lib/cjs/nip94.js","types":"./lib/types/nip94.d.ts"},"./nip96":{"import":"./lib/esm/nip96.js","require":"./lib/cjs/nip96.js","types":"./lib/types/nip96.d.ts"},"./nip98":{"import":"./lib/esm/nip98.js","require":"./lib/cjs/nip98.js","types":"./lib/types/nip98.d.ts"},"./nip99":{"import":"./lib/esm/nip99.js","require":"./lib/cjs/nip99.js","types":"./lib/types/nip99.d.ts"},"./fakejson":{"import":"./lib/esm/fakejson.js","require":"./lib/cjs/fakejson.js","types":"./lib/types/fakejson.d.ts"},"./utils":{"import":"./lib/esm/utils.js","require":"./lib/cjs/utils.js","types":"./lib/types/utils.d.ts"}},"license":"Unlicense","dependencies":{"@noble/ciphers":"0.2.0","@noble/curves":"1.2.0","@noble/hashes":"1.3.1","@scure/base":"1.1.1","@scure/bip32":"1.3.1","@scure/bip39":"1.2.1"},"optionalDependencies":{"nostr-wasm":"v0.1.0"},"peerDependencies":{"typescript":">=5.0.0"},"peerDependenciesMeta":{"typescript":{"optional":true}},"keywords":["decentralization","social","censorship-resistance","client","nostr"],"devDependencies":{"@types/node":"^18.13.0","@types/node-fetch":"^2.6.3","@typescript-eslint/eslint-plugin":"^6.5.0","@typescript-eslint/parser":"^6.5.0","bun-types":"^1.0.18","esbuild":"0.16.9","esbuild-plugin-alias":"^0.2.1","eslint":"^8.56.0","eslint-config-prettier":"^9.0.0","eslint-plugin-babel":"^5.3.1","esm-loader-typescript":"^1.0.3","events":"^3.3.0","mitata":"^0.1.6","mock-socket":"^9.3.1","msw":"^2.1.4","node-fetch":"^2.6.9","prettier":"^3.0.3","typescript":"^5.0.4"},"scripts":{"prepublish":"just build"},"_id":"@asoltys/nostr-tools@2.1.7","gitHead":"98039102eb9a214f0409935ef09160e327fd0c12","bugs":{"url":"https://github.com/nbd-wtf/nostr-tools/issues"},"homepage":"https://github.com/nbd-wtf/nostr-tools#readme","_nodeVersion":"18.19.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-GKhf2+9gfclvU2geFgUXduoHeZTtjd2Pd5HioIZbjyel3lr0GY5IH5AzAPgStxVkwPgLcn+A9H+PWIPXJPfDbQ==","shasum":"174d5f5d894ec08dec3019e7a3e9d6cd0e847a4b","tarball":"https://registry.npmjs.org/@asoltys/nostr-tools/-/nostr-tools-2.1.7.tgz","fileCount":227,"unpackedSize":2451608,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDgPi6T8qfjI20vBAJomt7gJgQMvTJzeb3xYmk860wFrgIhAKqLC52xMV+RP6lp2OFGBx1xY8wu3zCZ/BVyg8aUHmjC"}]},"_npmUser":{"name":"asoltys","email":"asoltys@gmail.com"},"directories":{},"maintainers":[{"name":"asoltys","email":"asoltys@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/nostr-tools_2.1.7_1707333764975_0.010704298145004953"},"_hasShrinkwrap":false}},"time":{"created":"2024-02-07T19:22:44.876Z","2.1.7":"2024-02-07T19:22:45.212Z","modified":"2024-02-07T19:22:45.491Z"},"maintainers":[{"name":"asoltys","email":"asoltys@gmail.com"}],"description":"Tools for making a Nostr client.","homepage":"https://github.com/nbd-wtf/nostr-tools#readme","keywords":["decentralization","social","censorship-resistance","client","nostr"],"repository":{"type":"git","url":"git+https://github.com/nbd-wtf/nostr-tools.git"},"bugs":{"url":"https://github.com/nbd-wtf/nostr-tools/issues"},"license":"Unlicense","readme":"# ![](https://img.shields.io/github/actions/workflow/status/nbd-wtf/nostr-tools/test.yml) nostr-tools\n\nTools for developing [Nostr](https://github.com/fiatjaf/nostr) clients.\n\nOnly depends on _@scure_ and _@noble_ packages.\n\nThis package is only providing lower-level functionality. If you want an easy-to-use fully-fledged solution that abstracts the hard parts of Nostr and makes decisions on your behalf, take a look at [NDK](https://github.com/nostr-dev-kit/ndk) and [@snort/system](https://www.npmjs.com/package/@snort/system).\n\n## Installation\n\n```bash\n npm install nostr-tools # or yarn add nostr-tools\n```\n\nIf using TypeScript, this package requires TypeScript >= 5.0.\n\n## Usage\n\n### Generating a private key and a public key\n\n```js\nimport { generateSecretKey, getPublicKey } from 'nostr-tools'\n\nlet sk = generateSecretKey() // `sk` is a Uint8Array\nlet pk = getPublicKey(sk) // `pk` is a hex string\n```\n\n### Creating, signing and verifying events\n\n```js\nimport { finalizeEvent, verifyEvent } from 'nostr-tools'\n\nlet event = finalizeEvent({\n  kind: 1,\n  created_at: Math.floor(Date.now() / 1000),\n  tags: [],\n  content: 'hello',\n}, sk)\n\nlet isGood = verifyEvent(event)\n```\n\n### Interacting with a relay\n\n```js\nimport { Relay, finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools'\n\nconst relay = await Relay.connect('wss://relay.example.com')\nconsole.log(`connected to ${relay.url}`)\n\n// let's query for an event that exists\nconst sub = relay.subscribe([\n  {\n    ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'],\n  },\n], {\n  onevent(event) {\n    console.log('we got the event we wanted:', event)\n  },\n  oneose() {\n    sub.close()\n  }\n})\n\n// let's publish a new event while simultaneously monitoring the relay for it\nlet sk = generateSecretKey()\nlet pk = getPublicKey(sk)\n\nrelay.sub([\n  {\n    kinds: [1],\n    authors: [pk],\n  },\n], {\n  onevent(event) {\n    console.log('got event:', event)\n  }\n})\n\nlet eventTemplate = {\n  kind: 1,\n  created_at: Math.floor(Date.now() / 1000),\n  tags: [],\n  content: 'hello world',\n}\n\n// this assigns the pubkey, calculates the event id and signs the event in a single step\nconst signedEvent = finalizeEvent(eventTemplate, sk)\nawait relay.publish(signedEvent)\n\nrelay.close()\n```\n\nTo use this on Node.js you first must install `websocket-polyfill` and import it:\n\n```js\nimport 'websocket-polyfill'\n```\n\n### Interacting with multiple relays\n\n```js\nimport { SimplePool } from 'nostr-tools'\n\nconst pool = new SimplePool()\n\nlet relays = ['wss://relay.example.com', 'wss://relay.example2.com']\n\nlet h = pool.subscribeMany(\n  [...relays, 'wss://relay.example3.com'],\n  [\n    {\n      authors: ['32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'],\n    },\n  ],\n  {\n    onevent(event) {\n      // this will only be called once the first time the event is received\n      // ...\n    },\n    oneose() {\n      h.close()\n    }\n  }\n)\n\nawait Promise.any(pool.publish(relays, newEvent))\nconsole.log('published to at least one relay!')\n\nlet events = await pool.querySync(relays, [{ kinds: [0, 1] }])\nlet event = await pool.get(relays, {\n  ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'],\n})\n```\n\n### Parsing references (mentions) from a content using NIP-10 and NIP-27\n\n```js\nimport { parseReferences } from 'nostr-tools'\n\nlet references = parseReferences(event)\nlet simpleAugmentedContent = event.content\nfor (let i = 0; i < references.length; i++) {\n  let { text, profile, event, address } = references[i]\n  let augmentedReference = profile\n    ? `<strong>@${profilesCache[profile.pubkey].name}</strong>`\n    : event\n    ? `<em>${eventsCache[event.id].content.slice(0, 5)}</em>`\n    : address\n    ? `<a href=\"${text}\">[link]</a>`\n    : text\n  simpleAugmentedContent.replaceAll(text, augmentedReference)\n}\n```\n\n### Querying profile data from a NIP-05 address\n\n```js\nimport { nip05 } from 'nostr-tools'\n\nlet profile = await nip05.queryProfile('jb55.com')\nconsole.log(profile.pubkey)\n// prints: 32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\nconsole.log(profile.relays)\n// prints: [wss://relay.damus.io]\n```\n\nTo use this on Node.js < v18, you first must install `node-fetch@2` and call something like this:\n\n```js\nnip05.useFetchImplementation(require('node-fetch'))\n```\n\n### Encoding and decoding NIP-19 codes\n\n```js\nimport { nip19, generateSecretKey, getPublicKey } from 'nostr-tools'\n\nlet sk = generateSecretKey()\nlet nsec = nip19.nsecEncode(sk)\nlet { type, data } = nip19.decode(nsec)\nassert(type === 'nsec')\nassert(data === sk)\n\nlet pk = getPublicKey(generateSecretKey())\nlet npub = nip19.npubEncode(pk)\nlet { type, data } = nip19.decode(npub)\nassert(type === 'npub')\nassert(data === pk)\n\nlet pk = getPublicKey(generateSecretKey())\nlet relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']\nlet nprofile = nip19.nprofileEncode({ pubkey: pk, relays })\nlet { type, data } = nip19.decode(nprofile)\nassert(type === 'nprofile')\nassert(data.pubkey === pk)\nassert(data.relays.length === 2)\n```\n\n## Import modes\n\n### Using just the packages you want\n\nImporting the entirety of `nostr-tools` may bloat your build, so you should probably import individual packages instead:\n\n```js\nimport { generateSecretKey, finalizeEvent, verifyEvent } from 'nostr-tools/pure'\nimport { SimplePool } from 'nostr-tools/pool'\nimport { Relay, Subscription } from 'nostr-tools/relay'\nimport { matchFilter } from 'nostr-tools/filter'\nimport { decode, nprofileEncode, neventEncode, npubEncode } from 'nostr-tools/nip19'\n// and so on and so forth\n```\n\n### Using it with `nostr-wasm`\n\n[`nostr-wasm`](https://github.com/fiatjaf/nostr-wasm) is a thin wrapper over [libsecp256k1](https://github.com/bitcoin-core/secp256k1) compiled to WASM just for hashing, signing and verifying Nostr events.\n\n```js\nimport { setNostrWasm, generateSecretKey, finalizeEvent, verifyEvent } from 'nostr-tools/wasm'\nimport { initNostrWasm } from 'nostr-wasm'\n\n// make sure this promise resolves before your app starts calling finalizeEvent or verifyEvent\ninitNostrWasm().then(setNostrWasm)\n\n// or use 'nostr-wasm/gzipped' or even 'nostr-wasm/headless',\n// see https://www.npmjs.com/package/nostr-wasm for options\n```\n\nIf you're going to use `Relay` and `SimplePool` you must also import `nostr-tools/abstract-relay` and/or `nostr-tools/abstract-pool` instead of the defaults and then instantiate them by passing the `verifyEvent`:\n\n```js\nimport { setNostrWasm, verifyEvent } from 'nostr-tools/wasm'\nimport { AbstractRelay } from 'nostr-tools/abstract-relay'\nimport { AbstractSimplePool } from 'nostr-tools/abstract-pool'\nimport { initNostrWasm } from 'nostr-wasm'\n\ninitNostrWasm().then(setNostrWasm)\n\nconst relay = AbstractRelay.connect('wss://relayable.org', { verifyEvent })\nconst pool = new AbstractSimplePool({ verifyEvent })\n```\n\nThis may be faster than the pure-JS [noble libraries](https://paulmillr.com/noble/) used by default and in `nostr-tools/pure`. Benchmarks:\n\n```\nbenchmark      time (avg)             (min … max)       p75       p99      p995\n------------------------------------------------- -----------------------------\n• relay read message and verify event (many events)\n------------------------------------------------- -----------------------------\nwasm        34.94 ms/iter   (34.61 ms … 35.73 ms)  35.07 ms  35.73 ms  35.73 ms\npure js     239.7 ms/iter (235.41 ms … 243.69 ms) 240.51 ms 243.69 ms 243.69 ms\ntrusted    402.71 µs/iter   (344.57 µs … 2.98 ms) 407.39 µs 745.62 µs 812.59 µs\n\nsummary for relay read message and verify event\n  wasm\n   86.77x slower than trusted\n   6.86x faster than pure js\n```\n\n### Using from the browser (if you don't want to use a bundler)\n\n```html\n<script src=\"https://unpkg.com/nostr-tools/lib/nostr.bundle.js\"></script>\n<script>\n  window.NostrTools.generateSecretKey('...') // and so on\n</script>\n```\n\n## Plumbing\n\nTo develop `nostr-tools`, install [`just`](https://just.systems/) and run `just -l` to see commands available.\n\n## License\n\nThis is free and unencumbered software released into the public domain. By submitting patches to this project, you agree to dedicate any and all copyright interest in this software to the public domain.\n\n## Contributing to this repository\n\nUse NIP-34 to send your patches to `naddr1qq9kummnw3ez6ar0dak8xqg5waehxw309aex2mrp0yhxummnw3ezucn8qyt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueqpzemhxue69uhhyetvv9ujuurjd9kkzmpwdejhgq3q80cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsxpqqqpmejdv00jq`.\n","readmeFilename":"README.md"}