Security News
PyPI Introduces Digital Attestations to Strengthen Python Package Security
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
NDK is a nostr development kit that makes the experience of building Nostr-related applications, whether they are relays, clients, or anything in between, better, more reliable and overall nicer to work with than existing solutions.
npm add @nostr-dev-kit/ndk
NDK uses the debug
package to assist in understanding what's happening behind the hood. If you are building a package
that runs on the server define the DEBUG
envionment variable like
export DEBUG='ndk:*'
or in the browser enable it by writing in the DevTools console
localStorage.debug = 'ndk:*'
t
tag usageYou can pass an object with several options to a newly created instance of NDK.
explicitRelayUrls
– an array of relay URLs.signer
- an instance of a signer.cacheAdapter
- an instance of a Cache Adapterdebug
- boolean true/false to turn on degbugging// Import the package
import NDK from "@nostr-dev-kit/ndk";
// Create a new NDK instance with explicit relays
ndk = new NDK({ explicitRelayUrls: ["wss://a.relay", "wss://another.relay"] });
Note: In normal client use, it's best practice to instantiate NDK as a singleton class. See more below.
After you've instatiated NDK, you need to tell it to connect before you'll be able to interact with any relays.
// Import the package
import NDK from "@nostr-dev-kit/ndk";
// Create a new NDK instance with explicit relays
ndk = new NDK({ explicitRelayUrls: ["wss://a.relay", "wss://another.relay"] });
// Now connect to specified relays
await ndk.connect();
NDK uses signers optionally passed in to sign events. Note that it is possible to use NDK without signing events (e.g. to get someone's profile).
Signing adapters can be passed in when NDK is instantiated or later during runtime.
Instatiate NDK with a NIP-07 signer
// Import the package, NIP-07 signer and NDK event
import NDK, { NDKNip07Signer, NDKEvent } from "@nostr-dev-kit/ndk";
const nip07signer = new NDKNip07Signer();
const ndk = new NDK({ signer: nip07signer });
NDK can now ask for permission, via their NIP-07 extension, to...
Read the user's public key
nip07signer.user().then(async (user) => {
if (!!user.npub) {
console.log("Permission granted to read their public key:", user.npub);
}
});
Sign & publish events
const ndkEvent = new NDKEvent(ndk);
ndkEvent.kind = 1;
ndkEvent.content = "Hello, world!";
ndkEvent.publish(); // This will trigger the extension to ask the user to confirm signing.
NDK provides database-agnostic caching functionality out-of-the-box to improve the performance of your application and reduce load on relays.
NDK will eventually allow you to use multiple caches simultaneously and allow for selective storage of data in the cache store that makes the most sense for your application.
The most important data to cache is where a user or note might be found. UX suffers profoundly when this type of data cannot be found. By design, the Nostr protocol leaves breadcrumbs of where a user or note might be found and NDK does it's best to store this data automatically and use it when you query for events.
const redisAdapter = new RedisAdapter(redisUrl);
const ndk = new NDK({ cacheAdapter: redisAdapter });
Clients often need to load data (e.g. profile data) from individual components at once (e.g. initial page render). This typically causes multiple subscriptions to be submitted fetching the same information and causing poor performance or getting rate-limited/maxed out by relays.
NDK implements a convenient subscription model, buffered queries, where a named subscription will be created after a customizable amount of time, so that multiple components can append queries.
// Component 1
ndk.subscribe({ kinds: [0], authors: ["pubkey-1"] });
// Component 2
ndk.subscribe({ kinds: [0], authors: ["pubkey-2"] });
In this example, NDK will wait 100ms (default groupableDelay
) before creating a subscription with the filter:
{kinds: [0], authors: ['pubkey-1', 'pubkey-2'] }
When a client submits a request through NDK, NDK will calculate which relays are most likely able to satisfy this request.
Queries submitted by the client might be broken into different queries if NDK computes different relays.
For example, say npub-A follows npub-B and npub-C. If the NDK client uses:
const ndk = new NDK({ explicitRelays: ["wss://nos.lol"] });
const npubA = ndk.getUser("npub-A");
const feedEvents = await npubA.feed();
This would result in the following request:
{ "kinds": [1], "authors": ["npub-B", "npub-C"] }
But if NDK has observed that npub-B
tends to write to wss://userb.xyz
and
npub-C
tends to write to wss://userc.io
, NDK will instead send the following queries.
// to npub-A's explicit relay wss://nos.lol *if* npub-B and npub-C have been seen on that relay
{ "kinds": [1], "authors": [ "npub-B", "npub-C" ] }
// to wss://userb.xyz
{ "kinds": [1], "authors": [ "npub-B" ] }
// to wss://userc.io
{ "kinds": [1], "authors": [ "npub-C" ] }
Often, clients need to fetch data but don't need to maintain an open connection to the relay. This is true of profile metadata requests especially.
NDK defaults to having the closeOnEose
flag set to true
, to make permanent subscriptions explicit in the codebase; if you want your
subscription to remain active beyond EOSE
, you should set it to false
.
closeOnEose
flag will make the connection close immediately after EOSE is seen.ndk.subscription({ kinds: [0], authors: ["..."] }, { closeOnEose: false });
NDK implements several conveience methods for common queries.
This is a handy method for instantiating a new NDKUser
and associating the current NDK instance with that user for future calls.
const pablo = ndk.getUser({
npub: "npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft"
});
const jeff = ndk.getUser({
hexpubkey: "1739d937dc8c0c7370aa27585938c119e25c41f6c441a5d34c6d38503e3136ef"
});
You can easily fetch a user's profile data from kind:0
events on relays. Calling .fetchProfile()
will update the profile
attribute on the user object instead of returning the profile directly. NDK then makes it trivial to update values and publish those updates back to relays.
const pablo = ndk.getUser({
npub: "npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft"
});
await pablo.fetchProfile();
const pabloFullProfile = pablo.profile;
pablo.profile.name = "Pablo";
await pablo.publish(); // Triggers signing via signer
You can fetch the first event or all events that match a given set of filters.
// Create a filter
const filter: NDKFilter = { kinds: [1], authors: [hexpubkey1, hexpubkey2] };
// Will return only the first event
event = await ndk.fetchEvent(filter);
// Will return all found events
events = await ndk.fetchEvents(filter);
const ndk = new NDK({ explicitRelays, signer });
const event = new NDKEvent(ndk);
event.kind = 1;
event.content = "PV Nostr! 🤙🏼";
await ndk.publish(event);
// Find the first event from @jack, and react/like it.
const event = await ndk.fetchEvent({ author: "jack@cashapp.com" })[0];
await event.react("🤙");
// Find the first event from @jack, and zap it.
const event = await ndk.fetchEvent({ author: "jack@cashapp.com" })[0];
await event.zap(1337, "Zapping your post!"); // Returns a zap request
explicitRelayUrls
specified by the user.FAQs
NDK - Nostr Development Kit
The npm package habla-ndk receives a total of 0 weekly downloads. As such, habla-ndk popularity was classified as not popular.
We found that habla-ndk demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.