Farther ShoreDocs
Go to Farther Shore
The fs.business() program
Functional declarationsSplit a growing programContract optionsDeterminismChange loop
Meters & measures
Counted resources
Routes & access groups
Route groups & grants
Plans & pricing
The build output
Team RBAC
Tenancy & identity
Frontend integrations
@farthershore/business
Add metered routes
Add a resource limit
Add team RBAC
@farthershore/business exports
@farthershore/business/codegen exports
Status
Docs/Build your product/The fs.business() program

The fs.business() program

Author the repository-owned contract with the functional Business SDK.

The business/ folder is the contractual source of truth. Farther Shore loads all of its supported source modules in canonical order and requires exactly one default-exported fs.business() result.

The managed repository begins without a source file. Create business/business.ts as the conventional starter, or split declarations into sibling modules. Discovery is by folder, not by filename.

ts
import * as fs from "@farthershore/business";

fs.backend("api");
const requests = fs.requests();
const status = fs.route("/v1/status", {
  get: { costs: [requests.fixed(1)] },
});

fs.plan("starter", {
  kind: fs.plan.kind.free,
  grants: [status],
  limits: [requests.perMinute(60)],
});

export default fs.business();

Functional declarations

Import the SDK as a namespace:

ts
import * as fs from "@farthershore/business";

Start with business, route, and plan. Add measure, dimension, meter, pricing, and meterRoutes for measured usage; requests and resource for structural limits; backend and frontendIntegration for runtime bindings. group composes routes and can declare custom permission subjects. Managed RBAC enablement is operating state, not an fs.rbac() declaration.

Use the generated Business SDK exports for the complete signatures and types. The SDK guide explains how to choose and combine them.

Declarations return immutable branded refs. Pass those refs to routes, groups, and plans; do not reconstruct reference-shaped objects or join by string.

Split a growing program

Only one module may finalize the registry:

business/
  business.ts      # imports declarations and default-exports fs.business()
  routes.ts        # exports route refs
  plans.ts         # declares plans using imported refs
  package.json
  tsconfig.json

Every discovered source module executes, even when the entry module does not import it explicitly. The normal isolated folder loader defers finalization until all discovered modules have imported, so an alphabetically early business module does not discard declarations in later files. Outside that loader, fs.business() finalizes immediately and later declarations fail.

For portable, easy-to-review programs, explicitly import declaration modules before the single default-exported fs.business() call. Do not depend on alphabetical filenames to establish dependencies: import the refs you use. Calling fs.business() twice is invalid even in deferred loader mode.

What folder discovery includes

Supported source extensions are .ts, .tsx, .mts, and .cts. The folder walk skips declaration files and files named with .test/.spec suffixes, and prunes node_modules, dist, __tests__, __fixtures__, and __mocks__. Symlink entries are not followed by the walk. These are discovery rules, not a sandbox for arbitrary code imported by your program.

--entry business/single-file.ts selects that file and its imports; it does not discover all its siblings. Prefer the normal folder build when verifying what the platform will compile. Ensure the business package uses ESM module semantics so its default export is exposed to the loader as intended.

Contract options

fs.business() accepts these business-wide contract option families:

OptionResponsibility
visibilityPublic/private business visibility intent
authHeaderAPI-key header the gateway reads; default x-api-key
upstreamAuthUpstream-auth contract; never paste credentials into source
billOn4xxBusiness-level treatment of client-error responses for billing
operatorPoliciesPlatform operator-policy intent
customerContextcontextTokens and customerAuth controls
billingLimit-upgrade timing and subscriber-change policy

Unknown top-level options are rejected. Business identity, display name, description, icons, concrete backend origins, environment variables, and release state are platform-owned and do not belong in this call.

Determinism

Treat the program as a pure declaration graph. Do not read environment variables, make network requests, inspect the filesystem, use current time, or generate random values while declaring the contract. The compiler builds twice and rejects different hashes.

Change loop

bash
farthershore build
farthershore validate
git add business
git commit -m "Update business contract"
git push

After push, inspect the repository validation/apply check for the same commit and intended environment. The accepted contract changes only after apply succeeds. A local build does not bind an origin, deploy your backend, or prove a subscriber can call the route.

Before handing off, exercise one allowed operation and one denied operation with a preview subscriber. Record the commit, environment, applied contract, and observed response. If compilation fails after splitting modules, check that the entry imports every declaration before sealing; if apply fails, correct the source and inspect the next apply instead of editing the generated artifact.

NextMeters & measures

On this page

Functional declarationsSplit a growing programWhat folder discovery includesContract optionsDeterminismChange loop