Add some type utils, findFeed, and fix feed listener to use limit: 0 instead of since

This commit is contained in:
Jon Staab
2025-09-09 16:12:16 -07:00
parent 9a476d2c30
commit 599e6a5085
19 changed files with 95 additions and 16 deletions
+1
View File
@@ -1,3 +1,4 @@
--ignore-dir=docs/assets
--ignore-dir=docs/reference --ignore-dir=docs/reference
--ignore-dir=docs/.vitepress/cache --ignore-dir=docs/.vitepress/cache
--ignore-dir=dist --ignore-dir=dist
+12
View File
@@ -30,6 +30,12 @@ export class FeedController {
// Load events with specified limit // Load events with specified limit
load(limit: number): Promise<void> load(limit: number): Promise<void>
// Get listener function (memoized)
getListener(): Promise<() => Promise<void>>
// Listen for new events in the feed
listen(): Promise<void>
} }
``` ```
@@ -90,4 +96,10 @@ await controller.load(50)
// Load more events // Load more events
await controller.load(50) await controller.load(50)
// Listen for new events
const unlisten = controller.listen()
// Unsubscribe from listener
unlisten()
``` ```
+17
View File
@@ -123,6 +123,23 @@ walkFeed(feed, (node) => {
}) })
``` ```
Find a specific feed in a feed tree:
```typescript
const feed = makeIntersectionFeed(
makeAuthorFeed("pubkey1"),
makeUnionFeed(
makeKindFeed(1),
makeTagFeed("#t", "bitcoin")
)
)
// Find a feed matching a specific condition
const bitcoinTagFeed = findFeed(feed, (f) =>
isTagFeed(f) && getFeedArgs(f)[1] === "bitcoin"
)
```
## Feed Simplification ## Feed Simplification
Flatten nested feeds of the same type: Flatten nested feeds of the same type:
+30
View File
@@ -2,6 +2,36 @@
The `Tools` module provides a comprehensive collection of utility functions for common programming tasks. It includes functions for array manipulation, object handling, type checking, math operations, and more. The `Tools` module provides a comprehensive collection of utility functions for common programming tasks. It includes functions for array manipulation, object handling, type checking, math operations, and more.
## Working with types
Utility types for TypeScript development:
```typescript
// Override properties of type T with properties from type R
export type Override<T, R> = Omit<T, keyof R> & R;
// Make specific properties of type T optional
export type MakeOptional<T, K extends keyof T> = Override<T, Partial<Pick<T, K>>>;
```
Examples:
```typescript
interface User {
id: string;
name: string;
email: string;
age: number;
}
// Override the id to be a number instead
type UserWithNumericId = Override<User, { id: number }>;
// Result: { id: number; name: string; email: string; age: number; }
// Make email and age optional
type PartialUser = MakeOptional<User, 'email' | 'age'>;
// Result: { id: string; name: string; email?: string; age?: number; }
```
## Basic functional programming utilities ## Basic functional programming utilities
```typescript ```typescript
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@welshman", "name": "@welshman",
"private": true, "private": true,
"version": "0.4.5", "version": "0.4.6",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
], ],
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/app", "name": "@welshman/app",
"version": "0.4.5", "version": "0.4.6",
"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.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/content", "name": "@welshman/content",
"version": "0.4.5", "version": "0.4.6",
"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.4.5", "version": "0.4.6",
"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.4.5", "version": "0.4.6",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "Utilities for building dynamic nostr feeds.", "description": "Utilities for building dynamic nostr feeds.",
+1 -4
View File
@@ -350,12 +350,9 @@ export class FeedController {
} }
return () => { return () => {
const since = now()
const controller = new AbortController() const controller = new AbortController()
const signal = AbortSignal.any(removeNil([controller.signal, this.options.signal])) const signal = AbortSignal.any(removeNil([controller.signal, this.options.signal]))
const requestFilters = filters! const requestFilters = filters!.map((filter: Filter) => ({...filter, limit: 0}))
.filter((filter: Filter) => !filter.until || filter.until <= since)
.map((filter: Filter) => ({...filter, since}))
requestPage( requestPage(
omitVals([undefined], { omitVals([undefined], {
+14
View File
@@ -214,6 +214,20 @@ export const walkFeed = (feed: Feed, visit: (feed: Feed) => void) => {
} }
} }
export const findFeed = (feed: Feed, match: (feed: Feed) => boolean): Feed | undefined => {
if (match(feed)) return feed
if (hasSubFeeds(feed)) {
for (const subFeed of getFeedArgs(feed)) {
const found = findFeed(subFeed, match)
if (found) {
return found
}
}
}
}
export const simplifyFeed = (feed: Feed): Feed => { export const simplifyFeed = (feed: Feed): Feed => {
if (isUnionFeed(feed)) { if (isUnionFeed(feed)) {
const args = getFeedArgs(feed) const args = getFeedArgs(feed)
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/lib", "name": "@welshman/lib",
"version": "0.4.5", "version": "0.4.6",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A collection of utilities.", "description": "A collection of utilities.",
+8
View File
@@ -14,6 +14,14 @@ export const isNotNil = <T>(x: T, ...args: unknown[]) => x !== undefined && x !=
export const assertNotNil = <T>(x: T, ...args: unknown[]) => x! export const assertNotNil = <T>(x: T, ...args: unknown[]) => x!
// ----------------------------------------------------------------------------
// Working with types
// ----------------------------------------------------------------------------
export type Override<T, R> = Omit<T, keyof R> & R
export type MakeOptional<T, K extends keyof T> = Override<T, Partial<Pick<T, K>>>
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Basic functional programming utilities // Basic functional programming utilities
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/net", "name": "@welshman/net",
"version": "0.4.5", "version": "0.4.6",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "Utilities for connecting with nostr relays.", "description": "Utilities for connecting with nostr relays.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@welshman/relay", "name": "@welshman/relay",
"version": "0.4.5", "version": "0.4.6",
"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.4.5", "version": "0.4.6",
"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.4.5", "version": "0.4.6",
"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.4.5", "version": "0.4.6",
"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.4.5", "version": "0.4.6",
"author": "hodlbod", "author": "hodlbod",
"license": "MIT", "license": "MIT",
"description": "A collection of nostr-related utilities.", "description": "A collection of nostr-related utilities.",