@farthershore/business
Functional value-model API for authoring a software business in TypeScript.
@farthershore/business is the Business-as-Code SDK. This guide explains the
3.2 authoring model; the generated export reference
contains the complete signatures and types. Use a single namespace
import and declaration functions that return immutable branded refs:
import * as fs from "@farthershore/business";
fs.backend("api");
const requests = fs.requests();
const tokens = fs.measure("tokens");
const tokenUsage = fs.meter("token_usage", { measures: [tokens] });
const tokenPricing = fs.pricing("token_usage", {
meter: tokenUsage,
catalog: [fs.rate.perMillion(fs.money.usd(2))],
});
const seats = fs.resource("seats", { cap: fs.scope.subscription });
const chat = fs.route("/v1/chat", {
post: { costs: [requests.fixed(1)], reports: [tokenUsage] },
});
const admin = fs.route("/v1/admin", {
post: { surfaces: [fs.surfaces.api] },
});
fs.meterRoutes("chat-tokens", chat, { reports: [tokenUsage] });
fs.plan("pro", {
kind: fs.plan.kind.hybrid,
price: fs.money.usd(49).monthly(),
usagePricing: tokenPricing.current(),
funding: { buckets: [fs.included(fs.money.usd(10))] },
spendPolicy: {
onExhaustion: fs.exhaustion.overage(tokenPricing.current()),
},
grants: [chat, admin],
limits: [requests.perMinute(60), seats.max(25)],
});
export default fs.business();
Rules
- Plans grant route refs directly. Use
fs.group()to reuse a route bundle. - Cross-references use refs, never declaration-name strings.
- Every plan declares
kind: fs.plan.kind.*; the compiler validates the five economic controls (price,usagePricing,funding,lifecycle,spendPolicy) against it. - Money constructors accept human major units and lower to exact minor units; catalog rates lower to exact rationals.
- Platform vocabulary is grouped under
fs.surfaces,fs.scope,fs.money,fs.rate,fs.modifier,fs.plan.kind,fs.exhaustion,fs.disclosure,fs.display, andfs.rail. - Managed RBAC enablement is platform-owned — toggle it in the dashboard or
with
farthershore business rbac enable, not in code. - The SDK declares the raw product-permission vocabulary through route
operations and permission-bearing groups. Subscribing organizations compose
that vocabulary into their own roles, defaults, assignments, and direct
grants at runtime; no customer role is authored in
business/or seeded by RBAC enablement. - Exactly one module under
business/default-exportsfs.business().
The compiler imports business modules in canonical order inside a fresh, compile-scoped worker. Ordinary TypeScript values and extra exports are inert; only registered SDK declarations affect Manifest IR. An import that throws is reported with its source file.
Routes and metering families
Routes follow the OpenAPI Path Item model: a concrete or {parameter} path
lists the HTTP operations that exist on that path. Wildcards do not declare
routes. fs.meterRoutes(key, route, options) binds a measurement meter to a
declared route under an author-supplied stable key.
const tokens = fs.measure("tokens");
const tokenUsage = fs.meter("token_usage", { measures: [tokens] });
const tokenPricing = fs.pricing("token_usage", {
meter: tokenUsage,
catalog: [fs.rate.perMillion(fs.money.usd(2))],
});
const createChat = fs.route("/v1/chat", {
post: { surfaces: [fs.surfaces.api] },
});
const getChat = fs.route("/v1/chat/{id}", {
get: { surfaces: [fs.surfaces.api, fs.surfaces.ui] },
});
const createEmbedding = fs.route("/v1/embeddings", {
post: { surfaces: [fs.surfaces.api] },
});
fs.meterRoutes("chat-tokens", createChat, {
reports: [tokenUsage],
maxOutputUnits: tokens.atMost(8192),
});
fs.meterRoutes("embedding-tokens", createEmbedding, { reports: [tokenUsage] });
fs.plan("pro", {
kind: fs.plan.kind.usage,
usagePricing: tokenPricing.current(),
grants: [createChat, getChat, createEmbedding],
});
The binding key ("chat-tokens") is what economic agreements and admission
bounds reference; keep it stable across releases. maxOutputUnits,
chunkPolicy, caps, and postStream declare the admission bounds described
in Meters and measures. A route with no binding reports no
rated usage.
Declarations
| Function | Purpose |
|---|---|
fs.requests() | Platform request counter for structural bounds and gateway-known fixed costs. |
fs.measure(key) | One observed quantity a backend reports. |
fs.dimension(key, options?) | A selector axis; .value(v) mints a catalog selector, .is(v) a modifier condition. |
fs.provider(key) | An owned provider namespace; .model(key) mints a catalog item. |
fs.meter(key, { measures, dimensions? }) | A measurement meter — what the backend reports together and under which dimensions. |
fs.pricing(key, { meter, catalog }) | A versioned catalog of exact rates for one meter; .current() / .withContractTerms() / .fixedVersion(n) bind it. |
fs.meterRoutes(key, route, options) | Bind a meter to a declared route under a stable key, with admission bounds. |
fs.route(path, operations) | Path-first HTTP operations and their policy, surface, action, and backend bindings. |
fs.plan(key, options) | Declared kind plus price, usagePricing, funding, lifecycle, spendPolicy, grants, limits, and archival behavior. |
fs.resource(name, options) | Counted resource; its ref exposes max(count) for typed plan limits. |
fs.backend(id, options) | Backend declaration returning a route-bindable ref. |
fs.frontendIntegration(id, options) | Browser-to-provider integration whose credential is held and injected by the platform. |
fs.group(key, routes) | Reusable route bundle. |
fs.business(options?) | Seal the registry; use as the sole default export. |
Value constructors: fs.money.usd(n).monthly() / .yearly(), fs.rate.perUnit / per / perMillion / rational / graduated / volume / backendQuoted,
fs.modifier.multiplier(n, d).when(...), fs.included / prepaid / promo / referral, fs.display.multiplier({ factor }), fs.disclosure.opaque | transparent, fs.exhaustion.block | overage(binding), fs.rail.x402, and
fs.plan.kind.*.
The namespace values fs.surfaces and fs.scope supply typed platform
vocabulary. Use the generated reference for the exhaustive export inventory;
this guide concentrates on the declarations used in the change loop.
Business identity, origin, and presentation are platform-owned operating state.
Frontend page routes and navigation are authored in the editable frontend
application, not in business.ts. Route surfaces control credential
callability only.
The source program must be deterministic; Farther Shore compiles it twice and
rejects differing hashes.
Choose an authoring workflow
| Goal | Workflow |
|---|---|
| Create or split a program | Business program, build output |
| Make an operation callable | Routes, groups and grants |
| Sell measured usage | Meters, plans, metered route recipe |
| Bound stored inventory | Resources, resource-limit recipe |
| Model customer access | Tenancy, team RBAC |
| Connect code and providers | Backend, frontend integrations |
The /codegen entrypoint is tooling for
source generation. It does not replace the authored business/ program or
activate a contract. In particular, reconstructing source from structural IR
cannot recover commerce data that is absent from that IR; unsupported shapes
fail rather than inventing prices. Review generated source, run the local
build, and verify apply in the selected environment before testing traffic.