Documentation
¶
Overview ¶
Package dtrpg wraps github.com/pilgrimagesoftware/dtrpg-sdk.go for the CLI's `import dtrpg` commands: application-key storage in the OS keychain, session exchange, paged library retrieval, and product-to-volume mapping. It drives catalog-api only through the internal/client package, never directly.
Index ¶
Constants ¶
const ( // KeychainService matches auth.ServiceName. Duplicated as an untyped // constant to avoid importing internal/auth from here. KeychainService = "sweetrpg-cli" // KeychainAccount is the slot holding the DriveThruRPG application key. KeychainAccount = "dtrpg-app-key" )
Keychain identifiers. The service name is shared with the platform session store; the account keeps the DriveThruRPG key in its own slot so `auth logout` and `dtrpg logout` never touch each other's credentials. One DriveThruRPG login is shared by every consumer (`catalog import dtrpg library`, `game-room import dtrpg`) - it's one external account either way, so there's nothing to isolate between them.
const ( PropProductID = "dtrpg_product_id" PropISBN = "dtrpg_isbn" )
Volume property names carrying DriveThruRPG provenance. dtrpg_product_id is also the idempotency key: a second import skips any product whose ID already appears here on an existing volume. Purchase date, order id, and cover URL are deliberately not recorded - they are personal-order facts (or, for the cover, an off-site reference) that don't belong in the shared catalog; the cover image itself is fetched and stored as a volume asset instead.
Variables ¶
var ErrNoKey = errors.New("no DriveThruRPG key stored: run 'sweetrpg dtrpg login'")
ErrNoKey means no DriveThruRPG application key is stored.
Functions ¶
This section is empty.
Types ¶
type Cover ¶
Cover is a downloaded cover image ready to upload.
func FetchCover ¶
FetchCover downloads a product's cover image from DriveThruRPG. Every failure mode (no URL, network error, non-2xx, oversized body, unsupported content type) returns a nil *Cover and a descriptive error - callers treat this as a per-product warning, never a fatal one.
type KeyStore ¶
KeyStore persists the DriveThruRPG application key. The seam keeps commands testable and lets a broken keychain surface as a clear refusal instead of a plaintext fallback.
type KeyringStore ¶
type KeyringStore struct{}
KeyringStore persists the key in the OS keychain via go-keyring, under KeychainAccount - the one slot shared by every consumer of the DriveThruRPG login.
func (KeyringStore) DeleteKey ¶
func (KeyringStore) DeleteKey() error
func (KeyringStore) LoadKey ¶
func (KeyringStore) LoadKey() (string, error)
func (KeyringStore) SaveKey ¶
func (KeyringStore) SaveKey(key string) error
type Library ¶
type Library struct {
Products []library.OrderProductItem
Included []library.IncludedItem
}
Library is the owner's full DriveThruRPG library: every ordered product across all pages, plus the sideloaded Publisher/Product resources they reference.
type MemoryKeyStore ¶
type MemoryKeyStore struct {
// contains filtered or unexported fields
}
MemoryKeyStore is an in-process KeyStore for tests.
func (*MemoryKeyStore) DeleteKey ¶
func (m *MemoryKeyStore) DeleteKey() error
func (*MemoryKeyStore) LoadKey ¶
func (m *MemoryKeyStore) LoadKey() (string, error)
func (*MemoryKeyStore) SaveKey ¶
func (m *MemoryKeyStore) SaveKey(key string) error
type Product ¶
type Product struct {
ProductID string // dtrpg_product_id; the idempotency key
Title string
PublisherName string
CoverURL string // source image to fetch and store as the volume cover
Archived bool
Volume catvo.VolumeVO
}
Product is one DriveThruRPG ordered product mapped to a catalog volume, keeping the fields the importer classifies and acts on alongside the volume payload.
func MapProducts ¶
MapProducts converts a fetched library into catalog volumes. Mapping is conservative: only title, short description, and category tags land in volume fields; ISBN, purchase date, cover URL, and the raw DTRPG identifiers ride in properties where a wrong guess can't pollute a typed field.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session is an authenticated DriveThruRPG library client. The JWT it holds is never persisted; it dies with the process, and each run re-exchanges the stored application key for a fresh one.
func NewSession ¶
NewSession exchanges appKey for a DriveThruRPG session and returns a library client bound to it. baseURL overrides the production API endpoint (tests point it at a fixture server); pass "" for production.
func (*Session) FetchLibrary ¶
func (s *Session) FetchLibrary(ctx context.Context, pageSize uint32, onPage func(page int, fetched int)) (Library, error)
FetchLibrary pages through the authenticated user's order_products, requesting filter categories so tags can be mapped. Rate-limit responses carrying Retry-After are waited out before retrying the same page.
The archived query parameter is deliberately left unset. An earlier version unconditionally passed archived=true on the (SDK-doc-comment) assumption that it additively includes archived items alongside active ones; against a real ~1700-title account that returned only 40 - evidently an archived-only filter, not "everything". Leaving the parameter off returns the account's full, unfiltered order_products, and each item's own Archived field (already read downstream in mapping.go) still drives per-product archived/active classification - no server-side filtering needed for that at all.
onPage, when non-nil, is called after each page is fetched with the page number just retrieved and the running product total - callers use it for progress output; pass nil to skip it.