Awesome-omni-skill blong-layer
Organize handlers into named functional groups within a Blong realm. Layers include gateway (API), adapter (external systems), orchestrator (business logic), error (domain errors), and test (automation). Use when organizing code by functional concern, defining handler groups, or controlling deployment activation.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/frontend/blong-layer" ~/.claude/skills/diegosouzapw-awesome-omni-skill-blong-layer && rm -rf "$T"
skills/frontend/blong-layer/SKILL.mdImplementing a Layer
Overview
Layers are named groups of handlers that organize code by functional concern within a realm. They enable clear separation of responsibilities and support the framework's modular architecture.
Key Pattern: Layers are self-contained — each layer file defines its own configuration and validation, co-located with its implementation. No need to maintain configuration in a central
server.ts.
Purpose
- Separation of Concerns: Group related functionality together
- Co-located Config: Each layer owns its configuration and validation
- Code Organization: Clear folder structure for handlers
- Deployment Control: Layers can be activated/deactivated per environment
- Team Coordination: Different teams can work on different layers
Recommended Layer Names
Server-Side Layers (auto-detected)
- API gateway: routes, validation, documentation (minimal business logic)gateway
- External system communication: SQL, HTTP, FTP, mail protocolsadapter
- Business process coordination between adaptersorchestrator
- Domain-specific error definitionserror
- Test automation (dev/build only)test
- Electronic Funds Transfer (high TPS OLTP requirements)eft
Browser-Side Layers (auto-detected)
- Browser adapter talking to serverbackend
- React UI componentscomponent
- Server-side code serving browser assetsbrowser
Folder Structure
Typical Realm with Layers
Well-known layer folders are auto-discovered — no
layer.server.ts needed:
realmname/ ├── server.ts # Optional — only for realm-level config/validation ├── error/ # Auto-activated (well-known name) │ └── error.ts ├── adapter/ # Auto-activated (well-known name) │ ├── db.ts # Self-contained database adapter (with config) │ ├── http.ts # Self-contained HTTP adapter (with config) │ └── db/ # Handler group: realmname.db │ ├── userUserAdd.ts │ └── userUserFind.ts ├── orchestrator/ # Auto-activated (well-known name) │ └── dispatch.ts # Self-contained orchestrator (with config) └── gateway/ # Auto-activated (well-known name) └── api/ └── user.yaml
Custom (non-well-known) layer folders need a
layer.server.ts or layer.browser.ts:
realmname/ └── myCustomLayer/ └── layer.server.ts # Required: declares activation for non-well-known folder
layer.server.ts / layer.browser.ts
For folders with non-standard names, add a
layer.server.ts or layer.browser.ts to declare activation. This eliminates the need for an explicit children array or activation config in the parent server.ts.
// myCustomLayer/layer.server.ts import {layer} from '@feasibleone/blong'; export default layer({ default: true, // active in all environments microservice: true, // additionally active in microservice deployment });
// myBrowserLayer/layer.browser.ts import {layer} from '@feasibleone/blong'; export default layer({ integration: true, // only active during integration testing });
Well-Known Layer Default Activations
| Folder | Server default | Browser default |
|---|---|---|
| | — |
| | - |
| | - |
| | — |
| | — |
| | — |
| | |
| | |
| |
Self-Contained Layer Pattern
Adapter Layer Definition
// adapter/db.ts - self-contained with config and validation import {adapter} from '@feasibleone/blong'; export default adapter(blong => ({ extends: 'adapter.knex', // Layer's own validation schema validation: blong.type.Object({ namespace: blong.type.Union([blong.type.String(), blong.type.Array(blong.type.String())]), imports: blong.type.Union([blong.type.String(), blong.type.Array(blong.type.String())]), logLevel: blong.type.Optional(blong.type.String()), }), // Layer's own configuration per environment activation: { default: { namespace: 'db/$subject', imports: '$subject.db', }, dev: { logLevel: 'trace', }, prod: { logLevel: 'warn', }, }, }));
Orchestrator Layer Definition
// orchestrator/dispatch.ts - self-contained with config and validation import {orchestrator} from '@feasibleone/blong'; export default orchestrator(blong => ({ extends: 'orchestrator.dispatch', validation: blong.type.Object({ namespace: blong.type.Union([blong.type.String(), blong.type.Array(blong.type.String())]), imports: blong.type.Union([ blong.type.String(), blong.type.Array(blong.type.String()), blong.type.Array(blong.type.RegExp()), ]), validations: blong.type.Optional( blong.type.Array(blong.type.Union([blong.type.String(), blong.type.RegExp()])), ), destination: blong.type.Optional(blong.type.String()), }), activation: { default: { destination: 'db', namespace: ['$subject'], imports: [/^$subject\./], validations: [/^$subject\.\w+\.validation$/], }, }, }));
Realm Entry Point (Only When Needed)
server.ts is optional. It is only needed when there is realm-level config or validation shared across layers.
// server.ts — only when realm-level config is needed import {realm} from '@feasibleone/blong'; export default realm(blong => ({ url: import.meta.url, validation: blong.type.Object({ myService: blong.type.Object({url: blong.type.String()}), }), activation: { default: { myService: {url: 'http://localhost:8080'}, }, }, }));
Handler Group Pattern
Group Naming Convention
Groups are named in format:
realmname.foldername
Example:
- Realm:
user - Folder:
orchestrator/user/ - Group name:
user.user
Referencing Groups
Groups are referenced in the
imports property of the adapter/orchestrator:
// adapter/db.ts - imports declared inline export default adapter(blong => ({ extends: 'adapter.knex', activation: { default: { namespace: ['user', 'role'], imports: ['user.user', 'user.role'], // handler groups loaded }, }, }));
Implementation Patterns
Error Layer
// realmname/error/error.ts export default { userNotFound: 'User not found', userExists: 'User already exists', invalidEmail: 'Invalid email format', permissionDenied: 'Permission denied', };
Adapter Layer Structure
adapter/ ├── db.ts # Self-contained database adapter ├── http.ts # Self-contained HTTP adapter ├── db/ # Handler group for db operations │ ├── userAdd.ts │ └── userFind.ts └── http/ # Handler group for HTTP operations ├── send.ts └── receive.ts
Orchestrator Layer Structure
orchestrator/ ├── dispatch.ts # Self-contained orchestrator definition ├── entity1/ # Handler group: realmname.entity1 │ ├── ~.schema.ts # Auto-generated validation │ ├── helper.ts # Library function │ └── realmEntity1Action.ts └── entity2/ # Handler group: realmname.entity2 ├── ~.schema.ts └── realmEntity2Action.ts
Gateway Layer Structure
gateway/ └── api/ ├── entity1.yaml # OpenAPI spec for entity1 └── entity2.yaml # OpenAPI spec for entity2
Or with custom validation:
gateway/ └── entity/ ├── entityAction1.ts # Manual validation └── entityAction2.ts
Test Layer Structure
test/ └── test/ # Handler group: test.test ├── testEntity1.ts ├── testEntity2.ts └── testWorkflow.ts
Layer Activation
In Realm Configuration (server.ts)
export default realm(blong => ({ config: { // Activate for automated testing test: { error: true, adapter: true, orchestrator: true, gateway: true, test: true, }, // Activate for microservice deployment microservice: { error: true, adapter: true, orchestrator: true, gateway: true, }, // Activate for single realm dev focus realm: { adapter: true, orchestrator: true, }, // Development with full stack dev: { error: true, adapter: true, orchestrator: true, gateway: true, }, }, }));
One Handler Per File Pattern
Benefits
- Fast Discovery: Use
in VS Code to find handlers quicklyctrl+p- Example:
findsctrl+p uuauserUserAdd.ts
- Example:
- Easier Code Review: Smaller files, less nesting
- Better Isolation: Clear boundaries between handlers
- Git-Friendly: Smaller diffs, fewer conflicts
Naming Convention
File name = handler name:
- Handler:
→ File:userUserAdduserUserAdd.ts - Handler:
→ File:mathNumberSummathNumberSum.ts - Library:
→ File:validateEmailvalidateEmail.ts
Adding a New Adapter
Before (Old Pattern) - Touch 2 files
// 1. Create adapter/newadapter.ts export default adapter(() => ({ extends: 'adapter.http', })); // 2. Update server.ts validation + config + children // (3 edits in server.ts)
After (New Pattern) - Touch 1 file
// 1. Create adapter/newadapter.ts - everything co-located export default adapter(blong => ({ extends: 'adapter.http', validation: blong.type.Object({ url: blong.type.String(), timeout: blong.type.Number(), }), activation: { default: { url: 'http://api.example.com', timeout: 5000, }, }, })); // 2. Done! Framework uses the layer's own config.
Multi-Layer Example
Complete Realm Structure
payment/ ├── server.ts # Minimal - activation only ├── error/ │ └── error.ts ├── adapter/ │ ├── db.ts # Self-contained: config + validation inside │ ├── fspiop.ts # Self-contained: config + validation inside │ └── db/ │ ├── paymentCreate.ts │ └── paymentFind.ts ├── orchestrator/ │ ├── dispatch.ts # Self-contained: config + validation inside │ ├── transfer/ │ │ ├── ~.schema.ts │ │ ├── calculateFees.ts │ │ ├── paymentTransferPrepare.ts │ │ └── paymentTransferCommit.ts │ └── quote/ │ ├── ~.schema.ts │ └── paymentQuoteCreate.ts ├── gateway/ │ └── api/ │ ├── transfer.yaml │ └── quote.yaml └── test/ └── test/ ├── testTransfer.ts └── testQuote.ts
Best Practices
- Co-locate Config: Put layer configuration in the layer file, not in server.ts
- Clear Separation: Keep business logic in orchestrator, not gateway
- Consistent Naming: Use lowercase single words for layer names
- Group by Entity: Organize handlers by business entity within layers
- Library Functions: Extract reusable code into library functions
- Error Definitions: Always define errors in error layer first
- Test Coverage: Create test layer with comprehensive test handlers
- One File Per Handler: Follow the one handler per file pattern
- Validation: Use
for automatic validation generation~.schema.ts - Import Order: Load layers in order: error → adapter → orchestrator → gateway → test
Examples from Codebase
- Complete realm:
core/test/demo/ - Payment realm:
ml/payment/ - Agreement realm:
ml/agreement/