Imported from RayhanHamada/raurus (
packages/server/AGENTS.md). Install upstream withnpx skills add RayhanHamada/raurus --skill server. Copyright stays with the author.
Package Agent Guide
Package Context
This package is @raurus/server, a contract-first HTTP server built on oRPC. It implements the shared contracts from @raurus/contract using @orpc/server and exposes an RPCHandler-backed fetch handler. It uses its own src/logger/ module (LogTape wrapper) for structured logging and never calls configure() itself — that is the responsibility of the consuming application.
Architecture
src/
├── index.ts # Public barrel — exports raurus and CreateRuntimeOptions from src/runtime/
├── core/
│ ├── index.ts # Barrel: re-exports errors + types + constants from @raurus/contract
│ ├── errors.ts # AdapterError — typed error with FailureCode
│ ├── types.ts # Domain types, adapter contracts, factories
│ └── types.test.ts # Vitest type-level tests
├── adapters/
│ ├── index.ts # Barrel: re-exports all adapters
│ ├── libsql/index.ts # libsql-based database adapter
│ └── s3mini/index.ts # S3-compatible storage adapter backed by s3mini
├── logger/
│ ├── config.ts # logTapeConfig (Config) + per-category level tables + initializeLogger
│ ├── get-logger.ts # getLogger factory (["raurus", ...rest] categories)
│ └── index.ts # Barrel: re-exports config + get-logger
└── runtime/
├── index.ts # Named export: raurus (alias for createRuntime) + CreateRuntimeOptions
├── models.ts # failureCodeToStatus mapper (FailureCode → HTTP status)
├── routes.ts # oRPC procedure implementations — wraps @raurus/contract contracts via implement()
├── runtime.ts # createRuntime() — async factory, inits adapters, returns { fetch, close }
└── utils.ts # Logger instance (getLogger("server")) + initializeLogger re-export
tsdown.config.ts # Build config — entry: src/index.ts, src/core/index.ts, src/runtime/index.ts, src/logger/index.ts, src/adapters/index.ts, src/adapters/*/index.ts
Key Concepts
- Single public export —
raurus()from@raurus/serveris the only entry point. It isasync:await raurus({...})creates a fetch-compatible runtime with both adapters already initialized.CreateRuntimeOptionsis also exported as a type for consumers.Router(the oRPC router type derived fromtypeof router) is exported so that RPC clients (e.g.,RPCLink) can consume the server's typed procedure signatures. - Contract-first — Routes are defined in
@raurus/contract(Valibot schemas + oRPC contracts). The server package implements them via@orpc/server'simplement(contracts).$context<ServerContext>(). Input validation is handled entirely by the contract layer. - CreateRuntimeOptions —
baseUrl: string | URL(required),databaseAdapter: RuntimeDatabaseAdapter(required),storageAdapter: RuntimeStorageAdapter(required),debug?: boolean(defaultfalse). - Context-based dependency injection —
routes.tsdefines aServerContextinterface{ db: RuntimeDatabaseAdapter; storage: RuntimeStorageAdapter }. Theimplement(contracts).$context<ServerContext>()threads adapters to every handler via the oRPC context, replacing Elysia's.decorate()pattern. - Error handling — Adapter methods throw
AdapterError(anErrorwith a requiredFailureCode). Procedure handlers catch it via a sharedtoORPCErrorhelper and throwORPCErrorwith the mapped status fromfailureCodeToStatus(code).NOT_FOUNDmaps to the contract'sNOT_FOUNDerror; everything else maps toNOT_IMPLEMENTED. Non-AdapterErrorexceptions (programmer bugs) propagate untouched. TheNOT_IMPLEMENTEDerror carries{ name: string }data as defined in the contract. TheCONFLICTerror carries{ name: string, detail?: string }and is used when a placeholder type mismatch is detected. - Logging — Use
getLogger("server")from@/logger(re-exported as@raurus/server/logger) for runtime, route, and adapter logs. Adapter modules scope their logger (getLogger("server", "libsql")). The server package only obtains loggers; the consuming app is responsible for callingconfigure()from@logtape/logtapeonce at startup (orinitializeLogger()from@raurus/server/loggerfor quickdebug-mode setup). - Fetch-compatible —
createRuntime()returns{ fetch, close }, backed byRPCHandlerfrom@orpc/server/fetch, compatible with Bun, Cloudflare Workers, and other WinterCG runtimes. Theclose()method gracefully shuts down both adapters. In serverless environments like Cloudflare Workers, there is no automatic shutdown hook —close()must be called explicitly by the consumer (e.g., in a scheduled handler or via a custom lifecycle wrapper).new URL()is used for baseUrl parsing instead ofURL.parse()for broad Workers compatibility date support. - Adapter lifecycle — Every adapter implements
init(),close(), andcheckConnection()fromAdapterLifecycle.createRuntime()awaits bothinit()calls concurrently at startup, so backend failures are fail-fast, not first-request.init()is idempotent.checkConnection()is a pure health probe — it resolves void when healthy, throwsAdapterError(CONNECTION) when not, and never triggersinit(). Adapter factories are synchronous and pure — they construct the adapter object but perform no side effects. All setup goes ininit().close()is idempotent; afterclose(), every other method rejects withAdapterError(CONFIGURATION). - Storage capabilities — Partial storage implementations declare
capabilities: { presignedUpload, delete }. All methods are required on the interface; an adapter with afalseflag rejects that method withAdapterError(NOT_IMPLEMENTED). Routes check the flag first and throwORPCError("NOT_IMPLEMENTED", { status: 501 })— never use a 400 status for a missing capability. - Metadata upsert procedure —
upsertMetadatadelegates directly todb.upsertContentMetadata(). Each(placeholder_id, pathname)pair is an independent row — the sameplaceholder_idmay exist on different pages with different types. ThrowsORPCError("NOT_IMPLEMENTED", ...)on adapter failure. - Placeholder storage — A single
raurus_placeholderstable stores all placeholder data with composite primary key(placeholder_id, pathname). There is no separate definitions table and no type-enforcement layer — the server simply upserts whatever the client sends.init()usesCREATE TABLE IF NOT EXISTS(idempotent, no sentinel query). - Metadata read procedure —
listMetadataByPathnamedelegates todb.listContentMetadataByPath()and returns all placeholder metadata for a given pathname. Used by the frontend to hydrate placeholder values on page load. Rows with unknowntypevalues are skipped with a warning log. - Presigned upload URL procedure —
getPresignedUploadUrlchecksstorage.capabilities.presignedUpload, then delegates tostorage.createPresignedUploadUrl(). ThrowsORPCError("NOT_IMPLEMENTED", { status: 501 })when the capability is off. - Delete asset procedure —
deleteAssetchecksstorage.capabilities.delete, then delegates tostorage.deleteAsset(). ThrowsORPCError("NOT_FOUND", { status: 404 })onAdapterErrorwithNOT_FOUND, andORPCError("NOT_IMPLEMENTED", ...)otherwise. - Failure code → HTTP status —
models.tsexportsfailureCodeToStatus(code: FailureCode): numberthat maps aFailureCodeto an HTTP status. Used bytoORPCErrorin procedure handlers. The code is always present onAdapterError, so no fallback is needed.
Package Standards
- Keep runtime logic under
src/runtime/—src/index.tsis a thin barrel that re-exportsraurusandCreateRuntimeOptionsfrom./runtime routes.tsis the single file defining procedure implementations usingimplement()from@orpc/serverand the contracts from@raurus/contract- Export the runtime factory as
raurusfromsrc/runtime/index.ts - Use the in-tree logger (
@/logger, published as@raurus/server/logger) for all logs; create module-levelconst log = getLogger("server", "<area>")loggers and do not callconfigure()inside this package - When an adapter call throws, log
error.messageand route it through thetoORPCErrorhelper inroutes.tswith a descriptive fallback name - When a storage capability is off, check
storage.capabilities.<flag>and throwORPCError("NOT_IMPLEMENTED", { status: 501 })— never use a 400 status for a missing capability - All validation is defined in
@raurus/contract— do not duplicate schemas in the server package
Workflow
-
Read the root
AGENTS.mdbefore planning or implementing changes -
Build with
bun run build(tsdown with ESM output) -
Run tests with
bun run test(vitest) -
Type-check with
bun run typecheck -
Build uses tsdown with entries
src/index.ts,src/core/index.ts,src/runtime/index.ts,src/logger/index.ts,src/adapters/index.ts, andsrc/adapters/*/index.ts— category barrel exports and individual adapters are auto-picked up -
Logger lives in
src/logger/— a LogTape wrapper exposinggetLogger,logTapeConfig,initializeLogger,RaurusPackageNames(["core", "server"]), and per-category level tables. Consumers import it via@raurus/server/logger. -
utils.tsexports a module-levelloglogger instance and re-exportsinitializeLoggerfrom@/logger -
Adapters live in per-adapter directories under
src/adapters/(libsql/,s3mini/), each with its ownindex.ts, all barrel-exported fromsrc/adapters/index.ts. Importable as@raurus/server/adapters,@raurus/server/adapters/libsql,@raurus/server/adapters/s3mini. -
Adapters extend the base config interfaces from
@raurus/server/core(RuntimeDatabaseAdapterBaseConfig,RuntimeStorageAdapterBaseConfig); factory functions return the adapter directly (theRuntimeDatabaseAdapterFactory/RuntimeStorageAdapterFactorytypes exist for custom adapters) -
Database adapters — currently only
libsql(LibsqlDatabaseAdapterConfig,libSqlDatabaseAdapter). TheCreateRuntimeOptionsfield is nameddatabaseAdapter. -
Storage adapters — currently only
s3mini(S3MiniStorageAdapterOptions,s3MiniStorageAdapter). TheCreateRuntimeOptionsfield is namedstorageAdapter. -
RuntimeDatabaseAdapterexposesupsertContentMetadata(resolves void) andlistContentMetadataByPath(resolves the metadata list) — both required.upsertContentMetadatatakes a discriminated payload union ({ type: photo, assetKey } | { type: text, text } | { type: link, text, link }). Link payloads carry bothtext(display/anchor text) andlink(href URL). -
RuntimeStorageAdapterrequirescreatePresignedUploadUrl(resolves{ url, headers? }) anddeleteAsset(resolves void), pluscapabilities: { presignedUpload, delete }flags for partial implementations -
createRuntime()is the async runtime factory function defined inruntime.ts; it is re-exported asraurusfromruntime/index.ts. The return type includes aclose()method for graceful shutdown. Alwaysawaitit. -
Adapter factories are synchronous and pure — all setup side effects (connections, schema migrations, authentication) go in
init(), whichcreateRuntime()awaits at startup. Config validation may throwAdapterError(CONFIGURATION) synchronously in the factory. -
New adapters need no lifecycle wrapper — just implement
AdapterLifecycle(init/close/checkConnection) plus the kind interface, declare anid, and (for storage) acapabilitiesmap. Each adapter guards its own methods against post-close()calls withAdapterError(CONFIGURATION). -
utils.tsexports a module-levelloglogger instance and re-exportsinitializeLoggerfrom@/logger -
The
@raurus/contractpackage is aworkspace:*dependency; contracts are imported viaimport { contracts } from "@raurus/contract". ThebaseOccontract defines shared error types:NOT_IMPLEMENTEDandCONFLICT, withNOT_FOUNDadded ondeleteAsset. -
The libsql database adapter creates a single
raurus_placeholderstable oninit()viaCREATE TABLE IF NOT EXISTSwith composite primary key(placeholder_id, pathname)and columns:type,asset_key,text_content,link_url,updated_at. -
Third-party drivers (
@libsql/client,s3mini) are peer dependencies — consumers install them. Mirror them indevDependenciesso tests and builds resolve locally. Cloudflare Workers compatibility is a hard constraint on driver choice. -
@orpc/serveris used for theRPCHandlerimport at@orpc/server/fetch