diff --git a/package.json b/package.json index e86cb8d..8538a5e 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,11 @@ "clean:firefox": "rimraf dist/firefox", "start:chrome": "ng serve chrome", "start:firefox": "ng serve firefox", + "fetch-kinds": "node scripts/fetch-kinds.js", "prepare:chrome": "./chrome_prepare_manifest.sh", "prepare:firefox": "./firefox_prepare_manifest.sh", - "build:chrome": "npm run prepare:chrome && ng build chrome", - "build:firefox": "npm run prepare:firefox && ng build firefox", + "build:chrome": "npm run fetch-kinds && npm run prepare:chrome && ng build chrome", + "build:firefox": "npm run fetch-kinds && npm run prepare:firefox && ng build firefox", "watch:chrome": "npm run prepare:chrome && ng build chrome --watch --configuration development", "watch:firefox": "npm run prepare:firefox && ng build firefox --watch --configuration development", "test": "ng test", diff --git a/projects/common/src/lib/constants/event-kinds.ts b/projects/common/src/lib/constants/event-kinds.ts new file mode 100644 index 0000000..afdd087 --- /dev/null +++ b/projects/common/src/lib/constants/event-kinds.ts @@ -0,0 +1,1756 @@ +/** + * Nostr Event Kinds Database + * Auto-generated from https://git.mleku.dev/mleku/nostr/raw/branch/main/encoders/kind/kinds.json + * Version: 2025-12-21 + * Source: https://github.com/nostr-protocol/nips + * + * DO NOT EDIT - This file is auto-generated by scripts/fetch-kinds.js + */ + +export interface KindInfo { + kind: number; + name: string; + description: string; + nip: string | null; + classification: 'regular' | 'replaceable' | 'ephemeral' | 'parameterized'; + deprecated: boolean; + spec: string | null; +} + +export interface KindRanges { + regular: { start: number; end: number; description: string }; + replaceable: { start: number; end: number; description: string }; + ephemeral: { start: number; end: number; description: string }; + parameterized: { start: number; end: number; description: string }; +} + +export const EVENT_KINDS: KindInfo[] = [ + { + "kind": 0, + "name": "Metadata", + "description": "User profile information (name, about, picture, nip05, etc.)", + "nip": "01", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 1, + "name": "Short Text Note", + "description": "Short-form text post (like a tweet)", + "nip": "01", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 2, + "name": "Recommend Relay", + "description": "Relay recommendation", + "nip": "01", + "classification": "regular", + "deprecated": true, + "spec": null + }, + { + "kind": 3, + "name": "Follows", + "description": "Following list with optional relay hints", + "nip": "02", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 4, + "name": "Encrypted Direct Message", + "description": "Private message using NIP-04 encryption", + "nip": "04", + "classification": "regular", + "deprecated": true, + "spec": null + }, + { + "kind": 5, + "name": "Event Deletion Request", + "description": "Request to delete events", + "nip": "09", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 6, + "name": "Repost", + "description": "Share/repost another text note", + "nip": "18", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 7, + "name": "Reaction", + "description": "Like, emoji reaction to an event", + "nip": "25", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 8, + "name": "Badge Award", + "description": "Award a badge to someone", + "nip": "58", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 9, + "name": "Chat Message", + "description": "Chat message", + "nip": "C7", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 10, + "name": "Group Chat Threaded Reply", + "description": "Threaded reply in group chat", + "nip": "29", + "classification": "regular", + "deprecated": true, + "spec": null + }, + { + "kind": 11, + "name": "Thread", + "description": "Thread event", + "nip": "7D", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 12, + "name": "Group Thread Reply", + "description": "Reply in group thread", + "nip": "29", + "classification": "regular", + "deprecated": true, + "spec": null + }, + { + "kind": 13, + "name": "Seal", + "description": "Sealed/encrypted event wrapper", + "nip": "59", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 14, + "name": "Direct Message", + "description": "Private direct message using NIP-17", + "nip": "17", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 15, + "name": "File Message", + "description": "File message in DMs", + "nip": "17", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 16, + "name": "Generic Repost", + "description": "Repost any event kind", + "nip": "18", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 17, + "name": "Reaction to Website", + "description": "Reaction to a website URL", + "nip": "25", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 20, + "name": "Picture", + "description": "Picture-first feed post", + "nip": "68", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 21, + "name": "Video Event", + "description": "Horizontal video event", + "nip": "71", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 22, + "name": "Short-form Video", + "description": "Short-form portrait video (like TikTok)", + "nip": "71", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 40, + "name": "Channel Creation", + "description": "Create a public chat channel", + "nip": "28", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 41, + "name": "Channel Metadata", + "description": "Set channel name, about, picture", + "nip": "28", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 42, + "name": "Channel Message", + "description": "Post message in channel", + "nip": "28", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 43, + "name": "Channel Hide Message", + "description": "Hide a message in channel", + "nip": "28", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 44, + "name": "Channel Mute User", + "description": "Mute a user in channel", + "nip": "28", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 62, + "name": "Request to Vanish", + "description": "Request permanent deletion of all user data", + "nip": "62", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 64, + "name": "Chess (PGN)", + "description": "Chess game in PGN format", + "nip": "64", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 443, + "name": "KeyPackage", + "description": "Marmot protocol key package", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "Marmot" + }, + { + "kind": 444, + "name": "Welcome Message", + "description": "Marmot protocol welcome message", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "Marmot" + }, + { + "kind": 445, + "name": "Group Event", + "description": "Marmot protocol group event", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "Marmot" + }, + { + "kind": 818, + "name": "Merge Requests", + "description": "Git merge request", + "nip": "54", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1018, + "name": "Poll Response", + "description": "Response to a poll", + "nip": "88", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1021, + "name": "Bid", + "description": "Auction bid", + "nip": "15", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1022, + "name": "Bid Confirmation", + "description": "Confirmation of auction bid", + "nip": "15", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1040, + "name": "OpenTimestamps", + "description": "OpenTimestamps attestation", + "nip": "03", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1059, + "name": "Gift Wrap", + "description": "Encrypted gift-wrapped event", + "nip": "59", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1060, + "name": "Gift Wrap (Kind 4)", + "description": "Gift wrap variant for NIP-04 compatibility", + "nip": "59", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1063, + "name": "File Metadata", + "description": "Metadata for shared files", + "nip": "94", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1068, + "name": "Poll", + "description": "Create a poll", + "nip": "88", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1111, + "name": "Comment", + "description": "Comment on events or external content", + "nip": "22", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1222, + "name": "Voice Message", + "description": "Voice message", + "nip": "A0", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1244, + "name": "Voice Message Comment", + "description": "Comment on voice message", + "nip": "A0", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1311, + "name": "Live Chat Message", + "description": "Message in live stream chat", + "nip": "53", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1337, + "name": "Code Snippet", + "description": "Code snippet post", + "nip": "C0", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1517, + "name": "Bitcoin Block", + "description": "Bitcoin block data", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "Nostrocket" + }, + { + "kind": 1617, + "name": "Patches", + "description": "Git patches", + "nip": "34", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1618, + "name": "Pull Requests", + "description": "Git pull request", + "nip": "34", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1619, + "name": "Pull Request Updates", + "description": "Updates to git pull request", + "nip": "34", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1621, + "name": "Issues", + "description": "Git issues", + "nip": "34", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1622, + "name": "Git Replies", + "description": "Replies on git objects", + "nip": "34", + "classification": "regular", + "deprecated": true, + "spec": null + }, + { + "kind": 1630, + "name": "Status", + "description": "Git status", + "nip": "34", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1631, + "name": "Status", + "description": "Git status", + "nip": "34", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1632, + "name": "Status", + "description": "Git status", + "nip": "34", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1633, + "name": "Status", + "description": "Git status", + "nip": "34", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1808, + "name": "Live Stream", + "description": "Live streaming event", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "zap.stream" + }, + { + "kind": 1971, + "name": "Problem Tracker", + "description": "Problem tracking", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "Nostrocket" + }, + { + "kind": 1984, + "name": "Reporting", + "description": "Report content or users", + "nip": "56", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1985, + "name": "Label", + "description": "Label/tag content with namespace", + "nip": "32", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1986, + "name": "Relay Reviews", + "description": "Reviews of relays", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 1987, + "name": "AI Embeddings", + "description": "AI embeddings/vector lists", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "NKBIP-02" + }, + { + "kind": 2003, + "name": "Torrent", + "description": "Torrent magnet link", + "nip": "35", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 2004, + "name": "Torrent Comment", + "description": "Comment on torrent", + "nip": "35", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 2022, + "name": "Coinjoin Pool", + "description": "Coinjoin coordination", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "joinstr" + }, + { + "kind": 4550, + "name": "Community Post Approval", + "description": "Approve post in community", + "nip": "72", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 5000, + "name": "Job Request", + "description": "Data vending machine job request (start of range)", + "nip": "90", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 6000, + "name": "Job Result", + "description": "Data vending machine job result (start of range)", + "nip": "90", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 7000, + "name": "Job Feedback", + "description": "Feedback on job request/result", + "nip": "90", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 7374, + "name": "Reserved Cashu Wallet Tokens", + "description": "Reserved Cashu wallet tokens", + "nip": "60", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 7375, + "name": "Cashu Wallet Tokens", + "description": "Cashu wallet tokens", + "nip": "60", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 7376, + "name": "Cashu Wallet History", + "description": "Cashu wallet transaction history", + "nip": "60", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 7516, + "name": "Geocache Log", + "description": "Geocaching log entry", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "geocaching" + }, + { + "kind": 7517, + "name": "Geocache Proof of Find", + "description": "Proof of geocache find", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "geocaching" + }, + { + "kind": 8000, + "name": "Add User", + "description": "Add user to group", + "nip": "43", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 8001, + "name": "Remove User", + "description": "Remove user from group", + "nip": "43", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 9000, + "name": "Group Control Events", + "description": "Group control events (start of range)", + "nip": "29", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 9041, + "name": "Zap Goal", + "description": "Fundraising goal for zaps", + "nip": "75", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 9321, + "name": "Nutzap", + "description": "Cashu nutzap", + "nip": "61", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 9467, + "name": "Tidal Login", + "description": "Tidal streaming login", + "nip": null, + "classification": "regular", + "deprecated": false, + "spec": "Tidal-nostr" + }, + { + "kind": 9734, + "name": "Zap Request", + "description": "Request Lightning payment", + "nip": "57", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 9735, + "name": "Zap", + "description": "Lightning payment receipt", + "nip": "57", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 9802, + "name": "Highlights", + "description": "Highlighted text selection", + "nip": "84", + "classification": "regular", + "deprecated": false, + "spec": null + }, + { + "kind": 10000, + "name": "Mute List", + "description": "List of muted users/content", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10001, + "name": "Pin List", + "description": "Pinned events", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10002, + "name": "Relay List Metadata", + "description": "User's preferred relays for read/write", + "nip": "65", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10003, + "name": "Bookmark List", + "description": "Bookmarked events", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10004, + "name": "Communities List", + "description": "Communities user belongs to", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10005, + "name": "Public Chats List", + "description": "Public chats user is in", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10006, + "name": "Blocked Relays List", + "description": "Relays user has blocked", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10007, + "name": "Search Relays List", + "description": "Preferred search relays", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10008, + "name": "Relay Group Configuration", + "description": "Relay group configuration", + "nip": null, + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10009, + "name": "User Groups", + "description": "Groups user belongs to", + "nip": "29", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10012, + "name": "Favorite Relays List", + "description": "User's favorite relays", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10013, + "name": "Private Event Relay List", + "description": "Relays for private events", + "nip": "37", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10015, + "name": "Interests List", + "description": "User interests/topics", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10019, + "name": "Nutzap Mint Recommendation", + "description": "Recommended Cashu mints for nutzaps", + "nip": "61", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10020, + "name": "Media Follows", + "description": "Followed media accounts", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10030, + "name": "User Emoji List", + "description": "Custom emoji list", + "nip": "51", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10050, + "name": "DM Relays List", + "description": "Relays to receive DMs on", + "nip": "17", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10051, + "name": "KeyPackage Relays List", + "description": "Marmot key package relays", + "nip": null, + "classification": "replaceable", + "deprecated": false, + "spec": "Marmot" + }, + { + "kind": 10063, + "name": "User Server List", + "description": "Blossom server list", + "nip": null, + "classification": "replaceable", + "deprecated": false, + "spec": "Blossom" + }, + { + "kind": 10096, + "name": "File Storage Server List", + "description": "File storage servers", + "nip": "96", + "classification": "replaceable", + "deprecated": true, + "spec": null + }, + { + "kind": 10166, + "name": "Relay Monitor Announcement", + "description": "Relay monitoring announcement", + "nip": "66", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10312, + "name": "Room Presence", + "description": "Presence in live room", + "nip": "53", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 10377, + "name": "Proxy Announcement", + "description": "Nostr proxy announcement", + "nip": null, + "classification": "replaceable", + "deprecated": false, + "spec": "Nostr Epoxy" + }, + { + "kind": 11111, + "name": "Transport Method Announcement", + "description": "Transport method announcement", + "nip": null, + "classification": "replaceable", + "deprecated": false, + "spec": "Nostr Epoxy" + }, + { + "kind": 12345, + "name": "Relay Policy Configuration", + "description": "Relay-internal policy configuration (admin only)", + "nip": null, + "classification": "replaceable", + "deprecated": false, + "spec": "orly" + }, + { + "kind": 13004, + "name": "JWT Binding", + "description": "Link between JWT certificate and pubkey", + "nip": null, + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 13194, + "name": "Wallet Service Info", + "description": "NWC wallet service information", + "nip": "47", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 13534, + "name": "Membership Lists", + "description": "Group membership lists", + "nip": "43", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 14388, + "name": "User Sound Effect Lists", + "description": "Sound effect lists", + "nip": null, + "classification": "replaceable", + "deprecated": false, + "spec": "Corny Chat" + }, + { + "kind": 17375, + "name": "Cashu Wallet Event", + "description": "Cashu wallet event", + "nip": "60", + "classification": "replaceable", + "deprecated": false, + "spec": null + }, + { + "kind": 21000, + "name": "Lightning Pub RPC", + "description": "Lightning.Pub RPC", + "nip": null, + "classification": "ephemeral", + "deprecated": false, + "spec": "Lightning.Pub" + }, + { + "kind": 22242, + "name": "Client Authentication", + "description": "Authenticate to relay", + "nip": "42", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 23194, + "name": "Wallet Request", + "description": "NWC wallet request", + "nip": "47", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 23195, + "name": "Wallet Response", + "description": "NWC wallet response", + "nip": "47", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 23196, + "name": "Wallet Notification (NIP-04)", + "description": "NWC wallet notification (NIP-04 encrypted)", + "nip": "47", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 23197, + "name": "Wallet Notification", + "description": "NWC wallet notification", + "nip": "47", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 24133, + "name": "Nostr Connect", + "description": "Remote signer connection", + "nip": "46", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 24242, + "name": "Blobs Stored on Mediaservers", + "description": "Blossom blob storage", + "nip": null, + "classification": "ephemeral", + "deprecated": false, + "spec": "Blossom" + }, + { + "kind": 27235, + "name": "HTTP Auth", + "description": "Authenticate HTTP requests", + "nip": "98", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 28934, + "name": "Join Request", + "description": "Request to join group", + "nip": "43", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 28935, + "name": "Invite Request", + "description": "Invite to group", + "nip": "43", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 28936, + "name": "Leave Request", + "description": "Leave group request", + "nip": "43", + "classification": "ephemeral", + "deprecated": false, + "spec": null + }, + { + "kind": 30000, + "name": "Follow Sets", + "description": "Categorized people lists", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30001, + "name": "Generic Lists", + "description": "Generic categorized lists", + "nip": "51", + "classification": "parameterized", + "deprecated": true, + "spec": null + }, + { + "kind": 30002, + "name": "Relay Sets", + "description": "Categorized relay lists", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30003, + "name": "Bookmark Sets", + "description": "Categorized bookmark lists", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30004, + "name": "Curation Sets", + "description": "Curated content sets", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30005, + "name": "Video Sets", + "description": "Video playlists", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30007, + "name": "Kind Mute Sets", + "description": "Muted event kinds", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30008, + "name": "Profile Badges", + "description": "Badges displayed on profile", + "nip": "58", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30009, + "name": "Badge Definition", + "description": "Define a badge/achievement", + "nip": "58", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30015, + "name": "Interest Sets", + "description": "Interest/topic sets", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30017, + "name": "Stall", + "description": "Marketplace stall definition", + "nip": "15", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30018, + "name": "Product", + "description": "Marketplace product listing", + "nip": "15", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30019, + "name": "Marketplace UI/UX", + "description": "Marketplace interface settings", + "nip": "15", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30020, + "name": "Product Sold as Auction", + "description": "Auction product listing", + "nip": "15", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30023, + "name": "Long-form Content", + "description": "Blog post, article in markdown", + "nip": "23", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30024, + "name": "Draft Long-form Content", + "description": "Draft article", + "nip": "23", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30030, + "name": "Emoji Sets", + "description": "Custom emoji sets", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30040, + "name": "Curated Publication Index", + "description": "Publication index", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "NKBIP-01" + }, + { + "kind": 30041, + "name": "Curated Publication Content", + "description": "Publication content", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "NKBIP-01" + }, + { + "kind": 30063, + "name": "Release Artifact Sets", + "description": "Software release artifacts", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30078, + "name": "Application-specific Data", + "description": "App-specific key-value storage", + "nip": "78", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30166, + "name": "Relay Discovery", + "description": "Relay discovery/monitoring", + "nip": "66", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30267, + "name": "App Curation Sets", + "description": "Curated app sets", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30311, + "name": "Live Event", + "description": "Live streaming event", + "nip": "53", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30312, + "name": "Interactive Room", + "description": "Interactive live room", + "nip": "53", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30313, + "name": "Conference Event", + "description": "Conference/meetup event", + "nip": "53", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30315, + "name": "User Statuses", + "description": "User status updates", + "nip": "38", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30388, + "name": "Slide Set", + "description": "Presentation slides", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "Corny Chat" + }, + { + "kind": 30402, + "name": "Classified Listing", + "description": "Classified ad listing", + "nip": "99", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30403, + "name": "Draft Classified Listing", + "description": "Draft classified ad", + "nip": "99", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30617, + "name": "Repository Announcements", + "description": "Git repository announcement", + "nip": "34", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30618, + "name": "Repository State Announcements", + "description": "Git repository state", + "nip": "34", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30818, + "name": "Wiki Article", + "description": "Wiki article", + "nip": "54", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 30819, + "name": "Redirects", + "description": "URL redirects", + "nip": "54", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 31234, + "name": "Draft Event", + "description": "Draft of any event", + "nip": "37", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 31388, + "name": "Link Set", + "description": "Link collection", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "Corny Chat" + }, + { + "kind": 31890, + "name": "Feed", + "description": "Custom feed definition", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "NUD: Custom Feeds" + }, + { + "kind": 31922, + "name": "Date-Based Calendar Event", + "description": "All-day calendar event", + "nip": "52", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 31923, + "name": "Time-Based Calendar Event", + "description": "Calendar event with time", + "nip": "52", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 31924, + "name": "Calendar", + "description": "Calendar definition", + "nip": "52", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 31925, + "name": "Calendar Event RSVP", + "description": "RSVP to calendar event", + "nip": "52", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 31989, + "name": "Handler Recommendation", + "description": "Recommended app for event kind", + "nip": "89", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 31990, + "name": "Handler Information", + "description": "App handler declaration", + "nip": "89", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 32123, + "name": "WaveLake Track", + "description": "WaveLake music track", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "WaveLake" + }, + { + "kind": 32267, + "name": "Software Application", + "description": "Software application listing", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 32388, + "name": "User Room Favorites", + "description": "Favorite rooms", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "Corny Chat" + }, + { + "kind": 33388, + "name": "High Scores", + "description": "Game high scores", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "Corny Chat" + }, + { + "kind": 34235, + "name": "Video Event Horizontal", + "description": "Horizontal video event", + "nip": "71", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 34236, + "name": "Video Event Vertical", + "description": "Vertical video event", + "nip": "71", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 34388, + "name": "Sound Effects", + "description": "Sound effect definitions", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "Corny Chat" + }, + { + "kind": 34550, + "name": "Community Definition", + "description": "Define a community", + "nip": "72", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 37516, + "name": "Geocache Listing", + "description": "Geocache location listing", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": "geocaching" + }, + { + "kind": 38172, + "name": "Cashu Mint Announcement", + "description": "Cashu mint announcement", + "nip": "87", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 38173, + "name": "Fedimint Announcement", + "description": "Fedimint announcement", + "nip": "87", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 38383, + "name": "Peer-to-peer Order Events", + "description": "P2P trading orders", + "nip": "69", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 39000, + "name": "Group Metadata Events", + "description": "Group metadata (start of range)", + "nip": "29", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 39089, + "name": "Starter Packs", + "description": "Starter pack lists", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 39092, + "name": "Media Starter Packs", + "description": "Media starter packs", + "nip": "51", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 39701, + "name": "Web Bookmarks", + "description": "Web URL bookmarks", + "nip": "B0", + "classification": "parameterized", + "deprecated": false, + "spec": null + }, + { + "kind": 39998, + "name": "ACL Event", + "description": "Access control list event", + "nip": null, + "classification": "parameterized", + "deprecated": false, + "spec": null + } +]; + +export const KIND_RANGES: KindRanges = { + "regular": { + "start": 1000, + "end": 9999, + "description": "Regular events - all versions kept, never replaced" + }, + "replaceable": { + "start": 10000, + "end": 19999, + "description": "Replaceable events - only latest per pubkey kept" + }, + "ephemeral": { + "start": 20000, + "end": 29999, + "description": "Ephemeral events - forwarded but not stored" + }, + "parameterized": { + "start": 30000, + "end": 39999, + "description": "Parameterized replaceable - replaced by d tag value" + } +}; + +export const PRIVILEGED_KINDS: number[] = [4,13,14,15,1059,1060,30078]; + +export const DIRECTORY_KINDS: number[] = [0,3,5,1984,10002,10000,10050]; + +export const KIND_ALIASES: Record = { + "SetMetadata": 0, + "Follows": 3, + "Contacts": 3, + "Deletion": 5, + "MemoryHole": 1984, + "BlockList": 10000, + "Article": 30023, + "CategorizedPeopleList": 30000, + "CategorizedBookmarksList": 30001 +}; + +// Lookup map for fast access +const kindMap = new Map(EVENT_KINDS.map(k => [k.kind, k])); + +export function getKindInfo(kind: number): KindInfo | undefined { + return kindMap.get(kind); +} + +export function getKindName(kind: number): string { + const info = kindMap.get(kind); + return info ? info.name : `Kind ${kind}`; +} + +export function isReplaceable(kind: number): boolean { + if (kind === 0 || kind === 3) return true; + return kind >= KIND_RANGES.replaceable.start && kind < KIND_RANGES.replaceable.end; +} + +export function isEphemeral(kind: number): boolean { + return kind >= KIND_RANGES.ephemeral.start && kind < KIND_RANGES.ephemeral.end; +} + +export function isParameterized(kind: number): boolean { + return kind >= KIND_RANGES.parameterized.start && kind <= KIND_RANGES.parameterized.end; +} + +export function isPrivileged(kind: number): boolean { + return PRIVILEGED_KINDS.includes(kind); +} + +export function isDirectoryKind(kind: number): boolean { + return DIRECTORY_KINDS.includes(kind); +} diff --git a/scripts/fetch-kinds.js b/scripts/fetch-kinds.js new file mode 100644 index 0000000..3e3b7e2 --- /dev/null +++ b/scripts/fetch-kinds.js @@ -0,0 +1,147 @@ +#!/usr/bin/env node +/** + * Fetches kinds.json from the nostr library and generates TypeScript definitions + * Run: node scripts/fetch-kinds.js + */ + +import { writeFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const KINDS_URL = 'https://git.mleku.dev/mleku/nostr/raw/branch/main/encoders/kind/kinds.json'; + +async function fetchKinds() { + console.log(`Fetching kinds from ${KINDS_URL}...`); + + const response = await fetch(KINDS_URL); + if (!response.ok) { + throw new Error(`Failed to fetch kinds.json: ${response.status} ${response.statusText}`); + } + + const data = await response.json(); + console.log(`Fetched ${Object.keys(data.kinds).length} kinds (version: ${data.version})`); + + return data; +} + +function generateTypeScript(data) { + const kinds = []; + + for (const [kindNum, info] of Object.entries(data.kinds)) { + const k = parseInt(kindNum, 10); + + // Determine classification + let classification = 'regular'; + if (info.classification) { + classification = info.classification; + } else if (k === 0 || k === 3 || (k >= data.ranges.replaceable.start && k < data.ranges.replaceable.end)) { + classification = 'replaceable'; + } else if (k >= data.ranges.parameterized.start && k <= data.ranges.parameterized.end) { + classification = 'parameterized'; + } else if (k >= data.ranges.ephemeral.start && k < data.ranges.ephemeral.end) { + classification = 'ephemeral'; + } + + kinds.push({ + kind: k, + name: info.name, + description: info.description, + nip: info.nip || null, + classification, + deprecated: info.deprecated || false, + spec: info.spec || null + }); + } + + // Sort by kind number + kinds.sort((a, b) => a.kind - b.kind); + + return `/** + * Nostr Event Kinds Database + * Auto-generated from ${KINDS_URL} + * Version: ${data.version} + * Source: ${data.source} + * + * DO NOT EDIT - This file is auto-generated by scripts/fetch-kinds.js + */ + +export interface KindInfo { + kind: number; + name: string; + description: string; + nip: string | null; + classification: 'regular' | 'replaceable' | 'ephemeral' | 'parameterized'; + deprecated: boolean; + spec: string | null; +} + +export interface KindRanges { + regular: { start: number; end: number; description: string }; + replaceable: { start: number; end: number; description: string }; + ephemeral: { start: number; end: number; description: string }; + parameterized: { start: number; end: number; description: string }; +} + +export const EVENT_KINDS: KindInfo[] = ${JSON.stringify(kinds, null, 2)}; + +export const KIND_RANGES: KindRanges = ${JSON.stringify(data.ranges, null, 2)}; + +export const PRIVILEGED_KINDS: number[] = ${JSON.stringify(data.privileged)}; + +export const DIRECTORY_KINDS: number[] = ${JSON.stringify(data.directory)}; + +export const KIND_ALIASES: Record = ${JSON.stringify(data.aliases, null, 2)}; + +// Lookup map for fast access +const kindMap = new Map(EVENT_KINDS.map(k => [k.kind, k])); + +export function getKindInfo(kind: number): KindInfo | undefined { + return kindMap.get(kind); +} + +export function getKindName(kind: number): string { + const info = kindMap.get(kind); + return info ? info.name : \`Kind \${kind}\`; +} + +export function isReplaceable(kind: number): boolean { + if (kind === 0 || kind === 3) return true; + return kind >= KIND_RANGES.replaceable.start && kind < KIND_RANGES.replaceable.end; +} + +export function isEphemeral(kind: number): boolean { + return kind >= KIND_RANGES.ephemeral.start && kind < KIND_RANGES.ephemeral.end; +} + +export function isParameterized(kind: number): boolean { + return kind >= KIND_RANGES.parameterized.start && kind <= KIND_RANGES.parameterized.end; +} + +export function isPrivileged(kind: number): boolean { + return PRIVILEGED_KINDS.includes(kind); +} + +export function isDirectoryKind(kind: number): boolean { + return DIRECTORY_KINDS.includes(kind); +} +`; +} + +async function main() { + try { + const data = await fetchKinds(); + const ts = generateTypeScript(data); + + // Write to common library + const outPath = join(__dirname, '..', 'projects', 'common', 'src', 'lib', 'constants', 'event-kinds.ts'); + + writeFileSync(outPath, ts); + console.log(`Generated ${outPath} with ${Object.keys(data.kinds).length} kinds`); + } catch (error) { + console.error('Error:', error.message); + process.exit(1); + } +} + +main();