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 -e "console.log('bsb_' + require('crypto').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:
Tree view shows nested config fields and object branches.
database
database
object
type
database.type
"file" | "postgres"
default: "file"
path
database.path
string
default: "./.temp/data"
auth
auth
object
requireAuth
auth.requireAuth
boolean
default: true
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
org
string
Organization name
name
string
Plugin name
version
string
Semantic version
language
"nodejs" | "csharp" | "go" | "java" | "python"
Programming language
metadata
object
Plugin metadata
eventSchema
unknown
EventSchemaExport object (parsed at HTTP boundary, transported as object)
capabilities
unknown
optional
Plugin capabilities object (parsed at HTTP boundary, optional top-level override)
configSchema
unknown
optional
Configuration JSON Schema object (parsed at HTTP boundary)
typeDefinitions
object
optional
Language-specific type definitions
documentation
string[]
Array of markdown documentation files (at least 1 required)
dependencies
object[]
optional
Plugin dependencies
package
object
optional
Language-specific package information
runtime
object
optional
Runtime version requirements
visibility
"public" | "private"
optional
Visibility level (default: public)
publishedBy
string
optional
User ID of the publisher (set by HTTP layer)
success
boolean
Operation success status
pluginId
string
Full plugin ID (org/name)
version
string
Published version
message
string
optional
Success or error message
registry.plugin.get
returnable
Get plugin details by org/name
registry.plugin.get
returnable
org
string
Organization name
name
string
Plugin name
version
string
optional
Version (defaults to latest)
id
string
Full ID: org/plugin-name
org
string
Organization or user name
name
string
Plugin name
displayName
string
Human-readable name
description
string
Short description
version
string
Semantic version (1.0.0)
majorMinor
string
Major.minor only (1.0)
language
"nodejs" | "csharp" | "go" | "java" | "python"
Programming language
package
object
optional
Language-specific package information
category
"service" | "observable" | "events" | "config"
Plugin category
tags
string[]
Searchable keywords
author
unknown
optional
Author - either a string or { name, email?, url? }
license
string
optional
License identifier
homepage
uri
optional
Documentation URL
repository
uri
optional
Source repository URL
visibility
"public" | "private"
Visibility level
eventSchema
unknown
Events map (Record<eventName, EventExportEntry>)
capabilities
unknown
optional
Plugin capabilities object
configSchema
unknown
optional
Configuration JSON Schema object
typeDefinitions
object
optional
Language-specific type definitions
documentation
string[]
optional
Array of markdown documentation files (at least 1 required)
dependencies
object[]
optional
Plugins this plugin depends on
permissions
object[]
optional
Per-package user permissions
eventCount
int32
Total event count
emitEventCount
int32
Fire-and-forget emit events
onEventCount
int32
Fire-and-forget on events
returnableEventCount
int32
Returnable events
broadcastEventCount
int32
Broadcast events
publishedBy
string
User ID who published
publishedAt
datetime
First publish timestamp
updatedAt
datetime
Last update timestamp
downloads
int32
optional
Download count
runtime
object
optional
Runtime version requirements
registry.plugin.list
returnable
List plugins with filtering
registry.plugin.list
returnable
org
string
optional
Filter by organization
language
"nodejs" | "csharp" | "go" | "java" | "python"
optional
Filter by language
category
"service" | "observable" | "events" | "config"
optional
Filter by category
limit
int32
optional
Results per page (default: 50)
offset
int32
optional
Pagination offset (default: 0)
results
object[]
Plugin list
total
int32
Total count
page
int32
Current page number
registry.plugin.search
returnable
Search plugins by query
registry.plugin.search
returnable
query
string
Search query string
language
"nodejs" | "csharp" | "go" | "java" | "python"
optional
Filter by language
category
"service" | "observable" | "events" | "config"
optional
Filter by category
limit
int32
optional
Results per page (default: 20)
offset
int32
optional
Pagination offset (default: 0)
results
object[]
Matching plugins
total
int32
Total result count
query
string
Search query used
registry.plugin.delete
returnable
Delete a plugin or specific version
registry.plugin.delete
returnable
org
string
Organization name
name
string
Plugin name
version
string
optional
Version (or all if not provided)
success
boolean
Success status
deleted
int32
Number of versions deleted
registry.plugin.versions
returnable
Get all versions of a plugin
registry.plugin.versions
returnable
org
string
Organization name
name
string
Plugin name
majorMinor
string
optional
Filter by major.minor
versions
object[]
All available versions
latest
string
Latest version
latestForMajorMinor
string
JSON map of major.minor to latest patch
registry.stats.get
returnable
Get registry statistics
registry.stats.get
returnable
totalPlugins
int32
Total plugin count
byLanguage
string
JSON map of language to count
byCategory
string
JSON map of category to count
totalDownloads
int32
Total downloads across all plugins
registry.auth.login
returnable
Authenticate user and get token
registry.auth.login
returnable
username
string
Username
password
string
Encrypted password
success
boolean
Login success
token
string
optional
Auth token
expiresAt
datetime
optional
Expiration
message
string
optional
Error message
registry.auth.verify
returnable
Verify authentication token
registry.auth.verify
returnable
token
string
Token to verify
valid
boolean
Token validity
userId
string
optional
User ID
permissions
string[]
optional
Available Versions
Dependencies
No dependencies