refactor: type events.ts, url.ts and crypto.ts
parent
5e75b64619
commit
67af695350
@ -0,0 +1,61 @@
|
|||||||
|
import {Event} from 'nostr-tools';
|
||||||
|
import {zeroLeadingBitsCount} from './utils';
|
||||||
|
|
||||||
|
export const isMention = ([tag, , , marker]: string[]) => tag === 'e' && marker === 'mention';
|
||||||
|
export const hasEventTag = (tag: string[]) => tag[0] === 'e';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate proof-of-work of a nostr event per nip-13.
|
||||||
|
* the validation always requires difficulty commitment in the nonce tag.
|
||||||
|
*
|
||||||
|
* @param {EventObj} evt event to validate
|
||||||
|
* TODO: @param {number} targetDifficulty target proof-of-work difficulty
|
||||||
|
*/
|
||||||
|
export const validatePow = (evt: Event) => {
|
||||||
|
const tag = evt.tags.find(tag => tag[0] === 'nonce');
|
||||||
|
if (!tag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const difficultyCommitment = Number(tag[2]);
|
||||||
|
if (!difficultyCommitment || Number.isNaN(difficultyCommitment)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return zeroLeadingBitsCount(evt.id) >= difficultyCommitment;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sortByCreatedAt = (evt1: Event, evt2: Event) => {
|
||||||
|
if (evt1.created_at === evt2.created_at) {
|
||||||
|
// console.log('TODO: OMG exactly at the same time, figure out how to sort then', evt1, evt2);
|
||||||
|
}
|
||||||
|
return evt1.created_at > evt2.created_at ? -1 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortEventCreatedAt = (created_at: number) => (
|
||||||
|
{created_at: a}: Event,
|
||||||
|
{created_at: b}: Event,
|
||||||
|
) => (
|
||||||
|
Math.abs(a - created_at) < Math.abs(b - created_at) ? -1 : 1
|
||||||
|
);
|
||||||
|
|
||||||
|
const isReply = ([tag, , , marker]: string[]) => tag === 'e' && marker !== 'mention';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find reply-to ID according to nip-10, find marked reply or root tag or
|
||||||
|
* fallback to positional (last) e tag or return null
|
||||||
|
* @param {event} evt
|
||||||
|
* @returns replyToID | null
|
||||||
|
*/
|
||||||
|
export const getReplyTo = (evt: Event): string | null => {
|
||||||
|
const eventTags = evt.tags.filter(isReply);
|
||||||
|
const withReplyMarker = eventTags.filter(([, , , marker]) => marker === 'reply');
|
||||||
|
if (withReplyMarker.length === 1) {
|
||||||
|
return withReplyMarker[0][1];
|
||||||
|
}
|
||||||
|
const withRootMarker = eventTags.filter(([, , , marker]) => marker === 'root');
|
||||||
|
if (withReplyMarker.length === 0 && withRootMarker.length === 1) {
|
||||||
|
return withRootMarker[0][1];
|
||||||
|
}
|
||||||
|
// fallback to deprecated positional 'e' tags (nip-10)
|
||||||
|
const lastTag = eventTags.at(-1);
|
||||||
|
return lastTag ? lastTag[1] : null;
|
||||||
|
};
|
@ -1,2 +1,4 @@
|
|||||||
|
export {zeroLeadingBitsCount} from './crypto';
|
||||||
export {elem, parseTextContent} from './dom';
|
export {elem, parseTextContent} from './dom';
|
||||||
export {bounce, dateTime, formatTime} from './time';
|
export {bounce, dateTime, formatTime} from './time';
|
||||||
|
export {getHost, getNoxyUrl, isHttpUrl, isWssUrl} from './url';
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
export const getHost = (url: string) => {
|
||||||
|
try {
|
||||||
|
return new URL(url).host;
|
||||||
|
} catch(err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isHttpUrl = (url: string) => {
|
||||||
|
try {
|
||||||
|
return ['http:', 'https:'].includes(new URL(url).protocol);
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isWssUrl = (url: string) => {
|
||||||
|
try {
|
||||||
|
return 'wss:' === new URL(url).protocol;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNoxyUrl = (
|
||||||
|
type: 'data' | 'meta',
|
||||||
|
url: string,
|
||||||
|
id: string,
|
||||||
|
relay: string,
|
||||||
|
) => {
|
||||||
|
if (!isHttpUrl(url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const link = new URL(`https://noxy.nostr.ch/${type}`);
|
||||||
|
link.searchParams.set('id', id);
|
||||||
|
link.searchParams.set('relay', relay);
|
||||||
|
link.searchParams.set('url', url);
|
||||||
|
return link;
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es2021"
|
"moduleResolution": "node",
|
||||||
|
"target": "es2022"
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
}
|
}
|
Loading…
Reference in New Issue