@tuxx/orbit-embed
v0.1.9
Published
Embed Orbit surfaces — feedback, task board — inside any client app. Auth-bridged via HMAC-signed JWTs issued by the host backend.
Maintainers
Readme
@tuxx/orbit-embed
Drop Orbit Bridge surfaces (client chat and task board) directly inside a client's own app. Authentication is bridged via a short-lived HMAC-signed JWT issued by the client's backend — no Orbit accounts are created, no data leaves the client's user funnel.
v0.1 surface area
<OrbitProvider>— single client + token refresher<OrbitClientPanel>— floating or inline client surface with messages, build status, files, and requests<OrbitFeedback>— client dashboard chat composer + thread<OrbitTaskBoard>— read-only client-safe task board for the active project
Install
npm install @tuxx/orbit-embedPeer dependencies: react >= 18 and react-dom >= 18.
Ship the bundled stylesheet once per host app:
import "@tuxx/orbit-embed/styles.css";Wire it up
Every new install should call the orbit-bridge Supabase Edge Function. The
host app's backend must mint a short-lived HS256 JWT signed with the
tenant's signing_secret (provisioned in Orbit admin → Bridge Settings).
Required claims:
| Claim | Meaning |
| ------------ | ----------------------------------------------- |
| tenant_id | embed_tenants.id issued during provisioning |
| sub | Stable external user id in the client's app |
| exp | Unix seconds; keep it short (≤ 15 minutes) |
| email | Optional — surfaces in Orbit inbox |
| name | Optional — surfaces in Orbit inbox |
Then, in the host React tree:
import {
OrbitProvider,
OrbitClientPanel,
} from "@tuxx/orbit-embed";
import "@tuxx/orbit-embed/styles.css";
export function ClientDashboardLayout() {
return (
<OrbitProvider
endpoint="https://<project>.supabase.co/functions/v1/orbit-bridge"
anonKey={import.meta.env.VITE_ORBIT_ANON_KEY}
token={async () => {
const res = await fetch("/api/orbit-bridge-token", {
credentials: "include",
});
if (!res.ok) throw new Error(`Orbit token failed (${res.status})`);
const data = await res.json() as { token: string };
return data.token;
}}
theme="inherit"
>
<OrbitClientPanel mode="floating" launcherLabel="Support" />
</OrbitProvider>
);
}Mount this from an authenticated dashboard/app layout only. Do not mount it in the public marketing site.
The token prop accepts either a string or an async function. Use the
function form so the widget can fetch a fresh JWT as the old one nears
expiry.
Server-side token minting (Node example)
import jwt from "jsonwebtoken";
export function mintOrbitJwt(user: { id: string; email?: string; name?: string }) {
return jwt.sign(
{
tenant_id: process.env.ORBIT_TENANT_ID!,
sub: user.id,
email: user.email,
name: user.name,
},
process.env.ORBIT_SIGNING_SECRET!, // base64 from Admin -> Bridge
{ algorithm: "HS256", expiresIn: "10m" },
);
}Token endpoints should return JSON:
{ "token": "<short-lived-orbit-tenant-jwt>" }Rotate the signing secret at any time from Orbit Admin -> Bridge Settings. Old JWTs stop verifying the moment the rotation lands.
Allowed origins
Every tenant declares which origins are allowed to call the gateway. The
edge function rejects any request whose Origin header isn't in the
allowlist. Add http://localhost:5173 (or whatever your dev port is) to
test locally.
What gets written to Orbit
- Messages from
<OrbitFeedback>land inpublic.inbox_messageswithchannel_type = 'orbit_bridge'and a reference back to the embed contact that sent them. - Structured bridge events are written to
public.bridge_events. - Bridge commands are queued in
public.bridge_commandsfor backend or browser listeners to poll and acknowledge. - Client requests and approvals are written to
public.bridge_client_requestsand mirrored into the Orbit inbox asorbit_bridgemessages. - Client-visible tasks are read-only in v0.1 — the widget reads the tenant's
active project via
public.project_tasksand surfaces the client-safe projection.
What's next
<OrionChat>— conversational agent scoped to the tenant's Orbit data- Write mutations on the task board (status transitions, comments)
- Guided repo installer that opens PRs against selected client dashboards
