Files
grimoire/src/lib/event-title.ts
Alejandro b2b398b9fb docs: add applesauce v5 upgrade plan (#39)
* docs: add applesauce v5 upgrade plan

Comprehensive migration plan covering:
- Package updates (add applesauce-common, update to v5)
- EventFactory import migration (applesauce-factory → applesauce-core)
- Unified event loader setup
- ActionHub → ActionRunner migration
- useObservableMemo → use$ hook migration
- New features: casting system, encrypted content caching
- Documentation and skills updates needed

* feat: upgrade applesauce libraries to v5

Major upgrade from applesauce v4 to v5 with breaking changes:

Package updates:
- applesauce-core: ^4.0.0 → ^5.0.0
- applesauce-actions: ^4.0.0 → ^5.0.0
- applesauce-loaders: ^4.0.0 → ^5.0.0
- applesauce-react: ^4.0.0 → ^5.0.0
- applesauce-relay: ^4.0.0 → ^5.0.0
- applesauce-signers: ^4.0.0 → ^5.0.0
- applesauce-accounts: ^4.0.0 → ^5.0.0
- Added new applesauce-common: ^5.0.0 package

API migrations:
- EventFactory: applesauce-factory → applesauce-core/event-factory
- ActionHub → ActionRunner with async function pattern (not generators)
- useObservableMemo → use$ hook across all components
- Helper imports: article, highlight, threading, zap, comment, lists
  moved from applesauce-core to applesauce-common
- parseCoordinate → parseReplaceableAddress
- Subscription options: retries → reconnect
- getEventPointerFromETag now returns null instead of throwing

New features:
- Unified event loader via createEventLoaderForStore
- Updated loaders.ts to use v5 unified loader pattern

Documentation:
- Updated CLAUDE.md with v5 patterns and migration notes
- Updated applesauce-core skill for v5 changes
- Created new applesauce-common skill

Test fixes:
- Updated publish-spellbook.test.ts for v5 ActionRunner pattern
- Updated publish-spell.test.ts with eventStore mock
- Updated relay-selection.test.ts with valid test events
- Updated loaders.test.ts with valid 64-char hex event IDs
- Added createEventLoaderForStore mock

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-05 14:54:21 +01:00

94 lines
2.3 KiB
TypeScript

import { NostrEvent } from "@/types/nostr";
import { getTagValue } from "applesauce-core/helpers";
import { kinds } from "nostr-tools";
import { getArticleTitle } from "applesauce-common/helpers/article";
import {
getRepositoryName,
getIssueTitle,
getPatchSubject,
getPullRequestSubject,
} from "@/lib/nip34-helpers";
import { getCodeName } from "@/lib/nip-c0-helpers";
import { getAppName } from "@/lib/nip89-helpers";
import { getKindInfo } from "@/constants/kinds";
/**
* Get a human-readable display title for any event
*
* Priority order:
* 1. Kind-specific helper functions (most accurate)
* 2. Generic 'subject' or 'title' tags
* 3. Event kind name as fallback
*
* @param event - The Nostr event
* @returns Human-readable title string
*/
export function getEventDisplayTitle(
event: NostrEvent,
showKind = true,
): string {
// Try kind-specific helpers first (most accurate)
let title: string | undefined;
switch (event.kind) {
case kinds.LongFormArticle: // Long-form article
title = getArticleTitle(event);
break;
case 30617: // Repository
title = getRepositoryName(event);
break;
case 1337: // Code snippet
title = getCodeName(event);
break;
case 1621: // Issue
title = getIssueTitle(event);
break;
case 1617: // Patch
title = getPatchSubject(event);
break;
case 1618: // Pull request
title = getPullRequestSubject(event);
break;
case 31990: // Application Handler
title = getAppName(event);
break;
}
if (title) return title;
// Try generic tag extraction
title =
getTagValue(event, "subject") ||
getTagValue(event, "title") ||
getTagValue(event, "name");
if (title) return title;
// Fall back to kind name
const kindInfo = getKindInfo(event.kind);
if (showKind && kindInfo) {
return kindInfo.name;
}
// Ultimate fallback
if (showKind) {
return `Kind ${event.kind}`;
}
return event.content;
}
/**
* Get a window title for an event with optional prefix
*
* @param event - The Nostr event
* @param prefix - Optional prefix for the title (e.g., "Repository:", "Article:")
* @returns Formatted window title
*/
export function getEventWindowTitle(
event: NostrEvent,
prefix?: string,
): string {
const title = getEventDisplayTitle(event);
return prefix ? `${prefix} ${title}` : title;
}