SDKs & clients
The two SDK families — app SDKs for building, client SDKs for consuming — the five gates in every language, and the package & version reference.
Two SDK families
The platform ships two kinds of SDK, and picking the right one is the first decision.
App SDKs are for building a platform-native app — a service that mounts tiered routers, resolves tenant context, applies access gates, and emits events through the outbox. There are two — a Python backend runtime (egav-app-sdk) and a TypeScript SDK (@egav/app-sdk) for React frontends — plus the shared Python platform clients you compose alongside them. All of that lives on the App SDKs page.
Client SDKs are for consuming the platform from an existing program in any language — headless OIDC login, an authenticated retrying JSON client that decodes the standard BaseResponse envelope, and the five access gates ported natively. There are four, each with its own page: Go, Rust, PHP, and Node. They deliberately omit the app-building runtime (no app factory, tenant middleware, outbox, or scoped CRUD) — that lives in the app SDKs.
| Family | SDK | Use it to | Page |
|---|---|---|---|
| App runtime | egav-app-sdk (Python) | Build a backend app: tier routers, gates, outbox, scoped CRUD | App SDKs |
| App SDK | @egav/app-sdk (TypeScript) | Build a React app: manifest parsing, tenant context, feature gates, field widgets, ApiClient | App SDKs |
| Shared clients | egav-authz-client, egav-cp-client, … | Compose auth, config, audit and notifications into a Python app | App SDKs |
| Client | github.com/djokodonev/egav-sdk-go | Call the platform from Go | Go |
| Client | crate egav-sdk | Call the platform from Rust | Rust |
| Client | egav/sdk | Call the platform from PHP | PHP |
| Client | @egav/sdk | Call the platform from Node | Node |
The distinction is stated in the client SDKs themselves — for example, the Go SDK's README notes the app-building runtime "lives in the Python (egav-app-sdk) and TypeScript (@egav/app-sdk) app SDKs. This package is for programs that consume the platform from Go."
The five gates, in any language
Every client SDK ships the same five access gates, applied in the same order to protect an endpoint:
- auth — validate the inbound end-user bearer, returning the resolved identity.
- permission — AuthZ confirms the user may perform the action.
- subscription-active — the org's subscription is active.
- feature — the org's plan enables the feature.
- quota — the org is under its plan limit for the metric.
Two credentials, correct trust model — no shortcut: the end-user bearer is used only for gate 1; the app's service x-api-key is used for gates 2–5 (the /internal/* endpoints are service-to-service). Every gate fails closed — an unreachable Control Plane or AuthZ raises 503 rather than default-allowing. The Auth & the five gates page covers the request-time model in depth.
The method surface is the same shape in every language; each client page shows the exact signatures:
| Gate | Go | Rust / PHP | Failed-gate status |
|---|---|---|---|
| auth | Authenticate | authenticate | 401 |
| permission | RequirePermission | require_permission / requirePermission | 403 |
| subscription | RequireActiveSubscription | require_active_subscription / requireActiveSubscription | 402 |
| feature | RequireFeature | require_feature / requireFeature | 403 |
| quota | EnforceQuota | enforce_quota / enforceQuota | 429 |
Any unreachable dependency (Control Plane, AuthZ) is 503 on every gate — refused, never degraded to allow.
Inside a Python backend app the same contract is composed from FastAPI dependencies — RequireAuthz from egav_authz_client (which authenticates the portal bearer and checks the permission in one dependency) plus require_active_subscription / require_feature / require_quota from egav_cp_client.feature_gates (see App SDKs):
from fastapi import APIRouter, Depends, Request
from egav_authz_client import RequireAuthz
from egav_cp_client.feature_gates import (
require_active_subscription, require_feature, require_quota,
)
router = APIRouter()
async def project_count(request: Request) -> int:
return await count_projects(request.state.identity.org_guid)
@router.post(
"/v1/my-saas/portal/projects",
dependencies=[
Depends(RequireAuthz("project", "create")), # auth + permission -> 401/403
Depends(require_active_subscription), # subscription -> 402
Depends(require_feature("projects")), # feature -> 403
Depends(require_quota("max_projects", current_usage=project_count)), # quota -> 429
],
)
async def create_project(payload: ProjectCreate):
return await save_project(payload)Package & version reference
Every identifier below is taken from the SDK's own manifest (pyproject.toml, package.json, go.mod, Cargo.toml, composer.json). Use these exact names; nothing here is aspirational.
| SDK | Package / module | Import | Version | Distribution |
|---|---|---|---|---|
| Python app runtime | egav-app-sdk | import egav_app_sdk | 0.2.0 | GitHub tarball or local pip install -e (not on PyPI) |
| TypeScript app SDK | @djokodonev/egav-app-sdk (alias @egav/app-sdk) | from '@egav/app-sdk' | 0.31.0 | GitHub Packages (npm.pkg.github.com), restricted |
| Go client | github.com/djokodonev/egav-sdk-go | import egavsdk "github.com/djokodonev/egav-sdk-go" | v0.1.0 | public GitHub repository, tagged; go get resolves through the module proxy |
| Rust client | crate egav-sdk (lib egav_sdk) | use egav_sdk::... | 0.1.0 | path dependency; crates.io publish pending |
| PHP client | egav/sdk (Egav\Sdk\) | use Egav\Sdk\... | 0.1.0 | Composer path repository; Packagist publish pending |
| Node client | @djokodonev/egav-sdk (alias @egav/sdk) | from '@egav/sdk' | 0.1.0 | GitHub Packages (npm.pkg.github.com), restricted |
A note on honesty. The Node client is published to GitHub Packages and installs from there with a read:packages token — a restricted registry, so a bare npm install from the public index still will not find it. The Go client is public and tagged (v0.1.0), so go get works with no extra setup. The Rust and PHP clients remain pre-publication: their import paths are stable, but no registry install is live yet, so they wire in via path / Composer-path steps. When those are tagged and published, this table gets version dependencies and those steps drop away — the import lines in your code will not change. The per-language pages (Go, Rust, PHP, Node) carry the full install + worked example for each.