decent-newsroom / bookshelf-bundle
Reusable Symfony bundle for a Nostr-based bookshelf and e-reader backed by Mercury
Package info
github.com/decent-newsroom/bookshelf-bundle
Type:symfony-bundle
pkg:composer/decent-newsroom/bookshelf-bundle
Requires
- php: ^8.3
- decent-newsroom/asciidoc-html: ^0.1.0
- innis/nostr-core: ^0.3.17
- swentel/nostr-php: ^1.9
- symfony/framework-bundle: ^7.4
- symfony/http-client: ^7.4
- symfony/http-foundation: ^7.4
- symfony/security-bundle: ^7.4
- symfony/twig-bundle: ^7.4
Requires (Dev)
- phpunit/phpunit: ^9.5
This package is auto-updated.
Last update: 2026-08-24 13:58:09 UTC
README
decent-newsroom/bookshelf-bundle is a reusable Symfony bundle providing a
Nostr-based bookshelf and e-reader backed by the Mercury
REST API.
It parses NKBIP-01 publication indexes (kind 30040) and their ordered
publication content events (kind 30041), exposes a public search and reader
UI, and lets authenticated users maintain a personal NKBIP-04 "My Books"
directory (kind 30045).
Features
- Public
/bookshelfsearch over the Mercury catalogue. /bookshelf/{id}continuous book reader with AsciiDoc chapter rendering.- Authenticated
/bookshelf/my-bookspersonal directory andPOST /api/bookshelf/directorypublish endpoint. - Keeps local persistence and relay publishing behind contracts so each host can provide its own implementation.
Documentation
Requirements
- PHP 8.3 or newer.
- Symfony 7.4 or newer.
innis/nostr-core^0.3.17.swentel/nostr-php^1.9(event signature verification).decent-newsroom/asciidoc-html^0.1.0(chapter rendering).
The package uses the DecentNewsroom\BookshelfBundle namespace. Its Composer
mapping is package-local and does not require the consuming application's
App\ classes.
Installation
Install the package from its Composer repository:
composer require decent-newsroom/bookshelf-bundle
During local development, a Symfony host can consume the package through a path repository:
{
"repositories": [
{
"type": "path",
"url": "packages/bookshelf-bundle",
"options": {
"symlink": true
}
}
],
"require": {
"decent-newsroom/bookshelf-bundle": "@dev"
}
}
Register the bundle if Symfony Flex has not done so:
use DecentNewsroom\BookshelfBundle\BookshelfBundle; return [ BookshelfBundle::class => ['all' => true], ];
Import its routes:
# config/routes/bookshelf.yaml bookshelf_bundle: resource: '@BookshelfBundle/Resources/config/routes.yaml'
Configuration
# config/packages/bookshelf.yaml (optional) bookshelf: mercury_api_base_url: 'https://mercury-relay.imwald.eu'
MERCURY_API_BASE_URL may also be set as an environment variable; both are
optional and default to the public Mercury relay.
Host integration
The bundle is deliberately storage-agnostic. A consuming application must alias two contracts:
| Contract | Responsibility |
|---|---|
Contract\DirectoryEventStoreInterface |
Look up a user's own stored directory events (kind 30045) by pubkey and kind. |
Contract\DirectoryEventPublisherInterface |
Persist a signature-verified directory event locally and publish it to the user's write relays. |
services: DecentNewsroom\BookshelfBundle\Contract\DirectoryEventStoreInterface: alias: App\Bookshelf\BookshelfEventStore DecentNewsroom\BookshelfBundle\Contract\DirectoryEventPublisherInterface: alias: App\Bookshelf\BookshelfEventPublisher
Events returned by DirectoryEventStoreInterface must implement
Contract\DirectoryEventInterface (getDTag(), getSlug(), getTags()).
Testing
Install the package dependencies and run its package-owned test suite:
composer install vendor/bin/phpunit -c phpunit.xml.dist
The package tests exercise MercuryApiClient and MercuryBookService
directly against a mocked HTTP client, so they do not require a Doctrine
entity or a newsroom database.
Scope and limitations
This package does not provide:
- a database implementation;
- relay selection, publishing, or NIP-42 authentication;
- application authentication or user management;
- the host application shell (
app-shell.html.twig) or its sidebar/menu components, which templates extend and reference by convention.
Those concerns belong to the consuming Symfony host and are connected through the package contracts and service configuration.