A decentralized music tracking and discovery platform built on AT Protocol 🎵 rocksky.app
spotify atproto lastfm musicbrainz scrobbling listenbrainz
rocksky purescript feeds README.md
3.7 kB · 75 lines
Markdown
at main

Rocksky feed generator #

PureScript port of apps/feeds, targeting Node.js >=22.15 in this workspace. All 52 algorithm definitions, query selection, pagination, optional-auth policy, configuration, and HTTP handlers live in src/Rocksky/Feeds/.

From purescript/:

bun install
bun run build:feeds
bun run start:feeds
bun run test:feeds
bun run bundle:feeds
# Alternatively, run the bundle with workspace npm dependencies available:
node feeds/dist/index.js

The entrypoint loads .env from the current directory. Configuration:

Variable Development default / behavior
NODE_ENV development; also accepts test and production
ROCKSKY_FEEDGEN_DOMAIN localhost; required in production
ROCKSKY_FEEDGEN_PORT 8002; required in production
XATA_POSTGRES_URL postgresql://postgres:mysecretpassword@localhost:5433/rocksky?sslmode=disable; required in production
XATA_READ_POSTGRES_URL Preferred when nonempty; otherwise use XATA_POSTGRES_URL
COMMIT_SHA unknown; exposed by the health endpoint
OTEL_ENABLED Set true to start the Node OpenTelemetry SDK
OTEL_DENO true also enables the Node SDK, for compatibility with existing deployment settings
OTEL_SERVICE_NAME rocksky-feeds
OTEL_EXPORTER_OTLP_ENDPOINT http://localhost:4318; per-signal endpoint variables override it

The service exposes /, /xrpc/_health, /.well-known/did.json, /xrpc/app.rocksky.feed.describeFeedGenerator, and /xrpc/app.rocksky.feed.getFeedSkeleton. Discovery preserves the publisher DID, algorithm order, and every original feed URI. Skeletons return { feed: [{ scrobble: uri }], cursor? }, matching the running source handlers (the source's generated lexicon output types are stale).

Query.purs uses the workspace's Drizzle bindings and shared Rocksky.Schema.Scrobbles / Rocksky.Schema.Artists tables. The all feed uses the typed query builder. Genre feeds use parameterized Drizzle SQL with the same bounded LATERAL query as the original. Pool sizing, replica preference, query timeouts, and the rocksky-feeds:replica application name are preserved. This read-only service does not create tables or apply migrations.

Pagination defaults to 50 rows and uses an exclusive timestamp cursor. The accepted offset parameter remains unused, matching the source. Invalid cursor strings fail for the all feed and are ignored by genre feeds. Only genre feeds filter null scrobble URIs. Timestamp ties have the same pagination limitations as the original service.

Bearer JWTs are signature-verified through the AT Protocol library. As in the source, authentication is optional, invalid tokens become anonymous, and no audience or lexicon-method restriction is imposed. All current feeds are public. Tokens are not printed in error logs.

FFI covers JWT verification, cursor number conversion, Node lifecycle, and OpenTelemetry adapters. Node replaces Deno's server and built-in telemetry; the workspace SDK supplies OTLP export and HTTP instrumentation. Feed and SQL spans and metric names are preserved. SQL bound values and caller DIDs are not added to custom telemetry attributes. SIGINT/SIGTERM close the HTTP server, database pool, and telemetry exporter.

Tests exercise HTTP contracts, all source algorithm mappings, real Drizzle SQL generation and row decoding, optional authentication, errors, and telemetry adapters. To also execute both query paths against PostgreSQL:

TEST_FEEDS_DATABASE_URL=postgresql://... bun run test:feeds

That test creates connection-local temporary artists and scrobbles tables; they disappear when the connection closes. It does not modify application tables.