mirror of
https://github.com/dergigi/boris.git
synced 2025-12-18 15:14:20 +01:00
feat: initialize markr nostr bookmark client
- Add project structure with TypeScript, React, and Vite - Implement nostr authentication using browser extension (NIP-07) - Add NIP-51 compliant bookmark fetching and display - Create minimal UI with login and bookmark components - Integrate applesauce-core and applesauce-react libraries - Add responsive styling with dark/light mode support - Include comprehensive README with setup instructions This is a minimal MVP for a nostr bookmark client that allows users to view their bookmarks according to NIP-51 specification.
This commit is contained in:
21
node_modules/applesauce-content/LICENSE
generated
vendored
Normal file
21
node_modules/applesauce-content/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 hzrd149
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
32
node_modules/applesauce-content/README.md
generated
vendored
Normal file
32
node_modules/applesauce-content/README.md
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# applesauce-content
|
||||
|
||||
applesauce package for parsing text note content
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
import { getParsedContent } from "applesauce-content/text";
|
||||
|
||||
const stringContent = `
|
||||
hello nostr!
|
||||
nostr:npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6
|
||||
`;
|
||||
const ats = getParsedContent(stringContent);
|
||||
|
||||
console.log(ats);
|
||||
/*
|
||||
{
|
||||
type: 'root',
|
||||
event: undefined,
|
||||
children: [
|
||||
{ type: 'text', value: 'hello nostr!' },
|
||||
{ type: 'text', value: '\n' },
|
||||
{
|
||||
type: 'mention',
|
||||
decoded: [Object],
|
||||
encoded: 'npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6'
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
```
|
||||
2
node_modules/applesauce-content/dist/helpers/index.d.ts
generated
vendored
Normal file
2
node_modules/applesauce-content/dist/helpers/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./regexp.js";
|
||||
export * from "./media.js";
|
||||
2
node_modules/applesauce-content/dist/helpers/index.js
generated
vendored
Normal file
2
node_modules/applesauce-content/dist/helpers/index.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./regexp.js";
|
||||
export * from "./media.js";
|
||||
3
node_modules/applesauce-content/dist/helpers/media.d.ts
generated
vendored
Normal file
3
node_modules/applesauce-content/dist/helpers/media.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { MediaAttachment } from "applesauce-core/helpers/file-metadata";
|
||||
/** Returns all URLs in a content string that contain a sha256 hash */
|
||||
export declare function getMediaAttachmentURLsFromContent(content: string): MediaAttachment[];
|
||||
15
node_modules/applesauce-content/dist/helpers/media.js
generated
vendored
Normal file
15
node_modules/applesauce-content/dist/helpers/media.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { getSha256FromURL } from "applesauce-core/helpers/file-metadata";
|
||||
import { Tokens } from "./regexp.js";
|
||||
/** Returns all URLs in a content string that contain a sha256 hash */
|
||||
export function getMediaAttachmentURLsFromContent(content) {
|
||||
return (Array.from(content.matchAll(Tokens.link))
|
||||
.map((match) => match[0])
|
||||
// filter out invalid URLs
|
||||
.filter((str) => URL.canParse(str))
|
||||
// convert to URLs
|
||||
.map((url) => new URL(url))
|
||||
// only keep urls with sha256 hashes in the
|
||||
.filter((url) => !!getSha256FromURL(url))
|
||||
// convert to media attachments
|
||||
.map((url) => ({ url: url.toString(), sha256: getSha256FromURL(url) })));
|
||||
}
|
||||
19
node_modules/applesauce-content/dist/helpers/regexp.d.ts
generated
vendored
Normal file
19
node_modules/applesauce-content/dist/helpers/regexp.d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export declare const Expressions: {
|
||||
readonly url: RegExp;
|
||||
readonly link: RegExp;
|
||||
readonly cashu: RegExp;
|
||||
readonly nostrLink: RegExp;
|
||||
readonly emoji: RegExp;
|
||||
readonly hashtag: RegExp;
|
||||
readonly lightning: RegExp;
|
||||
};
|
||||
/** A list of Regular Expressions that match tokens surrounded by whitespace to avoid matching in URLs */
|
||||
export declare const Tokens: {
|
||||
readonly url: RegExp;
|
||||
readonly link: RegExp;
|
||||
readonly cashu: RegExp;
|
||||
readonly nostrLink: RegExp;
|
||||
readonly emoji: RegExp;
|
||||
readonly hashtag: RegExp;
|
||||
readonly lightning: RegExp;
|
||||
};
|
||||
48
node_modules/applesauce-content/dist/helpers/regexp.js
generated
vendored
Normal file
48
node_modules/applesauce-content/dist/helpers/regexp.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
export const Expressions = {
|
||||
get url() {
|
||||
return /(?:https?|wss?|ircs?|s?ftp):\/\/([a-zA-Z0-9\.\-]+\.[a-zA-Z]+(?::\d+)?)([\/\?#][\p{L}\p{N}\p{M}&\.-\/\?=#\-@%\+_,:!~*]*)?/gu;
|
||||
},
|
||||
get link() {
|
||||
return /https?:\/\/([a-zA-Z0-9\.\-]+\.[a-zA-Z]+(?::\d+)?)([\/\?#][\p{L}\p{N}\p{M}&\.-\/\?=#\-@%\+_,:!~*]*)?/gu;
|
||||
},
|
||||
get cashu() {
|
||||
return /(?:cashu:\/{0,2})?(cashu(?:A|B)[A-Za-z0-9_-]{100,}={0,3})/gi;
|
||||
},
|
||||
get nostrLink() {
|
||||
return /(?:nostr:)?((npub|note|nprofile|nevent|naddr)1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58,})/gi;
|
||||
},
|
||||
get emoji() {
|
||||
return /:([a-zA-Z0-9_-]+):/gi;
|
||||
},
|
||||
get hashtag() {
|
||||
// NOTE: cant use \b here because it uses \w which only matches latin letters
|
||||
return /(?<=^|[^\p{L}#\/])#([\p{L}\p{N}\p{M}]+)(?=\p{Z}|$|\s)/gu;
|
||||
},
|
||||
get lightning() {
|
||||
return /(?:lightning:)?(LNBC[A-Za-z0-9]+)/gim;
|
||||
},
|
||||
};
|
||||
/** A list of Regular Expressions that match tokens surrounded by whitespace to avoid matching in URLs */
|
||||
export const Tokens = {
|
||||
get url() {
|
||||
return Expressions.url;
|
||||
},
|
||||
get link() {
|
||||
return Expressions.link;
|
||||
},
|
||||
get cashu() {
|
||||
return new RegExp(`(?<=^|\\s)${Expressions.cashu.source}`, "gi");
|
||||
},
|
||||
get nostrLink() {
|
||||
return new RegExp(`(?<=^|\\s)${Expressions.nostrLink.source}`, "gi");
|
||||
},
|
||||
get emoji() {
|
||||
return Expressions.emoji;
|
||||
},
|
||||
get hashtag() {
|
||||
return Expressions.hashtag;
|
||||
},
|
||||
get lightning() {
|
||||
return new RegExp(`(?<=^|\\s)${Expressions.lightning.source}`, "gim");
|
||||
},
|
||||
};
|
||||
4
node_modules/applesauce-content/dist/index.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * as Text from "./text/index.js";
|
||||
export * as Nast from "./nast/index.js";
|
||||
export * as Markdown from "./markdown/index.js";
|
||||
export * as Helpers from "./helpers/index.js";
|
||||
4
node_modules/applesauce-content/dist/index.js
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * as Text from "./text/index.js";
|
||||
export * as Nast from "./nast/index.js";
|
||||
export * as Markdown from "./markdown/index.js";
|
||||
export * as Helpers from "./helpers/index.js";
|
||||
1
node_modules/applesauce-content/dist/markdown/index.d.ts
generated
vendored
Normal file
1
node_modules/applesauce-content/dist/markdown/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./mentions.js";
|
||||
1
node_modules/applesauce-content/dist/markdown/index.js
generated
vendored
Normal file
1
node_modules/applesauce-content/dist/markdown/index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./mentions.js";
|
||||
8
node_modules/applesauce-content/dist/markdown/mentions.d.ts
generated
vendored
Normal file
8
node_modules/applesauce-content/dist/markdown/mentions.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { DecodeResult } from "applesauce-core/helpers";
|
||||
import { Link, Nodes } from "mdast";
|
||||
import { Transformer } from "unified";
|
||||
export interface NostrMention extends Link {
|
||||
type: "link";
|
||||
data: DecodeResult;
|
||||
}
|
||||
export declare function remarkNostrMentions(): Transformer<Nodes>;
|
||||
22
node_modules/applesauce-content/dist/markdown/mentions.js
generated
vendored
Normal file
22
node_modules/applesauce-content/dist/markdown/mentions.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { findAndReplace } from "mdast-util-find-and-replace";
|
||||
import { decode } from "nostr-tools/nip19";
|
||||
import { Tokens } from "../helpers/regexp.js";
|
||||
export function remarkNostrMentions() {
|
||||
return (tree) => {
|
||||
findAndReplace(tree, [
|
||||
Tokens.nostrLink,
|
||||
(_, $1) => {
|
||||
try {
|
||||
return {
|
||||
type: "link",
|
||||
data: decode($1),
|
||||
children: [],
|
||||
url: "nostr:" + $1,
|
||||
};
|
||||
}
|
||||
catch (error) { }
|
||||
return false;
|
||||
},
|
||||
]);
|
||||
};
|
||||
}
|
||||
3
node_modules/applesauce-content/dist/nast/eol-metadata.d.ts
generated
vendored
Normal file
3
node_modules/applesauce-content/dist/nast/eol-metadata.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Transformer } from "unified";
|
||||
import { Root } from "../nast/types.js";
|
||||
export declare function eolMetadata(): Transformer<Root>;
|
||||
14
node_modules/applesauce-content/dist/nast/eol-metadata.js
generated
vendored
Normal file
14
node_modules/applesauce-content/dist/nast/eol-metadata.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
export function eolMetadata() {
|
||||
return (tree) => {
|
||||
for (let i = 0; i < tree.children.length; i++) {
|
||||
const node = tree.children[i];
|
||||
const next = tree.children[i + 1];
|
||||
if ((node.type === "text" && node.value.endsWith("\n")) ||
|
||||
!next ||
|
||||
(next.type === "text" && next.value.startsWith("\n"))) {
|
||||
node.data = node.data || {};
|
||||
node.data.eol = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
6
node_modules/applesauce-content/dist/nast/find-and-replace.d.ts
generated
vendored
Normal file
6
node_modules/applesauce-content/dist/nast/find-and-replace.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Content, Root } from "./types.js";
|
||||
type Replace = (...groups: string[]) => null | undefined | false | string | Content | Content[];
|
||||
type FindAndReplaceTuple = [RegExp, Replace];
|
||||
type FindAndReplaceList = FindAndReplaceTuple[];
|
||||
export declare function findAndReplace(tree: Root, list: FindAndReplaceList): void;
|
||||
export {};
|
||||
95
node_modules/applesauce-content/dist/nast/find-and-replace.js
generated
vendored
Normal file
95
node_modules/applesauce-content/dist/nast/find-and-replace.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import { visitParents } from "unist-util-visit-parents";
|
||||
export function findAndReplace(tree, list) {
|
||||
const pairs = list;
|
||||
let pairIndex = -1;
|
||||
const visitor = (node, parents) => {
|
||||
let index = -1;
|
||||
/** @type {Parents | undefined} */
|
||||
let grandparent;
|
||||
while (++index < parents.length) {
|
||||
const parent = parents[index];
|
||||
// const siblings = grandparent ? grandparent.children : undefined;
|
||||
grandparent = parent;
|
||||
}
|
||||
if (grandparent) {
|
||||
return handler(node, parents);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
while (++pairIndex < pairs.length) {
|
||||
visitParents(tree, "text", visitor);
|
||||
}
|
||||
/**
|
||||
* Handle a text node which is not in an ignored parent.
|
||||
*
|
||||
* @param {Text} node
|
||||
* Text node.
|
||||
* @param {Array<Parents>} parents
|
||||
* Parents.
|
||||
* @returns {VisitorResult}
|
||||
* Result.
|
||||
*/
|
||||
function handler(node, parents) {
|
||||
const parent = parents[parents.length - 1];
|
||||
const find = pairs[pairIndex][0];
|
||||
const replace = pairs[pairIndex][1];
|
||||
let start = 0;
|
||||
const siblings = parent.children;
|
||||
const index = siblings.indexOf(node);
|
||||
let change = false;
|
||||
let nodes = [];
|
||||
find.lastIndex = 0;
|
||||
let match = find.exec(node.value);
|
||||
while (match) {
|
||||
const position = match.index;
|
||||
/** @type {RegExpMatchObject} */
|
||||
// const matchObject = {
|
||||
// index: match.index,
|
||||
// input: match.input,
|
||||
// stack: [...parents, node],
|
||||
// };
|
||||
// let value = replace(...match, matchObject);
|
||||
let value = replace(...match);
|
||||
if (typeof value === "string") {
|
||||
value = value.length > 0 ? { type: "text", value } : undefined;
|
||||
}
|
||||
// It wasn’t a match after all.
|
||||
if (value === false) {
|
||||
// False acts as if there was no match.
|
||||
// So we need to reset `lastIndex`, which currently being at the end of
|
||||
// the current match, to the beginning.
|
||||
find.lastIndex = position + 1;
|
||||
}
|
||||
else {
|
||||
if (start !== position) {
|
||||
nodes.push({
|
||||
type: "text",
|
||||
value: node.value.slice(start, position),
|
||||
});
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
nodes.push(...value);
|
||||
}
|
||||
else if (value) {
|
||||
nodes.push(value);
|
||||
}
|
||||
start = position + match[0].length;
|
||||
change = true;
|
||||
}
|
||||
if (!find.global) {
|
||||
break;
|
||||
}
|
||||
match = find.exec(node.value);
|
||||
}
|
||||
if (change) {
|
||||
if (start < node.value.length) {
|
||||
nodes.push({ type: "text", value: node.value.slice(start) });
|
||||
}
|
||||
parent.children.splice(index, 1, ...nodes);
|
||||
}
|
||||
else {
|
||||
nodes = [node];
|
||||
}
|
||||
return index + nodes.length;
|
||||
}
|
||||
}
|
||||
4
node_modules/applesauce-content/dist/nast/index.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/nast/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./types.js";
|
||||
export * from "./find-and-replace.js";
|
||||
export * from "./eol-metadata.js";
|
||||
export * from "./truncate.js";
|
||||
4
node_modules/applesauce-content/dist/nast/index.js
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/nast/index.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./types.js";
|
||||
export * from "./find-and-replace.js";
|
||||
export * from "./eol-metadata.js";
|
||||
export * from "./truncate.js";
|
||||
2
node_modules/applesauce-content/dist/nast/truncate.d.ts
generated
vendored
Normal file
2
node_modules/applesauce-content/dist/nast/truncate.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { Root } from "./types.js";
|
||||
export declare function truncateContent(tree: Root, maxLength?: number): Root;
|
||||
48
node_modules/applesauce-content/dist/nast/truncate.js
generated
vendored
Normal file
48
node_modules/applesauce-content/dist/nast/truncate.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
export function truncateContent(tree, maxLength = 256) {
|
||||
let length = 0;
|
||||
for (let i = 0; i < tree.children.length; i++) {
|
||||
const node = tree.children[i];
|
||||
switch (node.type) {
|
||||
case "hashtag":
|
||||
length += 1 + node.hashtag.length;
|
||||
break;
|
||||
case "mention":
|
||||
// guess user names are about 10 long
|
||||
length += 10;
|
||||
break;
|
||||
case "cashu":
|
||||
length += node.raw.length;
|
||||
break;
|
||||
case "gallery":
|
||||
length += node.links.reduce((t, l) => t + l.length, 0);
|
||||
break;
|
||||
case "link":
|
||||
case "text":
|
||||
length += node.value.length;
|
||||
break;
|
||||
case "emoji":
|
||||
length += 1;
|
||||
break;
|
||||
}
|
||||
if (length > maxLength) {
|
||||
if (node.type === "text") {
|
||||
const children = i > 0 ? tree.children.slice(0, i) : [];
|
||||
const chunkLength = node.value.length - (length - maxLength);
|
||||
// find the nearest newline
|
||||
const newLines = node.value.matchAll(/\n/g);
|
||||
for (const match of newLines) {
|
||||
if (match.index && match.index > chunkLength) {
|
||||
children.push({ type: "text", value: node.value.slice(0, match.index) });
|
||||
return { ...tree, children, truncated: true };
|
||||
}
|
||||
}
|
||||
// just cut the string
|
||||
children.push({ type: "text", value: node.value.slice(0, maxLength - length) });
|
||||
return { ...tree, children, truncated: true };
|
||||
}
|
||||
else
|
||||
return { ...tree, children: tree.children.slice(0, i), truncated: true };
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
72
node_modules/applesauce-content/dist/nast/types.d.ts
generated
vendored
Normal file
72
node_modules/applesauce-content/dist/nast/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
import { type Token } from "@cashu/cashu-ts";
|
||||
import { type DecodeResult } from "applesauce-core/helpers";
|
||||
import { type ParsedInvoice } from "applesauce-core/helpers/bolt11";
|
||||
import { type EventTemplate, type NostrEvent } from "nostr-tools";
|
||||
import { type Parent, type Node as UnistNode } from "unist";
|
||||
export interface CommonData {
|
||||
eol?: boolean;
|
||||
}
|
||||
export interface Node extends Omit<UnistNode, "data"> {
|
||||
data?: CommonData;
|
||||
}
|
||||
export interface Text extends Node {
|
||||
type: "text";
|
||||
value: string;
|
||||
}
|
||||
export interface Link extends Node {
|
||||
type: "link";
|
||||
value: string;
|
||||
href: string;
|
||||
}
|
||||
export interface Gallery extends Node {
|
||||
type: "gallery";
|
||||
links: string[];
|
||||
}
|
||||
export interface Mention extends Node {
|
||||
type: "mention";
|
||||
decoded: DecodeResult;
|
||||
encoded: string;
|
||||
}
|
||||
export interface CashuToken extends Node {
|
||||
type: "cashu";
|
||||
token: Token;
|
||||
raw: string;
|
||||
}
|
||||
export interface LightningInvoice extends Node {
|
||||
type: "lightning";
|
||||
invoice: string;
|
||||
parsed: ParsedInvoice;
|
||||
}
|
||||
export interface Hashtag extends Node {
|
||||
type: "hashtag";
|
||||
/** The name as it was written in the event */
|
||||
name: string;
|
||||
/** The lowercase canonical name */
|
||||
hashtag: string;
|
||||
/** The indexable tag for the hashtag. will be undefined if none was found */
|
||||
tag?: ["t", ...string[]];
|
||||
}
|
||||
export interface Emoji extends Node {
|
||||
type: "emoji";
|
||||
code: string;
|
||||
raw: string;
|
||||
url: string;
|
||||
tag: ["emoji", ...string[]];
|
||||
}
|
||||
export interface ContentMap {
|
||||
text: Text;
|
||||
link: Link;
|
||||
mention: Mention;
|
||||
cashu: CashuToken;
|
||||
lightning: LightningInvoice;
|
||||
hashtag: Hashtag;
|
||||
emoji: Emoji;
|
||||
gallery: Gallery;
|
||||
}
|
||||
export type Content = ContentMap[keyof ContentMap];
|
||||
export interface Root extends Parent {
|
||||
type: "root";
|
||||
children: Content[];
|
||||
event?: NostrEvent | EventTemplate;
|
||||
truncated?: boolean;
|
||||
}
|
||||
1
node_modules/applesauce-content/dist/nast/types.js
generated
vendored
Normal file
1
node_modules/applesauce-content/dist/nast/types.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
4
node_modules/applesauce-content/dist/text/cashu.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/text/cashu.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Transformer } from "unified";
|
||||
import { Root } from "../nast/types.js";
|
||||
/** Parse cashu tokens from an ATS tree */
|
||||
export declare function cashuTokens(): Transformer<Root>;
|
||||
25
node_modules/applesauce-content/dist/text/cashu.js
generated
vendored
Normal file
25
node_modules/applesauce-content/dist/text/cashu.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { getDecodedToken } from "@cashu/cashu-ts";
|
||||
import { Tokens } from "../helpers/regexp.js";
|
||||
import { findAndReplace } from "../nast/find-and-replace.js";
|
||||
/** Parse cashu tokens from an ATS tree */
|
||||
export function cashuTokens() {
|
||||
return (tree) => {
|
||||
findAndReplace(tree, [
|
||||
[
|
||||
Tokens.cashu,
|
||||
(_, $1) => {
|
||||
try {
|
||||
const token = getDecodedToken($1);
|
||||
return {
|
||||
type: "cashu",
|
||||
token,
|
||||
raw: $1,
|
||||
};
|
||||
}
|
||||
catch (error) { }
|
||||
return false;
|
||||
},
|
||||
],
|
||||
]);
|
||||
};
|
||||
}
|
||||
9
node_modules/applesauce-content/dist/text/content.d.ts
generated
vendored
Normal file
9
node_modules/applesauce-content/dist/text/content.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Transformer } from "unified";
|
||||
import { EventTemplate, NostrEvent } from "nostr-tools";
|
||||
import { Root } from "../nast/types.js";
|
||||
import { galleries } from "./gallery.js";
|
||||
export declare const TextNoteContentSymbol: unique symbol;
|
||||
export declare const textNoteTransformers: (typeof galleries)[];
|
||||
/** Parsed and process a note with custom transformers */
|
||||
export declare function getParsedContent(event: NostrEvent | EventTemplate | string, content?: string, transformers?: (() => Transformer<Root>)[], cacheKey?: symbol | null | undefined): Root;
|
||||
export declare function removeParsedTextContent(event: NostrEvent | EventTemplate): void;
|
||||
53
node_modules/applesauce-content/dist/text/content.js
generated
vendored
Normal file
53
node_modules/applesauce-content/dist/text/content.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
import { unified } from "unified";
|
||||
import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
|
||||
import { nostrMentions } from "./mentions.js";
|
||||
import { cashuTokens } from "./cashu.js";
|
||||
import { emojis } from "./emoji.js";
|
||||
import { createEventContentTree } from "./parser.js";
|
||||
import { hashtags } from "./hashtag.js";
|
||||
import { galleries } from "./gallery.js";
|
||||
import { lightningInvoices } from "./lightning.js";
|
||||
import { eolMetadata } from "../nast/eol-metadata.js";
|
||||
import { links } from "./links.js";
|
||||
export const TextNoteContentSymbol = Symbol.for("text-note-content");
|
||||
// default kind 1 transformers
|
||||
export const textNoteTransformers = [
|
||||
links,
|
||||
nostrMentions,
|
||||
galleries,
|
||||
emojis,
|
||||
hashtags,
|
||||
lightningInvoices,
|
||||
cashuTokens,
|
||||
eolMetadata,
|
||||
];
|
||||
/** Parsed and process a note with custom transformers */
|
||||
export function getParsedContent(event, content, transformers = textNoteTransformers, cacheKey = TextNoteContentSymbol) {
|
||||
// process strings
|
||||
if (typeof event === "string") {
|
||||
const processor = unified();
|
||||
for (const transformer of transformers) {
|
||||
processor.use(transformer);
|
||||
}
|
||||
return processor.runSync(createEventContentTree(event, content));
|
||||
}
|
||||
// no caching
|
||||
if (!cacheKey) {
|
||||
const processor = unified();
|
||||
for (const transformer of transformers) {
|
||||
processor.use(transformer);
|
||||
}
|
||||
return processor.runSync(createEventContentTree(event, content));
|
||||
}
|
||||
return getOrComputeCachedValue(event, cacheKey, () => {
|
||||
const processor = unified();
|
||||
for (const transformer of transformers) {
|
||||
processor.use(transformer);
|
||||
}
|
||||
return processor.runSync(createEventContentTree(event, content));
|
||||
});
|
||||
}
|
||||
export function removeParsedTextContent(event) {
|
||||
// @ts-expect-error
|
||||
delete event[TextNoteContentSymbol];
|
||||
}
|
||||
4
node_modules/applesauce-content/dist/text/emoji.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/text/emoji.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { type Transformer } from "unified";
|
||||
import { Root } from "../nast/types.js";
|
||||
/** Finds and creates emoji nodes in the tree */
|
||||
export declare function emojis(): Transformer<Root>;
|
||||
32
node_modules/applesauce-content/dist/text/emoji.js
generated
vendored
Normal file
32
node_modules/applesauce-content/dist/text/emoji.js
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import { getEmojiTag } from "applesauce-core/helpers/emoji";
|
||||
import { Tokens } from "../helpers/regexp.js";
|
||||
import { findAndReplace } from "../nast/find-and-replace.js";
|
||||
/** Finds and creates emoji nodes in the tree */
|
||||
export function emojis() {
|
||||
return (tree) => {
|
||||
const event = tree.event;
|
||||
if (!event)
|
||||
return;
|
||||
findAndReplace(tree, [
|
||||
[
|
||||
Tokens.emoji,
|
||||
(full, $1) => {
|
||||
try {
|
||||
const tag = getEmojiTag(event, $1);
|
||||
if (!tag)
|
||||
return false;
|
||||
return {
|
||||
type: "emoji",
|
||||
tag,
|
||||
raw: full,
|
||||
code: tag[1].toLowerCase(),
|
||||
url: tag[2],
|
||||
};
|
||||
}
|
||||
catch (error) { }
|
||||
return false;
|
||||
},
|
||||
],
|
||||
]);
|
||||
};
|
||||
}
|
||||
4
node_modules/applesauce-content/dist/text/gallery.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/text/gallery.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Transformer } from "unified";
|
||||
import { Root } from "../nast/types.js";
|
||||
/** Group images into galleries in an ATS tree */
|
||||
export declare function galleries(types?: string[]): Transformer<Root>;
|
||||
48
node_modules/applesauce-content/dist/text/gallery.js
generated
vendored
Normal file
48
node_modules/applesauce-content/dist/text/gallery.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import { convertToUrl, getURLFilename, IMAGE_EXT } from "applesauce-core/helpers/url";
|
||||
/** Group images into galleries in an ATS tree */
|
||||
export function galleries(types = IMAGE_EXT) {
|
||||
return (tree) => {
|
||||
let links = [];
|
||||
const commit = (index) => {
|
||||
// only create a gallery if there are more than a single image
|
||||
if (links.length > 1) {
|
||||
const start = tree.children.indexOf(links[0]);
|
||||
const end = tree.children.indexOf(links[links.length - 1]);
|
||||
// replace all nodes with a gallery
|
||||
tree.children.splice(start, 1 + end - start, { type: "gallery", links: links.map((l) => l.href) });
|
||||
links = [];
|
||||
// return new cursor
|
||||
return end - 1;
|
||||
}
|
||||
else {
|
||||
links = [];
|
||||
return index;
|
||||
}
|
||||
};
|
||||
for (let i = 0; i < tree.children.length; i++) {
|
||||
const node = tree.children[i];
|
||||
try {
|
||||
if (node.type === "link") {
|
||||
const url = convertToUrl(node.href);
|
||||
const filename = getURLFilename(url);
|
||||
if (filename && types.some((ext) => filename.endsWith(ext))) {
|
||||
links.push(node);
|
||||
}
|
||||
else {
|
||||
i = commit(i);
|
||||
}
|
||||
}
|
||||
else if (node.type === "text" && links.length > 0) {
|
||||
const isEmpty = node.value === "\n" || !node.value.match(/[^\s]/g);
|
||||
if (!isEmpty)
|
||||
i = commit(i);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
i = commit(i);
|
||||
}
|
||||
}
|
||||
// Do one finally commit, just in case a link is the last element in the list
|
||||
commit(tree.children.length);
|
||||
};
|
||||
}
|
||||
4
node_modules/applesauce-content/dist/text/hashtag.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/text/hashtag.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Transformer } from "unified";
|
||||
import { Root } from "../nast/types.js";
|
||||
/** Find and create hashtag notes in provided tree */
|
||||
export declare function hashtags(): Transformer<Root>;
|
||||
30
node_modules/applesauce-content/dist/text/hashtag.js
generated
vendored
Normal file
30
node_modules/applesauce-content/dist/text/hashtag.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { getHashtagTag } from "applesauce-core/helpers/hashtag";
|
||||
import { Tokens } from "../helpers/regexp.js";
|
||||
import { findAndReplace } from "../nast/find-and-replace.js";
|
||||
/** Find and create hashtag notes in provided tree */
|
||||
export function hashtags() {
|
||||
return (tree) => {
|
||||
const event = tree.event;
|
||||
findAndReplace(tree, [
|
||||
[
|
||||
Tokens.hashtag,
|
||||
(_, $1) => {
|
||||
try {
|
||||
const tag = event && getHashtagTag(event, $1);
|
||||
// Skip if the match if no tag was found in the event
|
||||
if (!tag && event)
|
||||
return false;
|
||||
return {
|
||||
type: "hashtag",
|
||||
tag,
|
||||
name: $1,
|
||||
hashtag: tag?.[1].toLowerCase() || $1.toLowerCase(),
|
||||
};
|
||||
}
|
||||
catch (error) { }
|
||||
return false;
|
||||
},
|
||||
],
|
||||
]);
|
||||
};
|
||||
}
|
||||
9
node_modules/applesauce-content/dist/text/index.d.ts
generated
vendored
Normal file
9
node_modules/applesauce-content/dist/text/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
export * from "./content.js";
|
||||
export * from "./links.js";
|
||||
export * from "./mentions.js";
|
||||
export * from "./cashu.js";
|
||||
export * from "./emoji.js";
|
||||
export * from "./parser.js";
|
||||
export * from "./hashtag.js";
|
||||
export * from "./gallery.js";
|
||||
export * from "./lightning.js";
|
||||
9
node_modules/applesauce-content/dist/text/index.js
generated
vendored
Normal file
9
node_modules/applesauce-content/dist/text/index.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
export * from "./content.js";
|
||||
export * from "./links.js";
|
||||
export * from "./mentions.js";
|
||||
export * from "./cashu.js";
|
||||
export * from "./emoji.js";
|
||||
export * from "./parser.js";
|
||||
export * from "./hashtag.js";
|
||||
export * from "./gallery.js";
|
||||
export * from "./lightning.js";
|
||||
4
node_modules/applesauce-content/dist/text/lightning.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/text/lightning.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { type Transformer } from "unified";
|
||||
import { Root } from "../nast/types.js";
|
||||
/** Finds and creates lightning invoice nodes in the tree */
|
||||
export declare function lightningInvoices(): Transformer<Root>;
|
||||
26
node_modules/applesauce-content/dist/text/lightning.js
generated
vendored
Normal file
26
node_modules/applesauce-content/dist/text/lightning.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import { parseBolt11 } from "applesauce-core/helpers/bolt11";
|
||||
import { Tokens } from "../helpers/regexp.js";
|
||||
import { findAndReplace } from "../nast/find-and-replace.js";
|
||||
/** Finds and creates lightning invoice nodes in the tree */
|
||||
export function lightningInvoices() {
|
||||
return (tree) => {
|
||||
findAndReplace(tree, [
|
||||
[
|
||||
Tokens.lightning,
|
||||
(_, $1) => {
|
||||
try {
|
||||
const invoice = $1;
|
||||
const parsed = parseBolt11(invoice);
|
||||
return {
|
||||
type: "lightning",
|
||||
invoice,
|
||||
parsed,
|
||||
};
|
||||
}
|
||||
catch (error) { }
|
||||
return false;
|
||||
},
|
||||
],
|
||||
]);
|
||||
};
|
||||
}
|
||||
4
node_modules/applesauce-content/dist/text/links.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/text/links.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Transformer } from "unified";
|
||||
import { Root } from "../nast/types.js";
|
||||
/** Finds and creates web links in the tree */
|
||||
export declare function links(): Transformer<Root>;
|
||||
23
node_modules/applesauce-content/dist/text/links.js
generated
vendored
Normal file
23
node_modules/applesauce-content/dist/text/links.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Tokens } from "../helpers/regexp.js";
|
||||
import { findAndReplace } from "../nast/find-and-replace.js";
|
||||
/** Finds and creates web links in the tree */
|
||||
export function links() {
|
||||
return (tree) => {
|
||||
findAndReplace(tree, [
|
||||
[
|
||||
Tokens.link,
|
||||
(_) => {
|
||||
try {
|
||||
return {
|
||||
type: "link",
|
||||
href: new URL(_).toString(),
|
||||
value: _,
|
||||
};
|
||||
}
|
||||
catch (error) { }
|
||||
return false;
|
||||
},
|
||||
],
|
||||
]);
|
||||
};
|
||||
}
|
||||
4
node_modules/applesauce-content/dist/text/mentions.d.ts
generated
vendored
Normal file
4
node_modules/applesauce-content/dist/text/mentions.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Transformer } from "unified";
|
||||
import { Root } from "../nast/types.js";
|
||||
/** Finds and creates NIP-19 nostr mentions in the tree */
|
||||
export declare function nostrMentions(): Transformer<Root>;
|
||||
24
node_modules/applesauce-content/dist/text/mentions.js
generated
vendored
Normal file
24
node_modules/applesauce-content/dist/text/mentions.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { decode } from "nostr-tools/nip19";
|
||||
import { Tokens } from "../helpers/regexp.js";
|
||||
import { findAndReplace } from "../nast/find-and-replace.js";
|
||||
/** Finds and creates NIP-19 nostr mentions in the tree */
|
||||
export function nostrMentions() {
|
||||
return (tree) => {
|
||||
findAndReplace(tree, [
|
||||
[
|
||||
Tokens.nostrLink,
|
||||
(_, $1) => {
|
||||
try {
|
||||
return {
|
||||
type: "mention",
|
||||
decoded: decode($1),
|
||||
encoded: $1,
|
||||
};
|
||||
}
|
||||
catch (error) { }
|
||||
return false;
|
||||
},
|
||||
],
|
||||
]);
|
||||
};
|
||||
}
|
||||
6
node_modules/applesauce-content/dist/text/parser.d.ts
generated
vendored
Normal file
6
node_modules/applesauce-content/dist/text/parser.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { EventTemplate, NostrEvent } from "nostr-tools";
|
||||
import { Root } from "../nast/types.js";
|
||||
/** Creates a {@link Root} ATS node for a text note */
|
||||
export declare function createEventContentTree(event: NostrEvent | EventTemplate | string, content?: string): Root;
|
||||
/** @deprecated use createEventContentTree instead */
|
||||
export declare const createTextNoteATS: typeof createEventContentTree;
|
||||
15
node_modules/applesauce-content/dist/text/parser.js
generated
vendored
Normal file
15
node_modules/applesauce-content/dist/text/parser.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/** Creates a {@link Root} ATS node for a text note */
|
||||
export function createEventContentTree(event, content) {
|
||||
return {
|
||||
type: "root",
|
||||
event: typeof event !== "string" ? event : undefined,
|
||||
children: [
|
||||
{
|
||||
type: "text",
|
||||
value: content || (typeof event === "string" ? event : event.content),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
/** @deprecated use createEventContentTree instead */
|
||||
export const createTextNoteATS = createEventContentTree;
|
||||
78
node_modules/applesauce-content/package.json
generated
vendored
Normal file
78
node_modules/applesauce-content/package.json
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"name": "applesauce-content",
|
||||
"version": "3.1.0",
|
||||
"description": "Unified plugins for processing event content",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"keywords": [
|
||||
"nostr",
|
||||
"applesauce"
|
||||
],
|
||||
"author": "hzrd149",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist",
|
||||
"applesauce"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"./helpers": {
|
||||
"import": "./dist/helpers/index.js",
|
||||
"require": "./dist/helpers/index.js",
|
||||
"types": "./dist/helpers/index.d.ts"
|
||||
},
|
||||
"./helpers/*": {
|
||||
"import": "./dist/helpers/*.js",
|
||||
"require": "./dist/helpers/*.js",
|
||||
"types": "./dist/helpers/*.d.ts"
|
||||
},
|
||||
"./nast": {
|
||||
"import": "./dist/nast/index.js",
|
||||
"require": "./dist/nast/index.js",
|
||||
"types": "./dist/nast/index.d.ts"
|
||||
},
|
||||
"./markdown": {
|
||||
"import": "./dist/markdown/index.js",
|
||||
"require": "./dist/markdown/index.js",
|
||||
"types": "./dist/markdown/index.d.ts"
|
||||
},
|
||||
"./text": {
|
||||
"import": "./dist/text/index.js",
|
||||
"require": "./dist/text/index.js",
|
||||
"types": "./dist/text/index.d.ts"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@cashu/cashu-ts": "2.0.0-rc1",
|
||||
"@types/hast": "^3.0.4",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@types/unist": "^3.0.3",
|
||||
"applesauce-core": "^3.1.0",
|
||||
"mdast-util-find-and-replace": "^3.0.2",
|
||||
"nostr-tools": "~2.15",
|
||||
"remark": "^15.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"unified": "^11.0.5",
|
||||
"unist-util-visit-parents": "^6.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.3",
|
||||
"applesauce-signers": "^3.1.0",
|
||||
"vitest": "^3.2.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "lightning",
|
||||
"url": "lightning:nostrudel@geyser.fund"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"watch:build": "tsc --watch > /dev/null",
|
||||
"test": "vitest run --passWithNoTests",
|
||||
"watch:test": "vitest"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user