mirror of
https://github.com/dergigi/boris.git
synced 2026-01-20 15:24:58 +01:00
- Update all applesauce packages from 3.1.0 to 4.0.0 - Add applesauce-factory dependency - Version 4.0.0 includes app-data helpers needed for NIP-78
135 lines
5.4 KiB
JavaScript
135 lines
5.4 KiB
JavaScript
import { Expressions } from "applesauce-content/helpers";
|
|
import { EncryptedContentSymbol, getEncryptedContentEncryptionMethods, getPubkeyFromDecodeResult, } from "applesauce-core/helpers";
|
|
import { ensureProfilePointerTag } from "../helpers/common-tags.js";
|
|
import { getContentPointers } from "../helpers/content.js";
|
|
import { eventPipe, skip } from "../helpers/pipeline.js";
|
|
import { ensureQuoteEventPointerTag } from "../helpers/quote.js";
|
|
import { ensureNamedValueTag } from "../helpers/tag.js";
|
|
/** Override the event content */
|
|
export function setContent(content) {
|
|
return async (draft) => {
|
|
draft = { ...draft, content };
|
|
Reflect.deleteProperty(draft, EncryptedContentSymbol);
|
|
return draft;
|
|
};
|
|
}
|
|
/** Replaces any `@npub` or bare npub mentions with nostr: prefix */
|
|
export function repairNostrLinks() {
|
|
return (draft) => ({
|
|
...draft,
|
|
content: draft.content.replaceAll(/(?<=^|\s)(?:@)?((?:npub|note|nprofile|nevent|naddr)1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58})/gi, "nostr:$1"),
|
|
});
|
|
}
|
|
/** "p" tag any pubkey mentioned in the content using nostr: links */
|
|
export function tagPubkeyMentions() {
|
|
return (draft) => {
|
|
let tags = Array.from(draft.tags);
|
|
const mentions = getContentPointers(draft.content);
|
|
for (const mention of mentions) {
|
|
const pubkey = getPubkeyFromDecodeResult(mention);
|
|
if (pubkey)
|
|
tags = ensureProfilePointerTag(tags, mention.type === "nprofile" ? mention.data : { pubkey });
|
|
}
|
|
return { ...draft, tags };
|
|
};
|
|
}
|
|
/** Sets the NIP-36 content-warning tag */
|
|
export function setContentWarning(warning) {
|
|
return (draft) => {
|
|
let tags = Array.from(draft.tags);
|
|
// remove existing content warning
|
|
tags = tags.filter((t) => t[0] !== "content-warning");
|
|
if (typeof warning === "string")
|
|
tags.push(["content-warning", warning]);
|
|
else if (warning === true)
|
|
tags.push(["content-warning"]);
|
|
return { ...draft, tags };
|
|
};
|
|
}
|
|
/** Include "q" quote tags for any nostr event mentioned in the content */
|
|
export function includeQuoteTags() {
|
|
return (draft) => {
|
|
let tags = Array.from(draft.tags);
|
|
const mentions = getContentPointers(draft.content);
|
|
for (const mention of mentions) {
|
|
switch (mention.type) {
|
|
case "note":
|
|
tags = ensureQuoteEventPointerTag(tags, { id: mention.data });
|
|
break;
|
|
case "nevent":
|
|
tags = ensureQuoteEventPointerTag(tags, mention.data);
|
|
break;
|
|
}
|
|
}
|
|
return { ...draft, tags };
|
|
};
|
|
}
|
|
/** Adds "t" tags for every #hashtag in the content */
|
|
export function includeContentHashtags() {
|
|
return (draft) => {
|
|
let tags = Array.from(draft.tags);
|
|
// create tags for all occurrences of #hashtag
|
|
const matches = draft.content.matchAll(Expressions.hashtag);
|
|
for (const [_, hashtag] of matches) {
|
|
const lower = hashtag.toLocaleLowerCase();
|
|
tags = ensureNamedValueTag(tags, ["t", lower]);
|
|
}
|
|
return { ...draft, tags };
|
|
};
|
|
}
|
|
/** Adds "emoji" tags for NIP-30 emojis used in the content */
|
|
export function includeEmojis(emojis) {
|
|
return (draft, ctx) => {
|
|
const all = [...(ctx.emojis ?? []), ...(emojis ?? [])];
|
|
const tags = Array.from(draft.tags);
|
|
// create tags for all occurrences of #hashtag
|
|
const matches = draft.content.matchAll(Expressions.emoji);
|
|
for (const [_, name] of matches) {
|
|
const emoji = all.find((e) => e.shortcode === name);
|
|
if (emoji?.url) {
|
|
tags.push(["emoji", emoji.shortcode, emoji.url]);
|
|
}
|
|
}
|
|
return { ...draft, tags };
|
|
};
|
|
}
|
|
/** Sets the text for a short text note and include hashtags and mentions */
|
|
export function setShortTextContent(content, options) {
|
|
return eventPipe(
|
|
// set text content
|
|
setContent(content),
|
|
// fix @ mentions
|
|
repairNostrLinks(),
|
|
// include "p" tags for pubkeys mentioned
|
|
tagPubkeyMentions(),
|
|
// include event "q" tags
|
|
includeQuoteTags(),
|
|
// include "t" tags for hashtags
|
|
includeContentHashtags(),
|
|
// include "emoji" tags
|
|
options?.emojis ? includeEmojis(options.emojis) : skip(),
|
|
// set "content-warning" tag
|
|
options?.contentWarning !== undefined ? setContentWarning(options.contentWarning) : skip());
|
|
}
|
|
/** Sets the content to be encrypted to the pubkey with optional override method */
|
|
export function setEncryptedContent(pubkey, content, override) {
|
|
return async (draft, { signer }) => {
|
|
if (!signer)
|
|
throw new Error("Signer required for encrypted content");
|
|
// Set method based on kind if not provided
|
|
const methods = getEncryptedContentEncryptionMethods(draft.kind, signer, override);
|
|
// add the plaintext content on the draft so it can be carried forward
|
|
const encrypted = await methods.encrypt(pubkey, content);
|
|
return { ...draft, content: encrypted, [EncryptedContentSymbol]: content };
|
|
};
|
|
}
|
|
/** Sets the hidden content on an event */
|
|
export function setHiddenContent(content, override) {
|
|
return async (draft, ctx) => {
|
|
if (!ctx.signer)
|
|
throw new Error("Signer required for encrypted content");
|
|
const pubkey = await ctx.signer.getPublicKey();
|
|
return setEncryptedContent(pubkey, content, override)(draft, ctx);
|
|
};
|
|
}
|