Browse Source

bug-fixes

imwald
Silberengel 1 month ago
parent
commit
0a1b0a4468
  1. 2
      src/components/Embedded/EmbeddedNote.tsx
  2. 59
      src/components/NoteOptions/useMenuActions.tsx
  3. 9
      src/components/SearchResult/index.tsx
  4. 11
      src/lib/relay-list-builder.ts
  5. 4
      src/pages/secondary/RssFeedSettingsPage/index.tsx
  6. 4
      src/providers/FeedProvider.tsx
  7. 9
      src/providers/NostrProvider/index.tsx
  8. 56
      src/services/client-replaceable-events.service.ts
  9. 20
      src/services/media-upload.service.ts
  10. 18
      src/services/spell.service.ts

2
src/components/Embedded/EmbeddedNote.tsx

@ -2,7 +2,6 @@ import { Skeleton } from '@/components/ui/skeleton'
import ExternalLink from '@/components/ExternalLink' import ExternalLink from '@/components/ExternalLink'
import { import {
FAST_READ_RELAY_URLS, FAST_READ_RELAY_URLS,
FAST_WRITE_RELAY_URLS,
PROFILE_RELAY_URLS, PROFILE_RELAY_URLS,
SEARCHABLE_RELAY_URLS, SEARCHABLE_RELAY_URLS,
ExtendedKind ExtendedKind
@ -537,7 +536,6 @@ function buildEmbedWideRelayUrlsStatic(
...nip66Service.getSearchableRelayUrls(), ...nip66Service.getSearchableRelayUrls(),
...SEARCHABLE_RELAY_URLS, ...SEARCHABLE_RELAY_URLS,
...FAST_READ_RELAY_URLS, ...FAST_READ_RELAY_URLS,
...FAST_WRITE_RELAY_URLS,
...PROFILE_RELAY_URLS, ...PROFILE_RELAY_URLS,
...menuRelayUrls ...menuRelayUrls
]) ])

59
src/components/NoteOptions/useMenuActions.tsx

