Linkify BIPs

This commit is contained in:
hzrd149 2025-02-28 09:45:34 -06:00
parent 5c177e2e03
commit bd6e21e53c
10 changed files with 345 additions and 87 deletions

View File

@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Linkify BIPs

View File

@ -0,0 +1,12 @@
import { Link, Tooltip } from "@chakra-ui/react";
import { BIPToken } from "../transform/bip-notation";
export default function BipDefinition({ node }: { node: BIPToken }) {
return (
<Tooltip label={node.name} aria-label="BIP Definition">
<Link isExternal href={`https://bips.xyz/${node.bip}`} textDecoration="underline">
{node.value}
</Link>
</Tooltip>
);
}

View File

@ -1,4 +1,3 @@
import { lazy } from "react";
import { Link, Text } from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";
import { ComponentMap } from "applesauce-react/hooks";
@ -6,9 +5,10 @@ import { ComponentMap } from "applesauce-react/hooks";
import Mention from "./components/mention";
import Cashu from "./components/cashu";
import { InlineEmoji } from "./components/ininle-emoji";
import NipDefinition from "./components/nip";
import { ImageGallery } from "./components/gallery";
import LightningInvoice from "./components/lightning";
import NipDefinition from "./components/nip";
import BipDefinition from "./components/bip";
export const components: ComponentMap = {
text: ({ node }) => <Text as="span">{node.value}</Text>,
@ -21,6 +21,7 @@ export const components: ComponentMap = {
</Link>
),
nip: NipDefinition,
bip: BipDefinition,
gallery: ({ node }) => <ImageGallery images={node.links} />,
lightning: ({ node }) => <LightningInvoice invoice={node.invoice} />,
};

View File

@ -0,0 +1,49 @@
import { Transformer } from "unified";
import { Root, findAndReplace, Node } from "applesauce-content/nast";
import { BIP_NAMES } from "../../../const";
export interface BIPToken extends Node {
type: "bip";
bip: number;
name: string;
value: string;
}
declare module "applesauce-content/nast" {
export interface BIPToken extends Node {
type: "bip";
bip: number;
name: string;
value: string;
}
export interface ContentMap {
bip: BIPToken;
}
}
export function bipDefinitions(): Transformer<Root> {
return (tree) => {
findAndReplace(tree, [
[
/(?<=^|[^\p{L}])bip[-\s]?(\d{1,3})/giu,
(match: string, $1: string) => {
try {
const bip = parseInt($1);
const name = BIP_NAMES[bip];
if (!name) return false;
return {
type: "bip",
bip,
value: match,
name,
};
} catch (error) {}
return false;
},
],
]);
};
}

View File

