@ffdb/client
v0.3.14
Published
Universal TypeScript client for the self-hosted FFDB Rust API
Maintainers
Readme
@ffdb/client
Universal TypeScript client for the current FFDB Rust API. It runs in modern
browsers, Node.js, React Native, and Expo when supplied with the runtime's
fetch implementation and an appropriate session store.
FFDB server and SDK releases are version-matched. Pin the package to the exact server version:
pnpm add --save-exact @ffdb/[email protected]The matching GitHub Release also includes a checksum-listed
ffdb-client-0.3.14.tgz for verified offline installation.
import { BrowserSessionStore, FFDBClient, generateId } from "@ffdb/client";
const client = new FFDBClient({
baseUrl: "https://api.example.com",
projectId: "019...",
sessionStore: new BrowserSessionStore(sessionStorage, "my-app.ffdb"),
});
await client.auth.signIn("[email protected]", "correct horse battery staple");
const result = await client.query({
sql: "SELECT id, title FROM todos WHERE owner_id = auth.uid()",
});
const id = generateId("todo_");Developer API keys are server/operator credentials. Do not embed them in browser
bundles. End-user requests use the short-lived project session managed by
client.auth.
Email verification and password recovery use a short FFDB-hosted handoff, then
return to the application with location.replace(). Supply the exact callback
URL when starting the action. Add the browser's origin and the exact callback
under Auth → Policy → Application URLs for the selected project. FFDB
validates both policies at request time, so changes require no host restart and
the emailed link cannot become an arbitrary open redirect.
const callback = new URL("/auth/complete", window.location.origin).href;
await client.auth.register({ email, password, redirect_to: callback });
await client.auth.startPasswordReset(email, { redirectTo: callback });The action credential and callback remain in the URL fragment while FFDB works, then are removed from the visible address bar immediately. Apps should render their normal sign-in or post-verification state at the callback URL. Server and native callers must provide the callback explicitly; FFDB does not guess one.
Platform billing uses the authenticated organization methods
organizationBilling(), createBillingCheckout(), and
createBillingPortal(). Application commerce is a separate project-scoped
surface under client.commerce. It supports encrypted BYO Stripe credentials
or Stripe Connect direct charges, products, immutable prices, one-time and
recurring Checkout, orders, payments, refunds, subscription cancellation,
customer self-service portal sessions, entitlements, and paid-order fulfillment. Provider credentials are write-only
and never reuse FFDB's own platform-billing customer.
client.commerce.disconnectAccount() removes an unused provider configuration
with an idempotent DELETE. The server refuses disconnection while catalog,
customer, order, or subscription records remain provider-bound, preserving
refund, subscription, and reconciliation capability.
const product = await client.commerce.createProduct({
name: "Team membership",
description: "Monthly access for one team",
tax_code: null,
});
const price = await client.commerce.createPrice({
product_id: product.id,
lookup_key: "team_monthly",
currency: "USD",
unit_amount_minor: 1500,
billing: { type: "recurring", interval: "month", interval_count: 1 },
entitlements: { seats: { type: "quantity", value: 10 } },
});
const portal = await client.commerce.customerPortal({
subject: { kind: "team", id: teamId },
return_url: "https://app.example.com/settings/billing",
});Instance operator lifecycle
Instance administration uses the platform developer session, not a project API key. Run it only in a trusted operator process; bootstrap tokens, passwords, and Stripe secrets must never be bundled into browser or native applications.
import { FFDBClient, MemoryDeveloperSessionStore } from "@ffdb/client";
const operatorSessions = new MemoryDeveloperSessionStore("ffdb-operator");
const operator = new FFDBClient({
baseUrl: "https://data.example.com",
developerSessionStore: operatorSessions,
});
const setup = await operator.instanceSetupStatus(); // public, non-secret state
if (setup.bootstrap_available) {
await operator.developerBootstrap(bootstrapToken, ownerEmail, ownerPassword);
}
await operator.configureInstance({
deployment_mode: "team",
organization_creation_policy: "invitation_only",
});
const status = await operator.instanceStatus();For an operator-owned Stripe account, configureInstance() accepts
platform_byo with write-only secret_key and webhook_secret values. A
platform_connect configuration also requires the operator's write-only Stripe
Connect platform secret_key and Connect webhook webhook_secret, in addition
to country/email and absolute portal return/refresh URLs. Then call
createInstanceConnectOnboarding() and refreshInstanceBilling() as required.
Responses expose provider status and capabilities but never return either
supplied credential.
Global administration is available through:
updateOrganizationCreationPolicy();instanceAdministrators(),grantInstanceAdministrator(), andrevokeInstanceAdministrator();- paginated
instanceOrganizations()andinstanceUsers(), plus auditedsetInstanceOrganizationDisabled()andsetInstanceUserDisabled()status changes; billingExemptions(),grantBillingExemption(), andrevokeBillingExemption();instancePlans(),putInstancePlan(), andretireInstancePlan().
The immutable owner and deployment/payment configuration remain owner-only; delegated instance administrators operate the audited global resources authorized by the API, including plan mutations. Provider readiness, owner/self-disable safeguards, and protected/in-use plan rules are enforced by the server.
InstancePlanCatalogEntry.provider_catalog_bound identifies a plan whose
provider-priced terms are already verified in Stripe. That flag is read-only
and omitted from PutInstancePlanCatalogEntryRequest; provider-bound billing
unit, price/currency, and storage/read/write/MAU terms cannot be edited in place.
Related packages
@ffdb/react: providers and hooks@ffdb/react-native: native session and SQLite adapters@ffdb/sync-client: logical offline synchronization@ffdb/cli: migrations, administration, scaffolding, and schema type generation
See the repository API reference for the complete method and response types.
