Improve event types

This commit is contained in:
Alex Gleason 2023-05-06 16:51:23 -05:00 committed by fiatjaf_
parent d0bd599ce8
commit 8a53b3b8b3
8 changed files with 29 additions and 28 deletions

View File

@ -103,7 +103,6 @@
"no-octal-escape": 2, "no-octal-escape": 2,
"no-path-concat": 0, "no-path-concat": 0,
"no-proto": 2, "no-proto": 2,
"no-redeclare": 2,
"no-regex-spaces": 2, "no-regex-spaces": 2,
"no-return-assign": 0, "no-return-assign": 0,
"no-self-assign": 2, "no-self-assign": 2,

View File

@ -6,7 +6,6 @@ import {getPublicKey} from './keys'
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
export enum Kind { export enum Kind {
UndefinedKindNumber = 255,
Metadata = 0, Metadata = 0,
Text = 1, Text = 1,
RecommendRelay = 2, RecommendRelay = 2,
@ -20,6 +19,7 @@ export enum Kind {
ChannelMessage = 42, ChannelMessage = 42,
ChannelHideMessage = 43, ChannelHideMessage = 43,
ChannelMuteUser = 44, ChannelMuteUser = 44,
Blank = 255,
Report = 1984, Report = 1984,
ZapRequest = 9734, ZapRequest = 9734,
Zap = 9735, Zap = 9735,
@ -46,24 +46,26 @@ export type Event<K extends number = Kind> = UnsignedEvent<K> & {
sig: string sig: string
} }
export function getBlankEvent<K extends Kind = Kind.UndefinedKindNumber>(kind?: K): EventTemplate<K> { export function getBlankEvent(): EventTemplate<Kind.Blank>
export function getBlankEvent<K extends number>(kind: K): EventTemplate<K>
export function getBlankEvent<K>(kind: K | Kind.Blank = Kind.Blank) {
return { return {
kind: kind || ( Kind.UndefinedKindNumber as K), kind,
content: '', content: '',
tags: [], tags: [],
created_at: 0 created_at: 0
} }
} }
export function finishEvent(t: EventTemplate, privateKey: string): Event { export function finishEvent<K extends number = Kind>(t: EventTemplate<K>, privateKey: string): Event<K> {
let event = t as Event let event = t as Event<K>
event.pubkey = getPublicKey(privateKey) event.pubkey = getPublicKey(privateKey)
event.id = getEventHash(event) event.id = getEventHash(event)
event.sig = getSignature(event, privateKey) event.sig = getSignature(event, privateKey)
return event return event
} }
export function serializeEvent(evt: UnsignedEvent): string { export function serializeEvent(evt: UnsignedEvent<number>): string {
if (!validateEvent(evt)) if (!validateEvent(evt))
throw new Error("can't serialize event with wrong or missing properties") throw new Error("can't serialize event with wrong or missing properties")
@ -77,14 +79,14 @@ export function serializeEvent(evt: UnsignedEvent): string {
]) ])
} }
export function getEventHash(event: UnsignedEvent): string { export function getEventHash(event: UnsignedEvent<number>): string {
let eventHash = sha256(utf8Encoder.encode(serializeEvent(event))) let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))
return secp256k1.utils.bytesToHex(eventHash) return secp256k1.utils.bytesToHex(eventHash)
} }
const isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object const isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object
export function validateEvent<T>(event: T): event is T & UnsignedEvent { export function validateEvent<T>(event: T): event is T & UnsignedEvent<number> {
if (!isRecord(event)) return false if (!isRecord(event)) return false
if (typeof event.kind !== 'number') return false if (typeof event.kind !== 'number') return false
if (typeof event.content !== 'string') return false if (typeof event.content !== 'string') return false
@ -104,7 +106,7 @@ export function validateEvent<T>(event: T): event is T & UnsignedEvent {
return true return true
} }
export function verifySignature(event: Event): boolean { export function verifySignature(event: Event<number>): boolean {
return secp256k1.schnorr.verifySync( return secp256k1.schnorr.verifySync(
event.sig, event.sig,
getEventHash(event), getEventHash(event),
@ -113,7 +115,7 @@ export function verifySignature(event: Event): boolean {
} }
/** @deprecated Use `getSignature` instead. */ /** @deprecated Use `getSignature` instead. */
export function signEvent(event: UnsignedEvent, key: string): string { export function signEvent(event: UnsignedEvent<number>, key: string): string {
console.warn( console.warn(
'nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead.' 'nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead.'
) )
@ -121,7 +123,7 @@ export function signEvent(event: UnsignedEvent, key: string): string {
} }
/** Calculate the signature for an event. */ /** Calculate the signature for an event. */
export function getSignature(event: UnsignedEvent, key: string): string { export function getSignature(event: UnsignedEvent<number>, key: string): string {
return secp256k1.utils.bytesToHex( return secp256k1.utils.bytesToHex(
secp256k1.schnorr.signSync(getEventHash(event), key) secp256k1.schnorr.signSync(getEventHash(event), key)
) )

View File

@ -5,7 +5,7 @@ import {base64} from '@scure/base'
import {utf8Decoder, utf8Encoder} from './utils' import {utf8Decoder, utf8Encoder} from './utils'
// @ts-ignore // @ts-ignore
if (typeof(crypto) !== 'undefined' && !crypto.subtle && crypto.webcrypto) { if (typeof crypto !== 'undefined' && !crypto.subtle && crypto.webcrypto) {
// @ts-ignore // @ts-ignore
crypto.subtle = crypto.webcrypto.subtle crypto.subtle = crypto.webcrypto.subtle
} }

View File

@ -17,9 +17,9 @@ export type ReactionEventTemplate = {
export function finishReactionEvent( export function finishReactionEvent(
t: ReactionEventTemplate, t: ReactionEventTemplate,
reacted: Event, reacted: Event<number>,
privateKey: string, privateKey: string,
): Event { ): Event<Kind.Reaction> {
const inheritedTags = reacted.tags.filter( const inheritedTags = reacted.tags.filter(
(tag) => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'), (tag) => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'),
) )
@ -37,7 +37,7 @@ export function finishReactionEvent(
}, privateKey) }, privateKey)
} }
export function getReactedEventPointer(event: Event): undefined | EventPointer { export function getReactedEventPointer(event: Event<number>): undefined | EventPointer {
if (event.kind !== Kind.Reaction) { if (event.kind !== Kind.Reaction) {
return undefined return undefined
} }

View File

@ -48,7 +48,7 @@ export function createDelegation(
} }
} }
export function getDelegator(event: Event): string | null { export function getDelegator(event: Event<number>): string | null {
// find delegation tag // find delegation tag
let tag = event.tags.find(tag => tag[0] === 'delegation' && tag.length >= 4) let tag = event.tags.find(tag => tag[0] === 'delegation' && tag.length >= 4)
if (!tag) return null if (!tag) return null

View File

@ -17,7 +17,7 @@ export const authenticate = async ({
}: { }: {
challenge: string challenge: string
relay: Relay relay: Relay
sign: (e: EventTemplate) => Promise<Event> sign: <K extends number = number>(e: EventTemplate<K>) => Promise<Event<K>>
}): Promise<void> => { }): Promise<void> => {
const e: EventTemplate = { const e: EventTemplate = {
kind: Kind.ClientAuth, kind: Kind.ClientAuth,

View File

@ -13,7 +13,7 @@ export function useFetchImplementation(fetchImplementation: any) {
_fetch = fetchImplementation _fetch = fetchImplementation
} }
export async function getZapEndpoint(metadata: Event): Promise<null | string> { export async function getZapEndpoint(metadata: Event<0>): Promise<null | string> {
try { try {
let lnurl: string = '' let lnurl: string = ''
let {lud06, lud16} = JSON.parse(metadata.content) let {lud06, lud16} = JSON.parse(metadata.content)
@ -53,11 +53,11 @@ export function makeZapRequest({
amount: number amount: number
comment: string comment: string
relays: string[] relays: string[]
}): EventTemplate { }): EventTemplate<9734> {
if (!amount) throw new Error('amount not given') if (!amount) throw new Error('amount not given')
if (!profile) throw new Error('profile not given') if (!profile) throw new Error('profile not given')
let zr = { let zr: EventTemplate<9734> = {
kind: 9734, kind: 9734,
created_at: Math.round(Date.now() / 1000), created_at: Math.round(Date.now() / 1000),
content: comment, content: comment,
@ -113,13 +113,13 @@ export function makeZapReceipt({
preimage: string | null preimage: string | null
bolt11: string bolt11: string
paidAt: Date paidAt: Date
}): EventTemplate { }): EventTemplate<9735> {
let zr: Event = JSON.parse(zapRequest) let zr: Event<9734> = JSON.parse(zapRequest)
let tagsFromZapRequest = zr.tags.filter( let tagsFromZapRequest = zr.tags.filter(
([t]) => t === 'e' || t === 'p' || t === 'a' ([t]) => t === 'e' || t === 'p' || t === 'a'
) )
let zap = { let zap: EventTemplate<9735> = {
kind: 9735, kind: 9735,
created_at: Math.round(paidAt.getTime() / 1000), created_at: Math.round(paidAt.getTime() / 1000),
content: '', content: '',

View File

@ -21,8 +21,8 @@ export function normalizeURL(url: string): string {
// fast insert-into-sorted-array functions adapted from https://github.com/terrymorse58/fast-sorted-array // fast insert-into-sorted-array functions adapted from https://github.com/terrymorse58/fast-sorted-array
// //
export function insertEventIntoDescendingList( export function insertEventIntoDescendingList(
sortedArray: Event[], sortedArray: Event<number>[],
event: Event event: Event<number>
) { ) {
let start = 0 let start = 0
let end = sortedArray.length - 1 let end = sortedArray.length - 1
@ -66,8 +66,8 @@ export function insertEventIntoDescendingList(
} }
export function insertEventIntoAscendingList( export function insertEventIntoAscendingList(
sortedArray: Event[], sortedArray: Event<number>[],
event: Event event: Event<number>
) { ) {
let start = 0 let start = 0
let end = sortedArray.length - 1 let end = sortedArray.length - 1