@omg-dev/admin
v0.4.42
Published
Embeddable internal admin console — a panel-registry React component (**Feature Flags**, **Users**, and read-only **Pricing/Billing**) that drops into any host as a single `<AdminConsole/>`. Host-agnostic: you pass it where the control-plane lives and how
Readme
@omg-dev/admin
Embeddable internal admin console — a panel-registry React component
(Feature Flags, Users, and read-only Pricing/Billing)
that drops into any host as a single <AdminConsole/>. Host-agnostic: you pass
it where the control-plane lives and how to mint a bearer token; it does the
rest. Self-styled (no Tailwind dependency), and every endpoint it calls is
admin-gated server-side
(requireAdmin allowlist in the control-plane).
The same component is embedded in three places:
- the omg dashboard (
/adminroute), - the LFG app (a
@vibesSDK app), as a tab, - Inspect (later — the per-app shell will mount it for platform admins).
Embed (any host)
import { AdminConsole } from "@omg-dev/admin";
<AdminConsole
config={{
apiBase: "https://backend.omg.dev", // control-plane origin
getToken: () => myAuth.getAccessToken(), // bearer JWT (or null when signed out)
}}
/>;Embed a single panel, or as a tab in an existing tab shell:
import { FlagsPanel, AdminClient } from "@omg-dev/admin";
const client = new AdminClient({ apiBase, getToken });
// inside your own <Tabs>: { id: "flags", label: "Flags", content: <FlagsPanel client={client} /> }Backend proxy (recommended — keep the token server-side)
Don't ship the control-plane token to the browser. Mount the proxy in your app's backend; the browser calls a same-origin path and the server injects the admin token (from its own env) and forwards to the control-plane:
// server (Bun.serve / Fetch API / Hono / Next route handler):
import { createOmgAdminProxy } from "@omg-dev/admin/server";
const omgAdmin = createOmgAdminProxy({ token: process.env.OMG_ADMIN_TOKEN! });
// inside your request handler:
const res = await omgAdmin(req); // Request → Response | null
if (res) return res; // null = not our path; fall through// client — point at the mount, no token in the browser:
<AdminConsole config={{ apiBase: "/_omg", getToken: () => null }} />The proxy only forwards /api/flags/*, /api/users/*,
and /api/adminBilling/* (the admin surface), so a leaked mount can't wield the
token elsewhere. OMG_ADMIN_TOKEN is an auth.omg.dev JWT for an allowlisted
admin — rotate it in server env, no client rebuild. Options:
{ token, target?, prefix? } (target default https://backend.omg.dev,
prefix default /_omg).
LFG integration
LFG already has a @omg-dev/sdk auth provider, so reuse its token. Add the dep
("@omg-dev/admin": "^0.4.13") and mount the console as a new tab:
import { AdminConsole } from "@omg-dev/admin";
import { useAuth } from "@omg-dev/sdk"; // or LFG's own auth hook
function AdminTab() {
const { token } = useAuth();
return (
<AdminConsole
config={{
apiBase: import.meta.env.VITE_CONTROLPLANE_URL ?? "https://backend.omg.dev",
getToken: () => token,
}}
/>
);
}The signed-in LFG user must be on the control-plane admin allowlist
(VIBES_ADMIN_EMAILS / VIBES_ADMIN_USER_IDS) or the panels return 401.
Standalone (its own app)
import { mountAdminConsole } from "@omg-dev/admin/standalone";
mountAdminConsole(document.getElementById("root")!, {
apiBase: "https://backend.omg.dev",
getToken: async () => myAuth.getToken(),
});Panels
- Flags (read/write) — create/edit flags, toggle, set rollout %, per-plan rules, and per-account overrides (search an account by email, flip it on). Boolean and JSON-valued flags (a JSON flag can carry e.g. a per-account model allowlist or a rate-limit config). Resolution order: explicit override → per-plan rule → rollout % (stable hash) → global default.
- Users (read-only) — searchable account list with sessions, app counts, flag override counts, and on-demand billing balance for the selected user.
- Pricing (read-only) — live plan→Stripe projection + the model catalog.
Pricing is code-defined (
defineBilling) and reconciled by the orchestrator; this is a window, not an editor.
Server contract
Talks to the control-plane custom functions:
POST /api/flags/{listFlags,upsert,setArchived,removeFlag,listOverrides,setOverride,removeOverride,findUsers,evaluate}POST /api/users/{listUsers,findUsers}POST /api/adminBilling/{planVersions,models,userBalance}
flags.evaluate is the consumer-facing endpoint (non-admin = self only) that
apps/services use to resolve a user's flag set.
