Move store to paravel

This commit is contained in:
Jon Staab 2024-03-26 13:42:00 -07:00
parent e2fe579e6c
commit c0d468a58a
37 changed files with 41 additions and 381 deletions

View File

@ -2,6 +2,7 @@
import {fromPairs} from "ramda"
import {batch} from "hurdak"
import {onMount} from "svelte"
import {writable} from "@coracle.social/lib"
import {getAddress, getReplyFilters} from "@coracle.social/util"
import Calendar from "@event-calendar/core"
import DayGrid from "@event-calendar/day-grid"
@ -15,7 +16,6 @@
hints,
canSign,
getRelaysFromFilters,
writable,
forcePlatformRelays,
load,
isDeleted,

View File

@ -1,6 +1,7 @@
<script lang="ts">
import {onMount} from "svelte"
import {Storage} from "hurdak"
import {writable, readable} from "@coracle.social/lib"
import {FeedLoader} from "src/engine"
import {createScroller} from "src/util/misc"
import {LOCAL_RELAY_URL} from "src/util/nostr"
@ -13,8 +14,6 @@
import type {DynamicFilter} from "src/engine"
import {
hints,
readable,
writable,
compileFilters,
forcePlatformRelays,
searchableRelays,

View File

@ -1,5 +1,6 @@
<script lang="ts">
import {join, identity} from "ramda"
import {writable} from "@coracle.social/lib"
import {Tags, createEvent} from "@coracle.social/util"
import {toast} from "src/partials/state"
import Anchor from "src/partials/Anchor.svelte"
@ -16,7 +17,6 @@
import {
env,
pubkey,
writable,
Publisher,
getClientTags,
tagsFromContent,

View File

@ -1,4 +1,5 @@
<script lang="ts">
import {writable} from "@coracle.social/lib"
import {Tags, createEvent} from "@coracle.social/util"
import {createEventDispatcher} from "svelte"
import {join, without, uniq} from "ramda"
@ -14,7 +15,6 @@
env,
Publisher,
uniqTags,
writable,
publishToZeroOrMoreGroups,
tagsFromContent,
getClientTags,

View File

@ -13,7 +13,7 @@
</style>
<script context="module">
import {writable} from "src/engine"
import {writable} from "@coracle.social/lib"
const maxWot = writable(10)
</script>

View File

@ -1,12 +1,13 @@
<script lang="ts">
import {throttle} from "throttle-debounce"
import {derived} from "@coracle.social/lib"
import {slide} from "src/util/transition"
import {fuzzy} from "src/util/misc"
import {parseAnything} from "src/util/nostr"
import FlexColumn from 'src/partials/FlexColumn.svelte'
import FlexColumn from "src/partials/FlexColumn.svelte"
import {router} from "src/app/router"
import type {Person, Topic} from "src/engine"
import {topics, derived, searchPeople, createPeopleLoader} from "src/engine"
import {topics, searchPeople, createPeopleLoader} from "src/engine"
export let term
export let replace = false

View File

@ -1,5 +1,6 @@
import Bugsnag from "@bugsnag/js"
import {hash, union} from "hurdak"
import {writable} from "@coracle.social/lib"
import {ConnectionStatus} from "@coracle.social/network"
import {warn} from "src/util/logger"
import {userKinds} from "src/util/nostr"
@ -12,7 +13,6 @@ import {
pubkey,
follows,
session,
writable,
loadSeen,
loadGroups,
loadDeletes,

View File

@ -2,6 +2,7 @@
import {onMount} from "svelte"
import {filter} from "ramda"
import {toTitle, Storage} from "hurdak"
import {readable} from "@coracle.social/lib"
import {slide} from "src/util/transition"
import Tabs from "src/partials/Tabs.svelte"
import Card from "src/partials/Card.svelte"
@ -15,7 +16,6 @@
import {
nip44,
pubkey,
readable,
canSign,
channels,
hasNewMessages,

View File

@ -4,7 +4,7 @@
import {v4 as uuid} from "uuid"
import {join, whereEq, identity} from "ramda"
import {throttle, commaFormat, toTitle, switcherFn} from "hurdak"
import {now} from "@coracle.social/lib"
import {now, writable} from "@coracle.social/lib"
import {createEvent, Tags} from "@coracle.social/util"
import {currencyOptions} from "src/util/i18n"
import {dateToSeconds} from "src/util/misc"
@ -34,7 +34,6 @@
env,
hints,
session,
writable,
getClientTags,
tagsFromContent,
publishToZeroOrMoreGroups,

View File

@ -1,11 +1,11 @@
<script lang="ts">
import {writable} from "@coracle.social/lib"
import Input from "src/partials/Input.svelte"
import Textarea from "src/partials/Textarea.svelte"
import ImageInput from "src/partials/ImageInput.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Field from "src/partials/Field.svelte"
import NsecWarning from "src/app/shared/NsecWarning.svelte"
import {writable} from "src/engine"
export let profile
export let setStage
@ -34,7 +34,8 @@
</script>
<div class="flex gap-3">
<p class="-ml-1 -mt-2 flex h-12 w-12 items-center justify-center rounded-full bg-neutral-700 text-lg">
<p
class="-ml-1 -mt-2 flex h-12 w-12 items-center justify-center rounded-full bg-neutral-700 text-lg">
2/4
</p>
<p class="text-2xl font-bold">Give us something to go on!</p>

View File

@ -1,5 +1,5 @@
import {none, any, filter} from "ramda"
import {derived} from "src/engine/core/utils"
import {derived} from "@coracle.social/lib"
import {pubkey} from "src/engine/session/state"
import {mutes} from "src/engine/people/derived"
import type {Channel} from "./model"

View File

@ -1,4 +1,4 @@
import {collection} from "src/engine/core/utils"
import {collection} from "@coracle.social/lib"
import type {Channel} from "./model"
export const channels = collection<Channel>("id")

View File

@ -1,2 +1 @@
export * from "./store"
export * from "./storage"

View File

@ -1,11 +1,11 @@
import {prop, identity, pluck, splitAt, nth, sortBy} from "ramda"
import {sleep, defer, chunk, randomInt, throttle} from "hurdak"
import {Storage as LocalStorage} from "hurdak"
import {writable} from "@coracle.social/lib"
import type {Writable, Collection} from "@coracle.social/lib"
import logger from "src/util/logger"
import {sessions} from "src/engine/session/state"
import {people} from "src/engine/people/state"
import type {Writable, Collection} from "./store"
import {writable} from "./store"
type Store = {
name: string

View File

@ -1,335 +0,0 @@
import {throttle} from "throttle-debounce"
import {is, identity, reject, filter, map, findIndex, equals} from "ramda"
import {ensurePlural} from "hurdak"
import logger from "src/util/logger"
type Invalidator<T> = (value?: T) => void
type Derivable = Readable<any> | Readable<any>[]
type Subscriber<T> = (value: T) => void
type Unsubscriber = () => void
type R = Record<string, any>
type M<T> = Map<string, T>
export interface Readable<T> {
get: () => T
subscribe(this: void, run: Subscriber<T>, invalidate?: Invalidator<T>): Unsubscriber
derived: <U>(f: (v: T) => U) => Readable<U>
throttle(t: number): Readable<T>
}
export class Writable<T> implements Readable<T> {
private value: T
private subs: Subscriber<T>[] = []
constructor(defaultValue: T, t?: number) {
this.value = defaultValue
if (t) {
this.notify = throttle(t, this.notify)
}
}
notify = () => {
for (const sub of this.subs) {
sub(this.value)
}
}
get() {
return this.value
}
set(newValue: T) {
this.value = newValue
this.notify()
}
update(f: (v: T) => T) {
this.set(f(this.value))
}
async updateAsync(f: (v: T) => Promise<T>) {
this.set(await f(this.value))
}
subscribe(f: Subscriber<T>) {
this.subs.push(f)
f(this.value)
return () => {
const idx = findIndex(equals(f), this.subs)
this.subs.splice(idx, 1)
}
}
derived<U>(f: (v: T) => U): Derived<U> {
return new Derived<U>(this, f)
}
throttle = (t: number) => {
return new Derived<T>(this, identity, t)
}
}
export class Derived<T> implements Readable<T> {
private callerSubs: Subscriber<T>[] = []
private mySubs: Unsubscriber[] = []
private stores: Derivable
private getValue: (values: any) => T
private latestValue: T | undefined
constructor(stores: Derivable, getValue: (values: any) => T, t = 0) {
this.stores = stores
this.getValue = getValue
if (t) {
this.notify = throttle(t, this.notify)
}
}
notify = () => {
this.latestValue = undefined
this.callerSubs.forEach(f => f(this.get()))
}
getInput() {
if (is(Array, this.stores)) {
return ensurePlural(this.stores).map(s => s.get())
} else {
return this.stores.get()
}
}
get = (): T => {
// Recalculate if we're not subscribed, because we won't get notified when deps change
if (this.latestValue === undefined || this.mySubs.length === 0) {
this.latestValue = this.getValue(this.getInput())
}
return this.latestValue
}
subscribe(f: Subscriber<T>) {
if (this.callerSubs.length === 0) {
for (const s of ensurePlural(this.stores)) {
this.mySubs.push(s.subscribe(this.notify))
}
}
this.callerSubs.push(f)
f(this.get())
return () => {
const idx = findIndex(equals(f), this.callerSubs)
this.callerSubs.splice(idx, 1)
if (this.callerSubs.length === 0) {
for (const unsub of this.mySubs.splice(0)) {
unsub()
}
}
}
}
derived<U>(f: (v: T) => U): Readable<U> {
return new Derived(this, f) as Readable<U>
}
throttle = (t: number) => {
return new Derived<T>(this, identity, t)
}
}
export class Key<T extends R> implements Readable<T> {
readonly pk: string
readonly key: string
private base: Writable<M<T>>
private store: Readable<T>
constructor(base: Writable<M<T>>, pk: string, key: string) {
if (!is(Map, base.get())) {
throw new Error("`key` can only be used on map collections")
}
this.pk = pk
this.key = key
this.base = base
this.store = base.derived<T>(m => m.get(key) as T)
}
get = () => this.base.get().get(this.key) as T
subscribe = (f: Subscriber<T>) => this.store.subscribe(f)
derived = <U>(f: (v: T) => U) => this.store.derived<U>(f)
throttle = (t: number) => this.store.throttle(t)
exists = () => this.base.get().has(this.key)
update = (f: (v: T) => T) =>
this.base.update((m: M<T>) => {
if (!this.key) {
throw new Error(`Cannot set key: "${this.key}"`)
}
// Make sure the pk always get set on the record
const {pk, key} = this
const oldValue = {...m.get(key), [pk]: key}
const newValue = {...f(oldValue), [pk]: key}
m.set(this.key, newValue)
return m
})
set = (v: T) => this.update(() => v)
merge = (d: Partial<T>) => this.update(v => ({...v, ...d}))
remove = () =>
this.base.update(m => {
m.delete(this.key)
return m
})
pop = () => {
const v = this.get()
this.remove()
return v
}
}
export class DerivedKey<T extends R> implements Readable<T> {
readonly pk: string
readonly key: string
private base: Readable<M<T>>
private store: Readable<T>
constructor(base: Readable<M<T>>, pk: string, key: string) {
if (!is(Map, base.get())) {
throw new Error("`key` can only be used on map collections")
}
this.pk = pk
this.key = key
this.base = base
this.store = base.derived<T>(m => m.get(key) as T)
}
get = () => this.base.get().get(this.key) as T
subscribe = (f: Subscriber<T>) => this.store.subscribe(f)
derived = <U>(f: (v: T) => U) => this.store.derived<U>(f)
throttle = (t: number) => this.store.throttle(t)
exists = () => this.base.get().has(this.key)
}
export class Collection<T extends R> implements Readable<T[]> {
readonly pk: string
readonly mapStore: Writable<M<T>>
readonly listStore: Readable<T[]>
constructor(pk: string, t?: number) {
this.pk = pk
this.mapStore = writable(new Map())
this.listStore = this.mapStore.derived<T[]>((m: M<T>) => Array.from(m.values()))
if (t) {
this.mapStore.notify = throttle(t, this.mapStore.notify)
}
}
get = () => this.listStore.get()
getMap = () => this.mapStore.get()
subscribe = (f: Subscriber<T[]>) => this.listStore.subscribe(f)
derived = <U>(f: (v: T[]) => U) => this.listStore.derived<U>(f)
throttle = (t: number) => this.listStore.throttle(t)
key = (k: string) => new Key(this.mapStore, this.pk, k)
set = (xs: T[]) => {
const m = new Map()
for (const x of xs) {
if (!x) {
logger.error("Empty value passed to collection store")
} else if (!x[this.pk]) {
logger.error(`Value with empty ${this.pk} passed to collection store`, x)
} else {
m.set(x[this.pk], x)
}
}
this.mapStore.set(m)
}
update = (f: (v: T[]) => T[]) => this.set(f(this.get()))
updateAsync = async (f: (v: T[]) => Promise<T[]>) => this.set(await f(this.get()))
reject = (f: (v: T) => boolean) => this.update(reject(f))
filter = (f: (v: T) => boolean) => this.update(filter(f))
map = (f: (v: T) => T) => this.update(map(f))
}
export class DerivedCollection<T extends R> implements Readable<T[]> {
readonly listStore: Derived<T[]>
readonly mapStore: Readable<M<T>>
constructor(
readonly pk: string,
stores: Derivable,
getValue: (values: any) => T[],
t = 0,
) {
this.listStore = new Derived(stores, getValue, t)
this.mapStore = new Derived(this.listStore, xs => new Map(xs.map(x => [x[pk], x])))
}
get = () => this.listStore.get()
getMap = () => this.mapStore.get()
subscribe = (f: Subscriber<T[]>) => this.listStore.subscribe(f)
derived = <U>(f: (v: T[]) => U) => this.listStore.derived<U>(f)
throttle = (t: number) => this.listStore.throttle(t)
key = (k: string) => new DerivedKey(this.mapStore, this.pk, k)
}
export const writable = <T>(v: T) => new Writable(v)
export const derived = <T>(stores: Derivable, getValue: (values: any) => T) =>
new Derived(stores, getValue)
export const readable = <T>(v: T) => derived(new Writable(v), identity) as Readable<T>
export const derivedCollection = <T>(
pk: string,
stores: Derivable,
getValue: (values: any) => T[],
) => new DerivedCollection(pk, stores, getValue)
export const key = <T extends R>(base: Writable<M<T>>, pk: string, key: string) =>
new Key<T>(base, pk, key)
export const collection = <T extends R>(pk: string) => new Collection<T>(pk)

View File

@ -1,6 +1,6 @@
import {Tags, getIdAndAddress} from "@coracle.social/util"
import {whereEq, groupBy, find} from "ramda"
import {derived, DerivedCollection} from "src/engine/core/utils"
import {derived, DerivedCollection} from "@coracle.social/lib"
import {pubkey} from "src/engine/session/state"
import {settings} from "src/engine/session/derived"
import {getWotScore} from "src/engine/people/utils"

View File

@ -1,4 +1,4 @@
import {Collection, Writable} from "src/engine/core/utils"
import {Collection, Writable} from "@coracle.social/lib"
import type {Event, ReadReceipt} from "./model"
export const _events = new Collection<Event>("id", 1000)

View File

@ -1,4 +1,4 @@
import {collection} from "src/engine/core/utils"
import {collection} from "@coracle.social/lib"
import type {Group, GroupKey, GroupRequest, GroupAlert} from "./model"
export const groups = collection<Group>("address")

View File

@ -1,7 +1,6 @@
import {sortBy} from "ramda"
import {cached} from "@coracle.social/lib"
import {cached, derived} from "@coracle.social/lib"
import {Tags} from "@coracle.social/util"
import {derived} from "src/engine/core/utils"
import {load} from "src/engine/network/utils"
import {hints} from "src/engine/relays/utils"
import {follows} from "src/engine/people/derived"

View File

@ -1,4 +1,4 @@
import {collection} from "src/engine/core/utils"
import {collection} from "@coracle.social/lib"
import type {Handler, HandlerRec} from "./model"
export const handlers = collection<Handler>("address")

View File

@ -1,5 +1,5 @@
import {whereEq} from "ramda"
import {derivedCollection} from "src/engine/core/utils"
import {derivedCollection} from "@coracle.social/lib"
import {deletes} from "src/engine/events/state"
import {pubkey} from "src/engine/session/state"
import type {Event} from "src/engine/events/model"

View File

@ -1,4 +1,4 @@
import {collection} from "src/engine/core/utils"
import {collection} from "@coracle.social/lib"
import type {Event} from "src/engine/events/model"
export const _labels = collection<Event>("id")

View File

@ -1,5 +1,5 @@
import {whereEq, sortBy} from "ramda"
import {derivedCollection} from "src/engine/core/utils"
import {derivedCollection} from "@coracle.social/lib"
import {pubkey} from "src/engine/session/state"
import {deletes} from "src/engine/events/state"
import type {List} from "./model"

View File

@ -1,4 +1,4 @@
import {collection} from "src/engine/core/utils"
import {collection} from "@coracle.social/lib"
import type {List} from "./model"
export const _lists = collection<List>("naddr")

View File

@ -1,12 +1,11 @@
import {mergeLeft, pluck, min, max, identity, sortBy} from "ramda"
import {first, sleep} from "hurdak"
import {now} from "@coracle.social/lib"
import {now, writable} from "@coracle.social/lib"
import type {Filter} from "@coracle.social/util"
import {guessFilterDelta} from "@coracle.social/util"
import type {Subscription} from "@coracle.social/network"
import type {Event} from "src/engine/events/model"
import {sortEventsDesc} from "src/engine/events/utils"
import {writable} from "src/engine/core/utils"
import {getUrls} from "./executor"
import {subscribe} from "./subscribe"
import {Tracker} from "./tracker"

View File

@ -1,6 +1,6 @@
import {partition, concat, prop, uniqBy, identity, without, assoc} from "ramda"
import {ensurePlural, doPipe, batch} from "hurdak"
import {now} from "@coracle.social/lib"
import {now, writable} from "@coracle.social/lib"
import type {Filter} from "@coracle.social/util"
import {
Tags,
@ -16,7 +16,6 @@ import type {DisplayEvent} from "src/engine/notes/model"
import type {Event} from "src/engine/events/model"
import {sortEventsDesc, unwrapRepost} from "src/engine/events/utils"
import {isEventMuted, isDeleted} from "src/engine/events/derived"
import {writable} from "src/engine/core/utils"
import {getUrls} from "./executor"
import {subscribe} from "./subscribe"
import {MultiCursor} from "./cursor"

View File

@ -1,9 +1,9 @@
import {uniqBy, identity, prop, sortBy} from "ramda"
import {batch} from "hurdak"
import {writable} from "@coracle.social/lib"
import {Tags, getIdOrAddress, getIdFilters, getIdAndAddress} from "@coracle.social/util"
import type {DisplayEvent} from "src/engine/notes/model"
import type {Event} from "src/engine/events/model"
import {writable} from "src/engine/core/utils"
import {hints} from "src/engine/relays/utils"
import {load} from "./load"

View File

@ -1,6 +1,6 @@
import {assoc, without, max, sortBy} from "ramda"
import {seconds} from "hurdak"
import {now} from "@coracle.social/lib"
import {now, derived} from "@coracle.social/lib"
import {Tags} from "@coracle.social/util"
import {isLike, reactionKinds, noteKinds, repostKinds} from "src/util/nostr"
import {tryJson} from "src/util/misc"
@ -8,7 +8,6 @@ import {isSeen} from "src/engine/events/derived"
import {deletes} from "src/engine/events/state"
import {unwrapRepost} from "src/engine/events/utils"
import {events, isEventMuted} from "src/engine/events/derived"
import {derived} from "src/engine/core/utils"
import {groupRequests, groupAdminKeys, groupAlerts} from "src/engine/groups/state"
import {getUserCircles} from "src/engine/groups/utils"
import {pubkey} from "src/engine/session/state"

View File

@ -1,7 +1,7 @@
import Fuse from "fuse.js"
import {doPipe} from "hurdak"
import {defaultTo, map, filter, sortBy} from "ramda"
import {derived} from "src/engine/core/utils"
import {derived} from "@coracle.social/lib"
import {pubkey} from "src/engine/session/state"
import {user} from "src/engine/session/derived"
import type {Person} from "./model"

View File

@ -1,7 +1,7 @@
import {debounce} from "throttle-debounce"
import {always} from "ramda"
import {noop, sleep} from "hurdak"
import {writable} from "src/engine/core/utils"
import {writable} from "@coracle.social/lib"
import {load} from "src/engine/network/utils"
import {searchableRelays} from "src/engine/relays/derived"
import type {Event} from "src/engine/events/model"

View File

@ -1,4 +1,4 @@
import {collection} from "src/engine/core/utils"
import {collection} from "@coracle.social/lib"
import type {Person} from "src/engine/people/model"
export const people = collection<Person>("pubkey")

View File

@ -1,4 +1,4 @@
import {collection} from "src/engine/core/utils"
import {collection} from "@coracle.social/lib"
import type {Relay} from "./model"
export const relays = collection<Relay>("url")

View File

@ -1,4 +1,4 @@
import {derived} from "src/engine/core/utils"
import {derived} from "@coracle.social/lib"
import type {Person} from "src/engine/people/model"
import {people} from "src/engine/people/state"
import type {Session} from "./model"

View File

@ -1,4 +1,4 @@
import {writable} from "src/engine/core/utils"
import {writable} from "@coracle.social/lib"
import type {Session} from "./model"
export const env = writable<Record<string, any>>({})

View File

@ -1,4 +1,4 @@
import {collection} from "src/engine/core/utils"
import {collection} from "@coracle.social/lib"
import type {Topic} from "./model"
export const topics = collection<Topic>("name")

View File

@ -1,9 +1,9 @@
import {debounce} from "throttle-debounce"
import {prop, last, fromPairs} from "ramda"
import {randomId, Storage} from "hurdak"
import type {Writable} from "@coracle.social/lib"
import {writable} from "@coracle.social/lib"
import {parseHex} from "src/util/html"
import type {Writable} from "src/engine"
import {writable} from "src/engine"
export const synced = (key: string, defaultValue: any) => {
const store = writable(Storage.getJson(key) || defaultValue)

View File

@ -1,9 +1,9 @@
import {takeWhile, find, filter, identity, mergeLeft, reject} from "ramda"
import {first, randomId, filterVals} from "hurdak"
import {writable} from "@coracle.social/lib"
import logger from "src/util/logger"
import {buildQueryString, parseQueryString, updateIn} from "src/util/misc"
import {globalHistory} from "src/util/history"
import {writable} from "src/engine"
// Adapted from https://github.com/EmilTholin/svelte-routing/blob/master/src/utils.js