rename client, update docs/skills
tests / tests (push) Failing after 5m4s

This commit is contained in:
2026-06-18 19:31:14 +00:00
parent dfeb7a747b
commit fe5c11b00f
92 changed files with 1811 additions and 5268 deletions
+117
View File
@@ -0,0 +1,117 @@
# Publishing Events
Publishing in `@welshman/app` is **optimistic** and built around *thunks*. A thunk writes the event to the local repository immediately (so the UI updates instantly), signs lazily, optionally gift-wraps (NIP-59) and computes proof-of-work (NIP-13), and reports acceptance/rejection per relay. The signing/publishing can be delayed, giving you a soft-undo window.
Publishing is managed by the `Thunks` plugin: `app.use(Thunks)`.
## Publishing to specific relays
```typescript
import {makeEvent, NOTE} from "@welshman/util"
const thunk = app.use(Thunks).publish({
event: makeEvent(NOTE, {content: "hi"}),
relays: ["wss://relay.example"],
})
```
## Publishing to the outbox
`publishToOutbox` resolves the current user's write relays (via the [Router](./routing)) for you — the usual way to publish your own notes.
```typescript
const thunk = app.use(Thunks).publishToOutbox({
event: makeEvent(NOTE, {content: "hi"}),
delay: 3000, // wait 3s before signing/sending — abortable until then
})
```
## `ThunkOptions`
```typescript
type ThunkOptions = Override<PublishOptions, {
app: IApp // injected for you by Thunks.publish
event: EventTemplate
recipient?: string // present → NIP-59 gift-wrap to this pubkey
delay?: number // ms to wait before signing/sending (soft-undo)
pow?: number // NIP-13 proof-of-work difficulty
}>
```
`publish`/`publishToOutbox` accept these options minus `app` (and minus `relays` for `publishToOutbox`).
## Working with a thunk
A thunk is a Svelte store; subscribe to watch per-relay progress.
```typescript
const thunk = app.use(Thunks).publish({event, relays})
thunk.subscribe(t => console.log(t.results)) // PublishResultsByRelay
// Soft-undo: only effective before `delay` elapses
thunk.abort()
// Inspect status
thunk.getCompleteUrls()
thunk.getIncompleteUrls()
thunk.getFailedUrls()
thunk.isComplete()
thunk.getError() // string | undefined
// Await outcomes
await thunk.waitForCompletion() // resolves when no relay is still pending
await thunk.waitForError() // resolves with the first error string
```
## Optimistic-publish history
The `Thunks` manager keeps a log of all thunks and supports retrying:
```typescript
const thunks = app.use(Thunks)
thunks.history // writable<Thunk[]> — the optimistic publish log
thunks.retry(thunk) // re-publish a (possibly merged) thunk
```
Each thunk is queued (batched) and its event is written to the repository and tracker the moment it is enqueued, so derived stores reflect it before any relay has responded. If a thunk is aborted before sending, its event and wrap are removed from the repository and its history entry is dropped.
## Gift-wrapped messages
There are two ways to publish encrypted, NIP-59 gift-wrapped events.
### A single thunk with a `recipient`
Set `recipient` on a normal thunk. The thunk wraps the rumor with an ephemeral key, registers it with the app's `WrapManager`, and publishes the wrap:
```typescript
app.use(Thunks).publish({
event: rumorTemplate,
relays: theirMessagingRelays,
recipient: theirPubkey,
})
```
### Many recipients via `Wraps`
The `Wraps` plugin publishes one wrap per recipient, resolving each recipient's NIP-17 messaging relays automatically:
```typescript
const merged = await app.use(Wraps).publish({
event: rumorTemplate,
recipients: [pubkeyA, pubkeyB],
})
await merged.waitForCompletion()
```
`Wraps.publish` returns a `MergedThunk` aggregating the per-recipient thunks. Incoming wraps addressed to the current user are unwrapped automatically by the [`appPolicyWraps`](./apppolicies) default policy; wraps that fail to unwrap (or are duplicates) are skipped.
## Proof of work
Set `pow` to a target difficulty (number of leading zero bits). The thunk mines the PoW before signing; for wrapped events the wrap itself is mined.
```typescript
app.use(Thunks).publish({event, relays, pow: 20})
```