Frontend SDK
Build a managed subscriber portal, understand runtime configuration, and follow the Git-triggered release flow.
@farthershore/farthershore-js connects a browser UI to Farther Shore platform
state and to the business routes behind the gateway. The frontend never needs a
backend origin, Core URL, business id, environment id, or auth endpoint in its
source code when it is hosted by Farther Shore.
The business contract lives in business/; editable UI code lives in
frontend/. Plans, routes, meters, and permissions are repository contract
state. Navigation, page composition, CSS, and browser interactions belong to the
frontend application.
Start with the managed frontend
The managed repository intentionally starts without sample frontend source. The
platform's standard subscriber experience remains available until you add a
custom frontend/ application. A custom hosted frontend is an opt-in part of
the managed repository; create that project, install
@farthershore/farthershore-js, and keep its package and Vite configuration
under frontend/.
The local commands below require that frontend/package.json already exists:
pnpm --dir frontend install
farthershore frontend dev
frontend dev starts Vite with hot reload. With no live configuration it uses
deterministic mock data and bypassed auth for local page work. To serve a
production build locally:
farthershore frontend preview
Opt into real platform data with --live, --core-url, or
VITE_FS_CORE_URL. The CLI injects a temporary window.__FS_CONFIG__ shim; it
does not edit your Vite config or frontend source.
Zero-config client
Hosted HTML receives an environment-specific window.__FS_CONFIG__ from the
edge. The SDK reads it lazily, so client creation is safe at module scope:
import { createFartherShoreClient } from "@farthershore/farthershore-js";
import { FartherShoreRoot } from "@farthershore/farthershore-js/components";
const fs = createFartherShoreClient();
export function App() {
return (
<FartherShoreRoot client={fs}>
<Portal />
</FartherShoreRoot>
);
}
The public client factory accepts application concerns such as organization
selection, mock mode, retry behavior, injected fetch, and error callbacks.
Platform routing and authentication are intentionally not part of custom hosted
frontend configuration; the platform supplies them.
FartherShoreRoot mounts the client provider, bootstrap gate, managed auth,
customer-readiness and legal gates, error boundary, and environment badge. A
signed-in customer does not reach application children until the selected
organization has an ACTIVE subscription with a non-null compiled plan. When
that entitlement is missing, the root presents the managed organization picker
and plan onboarding flow, then refetches the subscriber record before mounting
the application. A catalog entry alone is never treated as enrollment.
The root also includes the managed legal Markdown renderer and its GFM runtime
dependencies. A frontend using the root must not install react-markdown or
remark-gfm separately. The SDK ships no CSS; the frontend repository owns
presentation.
Request boundaries
| SDK surface | Destination | Credential |
|---|---|---|
fs.bootstrap() and public business resolution | Farther Shore platform | none |
| keys, usage, billing, plans, account and team resources | Farther Shore platform | subscriber session |
fs.route.get/post/… | business gateway route | SDK-managed signed browser context |
fs.integration(id) | compiled same-origin integration gateway | signed-in subscriber session |
The platform injects environment routing and the SDK attaches its managed browser context. Your code does not concatenate an environment hostname, select a backend origin, receive a bearer, or supply an access key. A route call is still enforced against the subscriber's current plan, permission, subject type, subscription state, and limits at request time.
const jobs = await fs.route.get("/v1/jobs");
Use typed errors and stable denial codes for UI remediation; never treat a hidden button as authorization.
Git-triggered hosting
Hosted frontend releases follow repository events. There is no separate manual deployment trigger.
| Scope | Build trigger | Activation |
|---|---|---|
| Production | Publish a GitHub Release from the managed repository | Successful release build becomes the production frontend according to release policy |
| Preview environment | Push to that environment branch | Successful build becomes the frontend for that environment |
| Local | farthershore frontend dev or frontend preview | Local Vite process only |
After a push or GitHub Release, inspect the latest known build for that exact source revision:
farthershore frontend status my-business \
--ref "$(git rev-parse HEAD)" \
--wait
For a preview environment:
farthershore frontend status my-business \
--env <environment-name-or-id> \
--ref "$(git rev-parse HEAD)" \
--wait \
--timeout 900
status reports the current release plus recent builds and failure reasons.
--ref limits the observation to the latest known build for that immutable
source revision; it does not identify a particular webhook delivery. Exact
attempt proof requires the build id returned by an enqueue response when one is
available. --wait exits nonzero if the observed build fails or the timeout
elapses.
A change to an FS_PUBLIC_ Variable also enqueues a frontend rebuild because
its value is baked into the bundle. A write-only secret does not rebuild the
frontend — it never enters the bundle; it is published to the edge for a named
integration that references it.
Roll back
Find a previously successful release id in frontend status, then reactivate
it:
farthershore frontend rollback my-business --release-id <release-id>
For production, omitting --env changes the active hosted artifact and pins the
production target. A later Release can build the repository fix, but the
successful build does not autoactivate while the pin remains. After proving the
new release id is healthy, explicitly reactivate it with the same frontend rollback command and read status back. There is no separate unpin command.
For a preview environment, add --env <environment-id>. Preview rollback
changes the active artifact but does not pin it: the next successful build
for that environment autoactivates. Treat preview rollback as temporary
containment, stop or fix the source that is producing bad builds, and verify the
active release again after every preview build.
React hooks
For custom presentation, mount FartherShoreProvider directly or use it through
FartherShoreRoot. Hooks follow the common shape { data, error, isLoading, isError, isSuccess, refetch, queryKey } and add domain mutations:
import { useApiKeys, useUsage } from "@farthershore/farthershore-js/react";
function Usage() {
const usage = useUsage();
if (usage.isLoading) return <p>Loading…</p>;
if (usage.error) return <p>Usage unavailable.</p>;
return <pre>{JSON.stringify(usage.data, null, 2)}</pre>;
}
See Root and data components, Auth and sessions, and Variables for the three integration boundaries most custom portals need.