@ -220,8 +220,7 @@ export function useMenuActions({
const allRelays = [ const allRelays = [
...(currentBrowsingRelayUrlsRef.current || []), ...(currentBrowsingRelayUrlsRef.current || []),
...(favoriteRelaysRef.current || []), ...(favoriteRelaysRef.current || []),
...FAST_READ_RELAY_URLS, ...FAST_READ_RELAY_URLS
...FAST_WRITE_RELAY_URLS
] ]
const comprehensiveRelays = Array.from( const comprehensiveRelays = Array.from(
new Set(allRelays.map(url => normalizeAnyRelayUrl(url)).filter((url): url is string => !!url)) new Set(allRelays.map(url => normalizeAnyRelayUrl(url)).filter((url): url is string => !!url))
@ -247,39 +246,47 @@ export function useMenuActions({
if (!pubkey) return if (!pubkey) return
try { try {
// Build comprehensive relay list for pin list fetching const pinListReadRelays = Array.from(
const allRelays = [ new Set(
...(currentBrowsingRelayUrls || []), [...currentBrowsingRelayUrls, ...favoriteRelays, ...FAST_READ_RELAY_URLS]
...(favoriteRelays || []), .map((url) => normalizeAnyRelayUrl(url))
...FAST_READ_RELAY_URLS, .filter((url): url is string => !!url)
...FAST_READ_RELAY_URLS, )
...FAST_WRITE_RELAY_URLS )
]
const normalizedRelays = allRelays
.map(url => normalizeAnyRelayUrl(url))
.filter((url): url is string => !!url)
const comprehensiveRelays = Array.from(new Set(normalizedRelays))
const latestPinList = await fetchNewestPinListForPubkey(pubkey, comprehensiveRelays) const latestPinList = await fetchNewestPinListForPubkey(pubkey, pinListReadRelays)
logger.component('PinNote', 'Current pin list event', { hasEvent: !!latestPinList }) logger.component('PinNote', 'Current pin list event', { hasEvent: !!latestPinList })
const newTags = buildPinListTagsAfterToggle(latestPinList ?? null, event, !isPinned) const newTags = buildPinListTagsAfterToggle(latestPinList ?? null, event, !isPinned)
const successMessage = isPinned ? t('Note unpinned') : t('Note pinned') const successMessage = isPinned ? t('Note unpinned') : t('Note pinned')
logger.component('PinNote', 'Pin list tag count after merge', { count: newTags.length }) logger.component('PinNote', 'Pin list tag count after merge', { count: newTags.length })
const publishRelays = Array.from(
new Set([
...pinListReadRelays,
...FAST_WRITE_RELAY_URLS.map((url) => normalizeAnyRelayUrl(url) || url).filter(
(url): url is string => !!url
)
])
)
// Create and publish the new pin list event // Create and publish the new pin list event
logger.component('PinNote', 'Publishing new pin list event', { tagCount: newTags.length, relayCount: comprehensiveRelays.length }) logger.component('PinNote', 'Publishing new pin list event', {
const publishedEvent = await publish({ tagCount: newTags.length,
kind: 10001, relayCount: publishRelays.length
tags: newTags,
content: '',
created_at: Math.floor(Date.now() / 1000)
}, {
specifiedRelayUrls: comprehensiveRelays
}) })
const publishedEvent = await publish(
{
kind: 10001,
tags: newTags,
content: '',
created_at: Math.floor(Date.now() / 1000)
},
{
specifiedRelayUrls: publishRelays
}
)
// Show publishing feedback with relay messages // Show publishing feedback with relay messages
if ((publishedEvent as any)?.relayStatuses) { if ((publishedEvent as any)?.relayStatuses) {

9
src/components/SearchResult/index.tsx

@ -1,9 +1,4 @@
import { import { FAST_READ_RELAY_URLS, NIP_SEARCH_PAGE_KINDS, SEARCHABLE_RELAY_URLS } from '@/constants'
FAST_READ_RELAY_URLS,
FAST_WRITE_RELAY_URLS,
NIP_SEARCH_PAGE_KINDS,
SEARCHABLE_RELAY_URLS
} from '@/constants'
import { compareEventsForDTagQuery } from '@/lib/dtag-search' import { compareEventsForDTagQuery } from '@/lib/dtag-search'
import { TSearchParams } from '@/types' import { TSearchParams } from '@/types'
import NormalFeed from '../NormalFeed' import NormalFeed from '../NormalFeed'
@ -47,7 +42,7 @@ export default function SearchResult({ searchParams }: { searchParams: TSearchPa
relays.push(...(favoriteRelays || [])) relays.push(...(favoriteRelays || []))
relays.push(...FAST_READ_RELAY_URLS, ...FAST_WRITE_RELAY_URLS, ...SEARCHABLE_RELAY_URLS) relays.push(...FAST_READ_RELAY_URLS, ...SEARCHABLE_RELAY_URLS)
const normalized = Array.from( const normalized = Array.from(
new Set(relays.map((url) => normalizeUrl(url) || url).filter((url): url is string => !!url)) new Set(relays.map((url) => normalizeUrl(url) || url).filter((url): url is string => !!url))

11
src/lib/relay-list-builder.ts

@ -9,7 +9,7 @@
* - Includes seen relays * - Includes seen relays
*/ */
import { FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS, PROFILE_FETCH_RELAY_URLS, SEARCHABLE_RELAY_URLS } from '@/constants' import { FAST_READ_RELAY_URLS, PROFILE_FETCH_RELAY_URLS, SEARCHABLE_RELAY_URLS } from '@/constants'
import { feedRelayPolicyUrls } from '@/features/feed/relay-policy' import { feedRelayPolicyUrls } from '@/features/feed/relay-policy'
import { userReadRelaysWithHttp } from '@/lib/favorites-feed-relays' import { userReadRelaysWithHttp } from '@/lib/favorites-feed-relays'
import { urlIsNonLocalForRemoteViewer } from '@/lib/relay-list-sanitize' import { urlIsNonLocalForRemoteViewer } from '@/lib/relay-list-sanitize'
@ -57,7 +57,10 @@ export interface RelayListBuilderOptions {
includeProfileFetchRelays?: boolean includeProfileFetchRelays?: boolean
/** Whether to include FAST_READ_RELAY_URLS as fallback */ /** Whether to include FAST_READ_RELAY_URLS as fallback */
includeFastReadRelays?: boolean includeFastReadRelays?: boolean
/** Whether to include FAST_WRITE_RELAY_URLS as fallback */ /**
* Legacy name: adds {@link FAST_READ_RELAY_URLS} as extra bootstrap mirrors for REQ/read lists
* (historically mis-tagged as fast write).
*/
includeFastWriteRelays?: boolean includeFastWriteRelays?: boolean
/** Whether to include SEARCHABLE_RELAY_URLS - for search */ /** Whether to include SEARCHABLE_RELAY_URLS - for search */
includeSearchableRelays?: boolean includeSearchableRelays?: boolean
@ -236,9 +239,9 @@ export async function buildComprehensiveRelayList(options: RelayListBuilderOptio
FAST_READ_RELAY_URLS.forEach(addRelay) FAST_READ_RELAY_URLS.forEach(addRelay)
} }
// 8. Fast write relays (for writing) // 8. Extra fast-read bootstrap mirrors (call sites use legacy `includeFastWriteRelays`)
if (includeFastWriteRelays) { if (includeFastWriteRelays) {
FAST_WRITE_RELAY_URLS.forEach(addRelay) FAST_READ_RELAY_URLS.forEach(addRelay)
} }
// 9. Searchable relays (for search) // 9. Searchable relays (for search)

4
src/pages/secondary/RssFeedSettingsPage/index.tsx

@ -2,7 +2,7 @@ import storage from '@/services/local-storage.service'
import { RefreshButton } from '@/components/RefreshButton' import { RefreshButton } from '@/components/RefreshButton'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context' import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { ExtendedKind, FAST_WRITE_RELAY_URLS, PROFILE_RELAY_URLS } from '@/constants' import { ExtendedKind, FAST_READ_RELAY_URLS, PROFILE_RELAY_URLS } from '@/constants'
import { getLatestEvent } from '@/lib/event' import { getLatestEvent } from '@/lib/event'
import { forwardRef, useCallback, useEffect, useState } from 'react' import { forwardRef, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -121,7 +121,7 @@ const RssFeedSettingsPage = forwardRef(({ index, hideTitlebar = false }: { index
} }
setLoading(true) setLoading(true)
try { try {
const events = await queryService.fetchEvents(FAST_WRITE_RELAY_URLS.concat(PROFILE_RELAY_URLS), { const events = await queryService.fetchEvents(FAST_READ_RELAY_URLS.concat(PROFILE_RELAY_URLS), {
kinds: [ExtendedKind.RSS_FEED_LIST], kinds: [ExtendedKind.RSS_FEED_LIST],
authors: [pubkey], authors: [pubkey],
limit: 1 limit: 1

4
src/providers/FeedProvider.tsx

@ -1,4 +1,4 @@
import { FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS } from '@/constants' import { FAST_READ_RELAY_URLS } from '@/constants'
import { feedRelayPolicyUrls } from '@/features/feed/relay-policy' import { feedRelayPolicyUrls } from '@/features/feed/relay-policy'
import { getRelayListFromEvent, getHttpRelayListFromEvent } from '@/lib/event-metadata' import { getRelayListFromEvent, getHttpRelayListFromEvent } from '@/lib/event-metadata'
import { buildAllFavoritesFeedRelayUrls } from '@/lib/home-feed-relays' import { buildAllFavoritesFeedRelayUrls } from '@/lib/home-feed-relays'
@ -86,7 +86,7 @@ export function FeedProvider({ children }: { children: ReactNode }) {
return { return {
inboxRelayUrls: relayList?.read?.length ? relayList.read : FAST_READ_RELAY_URLS, inboxRelayUrls: relayList?.read?.length ? relayList.read : FAST_READ_RELAY_URLS,
outboxRelayUrls: relayList?.write?.length ? relayList.write : FAST_WRITE_RELAY_URLS, outboxRelayUrls: relayList?.write?.length ? relayList.write : FAST_READ_RELAY_URLS,
cacheRelayUrls, cacheRelayUrls,
httpRelayUrls httpRelayUrls
} }

9
src/providers/NostrProvider/index.tsx

@ -5,7 +5,6 @@ import {
ACCOUNT_SESSION_NETWORK_HYDRATE_MIN_INTERVAL_MS, ACCOUNT_SESSION_NETWORK_HYDRATE_MIN_INTERVAL_MS,
DEFAULT_FAVORITE_RELAYS, DEFAULT_FAVORITE_RELAYS,
FAST_READ_RELAY_URLS, FAST_READ_RELAY_URLS,
FAST_WRITE_RELAY_URLS,
ExtendedKind, ExtendedKind,
PROFILE_FETCH_RELAY_URLS, PROFILE_FETCH_RELAY_URLS,
PROFILE_RELAY_URLS, PROFILE_RELAY_URLS,
@ -412,7 +411,7 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
}) })
queryService queryService
.fetchEvents(FAST_WRITE_RELAY_URLS.concat(PROFILE_RELAY_URLS), { .fetchEvents(FAST_READ_RELAY_URLS.concat(PROFILE_RELAY_URLS), {
kinds: [ExtendedKind.RSS_FEED_LIST], kinds: [ExtendedKind.RSS_FEED_LIST],
authors: [account.pubkey], authors: [account.pubkey],
limit: 1 limit: 1
@ -505,7 +504,7 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
const normalizedRelays = [ const normalizedRelays = [
...mergedRelayList.write.map((url: string) => normalizeUrl(url) || url), ...mergedRelayList.write.map((url: string) => normalizeUrl(url) || url),
...mergedRelayList.read.map((url: string) => normalizeUrl(url) || url), ...mergedRelayList.read.map((url: string) => normalizeUrl(url) || url),
...FAST_WRITE_RELAY_URLS.map((url: string) => normalizeUrl(url) || url), ...FAST_READ_RELAY_URLS.map((url: string) => normalizeUrl(url) || url),
...PROFILE_FETCH_RELAY_URLS.map((url: string) => normalizeUrl(url) || url) ...PROFILE_FETCH_RELAY_URLS.map((url: string) => normalizeUrl(url) || url)
] ]
const fetchRelays = Array.from(new Set(normalizedRelays)).slice(0, 16) const fetchRelays = Array.from(new Set(normalizedRelays)).slice(0, 16)
@ -670,7 +669,7 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
...mergedRelayList.read.map((u) => normalizeUrl(u) || u), ...mergedRelayList.read.map((u) => normalizeUrl(u) || u),
...SEARCHABLE_RELAY_URLS.map((u) => normalizeUrl(u) || u), ...SEARCHABLE_RELAY_URLS.map((u) => normalizeUrl(u) || u),
...PROFILE_FETCH_RELAY_URLS.map((u) => normalizeUrl(u) || u), ...PROFILE_FETCH_RELAY_URLS.map((u) => normalizeUrl(u) || u),
...FAST_WRITE_RELAY_URLS.map((u) => normalizeUrl(u) || u) ...FAST_READ_RELAY_URLS.map((u) => normalizeUrl(u) || u)
]) ])
).filter(Boolean) ).filter(Boolean)
queryService queryService
@ -866,7 +865,7 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
...rl.read.map((u) => normalizeUrl(u) || u), ...rl.read.map((u) => normalizeUrl(u) || u),
...SEARCHABLE_RELAY_URLS.map((u) => normalizeUrl(u) || u), ...SEARCHABLE_RELAY_URLS.map((u) => normalizeUrl(u) || u),
...PROFILE_FETCH_RELAY_URLS.map((u) => normalizeUrl(u) || u), ...PROFILE_FETCH_RELAY_URLS.map((u) => normalizeUrl(u) || u),
...FAST_WRITE_RELAY_URLS.map((u) => normalizeUrl(u) || u) ...FAST_READ_RELAY_URLS.map((u) => normalizeUrl(u) || u)
]) ])
).filter(Boolean) ).filter(Boolean)
return queryService.fetchEvents(relays, { return queryService.fetchEvents(relays, {

56
src/services/client-replaceable-events.service.ts

@ -1,7 +1,6 @@
import { import {
ExtendedKind, ExtendedKind,
FAST_READ_RELAY_URLS, FAST_READ_RELAY_URLS,
FAST_WRITE_RELAY_URLS,
MAX_CONCURRENT_RELAY_CONNECTIONS, MAX_CONCURRENT_RELAY_CONNECTIONS,
METADATA_BATCH_AUTHORS_CHUNK, METADATA_BATCH_AUTHORS_CHUNK,
METADATA_BATCH_QUERY_EOSE_TIMEOUT_MS, METADATA_BATCH_QUERY_EOSE_TIMEOUT_MS,
@ -653,8 +652,8 @@ export class ReplaceableEventService {
includeFastReadRelays: true, includeFastReadRelays: true,
includeFavoriteRelays: true, includeFavoriteRelays: true,
includeLocalRelays: true, includeLocalRelays: true,
/** Many users publish kind 0 to NIP-65 write relays; batch path skipped these before. */ /** Many users publish kind 0 to NIP-65 write relays; batch path includes public read mirrors via {@link buildComprehensiveRelayList}. */
includeFastWriteRelays: true, includeFastWriteRelays: false,
includeSearchableRelays: false, includeSearchableRelays: false,
preferPublicReadRelaysEarly: true preferPublicReadRelaysEarly: true
}) })
@ -677,52 +676,39 @@ export class ReplaceableEventService {
) )
).filter(Boolean) ).filter(Boolean)
} else if (kind === kinds.Contacts) { } else if (kind === kinds.Contacts) {
// Contacts (kind 3): often on write relays; aggregators/profile mirrors also carry copies. // Contacts (kind 3): aggregators + profile mirrors + fast read.
relayUrls = Array.from( relayUrls = Array.from(
new Set( new Set(
[ [...READ_ONLY_RELAY_URLS, ...PROFILE_FETCH_RELAY_URLS, ...FAST_READ_RELAY_URLS].map(
...FAST_WRITE_RELAY_URLS, (u) => normalizeUrl(u) || u
...READ_ONLY_RELAY_URLS, )
...PROFILE_FETCH_RELAY_URLS,
...FAST_READ_RELAY_URLS
].map((u) => normalizeUrl(u) || u)
) )
).filter(Boolean) ).filter(Boolean)
} else if (kind === kinds.RelayList) { } else if (kind === kinds.RelayList) {
// NIP-65 (10002): almost always on the author's write/outbox relays; FAST_READ-only misses most users. // NIP-65 (10002): aggregators + profile mirrors + fast read.
relayUrls = Array.from( relayUrls = Array.from(
new Set( new Set(
[ [...READ_ONLY_RELAY_URLS, ...PROFILE_FETCH_RELAY_URLS, ...FAST_READ_RELAY_URLS].map(
...FAST_WRITE_RELAY_URLS, (u) => normalizeUrl(u) || u
...READ_ONLY_RELAY_URLS, )
...PROFILE_FETCH_RELAY_URLS,
...FAST_READ_RELAY_URLS
].map((u) => normalizeUrl(u) || u)
) )
).filter(Boolean) ).filter(Boolean)
} else if (kind === kinds.Mutelist || kind === kinds.BookmarkList) { } else if (kind === kinds.Mutelist || kind === kinds.BookmarkList) {
// Mute / bookmark lists: same distribution as contacts (writes + mirrors); FAST_READ-only misses many copies. // Mute / bookmark lists: same distribution as contacts; FAST_READ + mirrors.
relayUrls = Array.from( relayUrls = Array.from(
new Set( new Set(
[ [...READ_ONLY_RELAY_URLS, ...PROFILE_FETCH_RELAY_URLS, ...FAST_READ_RELAY_URLS].map(
...FAST_WRITE_RELAY_URLS, (u) => normalizeUrl(u) || u
...READ_ONLY_RELAY_URLS, )
...PROFILE_FETCH_RELAY_URLS,
...FAST_READ_RELAY_URLS
].map((u) => normalizeUrl(u) || u)
) )
).filter(Boolean) ).filter(Boolean)
} else if (kind === ExtendedKind.PAYMENT_INFO) { } else if (kind === ExtendedKind.PAYMENT_INFO) {
// NIP-A3 kind 10133: often published to the user's write relays only; FAST_READ alone misses many copies. // NIP-A3 kind 10133: aggregators + profile mirrors + fast read.
// Mirror contacts + pin-list coverage (writes + profile mirrors + aggregators + fast read).
relayUrls = Array.from( relayUrls = Array.from(
new Set( new Set(
[ [...READ_ONLY_RELAY_URLS, ...PROFILE_FETCH_RELAY_URLS, ...FAST_READ_RELAY_URLS].map(
...FAST_WRITE_RELAY_URLS, (u) => normalizeUrl(u) || u
...READ_ONLY_RELAY_URLS, )
...PROFILE_FETCH_RELAY_URLS,
...FAST_READ_RELAY_URLS
].map((u) => normalizeUrl(u) || u)
) )
).filter(Boolean) ).filter(Boolean)
} else { } else {
@ -1174,7 +1160,7 @@ export class ReplaceableEventService {
includeFavoriteRelays: true, includeFavoriteRelays: true,
includeProfileFetchRelays: true, includeProfileFetchRelays: true,
includeFastReadRelays: true, includeFastReadRelays: true,
includeFastWriteRelays: true, includeFastWriteRelays: false,
includeSearchableRelays: true, includeSearchableRelays: true,
includeLocalRelays: true includeLocalRelays: true
}) })
@ -1400,7 +1386,7 @@ export class ReplaceableEventService {
/** /**
* Fetch follow list event. * Fetch follow list event.
* When relayUrls are provided (e.g. user write + search relays), queries those directly. * When relayUrls are provided (e.g. user write + search relays), queries those directly.
* Otherwise uses the default relay set (FAST_WRITE + PROFILE_FETCH + FAST_READ). * Otherwise uses the default relay set (READ_ONLY + PROFILE_FETCH + FAST_READ).
*/ */
/** Hard cap: {@link fetchReplaceableEvent} can otherwise wedge the DataLoader chain when relays never answer. */ /** Hard cap: {@link fetchReplaceableEvent} can otherwise wedge the DataLoader chain when relays never answer. */
private static readonly FETCH_FOLLOW_LIST_REPLACEABLE_TIMEOUT_MS = 14_000 private static readonly FETCH_FOLLOW_LIST_REPLACEABLE_TIMEOUT_MS = 14_000
@ -1557,7 +1543,7 @@ export class ReplaceableEventService {
includeFavoriteRelays: true, includeFavoriteRelays: true,
includeProfileFetchRelays: true, includeProfileFetchRelays: true,
includeFastReadRelays: true, includeFastReadRelays: true,
includeFastWriteRelays: true, includeFastWriteRelays: false,
includeSearchableRelays: true, includeSearchableRelays: true,
includeLocalRelays: true includeLocalRelays: true
}) })

20
src/services/media-upload.service.ts

@ -1,4 +1,4 @@
/** Compression runs entirely in-app before upload (`compress-upload-media`). Load `local-storage` before `./client.service` (that graph can re-enter here; constructor reads storage). */ /** Compression runs entirely in-app before upload (`compress-upload-media`). Load `local-storage` before `./client.service`; the default export is lazily constructed so `client`↔`draft-event`↔this module cycles cannot run the constructor before `storage` is initialized. */
import storage from './local-storage.service' import storage from './local-storage.service'
import { compressMediaForUpload } from '@/lib/compress-upload-media' import { compressMediaForUpload } from '@/lib/compress-upload-media'
import { fetchWithTimeout } from '@/lib/fetch-with-timeout' import { fetchWithTimeout } from '@/lib/fetch-with-timeout'
@ -312,5 +312,21 @@ class MediaUploadService {
} }
} }
const instance = new MediaUploadService() /**
* Eager `new MediaUploadService()` at module load can run while `storage` is still in the TDZ:
* `client.service` (and its graph) may synchronously pull `draft-event` this module again
* before static imports have finished binding. Lazily construct on first property access.
*/
function createMediaUploadServiceLazy(): MediaUploadService {
let inner: MediaUploadService | undefined
return new Proxy({} as MediaUploadService, {
get(_target, prop, receiver) {
if (!inner) inner = new MediaUploadService()
const v = Reflect.get(inner, prop, receiver) as unknown
return typeof v === 'function' ? (v as (...args: unknown[]) => unknown).bind(inner) : v
}
})
}
const instance = createMediaUploadServiceLazy()
export default instance export default instance

18
src/services/spell.service.ts

@ -2,7 +2,7 @@
* NIP-A7 Spells: parse and execute kind 777 events as portable relay query filters. * NIP-A7 Spells: parse and execute kind 777 events as portable relay query filters.
*/ */
import { ExtendedKind, FAST_WRITE_RELAY_URLS } from '@/constants' import { ExtendedKind, FAST_READ_RELAY_URLS } from '@/constants'
import { getRelayUrlsWithFavoritesFastReadAndInbox } from '@/lib/favorites-feed-relays' import { getRelayUrlsWithFavoritesFastReadAndInbox } from '@/lib/favorites-feed-relays'
import { tagNameEquals } from '@/lib/tag' import { tagNameEquals } from '@/lib/tag'
import logger from '@/lib/logger' import logger from '@/lib/logger'
@ -48,9 +48,9 @@ export type SpellExecutionContext = {
contacts: string[] contacts: string[]
} }
/** When the spell has no `relays` tag and NIP-65 write list is empty: known-good write relays. */ /** When the spell has no `relays` tag and NIP-65 write list is empty: known-good read mirrors for REQ. */
function defaultSpellWriteFallbackRelays(): string[] { function defaultSpellRelayFallbackRelays(): string[] {
return dedupeRelayUrls([...FAST_WRITE_RELAY_URLS]) return dedupeRelayUrls([...FAST_READ_RELAY_URLS])
} }
/** Max kind-777 events to pull when syncing spell definitions from relays (you only). */ /** Max kind-777 events to pull when syncing spell definitions from relays (you only). */
@ -109,15 +109,15 @@ function dedupeRelayUrls(urls: string[]): string[] {
export type GetRelaysForSpellOptions = { export type GetRelaysForSpellOptions = {
/** /**
* When true (default): merge FAST_WRITE after the primary list (REQ feeds) for resilience. * When true (default): merge {@link FAST_READ_RELAY_URLS} after the primary list (REQ) for resilience.
* When false: use only spell `relays` tag, NIP-65 write relays, or write fallback no extra padding (COUNT). * When false: use only spell `relays` tag, NIP-65 write relays, or read fallback no extra padding (COUNT).
*/ */
mergeDefaultReadRelays?: boolean mergeDefaultReadRelays?: boolean
} }
/** /**
* Get relay URLs for executing a spell: spell `relays` tag, else the user's NIP-65 **write** (outbox) relays. * Get relay URLs for executing a spell: spell `relays` tag, else the user's NIP-65 **write** (outbox) relays.
* Publishing and running spells use outboxes only (plus optional FAST_WRITE padding when mergeDefaults is true). * Running a spell issues REQ queries; optional {@link FAST_READ_RELAY_URLS} padding helps when primaries are slow.
*/ */
export function getRelaysForSpell( export function getRelaysForSpell(
spell: Event, spell: Event,
@ -137,10 +137,10 @@ export function getRelaysForSpell(
primary = [...context.relayListWrite] primary = [...context.relayListWrite]
} }
if (!primary.length) { if (!primary.length) {
return defaultSpellWriteFallbackRelays() return defaultSpellRelayFallbackRelays()
} }
if (mergeDefaults) { if (mergeDefaults) {
return dedupeRelayUrls([...primary, ...FAST_WRITE_RELAY_URLS]) return dedupeRelayUrls([...primary, ...FAST_READ_RELAY_URLS])
} }
return dedupeRelayUrls(primary) return dedupeRelayUrls(primary)
} }

Loading…
Cancel
Save