@stipira/addon-sdk
v0.2.0
Published
Client SDK for Stipira addons — session, permissions, navigation, theming, and audit over the platform postMessage bus.
Downloads
225
Maintainers
Readme
@stipira/addon-sdk
Client SDK for Stipira addons — session, permissions, navigation, theming, and audit over the platform's postMessage bus. See ADR-017 in the Stipira repo for the design.
Install
pnpm add @stipira/addon-sdk
# or
npm install @stipira/addon-sdkUsage — inside an addon iframe
import { createAddonSdk } from "@stipira/addon-sdk";
const sdk = createAddonSdk({
parentOrigin: "https://t-abc123.stipira.com",
});
// Announce readiness (parent may reveal the iframe on this signal).
await sdk.ready();
// Session
const user = await sdk.session.getUser();
console.log(user.email, user.tenant_id, user.us_person);
// Permissions
if (await sdk.session.hasPermission("tranche.deal.approve")) {
// show approve button
}
// Navigation — asks the parent to update the browser URL
await sdk.nav.pushRoute("/deals/abc");
// Theme tokens — pull once at startup, apply as CSS variables
const theme = await sdk.theme.getTokens();
// Audit — every consequential action gets an event
await sdk.audit.emit("tranche.deal.approved", { deal_id: "abc" });
// On unmount
sdk.destroy();Event names in audit.emit() MUST match a value declared in the addon's manifest under audit.events[]. The parent enforces this against the admitted manifest.
Usage — parent app hosting an iframe
import { createAddonHost } from "@stipira/addon-sdk";
const host = createAddonHost({
iframe: iframeRef.current!,
addonOrigin: "https://tranche.addons.stipira.internal",
onGetUser: () => currentSession,
onHasPermission: (scope) => rbac.userHasPermission(scope),
onNavPushRoute: (path) => router.push(`/addons/tranche${path}`),
onGetThemeTokens: () => ({ "--primary": "#0f172a" }),
onAuditEmit: async ({ event, payload }) => {
// validate event is in the manifest's audit.events[] first
await platformAudit.log(event, payload);
},
onReady: () => setAddonReady(true),
});
// On unmount
useEffect(() => () => host.destroy(), [host]);Protocol
- Message envelope:
{ protocol_version: 1, id, type, payload } - Reply envelope:
{ reply_to: <id>, reply: { ok: true, data } | { ok: false, error } } - Origin is verified on every incoming message; mismatches are silently dropped and logged via
onWarn. - Unknown message types are silently dropped (not errors — the addon may have registered handlers for a future protocol version).
- Requests default to a 5-second timeout; override via
bus.timeoutMs.
Version drift between sender and receiver is a hard drop (with warning); the SDK's PROTOCOL_VERSION constant must match on both sides. Bumping the version requires shipping a new SDK release and having both parent + addon upgrade to it.
Security
- The addon iframe runs at its own admitted origin, isolated by the browser's same-origin policy.
- The parent's CSP
frame-srcallowlists only currently-installed addon origins for the current tenant. An uninstalled addon literally cannot render. - The session cookie (
stipira_session) isHttpOnly— the addon frontend cannot read it directly. The cookie reaches the addon's OWN backend automatically because both live under*.stipira.com; that backend calls/api/v1/session/validateto trust the identity. - Every audit event lands in
platform_audit_logwithsource_addon = <name>.
See ADR-017 for the full trade-off analysis (iframe vs. module federation).