@ -1,7 +1,6 @@
import { Transformer } from "unified";
import { Root, findAndReplace, Node } from "applesauce-content/nast";
import { NIP_NAMES } from "../../../views/relays/components/supported-nips";
import { NIP_NAMES } from "../../../const";
export interface NIPToken extends Node {
type: "nip";

View File

@ -6,8 +6,9 @@ import { emojis, nostrMentions, links, hashtags } from "applesauce-content/text"
import { components } from "../content";
import { renderGenericUrl } from "../content/links";
import { nipDefinitions } from "../content/transform/nip-notation";
import { bipDefinitions } from "../content/transform/bip-notation";
const transformers = [links, nostrMentions, emojis, hashtags, nipDefinitions];
const transformers = [links, nostrMentions, emojis, hashtags, nipDefinitions, bipDefinitions];
const linkRenderers = [renderGenericUrl];

View File

@ -29,8 +29,9 @@ import { LightboxProvider } from "../../lightbox-provider";
import MediaOwnerProvider from "../../../providers/local/media-owner-provider";
import { components } from "../../content";
import { nipDefinitions } from "../../content/transform/nip-notation";
import { bipDefinitions } from "../../content/transform/bip-notation";
const transformers = [...textNoteTransformers, galleries, nipDefinitions];
const transformers = [...textNoteTransformers, galleries, nipDefinitions, bipDefinitions];
export type TextNoteContentsProps = {
event: NostrEvent | EventTemplate;

View File

@ -87,3 +87,271 @@ export const NIP_89_CLIENT_APP: EventFactoryClient = {
export const SUPPORT_PUBKEY = "713978c3094081b34fcf2f5491733b0c22728cd3b7a6946519d40f5f08598af8";
export const TENOR_API_KEY = import.meta.env.VITE_TENOR_API_KEY as string | undefined;
// copied from github
export const NIP_NAMES: Record<string, string> = {
"01": "Basic protocol",
"02": "Follow List",
"03": "OpenTimestamps Attestations for Events",
"04": "Encrypted Direct Message",
"05": "Mapping Nostr keys to DNS-based internet identifiers",
"06": "Basic key derivation from mnemonic seed phrase",
"07": "window.nostr capability for web browsers",
"08": "Handling Mentions",
"09": "Event Deletion Request",
"10": "Conventions for clients' use of `e` and `p` tags in text events",
"11": "Relay Information Document",
"13": "Proof of Work",
"14": "Subject tag in text events",
"15": "Nostr Marketplace (for resilient marketplaces)",
"17": "Private Direct Messages",
"18": "Reposts",
"19": "bech32-encoded entities",
"21": "nostr: URI scheme",
"22": "Comment",
"23": "Long-form Content",
"24": "Extra metadata fields and tags",
"25": "Reactions",
"26": "Delegated Event Signing",
"27": "Text Note References",
"28": "Public Chat",
"29": "Relay-based Groups",
"30": "Custom Emoji",
"31": "Dealing with Unknown Events",
"32": "Labeling",
"34": "git stuff",
"35": "Torrents",
"36": "Sensitive Content",
"37": "Draft Events",
"38": "User Statuses",
"39": "External Identities in Profiles",
"40": "Expiration Timestamp",
"42": "Authentication of clients to relays",
"44": "Encrypted Payloads (Versioned)",
"45": "Counting results",
"46": "Nostr Remote Signing",
"47": "Nostr Wallet Connect",
"48": "Proxy Tags",
"49": "Private Key Encryption",
"50": "Search Capability",
"51": "Lists",
"52": "Calendar Events",
"53": "Live Activities",
"54": "Wiki",
"55": "Android Signer Application",
"56": "Reporting",
"57": "Lightning Zaps",
"58": "Badges",
"59": "Gift Wrap",
"60": "Cashu Wallet",
"61": "Nutzaps",
"64": "Chess (PGN)",
"65": "Relay List Metadata",
"68": "Picture-first feeds",
"69": "Peer-to-peer Order events",
"70": "Protected Events",
"71": "Video Events",
"72": "Moderated Communities",
"73": "External Content IDs",
"75": "Zap Goals",
"78": "Application-specific data",
"84": "Highlights",
"86": "Relay Management API",
"89": "Recommended Application Handlers",
"90": "Data Vending Machines",
"92": "Media Attachments",
"94": "File Metadata",
"96": "HTTP File Storage Integration",
"98": "HTTP Auth",
"99": "Classified Listings",
"7D": "Threads",
C7: "Chats",
};
// Copied from https://github.com/bitcoin/bips on 02/28/2025
export const BIP_NAMES: Record<number, string> = {
"1": "BIP Purpose and Guidelines",
"2": "BIP process, revised",
"3": "Updated BIP Process",
"8": "Version bits with lock-in by height",
"9": "Version bits with timeout and delay",
"10": "Multi-Sig Transaction Distribution",
"11": "M-of-N Standard Transactions",
"12": "OP_EVAL",
"13": "Address Format for pay-to-script-hash",
"14": "Protocol Version and User Agent",
"15": "Aliases",
"16": "Pay to Script Hash",
"17": "OP_CHECKHASHVERIFY (CHV)",
"18": "hashScriptCheck",
"19": "M-of-N Standard Transactions (Low SigOp)",
"20": "URI Scheme",
"21": "URI Scheme",
"22": "getblocktemplate - Fundamentals",
"23": "getblocktemplate - Pooled Mining",
"30": "Duplicate transactions",
"31": "Pong message",
"32": "Hierarchical Deterministic Wallets",
"33": "Stratized Nodes",
"34": "Block v2, Height in Coinbase",
"35": "mempool message",
"36": "Custom Services",
"37": "Connection Bloom filtering",
"38": "Passphrase-protected private key",
"39": "Mnemonic code for generating deterministic keys",
"40": "Stratum wire protocol",
"41": "Stratum mining protocol",
"42": "A finite monetary supply for Bitcoin",
"43": "Purpose Field for Deterministic Wallets",
"44": "Multi-Account Hierarchy for Deterministic Wallets",
"45": "Structure for Deterministic P2SH Multisignature Wallets",
"46": "Address Scheme for Timelocked Fidelity Bonds",
"47": "Reusable Payment Codes for Hierarchical Deterministic Wallets",
"48": "Multi-Script Hierarchy for Multi-Sig Wallets",
"49": "Derivation scheme for P2WPKH-nested-in-P2SH based accounts",
"50": "March 2013 Chain Fork Post-Mortem",
"52": "Durable, Low Energy Bitcoin PoW",
"60": 'Fixed Length "version" Message (Relay-Transactions Field)',
"61": "Reject P2P message",
"62": "Dealing with malleability",
"63": "Stealth Addresses",
"64": "getutxo message",
"65": "OP_CHECKLOCKTIMEVERIFY",
"66": "Strict DER signatures",
"67": "Deterministic Pay-to-script-hash multi-signature addresses through public key sorting",
"68": "Relative lock-time using consensus-enforced sequence numbers",
"69": "Lexicographical Indexing of Transaction Inputs and Outputs",
"70": "Payment Protocol",
"71": "Payment Protocol MIME types",
"72": "bitcoin: uri extensions for Payment Protocol",
"73": 'Use "Accept" header for response type negotiation with Payment Request URLs',
"74": "Allow zero value OP_RETURN in Payment Protocol",
"75": "Out of Band Address Exchange using Payment Protocol Encryption",
"78": "A Simple Payjoin Proposal",
"79": "Bustapay :: a practical coinjoin protocol",
"80": "Hierarchy for Non-Colored Voting Pool Deterministic Multisig Wallets",
"81": "Hierarchy for Colored Voting Pool Deterministic Multisig Wallets",
"83": "Dynamic Hierarchical Deterministic Key Trees",
"84": "Derivation scheme for P2WPKH based accounts",
"85": "Deterministic Entropy From BIP32 Keychains",
"86": "Key Derivation for Single Key P2TR Outputs",
"87": "Hierarchy for Deterministic Multisig Wallets",
"88": "Hierarchical Deterministic Path Templates",
"90": "Buried Deployments",
"91": "Reduced threshold Segwit MASF",
"93": "codex32: Checksummed SSSS-aware BIP32 seeds",
"94": "Testnet 4",
"98": "Fast Merkle Trees",
"99": "Motivation and deployment of consensus rule changes ([soft/hard]forks)",
"100": "Dynamic maximum block size by miner vote",
"101": "Increase maximum block size",
"102": "Block size increase to 2MB",
"103": "Block size following technological growth",
"104": "'Block75' - Max block size like difficulty",
"105": "Consensus based block size retargeting algorithm",
"106": "Dynamically Controlled Bitcoin Block Size Max Cap",
"107": "Dynamic limit on the block size",
"109": "Two million byte size limit with sigop and sighash limits",
"111": "NODE_BLOOM service bit",
"112": "CHECKSEQUENCEVERIFY",
"113": "Median time-past as endpoint for lock-time calculations",
"114": "Merkelized Abstract Syntax Tree",
"115": "Generic anti-replay protection using Script",
"116": "MERKLEBRANCHVERIFY",
"117": "Tail Call Execution Semantics",
"118": "SIGHASH_ANYPREVOUT for Taproot Scripts",
"119": "CHECKTEMPLATEVERIFY",
"120": "Proof of Payment",
"121": "Proof of Payment URI scheme",
"122": "URI scheme for Blockchain references / exploration",
"123": "BIP Classification",
"124": "Hierarchical Deterministic Script Templates",
"125": "Opt-in Full Replace-by-Fee Signaling",
"126": "Best Practices for Heterogeneous Input Script Transactions",
"127": "Simple Proof-of-Reserves Transactions",
"129": "Bitcoin Secure Multisig Setup (BSMS)",
"130": "sendheaders message",
"131": '"Coalescing Transaction" Specification (wildcard inputs)',
"132": "Committee-based BIP Acceptance Process",
"133": "feefilter message",
"134": "Flexible Transactions",
"135": "Generalized version bits voting",
"136": "Bech32 Encoded Tx Position References",
"137": "Signatures of Messages using Private Keys",
"140": "Normalized TXID",
"141": "Segregated Witness (Consensus layer)",
"142": "Address Format for Segregated Witness",
"143": "Transaction Signature Verification for Version 0 Witness Program",
"144": "Segregated Witness (Peer Services)",
"145": "getblocktemplate Updates for Segregated Witness",
"146": "Dealing with signature encoding malleability",
"147": "Dealing with dummy stack element malleability",
"148": "Mandatory activation of segwit deployment",
"149": "Segregated Witness (second deployment)",
"150": "Peer Authentication",
"151": "Peer-to-Peer Communication Encryption",
"152": "Compact Block Relay",
"154": "Rate Limiting via peer specified challenges",
"155": "addrv2 message",
"156": "Dandelion - Privacy Enhancing Routing",
"157": "Client Side Block Filtering",
"158": "Compact Block Filters for Light Clients",
"159": "NODE_NETWORK_LIMITED service bit",
"171": "Currency/exchange rate information API",
"173": "Base32 address format for native v0-16 witness outputs",
"174": "Partially Signed Bitcoin Transaction Format",
"175": "Pay to Contract Protocol",
"176": "Bits Denomination",
"178": "Version Extended WIF",
"179": "Name for payment recipient identifiers",
"180": "Block size/weight fraud proof",
"197": "Hashed Time-Locked Collateral Contract",
"199": "Hashed Time-Locked Contract transactions",
"300": "Hashrate Escrows (Consensus layer)",
"301": "Blind Merged Mining (Consensus layer)",
"310": "Stratum protocol extensions",
"320": "nVersion bits for general purpose use",
"322": "Generic Signed Message Format",
"324": "Version 2 P2P Encrypted Transport Protocol",
"325": "Signet",
"326": "Anti-fee-sniping in taproot transactions",
"327": "MuSig2 for BIP340-compatible Multi-Signatures",
"328": "Derivation Scheme for MuSig2 Aggregate Keys",
"329": "Wallet Labels Export Format",
"330": "Transaction announcements reconciliation",
"331": "Ancestor Package Relay",
"337": "Compressed Transactions",
"338": "Disable transaction relay message",
"339": "WTXID-based transaction relay",
"340": "Schnorr Signatures for secp256k1",
"341": "Taproot: SegWit version 1 spending rules",
"342": "Validation of Taproot Scripts",
"343": "Mandatory activation of taproot deployment",
"345": "OP_VAULT",
"347": "OP_CAT in Tapscript",
"348": "CHECKSIGFROMSTACK",
"349": "OP_INTERNALKEY",
"350": "Bech32m format for v1+ witness addresses",
"351": "Private Payments",
"352": "Silent Payments",
"353": "DNS Payment Instructions",
"370": "PSBT Version 2",
"371": "Taproot Fields for PSBT",
"372": "Pay-to-contract tweak fields for PSBT",
"373": "MuSig2 PSBT Fields",
"374": "Discrete Log Equality Proofs",
"375": "Sending Silent Payments with PSBTs",
"379": "Miniscript",
"380": "Output Script Descriptors General Operation",
"381": "Non-Segwit Output Script Descriptors",
"382": "Segwit Output Script Descriptors",
"383": "Multisig Output Script Descriptors",
"384": "combo() Output Script Descriptors",
"385": "raw() and addr() Output Script Descriptors",
"386": "tr() Output Script Descriptors",
"387": "Tapscript Multisig Output Script Descriptors",
"388": "Wallet Policies for Descriptor Wallets",
"389": "Multipath Descriptor Key Expressions",
"390": "musig() Descriptor Key Expression",
"431": "Topology Restrictions for Pinning",
};

View File

@ -1,84 +1,5 @@
import { Flex, FlexProps, Tag, Tooltip } from "@chakra-ui/react";
// copied from github
export const NIP_NAMES: Record<string, string> = {
"01": "Basic protocol",
"02": "Follow List",
"03": "OpenTimestamps Attestations for Events",
"04": "Encrypted Direct Message",
"05": "Mapping Nostr keys to DNS-based internet identifiers",
"06": "Basic key derivation from mnemonic seed phrase",
"07": "window.nostr capability for web browsers",
"08": "Handling Mentions",
"09": "Event Deletion Request",
"10": "Conventions for clients' use of `e` and `p` tags in text events",
"11": "Relay Information Document",
"13": "Proof of Work",
"14": "Subject tag in text events",
"15": "Nostr Marketplace (for resilient marketplaces)",
"17": "Private Direct Messages",
"18": "Reposts",
"19": "bech32-encoded entities",
"21": "nostr: URI scheme",
"22": "Comment",
"23": "Long-form Content",
"24": "Extra metadata fields and tags",
"25": "Reactions",
"26": "Delegated Event Signing",
"27": "Text Note References",
"28": "Public Chat",
"29": "Relay-based Groups",
"30": "Custom Emoji",
"31": "Dealing with Unknown Events",
"32": "Labeling",
"34": "git stuff",
"35": "Torrents",
"36": "Sensitive Content",
"37": "Draft Events",
"38": "User Statuses",
"39": "External Identities in Profiles",
"40": "Expiration Timestamp",
"42": "Authentication of clients to relays",
"44": "Encrypted Payloads (Versioned)",
"45": "Counting results",
"46": "Nostr Remote Signing",
"47": "Nostr Wallet Connect",
"48": "Proxy Tags",
"49": "Private Key Encryption",
"50": "Search Capability",
"51": "Lists",
"52": "Calendar Events",
"53": "Live Activities",
"54": "Wiki",
"55": "Android Signer Application",
"56": "Reporting",
"57": "Lightning Zaps",
"58": "Badges",
"59": "Gift Wrap",
"60": "Cashu Wallet",
"61": "Nutzaps",
"64": "Chess (PGN)",
"65": "Relay List Metadata",
"68": "Picture-first feeds",
"69": "Peer-to-peer Order events",
"70": "Protected Events",
"71": "Video Events",
"72": "Moderated Communities",
"73": "External Content IDs",
"75": "Zap Goals",
"78": "Application-specific data",
"84": "Highlights",
"86": "Relay Management API",
"89": "Recommended Application Handlers",
"90": "Data Vending Machines",
"92": "Media Attachments",
"94": "File Metadata",
"96": "HTTP File Storage Integration",
"98": "HTTP Auth",
"99": "Classified Listings",
"7D": "Threads",
C7: "Chats",
};
import { NIP_NAMES } from "../../../const";
function NipTag({ nip, name }: { nip: number; name?: boolean }) {
const nipStr = String(nip).padStart(2, "0");

View File

@ -12,9 +12,10 @@ import { NostrEvent } from "../../../../types/nostr-event";
import { components } from "../../../../components/content";
import { textNoteTransformers } from "applesauce-content/text";
import { nipDefinitions } from "../../../../components/content/transform/nip-notation";
import { bipDefinitions } from "../../../../components/content/transform/bip-notation";
const StreamChatMessageContentSymbol = Symbol.for("stream-chat-message-content");
const transformers = [...textNoteTransformers, nipDefinitions];
const transformers = [...textNoteTransformers, nipDefinitions, bipDefinitions];
const linkRenderers = [renderImageUrl, renderWavlakeUrl, renderStemstrUrl, renderSoundCloudUrl, renderGenericUrl];
const ChatMessageContent = React.memo(({ event }: { event: NostrEvent }) => {