164 lines
3.0 KiB
Markdown
164 lines
3.0 KiB
Markdown
|
|
## Purpose
|
|
|
|
This guide explains how to create and publish "Days Since / Until" counter events on Nostr using NDK (Nostr Development Kit).
|
|
|
|
Counters are stored as `kind: 30078` events with metadata tags for rendering.
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
* NDK installed
|
|
* Signer available (via NIP-07, NIP-46, or npub/nsec input)
|
|
* Relay pool configured and connected
|
|
|
|
---
|
|
|
|
## Example Setup
|
|
|
|
```ts
|
|
import NDK, { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
|
|
|
const ndk = new NDK({
|
|
explicitRelayUrls: [
|
|
"wss://relay.azzamo.net",
|
|
"wss://relay.damus.io"
|
|
]
|
|
});
|
|
await ndk.connect();
|
|
|
|
// Login with nsec
|
|
const signer = new NDKPrivateKeySigner("nsec1...");
|
|
ndk.signer = signer;
|
|
await ndk.signer.user();
|
|
```
|
|
|
|
You can also support login via npub (read-only) or NIP-07 browser extension.
|
|
|
|
---
|
|
|
|
## Create Counter Function
|
|
|
|
```ts
|
|
async function publishCounter({
|
|
title,
|
|
date,
|
|
type = "since", // or "until"
|
|
visibility = "public", // or "private"
|
|
}: {
|
|
title: string;
|
|
date: string; // format YYYY-MM-DD
|
|
type?: "since" | "until";
|
|
visibility?: "public" | "private";
|
|
}) {
|
|
const event = new NDKEvent(ndk);
|
|
event.kind = 30078;
|
|
event.tags = [
|
|
["type", type],
|
|
["title", title],
|
|
["date", date],
|
|
["visibility", visibility],
|
|
];
|
|
event.content = "";
|
|
|
|
await event.sign();
|
|
await event.publish();
|
|
return event;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Public Counter Example
|
|
|
|
```ts
|
|
const ev = await publishCounter({
|
|
title: "Quit smoking",
|
|
date: "2024-12-01",
|
|
type: "since",
|
|
visibility: "public",
|
|
});
|
|
console.log("View at /counter/" + ev.id);
|
|
```
|
|
|
|
### Published JSON Output:
|
|
|
|
```json
|
|
{
|
|
"kind": 30078,
|
|
"content": "",
|
|
"tags": [
|
|
["type", "since"],
|
|
["title", "Quit smoking"],
|
|
["date", "2024-12-01"],
|
|
["visibility", "public"]
|
|
],
|
|
"created_at": 1725000000,
|
|
"id": "note1...",
|
|
"pubkey": "npub1..."
|
|
}
|
|
```
|
|
|
|
### Slug / Permalink
|
|
|
|
Use the full event ID as the URL slug:
|
|
|
|
```
|
|
/counter/note1xyz... ← based on event.id (NIP-19 encoded)
|
|
```
|
|
|
|
---
|
|
|
|
## Private Counter Example
|
|
|
|
```ts
|
|
await publishCounter({
|
|
title: "Last relapse",
|
|
date: "2025-07-01",
|
|
type: "since",
|
|
visibility: "private",
|
|
});
|
|
```
|
|
|
|
> Note: Private counters are still published to relays but can be filtered out in the app logic.
|
|
|
|
---
|
|
|
|
## Reading Events
|
|
|
|
To fetch all public counters:
|
|
|
|
```ts
|
|
const events = await ndk.fetchEvents({
|
|
kinds: [30078]
|
|
});
|
|
|
|
const publicEvents = Array.from(events).filter(e =>
|
|
e.tags.find(([k, v]) => k === "visibility" && v === "public")
|
|
);
|
|
```
|
|
|
|
To fetch your own counters:
|
|
|
|
```ts
|
|
const user = await ndk.signer?.user();
|
|
const events = await ndk.fetchEvents({
|
|
kinds: [30078],
|
|
authors: [user?.pubkey || ""]
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
* The URL slug for counters is the **event ID** (NIP-19 encoded if needed)
|
|
* Event `id` is used to lookup and display the counter
|
|
* Lightning zaps should be handled via metadata (fetch kind:0 or NIP-05 info)
|
|
* Updating a counter means publishing a new event with new content
|
|
|
|
---
|
|
|
|
Let me know if you want to include zaps, NIP-75 fundraising goals, or update/delete flows.
|