Add documentation
This commit is contained in:
@@ -1,3 +1,73 @@
|
||||
# @welshman/store [](https://npmjs.com/package/@welshman/store)
|
||||
|
||||
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}),
|
||||
})
|
||||
```
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
@@ -1,11 +1,29 @@
|
||||
# @welshman/content [](https://npmjs.com/package/@welshman/content)
|
||||
|
||||
Utilities for parsing note content.
|
||||
Utilities for parsing and rendering note content. Customizable via RenderOptions.
|
||||
|
||||
```typescript
|
||||
import {parse, render} from '@welshman/content'
|
||||
|
||||
const content = "Hello<br>from https://coracle.tools! <script>alert('evil')</script>"
|
||||
const html = parse({content}).map(render).join("")
|
||||
const parsed = parse({content, tags: []})
|
||||
// [
|
||||
// { type: 'text', value: 'Hello<br>from ', raw: 'Hello<br>from ' },
|
||||
// {
|
||||
// type: 'link',
|
||||
// value: { url: URL, isMedia: false },
|
||||
// raw: 'https://coracle.tools'
|
||||
// },
|
||||
// {
|
||||
// type: 'text',
|
||||
// value: "! <script>alert('evil')</script>",
|
||||
// raw: "! <script>alert('evil')</script>"
|
||||
// }
|
||||
// ]
|
||||
|
||||
const result = renderAsText(parsed)
|
||||
// => Hello<br>from https://coracle.tools/! <script>alert('evil')</script>
|
||||
|
||||
const result = renderAsHtml(parsed)
|
||||
// => Hello<br>from <a href="https://coracle.tools/" target="_blank">coracle.tools/</a>! <script>alert('evil')</script>
|
||||
```
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# @welshman/feeds [](https://npmjs.com/package/@welshman/feeds)
|
||||
# @welshman/feeds [](https://npmjs.com/package/@welshman/feeds)
|
||||
|
||||
A custom feed compiler and loader for nostr. Read the spec on [wikifreedia](https://wikifreedia.xyz/cip-01/97c70a44366a6535c1).
|
||||
|
||||
@@ -18,7 +18,7 @@ const feed = intersectionFeed(
|
||||
scopeFeed("global"),
|
||||
)
|
||||
|
||||
// Create a controller
|
||||
// Create a controller, providing required context via FeedOptions
|
||||
const controller = new FeedController({
|
||||
feed,
|
||||
request,
|
||||
@@ -30,5 +30,5 @@ const controller = new FeedController({
|
||||
})
|
||||
|
||||
// Load notes using the feed
|
||||
controller.load(10)
|
||||
const events = await controller.load(10)
|
||||
```
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
+10
-8
@@ -1,11 +1,13 @@
|
||||
# @welshman/lib [](https://npmjs.com/package/@welshman/lib)
|
||||
|
||||
Some general-purpose utilities used elsewhere in @welshman.
|
||||
Some general-purpose utilities for use in @welshman apps.
|
||||
|
||||
- `Deferred` is just a promise with `resolve` and `reject` methods.
|
||||
- `Emitter` extends EventEmitter to support `emitter.on('*', ...)`.
|
||||
- `Fluent` is a wrapper around arrays with chained methods that modify and copy the underlying array.
|
||||
- `LRUCache` is an implementation of an LRU cache.
|
||||
- `Worker` is an implementation of an asynchronous queue.
|
||||
- `Tools` is a collection of general-purpose utility functions.
|
||||
- `Store` is an implementation of svelte-like subscribable stores with extra features.
|
||||
Includes:
|
||||
|
||||
- LRU cache implementation
|
||||
- Worker for throttling work to avoid locking up the UI
|
||||
- URL normalization (taken from normalize-url)
|
||||
- A global `ctx` variable which can be used for global configuration
|
||||
- CustomPromise, which provides an error type, and `defer` utility
|
||||
- Ramda-like utilities, but without auto-currying
|
||||
- Utils for throttling, working with nil, json, fetch, deep equals, etc.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"exclude": ["normalize-url/*"],
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
+55
-16
@@ -2,21 +2,60 @@
|
||||
|
||||
Utilities having to do with connection management and nostr messages.
|
||||
|
||||
- `Connection` - the main api for dealing with relay connections
|
||||
- `ConnectionAuth` - tracks auth status for a connection
|
||||
- `ConnectionSender` - a send queue for connections
|
||||
- `ConnectionState` - tracks pending publishes and requests for a connection
|
||||
- `ConnectionStats` - tracks timing and error stats for a connection
|
||||
- `Context` - provides default values for configuring `ctx.net`
|
||||
- `Executor` - implements common nostr flows on a given `target`
|
||||
- `Pool` - a thin wrapper around `Map` which stores `Connection`s
|
||||
- `Publish` - utilities for publishing events
|
||||
- `Socket` - a wrapper around isomorphic-ws that handles json parsing/serialization
|
||||
- `Subscribe` - utilities for making requests against nostr relays
|
||||
- `Tracker` - tracks which relays a given event was seen on
|
||||
```typescript
|
||||
import {ctx, setContext} from '@welshman/lib'
|
||||
import {type TrustedEvent, createEvent, NOTE} from '@welshman/util'
|
||||
import {subscribe, publish, getDefaultNetContext} from '@welshman/net'
|
||||
|
||||
Executor `target`s extend `Emitter`, and have a `send` method, a `cleanup` method, and a `connections` getter. They are intended to be passed to an `Executor` for use.
|
||||
// Sets up customizable event valdation, handlers, etc
|
||||
setContext(getDefaultNetContext())
|
||||
|
||||
- `targets/Multi` allows you to compose multiple targets together.
|
||||
- `targets/Relay` takes a `Connection` and provides listeners for different verbs.
|
||||
- `targets/Relays` takes an array of `Connection`s and provides listeners for different verbs, merging all events into a single stream.
|
||||
// Send a subscription
|
||||
const sub = subscribe({
|
||||
relays: ['wss://relay.example.com/'],
|
||||
filters: [{kinds: [1], limit: 1}],
|
||||
closeOnEose: true,
|
||||
timeout: 10000,
|
||||
})
|
||||
|
||||
sub.emitter.on(SubscriptionEvent.Event, (url: string, event: TrustedEvent) => {
|
||||
console.log(url, event)
|
||||
sub.close()
|
||||
})
|
||||
|
||||
// Publish an event
|
||||
const pub = publish({
|
||||
relays: ['wss://relay.example.com/'],
|
||||
event: createEvent(NOTE, {content: 'hi'}),
|
||||
})
|
||||
|
||||
pub.emitter.on('*', (status: PublishStatus, url: string) => {
|
||||
console.log(status, url)
|
||||
})
|
||||
|
||||
// The Tracker class can tell you which relays an event was read from or published to
|
||||
console.log(ctx.net.tracker.getRelays(event.id))
|
||||
```
|
||||
|
||||
The main reason this module exists is to support different backends via Executor and different `target` classes. For example, to add a local relay that automatically gets used:
|
||||
|
||||
```typescript
|
||||
import {setContext} from '@welshman/lib'
|
||||
import {LOCAL_RELAY_URL, Relay, Repository} from '@welshman/util'
|
||||
import {getDefaultNetContext, Multi, Local, Relays, Executor} from '@welshman/net'
|
||||
|
||||
const repository = new Repository()
|
||||
|
||||
const relay = new Relay(repository)
|
||||
|
||||
setContext(getDefaultNetContext({
|
||||
getExecutor: (relays: string[]) => {
|
||||
return new Executor(
|
||||
new Multi([
|
||||
new Local(relay),
|
||||
new Relays(remoteUrls.map(url => ctx.net.pool.get(url))),
|
||||
])
|
||||
)
|
||||
},
|
||||
}))
|
||||
```
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
@@ -1,3 +1,93 @@
|
||||
# @welshman/store [](https://npmjs.com/package/@welshman/store)
|
||||
# @welshman/signer [](https://npmjs.com/package/@welshman/signer)
|
||||
|
||||
Utilities for dealing with svelte stores when using welshman.
|
||||
Implementations of signer utilities and classes.
|
||||
|
||||
## Nips supported
|
||||
|
||||
- NIP 01 (private key login)
|
||||
- NIP 07
|
||||
- NIP 46
|
||||
- NIP 55
|
||||
- NIP 59 (gift wrapping, works with any signer that supports encryption)
|
||||
|
||||
## Examples
|
||||
|
||||
### NIP 01
|
||||
|
||||
```typescript
|
||||
import {makeSecret, Nip01Signer} from '@welshman/signer'
|
||||
|
||||
const signer = Nip01Signer.fromSecret(makeSecret())
|
||||
```
|
||||
|
||||
### NIP 07
|
||||
|
||||
```typescript
|
||||
import {getNip07, Nip07Signer} from '@welshman/signer'
|
||||
|
||||
if (getNip07()) {
|
||||
const signer = new Nip07Signer()
|
||||
}
|
||||
```
|
||||
|
||||
### NIP 55
|
||||
|
||||
```typescript
|
||||
import {getNip07, Nip07Signer} from '@welshman/signer'
|
||||
|
||||
if (getNip07()) {
|
||||
const signer = new Nip07Signer()
|
||||
}
|
||||
```
|
||||
|
||||
### NIP 46
|
||||
|
||||
```typescript
|
||||
import {createEvent, NOTE} from '@welshman/util'
|
||||
import {makeSecret, Nip46Broker, Nip46Signer} from '@welshman/signer'
|
||||
|
||||
const clientSecret = makeSecret()
|
||||
const relays = ['wss://relay.signer.example/']
|
||||
const broker = Nip46Broker.get({relays, clientSecret})
|
||||
const signer = new Nip46Signer(broker)
|
||||
const ncUrl = broker.makeNostrconnectUrl({name: "My app"})
|
||||
const abortController = new AbortController()
|
||||
|
||||
let response
|
||||
try {
|
||||
response = await broker.waitForNostrconnect(url, abortController)
|
||||
} catch (e: any) {
|
||||
if (e?.error) {
|
||||
showWarning(`Received error from signer: ${e.error}`)
|
||||
} else if (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
if (response) {
|
||||
// Now we know the bunker's pubkey and can do stuff with the signer
|
||||
const signerPubkey = response.event.pubkey
|
||||
|
||||
// Next time we want to use our signer, we can instantiate it like so:
|
||||
const newBroker = Nip46Broker.get({relays, clientSecret, signerPubkey})
|
||||
const newSigner = new Nip46Signer(newBroker)
|
||||
}
|
||||
```
|
||||
|
||||
### Using signers
|
||||
|
||||
```typescript
|
||||
import {createEvent, NOTE, DIRECT_MESSAGE} from '@welshman/util'
|
||||
|
||||
const signer = // Create your signer...
|
||||
const nip59 = Nip59.fromSigner(signer)
|
||||
|
||||
// Sign an event
|
||||
const event = await signer.sign(createEvent(NOTE, {content: "hi"}))
|
||||
|
||||
// Wrap a NIP 17 DM
|
||||
const rumor = await nip59.wrap(recipientPubkey, createEvent(DIRECT_MESSAGE, {content: "hi"}))
|
||||
|
||||
// Note that it returns a rumor; be sure to publish the `wrap`
|
||||
const wrap = rumor.wrap
|
||||
```
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
@@ -1,3 +1,17 @@
|
||||
# @welshman/store [](https://npmjs.com/package/@welshman/store)
|
||||
|
||||
Utilities for dealing with svelte stores when using welshman.
|
||||
|
||||
```typescript
|
||||
import {Repository, NAMED_PEOPLE, NAMED_TOPICS, type TrustedEvent, readUserList, List} from '@welshman/util'
|
||||
import {deriveEventsMapped} from '@welshman/store'
|
||||
|
||||
const repository = new Repository()
|
||||
|
||||
// Create a svelte store that performantly maps matching events in the repository to List objects
|
||||
const lists = deriveEventsMapped<PublishedUserList>(repository, {
|
||||
filters: [{kinds: [NAMED_PEOPLE, NAMED_TOPICS]}],
|
||||
eventToItem: (event: TrustedEvent) => (event.tags.length > 1 ? readUserList(event) : null),
|
||||
itemToEvent: (list: List) => list.event,
|
||||
})
|
||||
```
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
+12
-11
@@ -1,14 +1,15 @@
|
||||
# @welshman/util [](https://npmjs.com/package/@welshman/util)
|
||||
|
||||
Some nostr-specific utilities. For the most part, these will not have side effects or manage state.
|
||||
Some nostr-specific utilities. For the most part, these will not have side effects or manage state. Includes:
|
||||
|
||||
- `Address` utilities for dealing with nostr addresses.
|
||||
- `Events` utilities for dealing with nostr events.
|
||||
- `Filters` utilities for dealing with nostr filters.
|
||||
- `Kinds` kind constants and related utility functions.
|
||||
- `Links` utilities for encoding and decoding nostr links.
|
||||
- `Relay` an implementation of an in-memory nostr relay.
|
||||
- `Relays` utilities related to relay urls.
|
||||
- `Router` is a utility for selecting relay urls based on user preferences and protocol hints.
|
||||
- `Tags` convenient way to access and modify tags.
|
||||
- `Zaps` utilities related to zaps.
|
||||
- Event kind constants
|
||||
- A nostr address class
|
||||
- Utilities for working with nostr filters and tags
|
||||
- Helpers for working with zap events and lightning invoices
|
||||
- A `Encryptable` for ensuring payloads get encrypted
|
||||
- An implementation of an in-memory relay, backed by an events repository
|
||||
- Utilities for building events, validating signatures, and checking event type (replaceable, etc.)
|
||||
- Types and utilities for NIP 89 handlers
|
||||
- Types and utilities for NIP 51 lists
|
||||
- Types and utilities for NIP 01 profile metadata
|
||||
- Types and utilities for NIP 11 relay profiles
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"entryPoints": ["src/index.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user