ResourceX Registry Server - HTTP API server for hosting and serving ResourceX resources.
bun add @resourcexjs/server @resourcexjs/node-provider
# or
npm install @resourcexjs/server @resourcexjs/node-providerThis package provides three levels of abstraction for building a ResourceX registry server:
- Hono Server - Ready-to-use server with all endpoints configured
- Handlers - Framework-agnostic request handlers for custom integrations
- Protocol - Type definitions and constants for building clients
import { createRegistryServer } from "@resourcexjs/server";
import { FileSystemRXAStore, FileSystemRXMStore } from "@resourcexjs/node-provider";
const server = createRegistryServer({
rxaStore: new FileSystemRXAStore("./data/blobs"),
rxmStore: new FileSystemRXMStore("./data/manifests"),
});
// Bun
Bun.serve({ fetch: server.fetch, port: 3000 });
// Node.js (with @hono/node-server)
import { serve } from "@hono/node-server";
serve({ fetch: server.fetch, port: 3000 });Creates a Hono app with all registry endpoints configured.
import { createRegistryServer } from "@resourcexjs/server";
import { FileSystemRXAStore, FileSystemRXMStore } from "@resourcexjs/node-provider";
const server = createRegistryServer({
rxaStore: new FileSystemRXAStore("./data/blobs"),
rxmStore: new FileSystemRXMStore("./data/manifests"),
basePath: "", // Optional: API route prefix (default: "")
cors: true, // Optional: Enable CORS (default: true)
});interface RegistryServerConfig {
rxaStore: RXAStore; // Content-addressable blob storage
rxmStore: RXMStore; // Manifest storage
basePath?: string; // API route prefix (default: "")
cors?: boolean; // Enable CORS (default: true)
}Framework-agnostic handlers for custom server integrations (Next.js, Express, etc.).
import {
handlePublish,
handleGetResource,
handleHeadResource,
handleDeleteResource,
handleGetContent,
handleSearch,
CASRegistry,
} from "@resourcexjs/server";
import { FileSystemRXAStore, FileSystemRXMStore } from "@resourcexjs/node-provider";
const registry = new CASRegistry(
new FileSystemRXAStore("./data/blobs"),
new FileSystemRXMStore("./data/manifests")
);
// Next.js Route Handler example
export async function POST(request: Request) {
return handlePublish(request, registry);
}| Handler | Description |
|---|---|
handlePublish(request, registry) |
Process multipart form publish request |
handleGetResource(locator, registry) |
Get resource manifest |
handleHeadResource(locator, registry) |
Check resource existence |
handleDeleteResource(locator, registry) |
Delete a resource |
handleGetContent(locator, registry) |
Download resource archive |
handleSearch(query, limit, offset, registry) |
Search resources |
All endpoints are prefixed with /api/v1.
Health check endpoint.
Response:
{ "status": "ok" }Publish a resource to the registry.
Content-Type: multipart/form-data
Fields:
locator(string) - Resource locator (e.g.,hello:1.0.0)manifest(file) - JSON manifest filecontent(file) - Archive file (tar.gz)
Response (201):
{ "locator": "hello:1.0.0" }Get resource manifest.
Response (200):
{
"name": "hello",
"type": "text",
"tag": "1.0.0",
"path": "prompts"
}Check if resource exists.
Response: 200 if exists, 404 if not.
Delete a resource.
Response: 204 on success.
Download resource archive.
Response: Binary application/gzip content.
Search for resources.
Query Parameters:
q(string, optional) - Search querylimit(number, default: 100) - Max resultsoffset(number, default: 0) - Pagination offset
Response (200):
{
"results": [
{
"locator": "hello:1.0.0",
"name": "hello",
"type": "text",
"tag": "1.0.0"
}
],
"total": 1
}Type definitions and constants for building clients.
import {
API_VERSION, // "v1"
API_PREFIX, // "/api/v1"
ENDPOINTS, // { publish, resource, content, search, health }
CONTENT_TYPES, // { json, binary, formData }
ERROR_CODES, // Error code constants
buildResourceUrl, // Build resource URL
buildContentUrl, // Build content URL
buildPublishUrl, // Build publish URL
buildSearchUrl, // Build search URL with params
} from "@resourcexjs/server";
// Types
import type {
ManifestData,
SearchQuery,
PublishResponse,
GetResourceResponse,
SearchResultItem,
SearchResponse,
ErrorResponse,
ErrorCode,
} from "@resourcexjs/server";import { buildResourceUrl, buildSearchUrl } from "@resourcexjs/server";
const url = buildResourceUrl("https://registry.example.com", "hello:1.0.0");
// "https://registry.example.com/api/v1/resource/hello%3A1.0.0"
const searchUrl = buildSearchUrl("https://registry.example.com", {
q: "prompt",
limit: 10,
});
// "https://registry.example.com/api/v1/search?q=prompt&limit=10"All error responses follow a consistent format:
{
"error": "Error message",
"code": "ERROR_CODE"
}| Code | Status | Description |
|---|---|---|
LOCATOR_REQUIRED |
400 | Missing locator field |
MANIFEST_REQUIRED |
400 | Missing manifest file |
CONTENT_REQUIRED |
400 | Missing content file |
INVALID_MANIFEST |
400 | Invalid manifest format |
INVALID_LOCATOR |
400 | Invalid locator format |
RESOURCE_NOT_FOUND |
404 | Resource does not exist |
INTERNAL_ERROR |
500 | Internal server error |
For convenience, this package re-exports commonly used classes:
import { CASRegistry, FileSystemRXAStore, FileSystemRXMStore } from "@resourcexjs/server";
import type { RXAStore, RXMStore, Registry } from "@resourcexjs/server";The server uses content-addressable storage (CAS) for efficient deduplication:
./data/
├── blobs/ # Content-addressable blob storage
│ └── ab/
│ └── sha256:abcd1234... # Archive data (tar.gz)
└── manifests/
└── _local/ # Resources stored on this server
└── my-prompt/
└── 1.0.0.json # Manifest with digest reference
Note: The server stores resources without registry prefix. When a resource is published to registry.example.com/hello:1.0.0, it's stored as hello:1.0.0 on the server. The registry prefix is added by clients when they pull resources.
| Package | Description |
|---|---|
resourcexjs |
Client SDK |
@resourcexjs/core |
Core primitives and CASRegistry |
@resourcexjs/node-provider |
Node.js/Bun storage providers |
Apache-2.0