mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-09 08:38:50 +00:00
Nip58 Implementation (#386)
* implement nip58 * add tests for nip58 * export nip58 * bump version
This commit is contained in:
245
nip58.ts
Normal file
245
nip58.ts
Normal file
@@ -0,0 +1,245 @@
|
||||
import { Event, EventTemplate } from './core'
|
||||
import {
|
||||
BadgeAward as BadgeAwardKind,
|
||||
BadgeDefinition as BadgeDefinitionKind,
|
||||
ProfileBadges as ProfileBadgesKind,
|
||||
} from './kinds'
|
||||
|
||||
/**
|
||||
* Represents the structure for defining a badge within the Nostr network.
|
||||
* This structure is used to create templates for badge definition events,
|
||||
* facilitating the recognition and awarding of badges to users for various achievements.
|
||||
*/
|
||||
export type BadgeDefinition = {
|
||||
/**
|
||||
* A unique identifier for the badge. This is used to distinguish badges
|
||||
* from one another and should be unique across all badge definitions.
|
||||
* Typically, this could be a short, descriptive string.
|
||||
*/
|
||||
d: string
|
||||
|
||||
/**
|
||||
* An optional short name for the badge. This provides a human-readable
|
||||
* title for the badge, making it easier to recognize and refer to.
|
||||
*/
|
||||
name?: string
|
||||
|
||||
/**
|
||||
* An optional description for the badge. This field can be used to
|
||||
* provide more detailed information about the badge, such as the criteria
|
||||
* for its awarding or its significance.
|
||||
*/
|
||||
description?: string
|
||||
|
||||
/**
|
||||
* An optional image URL and dimensions for the badge. The first element
|
||||
* of the tuple is the URL pointing to a high-resolution image representing
|
||||
* the badge, and the second element specifies the image's dimensions in
|
||||
* the format "widthxheight". The recommended dimensions are 1024x1024 pixels.
|
||||
*/
|
||||
image?: [string, string]
|
||||
|
||||
/**
|
||||
* An optional list of thumbnail images for the badge. Each element in the
|
||||
* array is a tuple, where the first element is the URL pointing to a thumbnail
|
||||
* version of the badge image, and the second element specifies the thumbnail's
|
||||
* dimensions in the format "widthxheight". Multiple thumbnails can be provided
|
||||
* to support different display sizes.
|
||||
*/
|
||||
thumbs?: Array<[string, string]>
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the structure for awarding a badge to one or more recipients
|
||||
* within the Nostr network. This structure is used to create templates for
|
||||
* badge award events, which are immutable and signify the recognition of
|
||||
* individuals' achievements or contributions.
|
||||
*/
|
||||
export type BadgeAward = {
|
||||
/**
|
||||
* A reference to the Badge Definition event. This is typically composed
|
||||
* of the event ID of the badge definition. It establishes a clear linkage
|
||||
* between the badge being awarded and its original definition, ensuring
|
||||
* that recipients are awarded the correct badge.
|
||||
*/
|
||||
a: string
|
||||
|
||||
/**
|
||||
* An array of p tags, each containing a pubkey and its associated relays.
|
||||
*/
|
||||
p: string[][]
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the collection of badges a user chooses to display on their profile.
|
||||
* This structure is crucial for applications that allow users to showcase achievements
|
||||
* or recognitions in the form of badges, following the specifications of NIP-58.
|
||||
*/
|
||||
export type ProfileBadges = {
|
||||
/**
|
||||
* A unique identifier for the profile badges collection. According to NIP-58,
|
||||
* this should be set to "profile_badges" to differentiate it from other event types.
|
||||
*/
|
||||
d: 'profile_badges'
|
||||
|
||||
/**
|
||||
* A list of badges that the user has elected to display on their profile. Each item
|
||||
* in the array represents a specific badge, including references to both its definition
|
||||
* and the award event.
|
||||
*/
|
||||
badges: Array<{
|
||||
/**
|
||||
* The event address of the badge definition. This is a reference to the specific badge
|
||||
* being displayed, linking back to the badge's original definition event. It allows
|
||||
* clients to fetch and display the badge's details, such as its name, description,
|
||||
* and image.
|
||||
*/
|
||||
a: string
|
||||
|
||||
/**
|
||||
* The event id of the badge award with corresponding relays. This references the event
|
||||
* in which the badge was awarded to the user. It is crucial for verifying the
|
||||
* authenticity of the badge display, ensuring that the user was indeed awarded the
|
||||
* badge they are choosing to display.
|
||||
*/
|
||||
e: string[]
|
||||
}>
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an EventTemplate based on the provided BadgeDefinition.
|
||||
*
|
||||
* @param {BadgeDefinition} badgeDefinition - The BadgeDefinition object.
|
||||
* @returns {EventTemplate} - The generated EventTemplate object.
|
||||
*/
|
||||
export function generateBadgeDefinitionEventTemplate({
|
||||
d,
|
||||
description,
|
||||
image,
|
||||
name,
|
||||
thumbs,
|
||||
}: BadgeDefinition): EventTemplate {
|
||||
// Mandatory tags
|
||||
const tags: string[][] = [['d', d]]
|
||||
|
||||
// Append optional tags
|
||||
name && tags.push(['name', name])
|
||||
description && tags.push(['description', description])
|
||||
image && tags.push(['image', ...image])
|
||||
if (thumbs) {
|
||||
for (const thumb of thumbs) {
|
||||
tags.push(['thumb', ...thumb])
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the EventTemplate object
|
||||
const eventTemplate: EventTemplate = {
|
||||
content: '',
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
kind: BadgeDefinitionKind,
|
||||
tags,
|
||||
}
|
||||
|
||||
return eventTemplate
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a badge definition event.
|
||||
*
|
||||
* @param event - The event to validate.
|
||||
* @returns A boolean indicating whether the event is a valid badge definition event.
|
||||
*/
|
||||
export function validateBadgeDefinitionEvent(event: Event): boolean {
|
||||
if (event.kind !== BadgeDefinitionKind) return false
|
||||
|
||||
const requiredTags = ['d'] as const
|
||||
for (const tag of requiredTags) {
|
||||
if (!event.tags.find(([t]) => t == tag)) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an EventTemplate based on the provided BadgeAward.
|
||||
*
|
||||
* @param {BadgeAward} badgeAward - The BadgeAward object.
|
||||
* @returns {EventTemplate} - The generated EventTemplate object.
|
||||
*/
|
||||
export function generateBadgeAwardEventTemplate({ a, p }: BadgeAward): EventTemplate {
|
||||
// Mandatory tags
|
||||
const tags: string[][] = [['a', a]]
|
||||
for (const _p of p) {
|
||||
tags.push(['p', ..._p])
|
||||
}
|
||||
|
||||
// Construct the EventTemplate object
|
||||
const eventTemplate: EventTemplate = {
|
||||
content: '',
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
kind: BadgeAwardKind,
|
||||
tags,
|
||||
}
|
||||
|
||||
return eventTemplate
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a badge award event.
|
||||
*
|
||||
* @param event - The event to validate.
|
||||
* @returns A boolean indicating whether the event is a valid badge award event.
|
||||
*/
|
||||
export function validateBadgeAwardEvent(event: Event): boolean {
|
||||
if (event.kind !== BadgeAwardKind) return false
|
||||
|
||||
const requiredTags = ['a', 'p'] as const
|
||||
for (const tag of requiredTags) {
|
||||
if (!event.tags.find(([t]) => t == tag)) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an EventTemplate based on the provided ProfileBadges.
|
||||
*
|
||||
* @param {ProfileBadges} profileBadges - The ProfileBadges object.
|
||||
* @returns {EventTemplate} - The generated EventTemplate object.
|
||||
*/
|
||||
export function generateProfileBadgesEventTemplate({ badges }: ProfileBadges): EventTemplate {
|
||||
// Mandatory tags
|
||||
const tags: string[][] = [['d', 'profile_badges']]
|
||||
|
||||
// Append optional tags
|
||||
for (const badge of badges) {
|
||||
tags.push(['a', badge.a], ['e', ...badge.e])
|
||||
}
|
||||
|
||||
// Construct the EventTemplate object
|
||||
const eventTemplate: EventTemplate = {
|
||||
content: '',
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
kind: ProfileBadgesKind,
|
||||
tags,
|
||||
}
|
||||
|
||||
return eventTemplate
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a profile badges event.
|
||||
*
|
||||
* @param event - The event to validate.
|
||||
* @returns A boolean indicating whether the event is a valid profile badges event.
|
||||
*/
|
||||
export function validateProfileBadgesEvent(event: Event): boolean {
|
||||
if (event.kind !== ProfileBadgesKind) return false
|
||||
|
||||
const requiredTags = ['d'] as const
|
||||
for (const tag of requiredTags) {
|
||||
if (!event.tags.find(([t]) => t == tag)) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user