TypeScript SDK Reference
Complete API reference for the @coresdk/sdk package
Phase 2 — not yet available. The TypeScript SDK ships in Phase 2. The API documented below reflects the planned design.
TypeScript SDK Reference
Complete API reference for @coresdk/sdk. For a working example, see the TypeScript Quickstart.
npm install @coresdk/sdk
# or
pnpm add @coresdk/sdk
# Phase 2 — not yet publishedNode.js 18+ and TypeScript 5+ required.
new CoreSDK(options)
Creates and configures a CoreSDK instance. JWKS are fetched lazily on the first authenticated request.
Signature
new CoreSDK(options: CoreSDKOptions): CoreSDKCoreSDKOptions
interface CoreSDKOptions {
tenant: string;
jwksUrl: string;
policyDir?: string; // default: "./policies"
otelEndpoint?: string;
tokenHeader?: string; // default: "Authorization"
clockSkew?: number; // seconds, default: 30
errorMapper?: ErrorMapper;
}| Option | Type | Required | Description |
|---|---|---|---|
tenant | string | Yes | Tenant identifier for this service instance |
jwksUrl | string | Yes | URL of the JWKS endpoint used to verify JWTs |
policyDir | string | No | Directory of .rego policy files. Defaults to "./policies" |
otelEndpoint | string | No | OTLP gRPC endpoint for traces and metrics |
tokenHeader | string | No | HTTP header carrying the bearer token. Defaults to "Authorization" |
clockSkew | number | No | Acceptable JWT clock skew in seconds. Defaults to 30 |
errorMapper | ErrorMapper | No | Custom error response handler (see Error types) |
Example
import { CoreSDK } from "@coresdk/sdk";
const sdk = new CoreSDK({
tenant: "acme",
jwksUrl: "https://your-idp.com/.well-known/jwks.json",
policyDir: "./policies",
otelEndpoint: "http://localhost:4317",
});CoreSDKMiddleware
Returns an Express-compatible RequestHandler that authenticates every request, populates req.user and req.tenant, and emits OTEL spans.
Signature
middleware(): RequestHandlerReturns RequestHandler (compatible with Express 4/5 and Connect)
Usage
import express from "express";
import { CoreSDK } from "@coresdk/sdk";
const sdk = new CoreSDK({ tenant: "acme", jwksUrl: "..." });
const app = express();
app.use(CoreSDKMiddleware);
app.get("/api/orders", (req, res) => {
// req.user is CoreSDKUser, req.tenant is CoreSDKTenant
res.json({ userId: req.user.id });
});Unauthenticated requests receive 401. Policy-blocked requests receive 403. Both return RFC 9457 application/problem+json.
require_role(action)
Returns an Express middleware that enforces a policy action check. Apply it per-route after CoreSDKMiddleware.
Signature
require(action: string): RequestHandlerParameters
| Parameter | Type | Description |
|---|---|---|
action | string | Policy action string, e.g. "orders:read" |
Returns RequestHandler
Usage
app.get(
"/api/orders",
require_role("orders:read"),
async (req, res) => {
const orders = await db.orders.forUser(req.user.id);
res.json(orders);
}
);
app.post(
"/api/orders",
require_role("orders:write"),
async (req, res) => {
const order = await db.orders.create(req.body, req.user.id);
res.status(201).json(order);
}
);sdk.currentUser(req)
Retrieves the authenticated user from an Express request object. Returns null if no user was attached (i.e., middleware was not applied).
Signature
currentUser(req: Request): CoreSDKUser | nullReturns CoreSDKUser | null
import { Request } from "express";
function auditAction(req: Request, action: string) {
const user = sdk.currentUser(req);
if (!user) throw new Error("unauthenticated");
auditLog.write({ userId: user.id, tenantId: user.tenantId, action });
}Fastify plugin
import Fastify from "fastify";
import { coreSDKPlugin } from "@coresdk/sdk/fastify";
const fastify = Fastify();
await fastify.register(coreSDKPlugin, {
tenant: "acme",
jwksUrl: "https://your-idp.com/.well-known/jwks.json",
});
fastify.get("/api/orders", {
preHandler: fastify.corerequire_role("orders:read"),
handler: async (request) => {
// request.user is CoreSDKUser
return db.orders.forUser(request.user.id);
},
});The plugin decorates the Fastify instance with fastify.coresdk and each request with request.user and request.tenant.
Next.js App Router
// app/api/orders/route.ts
import { withCoreSDK } from "@coresdk/sdk/next";
export const GET = withCoreSDK(
{ action: "orders:read" },
async (req, { user, tenant }) => {
const orders = await db.orders.forUser(user.id);
return Response.json(orders);
}
);
export const POST = withCoreSDK(
{ action: "orders:write" },
async (req, { user }) => {
const body = await req.json();
const order = await db.orders.create(body, user.id);
return Response.json(order, { status: 201 });
}
);withCoreSDK options
| Option | Type | Description |
|---|---|---|
action | string | Policy action to require. Omit to authenticate only, without an action check |
sdk.policy().evaluate(rule, input)
Evaluates an OPA policy rule directly, outside the middleware path.
Signature
evaluate(rule: string, input: Record<string, unknown>): Promise<PolicyResult>Parameters
| Parameter | Type | Description |
|---|---|---|
rule | string | Dot-separated Rego rule path, e.g. "data.billing.can_upgrade" |
input | Record<string, unknown> | Input document passed to the policy engine |
Returns Promise<PolicyResult>
interface PolicyResult {
allowed: boolean;
reason?: string;
}Usage
const result = await sdk.policy().evaluate("data.billing.can_upgrade", {
user: req.user,
targetPlan: "enterprise",
});
if (!result.allowed) {
res.status(403).json({ error: result.reason ?? "Upgrade not permitted" });
return;
}Tenant management
All tenant methods return Promise<T>.
sdk.tenants.get(id)
get(id: string): Promise<CoreSDKTenant>const tenant = await sdk.tenants.get("acme");
console.log(tenant.plan);sdk.tenants.create(options)
create(options: CreateTenantOptions): Promise<CoreSDKTenant>
interface CreateTenantOptions {
id: string;
name: string;
plan?: TenantPlan; // defaults to "free"
metadata?: Record<string, unknown>;
}const tenant = await sdk.tenants.create({
id: "newcorp",
name: "New Corp",
plan: "business",
});sdk.tenants.update(id, options)
update(id: string, options: UpdateTenantOptions): Promise<CoreSDKTenant>
interface UpdateTenantOptions {
name?: string;
plan?: TenantPlan;
metadata?: Record<string, unknown>;
}const tenant = await sdk.tenants.update("newcorp", { plan: "enterprise" });sdk.tenants.delete(id)
delete(id: string): Promise<void>await sdk.tenants.delete("oldcorp");sdk.tenants.list()
list(): Promise<CoreSDKTenant[]>const tenants = await sdk.tenants.list();
tenants.forEach(t => console.log(t.id, t.plan));TypeScript types
All types are exported from @coresdk/sdk.
import type {
CoreSDKUser,
CoreSDKTenant,
TenantPlan,
PolicyResult,
CoreSDKOptions,
CreateTenantOptions,
UpdateTenantOptions,
ErrorMapper,
} from "@coresdk/sdk";CoreSDKUser
interface CoreSDKUser {
id: string; // JWT sub claim
email: string; // JWT email claim
role: string; // Mapped role for this tenant
tenantId: string; // Tenant the user belongs to
rawClaims: Record<string, unknown>; // Full decoded JWT claims
}CoreSDKTenant
interface CoreSDKTenant {
id: string;
name: string;
plan: TenantPlan;
metadata: Record<string, unknown>;
}
type TenantPlan = "free" | "team" | "business" | "enterprise";Express augmentation
@coresdk/sdk ships global augmentations for Express so req.user and req.tenant are typed automatically — no import needed in handler files.
// Automatically available when @coresdk/sdk is installed:
declare global {
namespace Express {
interface Request {
user: CoreSDKUser;
tenant: CoreSDKTenant;
}
}
}Error types
All SDK methods throw subclasses of CoreSDKError.
import {
CoreSDKError,
TokenExpiredError,
TokenInvalidError,
PolicyDeniedError,
TenantNotFoundError,
JwksFetchError,
ConfigurationError,
} from "@coresdk/sdk/errors";| Class | Properties | Description |
|---|---|---|
TokenExpiredError | expiredAt: Date | JWT exp claim is in the past |
TokenInvalidError | reason: string | Bad signature, malformed JWT, or missing required claims |
PolicyDeniedError | action: string, reason?: string | OPA policy returned false |
TenantNotFoundError | tenantId: string | Tenant lookup returned no record |
JwksFetchError | url: string, cause: unknown | Network or parse failure fetching JWKS |
ConfigurationError | message: string | Missing required option or invalid value |
Handling errors
import { PolicyDeniedError, TokenExpiredError } from "@coresdk/sdk/errors";
try {
const user = sdk.currentUser(req);
} catch (err) {
if (err instanceof TokenExpiredError) {
console.log("Expired at", err.expiredAt);
} else if (err instanceof PolicyDeniedError) {
console.log(`Denied: ${err.action} — ${err.reason}`);
}
}Custom ErrorMapper
import { ErrorMapper, CoreSDKError, PolicyDeniedError } from "@coresdk/sdk/errors";
import { Response } from "express";
class MyMapper implements ErrorMapper {
map(err: CoreSDKError, res: Response): void {
if (err instanceof PolicyDeniedError) {
res.status(403).json({
type: "https://errors.acme.com/forbidden",
title: "Action not permitted",
detail: `'${err.action}' is not allowed`,
});
} else {
this.default(err, res);
}
}
}
const sdk = new CoreSDK({
tenant: "acme",
jwksUrl: "https://your-idp.com/.well-known/jwks.json",
errorMapper: new MyMapper(),
});