Browse Source

refactor: fetch user profile only when needed

store hexpubkey in Repo and Proposal data object
instead of full profile

this prevents unnecessary state updates for those objects

the trade-off is including business logic (getting profile data)
within UI components

this is mitigated by allowing hexpubkey or UserObject to be passed
to UI components so that UI component tests can be written without
having to worry about business logic

this new approach can be abstracted to other object types
master
DanConwayDev 2 years ago
parent
commit
33d35dcac8
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. 29
      src/lib/components/proposals/ProposalHeader.svelte
  2. 18
      src/lib/components/repo/type.ts
  3. 48
      src/lib/components/repo/vectors.ts
  4. 28
      src/lib/components/users/UserHeader.svelte
  5. 8
      src/lib/components/users/type.ts
  6. 22
      src/lib/components/users/vectors.ts
  7. 28
      src/lib/stores/Issue.ts
  8. 32
      src/lib/stores/Proposals.ts
  9. 44
      src/lib/stores/repos.ts
  10. 13
      src/lib/stores/users.ts

29
src/lib/components/proposals/ProposalHeader.svelte

@ -5,10 +5,16 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import { summary_defaults } from './type' import { summary_defaults } from './type'
import { getName } from '../users/type' import {
defaults as user_defaults,
getName,
type UserObject,
} from '../users/type'
import Container from '../Container.svelte' import Container from '../Container.svelte'
import Status from './Status.svelte' import Status from './Status.svelte'
import { logged_in_user } from '$lib/stores/users' import { ensureUser, logged_in_user } from '$lib/stores/users'
import type { Unsubscriber } from 'svelte/store'
import { onDestroy } from 'svelte'
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
export let type: 'proposal' | 'issue' = 'proposal' export let type: 'proposal' | 'issue' = 'proposal'
@ -27,8 +33,23 @@
let short_title: string let short_title: string
let created_at_ago: string let created_at_ago: string
let author_name = '' let author_name = ''
let author_object: UserObject = {
...user_defaults,
}
let unsubscriber: Unsubscriber
$: {
if (typeof author === 'string') {
if (unsubscriber) unsubscriber()
unsubscriber = ensureUser(author).subscribe((u) => {
author_object = { ...u }
})
} else author_object = author
}
onDestroy(() => {
if (unsubscriber) unsubscriber()
})
$: { $: {
author_name = getName(author) author_name = getName(author_object)
} }
$: { $: {
if (title.length > 70) short_title = title.slice(0, 65) + '...' if (title.length > 70) short_title = title.slice(0, 65) + '...'
@ -67,7 +88,7 @@
opened {created_at_ago} opened {created_at_ago}
</div> </div>
<div class="inline align-middle"> <div class="inline align-middle">
{#if author.loading} {#if author_object.loading}
<div class="skeleton inline-block h-3 w-20 pb-2"></div> <div class="skeleton inline-block h-3 w-20 pb-2"></div>
{:else} {:else}
{author_name} {author_name}

18
src/lib/components/repo/type.ts

@ -1,6 +1,10 @@
import { defaults as user_defaults, type User } from '../users/type' import {
defaults as user_defaults,
type User,
type UserObject,
} from '../users/type'
export interface RepoEvent { export interface RepoEventBase {
event_id: string event_id: string
naddr: string naddr: string
identifier: string identifier: string
@ -10,12 +14,20 @@ export interface RepoEvent {
clone: string[] clone: string[]
web: string[] web: string[]
tags: string[] tags: string[]
maintainers: User[] maintainers: string | User[]
relays: string[] relays: string[]
referenced_by: string[] referenced_by: string[]
created_at: number created_at: number
loading: boolean loading: boolean
} }
export interface RepoEvent extends RepoEventBase {
maintainers: string[]
}
export interface RepoEventWithMaintainersMetadata extends RepoEventBase {
maintainers: UserObject[]
}
export const event_defaults: RepoEvent = { export const event_defaults: RepoEvent = {
event_id: '', event_id: '',
naddr: '', naddr: '',

48
src/lib/components/repo/vectors.ts

@ -1,5 +1,5 @@
import { UserVectors, withName } from '../users/vectors' import { UserVectors, withName } from '../users/vectors'
import type { RepoEvent, RepoSummary } from './type' import type { RepoEventWithMaintainersMetadata, RepoSummary } from './type'
export const RepoSummaryCardArgsVectors = { export const RepoSummaryCardArgsVectors = {
Short: { Short: {
@ -33,7 +33,7 @@ export const RepoSummaryCardArgsVectors = {
], ],
} as RepoSummary, } as RepoSummary,
} }
const base: RepoEvent = { const base: RepoEventWithMaintainersMetadata = {
identifier: '9ee507fc4357d7ee16a5d8901bedcd103f23c17d', identifier: '9ee507fc4357d7ee16a5d8901bedcd103f23c17d',
unique_commit: '9ee507fc4357d7ee16a5d8901bedcd103f23c17d', unique_commit: '9ee507fc4357d7ee16a5d8901bedcd103f23c17d',
name: 'Short Name', name: 'Short Name',
@ -55,24 +55,31 @@ const base: RepoEvent = {
} }
export const RepoDetailsArgsVectors = { export const RepoDetailsArgsVectors = {
Short: { ...base } as RepoEvent, Short: { ...base } as RepoEventWithMaintainersMetadata,
Long: { Long: {
...base, ...base,
name: 'Long Name that goes on and on and on and on and on and on and on and on and on', name: 'Long Name that goes on and on and on and on and on and on and on and on and on',
description: description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis nisl eget turpis congue molestie. Nulla vitae purus nec augue accumsan facilisis sed sed ligula. Vestibulum sed risus lacinia risus lacinia molestie. Ut lorem quam, consequat eget tempus in, rhoncus vel nunc. Duis efficitur a leo vel sodales. Nam id fermentum lacus. Etiam nec placerat velit. Praesent ac consectetur est. Aenean iaculis commodo enim.\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis nisl eget turpis congue molestie.', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis nisl eget turpis congue molestie. Nulla vitae purus nec augue accumsan facilisis sed sed ligula. Vestibulum sed risus lacinia risus lacinia molestie. Ut lorem quam, consequat eget tempus in, rhoncus vel nunc. Duis efficitur a leo vel sodales. Nam id fermentum lacus. Etiam nec placerat velit. Praesent ac consectetur est. Aenean iaculis commodo enim.\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis nisl eget turpis congue molestie.',
} as RepoEvent, } as RepoEventWithMaintainersMetadata,
LongNoSpaces: { LongNoSpaces: {
...base, ...base,
name: 'LongNameLongNameLongNameLongNameLongNameLongNameLongNameLongName', name: 'LongNameLongNameLongNameLongNameLongNameLongNameLongNameLongName',
description: description:
'LoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsum', 'LoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsumLoremipsum',
} as RepoEvent, } as RepoEventWithMaintainersMetadata,
NoNameOrDescription: { ...base, name: '', description: '' } as RepoEvent, NoNameOrDescription: {
NoDescription: { ...base, description: '' } as RepoEvent, ...base,
NoTags: { ...base, tags: [] } as RepoEvent, name: '',
NoGitServer: { ...base, clone: [''] } as RepoEvent, description: '',
NoWeb: { ...base, web: [] } as RepoEvent, } as RepoEventWithMaintainersMetadata,
NoDescription: {
...base,
description: '',
} as RepoEventWithMaintainersMetadata,
NoTags: { ...base, tags: [] } as RepoEventWithMaintainersMetadata,
NoGitServer: { ...base, clone: [''] } as RepoEventWithMaintainersMetadata,
NoWeb: { ...base, web: [] } as RepoEventWithMaintainersMetadata,
MaintainersOneProfileNotLoaded: { MaintainersOneProfileNotLoaded: {
...base, ...base,
maintainers: [ maintainers: [
@ -80,7 +87,7 @@ export const RepoDetailsArgsVectors = {
{ ...UserVectors.loading }, { ...UserVectors.loading },
{ ...base.maintainers[2] }, { ...base.maintainers[2] },
], ],
} as RepoEvent, } as RepoEventWithMaintainersMetadata,
MaintainersOneProfileDisplayNameWithoutName: { MaintainersOneProfileDisplayNameWithoutName: {
...base, ...base,
maintainers: [ maintainers: [
@ -88,7 +95,7 @@ export const RepoDetailsArgsVectors = {
{ ...UserVectors.display_name_only }, { ...UserVectors.display_name_only },
{ ...base.maintainers[2] }, { ...base.maintainers[2] },
], ],
} as RepoEvent, } as RepoEventWithMaintainersMetadata,
MaintainersOneProfileNameAndDisplayNamePresent: { MaintainersOneProfileNameAndDisplayNamePresent: {
...base, ...base,
maintainers: [ maintainers: [
@ -96,7 +103,7 @@ export const RepoDetailsArgsVectors = {
{ ...UserVectors.display_name_and_name }, { ...UserVectors.display_name_and_name },
{ ...base.maintainers[2] }, { ...base.maintainers[2] },
], ],
} as RepoEvent, } as RepoEventWithMaintainersMetadata,
MaintainersOneProfileNoNameOrDisplayNameBeingPresent: { MaintainersOneProfileNoNameOrDisplayNameBeingPresent: {
...base, ...base,
maintainers: [ maintainers: [
@ -104,8 +111,15 @@ export const RepoDetailsArgsVectors = {
{ ...UserVectors.no_profile }, { ...UserVectors.no_profile },
{ ...base.maintainers[2] }, { ...base.maintainers[2] },
], ],
} as RepoEvent, } as RepoEventWithMaintainersMetadata,
NoMaintainers: { ...base, maintainers: [] } as RepoEvent, NoMaintainers: {
NoRelays: { ...base, relays: [] } as RepoEvent, ...base,
NoMaintainersOrRelays: { ...base, maintainers: [], relays: [] } as RepoEvent, maintainers: [],
} as RepoEventWithMaintainersMetadata,
NoRelays: { ...base, relays: [] } as RepoEventWithMaintainersMetadata,
NoMaintainersOrRelays: {
...base,
maintainers: [],
relays: [],
} as RepoEventWithMaintainersMetadata,
} }

28
src/lib/components/users/UserHeader.svelte

@ -1,10 +1,11 @@
<script lang="ts"> <script lang="ts">
import { getName, type User } from './type' import { ensureUser } from '$lib/stores/users'
import type { Unsubscriber } from 'svelte/store'
import { defaults, getName, type User, type UserObject } from './type'
import { onDestroy } from 'svelte'
export let user: User = { export let user: User = {
hexpubkey: '', ...defaults,
npub: '',
loading: true,
} }
export let inline = false export let inline = false
@ -12,8 +13,23 @@
export let avatar_only = false export let avatar_only = false
export let in_event_header = false export let in_event_header = false
$: ({ profile, loading } = user) let user_object: UserObject = {
$: display_name = getName(user) ...defaults,
}
let unsubscriber: Unsubscriber
$: {
if (typeof user === 'string') {
if (unsubscriber) unsubscriber()
unsubscriber = ensureUser(user).subscribe((u) => {
user_object = { ...u }
})
} else user_object = user
}
onDestroy(() => {
if (unsubscriber) unsubscriber()
})
$: ({ profile, loading } = user_object)
$: display_name = getName(user_object)
</script> </script>
<div class:inline-block={inline}> <div class:inline-block={inline}>

8
src/lib/components/users/type.ts

@ -1,19 +1,21 @@
import type { NDKUserProfile } from '@nostr-dev-kit/ndk' import type { NDKUserProfile } from '@nostr-dev-kit/ndk'
export interface User { export interface UserObject {
loading: boolean loading: boolean
hexpubkey: string hexpubkey: string
npub: string npub: string
profile?: NDKUserProfile profile?: NDKUserProfile
} }
export const defaults: User = { export const defaults: UserObject = {
loading: true, loading: true,
hexpubkey: '', hexpubkey: '',
npub: '', npub: '',
} }
export function getName(user: User, truncate_above = 25): string { export type User = UserObject | string
export function getName(user: UserObject, truncate_above = 25): string {
return truncate( return truncate(
user.profile user.profile
? user.profile.name ? user.profile.name

22
src/lib/components/users/vectors.ts

@ -1,7 +1,7 @@
import type { User } from './type' import type { UserObject } from './type'
// nsec1rg53qfv09az39dlw6j64ange3cx8sh5p8np29qcxtythplvplktsv93tnr // nsec1rg53qfv09az39dlw6j64ange3cx8sh5p8np29qcxtythplvplktsv93tnr
const base: User = { const base: UserObject = {
hexpubkey: '3eb45c6f15752d796fa5465d0530a5a5feb79fb6f08c0a4176be9d73cc28c40d', hexpubkey: '3eb45c6f15752d796fa5465d0530a5a5feb79fb6f08c0a4176be9d73cc28c40d',
npub: 'npub18669cmc4w5khjma9gews2v995hlt08ak7zxq5stkh6wh8npgcsxslt2xjn', npub: 'npub18669cmc4w5khjma9gews2v995hlt08ak7zxq5stkh6wh8npgcsxslt2xjn',
loading: false, loading: false,
@ -10,30 +10,30 @@ const base: User = {
const image = '../test-profile-image.jpg' const image = '../test-profile-image.jpg'
export const UserVectors = { export const UserVectors = {
loading: { ...base, loading: true } as User, loading: { ...base, loading: true } as UserObject,
default: { ...base, profile: { name: 'DanConwayDev', image } } as User, default: { ...base, profile: { name: 'DanConwayDev', image } } as UserObject,
display_name_only: { display_name_only: {
...base, ...base,
profile: { displayName: 'DanConwayDev', image }, profile: { displayName: 'DanConwayDev', image },
} as User, } as UserObject,
display_name_and_name: { display_name_and_name: {
...base, ...base,
profile: { name: 'Dan', displayName: 'DanConwayDev', image }, profile: { name: 'Dan', displayName: 'DanConwayDev', image },
} as User, } as UserObject,
no_image: { ...base, profile: { name: 'DanConwayDev' } } as User, no_image: { ...base, profile: { name: 'DanConwayDev' } } as UserObject,
no_profile: { ...base } as User, no_profile: { ...base } as UserObject,
long_name: { long_name: {
...base, ...base,
profile: { name: 'Really Really Long Long Name', image }, profile: { name: 'Really Really Long Long Name', image },
} as User, } as UserObject,
} }
export function withName(base: User, name: string): User { export function withName(base: UserObject, name: string): UserObject {
return { return {
...base, ...base,
profile: { profile: {
...base.profile, ...base.profile,
name, name,
}, },
} as User } as UserObject
} }

28
src/lib/stores/Issue.ts

@ -1,8 +1,6 @@
import { NDKRelaySet, type NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk' import { NDKRelaySet, type NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk'
import { writable, type Unsubscriber, type Writable } from 'svelte/store' import { writable, type Writable } from 'svelte/store'
import { base_relays, ndk } from './ndk' import { base_relays, ndk } from './ndk'
import type { User } from '$lib/components/users/type'
import { ensureUser } from './users'
import { type IssueFull, full_defaults } from '$lib/components/issues/type' import { type IssueFull, full_defaults } from '$lib/components/issues/type'
import { proposal_status_kinds, proposal_status_open } from '$lib/kinds' import { proposal_status_kinds, proposal_status_open } from '$lib/kinds'
import { awaitSelectedRepoCollection } from './repo' import { awaitSelectedRepoCollection } from './repo'
@ -20,7 +18,6 @@ export const selected_issue_full: Writable<IssueFull> = writable({
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
let selected_issue_repo_id: string = '' let selected_issue_repo_id: string = ''
let selected_issue_id: string = '' let selected_issue_id: string = ''
let issue_summary_author_unsubsriber: Unsubscriber | undefined
export const selected_issue_replies: Writable<NDKEvent[]> = writable([]) export const selected_issue_replies: Writable<NDKEvent[]> = writable([])
@ -59,8 +56,6 @@ export const ensureIssueFull = (repo_identifier: string, issue_id: string) => {
}, },
loading: true, loading: true,
}) })
if (issue_summary_author_unsubsriber) issue_summary_author_unsubsriber()
issue_summary_author_unsubsriber = undefined
new Promise(async (r) => { new Promise(async (r) => {
const repo_collection = await awaitSelectedRepoCollection(repo_identifier) const repo_collection = await awaitSelectedRepoCollection(repo_identifier)
@ -98,30 +93,11 @@ export const ensureIssueFull = (repo_identifier: string, issue_id: string) => {
descritpion: extractIssueDescription(event.content), descritpion: extractIssueDescription(event.content),
created_at: event.created_at, created_at: event.created_at,
comments: 0, comments: 0,
author: { author: event.pubkey,
hexpubkey: event.pubkey,
loading: true,
npub: '',
},
loading: false, loading: false,
}, },
} }
}) })
issue_summary_author_unsubsriber = ensureUser(event.pubkey).subscribe(
(u: User) => {
selected_issue_full.update((full) => {
return {
...full,
summary: {
...full.summary,
author:
event.pubkey == u.hexpubkey ? u : full.summary.author,
},
}
})
}
)
} }
} catch {} } catch {}
}) })

32
src/lib/stores/Proposals.ts

@ -4,11 +4,9 @@ import {
NDKSubscription, NDKSubscription,
type NDKFilter, type NDKFilter,
} from '@nostr-dev-kit/ndk' } from '@nostr-dev-kit/ndk'
import { writable, type Unsubscriber, type Writable } from 'svelte/store' import { writable, type Writable } from 'svelte/store'
import { base_relays, ndk } from './ndk' import { base_relays, ndk } from './ndk'
import { summary_defaults } from '$lib/components/proposals/type' import { summary_defaults } from '$lib/components/proposals/type'
import type { User } from '$lib/components/users/type'
import { ensureUser } from './users'
import type { ProposalSummaries } from '$lib/components/proposals/type' import type { ProposalSummaries } from '$lib/components/proposals/type'
import { awaitSelectedRepoCollection } from './repo' import { awaitSelectedRepoCollection } from './repo'
import { import {
@ -29,8 +27,6 @@ export const proposal_summaries: Writable<ProposalSummaries> = writable({
let selected_repo_id: string | undefined = '' let selected_repo_id: string | undefined = ''
let authors_unsubscribers: Unsubscriber[] = []
let sub: NDKSubscription let sub: NDKSubscription
export const ensureProposalSummaries = async (repo_id: string | undefined) => { export const ensureProposalSummaries = async (repo_id: string | undefined) => {
@ -43,8 +39,6 @@ export const ensureProposalSummaries = async (repo_id: string | undefined) => {
if (sub) sub.stop() if (sub) sub.stop()
if (sub_statuses) sub_statuses.stop() if (sub_statuses) sub_statuses.stop()
authors_unsubscribers.forEach((u) => u())
authors_unsubscribers = []
selected_repo_id = repo_id selected_repo_id = repo_id
@ -83,7 +77,7 @@ export const ensureProposalSummaries = async (repo_id: string | undefined) => {
filter = { filter = {
kinds: [patch_kind], kinds: [patch_kind],
'#a': repo.maintainers.map( '#a': repo.maintainers.map(
(m) => `${repo_kind}:${m.hexpubkey}:${repo.identifier}` (m) => `${repo_kind}:${m}:${repo.identifier}`
), ),
limit: 100, limit: 100,
} }
@ -91,7 +85,7 @@ export const ensureProposalSummaries = async (repo_id: string | undefined) => {
filter = { filter = {
kinds: [patch_kind], kinds: [patch_kind],
'#a': repo.maintainers.map( '#a': repo.maintainers.map(
(m) => `${repo_kind}:${m.hexpubkey}:${repo.identifier}` (m) => `${repo_kind}:${m}:${repo.identifier}`
), ),
'#t': ['root'], '#t': ['root'],
limit: 100, limit: 100,
@ -139,11 +133,7 @@ export const ensureProposalSummaries = async (repo_id: string | undefined) => {
descritpion: event.tagValue('description') || '', descritpion: event.tagValue('description') || '',
created_at: event.created_at, created_at: event.created_at,
comments: 0, comments: 0,
author: { author: event.pubkey,
hexpubkey: event.pubkey,
loading: true,
npub: '',
},
loading: false, loading: false,
}, },
], ],
@ -174,20 +164,6 @@ export const ensureProposalSummaries = async (repo_id: string | undefined) => {
} }
} }
} }
authors_unsubscribers.push(
ensureUser(event.pubkey).subscribe((u: User) => {
proposal_summaries.update((proposals) => {
return {
...proposals,
summaries: proposals.summaries.map((o) => ({
...o,
author: event.pubkey === o.author.hexpubkey ? u : o.author,
})),
}
})
})
)
} catch {} } catch {}
}) })
sub.on('eose', () => { sub.on('eose', () => {

44
src/lib/stores/repos.ts

@ -8,8 +8,6 @@ import { NDKRelaySet, type NDKFilter, NDKEvent } from '@nostr-dev-kit/ndk'
import { get, writable, type Writable } from 'svelte/store' import { get, writable, type Writable } from 'svelte/store'
import { base_relays, ndk } from './ndk' import { base_relays, ndk } from './ndk'
import { repo_kind } from '$lib/kinds' import { repo_kind } from '$lib/kinds'
import type { User } from '$lib/components/users/type'
import { ensureUser } from './users'
import { selectRepoFromCollection } from '$lib/components/repo/utils' import { selectRepoFromCollection } from '$lib/components/repo/utils'
import { selected_repo_collection } from './repo' import { selected_repo_collection } from './repo'
@ -99,7 +97,7 @@ export const ensureRepoCollection = (
const ref_sub = ndk.subscribe( const ref_sub = ndk.subscribe(
{ {
'#a': [ '#a': [
`${repo_kind}:${repo_event.maintainers[0].hexpubkey}:${repo_event.identifier}`, `${repo_kind}:${repo_event.maintainers[0]}:${repo_event.identifier}`,
], ],
limit: 10, limit: 10,
}, },
@ -166,35 +164,11 @@ export const ensureRepoCollection = (
} }
}) })
}) })
// load maintainers - we will subscribe later to prevent too many updates
repo_event.maintainers.forEach((m) => ensureUser(m.hexpubkey))
} }
}) })
sub.on('eose', () => { sub.on('eose', () => {
// still awaiting reference_by at this point // still awaiting reference_by at this point
repos[unique_commit_or_identifier].update((repo_collection) => { repos[unique_commit_or_identifier].update((repo_collection) => {
// subscribe to maintainers
const hexpubkeys = repo_collection.events.flatMap((repo_event) =>
repo_event.maintainers.map((m) => m.hexpubkey)
)
hexpubkeys.forEach((hexpubkey) => {
ensureUser(hexpubkey).subscribe((u) => {
repos[unique_commit_or_identifier].update((repo_collection) => ({
...repo_collection,
events: [
...repo_collection.events.map((repo_event) => ({
...repo_event,
maintainers: [
...repo_event.maintainers.map((m) => ({
...(m.hexpubkey === u.hexpubkey ? u : m),
})),
],
})),
],
}))
})
})
return { return {
...repo_collection, ...repo_collection,
loading: false, loading: false,
@ -217,21 +191,11 @@ export const ensureRepoCollection = (
export const eventToRepoEvent = (event: NDKEvent): RepoEvent | undefined => { export const eventToRepoEvent = (event: NDKEvent): RepoEvent | undefined => {
if (event.kind !== repo_kind) return undefined if (event.kind !== repo_kind) return undefined
const maintainers = [ const maintainers = [event.pubkey]
{
hexpubkey: event.pubkey,
loading: true,
npub: '',
} as User,
]
event.getMatchingTags('maintainers').forEach((t: string[]) => { event.getMatchingTags('maintainers').forEach((t: string[]) => {
t.forEach((v, i) => { t.forEach((v, i) => {
if (i > 0 && v !== maintainers[0].hexpubkey) { if (i > 0 && v !== maintainers[0]) {
maintainers.push({ maintainers.push(v)
hexpubkey: v,
loading: true,
npub: '',
} as User)
} }
}) })
}) })

13
src/lib/stores/users.ts

@ -1,18 +1,18 @@
import { import {
defaults as user_defaults, defaults as user_defaults,
type User, type UserObject,
} from '$lib/components/users/type' } from '$lib/components/users/type'
import { NDKNip07Signer, NDKRelayList } from '@nostr-dev-kit/ndk' import { NDKNip07Signer, NDKRelayList } from '@nostr-dev-kit/ndk'
import { get, writable, type Unsubscriber, type Writable } from 'svelte/store' import { get, writable, type Unsubscriber, type Writable } from 'svelte/store'
import { ndk } from './ndk' import { ndk } from './ndk'
export const users: { [hexpubkey: string]: Writable<User> } = {} export const users: { [hexpubkey: string]: Writable<UserObject> } = {}
export const ensureUser = (hexpubkey: string): Writable<User> => { export const ensureUser = (hexpubkey: string): Writable<UserObject> => {
if (!users[hexpubkey]) { if (!users[hexpubkey]) {
const u = ndk.getUser({ hexpubkey }) const u = ndk.getUser({ hexpubkey })
const base: User = { const base: UserObject = {
loading: false, loading: false,
hexpubkey, hexpubkey,
npub: u.npub, npub: u.npub,
@ -44,7 +44,7 @@ export const ensureUser = (hexpubkey: string): Writable<User> => {
return users[hexpubkey] return users[hexpubkey]
} }
export const returnUser = async (hexpubkey: string): Promise<User> => { export const returnUser = async (hexpubkey: string): Promise<UserObject> => {
return new Promise((r) => { return new Promise((r) => {
const unsubscriber = ensureUser(hexpubkey).subscribe((u) => { const unsubscriber = ensureUser(hexpubkey).subscribe((u) => {
if (!u.loading) { if (!u.loading) {
@ -81,7 +81,8 @@ export const checkForNip07Plugin = () => {
const signer = new NDKNip07Signer(2000) const signer = new NDKNip07Signer(2000)
export const logged_in_user: Writable<undefined | User> = writable(undefined) export const logged_in_user: Writable<undefined | UserObject> =
writable(undefined)
export const login = async (): Promise<void> => { export const login = async (): Promise<void> => {
return new Promise(async (res, rej) => { return new Promise(async (res, rej) => {

Loading…
Cancel
Save