BSB Registry Core
service-bsb-registryEvent-driven plugin registry core for multi-language BSB plugin storage and discovery
BSB Registry Core
Event-driven plugin storage and business logic for the BSB plugin registry. This plugin has no HTTP server -- it exposes all operations as BSB returnable events. The companion service-bsb-registry-ui plugin provides the HTTP/web layer.
Configuration
service-bsb-registry:
database:
type: file # 'file' or 'postgres'
path: ./.temp/data # file storage directory (type: file)
auth:
requireAuth: true # require bearer token for write operations
| Option | Type | Default | Description |
|---|---|---|---|
database.type |
'file' or 'postgres' |
'file' |
Storage backend |
database.path |
string | ./.temp/data |
Directory for file-based storage |
auth.requireAuth |
boolean | true |
Require authentication for publish/delete |
Events
All operations are exposed as returnable events. The UI/API plugin (or any other BSB plugin) calls these via the generated BsbRegistryClient.
Plugin Operations
| Event | Input | Output | Description |
|---|---|---|---|
registry.plugin.publish |
PublishRequest | PublishResponse | Publish a new plugin version |
registry.plugin.get |
{ org, name, version? } |
RegistryEntry | Get plugin details (latest if no version) |
registry.plugin.list |
ListQuery | ListResults | List plugins with filtering and pagination |
registry.plugin.search |
SearchQuery | SearchResults | Full-text search across names, tags, descriptions |
registry.plugin.delete |
{ org, name, version? } |
{ success, deleted } |
Delete a plugin or specific version |
registry.plugin.versions |
{ org, name, majorMinor? } |
VersionList | Get all versions of a plugin |
Stats and Auth
| Event | Input | Output | Description |
|---|---|---|---|
registry.stats.get |
{} |
RegistryStats | Total plugins, counts by language/category |
registry.auth.login |
{ username, password } |
{ success, token?, message? } |
Login (not yet implemented -- use tokens) |
registry.auth.verify |
{ token } |
{ valid, userId?, permissions? } |
Verify a bearer token |
Publish Request Schema
The publish request is the primary write operation. The body is validated by the UI/API plugin at the HTTP boundary and passed as a structured object through events.
{
"org": "mycompany",
"name": "service-my-plugin",
"version": "1.0.0",
"language": "nodejs",
"metadata": {
"displayName": "My Plugin",
"description": "Short description of the plugin",
"category": "service",
"tags": ["example", "demo"],
"author": "Author Name",
"license": "MIT",
"homepage": "https://example.com",
"repository": "https://github.com/org/repo"
},
"eventSchema": {
"pluginName": "service-my-plugin",
"version": "1.0.0",
"events": {
"my-plugin.do-something": {
"type": "returnable",
"category": "onReturnableEvents",
"description": "Does something",
"inputSchema": { "type": "object", "properties": {} },
"outputSchema": { "type": "object", "properties": {} }
}
},
"dependencies": []
},
"configSchema": {
"type": "object",
"properties": {
"port": { "type": "number", "default": 3000, "description": "Server port" }
},
"required": ["port"]
},
"documentation": [
"# My Plugin\n\nThis is the main readme content...",
"# API Reference\n\nDetailed API documentation..."
],
"dependencies": [
{ "id": "bettercorp/service-other", "version": "^1.0.0" }
],
"package": {
"nodejs": "@mycompany/my-plugin"
},
"runtime": {
"nodejs": ">=18.0.0"
},
"visibility": "public"
}
Field Reference
| Field | Required | Type | Description |
|---|---|---|---|
org |
yes | string | Organization name (use _ for unaffiliated) |
name |
yes | string | Plugin name |
version |
yes | string | Semver version (e.g. 1.0.0) |
language |
yes | enum | nodejs, csharp, go, java, python |
metadata |
yes | object | Display info (displayName, description, category, tags, etc.) |
eventSchema |
yes | object | EventSchemaExport object from build |
configSchema |
no | object | JSON Schema for plugin configuration (must have type: "object") |
documentation |
yes | string[] | Array of markdown strings (min 1, max 20). Title extracted from first # heading |
dependencies |
no | array | Plugin dependencies [{ id, version }] |
package |
no | object | Language-specific package names (npm, NuGet, etc.) |
runtime |
no | object | Runtime version requirements |
visibility |
no | enum | public (default) or private |
Version Immutability
Published versions are immutable. Attempting to publish the same org/name/version will return an error. Publish a new version instead.
Storage
File Storage (Default)
Stores plugin data as JSON files in the configured directory. Suitable for development and single-instance deployments.
PostgreSQL (Production)
For multi-instance or high-availability deployments. Set database.type: postgres and provide the connection URL. Migrations run automatically on first start.
Authentication
Authentication is enforced at the HTTP layer (by service-bsb-registry-ui). The core plugin trusts event callers -- if you are calling events directly from another BSB plugin, no token is needed.
API tokens are stored in a JSON file:
{
"tokens": [
{
"name": "ci-deploy",
"token": "bsb_abc123...",
"createdAt": "2026-02-13T00:00:00Z",
"permissions": ["read", "write"]
}
]
}
Permissions:
read-- list, search, get plugin detailswrite-- publish and delete pluginsadmin-- all operations
See Also
- service-bsb-registry-ui -- Web UI and REST API
- BSB Registry README -- Project overview
Registry File DB
File-based storage backend for the BSB Registry. Stores all data as JSON files in a configurable directory. This is the default storage backend -- suitable for development, single-instance deployments, and small registries.
Configuration
service-bsb-registry:
database:
type: file
path: ./.temp/data
The path is the root directory. All subdirectories and files are created automatically on first startup.
Directory Layout
<path>/
plugins/
<org>/
<name>/
<version>.json # RegistryEntry for each published version
orgs/
<orgId>.json # Organization metadata + members
users.json # User[] array
tokens.json # AuthToken[] array
File Schemas
Plugin Version -- plugins/<org>/<name>/<version>.json
One file per published version. Created on publish, never modified (versions are immutable).
{
"id": "mycompany/service-demo",
"org": "mycompany",
"name": "service-demo",
"displayName": "Demo Service",
"description": "Example service plugin",
"version": "1.0.0",
"majorMinor": "1.0",
"language": "nodejs",
"category": "service",
"tags": ["demo", "example"],
"visibility": "public",
"eventSchema": {
"demo.do-something": {
"type": "returnable",
"category": "onReturnableEvents",
"description": "Does something",
"inputSchema": { "type": "object", "properties": {} },
"outputSchema": { "type": "object", "properties": {} }
}
},
"configSchema": {
"type": "object",
"properties": {
"port": { "type": "number", "default": 3000, "description": "Server port" }
},
"required": ["port"]
},
"documentation": [
"# Demo Service\n\nMain documentation content..."
],
"dependencies": [],
"package": {
"nodejs": "@mycompany/service-demo"
},
"runtime": {
"nodejs": ">=18.0.0"
},
"author": {
"name": "Author Name",
"email": "author@example.com"
},
"license": "MIT",
"homepage": "https://example.com",
"repository": "https://github.com/mycompany/service-demo",
"eventCount": 1,
"emitEventCount": 0,
"onEventCount": 0,
"returnableEventCount": 1,
"broadcastEventCount": 0,
"publishedBy": "user-uuid-here",
"publishedAt": "2026-02-17T00:00:00.000Z",
"updatedAt": "2026-02-17T00:00:00.000Z",
"downloads": 0
}
Field Reference
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Full ID (org/name) |
org |
string | yes | Organization name |
name |
string | yes | Plugin name |
displayName |
string | yes | Human-readable name |
description |
string | yes | Short description (max 1000 chars) |
version |
string | yes | Semver (1.0.0) |
majorMinor |
string | yes | Major.minor only (1.0) |
language |
enum | yes | nodejs, csharp, go, java, python |
category |
enum | yes | service, observable, events, config |
tags |
string[] | yes | Searchable keywords |
visibility |
enum | yes | public or private |
eventSchema |
object | yes | Events map (Record<eventName, EventExportEntry>) |
configSchema |
object | no | JSON Schema for plugin config (type: "object") |
documentation |
string[] | no | Array of markdown strings |
dependencies |
array | no | [{ id: "org/name", version: "^1.0.0" }] |
package |
object | no | Language-specific package names |
runtime |
object | no | Runtime version requirements |
author |
string or object | no | Author name or { name, email?, url? } |
license |
string | no | License identifier |
homepage |
string | no | Documentation URL |
repository |
string | no | Source repository URL |
eventCount |
int | yes | Total event count |
emitEventCount |
int | yes | Fire-and-forget emit events |
onEventCount |
int | yes | Fire-and-forget on events |
returnableEventCount |
int | yes | Returnable events |
broadcastEventCount |
int | yes | Broadcast events |
publishedBy |
string | yes | User ID or "system" |
publishedAt |
ISO datetime | yes | First publish timestamp |
updatedAt |
ISO datetime | yes | Last update timestamp |
downloads |
int | no | Download count (default 0) |
Organization -- orgs/<orgId>.json
One file per organization. Created when an organization is first set up.
{
"id": "mycompany",
"name": "mycompany",
"displayName": "My Company",
"pluginCount": 0,
"visibility": "public",
"members": [
{
"userId": "user-uuid-here",
"permission": "write"
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Organization ID |
name |
string | yes | Organization name (same as ID) |
displayName |
string | yes | Human-readable display name |
pluginCount |
int | yes | Stored count (live count computed on read) |
visibility |
enum | yes | public or private |
members |
array | no | [{ userId, permission }] |
Member permissions: read or write.
Users -- users.json
Single file containing all registered users as a JSON array.
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Admin User",
"email": "admin@example.com",
"active": true,
"permissions": ["read", "write", "create-org"],
"createdAt": "2026-02-17T00:00:00.000Z",
"updatedAt": "2026-02-17T00:00:00.000Z"
}
]
| Field | Type | Required | Description |
|---|---|---|---|
id |
UUID | yes | User ID |
name |
string | yes | Display name |
email |
string | yes | Email address |
active |
boolean | yes | Account active flag |
permissions |
string[] | yes | User-level permissions: read, write, create-org |
createdAt |
ISO datetime | yes | Account creation time |
updatedAt |
ISO datetime | yes | Last update time |
Tokens -- tokens.json
Single file containing all API tokens as a JSON array.
[
{
"token": "bsb_abc123...",
"userId": "550e8400-e29b-41d4-a716-446655440000",
"name": "CI deploy",
"permissions": ["read", "write"],
"createdAt": "2026-02-17T00:00:00.000Z",
"expiresAt": null
}
]
| Field | Type | Required | Description |
|---|---|---|---|
token |
string | yes | Bearer token string |
userId |
UUID | yes | Owner user ID |
name |
string | yes | Token label (e.g. "CI deploy", "laptop") |
permissions |
string[] | no | Token-scoped permissions (inherits from user if omitted) |
createdAt |
ISO datetime | yes | Token creation time |
expiresAt |
ISO datetime | no | Optional expiration (null = never expires) |
Bootstrapping
On first startup, the file DB creates the directory structure and empty users.json / tokens.json files automatically. No manual setup is needed.
To seed initial data, create the files manually before starting the service:
- Create
users.jsonwith at least one admin user - Create
tokens.jsonwith a token tied to that user - Start the service -- it will use the existing files
Generate a token string:
node --input-type=module -e "import { randomBytes } from 'node:crypto'; console.log('bsb_' + randomBytes(32).toString('hex'));"
Limitations
- Single-writer only -- no concurrent process safety
- All queries scan files on disk (no indexing)
- Not suitable for large registries (1000+ plugins)
- No automatic backups -- back up the data directory yourself
For production or multi-instance deployments, use PostgreSQL (database.type: postgres).
See Also
- service-bsb-registry -- Core registry plugin
- service-bsb-registry-ui -- Web UI and REST API
Installation
bsb client install service-bsb-registry
bsb plugin install service-bsb-registry
npm install @bsb/registry
Configuration
Configuration options for this plugin:
No configuration required
Events
Events available to clients of this plugin:
Emit and Return
Call these events and receive a response.
registry.plugin.publish
returnable
Publish a new plugin or version
registry.plugin.publish
returnable
registry.plugin.get
returnable
Get plugin details by org/name
registry.plugin.get
returnable
registry.plugin.list
returnable
List plugins with filtering
registry.plugin.list
returnable
registry.plugin.search
returnable
Search plugins by query
registry.plugin.search
returnable
registry.plugin.delete
returnable
Delete a plugin or specific version
registry.plugin.delete
returnable
registry.plugin.versions
returnable
Get all versions of a plugin
registry.plugin.versions
returnable
registry.stats.get
returnable
Get registry statistics
registry.stats.get
returnable
registry.auth.login
returnable
Authenticate user and get token
registry.auth.login
returnable
registry.auth.verify
returnable
Verify authentication token
registry.auth.verify
returnable
Available Versions
Dependencies
No dependencies