Compare commits

...

3 Commits

Author SHA1 Message Date
Jon Staab
c15453b996 remove amber 2024-06-17 12:33:13 -07:00
Jon Staab
a94fabdffb Add wot score component 2024-06-17 12:28:38 -07:00
Jon Staab
0d8d832e87 Fix some group related things 2024-06-17 12:28:19 -07:00
15 changed files with 175 additions and 336 deletions

View File

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import {debounce} from "throttle-debounce" import {debounce} from "throttle-debounce"
import {equals} from "ramda"
import {isSearchFeed, makeSearchFeed, makeScopeFeed, Scope, getFeedArgs} from "@welshman/feeds" import {isSearchFeed, makeSearchFeed, makeScopeFeed, Scope, getFeedArgs} from "@welshman/feeds"
import {toSpliced} from "src/util/misc" import {toSpliced} from "src/util/misc"
import {boolCtrl} from "src/partials/utils" import {boolCtrl} from "src/partials/utils"
@ -11,6 +12,7 @@
import MenuItem from "src/partials/MenuItem.svelte" import MenuItem from "src/partials/MenuItem.svelte"
import FeedForm from "src/app/shared/FeedForm.svelte" import FeedForm from "src/app/shared/FeedForm.svelte"
import {router} from "src/app/util" import {router} from "src/app/util"
import {globalFeed} from "src/app/state"
import {normalizeFeedDefinition, displayList, readFeed, makeFeed, displayFeed} from "src/domain" import {normalizeFeedDefinition, displayList, readFeed, makeFeed, displayFeed} from "src/domain"
import {userListFeeds, canSign, deleteEvent, userFeeds} from "src/engine" import {userListFeeds, canSign, deleteEvent, userFeeds} from "src/engine"
@ -118,15 +120,27 @@
<Anchor modal href="/feeds/create"><i class="fa fa-plus" /></Anchor> <Anchor modal href="/feeds/create"><i class="fa fa-plus" /></Anchor>
</MenuItem> </MenuItem>
<div class="max-h-80 overflow-auto"> <div class="max-h-80 overflow-auto">
<MenuItem on:click={() => setFeed(followsFeed)}>Follows</MenuItem> <MenuItem
<MenuItem on:click={() => setFeed(networkFeed)}>Network</MenuItem> active={equals(followsFeed.definition, $globalFeed.definition)}
on:click={() => setFeed(followsFeed)}>
Follows
</MenuItem>
<MenuItem
active={equals(networkFeed.definition, $globalFeed.definition)}
on:click={() => setFeed(networkFeed)}>
Network
</MenuItem>
{#each $userFeeds as feed} {#each $userFeeds as feed}
<MenuItem on:click={() => setFeed(feed)}> <MenuItem
active={equals(feed.definition, $globalFeed.definition)}
on:click={() => setFeed(feed)}>
{displayFeed(feed)} {displayFeed(feed)}
</MenuItem> </MenuItem>
{/each} {/each}
{#each $userListFeeds as feed} {#each $userListFeeds as feed}
<MenuItem on:click={() => setFeed(feed)}> <MenuItem
active={equals(feed.definition, $globalFeed.definition)}
on:click={() => setFeed(feed)}>
{displayList(feed.list)} {displayList(feed.list)}
</MenuItem> </MenuItem>
{/each} {/each}

View File

@ -1,17 +1,19 @@
<script> <script>
import {ellipsize} from "hurdak" import {ellipsize} from "hurdak"
import {derived} from "svelte/store"
import {remove} from "@welshman/lib"
import Chip from "src/partials/Chip.svelte" import Chip from "src/partials/Chip.svelte"
import Card from "src/partials/Card.svelte" import Card from "src/partials/Card.svelte"
import GroupCircle from "src/app/shared/GroupCircle.svelte" import GroupCircle from "src/app/shared/GroupCircle.svelte"
import PersonCircles from "src/app/shared/PersonCircles.svelte" import PersonCircles from "src/app/shared/PersonCircles.svelte"
import {router} from "src/app/util/router" import {router} from "src/app/util/router"
import {displayGroup, deriveGroup, getWotCommunityMembers} from "src/engine" import {displayGroup, deriveGroup, userFollowsByCommunity, pubkey} from "src/engine"
export let address export let address
export let modal = false export let modal = false
const group = deriveGroup(address) const group = deriveGroup(address)
const members = $getWotCommunityMembers(address) const members = derived(userFollowsByCommunity, $m => remove($pubkey, $m.get(address) || []))
const enter = () => { const enter = () => {
const route = router.at("groups").of(address).at("notes") const route = router.at("groups").of(address).at("notes")
@ -45,9 +47,10 @@
{ellipsize($group.meta.about, 300)} {ellipsize($group.meta.about, 300)}
</p> </p>
{/if} {/if}
{#if members.length > 0} {#if $members.length > 0}
<p class="mt-4 text-lg text-neutral-300">Members:</p> <div class="pt-1">
<PersonCircles pubkeys={members.slice(0, 20)} /> <PersonCircles class="h-6 w-6" pubkeys={$members.slice(0, 20)} />
</div>
{/if} {/if}
</div> </div>
</Card> </Card>

View File

@ -44,101 +44,103 @@
{#await promise} {#await promise}
<!-- pass --> <!-- pass -->
{:then event} {:then event}
<div in:fly|local={{y: 20}}> {#if event}
<Card> <div in:fly|local={{y: 20}}>
<FlexColumn> <Card>
<div class="flex justify-between"> <FlexColumn>
<span>Kind {event.kind}, published {formatTimestamp(pub.created_at)}</span> <div class="flex justify-between">
<Anchor underline modal class="text-sm" on:click={() => open(event)}>View Note</Anchor> <span>Kind {event.kind}, published {formatTimestamp(pub.created_at)}</span>
</div> <Anchor underline modal class="text-sm" on:click={() => open(event)}>View Note</Anchor>
<div class="flex justify-between text-sm"> </div>
<div class="hidden gap-4 sm:flex"> <div class="flex justify-between text-sm">
<span class="flex items-center gap-2"> <div class="hidden gap-4 sm:flex">
<i class="fa fa-check" />
{success.length} succeeded
</span>
{#if pending.length > 0}
<span class="flex items-center gap-2"> <span class="flex items-center gap-2">
<i class="fa fa-circle-notch fa-spin" /> <i class="fa fa-check" />
{pending.length} pending {success.length} succeeded
</span>
{/if}
{#if failure.length > 0}
<span class="flex items-center gap-2">
<i class="fa fa-triangle-exclamation" />
{failure.length} failed
</span>
{/if}
{#if timeout.length > 0}
<span class="flex items-center gap-2">
<i class="fa fa-stopwatch" />
{timeout.length} timed out
</span> </span>
{#if pending.length > 0}
<span class="flex items-center gap-2">
<i class="fa fa-circle-notch fa-spin" />
{pending.length} pending
</span>
{/if}
{#if failure.length > 0}
<span class="flex items-center gap-2">
<i class="fa fa-triangle-exclamation" />
{failure.length} failed
</span>
{/if}
{#if timeout.length > 0}
<span class="flex items-center gap-2">
<i class="fa fa-stopwatch" />
{timeout.length} timed out
</span>
{/if}
</div>
{#if expanded}
<Anchor class="flex items-center gap-2" on:click={collapse}>
<i class="fa fa-caret-up" />
<span class="text-underline">Hide Details</span>
</Anchor>
{:else}
<Anchor class="flex items-center gap-2" on:click={expand}>
<i class="fa fa-caret-down" />
<span class="text-underline">Show Details</span>
</Anchor>
{/if} {/if}
</div> </div>
{#if expanded} {#if expanded}
<Anchor class="flex items-center gap-2" on:click={collapse}> <div transition:slide|local>
<i class="fa fa-caret-up" /> <FlexColumn>
<span class="text-underline">Hide Details</span> {#if pending.length > 0}
</Anchor> <p class="mt-4 text-lg">The following relays are still pending:</p>
{:else} <div class="grid gap-2 sm:grid-cols-2">
<Anchor class="flex items-center gap-2" on:click={expand}> {#each pending as url}
<i class="fa fa-caret-down" /> <RelayCard hideActions {url} />
<span class="text-underline">Show Details</span> {/each}
</Anchor> </div>
{/if}
{#if success.length > 0}
<p class="mt-4 text-lg">The following relays accepted your note:</p>
<div class="grid gap-2 sm:grid-cols-2">
{#each success as url}
<RelayCard hideActions {url} />
{/each}
</div>
{/if}
{#if failure.length > 0}
<p class="mt-4 text-lg">The following relays rejected your note:</p>
{#each failure as url}
<RelayCard {url}>
<div slot="actions">
<Anchor
on:click={() => retry(url, event)}
class="flex items-center gap-2 text-sm">
<i class="fa fa-rotate" /> Retry
</Anchor>
</div>
</RelayCard>
{/each}
{/if}
{#if timeout.length > 0}
<p class="mt-4 text-lg">The following relays did not respond:</p>
{#each timeout as url}
<RelayCard {url}>
<div slot="actions">
<Anchor
on:click={() => retry(url, event)}
class="flex items-center gap-2 text-sm">
<i class="fa fa-rotate" /> Retry
</Anchor>
</div>
</RelayCard>
{/each}
{/if}
</FlexColumn>
</div>
{/if} {/if}
</div> </FlexColumn>
{#if expanded} </Card>
<div transition:slide|local> </div>
<FlexColumn> {/if}
{#if pending.length > 0}
<p class="mt-4 text-lg">The following relays are still pending:</p>
<div class="grid gap-2 sm:grid-cols-2">
{#each pending as url}
<RelayCard hideActions {url} />
{/each}
</div>
{/if}
{#if success.length > 0}
<p class="mt-4 text-lg">The following relays accepted your note:</p>
<div class="grid gap-2 sm:grid-cols-2">
{#each success as url}
<RelayCard hideActions {url} />
{/each}
</div>
{/if}
{#if failure.length > 0}
<p class="mt-4 text-lg">The following relays rejected your note:</p>
{#each failure as url}
<RelayCard {url}>
<div slot="actions">
<Anchor
on:click={() => retry(url, event)}
class="flex items-center gap-2 text-sm">
<i class="fa fa-rotate" /> Retry
</Anchor>
</div>
</RelayCard>
{/each}
{/if}
{#if timeout.length > 0}
<p class="mt-4 text-lg">The following relays did not respond:</p>
{#each timeout as url}
<RelayCard {url}>
<div slot="actions">
<Anchor
on:click={() => retry(url, event)}
class="flex items-center gap-2 text-sm">
<i class="fa fa-rotate" /> Retry
</Anchor>
</div>
</RelayCard>
{/each}
{/if}
</FlexColumn>
</div>
{/if}
</FlexColumn>
</Card>
</div>
{/await} {/await}

View File

@ -0,0 +1 @@

View File

@ -1,7 +1,7 @@
import {partition, prop, uniqBy} from "ramda" import {partition, prop, uniqBy} from "ramda"
import {batch, tryFunc, seconds} from "hurdak" import {batch, tryFunc, seconds} from "hurdak"
import {writable, derived} from "svelte/store" import {writable, derived} from "svelte/store"
import {inc, pushToMapKey, sortBy, now} from "@welshman/lib" import {inc, assoc, pushToMapKey, sortBy, now} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import { import {
Tags, Tags,
@ -14,7 +14,7 @@ import {
REACTION, REACTION,
} from "@welshman/util" } from "@welshman/util"
import {Tracker} from "@welshman/net" import {Tracker} from "@welshman/net"
import type {Feed} from "@welshman/feeds" import type {Feed, RequestItem} from "@welshman/feeds"
import {walkFeed, FeedLoader as CoreFeedLoader} from "@welshman/feeds" import {walkFeed, FeedLoader as CoreFeedLoader} from "@welshman/feeds"
import {noteKinds, isLike, reactionKinds, repostKinds} from "src/util/nostr" import {noteKinds, isLike, reactionKinds, repostKinds} from "src/util/nostr"
import {withGetter} from "src/util/misc" import {withGetter} from "src/util/misc"
@ -59,7 +59,7 @@ const prepFilters = (filters, opts: FeedOpts) => {
return filters return filters
} }
function* getRequestItems({relays, filters}, opts: FeedOpts) { function* getRequestItems({relays, filters}: RequestItem, opts: FeedOpts) {
filters = prepFilters(filters, opts) filters = prepFilters(filters, opts)
// Use relays specified in feeds // Use relays specified in feeds
@ -127,14 +127,15 @@ export const createFeed = (opts: FeedOpts) => {
if (reqs && opts.shouldListen) { if (reqs && opts.shouldListen) {
const tracker = new Tracker() const tracker = new Tracker()
for (const {relays, filters} of reqs) { for (const request of reqs) {
for (const request of Array.from(getRequestItems({relays, filters}, opts))) { for (const {relays, filters} of Array.from(getRequestItems(request, opts))) {
subscribe({ subscribe({
...request, relays,
tracker, tracker,
skipCache: true, skipCache: true,
onEvent: prependEvent, onEvent: prependEvent,
signal: controller.signal, signal: controller.signal,
filters: filters.map(assoc("since", now())),
forcePlatform: opts.forcePlatform && (relays?.length || 0) === 0, forcePlatform: opts.forcePlatform && (relays?.length || 0) === 0,
}) })
} }

View File

@ -14,19 +14,15 @@
import { import {
load, load,
hints, hints,
Amber,
loadHandle, loadHandle,
getExtension, getExtension,
withExtension, withExtension,
loginWithAmber,
loginWithExtension, loginWithExtension,
loginWithNostrConnect, loginWithNostrConnect,
} from "src/engine" } from "src/engine"
import {router} from "src/app/util/router" import {router} from "src/app/util/router"
import {boot} from "src/app/state" import {boot} from "src/app/state"
const amber = Amber.get()
const signUp = () => router.at("signup").replaceModal() const signUp = () => router.at("signup").replaceModal()
const useBunker = () => router.at("login/bunker").replaceModal() const useBunker = () => router.at("login/bunker").replaceModal()
@ -41,15 +37,6 @@
} }
}) })
const useAmber = async () => {
const pubkey = await tryCatch(amber.getPubkey, e => showWarning(e.toString()))
if (pubkey) {
loginWithAmber(pubkey)
boot()
}
}
const usePrivateKey = () => router.at("login/privkey").replaceModal() const usePrivateKey = () => router.at("login/privkey").replaceModal()
const usePublicKey = () => router.at("login/pubkey").replaceModal() const usePublicKey = () => router.at("login/pubkey").replaceModal()
@ -195,14 +182,6 @@
<span>Extension</span> <span>Extension</span>
</Tile> </Tile>
{/if} {/if}
{#if amber.isEnabled()}
<Tile class="cursor-pointer bg-tinted-800" on:click={useAmber}>
<div>
<i class="fa fa-gem fa-xl" />
</div>
<span>Amber</span>
</Tile>
{/if}
<Tile class="cursor-pointer bg-tinted-800" on:click={usePrivateKey}> <Tile class="cursor-pointer bg-tinted-800" on:click={usePrivateKey}>
<div> <div>
<i class="fa fa-key fa-xl" /> <i class="fa fa-key fa-xl" />

View File

@ -919,8 +919,6 @@ export const loginWithPublicKey = pubkey => addSession({method: "pubkey", pubkey
export const loginWithExtension = pubkey => addSession({method: "extension", pubkey}) export const loginWithExtension = pubkey => addSession({method: "extension", pubkey})
export const loginWithAmber = pubkey => addSession({method: "amber", pubkey})
export const loginWithNsecBunker = async (pubkey, connectToken, connectRelay) => { export const loginWithNsecBunker = async (pubkey, connectToken, connectRelay) => {
const connectKey = generatePrivateKey() const connectKey = generatePrivateKey()
const connectHandler = {relays: [connectRelay]} const connectHandler = {relays: [connectRelay]}

View File

@ -11,6 +11,7 @@ import {
MUTES, MUTES,
FOLLOWS, FOLLOWS,
RELAYS, RELAYS,
COMMUNITIES,
} from "@welshman/util" } from "@welshman/util"
import {tryJson} from "src/util/misc" import {tryJson} from "src/util/misc"
import {appDataKeys, giftWrapKinds, getPublicKey} from "src/util/nostr" import {appDataKeys, giftWrapKinds, getPublicKey} from "src/util/nostr"
@ -195,9 +196,9 @@ projections.addHandler(27, (e: TrustedEvent) => {
} }
}) })
// Membership access/exit requests // Membership
projections.addHandler(10004, (e: TrustedEvent) => { projections.addHandler(COMMUNITIES, (e: TrustedEvent) => {
let session = getSession(e.pubkey) let session = getSession(e.pubkey)
if (!session) { if (!session) {

View File

@ -38,6 +38,7 @@ import {
sort, sort,
groupBy, groupBy,
indexBy, indexBy,
pushToMapKey,
} from "@welshman/lib" } from "@welshman/lib"
import { import {
WRAP, WRAP,
@ -689,7 +690,7 @@ export const communityLists = withGetter(
) )
export const communityListsByPubkey = withGetter( export const communityListsByPubkey = withGetter(
derived(muteLists, $ls => indexBy($l => $l.event.pubkey, $ls)), derived(communityLists, $ls => indexBy($l => $l.event.pubkey, $ls)),
) )
export const getCommunityList = (pk: string) => export const getCommunityList = (pk: string) =>
@ -703,16 +704,17 @@ export const getCommunities = (pk: string) => getSingletonValues("a", getCommuni
export const deriveCommunities = (pk: string) => export const deriveCommunities = (pk: string) =>
derived(communityListsByPubkey, m => getSingletonValues("a", m.get(pk))) derived(communityListsByPubkey, m => getSingletonValues("a", m.get(pk)))
export const getWotCommunityMembers = withGetter( export const userFollowsByCommunity = derived(communityLists, $communityLists => {
derived( const m = new Map<string, string[]>()
[userFollows, communityListsByPubkey],
([$userFollows, $communityListsByPubkey]) => for (const list of $communityLists) {
address => for (const a of getSingletonValues("a", list)) {
Array.from($userFollows).filter(pk => pushToMapKey(m, a, list.event.pubkey)
getSingletonValues("a", $communityListsByPubkey.get(pk)), }
), }
),
) return m
})
// Groups // Groups
@ -722,30 +724,33 @@ export const deriveGroup = address => {
return groups.key(address).derived(defaultTo({id, pubkey, address})) return groups.key(address).derived(defaultTo({id, pubkey, address}))
} }
export const searchGroups = groups.throttle(300).derived($groups => { export const searchGroups = derived(
const options = $groups [groups.throttle(300), userFollowsByCommunity],
.filter(group => !repository.deletes.has(group.address)) ([$groups, $userFollowsByCommunity]) => {
.map(group => ({group, score: getWotCommunityMembers.get()(group.address).length})) const options = $groups
.filter(group => !repository.deletes.has(group.address))
.map(group => ({group, score: $userFollowsByCommunity.get(group.address)?.length || 0}))
const fuse = new Fuse(options, { const fuse = new Fuse(options, {
keys: [{name: "group.id", weight: 0.2}, "group.meta.name", "group.meta.about"], keys: [{name: "group.id", weight: 0.2}, "group.meta.name", "group.meta.about"],
threshold: 0.3, threshold: 0.3,
shouldSort: false, shouldSort: false,
includeScore: true, includeScore: true,
}) })
return (term: string) => { return (term: string) => {
if (!term) { if (!term) {
return sortBy(item => -item.score, options).map(item => item.group) return sortBy(item => -item.score, options).map(item => item.group)
}
return doPipe(fuse.search(term), [
$results =>
sortBy((r: any) => r.score - Math.pow(Math.max(0, r.item.score), 1 / 100), $results),
$results => $results.map((r: any) => r.item.group),
])
} }
},
return doPipe(fuse.search(term), [ )
$results =>
sortBy((r: any) => r.score - Math.pow(Math.max(0, r.item.score), 1 / 100), $results),
$results => $results.map((r: any) => r.item.group),
])
}
})
export const getRecipientKey = wrap => { export const getRecipientKey = wrap => {
const pubkey = Tags.fromEvent(wrap).values("p").first() const pubkey = Tags.fromEvent(wrap).values("p").first()
@ -1601,6 +1606,8 @@ export const publish = ({forcePlatform = true, ...request}: MyPublishRequest) =>
// Add the event to projections // Add the event to projections
if (canUnwrap(request.event)) { if (canUnwrap(request.event)) {
ensureUnwrapped(request.event).then(projections.push) ensureUnwrapped(request.event).then(projections.push)
} else {
projections.push(request.event)
} }
// Listen to updates and update our publish queue // Listen to updates and update our publish queue

View File

@ -1,160 +0,0 @@
import {defer} from "hurdak"
import {sleep, tryCatch, Worker} from "@welshman/lib"
import type {HashedEvent, SignedEvent} from "@welshman/util"
import {hasValidSignature} from "@welshman/util"
import {parsePubkey} from "src/util/nostr"
const createGetPublicKeyIntent = () =>
`intent:#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=get_public_key;end`
const createSignEventIntent = (draft: HashedEvent) =>
`intent:${encodeURIComponent(
JSON.stringify(draft),
)}#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=sign_event;end`
const createNip04EncryptIntent = (pubkey: string, plainText: string) =>
`intent:${encodeURIComponent(
plainText,
)}#Intent;scheme=nostrsigner;S.pubKey=${pubkey};S.compressionType=none;S.returnType=signature;S.type=nip04_encrypt;end`
const createNip04DecryptIntent = (pubkey: string, data: string) =>
`intent:${encodeURIComponent(
data,
)}#Intent;scheme=nostrsigner;S.pubKey=${pubkey};S.compressionType=none;S.returnType=signature;S.type=nip04_decrypt;end`
const createNip44EncryptIntent = (pubkey: string, plainText: string) =>
`intent:${encodeURIComponent(
plainText,
)}#Intent;scheme=nostrsigner;S.pubKey=${pubkey};S.compressionType=none;S.returnType=signature;S.type=nip44_encrypt;end`
const createNip44DecryptIntent = (pubkey: string, data: string) =>
`intent:${encodeURIComponent(
data,
)}#Intent;scheme=nostrsigner;S.pubKey=${pubkey};S.compressionType=none;S.returnType=signature;S.type=nip44_decrypt;end`
class Request {
result = defer<{result?: string; error?: string}>()
constructor(readonly intent: string) {}
fulfill = async () => {
// Clear out the clipboard if we can
await tryCatch(() => navigator.clipboard.writeText(""))
// Send the intent to amber
const other = window.open(this.intent, "_blank")
// Wait a moment to avoid the visibilitychange listener firing before navigation
await sleep(500)
const cleanup = () => {
document.removeEventListener("visibilitychange", onVisibilityChange)
clearTimeout(timeout)
other.close()
}
const onResult = result => {
this.result.resolve({result})
cleanup()
}
const onError = error => {
this.result.resolve({error})
cleanup()
}
const timeout = setTimeout(() => onError("No data received."), 15000)
const onVisibilityChange = async () => {
await sleep(500)
if (document.visibilityState !== "visible") return
try {
const result = await navigator.clipboard.readText()
if (result) {
onResult(result)
}
} catch (e) {
// Pass, document isn't focused
}
}
document.addEventListener("visibilitychange", onVisibilityChange)
return this.result
}
}
let singleton: Amber
export class Amber {
worker = new Worker<Request>()
constructor() {
this.worker.addGlobalHandler(request => request.fulfill())
}
static get() {
if (!singleton) {
singleton = new Amber()
}
return singleton
}
_request = async (intent: string) => {
const request = new Request(intent)
this.worker.push(request)
return request.result.then(({result, error}) => {
if (error) {
throw error
}
return result
})
}
isEnabled = () => navigator.userAgent.includes("Android") && navigator.clipboard?.readText
getPubkey = async () => {
const result = await this._request(createGetPublicKeyIntent())
const pubkey = await parsePubkey(result)
if (!pubkey) {
throw new Error("Expected clipboard to have pubkey")
}
return pubkey
}
signEvent = async (draft: HashedEvent): Promise<SignedEvent> => {
const sig = await this._request(createSignEventIntent(draft))
if (!sig.match(/^[a-f0-9]+$/)) throw new Error("Expected hex signature")
const event: SignedEvent = {...draft, sig}
if (!hasValidSignature(event)) throw new Error("Invalid signature")
return event
}
nip04Encrypt = (pubkey: string, plaintext: string): Promise<string> =>
this._request(createNip04EncryptIntent(pubkey, plaintext))
nip04Decrypt = (pubkey: string, data: string): Promise<string> =>
this._request(createNip04DecryptIntent(pubkey, data))
nip44Encrypt = (pubkey: string, plaintext: string): Promise<string> =>
this._request(createNip44EncryptIntent(pubkey, plaintext))
nip44Decrypt = (pubkey: string, data: string): Promise<string> =>
this._request(createNip44DecryptIntent(pubkey, data))
}

View File

@ -5,7 +5,6 @@ import {Nip59} from "./nip59"
import {Signer} from "./signer" import {Signer} from "./signer"
import {Connect} from "./connect" import {Connect} from "./connect"
export * from "./amber"
export * from "./nip04" export * from "./nip04"
export * from "./nip07" export * from "./nip07"
export * from "./nip44" export * from "./nip44"

View File

@ -3,7 +3,6 @@ import {switcherFn, tryFunc} from "hurdak"
import type {Session} from "src/engine/model" import type {Session} from "src/engine/model"
import type {Connect} from "./connect" import type {Connect} from "./connect"
import {withExtension} from "./nip07" import {withExtension} from "./nip07"
import {Amber} from "./amber"
export class Nip04 { export class Nip04 {
constructor( constructor(
@ -12,7 +11,7 @@ export class Nip04 {
) {} ) {}
isEnabled() { isEnabled() {
return ["amber", "privkey", "connect", "extension"].includes(this.session?.method) return ["privkey", "connect", "extension"].includes(this.session?.method)
} }
async encrypt(message: string, pk: string, sk: string) { async encrypt(message: string, pk: string, sk: string) {
@ -27,7 +26,6 @@ export class Nip04 {
const {method, privkey} = this.session const {method, privkey} = this.session
return switcherFn(method, { return switcherFn(method, {
amber: () => Amber.get().nip04Encrypt(pk, message),
privkey: () => this.encrypt(message, pk, privkey), privkey: () => this.encrypt(message, pk, privkey),
extension: () => withExtension(ext => ext.nip04.encrypt(pk, message)), extension: () => withExtension(ext => ext.nip04.encrypt(pk, message)),
connect: () => this.connect.broker.nip04Encrypt(pk, message), connect: () => this.connect.broker.nip04Encrypt(pk, message),
@ -38,7 +36,6 @@ export class Nip04 {
const {method, privkey} = this.session const {method, privkey} = this.session
return switcherFn(method, { return switcherFn(method, {
amber: () => Amber.get().nip04Decrypt(pk, message),
privkey: () => this.decrypt(message, pk, privkey), privkey: () => this.decrypt(message, pk, privkey),
extension: () => withExtension(ext => ext.nip04.decrypt(pk, message)), extension: () => withExtension(ext => ext.nip04.decrypt(pk, message)),
connect: () => this.connect.broker.nip04Decrypt(pk, message), connect: () => this.connect.broker.nip04Decrypt(pk, message),

View File

@ -6,7 +6,6 @@ import {fromHex} from "src/util/nostr"
import type {Session} from "src/engine/model" import type {Session} from "src/engine/model"
import type {Connect} from "./connect" import type {Connect} from "./connect"
import {withExtension} from "./nip07" import {withExtension} from "./nip07"
import {Amber} from "./amber"
// Deriving shared secret is an expensive computation, cache it // Deriving shared secret is an expensive computation, cache it
export const getSharedSecret = cached({ export const getSharedSecret = cached({
@ -22,7 +21,7 @@ export class Nip44 {
) {} ) {}
isEnabled() { isEnabled() {
if (["amber", "privkey", "connect"].includes(this.session?.method)) { if (["privkey", "connect"].includes(this.session?.method)) {
return true return true
} }
@ -45,7 +44,6 @@ export class Nip44 {
const {method, privkey} = this.session const {method, privkey} = this.session
return switcherFn(method, { return switcherFn(method, {
amber: () => Amber.get().nip44Encrypt(pk, message),
privkey: () => this.encrypt(message, pk, privkey), privkey: () => this.encrypt(message, pk, privkey),
extension: () => withExtension(ext => ext.nip44.encrypt(pk, message)), extension: () => withExtension(ext => ext.nip44.encrypt(pk, message)),
connect: () => this.connect.broker.nip44Encrypt(pk, message), connect: () => this.connect.broker.nip44Encrypt(pk, message),
@ -56,7 +54,6 @@ export class Nip44 {
const {method, privkey} = this.session const {method, privkey} = this.session
return switcherFn(method, { return switcherFn(method, {
amber: () => Amber.get().nip44Decrypt(pk, message),
privkey: () => this.decrypt(message, pk, privkey), privkey: () => this.decrypt(message, pk, privkey),
extension: () => withExtension(ext => ext.nip44.decrypt(pk, message)), extension: () => withExtension(ext => ext.nip44.decrypt(pk, message)),
connect: () => this.connect.broker.nip44Decrypt(pk, message), connect: () => this.connect.broker.nip44Decrypt(pk, message),

View File

@ -5,7 +5,6 @@ import {getPublicKey, getSignature} from "src/util/nostr"
import type {Session} from "src/engine/model" import type {Session} from "src/engine/model"
import type {Connect} from "./connect" import type {Connect} from "./connect"
import {withExtension} from "./nip07" import {withExtension} from "./nip07"
import {Amber} from "./amber"
export class Signer { export class Signer {
constructor( constructor(
@ -14,7 +13,7 @@ export class Signer {
) {} ) {}
isEnabled() { isEnabled() {
return ["amber", "connect", "privkey", "extension"].includes(this.session?.method) return ["connect", "privkey", "extension"].includes(this.session?.method)
} }
prepWithKey(event: EventTemplate, sk: string) { prepWithKey(event: EventTemplate, sk: string) {
@ -48,7 +47,6 @@ export class Signer {
const event = this.prepAsUser(template) const event = this.prepAsUser(template)
return switcherFn(method, { return switcherFn(method, {
amber: () => Amber.get().signEvent(event),
privkey: () => ({...event, sig: getSignature(event, privkey)}), privkey: () => ({...event, sig: getSignature(event, privkey)}),
extension: () => withExtension(ext => ext.signEvent(event)), extension: () => withExtension(ext => ext.signEvent(event)),
connect: () => this.connect.broker.signEvent(template), connect: () => this.connect.broker.signEvent(template),

View File

@ -3,12 +3,14 @@
import Anchor from "src/partials/Anchor.svelte" import Anchor from "src/partials/Anchor.svelte"
export let inert = false export let inert = false
export let active = false
</script> </script>
<Anchor <Anchor
{...$$props} {...$$props}
class={cx($$props.class, "block p-3 px-4", { class={cx($$props.class, "block p-3 px-4", {
"transition-all hover:bg-accent hover:text-white": !inert, "bg-accent text-neutral-100": active,
"transition-all hover:bg-accent hover:text-neutral-100": !inert,
})} })}
on:click> on:click>
<slot /> <slot />