Commit graph naco-api/internal/nostr
Author SHA1 Message Date
4f107da9ee
fix: harden Nostr client relay handling and error propagation
- budget relay queries across a shared 20s deadline (5s per relay) and
  dedupe events by ID across relays
- surface 'could not connect to any relay' when no query succeeded and
  abort early on relay-connect and stream-cancel errors
- guard zero/negative limits across all fetchers
- GetActor falls through relays and rejects empty profile metadata;
  SearchActors propagates relay errors instead of silently returning none
- NewNostrClient validates relay ws://wss:// schemes, trims, and dedupes
2026-09-09 23:17:56 +00:00
1640fae6be
fix: surface relay-connect and stream-cancel errors
- nostr GetPost: track whether any relay was reached so an unreachable
  relay set surfaces 'could not connect to any relay' (consistent with
  GetLatestNPosts/GetPostsInTimeframe) instead of a misleading
  'post not found'.
- ollama SummarizeStyle: surface ctx cancellation after Generate when
  the Ollama stream reader closes cleanly on a canceled context,
  instead of returning a truncated summary.
2026-09-09 14:42:10 +00:00
3b443eff36
refactor: harden HTTP clients with timeouts, per-relay ctx, rate-limit handling 2026-09-08 01:11:13 +00:00
c8d1829172 test(clients): expand coverage for rate-limit, pagination and error paths
- nostr: variants for resolvePubkey/EventID, invalid ID/author checks, relay failure
- bluesky: add FeedGetPosts/getProfile/searchActors mocks, pagination and time-filtering with cursor
- twitter: add RateLimit retry (Reset/Retry-After), exhausted retries, lookup errors, context cancel
- activitypub: fix GetPostsInTimeframe to test 2-page pagination and start/end boundary
2026-09-03 17:00:28 +00:00
4ac15ff6c2 test: cover getActor/searchActors clients and migrations
Runnable (HTTP-mocked) unit tests:
- activitypub: GetActor (accounts/lookup) plus id-lookup fallback, and SearchActors
  (accounts/search).
- twitter: GetActor (/users/by/username) and SearchActors (/users/search).
- nostr: SearchActors best-effort path (non-resolvable query returns empty, no network).
- store: extractUpSQL parsing helper.

Store integration test (TestStoreRoundTrip) is gated behind TEST_DATABASE_URL and skipped
when no Postgres+pgvector is available; it runs Migrate and exercises the Upsert/Get/
FindSimilarUsers round-trip against a real database.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 02:16:39 +02:00
1d97ca1164 feat: add getActor and searchActors tools across platforms
Introduce a shared actor.Profile type (internal/actor) so every platform client can return a
common shape without importing the server package (which would be an import cycle).

- Bluesky: GetActor (app.bsky.actor.getProfile) and SearchActors (app.bsky.actor.searchActors) via XRPC.
- ActivityPub: GetActor (accounts/lookup, falling back to accounts/{id}) and SearchActors
  (accounts/search).
- Nostr: GetActor subscribes to kind:0 metadata; SearchActors is best-effort (resolves a
  pubkey/npub query to a single profile; Nostr has no global actor search).
- Twitter: GetActor (/users/by/username) and SearchActors (/users/search).

server: register getActor and searchActors as payable tools; searchActors fans the query out
to all four platforms and merges results, skipping any platform that errors.

Schema fixes: document that getPost.collection is Bluesky-only, and that getFeed.uri is a feed
URI for Bluesky but an author handle for other platforms.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 02:14:29 +02:00
533ecede00 test: cover new cross-platform client methods
Add runnable (HTTP-mocked) unit tests for the client methods added when extending the
post tools to all platforms:

- twitter: GetPost (single-tweet object response + author expansion + public_metrics) and
  GetPostsInTimeframe (start_time/end_time query params + metrics)
- activitypub: GetPostsInTimeframe (paginated Mastodon statuses within a window)
- nostr: resolvePubkey/resolveEventID resolution helpers via real npub/note encoding

Also fix a latent bug in internal/nostr: resolvePubkey/resolveEventID wrapped the wrong
error variable (the nip19 error instead of the hex-decode error) when the 64-hex fallback
failed, producing misleading messages.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 01:44:39 +02:00
4d11cea6cd feat: extend post tools (getPost, getLatestPosts, getPostsInTime, getFeed) to all platforms
Previously these tools were Bluesky-only. They now dispatch by platform:

- getPost: Bluesky uses actor+collection+rkey; ActivityPub uses GetPost(statusID);
  Nostr uses GetPost(noteID); Twitter uses GetPost(tweetID)
- getLatestPosts / getPostsInTime: delegate to each platform client
- getFeed: Bluesky uses GetFeed; other platforms treat the URI as an author handle and
  return their latest posts (no custom-feed concept elsewhere)

Client additions:
- twitter: GetPost, GetPostsInTimeframe; Post now carries like/repost/quote/reply
  counts from public_metrics (populated in GetLatestNPosts and GetPostsInTimeframe)
- nostr: GetPost, GetPostsInTimeframe (relay queries with Since/Until); resolveEventID
  helper mirroring resolvePubkey

Server gains normalized mapping/dispatch helpers (bskyPostViewToResponse,
apPostToResponse, nostrPostToResponse, twitterPostToResponse, fetchSinglePost,
fetchLatestPosts, fetchPostsInTime, fetchFeed) that return a uniform
GetPostResponsePost, mapping missing engagement counts to 0.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 01:41:14 +02:00
e5168e33f3 add: multi-platform getStyleProfile with slow, discovery-based prewarmer
- Nostr client (fiatjaf.com/nostr) fetching kind:1 notes from relays
- Twitter client using raw Twitter API v2 (no external X library), optional (no token = lazy error)
- getStyleProfile dispatches by platform; a profile is updated only when a request is
  made and the cached profile is older than a week (served from cache otherwise)
- shared requestStyleProfile path used by both the tool and the prewarmer
- StartPrewarm discovers interesting authors (from a feed URI or seed list) and
  pre-fetches at most one profile per minute; fresh profiles are never re-embedded
2026-08-29 01:07:47 +02:00