@bandf/framework
v1.7.0
Published
The bandf serverless web framework: router, stdlib, OAS pipeline, compile tooling, and CLI
Readme
@bandf/framework
@bandf/framework is the engine behind a BandF workspace. It discovers independent apps, turns OpenAPI operations into validated HTTP handlers, compiles or bundles browser views, supplies shared services and state, and coordinates local development and AWS deployment.
App developers normally work in a BandF workspace. The framework package provides the runtime and tooling; the workspace supplies apps, shared assets, environment configuration, and the thin Lambda entry point.
Contents
- System model
- Filesystem contracts
- Request runtime
- Standard library and services
- Browser delivery
- State, identity, and assets
- Local development and deployment
- Companion packages
- Framework layout
- Related links
System model
A BandF workspace is an implementation of the framework, not a monolithic application. Each directory under apps/ is a complete app boundary. Removing one app does not affect another app or the request runtime. Cross-app behavior belongs in the framework, in a reusable Service, or in the workspace's explicit common/ layer.
The framework favors discovery over repeated configuration:
api/api.ymldeclares an app's HTTP surface;x-actor-idmaps operations to files underactors/;- the app's build script determines whether Parcel or the HTML compiler owns its views;
- Service directories and their
methods.ymlcontracts are discovered automatically; - view and public-asset directories establish URL behavior;
common/supplies intentionally shared state, assets, templates, and browser code.
This keeps the app-authoring experience consistent even though React apps and HTML/Markdown apps use different build systems.
flowchart LR
Workspace[BandF workspace] --> Apps[Independent apps]
Workspace --> Common[common/ shared layer]
Workspace --> Config[Workspace configuration]
Framework[@bandf/framework] --> Runtime[Router and OAS runtime]
Framework --> Tooling[CLI, local orchestration, deploy plugins]
Framework --> Packages[State, identity, UI, testing]
Runtime --> Apps
Runtime --> Common
Runtime --> Services[Framework and app Services]
Tooling --> AppsFilesystem contracts
The framework reads the workspace and selected app to determine what to run.
| Path | Contract |
| ------------------------------ | ----------------------------------------------------------------------------- |
| router.js | Thin workspace handler that re-exports the framework's main Lambda handler. |
| serverless.yml | Shared Lambda, API Gateway, packaging, environment, and plugin configuration. |
| apps/<app>/configuration.yml | App-specific environment values consumed by Serverless. |
| apps/<app>/api/api.yml | Optional OpenAPI 3 contract for app routes. |
| apps/<app>/actors/ | Actor modules named by x-actor-id. |
| apps/<app>/views/ | React sources or HTML/Markdown sources, depending on app type. |
| apps/<app>/services/ | Optional app-owned Services. |
| apps/<app>/views/public/ | App-owned public assets. |
| common/ | Explicit shared assets, state, mail templates, and browser resources. |
Apps may be API-only and omit views/. For deployment, that intent must also be explicit with API_ONLY=true; a missing React build output is otherwise treated as an incomplete build.
Request runtime
The workspace handler boots one immutable standard library, discovers Channels and Services, parses OpenAPI, imports actors, and registers the resulting operations with find-my-way. The app OAS document is optional; the framework's internal bandf.yml is always present and owns the built-in view and identity routes.
sequenceDiagram
participant G as API Gateway or local proxy
participant R as Router
participant O as OAS actor runtime
participant A as App actor
participant S as Services
G->>R: Lambda-style request event
R->>R: CORS, assets, route lookup, auth
R->>O: matched operation and request data
O->>O: validate body and declared parameters
O->>A: immutable payload, STDLIB, Event, Context
A->>S: optional service calls
A-->>O: status-keyed reply
O->>O: validate declared response schema
O-->>R: status, body, headers, content type
R-->>G: compressed Lambda proxy responseOpenAPI and actors
Each HTTP operation uses x-actor-id to name its actor. The final actor path segment must be a JavaScript module name accepted by the OAS parser. Actor imports and contract compilation happen at boot, so invalid mappings fail early.
export default async ({ payload, STDLIB, Event, Context }) => {
const { name } = payload.message;
return {
200: { greeting: `Hello, ${name}` },
};
};The actor receives:
payload.message: the parsed request body; an absent body is{};payload.params: declared path, query, and header parameters flattened by name;payload.queryandpayload.headers: the raw query and header objects;payload.method,payload.url, andpayload.actorId: route metadata;payload.store: request-scoped data assembled by router middleware;STDLIB,Event, andContext: the shared toolkit and original Lambda inputs.
Actors return an object keyed by a declared numeric HTTP status. headers and type are optional peers to the status keys. Request and parameter validation failures are client errors; an actor reply that violates its declared schema is a server error. Undeclared statuses fail rather than silently escaping the contract.
Only explicit three-digit response codes are instrumented. Bearer authentication uses the framework's OpenAPI security scheme, and a route opts out with security: [].
Middleware order
The router's ordering is part of its contract: CORS and asset resolution run before normal route dispatch; the gatekeeper populates request identity and location context before the actor runs; response serialization, compression, error shaping, and security headers are applied on the way out. Diagnostics Channels mark lifecycle boundaries without coupling actors to the router implementation.
Standard library and services
STDLIB is constructed once during router boot and passed to actors and Services as an immutable toolkit. It centralizes:
- workspace, app, source, compiled, and asset paths;
- the configured HTTP client, logging, cache, utility, and validation helpers;
- HTML/Markdown compilation and view resolution;
- S3 object access and bucket naming;
- the Service registry.
Services are the main extension point for reusable stack capabilities. The loader discovers framework Services first and then the selected app's Services. Each Service directory declares callable methods in methods.yml; the loader validates method input with Ajv and exposes enabled methods through STDLIB.Services.get('<service>/<method>'). An app method with the same key replaces the framework method and emits a warning.
Framework Services include filesystem/S3 access, mail delivery and templates, and Supabase document and identity access. Apps can add domain Services such as Stripe checkout and subscriptions without placing that behavior in another app. A Service registers only when its required environment is available; callers should treat an absent optional Service as a capability that is not configured.
Channels use node:diagnostics_channel for lifecycle, producer, and Service instrumentation. They are internal observation points, not a durable queue or a cross-app messaging API. Local consumer discovery is available for offline diagnostics; producer scaffolding does not create an application event bus.
Browser delivery
The app's package.json determines the view pipeline. A build script containing the parcel command identifies a bundled app; other view apps use the framework compiler.
| Concern | React app | HTML/Markdown app |
| --------------- | ------------------------------------------ | ---------------------------------------------------------------------- |
| Build system | Parcel | BandF HTML/Markdown compiler |
| Local reload | Parcel HMR | BrowserSync reload through its proxy |
| Browser modules | Normal Parcel imports | Local scripts are compiled and inlined; remote scripts remain external |
| Environment | Parcel plus the injected browser allowlist | Compiler substitution plus the same injected allowlist |
| State boot | Injected by the Parcel HTML transformer | Injected by the HTML compiler |
| Deploy artifact | Parcel views/dist, then compiled pages | Compiled pages from source views |
The HTML pipeline is not raw static-file serving. It parses HTML or GitHub-flavored Markdown, resolves scripts, styles, state, assets, and image behavior, and writes .compiled artifacts for the runtime view actor. BrowserSync gives that pipeline the same save-and-see experience that Parcel HMR provides for React.
Parcel's custom HTML transformer supplies the same framework boot state, shared-resource invalidation, seed signature, and optional in-page agent loader. During deployment the view compiler consumes the Parcel output and inlines its browser assets into the final page.
State, identity, and assets
@bandf/framework-state gives React and vanilla apps the same Valtio-backed store model. App code explicitly creates namespaces, while the framework adds reserved environment and system slices. The system slice comes from files in common/state/; the environment slice contains only the browser allowlist. Persistence is app-and-stage scoped and excludes framework-owned slices by default.
@bandf/framework-identity provides two peer login methods:
- MetaMask uses an EIP-1193 provider and a Sign-In with Ethereum challenge;
- email uses a short-lived magic link delivered through the mail Service.
Both methods prove an allowlisted Supabase identity and receive the same bearer JWT session. React components, vanilla custom elements, and imperative cores share the same session storage and internal identity endpoints.
Asset resolution is app-first and then common/. Public assets are available below /assets/; view-relative assets can be inlined by the compiler. Image processing, lazy loading, and the optional expander are kept consistent across view types. S3 helpers address an externally provisioned bucket, normally named from the workspace prefix, app, and stage; the framework does not create the bucket.
Local development and deployment
bandf start <app> <stage> derives a port family from the configured app port and orchestrates the processes with PM2:
- the Lambda-compatible server runs through Serverless Offline;
- HTML/Markdown apps use BrowserSync on the development port;
- React apps use Parcel and its HMR transport;
- the optional agent bridge uses its own HTTP and WebSocket ports.
PM2 watches server-side app, shared, and framework inputs and restarts the appropriate process. Browser view tools own view reloads, so server restarts and UI refreshes remain separate concerns.
When the agent bridge is enabled locally, the framework injects an in-page control bar and runs the coding agent in Docker. The selected app is the editing boundary, the framework is mounted read-only, and checkpoints support diff, undo, and recovery. The container mount is not a security sandbox for sibling app paths; the layered agent instructions and server-side checks enforce the named-app contract.
Deployment builds the selected view pipeline, compiles final pages, and lets Serverless package the selected app, shared resources, and framework runtime for a Node.js Lambda behind API Gateway. The default workspace target uses Node 24 on ARM64 in us-east-1. AWS accounts, IAM, DNS, S3, Supabase, mail, and payment-provider resources remain external prerequisites rather than framework-provisioned resources.
Companion packages
The framework installs matching companion packages that app code imports directly:
| Package | Purpose |
| ---------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| @bandf/framework-state | React and vanilla state, persistence, browser environment, shared system-state loading. |
| @bandf/framework-identity | MetaMask/SIWE and email magic-link login adapters and controls. |
| @bandf/framework-ui | Raw JSX React primitives, BandF components, and Tailwind helpers. |
| @bandf/framework-testing | Six-phase app and framework test orchestration. |
Framework layout
| Path | Responsibility |
| ---------------------------- | --------------------------------------------------------------------------------- |
| router.js | Lambda handler and middleware composition. |
| oas/ | OAS parsing, actor construction, request/response validation, and HTTP execution. |
| stdlib/ | Standard library, compiler, Services, S3, HTTP, logging, and utilities. |
| channels/ and producers/ | Diagnostics-channel discovery and lifecycle instrumentation. |
| router-extensions/ | Assets, CORS, authentication, response shaping, and headers. |
| parcel-transformers/ | React HTML boot-state and agent integration. |
| serverless-plugins/ | Package and deploy hooks. |
| bin/ | bandf commands, local orchestration, generation, testing, and agent bridge. |
| templates/ | App scaffolds selected by bandf generate. |
| packages/ | State, identity, UI, and testing packages. |
