Delete readmes, update docs

This commit is contained in:
Jon Staab
2025-04-09 11:17:12 -07:00
parent 3301616e7d
commit 8e585fc150
53 changed files with 1946 additions and 2468 deletions
-73
View File
@@ -1,73 +0,0 @@
# @welshman/app [![version](https://badgen.net/npm/v/@welshman/app)](https://npmjs.com/package/@welshman/app)
Utilities for dealing with svelte stores when using welshman.
```typescript
import {ctx, setContext} from '@welshman/lib'
import {getNip07} from '@welshman/signer'
import {throttled} from '@welshman/store'
import {createEvent, NOTE} from '@welshman/util'
import {
getDefaultNetContext,
getDefaultAppContext,
signer,
pubkey,
publishThunk,
load,
initStorage,
storageAdapters,
freshness,
plaintext,
repository,
tracker,
} from '@welshman/app'
// Set up app config
setContext({
net: getDefaultNetContext(),
app: getDefaultAppContext(),
})
// Log in via NIP 07
addSession({method: 'nip07', pubkey: await getNip07().getPubkey()})
// Signer is ready to go
const event = signer.get().encrypt(/* ... */)
// This will fetch the user's profile automatically, and return an observable that updates
// automatically. Several different stores exist that are ready to go, including handles,
// zappers, relaySelections, relays, follows, mutes.
const profile = deriveProfile(pubkey.get())
// A global router helps make intelligent relay selections
const router = ctx.app.router
// Publish is done using thunks, which optimistically publish to the local database, deferring
// signing and publishing for instant user feedback. Progress is reported as relays accept/reject the event
const thunk = publishThunk({
relays: router.FromUser().getUrls(),
event: createEvent(NOTE, {content: "hi"}),
delay: 3000,
})
// Thunks can be aborted until after `delay`, allowing for soft-undo
thunk.controller.abort()
// Subscriptions automatically infer relays using `router` if not provided. If the request can be cached,
// results from the local repository are returned immediately. `subscribe` and `load` are both available
const events = await load({filters: [{kinds: [NOTE]}])
// Some commands are included
const thunk = follow('97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322')
// Stores can be easily synchronized with indexeddb. Freshness keeps track of how stale the caches are,
// plaintext maps encrypted events to their decrypted content, repository and tracker hold events and
// event/relay mappings, respectively.
const ready = initStorage("my-db", 1, {
relays: {keyPath: "url", store: throttled(3000, relays)},
handles: {keyPath: "nip05", store: throttled(3000, handles)},
freshness: storageAdapters.fromObjectStore(freshness, {throttle: 3000}),
plaintext: storageAdapters.fromObjectStore(plaintext, {throttle: 3000}),
events: storageAdapters.fromRepositoryAndTracker(repository, tracker, {throttle: 3000}),
})
```
+103
View File
@@ -0,0 +1,103 @@
import {get, derived} from 'svelte/store'
import {batch, fromPairs} from '@welshman/lib'
import {PROFILE, FOLLOWS, MUTES, RELAYS, INBOX_RELAYS, getPubkeyTagValues, getListTags} from '@welshman/util'
import {throttled, withGetter} from '@welshman/store'
import {RepositoryUpdate} from '@welshman/relay'
import {getAll, bulkPut, bulkDelete} from './storage.js'
import {relays} from './relays.js'
import {handles, onHandle} from './handles.js'
import {zappers, onZapper} from './zappers.js'
import {plaintext} from './plaintext.js'
import {freshness} from './freshness.js'
import {repository} from './core.js'
import {sessions} from './session.js'
import {userFollows} from './user.js'
export const defaultStorageAdapters = {
relays: {
keyPath: "url",
init: async () => relays.set(await getAll("relays")),
sync: () => throttled(3000, relays).subscribe($relays => bulkPut("relays", $relays)),
},
handles: {
keyPath: "nip05",
init: async () => handles.set(await getAll("handles")),
sync: () => onHandle(batch(300, $handles => bulkPut("handles", $handles))),
},
zappers: {
keyPath: "lnurl",
init: async () => zappers.set(await getAll("zappers")),
sync: () => onZapper(batch(300, $zappers => bulkPut("zappers", $zappers))),
},
freshness: {
keyPath: "key",
init: async () => {
const items = await getAll("freshness")
freshness.set(fromPairs(items.map(item => [item.key, item.value])))
},
sync: () => {
const interval = setInterval(() => {
bulkPut(
"freshness",
Object.entries(freshness.get()).map(([key, value]) => ({key, value})),
)
}, 10_000)
return () => clearInterval(interval)
},
},
plaintext: {
keyPath: "key",
init: async () => {
const items = await getAll("plaintext")
plaintext.set(fromPairs(items.map(item => [item.key, item.value])))
},
sync: () => {
const interval = setInterval(() => {
bulkPut(
"plaintext",
Object.entries(plaintext.get()).map(([key, value]) => ({key, value})),
)
}, 10_000)
return () => clearInterval(interval)
},
},
events: {
keyPath: "id",
init: async () => repository.load(await getAll("events")),
sync: () => {
const userFollowPubkeys = withGetter(
derived(userFollows, l => new Set(getPubkeyTagValues(getListTags(l))))
)
const onUpdate = async ({added, removed}: RepositoryUpdate) => {
const sessionKeys = new Set(Object.keys(sessions.get()))
const metaKinds = [PROFILE, FOLLOWS, MUTES, RELAYS, INBOX_RELAYS]
if (removed.size > 0) {
await bulkDelete("events", Array.from(removed))
}
if (added.length > 0) {
await bulkPut(
"events",
added.filter(e => {
if (sessionKeys.has(e.pubkey)) return true
if (e.tags.some(t => sessionKeys.has(t[1]))) return true
if (metaKinds.includes(e.kind) && userFollowPubkeys.get()?.has(e.pubkey)) return true
return false
}),
)
}
}
repository.on("update", onUpdate)
return () => repository.off("update", onUpdate)
},
},
}
+3 -3
View File
@@ -1,5 +1,5 @@
import {readable, derived, type Readable, type Subscriber} from "svelte/store"
import {indexBy, remove, type Maybe, now} from "@welshman/lib"
import {indexBy, remove, now} from "@welshman/lib"
import {withGetter} from "@welshman/store"
import {getFreshness, setFreshnessThrottled} from "./freshness.js"
@@ -15,7 +15,7 @@ export const collection = <T>({
load?: (key: string, relays: string[]) => Promise<any>
}) => {
const indexStore = withGetter(derived(store, $items => indexBy(getKey, $items)))
const pending = new Map<string, Promise<Maybe<T>>>()
const pending = new Map<string, Promise<T | void>>()
const loadAttempts = new Map<string, number>()
let subscribers: Subscriber<T>[] = []
@@ -76,7 +76,7 @@ export const collection = <T>({
return fresh
}
const deriveItem = (key: Maybe<string>, relays: string[] = []) => {
const deriveItem = (key: string | undefined, relays: string[] = []) => {
if (!key) {
return readable(undefined)
}
+1
View File
@@ -1,3 +1,4 @@
export * from "./adapters.js"
export * from "./context.js"
export * from "./core.js"
export * from "./collection.js"