Re-work publish/thunk status

This commit is contained in:
Jon Staab
2025-10-01 16:59:16 -07:00
parent a2d519766d
commit d01f844078
21 changed files with 225 additions and 190 deletions
+5 -5
View File
@@ -32,10 +32,10 @@ const publish = async (content: string) => {
delay: 3000, // 3s window for abort delay: 3000, // 3s window for abort
}) })
// Track publish status // Track publish results
thunk.status.subscribe(statuses => { thunk.subscribe($thunk => {
for (const [url, {status, message}] of Object.entries(statuses)) { for (const [url, result] of Object.entries($thunk.results)) {
console.log(`${url}: ${status} ${message}`) console.log(`${url}: ${result.status} - ${result.detail}`)
} }
}) })
@@ -47,7 +47,7 @@ const publish = async (content: string) => {
}, 1000) }, 1000)
// Wait for completion // Wait for completion
await thunk.result await thunk.complete
} }
``` ```
+24 -7
View File
@@ -14,11 +14,24 @@ Status values for publish operations:
- `Timeout` - Request timed out - `Timeout` - Request timed out
- `Aborted` - Request was aborted - `Aborted` - Request was aborted
## Types
### PublishResult
Result object for publish operations:
- `relay` - The relay URL
- `status` - PublishStatus enum value
- `detail` - Human-readable status message
### PublishResultsByRelay
Type alias for `Record<string, PublishResult>` - maps relay URLs to their publish results.
## Functions ## Functions
### publishOne(options) ### publishOne(options)
Publishes an event to a single relay and returns a promise that resolves with the publish status. Publishes an event to a single relay and returns a promise that resolves with a `PublishResult`.
**Options:** **Options:**
- `event` - The signed event to publish - `event` - The signed event to publish
@@ -26,11 +39,11 @@ Publishes an event to a single relay and returns a promise that resolves with th
- `signal?` - AbortSignal for cancellation - `signal?` - AbortSignal for cancellation
- `timeout?` - Timeout in milliseconds (default: 10000) - `timeout?` - Timeout in milliseconds (default: 10000)
- `context?` - Adapter context - `context?` - Adapter context
- Callback functions: `onSuccess`, `onFailure`, `onPending`, `onTimeout`, `onAborted`, `onComplete` - Callback functions (all receive `PublishResult`): `onSuccess`, `onFailure`, `onPending`, `onTimeout`, `onAborted`, `onComplete`
### publish(options) ### publish(options)
Publishes an event to multiple relays in parallel and returns a status object mapping relay URLs to their publish status. Publishes an event to multiple relays in parallel and returns a `PublishResultsByRelay` object mapping relay URLs to their publish results.
## Example ## Example
@@ -41,13 +54,17 @@ const event = {
// ... signed event // ... signed event
} }
const statusByRelay = await publish({ const resultsByRelay = await publish({
event, event,
relays: ["wss://relay1.com", "wss://relay2.com"], relays: ["wss://relay1.com", "wss://relay2.com"],
timeout: 5000, timeout: 5000,
onSuccess: (detail, relay) => console.log(`Published to ${relay}`), onSuccess: (result) => console.log(`Published to ${result.relay}: ${result.detail}`),
onFailure: (detail, relay) => console.log(`Failed on ${relay}: ${detail}`) onFailure: (result) => console.log(`Failed on ${result.relay}: ${result.detail}`)
}) })
console.log(statusByRelay) // { "wss://relay1.com": "success", "wss://relay2.com": "failure" } console.log(resultsByRelay)
// {
// "wss://relay1.com": {relay: "wss://relay1.com", status: PublishStatus.Success, detail: "ok"},
// "wss://relay2.com": {relay: "wss://relay2.com", status: PublishStatus.Failure, detail: "invalid: ..."}
// }
``` ```
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@welshman", "name": "@welshman",
"private": true, "private": true,
"version": "0.5.0", "version": "0.5.1",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
], ],
+3 -3
View File
@@ -104,14 +104,14 @@ describe("thunk", () => {
// Wait for initial async operations // Wait for initial async operations
await vi.runAllTimersAsync() await vi.runAllTimersAsync()
expect(thunk.status[LOCAL_RELAY_URL]).toEqual(PublishStatus.Success) expect(thunk.results[LOCAL_RELAY_URL].status).toEqual(PublishStatus.Success)
// Verify tracker was called on success // Verify tracker was called on success
expect(track).toHaveBeenCalledWith(thunk.event.id, LOCAL_RELAY_URL) expect(track).toHaveBeenCalledWith(thunk.event.id, LOCAL_RELAY_URL)
await vi.runAllTimersAsync() await vi.runAllTimersAsync()
await thunk.complete
const finalStatus = await thunk.result expect(thunk.results[LOCAL_RELAY_URL].status).toEqual(PublishStatus.Success)
expect(finalStatus).toEqual({[LOCAL_RELAY_URL]: PublishStatus.Success})
}) })
}) })
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/app", "name": "@welshman/app",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A collection of svelte stores for use in building nostr client applications.", "description": "A collection of svelte stores for use in building nostr client applications.",
+22 -9
View File
@@ -85,17 +85,30 @@ export const relaysByPubkey = derived(relays, $relays =>
) )
export const fetchRelayProfiles = async (urls: string[]) => { export const fetchRelayProfiles = async (urls: string[]) => {
const base = appContext.dufflepudUrl
if (!base) {
throw new Error("ctx.app.dufflepudUrl is required to fetch relay metadata")
}
const res: any = await postJson(`${base}/relay/info`, {urls})
const profilesByUrl = new Map<string, RelayProfile>() const profilesByUrl = new Map<string, RelayProfile>()
for (const {url, info} of res?.data || []) { if (appContext.dufflepudUrl) {
profilesByUrl.set(url, info) const res: any = await postJson(`${appContext.dufflepudUrl}/relay/info`, {urls})
for (const {url, info} of res?.data || []) {
profilesByUrl.set(url, info)
}
} else {
await Promise.all(
urls.map(async url => {
try {
const res = await fetch(url.replace(/^ws/, "http"), {
headers: {
Accept: "application/nostr+json",
},
})
profilesByUrl.set(url, await res.json())
} catch (e) {
// pass
}
}),
)
} }
return profilesByUrl return profilesByUrl
+67 -64
View File
@@ -26,7 +26,13 @@ import {
isUnwrappedEvent, isUnwrappedEvent,
isSignedEvent, isSignedEvent,
} from "@welshman/util" } from "@welshman/util"
import {publish, PublishStatus, PublishOptions, PublishStatusByRelay} from "@welshman/net" import {
publish,
PublishStatus,
PublishResult,
PublishOptions,
PublishResultsByRelay,
} from "@welshman/net"
import {repository, tracker} from "./core.js" import {repository, tracker} from "./core.js"
import {pubkey, getSession, getSigner} from "./session.js" import {pubkey, getSession, getSigner} from "./session.js"
@@ -57,21 +63,28 @@ export class Thunk {
_subs: Subscriber<Thunk>[] = [] _subs: Subscriber<Thunk>[] = []
event: TrustedEvent event: TrustedEvent
result = defer<PublishStatusByRelay>() results: PublishResultsByRelay = {}
status: PublishStatusByRelay = {} complete = defer<void>()
details: Record<string, string> = {}
controller = new AbortController() controller = new AbortController()
constructor(readonly options: ThunkOptions) { constructor(readonly options: ThunkOptions) {
this.event = prepEvent(options.event) this.event = prepEvent(options.event)
for (const relay of options.relays) { for (const relay of options.relays) {
this.status[relay] = PublishStatus.Sending this.results[relay] = {
relay,
status: PublishStatus.Sending,
detail: "sending...",
}
} }
this.controller.signal.addEventListener("abort", () => { this.controller.signal.addEventListener("abort", () => {
for (const relay of options.relays) { for (const relay of options.relays) {
this._setAborted(relay) this._setAborted({
relay,
status: PublishStatus.Aborted,
detail: "aborted",
})
} }
}) })
} }
@@ -82,32 +95,33 @@ export class Thunk {
} }
} }
_fail(message: string) { _fail(detail: string) {
for (const relay of this.options.relays) { for (const relay of this.options.relays) {
this.status[relay] = PublishStatus.Failure this.results[relay] = {
this.details[relay] = message relay,
status: PublishStatus.Failure,
detail: detail,
}
} }
this._notify() this._notify()
} }
_setPending(relay: string) { _setPending = (result: PublishResult) => {
this.options.onPending?.(relay) this.options.onPending?.(result)
this.status[relay] = PublishStatus.Pending this.results[result.relay] = result
this._notify() this._notify()
} }
_setTimeout(relay: string) { _setTimeout = (result: PublishResult) => {
this.options.onTimeout?.(relay) this.options.onTimeout?.(result)
this.status[relay] = PublishStatus.Timeout this.results[result.relay] = result
this.details[relay] = "Publish timed out"
this._notify() this._notify()
} }
_setAborted(relay: string) { _setAborted = (result: PublishResult) => {
this.options.onAborted?.(relay) this.options.onAborted?.(result)
this.status[relay] = PublishStatus.Aborted this.results[result.relay] = result
this.details[relay] = "Publish was aborted"
this._notify() this._notify()
} }
@@ -159,38 +173,30 @@ export class Thunk {
} }
// Send it off // Send it off
this.result.resolve( await publish({
await publish({ ...this.options,
...this.options, event: signedEvent,
event: signedEvent, onSuccess: (result: PublishResult) => {
onSuccess: (message: string, relay: string) => { tracker.track(signedEvent.id, result.relay)
tracker.track(signedEvent.id, relay) this.options.onSuccess?.(result)
this.options.onSuccess?.(message, relay) this.results[result.relay] = result
this.status[relay] = PublishStatus.Success this._notify()
this.details[relay] = message },
this._notify() onFailure: (result: PublishResult) => {
}, this.options.onFailure?.(result)
onFailure: (message: string, relay: string) => { this.results[result.relay] = result
this.options.onFailure?.(message, relay) this._notify()
this.status[relay] = PublishStatus.Failure },
this.details[relay] = message onPending: this._setPending,
this._notify() onTimeout: this._setTimeout,
}, onAborted: this._setAborted,
onPending: (relay: string) => { onComplete: (result: PublishResult) => {
this._setPending(relay) this.options.onComplete?.(result)
}, this._subs = []
onTimeout: (relay: string) => { },
this._setTimeout(relay) })
},
onAborted: (relay: string) => { this.complete.resolve()
this._setAborted(relay)
},
onComplete: () => {
this.options.onComplete?.()
this._subs = []
},
}),
)
} }
subscribe(subscriber: Subscriber<Thunk>) { subscribe(subscriber: Subscriber<Thunk>) {
@@ -207,8 +213,7 @@ export class Thunk {
export class MergedThunk { export class MergedThunk {
_subs: Subscriber<MergedThunk>[] = [] _subs: Subscriber<MergedThunk>[] = []
status: PublishStatusByRelay = {} results: PublishResultsByRelay = {}
details: Record<string, string> = {}
constructor(readonly thunks: Thunk[]) { constructor(readonly thunks: Thunk[]) {
const {Aborted, Failure, Timeout, Pending, Sending, Success} = PublishStatus const {Aborted, Failure, Timeout, Pending, Sending, Success} = PublishStatus
@@ -216,16 +221,14 @@ export class MergedThunk {
for (const thunk of thunks) { for (const thunk of thunks) {
thunk.subscribe($thunk => { thunk.subscribe($thunk => {
this.status = {} this.results = {}
this.details = {}
for (const relay of relays) { for (const relay of relays) {
for (const status of [Aborted, Failure, Timeout, Pending, Sending, Success]) { for (const status of [Aborted, Failure, Timeout, Pending, Sending, Success]) {
const thunk = thunks.find(t => t.status[relay] === status) const thunk = thunks.find(t => t.results[relay]?.status === status)
if (thunk) { if (thunk) {
this.status[relay] = thunk.status[relay]! this.results[relay] = thunk.results[relay]!
this.details[relay] = thunk.details[relay]!
} }
} }
} }
@@ -271,9 +274,9 @@ export const getThunkUrlsWithStatus = (
) => { ) => {
statuses = ensurePlural(statuses) statuses = ensurePlural(statuses)
return Object.entries(thunk.status) return Object.entries(thunk.results)
.filter(([_, status]) => statuses.includes(status)) .filter(([_, {status}]) => statuses.includes(status))
.map(nth(0)) .map(nth(0)) as string[]
} }
export const getCompleteThunkUrls = (thunk: AbstractThunk) => export const getCompleteThunkUrls = (thunk: AbstractThunk) =>
@@ -299,9 +302,9 @@ export const thunkIsComplete = (thunk: AbstractThunk) =>
// Thunk errors // Thunk errors
export const getThunkError = (thunk: Thunk) => { export const getThunkError = (thunk: Thunk) => {
for (const [relay, status] of Object.entries(thunk.status)) { for (const [_, {status, detail}] of Object.entries(thunk.results)) {
if (status === PublishStatus.Failure) { if (status === PublishStatus.Failure) {
return thunk.details[relay] return detail
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/content", "name": "@welshman/content",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A collection of utilities for parsing nostr note content.", "description": "A collection of utilities for parsing nostr note content.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/editor", "name": "@welshman/editor",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A batteries-included nostr editor.", "description": "A batteries-included nostr editor.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/feeds", "name": "@welshman/feeds",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "Utilities for building dynamic nostr feeds.", "description": "Utilities for building dynamic nostr feeds.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/lib", "name": "@welshman/lib",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A collection of utilities.", "description": "A collection of utilities.",
+26 -6
View File
@@ -1,5 +1,5 @@
import {describe, expect, it, vi, beforeEach, afterEach} from "vitest" import {describe, expect, it, vi, beforeEach, afterEach} from "vitest"
import {publishOne, publish} from "../src/publish" import {publishOne, publish, PublishStatus} from "../src/publish"
import {MockAdapter} from "../src/adapter" import {MockAdapter} from "../src/adapter"
import {ClientMessageType} from "../src/message" import {ClientMessageType} from "../src/message"
import {makeEvent} from "@welshman/util" import {makeEvent} from "@welshman/util"
@@ -40,7 +40,11 @@ describe("publishOne", () => {
await vi.runAllTimers() await vi.runAllTimers()
expect(successSpy).toHaveBeenCalledWith("hi") expect(successSpy).toHaveBeenCalledWith({
relay: "1",
detail: "hi",
status: PublishStatus.Success,
})
expect(failureSpy).not.toHaveBeenCalled() expect(failureSpy).not.toHaveBeenCalled()
expect(completeSpy).toHaveBeenCalled() expect(completeSpy).toHaveBeenCalled()
}) })
@@ -72,7 +76,11 @@ describe("publishOne", () => {
await vi.runAllTimers() await vi.runAllTimers()
expect(successSpy).not.toHaveBeenCalled() expect(successSpy).not.toHaveBeenCalled()
expect(failureSpy).toHaveBeenCalledWith("hi") expect(failureSpy).toHaveBeenCalledWith({
relay: "1",
detail: "hi",
status: PublishStatus.Failure,
})
expect(completeSpy).toHaveBeenCalled() expect(completeSpy).toHaveBeenCalled()
}) })
@@ -196,9 +204,21 @@ describe("publish", () => {
await vi.runAllTimersAsync() await vi.runAllTimersAsync()
expect(successSpy).toHaveBeenCalledWith("hi", "1") expect(successSpy).toHaveBeenCalledWith({
expect(failureSpy).toHaveBeenCalledWith("hi", "2") relay: "1",
status: PublishStatus.Success,
detail: "hi",
})
expect(failureSpy).toHaveBeenCalledWith({
relay: "2",
status: PublishStatus.Failure,
detail: "hi",
})
expect(completeSpy).toHaveBeenCalledTimes(1) expect(completeSpy).toHaveBeenCalledTimes(1)
expect(timeoutSpy).toHaveBeenCalledWith("3") expect(timeoutSpy).toHaveBeenCalledWith({
relay: "3",
status: PublishStatus.Timeout,
detail: "timed out",
})
}) })
}) })
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/net", "name": "@welshman/net",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "Utilities for connecting with nostr relays.", "description": "Utilities for connecting with nostr relays.",
+66 -66
View File
@@ -1,3 +1,4 @@
import {fromPairs} from "@welshman/lib"
import {SignedEvent} from "@welshman/util" import {SignedEvent} from "@welshman/util"
import {RelayMessage, ClientMessageType, isRelayOk} from "./message.js" import {RelayMessage, ClientMessageType, isRelayOk} from "./message.js"
import {AdapterEvent, AdapterContext, getAdapter} from "./adapter.js" import {AdapterEvent, AdapterContext, getAdapter} from "./adapter.js"
@@ -14,6 +15,7 @@ export enum PublishStatus {
export type PublishResult = { export type PublishResult = {
status: PublishStatus status: PublishStatus
detail: string detail: string
relay: string
} }
export type PublishOneOptions = { export type PublishOneOptions = {
@@ -22,26 +24,30 @@ export type PublishOneOptions = {
signal?: AbortSignal signal?: AbortSignal
timeout?: number timeout?: number
context?: AdapterContext context?: AdapterContext
onSuccess?: (detail: string) => void onSuccess?: (result: PublishResult) => void
onFailure?: (detail: string) => void onFailure?: (result: PublishResult) => void
onPending?: () => void onPending?: (result: PublishResult) => void
onTimeout?: () => void onTimeout?: (result: PublishResult) => void
onAborted?: () => void onAborted?: (result: PublishResult) => void
onComplete?: () => void onComplete?: (result: PublishResult) => void
} }
export const publishOne = (options: PublishOneOptions) => export const publishOne = (options: PublishOneOptions) =>
new Promise(resolve => { new Promise<PublishResult>(resolve => {
const adapter = getAdapter(options.relay, options.context) const adapter = getAdapter(options.relay, options.context)
let status = PublishStatus.Pending const result = {
relay: options.relay,
status: PublishStatus.Pending,
detail: "",
}
options.onPending?.() options.onPending?.(result)
const cleanup = () => { const cleanup = () => {
options.onComplete?.() options.onComplete?.(result)
adapter.cleanup() adapter.cleanup()
resolve(status) resolve(result)
} }
adapter.on(AdapterEvent.Receive, (message: RelayMessage, url: string) => { adapter.on(AdapterEvent.Receive, (message: RelayMessage, url: string) => {
@@ -51,11 +57,15 @@ export const publishOne = (options: PublishOneOptions) =>
if (id !== options.event.id) return if (id !== options.event.id) return
if (ok) { if (ok) {
status = PublishStatus.Success result.status = PublishStatus.Success
options.onSuccess?.(detail) result.detail = detail
options.onSuccess?.(result)
} else { } else {
status = PublishStatus.Failure result.status = PublishStatus.Failure
options.onFailure?.(detail) result.detail = detail
options.onFailure?.(result)
} }
cleanup() cleanup()
@@ -63,18 +73,22 @@ export const publishOne = (options: PublishOneOptions) =>
}) })
options.signal?.addEventListener("abort", () => { options.signal?.addEventListener("abort", () => {
if (status === PublishStatus.Pending) { if (result.status === PublishStatus.Pending) {
status = PublishStatus.Aborted result.status = PublishStatus.Aborted
options.onAborted?.() result.detail = "aborted"
options.onAborted?.(result)
} }
cleanup() cleanup()
}) })
setTimeout(() => { setTimeout(() => {
if (status === PublishStatus.Pending) { if (result.status === PublishStatus.Pending) {
status = PublishStatus.Timeout result.status = PublishStatus.Timeout
options.onTimeout?.() result.detail = "timed out"
options.onTimeout?.(result)
} }
cleanup() cleanup()
@@ -83,7 +97,7 @@ export const publishOne = (options: PublishOneOptions) =>
adapter.send([ClientMessageType.Event, options.event]) adapter.send([ClientMessageType.Event, options.event])
}) })
export type PublishStatusByRelay = Record<string, PublishStatus> export type PublishResultsByRelay = Record<string, PublishResult>
export type PublishOptions = { export type PublishOptions = {
event: SignedEvent event: SignedEvent
@@ -91,17 +105,16 @@ export type PublishOptions = {
signal?: AbortSignal signal?: AbortSignal
timeout?: number timeout?: number
context?: AdapterContext context?: AdapterContext
onSuccess?: (detail: string, relay: string) => void onSuccess?: (result: PublishResult) => void
onFailure?: (detail: string, relay: string) => void onFailure?: (result: PublishResult) => void
onPending?: (relay: string) => void onPending?: (result: PublishResult) => void
onTimeout?: (relay: string) => void onTimeout?: (result: PublishResult) => void
onAborted?: (relay: string) => void onAborted?: (result: PublishResult) => void
onComplete?: () => void onComplete?: (result: PublishResult) => void
} }
export const publish = async (options: PublishOptions) => { export const publish = async (options: PublishOptions): Promise<PublishResultsByRelay> => {
const {event, timeout, signal, context} = options const {event, timeout, signal, context} = options
const status: PublishStatusByRelay = {}
const completed = new Set<string>() const completed = new Set<string>()
const relays = new Set(options.relays) const relays = new Set(options.relays)
@@ -109,44 +122,31 @@ export const publish = async (options: PublishOptions) => {
console.warn("Non-unique relays passed to publish") console.warn("Non-unique relays passed to publish")
} }
await Promise.all( return fromPairs(
options.relays.map(relay => await Promise.all(
publishOne({ options.relays.map(async relay => {
event, const result = await publishOne({
relay, event,
signal, relay,
timeout, signal,
context, timeout,
onSuccess: (detail: string) => { context,
status[relay] = PublishStatus.Success onSuccess: options.onSuccess,
options.onSuccess?.(detail, relay) onFailure: options.onFailure,
}, onPending: options.onPending,
onFailure: (detail: string) => { onTimeout: options.onTimeout,
status[relay] = PublishStatus.Failure onAborted: options.onAborted,
options.onFailure?.(detail, relay) onComplete: (result: PublishResult) => {
}, completed.add(relay)
onPending: () => {
status[relay] = PublishStatus.Pending
options.onPending?.(relay)
},
onTimeout: () => {
status[relay] = PublishStatus.Timeout
options.onTimeout?.(relay)
},
onAborted: () => {
status[relay] = PublishStatus.Aborted
options.onAborted?.(relay)
},
onComplete: () => {
completed.add(relay)
if (completed.size === relays.size) { if (completed.size === relays.size) {
options.onComplete?.() options.onComplete?.(result)
} }
}, },
})
return [relay, result]
}), }),
), ),
) )
return status
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/relay", "name": "@welshman/relay",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "An in-memory nostr relay implementation.", "description": "An in-memory nostr relay implementation.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/router", "name": "@welshman/router",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A collection of utilities for nostr relay selection.", "description": "A collection of utilities for nostr relay selection.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/signer", "name": "@welshman/signer",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A nostr signer implemenation supporting several login methods.", "description": "A nostr signer implemenation supporting several login methods.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/store", "name": "@welshman/store",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A collection of utilities based on svelte/store for use with welshman", "description": "A collection of utilities based on svelte/store for use with welshman",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/util", "name": "@welshman/util",
"version": "0.5.0", "version": "0.5.1",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A collection of nostr-related utilities.", "description": "A collection of nostr-related utilities.",
-17
View File
@@ -20,9 +20,6 @@ importers:
eslint-plugin-prettier: eslint-plugin-prettier:
specifier: ~5.2.5 specifier: ~5.2.5
version: 5.2.6(eslint-config-prettier@10.1.1(eslint@9.23.0))(eslint@9.23.0)(prettier@3.5.3) version: 5.2.6(eslint-config-prettier@10.1.1(eslint@9.23.0))(eslint@9.23.0)(prettier@3.5.3)
fake-indexeddb:
specifier: ^6.0.0
version: 6.0.0
globals: globals:
specifier: ~16.0.0 specifier: ~16.0.0
version: 16.0.0 version: 16.0.0
@@ -95,9 +92,6 @@ importers:
fuse.js: fuse.js:
specifier: ^7.0.0 specifier: ^7.0.0
version: 7.1.0 version: 7.1.0
idb:
specifier: ^8.0.0
version: 8.0.2
svelte: svelte:
specifier: ^4.2.18 specifier: ^4.2.18
version: 4.2.19 version: 4.2.19
@@ -1698,10 +1692,6 @@ packages:
resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
fake-indexeddb@6.0.0:
resolution: {integrity: sha512-YEboHE5VfopUclOck7LncgIqskAqnv4q0EWbYCaxKKjAvO93c+TJIaBuGy8CBFdbg9nKdpN3AuPRwVBJ4k7NrQ==}
engines: {node: '>=18'}
fast-deep-equal@3.1.3: fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -1805,9 +1795,6 @@ packages:
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
idb@8.0.2:
resolution: {integrity: sha512-CX70rYhx7GDDQzwwQMDwF6kDRQi5vVs6khHUumDrMecBylKkwvZ8HWvKV08AGb7VbpoGCWUQ4aHzNDgoUiOIUg==}
ignore@5.3.2: ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
@@ -3901,8 +3888,6 @@ snapshots:
expect-type@1.2.1: {} expect-type@1.2.1: {}
fake-indexeddb@6.0.0: {}
fast-deep-equal@3.1.3: {} fast-deep-equal@3.1.3: {}
fast-diff@1.3.0: {} fast-diff@1.3.0: {}
@@ -4011,8 +3996,6 @@ snapshots:
husky@9.1.7: {} husky@9.1.7: {}
idb@8.0.2: {}
ignore@5.3.2: {} ignore@5.3.2: {}
import-fresh@3.3.1: import-fresh@3.3.1:
-1
View File
@@ -4,7 +4,6 @@ import {defineConfig} from "vitest/config"
export default defineConfig({ export default defineConfig({
test: { test: {
environment: "happy-dom", environment: "happy-dom",
setupFiles: "./vitest.setup.ts",
include: ["packages/**/*.test.ts"], include: ["packages/**/*.test.ts"],
coverage: { coverage: {
provider: "v8", provider: "v8",