clone of repo on github
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

202 lines
6.3 KiB

import { get } from "svelte/store";
import { ndkInstance } from "../ndk.ts";
import { getMimeTags } from "../utils/mime.ts";
import { parseAsciiDocWithMetadata, metadataToTags } from "../utils/asciidoc_metadata.ts";
import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk";
import { nip19 } from "nostr-tools";
export interface PublishResult {
success: boolean;
eventId?: string;
error?: string;
}
export interface PublishOptions {
content: string;
kind?: number;
onSuccess?: (eventId: string) => void;
onError?: (error: string) => void;
}
/**
* Publishes AsciiDoc content as Nostr events
* @param options - Publishing options
* @returns Promise resolving to publish result
*/
export async function publishZettel(
options: PublishOptions,
): Promise<PublishResult> {
const { content, kind = 30041, onSuccess, onError } = options;
if (!content.trim()) {
const error = "Please enter some content";
onError?.(error);
return { success: false, error };
}
// Get the current NDK instance from the store
const ndk = get(ndkInstance);
if (!ndk?.activeUser) {
const error = "Please log in first";
onError?.(error);
return { success: false, error };
}
try {
// Parse content into sections using the standardized parser
const parsed = parseAsciiDocWithMetadata(content);
if (parsed.sections.length === 0) {
throw new Error("No valid sections found in content");
}
// For now, publish only the first section
const firstSection = parsed.sections[0];
const title = firstSection.title;
const cleanContent = firstSection.content;
const sectionTags = metadataToTags(firstSection.metadata);
// Generate d-tag and create event
const dTag = generateDTag(title);
const [mTag, MTag] = getMimeTags(kind);
const tags: string[][] = [["d", dTag], mTag, MTag, ["title", title]];
if (sectionTags) {
tags.push(...sectionTags);
}
// Create and sign NDK event
const ndkEvent = new NDKEvent(ndk);
ndkEvent.kind = kind;
ndkEvent.created_at = Math.floor(Date.now() / 1000);
ndkEvent.tags = tags;
ndkEvent.content = cleanContent;
ndkEvent.pubkey = ndk.activeUser.pubkey;
await ndkEvent.sign();
// Publish to relays
const allRelayUrls = Array.from(ndk.pool?.relays.values() || []).map(
(r) => r.url,
);
if (allRelayUrls.length === 0) {
throw new Error("No relays available in NDK pool");
}
const relaySet = NDKRelaySet.fromRelayUrls(allRelayUrls, ndk);
const publishedToRelays = await ndkEvent.publish(relaySet);
if (publishedToRelays.size > 0) {
const result = { success: true, eventId: ndkEvent.id };
onSuccess?.(ndkEvent.id);
return result;
} else {
// Try fallback publishing logic here...
throw new Error("Failed to publish to any relays");
}
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
onError?.(errorMessage);
return { success: false, error: errorMessage };
}
}
/**
* Publishes all AsciiDoc sections as separate Nostr events
* @param options - Publishing options
* @returns Promise resolving to array of publish results
*/
export async function publishMultipleZettels(
options: PublishOptions,
): Promise<PublishResult[]> {
const { content, kind = 30041, onError } = options;
if (!content.trim()) {
const error = 'Please enter some content';
onError?.(error);
return [{ success: false, error }];
}
const ndk = get(ndkInstance);
if (!ndk?.activeUser) {
const error = 'Please log in first';
onError?.(error);
return [{ success: false, error }];
}
try {
const parsed = parseAsciiDocWithMetadata(content);
if (parsed.sections.length === 0) {
throw new Error('No valid sections found in content');
}
const allRelayUrls = Array.from(ndk.pool?.relays.values() || []).map((r) => r.url);
if (allRelayUrls.length === 0) {
throw new Error('No relays available in NDK pool');
}
const relaySet = NDKRelaySet.fromRelayUrls(allRelayUrls, ndk);
const results: PublishResult[] = [];
const publishedEvents: NDKEvent[] = [];
for (const section of parsed.sections) {
const title = section.title;
const cleanContent = section.content;
const sectionTags = metadataToTags(section.metadata);
const dTag = generateDTag(title);
const [mTag, MTag] = getMimeTags(kind);
const tags: string[][] = [["d", dTag], mTag, MTag, ["title", title]];
if (sectionTags) {
tags.push(...sectionTags);
}
const ndkEvent = new NDKEvent(ndk);
ndkEvent.kind = kind;
ndkEvent.created_at = Math.floor(Date.now() / 1000);
ndkEvent.tags = tags;
ndkEvent.content = cleanContent;
ndkEvent.pubkey = ndk.activeUser.pubkey;
try {
await ndkEvent.sign();
const publishedToRelays = await ndkEvent.publish(relaySet);
if (publishedToRelays.size > 0) {
results.push({ success: true, eventId: ndkEvent.id });
publishedEvents.push(ndkEvent);
} else {
results.push({ success: false, error: 'Failed to publish to any relays' });
}
} catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
results.push({ success: false, error: errorMessage });
}
}
// Debug: extract and log 'e' and 'a' tags from all published events
publishedEvents.forEach(ev => {
// Extract d-tag from tags
const dTagEntry = ev.tags.find(t => t[0] === 'd');
const dTag = dTagEntry ? dTagEntry[1] : '';
const aTag = `${ev.kind}:${ev.pubkey}:${dTag}`;
console.log(`Event ${ev.id} tags:`);
console.log(' e:', ev.id);
console.log(' a:', aTag);
// Print nevent and naddr using nip19
const nevent = nip19.neventEncode({ id: ev.id });
const naddr = nip19.naddrEncode({ kind: ev.kind, pubkey: ev.pubkey, identifier: dTag });
console.log(' nevent:', nevent);
console.log(' naddr:', naddr);
});
return results;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
onError?.(errorMessage);
return [{ success: false, error: errorMessage }];
}
}
function generateDTag(title: string): string {
return title
.toLowerCase()
.replace(/[^\w\s-]/g, "")
.replace(/\s+/g, "-");
}