Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cmdruid/use-nostr
A turn-key library for using Nostr with React.
https://github.com/cmdruid/use-nostr
client hooks nostr react
Last synced: 2 months ago
JSON representation
A turn-key library for using Nostr with React.
- Host: GitHub
- URL: https://github.com/cmdruid/use-nostr
- Owner: cmdruid
- Created: 2023-05-15T21:27:15.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2023-06-12T17:37:21.000Z (over 1 year ago)
- Last Synced: 2024-11-02T12:07:50.090Z (2 months ago)
- Topics: client, hooks, nostr, react
- Language: TypeScript
- Homepage: https://www.npmjs.com/@cmdcode/use-nostr
- Size: 175 KB
- Stars: 19
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# useNostr
This project is designed to be a turn-key library for using Nostr with React.
- Login with pubkey, npub, seckey, nsec, extension, or generate a new key.
- Nostr client API with `get`, `list`, `sub`, and `publish`.
- Configure a list of relays for your client to use.
- Uses a simple reducer `store` with `update` method.
- Helper boolean, status and error messages for reactive components.**NEW**: Nostr rooms now available! Easily create group messaging using a shared secret!
Coming soon:
- Sign / verify custom messages and challenges using the Signer API.
- Receive a Taproot HD wallet derived from your nostr signing device.
- Better integration of user profile and relay list.
- Remote signing support.This project is fully typed and designed to work with intellisense.
More documentation coming soon!
## Import
To make `useNostr` available across your entire react app, wrap your root component with the included `NostrProvider` component:
```tsx
// Example entrypoint for react / nextjs.
// Your project may look slightly different.
import { NostrProvider } from '@cmdcode/use-nostr'export default function App ({ Component, pageProps }) {
return (
)
}
```## Basic Usage
With the `NostrProvider` configured, importing the library and store is relatively simple.
Here is a basic example of reading and updating your relay list:
```tsx
import { useState } from 'react'
import { useNostr } from '@cmdcode/use-nostr'export default function Relays () {
const { store, update } = useNostr()
const [ input, setInput ] = useState('')function handleSubmit() {
update({ relays: [ ...store.relays, input ] })
}return (
Relays
{ store.relays &&{JSON.stringify(store.relays, null, 2)}}
{ setInput(e.target.value) }} value={input} />
Add Relay
)
}
```Here is an example login flow that covers all methods of signing in:
```tsx
import { useState } from 'react'
import { useNostr } from '@cmdcode/use-nostr'export default function Login () {
const [ pubkey, setPubKey ] = useState('')
const [ seckey, setSecKey ] = useState('')const { hasExtension, login, store } = useNostr()
return (
Login Via Extention:
Login
Login with your Public Key or npub:
setPubKey(e.target.value)}>
login.withPubKey(pubkey)}>Login
Login with your Secret Key or nsec:
setSecKey(e.target.value)}>
login.withSecKey(seckey)}>Login
Generate
)
}
```## Library API
The library is split into several modules that plug into the main store.
### Store API
```ts
const { store, update, reset, setError } = useNostr()// The main data store.
store : NostrStore
// Update the data store using a JSON object.
update = (store : Partial) => void
// Resets the data store. Provide an
// optional JSON object for defaults.
reset = (store : Partial) => void
// Sets an error message in the store,
// plus print to console.
setError = (err : Error) => voidinterface NostrStore {
// Schema for the data store.
client ?: Client
connection : 'none' | 'conn' | 'ok' | 'error'
hasExtension : boolean
isConnected : boolean
isLoading : boolean
error ?: string
pubkey ?: string
profile ?: Profile
relays : string[]
signer ?: Signer
}
```### Login API
```ts
const { login, logout } = useNostr()login = {
// Login with NIP-07 extension (if available).
withExt : () => void,
// Login with npub or pubkey hex (read only).
withPubKey : (string) => void,
// Login with nsec or seckey hex.
withSecKey : (string) => void,
// Generate a new (ephemeral) keypair.
generateKey : () => void
}// Removes all user data from the store.
logout = () => void
```### Client API
```ts
const { client } = useNostr()client = {
// Checks pool connection and returns a boolean result.
connected : () => Promise,
// Publish an event from a partial JSON template.
publish : (event : Partial) => Promise,
// Fetch the top event using the provided filter.
get : (filter : Filter) => Promise,
// Fetch a list of events using the provided filters.
list : (filters : Filter[]) => Promise,
// Publish a signed event and receive a Pub emitter.
pub : (event : Event) => Promise,
// Subscribe to a list of filters and receive a Sub emitter.
sub : (filters : Filter[]) => Promise
}
```### Profile API
```ts
const { getProfile, setProfile } = useNostr()// Fetch your profile from the relays.
getProfile = () => Promise
// Update your profile using a partial JSON template.
setprofile = (updates : Partial) => Promise
```### Room API
Rooms are a way to pass messages in real-time between a group of users. You can create or join a room using a secret string that is shared by all parties. All messages within the room are encrypted and covertly tagged using the shared secret.
A room object works like a typical event emitter. You can broadcast a custom event to the room using `pub`, and listen for custom events using `on`, `once` or `within`. You can also emit events only to yourself using `emit`. Any callback methods registered to an event will receive a payload of data from the publisher, plus the event envelope it was wrapped in.
```ts
const { joinRoom } = useNostr()// Multiple parties can join a single room using a secret string.
const room = joinRoom('secretstring')// You can publish any type of payload to any custom named event.
room.pub('customevent', { hello: 'world!' })// You can attach a callback method to any custom event.
room.on('customevent', (payload, envelope) => {
console.log(payload) // { hello: 'world!' }
// The envelope is the event object itself.
console.log(envelope)
/* {
* "kind": 21111,
* "tags": [
* [ "h", "11ed64797736fdb7577bc10987e8b0a82210a93e90d39a217306e714504e97a4" ],
* [ "expiration", "1772782615" ]
* ],
* "content": "6JArpHDMApqEY7dDuf_mo-KZHfMbZrZ6o6qJnXqxRuc8QzAWRz4zJ4kjzwCzM3Utf-_WeRJ-E59TCr3esj65gw?iv=MJjiOgQ7cGjAT5k6wWpHfg",
* "created_at": 1686382615
* }
*/class NostrRoom {
cache : Array // A rolling cache of past events.
config : RoomConfig // Configuration for the room.
events : Callbacks // List of callbacks registered for each event label.
connected : boolean // Returns true once the room has an active subscription.
members : string[] // A list of pubkeys that represent active participants.
roomId : Buff // The identifer used to tag each event (for filtering).
sharedKey : Buff // The shared key used for encryption (computed from secret).// Emit an event only to yourself. Useful for internal logic.
emit (eventName: string, ...args: any[]) => void
// Broadcast an event to everyone in the room.
pub (
eventName : string,
payload : Json,
template ?: Partial
) => Promise
// Register a callback method for a particular event.
on (eventName : string, fn : Function) => void
// Register a callback that only executes once.
once (eventName : string, fn : Function) => void
// Register a callback that only exists for a limited time.
within (eventName : string, fn : Function, timeout: number) => void
// Remove a specific callback from the event list.
remove (eventName : string, fn : Function) => void
// Remove all callbacks registered to a specific event label.
prune(eventName: string) => void
// Unsubscribe the room from the relay pool.
leave() => void
}type EventRecord = [ eventName: string, payload: any, envelope: Event ]
type Callbacks = Record>interface RoomConfig {
cacheSize : number // Sets the number of past events to store in cache.
allowEcho : boolean // Toggles receipt of events that you published yourself.
encryption : boolean // Toggles encryption for event content.
expiration : number // Events are set to expire after the time period.
filter : Filter // Customize the filter used to subscribe to room events.
inactiveLimit ?: number // Users in the room are marked inactive after the time period.
kind : number // Set which kind number to use for each event envelope.
tags : string[][] // Set custom tags to be added to each event envelope.
}
```### Signer API
Coming soon!
## Development / Testing
This library uses `yarn` for package management and `vite` for a development / demo server.
```bash
## Start the vite development server:
yarn dev
## Build a new release of the package:
yarn release
```## Bugs / Issues
If you run into any bugs or have any questions, please submit an issue ticket.
## Contribution
Feel free to fork and make contributions. Suggestions are welcome!
## Dependencies
This library contains minimal dependencies.
**React**
React library for hooks and JSX.
https://github.com/facebook/react**nostr-tools**
Nostr utility library for all nostr stuff.
https://github.com/nbd-wtf/nostr-tools## Resources
**Nostr Implementation Possibilities**
This site is an index of current and draft NIPs.
https://nips.be## License
Use this library however you want!
## Contact
You can find me on nostr at: `npub1gg5uy8cpqx4u8wj9yvlpwm5ht757vudmrzn8y27lwunt5f2ytlusklulq3`