Remove relay package, move everything into net
This commit is contained in:
@@ -87,11 +87,6 @@ export default defineConfig({
|
|||||||
{text: "NIP 59", link: "/signer/nip-59"},
|
{text: "NIP 59", link: "/signer/nip-59"},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
text: "@welshman/relay",
|
|
||||||
link: "/relay/",
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
text: "@welshman/router",
|
text: "@welshman/router",
|
||||||
link: "/router/",
|
link: "/router/",
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ Welshman is modular - install only what you need:
|
|||||||
# Core nostr utilities (events, filters, tags)
|
# Core nostr utilities (events, filters, tags)
|
||||||
npm i @welshman/util
|
npm i @welshman/util
|
||||||
|
|
||||||
# In-memory event store and relay adapter
|
|
||||||
npm i @welshman/relay
|
|
||||||
|
|
||||||
# Networking and relay management
|
# Networking and relay management
|
||||||
npm i @welshman/net
|
npm i @welshman/net
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ features:
|
|||||||
- title: "@welshman/signer"
|
- title: "@welshman/signer"
|
||||||
details: Implementations of various nostr signing methods (NIP-01, NIP-07, NIP-46, NIP-55).
|
details: Implementations of various nostr signing methods (NIP-01, NIP-07, NIP-46, NIP-55).
|
||||||
link: "/signer"
|
link: "/signer"
|
||||||
- title: "@welshman/relay"
|
|
||||||
details: In-memory relay and event store.
|
|
||||||
link: "/relay"
|
|
||||||
- title: "@welshman/router"
|
- title: "@welshman/router"
|
||||||
details: Tools for relay selection.
|
details: Tools for relay selection.
|
||||||
link: "/router"
|
link: "/router"
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
# @welshman/relay
|
|
||||||
|
|
||||||
[](https://npmjs.com/package/@welshman/relay)
|
|
||||||
|
|
||||||
A few utilites for storing nostr events in memory.
|
|
||||||
|
|
||||||
## What's Included
|
|
||||||
|
|
||||||
- **Event Store** - A Repository class which stores events in memory
|
|
||||||
- **Relay Adapter** - A LocalRelay class which adapts nostr messages to the repository
|
|
||||||
- **Event Tracker** - A Tracker class for managing which events have been seen from which relays
|
|
||||||
- **Gift Wrap Manager** - A WrapManager class for tracking and unwrapping NIP-59 gift wrapped events
|
|
||||||
|
|
||||||
## Quick Example
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import {Repository, LocalRelay} from "@welshman/relay"
|
|
||||||
|
|
||||||
// Create an in-memory event repository
|
|
||||||
const repository = Repository.get()
|
|
||||||
|
|
||||||
// Publish events directly to the repository
|
|
||||||
const textNote = {
|
|
||||||
id: "event123",
|
|
||||||
pubkey: "author-pubkey",
|
|
||||||
created_at: Math.floor(Date.now() / 1000),
|
|
||||||
kind: 1,
|
|
||||||
tags: [],
|
|
||||||
content: "Hello, world!",
|
|
||||||
sig: "signature"
|
|
||||||
}
|
|
||||||
|
|
||||||
repository.publish(textNote)
|
|
||||||
|
|
||||||
// Query events using filters
|
|
||||||
const recentNotes = repository.query([{kinds: [1], limit: 10}])
|
|
||||||
console.log(`Found ${recentNotes.length} text notes`)
|
|
||||||
|
|
||||||
// Listen for repository updates
|
|
||||||
repository.on("update", ({added, removed}) => {
|
|
||||||
console.log(`Added ${added.length} events, removed ${removed.size} events`)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Create a local relay that adapts Nostr messages to the repository
|
|
||||||
const relay = new LocalRelay(repository)
|
|
||||||
|
|
||||||
// Listen for relay messages
|
|
||||||
relay.on("EVENT", (subId, event) => {
|
|
||||||
console.log(`Received event ${event.id} for subscription ${subId}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
relay.on("OK", (eventId, success, message) => {
|
|
||||||
console.log(`Event ${eventId} ${success ? "accepted" : "rejected"}: ${message}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Use relay protocol to publish and subscribe
|
|
||||||
relay.send("EVENT", {
|
|
||||||
id: "event456",
|
|
||||||
pubkey: "another-author",
|
|
||||||
created_at: Math.floor(Date.now() / 1000),
|
|
||||||
kind: 1,
|
|
||||||
tags: [["t", "welshman"]],
|
|
||||||
content: "Using LocalRelay!",
|
|
||||||
sig: "signature"
|
|
||||||
})
|
|
||||||
|
|
||||||
// Subscribe to events with hashtag
|
|
||||||
relay.send("REQ", "tagged", {kinds: [1], "#t": ["welshman"]})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tracking Events Across Relays
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import {Tracker} from "@welshman/relay"
|
|
||||||
|
|
||||||
const tracker = new Tracker()
|
|
||||||
|
|
||||||
// Track events from different relays
|
|
||||||
const isDuplicate1 = tracker.track("event123", "wss://relay1.com") // false
|
|
||||||
const isDuplicate2 = tracker.track("event123", "wss://relay2.com") // false
|
|
||||||
const isDuplicate3 = tracker.track("event123", "wss://relay1.com") // true (duplicate)
|
|
||||||
|
|
||||||
// Check which relays have sent an event
|
|
||||||
const relays = tracker.getRelays("event123") // Set(["wss://relay1.com", "wss://relay2.com"])
|
|
||||||
|
|
||||||
// Copy relay tracking from one event to another (useful for wrapped events)
|
|
||||||
tracker.copy("wrap-event-id", "rumor-event-id")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Managing Gift Wrapped Events
|
|
||||||
|
|
||||||
The WrapManager handles NIP-59 gift wrapped events, automatically unwrapping incoming wrapped events and tracking the relationship between wraps and their inner rumors.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import {Repository, LocalRelay, Tracker, WrapManager} from "@welshman/relay"
|
|
||||||
import {ISigner} from "@welshman/signer"
|
|
||||||
|
|
||||||
const repository = Repository.get()
|
|
||||||
const relay = new LocalRelay(repository)
|
|
||||||
const tracker = new Tracker()
|
|
||||||
|
|
||||||
// Create a wrap manager with a function to get signers for different pubkeys
|
|
||||||
const wrapManager = new WrapManager({
|
|
||||||
relay,
|
|
||||||
tracker,
|
|
||||||
getSigner: (pubkey: string) => {
|
|
||||||
// Return the appropriate signer for this pubkey
|
|
||||||
return mySignerMap.get(pubkey)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// When you publish a wrapped event, track it
|
|
||||||
wrapManager.add({
|
|
||||||
recipient: recipientPubkey,
|
|
||||||
wrap: wrappedEvent,
|
|
||||||
rumor: innerEvent
|
|
||||||
})
|
|
||||||
|
|
||||||
// When you receive a wrapped event, unwrap it
|
|
||||||
await wrapManager.unwrap(receivedWrapEvent)
|
|
||||||
|
|
||||||
// The rumor will be automatically published to the repository
|
|
||||||
// and relay tracking will be copied from the wrap to the rumor
|
|
||||||
|
|
||||||
// Remove wraps by various criteria
|
|
||||||
wrapManager.remove(wrapId)
|
|
||||||
wrapManager.removeByRumorId(rumorId)
|
|
||||||
|
|
||||||
// Listen for wrap manager events
|
|
||||||
wrapManager.on("add", (wrapItem) => {
|
|
||||||
console.log("Wrap added:", wrapItem)
|
|
||||||
})
|
|
||||||
|
|
||||||
wrapManager.on("remove", (wrapItem) => {
|
|
||||||
console.log("Wrap removed:", wrapItem)
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install @welshman/relay
|
|
||||||
```
|
|
||||||
@@ -42,7 +42,7 @@ Creates a cached loader function with staleness checking and exponential backoff
|
|||||||
import {writable} from 'svelte/store'
|
import {writable} from 'svelte/store'
|
||||||
import {derived, readable} from "svelte/store"
|
import {derived, readable} from "svelte/store"
|
||||||
import {readProfile, PROFILE, PublishedProfile} from "@welshman/util"
|
import {readProfile, PROFILE, PublishedProfile} from "@welshman/util"
|
||||||
import {Repository} from "@welshman/relay"
|
import {Repository} from "@welshman/net"
|
||||||
import {deriveEventsMapped, collection, withGetter} from "@welshman/store"
|
import {deriveEventsMapped, collection, withGetter} from "@welshman/store"
|
||||||
|
|
||||||
const repository = new Repository()
|
const repository = new Repository()
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Creates a reactive store that tracks whether an event is deleted by address.
|
|||||||
## Example
|
## Example
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import {Repository} from "@welshman/relay"
|
import {Repository} from "@welshman/net"
|
||||||
import {deriveEventsMapped, deriveEvents} from "@welshman/store"
|
import {deriveEventsMapped, deriveEvents} from "@welshman/store"
|
||||||
import {readProfile, PROFILE} from "@welshman/util"
|
import {readProfile, PROFILE} from "@welshman/util"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {PublishStatus} from "@welshman/net"
|
import {PublishStatus, LOCAL_RELAY_URL} from "@welshman/net"
|
||||||
import {NOTE, DIRECT_MESSAGE, WRAP, makeEvent} from "@welshman/util"
|
import {NOTE, DIRECT_MESSAGE, WRAP, makeEvent} from "@welshman/util"
|
||||||
import {LOCAL_RELAY_URL} from "@welshman/relay"
|
|
||||||
import {getPubkey, makeSecret, prep} from "@welshman/signer"
|
import {getPubkey, makeSecret, prep} from "@welshman/signer"
|
||||||
import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"
|
import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"
|
||||||
import {repository, tracker} from "../src/core"
|
import {repository, tracker} from "../src/core"
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@welshman/feeds": "workspace:*",
|
"@welshman/feeds": "workspace:*",
|
||||||
"@welshman/lib": "workspace:*",
|
"@welshman/lib": "workspace:*",
|
||||||
"@welshman/relay": "workspace:*",
|
|
||||||
"@welshman/router": "workspace:*",
|
"@welshman/router": "workspace:*",
|
||||||
"@welshman/net": "workspace:*",
|
"@welshman/net": "workspace:*",
|
||||||
"@welshman/signer": "workspace:*",
|
"@welshman/signer": "workspace:*",
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ export type SendWrappedOptions = Omit<ThunkOptions, "event" | "relays"> & {
|
|||||||
recipients: string[]
|
recipients: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sendWrapped = async ({event, recipients, ...options}: SendWrappedOptions) =>
|
export const sendWrapped = ({event, recipients, ...options}: SendWrappedOptions) =>
|
||||||
new MergedThunk(
|
new MergedThunk(
|
||||||
uniq(recipients).map(recipient => {
|
uniq(recipients).map(recipient => {
|
||||||
const relays = Router.get().PubkeyInbox(recipient).getUrls()
|
const relays = Router.get().PubkeyInbox(recipient).getUrls()
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import {throttle} from "@welshman/lib"
|
import {throttle} from "@welshman/lib"
|
||||||
import {Repository, LocalRelay, Tracker} from "@welshman/relay"
|
import {Repository, Tracker} from "@welshman/net"
|
||||||
import {custom} from "@welshman/store"
|
import {custom} from "@welshman/store"
|
||||||
|
|
||||||
export const tracker = new Tracker()
|
export const tracker = new Tracker()
|
||||||
|
|
||||||
export const repository = Repository.get()
|
export const repository = Repository.get()
|
||||||
|
|
||||||
export const relay = new LocalRelay(repository)
|
|
||||||
|
|
||||||
// Adapt objects to stores
|
// Adapt objects to stores
|
||||||
|
|
||||||
export const makeRepositoryStore = ({throttle: t = 300}: {throttle?: number} = {}) =>
|
export const makeRepositoryStore = ({throttle: t = 300}: {throttle?: number} = {}) =>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import {
|
|||||||
getPubkey,
|
getPubkey,
|
||||||
ISigner,
|
ISigner,
|
||||||
} from "@welshman/signer"
|
} from "@welshman/signer"
|
||||||
import {WrapManager} from "@welshman/relay"
|
import {WrapManager} from "@welshman/net"
|
||||||
import {relay, tracker} from "./core.js"
|
import {tracker, repository} from "./core.js"
|
||||||
|
|
||||||
export enum SessionMethod {
|
export enum SessionMethod {
|
||||||
Nip01 = "nip01",
|
Nip01 = "nip01",
|
||||||
@@ -279,7 +279,7 @@ export const nip44EncryptToSelf = (payload: string) => {
|
|||||||
|
|
||||||
// Gift wrap utilities
|
// Gift wrap utilities
|
||||||
|
|
||||||
export const wrapManager = new WrapManager({relay, tracker})
|
export const wrapManager = new WrapManager({repository, tracker})
|
||||||
|
|
||||||
export const shouldUnwrap = withGetter(writable(false))
|
export const shouldUnwrap = withGetter(writable(false))
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@welshman/feeds": ["../feeds/src/index.js"],
|
"@welshman/feeds": ["../feeds/src/index.js"],
|
||||||
"@welshman/lib": ["../lib/src/index.js"],
|
"@welshman/lib": ["../lib/src/index.js"],
|
||||||
"@welshman/relay": ["../relay/src/index.js"],
|
|
||||||
"@welshman/net": ["../net/src/index.js"],
|
"@welshman/net": ["../net/src/index.js"],
|
||||||
"@welshman/signer": ["../signer/src/index.js"],
|
"@welshman/signer": ["../signer/src/index.js"],
|
||||||
"@welshman/store": ["../store/src/index.js"],
|
"@welshman/store": ["../store/src/index.js"],
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "workspace:*",
|
"@welshman/lib": "workspace:*",
|
||||||
"@welshman/net": "workspace:*",
|
"@welshman/net": "workspace:*",
|
||||||
"@welshman/relay": "workspace:*",
|
|
||||||
"@welshman/router": "workspace:*",
|
"@welshman/router": "workspace:*",
|
||||||
"@welshman/signer": "workspace:*",
|
"@welshman/signer": "workspace:*",
|
||||||
"@welshman/util": "workspace:*",
|
"@welshman/util": "workspace:*",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
now,
|
now,
|
||||||
} from "@welshman/lib"
|
} from "@welshman/lib"
|
||||||
import {EPOCH, trimFilters, guessFilterDelta, TrustedEvent, Filter} from "@welshman/util"
|
import {EPOCH, trimFilters, guessFilterDelta, TrustedEvent, Filter} from "@welshman/util"
|
||||||
import {Tracker} from "@welshman/relay"
|
import {Tracker} from "@welshman/net"
|
||||||
import {Feed, FeedType, RequestItem} from "./core.js"
|
import {Feed, FeedType, RequestItem} from "./core.js"
|
||||||
import {FeedCompiler, FeedCompilerOptions} from "./compiler.js"
|
import {FeedCompiler, FeedCompilerOptions} from "./compiler.js"
|
||||||
import {requestPage} from "./request.js"
|
import {requestPage} from "./request.js"
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ import {
|
|||||||
RELAYS,
|
RELAYS,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {Nip01Signer, ISigner} from "@welshman/signer"
|
import {Nip01Signer, ISigner} from "@welshman/signer"
|
||||||
import {LOCAL_RELAY_URL, Tracker} from "@welshman/relay"
|
|
||||||
import {Router, getFilterSelections, addMinimalFallbacks} from "@welshman/router"
|
import {Router, getFilterSelections, addMinimalFallbacks} from "@welshman/router"
|
||||||
import {AdapterContext, request, publish} from "@welshman/net"
|
import {LOCAL_RELAY_URL, Tracker, AdapterContext, request, publish} from "@welshman/net"
|
||||||
|
|
||||||
export type RequestPageOptions = {
|
export type RequestPageOptions = {
|
||||||
filters: Filter[]
|
filters: Filter[]
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@welshman/lib": ["../lib/src/index.js"],
|
"@welshman/lib": ["../lib/src/index.js"],
|
||||||
|
"@welshman/net": ["../net/src/index.js"],
|
||||||
|
"@welshman/router": ["../router/src/index.js"],
|
||||||
|
"@welshman/signer": ["../signer/src/index.js"],
|
||||||
"@welshman/util": ["../util/src/index.js"]
|
"@welshman/util": ["../util/src/index.js"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import EventEmitter from "events"
|
|
||||||
import {describe, expect, it, vi, beforeEach, afterEach} from "vitest"
|
import {describe, expect, it, vi, beforeEach, afterEach} from "vitest"
|
||||||
import {LocalRelay, Repository, LOCAL_RELAY_URL} from "@welshman/relay"
|
import {makeEvent} from "@welshman/util"
|
||||||
|
import {prep, getPubkey, makeSecret} from "@welshman/signer"
|
||||||
import {AdapterEvent, SocketAdapter, LocalAdapter, getAdapter} from "../src/adapter"
|
import {AdapterEvent, SocketAdapter, LocalAdapter, getAdapter} from "../src/adapter"
|
||||||
|
import {Repository, LOCAL_RELAY_URL} from "../src/repository"
|
||||||
import {ClientMessage, RelayMessage} from "../src/message"
|
import {ClientMessage, RelayMessage} from "../src/message"
|
||||||
import {Socket, SocketEvent} from "../src/socket"
|
import {Socket, SocketEvent} from "../src/socket"
|
||||||
import {Pool} from "../src/pool"
|
import {Pool} from "../src/pool"
|
||||||
@@ -69,17 +70,13 @@ describe("SocketAdapter", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("LocalAdapter", () => {
|
describe("LocalAdapter", () => {
|
||||||
let relay: LocalRelay & EventEmitter
|
let repository: Repository
|
||||||
let adapter: LocalAdapter
|
let adapter: LocalAdapter
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const mockRelay = new EventEmitter()
|
repository = new Repository()
|
||||||
Object.assign(mockRelay, {
|
adapter = new LocalAdapter(repository)
|
||||||
send: vi.fn(),
|
vi.useFakeTimers()
|
||||||
removeAllListeners: vi.fn(),
|
|
||||||
})
|
|
||||||
relay = mockRelay as unknown as LocalRelay & EventEmitter
|
|
||||||
adapter = new LocalAdapter(relay)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -88,32 +85,35 @@ describe("LocalAdapter", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should initialize with correct relay", () => {
|
it("should initialize with correct relay", () => {
|
||||||
expect(adapter.relay).toBe(relay)
|
|
||||||
expect(adapter.urls).toEqual([LOCAL_RELAY_URL])
|
expect(adapter.urls).toEqual([LOCAL_RELAY_URL])
|
||||||
expect(adapter.sockets).toEqual([])
|
expect(adapter.sockets).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should forward received messages", () => {
|
it("should forward received messages", () => {
|
||||||
const receiveSpy = vi.fn()
|
const receiveSpy = vi.fn()
|
||||||
|
const pubkey = getPubkey(makeSecret())
|
||||||
|
const event = prep(makeEvent(1), pubkey)
|
||||||
|
|
||||||
|
adapter.send(["REQ", "r1", {kinds: [1]}])
|
||||||
|
adapter.send(["REQ", "r2", {kinds: [2]}])
|
||||||
adapter.on(AdapterEvent.Receive, receiveSpy)
|
adapter.on(AdapterEvent.Receive, receiveSpy)
|
||||||
|
repository.publish(event)
|
||||||
|
|
||||||
const message: RelayMessage = ["EVENT", "123", {id: "123", kind: 1}]
|
expect(receiveSpy).toHaveBeenCalledTimes(1)
|
||||||
relay.emit("*", ...message)
|
expect(receiveSpy).toHaveBeenCalledWith(["EVENT", "r1", event], LOCAL_RELAY_URL)
|
||||||
|
|
||||||
expect(receiveSpy).toHaveBeenCalledWith(message, LOCAL_RELAY_URL)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should send messages to relay", () => {
|
it("should send messages to relay", async () => {
|
||||||
const message: ClientMessage = ["EVENT", {id: "123", kind: 1}]
|
const publishSpy = vi.spyOn(repository, "publish")
|
||||||
adapter.send(message)
|
const pubkey = getPubkey(makeSecret())
|
||||||
|
const event = prep(makeEvent(1), pubkey)
|
||||||
|
|
||||||
expect(relay.send).toHaveBeenCalledWith("EVENT", message[1])
|
adapter.send(["EVENT", event])
|
||||||
})
|
|
||||||
|
|
||||||
it("should cleanup properly", () => {
|
await vi.runAllTimersAsync()
|
||||||
const removeListenersSpy = vi.spyOn(adapter, "removeAllListeners")
|
|
||||||
adapter.cleanup()
|
expect(publishSpy).toHaveBeenCalledTimes(1)
|
||||||
expect(removeListenersSpy).toHaveBeenCalled()
|
expect(publishSpy).toHaveBeenCalledWith(event)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "workspace:*",
|
"@welshman/lib": "workspace:*",
|
||||||
"@welshman/relay": "workspace:*",
|
|
||||||
"@welshman/util": "workspace:*",
|
"@welshman/util": "workspace:*",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"isomorphic-ws": "^5.0.0"
|
"isomorphic-ws": "^5.0.0"
|
||||||
|
|||||||
+59
-10
@@ -1,8 +1,16 @@
|
|||||||
import EventEmitter from "events"
|
import EventEmitter from "events"
|
||||||
import {call, mergeRight, on} from "@welshman/lib"
|
import {call, sleep, mergeRight, on} from "@welshman/lib"
|
||||||
import {isRelayUrl} from "@welshman/util"
|
import {isRelayUrl, matchFilters, Filter} from "@welshman/util"
|
||||||
import {LocalRelay, LOCAL_RELAY_URL} from "@welshman/relay"
|
import {LOCAL_RELAY_URL, Repository} from "./repository"
|
||||||
import {RelayMessage, ClientMessage} from "./message.js"
|
import {
|
||||||
|
RelayMessage,
|
||||||
|
RelayMessageType,
|
||||||
|
ClientMessage,
|
||||||
|
ClientMessageType,
|
||||||
|
ClientEvent,
|
||||||
|
ClientReq,
|
||||||
|
ClientClose,
|
||||||
|
} from "./message.js"
|
||||||
import {Socket, SocketEvent} from "./socket.js"
|
import {Socket, SocketEvent} from "./socket.js"
|
||||||
import {Unsubscriber} from "./util.js"
|
import {Unsubscriber} from "./util.js"
|
||||||
import {netContext, NetContext} from "./context.js"
|
import {netContext, NetContext} from "./context.js"
|
||||||
@@ -53,12 +61,20 @@ export class SocketAdapter extends AbstractAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class LocalAdapter extends AbstractAdapter {
|
export class LocalAdapter extends AbstractAdapter {
|
||||||
constructor(readonly relay: LocalRelay) {
|
subs = new Map<string, Filter[]>()
|
||||||
|
|
||||||
|
constructor(readonly repository: Repository) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this._unsubscribers.push(
|
this._unsubscribers.push(
|
||||||
on(relay, "*", (...message: RelayMessage) => {
|
on(repository, "update", ({added}) => {
|
||||||
this.emit(AdapterEvent.Receive, message, LOCAL_RELAY_URL)
|
for (const [subId, filters] of this.subs.entries()) {
|
||||||
|
for (const event of added) {
|
||||||
|
if (matchFilters(filters, event)) {
|
||||||
|
this.#receive([RelayMessageType.Event, subId, event])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -72,9 +88,42 @@ export class LocalAdapter extends AbstractAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
send(message: ClientMessage) {
|
send(message: ClientMessage) {
|
||||||
const [type, ...rest] = message
|
switch (message[0]) {
|
||||||
|
case ClientMessageType.Event:
|
||||||
|
return this.#handleEVENT(message as ClientEvent)
|
||||||
|
case ClientMessageType.Close:
|
||||||
|
return this.#handleCLOSE(message as ClientClose)
|
||||||
|
case ClientMessageType.Req:
|
||||||
|
return this.#handleREQ(message as ClientReq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.relay.send(type, ...rest)
|
#receive(message: RelayMessage) {
|
||||||
|
this.emit(AdapterEvent.Receive, message, LOCAL_RELAY_URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
#handleEVENT([_, event]: ClientEvent) {
|
||||||
|
this.repository.publish(event)
|
||||||
|
|
||||||
|
// Callers generally expect async relays
|
||||||
|
sleep(1).then(() => this.#receive([RelayMessageType.Ok, event.id, true, ""]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#handleCLOSE([_, subId]: ClientClose) {
|
||||||
|
this.subs.delete(subId)
|
||||||
|
}
|
||||||
|
|
||||||
|
#handleREQ([_, subId, ...filters]: ClientReq) {
|
||||||
|
this.subs.set(subId, filters)
|
||||||
|
|
||||||
|
// Callers generally expect async relays
|
||||||
|
sleep(1).then(() => {
|
||||||
|
for (const event of this.repository.query(filters)) {
|
||||||
|
this.#receive([RelayMessageType.Event, subId, event])
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#receive([RelayMessageType.Eose, subId])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +162,7 @@ export const getAdapter = (url: string, adapterContext: AdapterContext = {}) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (url === LOCAL_RELAY_URL) {
|
if (url === LOCAL_RELAY_URL) {
|
||||||
return new LocalAdapter(new LocalRelay(context.repository))
|
return new LocalAdapter(context.repository)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRelayUrl(url)) {
|
if (isRelayUrl(url)) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {Repository} from "@welshman/relay"
|
|
||||||
import {verifyEvent, TrustedEvent} from "@welshman/util"
|
import {verifyEvent, TrustedEvent} from "@welshman/util"
|
||||||
import {AbstractAdapter} from "./adapter.js"
|
import {AbstractAdapter} from "./adapter.js"
|
||||||
|
import {Repository} from "./repository.js"
|
||||||
import {Pool} from "./pool.js"
|
import {Pool} from "./pool.js"
|
||||||
|
|
||||||
export type NetContext = {
|
export type NetContext = {
|
||||||
|
|||||||
@@ -8,4 +8,7 @@ export * from "./policy.js"
|
|||||||
export * from "./pool.js"
|
export * from "./pool.js"
|
||||||
export * from "./publish.js"
|
export * from "./publish.js"
|
||||||
export * from "./socket.js"
|
export * from "./socket.js"
|
||||||
|
export * from "./repository.js"
|
||||||
export * from "./request.js"
|
export * from "./request.js"
|
||||||
|
export * from "./tracker.js"
|
||||||
|
export * from "./wrapManager.js"
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ import {
|
|||||||
deduplicateEvents,
|
deduplicateEvents,
|
||||||
getFilterResultCardinality,
|
getFilterResultCardinality,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {Tracker} from "@welshman/relay"
|
|
||||||
import {RelayMessage, ClientMessageType, isRelayEvent, isRelayEose} from "./message.js"
|
import {RelayMessage, ClientMessageType, isRelayEvent, isRelayEose} from "./message.js"
|
||||||
import {getAdapter, AdapterContext, AdapterEvent} from "./adapter.js"
|
import {getAdapter, AdapterContext, AdapterEvent} from "./adapter.js"
|
||||||
import {SocketEvent, SocketStatus} from "./socket.js"
|
import {SocketEvent, SocketStatus} from "./socket.js"
|
||||||
import {netContext} from "./context.js"
|
import {netContext} from "./context.js"
|
||||||
|
import {Tracker} from "./tracker.js"
|
||||||
|
|
||||||
export type BaseRequestOptions = {
|
export type BaseRequestOptions = {
|
||||||
signal?: AbortSignal
|
signal?: AbortSignal
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {Emitter, remove, omit} from "@welshman/lib"
|
import {Emitter, remove, omit} from "@welshman/lib"
|
||||||
import {HashedEvent, SignedEvent} from "@welshman/util"
|
import {HashedEvent, SignedEvent} from "@welshman/util"
|
||||||
import {Tracker} from "./tracker.js"
|
import {Tracker} from "./tracker.js"
|
||||||
import {LocalRelay} from "./relay.js"
|
import {Repository} from "./repository.js"
|
||||||
|
|
||||||
export type WrapItem = Omit<HashedEvent, "content"> & {
|
export type WrapItem = Omit<HashedEvent, "content"> & {
|
||||||
rumorId: string
|
rumorId: string
|
||||||
@@ -11,24 +11,30 @@ export type WrapItem = Omit<HashedEvent, "content"> & {
|
|||||||
export type WrapReference = string[]
|
export type WrapReference = string[]
|
||||||
|
|
||||||
export type WrapManagerOptions = {
|
export type WrapManagerOptions = {
|
||||||
relay: LocalRelay
|
repository: Repository
|
||||||
tracker: Tracker
|
tracker: Tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WrapManager extends Emitter {
|
export class WrapManager extends Emitter {
|
||||||
_wrapIndex = new Map<string, WrapItem>()
|
_wrapIndex = new Map<string, WrapItem>()
|
||||||
_rumorIndex = new Map<string, WrapReference>()
|
_rumorIndex = new Map<string, WrapReference>()
|
||||||
_recipientIndex = new Map<string, WrapReference>()
|
|
||||||
|
|
||||||
constructor(readonly options: WrapManagerOptions) {
|
constructor(readonly options: WrapManagerOptions) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
getRumor = (id: string) => {
|
// Reading/exporting
|
||||||
const wrapItem = this._wrapIndex.get(id)
|
|
||||||
|
dump = () => Array.from(this._wrapIndex.values())
|
||||||
|
|
||||||
|
getWraps = (rumorId: string) =>
|
||||||
|
this._rumorIndex.get(rumorId).map(wrapId => this._wrapIndex.get(wrapId)!)
|
||||||
|
|
||||||
|
getRumor = (wrapId: string) => {
|
||||||
|
const wrapItem = this._wrapIndex.get(wrapId)
|
||||||
|
|
||||||
if (wrapItem) {
|
if (wrapItem) {
|
||||||
return this.options.relay.repository.getEvent(wrapItem.rumorId)
|
return this.options.repository.getEvent(wrapItem.rumorId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +61,8 @@ export class WrapManager extends Emitter {
|
|||||||
|
|
||||||
this._add(wrapItem)
|
this._add(wrapItem)
|
||||||
|
|
||||||
// Send via our relay so that listeners get notified
|
// Save to our repository
|
||||||
this.options.relay.send("EVENT", rumor)
|
this.options.repository.publish(rumor)
|
||||||
|
|
||||||
// Mark the rumor as having come from the wrap's urls
|
// Mark the rumor as having come from the wrap's urls
|
||||||
this.options.tracker.copy(wrap.id, rumor.id)
|
this.options.tracker.copy(wrap.id, rumor.id)
|
||||||
@@ -71,7 +77,7 @@ export class WrapManager extends Emitter {
|
|||||||
|
|
||||||
if (wrapItem) {
|
if (wrapItem) {
|
||||||
this._remove(wrapItem)
|
this._remove(wrapItem)
|
||||||
this.options.relay.repository.removeEvent(wrapItem.rumorId)
|
this.options.repository.removeEvent(wrapItem.rumorId)
|
||||||
this.emit("remove", wrapItem)
|
this.emit("remove", wrapItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,8 +5,7 @@
|
|||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@welshman/lib": ["../lib/src/index.js"],
|
"@welshman/lib": ["../lib/src/index.js"],
|
||||||
"@welshman/util": ["../util/src/index.js"],
|
"@welshman/util": ["../util/src/index.js"]
|
||||||
"@welshman/relay": ["../relay/src/index.js"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
build
|
|
||||||
normalize-url
|
|
||||||
Negentropy.ts
|
|
||||||
__tests__
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
import {describe, it, expect, beforeEach, vi, afterEach} from "vitest"
|
|
||||||
import {now} from "@welshman/lib"
|
|
||||||
import type {TrustedEvent} from "@welshman/util"
|
|
||||||
import {LocalRelay} from "../src/relay"
|
|
||||||
import {Repository} from "../src/repository"
|
|
||||||
|
|
||||||
describe("LocalRelay", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks()
|
|
||||||
vi.useFakeTimers()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
vi.useRealTimers()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Realistic Nostr data
|
|
||||||
const pubkey = "ee".repeat(32)
|
|
||||||
const id = "ff".repeat(32)
|
|
||||||
const sig = "00".repeat(64)
|
|
||||||
const currentTime = now()
|
|
||||||
|
|
||||||
const createEvent = (overrides = {}): TrustedEvent => ({
|
|
||||||
id: id,
|
|
||||||
pubkey: pubkey,
|
|
||||||
created_at: currentTime,
|
|
||||||
kind: 1,
|
|
||||||
tags: [],
|
|
||||||
content: "Hello Nostr!",
|
|
||||||
sig: sig,
|
|
||||||
...overrides,
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("LocalRelay class", () => {
|
|
||||||
let relay: LocalRelay
|
|
||||||
let repository: Repository<TrustedEvent>
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
repository = new Repository<TrustedEvent>()
|
|
||||||
relay = new LocalRelay(repository)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("EVENT handling", () => {
|
|
||||||
it("should publish events to repository", async () => {
|
|
||||||
const event = createEvent()
|
|
||||||
const publishSpy = vi.spyOn(repository, "publish")
|
|
||||||
|
|
||||||
relay.send("EVENT", event)
|
|
||||||
|
|
||||||
expect(publishSpy).toHaveBeenCalledWith(event)
|
|
||||||
|
|
||||||
// Should emit OK
|
|
||||||
const okHandler = vi.fn()
|
|
||||||
relay.on("OK", okHandler)
|
|
||||||
|
|
||||||
// Wait for async operations
|
|
||||||
await vi.runAllTimersAsync()
|
|
||||||
|
|
||||||
expect(okHandler).toHaveBeenCalledWith(event.id, true, "")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should notify matching subscribers", async () => {
|
|
||||||
const event = createEvent()
|
|
||||||
const subId = "test-sub"
|
|
||||||
const filter = {kinds: [1]}
|
|
||||||
|
|
||||||
relay.send("REQ", subId, filter)
|
|
||||||
|
|
||||||
const eventHandler = vi.fn()
|
|
||||||
relay.on("EVENT", eventHandler)
|
|
||||||
|
|
||||||
relay.send("EVENT", event)
|
|
||||||
|
|
||||||
await vi.runAllTimersAsync()
|
|
||||||
|
|
||||||
expect(eventHandler).toHaveBeenCalledWith(subId, event)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should not notify for deleted events", async () => {
|
|
||||||
const event = createEvent()
|
|
||||||
repository.removeEvent(event.id)
|
|
||||||
|
|
||||||
const eventHandler = vi.fn()
|
|
||||||
relay.on("EVENT", eventHandler)
|
|
||||||
|
|
||||||
relay.send("EVENT", event)
|
|
||||||
|
|
||||||
await vi.runAllTimersAsync()
|
|
||||||
|
|
||||||
expect(eventHandler).not.toHaveBeenCalled()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("REQ handling", () => {
|
|
||||||
it("should handle subscription requests", async () => {
|
|
||||||
const event = createEvent()
|
|
||||||
repository.publish(event)
|
|
||||||
|
|
||||||
const subId = "test-sub"
|
|
||||||
const filter = {kinds: [1]}
|
|
||||||
|
|
||||||
const eventHandler = vi.fn()
|
|
||||||
const eoseHandler = vi.fn()
|
|
||||||
|
|
||||||
relay.on("EVENT", eventHandler)
|
|
||||||
relay.on("EOSE", eoseHandler)
|
|
||||||
|
|
||||||
relay.send("REQ", subId, filter)
|
|
||||||
|
|
||||||
await vi.runAllTimersAsync()
|
|
||||||
|
|
||||||
expect(eventHandler).toHaveBeenCalledWith(subId, event)
|
|
||||||
expect(eoseHandler).toHaveBeenCalledWith(subId)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should handle multiple filters", async () => {
|
|
||||||
const event1 = createEvent({kind: 1})
|
|
||||||
const event2 = createEvent({kind: 2, id: "ee".repeat(31)})
|
|
||||||
repository.publish(event1)
|
|
||||||
repository.publish(event2)
|
|
||||||
|
|
||||||
const subId = "test-sub"
|
|
||||||
const filters = [{kinds: [1]}, {kinds: [2]}]
|
|
||||||
|
|
||||||
const eventHandler = vi.fn()
|
|
||||||
relay.on("EVENT", eventHandler)
|
|
||||||
|
|
||||||
relay.send("REQ", subId, ...filters)
|
|
||||||
|
|
||||||
await vi.runAllTimersAsync()
|
|
||||||
|
|
||||||
expect(eventHandler).toHaveBeenCalledTimes(2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("CLOSE handling", () => {
|
|
||||||
it("should close subscriptions", async () => {
|
|
||||||
const subId = "test-sub"
|
|
||||||
relay.send("REQ", subId, {kinds: [1]})
|
|
||||||
relay.send("CLOSE", subId)
|
|
||||||
|
|
||||||
await vi.runAllTimersAsync()
|
|
||||||
|
|
||||||
const event = createEvent()
|
|
||||||
const eventHandler = vi.fn()
|
|
||||||
relay.on("EVENT", eventHandler)
|
|
||||||
|
|
||||||
relay.send("EVENT", event)
|
|
||||||
|
|
||||||
await vi.runAllTimersAsync()
|
|
||||||
|
|
||||||
expect(eventHandler).not.toHaveBeenCalled()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@welshman/relay",
|
|
||||||
"version": "0.5.4",
|
|
||||||
"author": "hodlbod",
|
|
||||||
"license": "MIT",
|
|
||||||
"description": "An in-memory nostr relay implementation.",
|
|
||||||
"publishConfig": {
|
|
||||||
"access": "public"
|
|
||||||
},
|
|
||||||
"type": "module",
|
|
||||||
"main": "dist/relay/src/index.js",
|
|
||||||
"types": "dist/relay/src/index.d.ts",
|
|
||||||
"files": [
|
|
||||||
"dist"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"build": "pnpm run clean && pnpm run compile --force",
|
|
||||||
"clean": "rimraf ./dist",
|
|
||||||
"compile": "tsc -b tsconfig.build.json",
|
|
||||||
"prepublishOnly": "pnpm run build"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@welshman/lib": "workspace:*",
|
|
||||||
"@welshman/util": "workspace:*",
|
|
||||||
"@welshman/signer": "workspace:*"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"rimraf": "~6.0.0",
|
|
||||||
"typescript": "~5.8.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export * from "./relay.js"
|
|
||||||
export * from "./repository.js"
|
|
||||||
export * from "./tracker.js"
|
|
||||||
export * from "./wrapManager.js"
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import {Emitter, sleep} from "@welshman/lib"
|
|
||||||
import {Filter, TrustedEvent, matchFilters} from "@welshman/util"
|
|
||||||
import {Repository} from "./repository.js"
|
|
||||||
|
|
||||||
export class LocalRelay extends Emitter {
|
|
||||||
subs = new Map<string, Filter[]>()
|
|
||||||
|
|
||||||
constructor(readonly repository: Repository) {
|
|
||||||
super()
|
|
||||||
}
|
|
||||||
|
|
||||||
send(type: string, ...message: any[]) {
|
|
||||||
switch (type) {
|
|
||||||
case "EVENT":
|
|
||||||
return this.handleEVENT(message as [TrustedEvent])
|
|
||||||
case "CLOSE":
|
|
||||||
return this.handleCLOSE(message as [string])
|
|
||||||
case "REQ":
|
|
||||||
return this.handleREQ(message as [string, ...Filter[]])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEVENT([event]: [TrustedEvent]) {
|
|
||||||
this.repository.publish(event)
|
|
||||||
|
|
||||||
// Callers generally expect async relays
|
|
||||||
void sleep(1).then(() => {
|
|
||||||
this.emit("OK", event.id, true, "")
|
|
||||||
|
|
||||||
if (!this.repository.isDeleted(event)) {
|
|
||||||
for (const [subId, filters] of this.subs.entries()) {
|
|
||||||
if (matchFilters(filters, event)) {
|
|
||||||
this.emit("EVENT", subId, event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCLOSE([subId]: [string]) {
|
|
||||||
this.subs.delete(subId)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleREQ([subId, ...filters]: [string, ...Filter[]]) {
|
|
||||||
this.subs.set(subId, filters)
|
|
||||||
|
|
||||||
// Callers generally expect async relays
|
|
||||||
void sleep(1).then(() => {
|
|
||||||
for (const event of this.repository.query(filters)) {
|
|
||||||
this.emit("EVENT", subId, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit("EOSE", subId)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.build.json",
|
|
||||||
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "./dist",
|
|
||||||
"paths": {
|
|
||||||
"@welshman/lib": ["../lib/src/index.js"],
|
|
||||||
"@welshman/util": ["../util/src/index.js"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"include": [
|
|
||||||
"src/**/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.json"
|
|
||||||
}
|
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "workspace:*",
|
"@welshman/lib": "workspace:*",
|
||||||
"@welshman/util": "workspace:*",
|
"@welshman/util": "workspace:*",
|
||||||
"@welshman/relay": "workspace:*"
|
"@welshman/net": "workspace:*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"rimraf": "~6.0.0",
|
"rimraf": "~6.0.0",
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import {
|
|||||||
getPubkeyTags,
|
getPubkeyTags,
|
||||||
RelayMode,
|
RelayMode,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {Repository} from "@welshman/relay"
|
import {Repository} from "@welshman/net"
|
||||||
|
|
||||||
export const INDEXED_KINDS = [PROFILE, RELAYS, INBOX_RELAYS, FOLLOWS]
|
export const INDEXED_KINDS = [PROFILE, RELAYS, INBOX_RELAYS, FOLLOWS]
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@welshman/lib": ["../lib/src/index.js"],
|
"@welshman/lib": ["../lib/src/index.js"],
|
||||||
"@welshman/util": ["../util/src/index.js"],
|
"@welshman/util": ["../util/src/index.js"],
|
||||||
"@welshman/relay": ["../relay/src/index.js"],
|
|
||||||
"@welshman/net": ["../net/src/index.js"]
|
"@welshman/net": ["../net/src/index.js"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {TrustedEvent} from "@welshman/util"
|
import {TrustedEvent} from "@welshman/util"
|
||||||
import {Repository} from "@welshman/relay"
|
import {Repository} from "@welshman/net"
|
||||||
import {get} from "svelte/store"
|
import {get} from "svelte/store"
|
||||||
import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"
|
import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "workspace:*",
|
"@welshman/lib": "workspace:*",
|
||||||
"@welshman/util": "workspace:*",
|
"@welshman/util": "workspace:*",
|
||||||
"@welshman/relay": "workspace:*",
|
"@welshman/net": "workspace:*",
|
||||||
"svelte": "^4.2.18"
|
"svelte": "^4.2.18"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {derived} from "svelte/store"
|
import {derived} from "svelte/store"
|
||||||
import {sortBy, identity, ensurePlural, removeNil, batch, partition, first} from "@welshman/lib"
|
import {sortBy, identity, ensurePlural, removeNil, batch, partition, first} from "@welshman/lib"
|
||||||
import {Repository} from "@welshman/relay"
|
|
||||||
import {matchFilters, getIdAndAddress, getIdFilters, Filter, TrustedEvent} from "@welshman/util"
|
import {matchFilters, getIdAndAddress, getIdFilters, Filter, TrustedEvent} from "@welshman/util"
|
||||||
|
import {Repository} from "@welshman/net"
|
||||||
import {custom} from "./custom.js"
|
import {custom} from "./custom.js"
|
||||||
|
|
||||||
export type DeriveEventsMappedOptions<T> = {
|
export type DeriveEventsMappedOptions<T> = {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@welshman/lib": ["../lib/src/index.js"],
|
"@welshman/lib": ["../lib/src/index.js"],
|
||||||
"@welshman/util": ["../util/src/index.js"],
|
"@welshman/util": ["../util/src/index.js"],
|
||||||
"@welshman/relay": ["../relay/src/index.js"]
|
"@welshman/net": ["../net/src/index.js"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Generated
+4
-32
@@ -74,9 +74,6 @@ importers:
|
|||||||
'@welshman/net':
|
'@welshman/net':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../net
|
version: link:../net
|
||||||
'@welshman/relay':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../relay
|
|
||||||
'@welshman/router':
|
'@welshman/router':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../router
|
version: link:../router
|
||||||
@@ -194,9 +191,6 @@ importers:
|
|||||||
'@welshman/net':
|
'@welshman/net':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../net
|
version: link:../net
|
||||||
'@welshman/relay':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../relay
|
|
||||||
'@welshman/router':
|
'@welshman/router':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../router
|
version: link:../router
|
||||||
@@ -241,9 +235,6 @@ importers:
|
|||||||
'@welshman/lib':
|
'@welshman/lib':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../lib
|
version: link:../lib
|
||||||
'@welshman/relay':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../relay
|
|
||||||
'@welshman/util':
|
'@welshman/util':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../util
|
version: link:../util
|
||||||
@@ -261,33 +252,14 @@ importers:
|
|||||||
specifier: ~5.8.0
|
specifier: ~5.8.0
|
||||||
version: 5.8.2
|
version: 5.8.2
|
||||||
|
|
||||||
packages/relay:
|
|
||||||
dependencies:
|
|
||||||
'@welshman/lib':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../lib
|
|
||||||
'@welshman/signer':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../signer
|
|
||||||
'@welshman/util':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../util
|
|
||||||
devDependencies:
|
|
||||||
rimraf:
|
|
||||||
specifier: ~6.0.0
|
|
||||||
version: 6.0.1
|
|
||||||
typescript:
|
|
||||||
specifier: ~5.8.0
|
|
||||||
version: 5.8.2
|
|
||||||
|
|
||||||
packages/router:
|
packages/router:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@welshman/lib':
|
'@welshman/lib':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../lib
|
version: link:../lib
|
||||||
'@welshman/relay':
|
'@welshman/net':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../relay
|
version: link:../net
|
||||||
'@welshman/util':
|
'@welshman/util':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../util
|
version: link:../util
|
||||||
@@ -338,9 +310,9 @@ importers:
|
|||||||
'@welshman/lib':
|
'@welshman/lib':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../lib
|
version: link:../lib
|
||||||
'@welshman/relay':
|
'@welshman/net':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../relay
|
version: link:../net
|
||||||
'@welshman/util':
|
'@welshman/util':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../util
|
version: link:../util
|
||||||
|
|||||||
Reference in New Issue
Block a user