SeptemCore LogoSeptemCore
SDK Reference

@platform/sdk-core

sdk-core is the foundation of the Platform SDK. Provides the HTTP client (Fetch API with automatic retries), RFC 9457 error parsing into typed PlatformError, JWT access + refresh token management with BroadcastChannel cross-tab coordination (10s grace window), and request/response interceptors for logging, auth header injection, and tracing.

@platform/sdk-core is the foundational package of the Platform SDK. It is a transitive dependency of every other @platform/sdk-* package and is never installed directly in normal module development. You only interact with it when registering global interceptors or handling PlatformError objects.


Installation

# Installed automatically as a dependency of other SDK packages.
# Direct install only when working with interceptors or PlatformError:
pnpm add @platform/sdk-core

kernel.init()

import { kernel } from '@platform/sdk-core';

await kernel.init({
  apiUrl:      'https://api.septemcore.com/v1',  // Platform API base URL
  tenantId:    'YOUR_TENANT_ID',                 // ULID from tenant record
  moduleId:    '@scope/my-module',               // Must match module.manifest.json
  environment: 'production',                     // 'development' | 'staging' | 'production'
  logLevel:    'warn',                           // 'debug' | 'info' | 'warn' | 'error'
});
ParameterTypeRequiredDescription
apiUrlstringBase URL including version prefix (/v1)
tenantIdstringULID of the current tenant
moduleIdstringModule identifier — must match name in module.manifest.json
environmentstringAffects logging verbosity and telemetry tagging
logLevelstringDefault: warn

kernel.init() must resolve before any SDK method is called. Calling any method before initialization throws KernelNotInitializedError.


HTTP Client

The SDK uses the native Fetch API with the following defaults:

BehaviorValue
Base URLSet by kernel.init({ apiUrl })
Timeout30 seconds per request
Retry policy1 automatic retry with 100ms backoff for GET requests on network failure. POST/PATCH/DELETE — no automatic retry (use explicit idempotency keys).
Auth headerAuthorization: Bearer {accessToken} injected on every request
Content-Typeapplication/json (default). Overridden to multipart/form-data for file uploads.
Trace headerX-Request-ID: {uuid} auto-generated per request for correlation

Token Management

The SDK manages JWT access tokens and refresh tokens automatically. Module authors never handle tokens manually.

Token Lifecycle

User logs in (sdk-auth):
  → SDK receives { accessToken, refreshToken }
  → Stores in memory (accessToken) + localStorage (refreshToken)
  → Injects accessToken into every outgoing request

accessToken expires (default 15 min):
  → SDK detects 401 response
  → POST /auth/token/refresh { refreshToken }
  → Receives new { accessToken, refreshToken }
  → Retries original request with new accessToken
  → All other tabs notified via BroadcastChannel

Cross-Tab Coordination (BroadcastChannel)

Multiple browser tabs open to the same module may all detect a token expiry simultaneously and race to call /auth/token/refresh. The SDK prevents duplicate refresh calls:

Tab A: detects 401 → acquires "refresh lock" via BroadcastChannel
Tab B: detects 401 → sees lock held → waits for broadcast
Tab A: calls POST /auth/token/refresh → success
Tab A: broadcasts new accessToken to all tabs
Tab B: receives broadcast → updates local token → retries original request

Server-side protection (10-second grace window):
  Refresh token remains valid for 10 seconds after first use.
  If Tab A's broadcast fails and Tab B calls refresh independently
  within 10s → gets the same new token pair (idempotent).
  After 10s → token revoked → user must log in again.
ParameterValue
Cross-tab mechanismBroadcastChannel API (platform_auth_channel)
Server-side grace10 seconds after first refresh use (AUTH_REFRESH_GRACE_WINDOW_SEC)
In-flight deduplicationOnly one refresh call per tab group at a time

Error Handling (RFC 9457)

All platform API errors follow RFC 9457 — Problem Details for HTTP APIs. The SDK parses Content-Type: application/problem+json responses into typed PlatformError instances:

import { PlatformError } from '@platform/sdk-core';

try {
  const result = await kernel.data().query('contacts', { pageSize: 20 });
} catch (error) {
  if (error instanceof PlatformError) {
    // Typed RFC 9457 problem
    console.error(error.type);     // e.g. "https://api.septemcore.com/problems/not-found"
    console.error(error.title);    // e.g. "Not Found"
    console.error(error.status);   // e.g. 404
    console.error(error.detail);   // Human-readable detail
    console.error(error.instance); // e.g. "/api/v1/data/contacts"
    console.error(error.traceId);  // OpenTelemetry trace ID
    console.error(error.errors);   // Validation errors array (422 only)
  } else {
    // Raw network failure (no HTTP response)
    console.error('Network error:', error);
  }
}

Validation Errors

When the API returns 422 Unprocessable Entity, the errors[] array contains per-field details:

{
  "type":   "https://api.septemcore.com/problems/validation-error",
  "title":  "Validation Error",
  "status": 422,
  "errors": [
    { "field": "email",    "message": "Must be a valid email address" },
    { "field": "roleId",   "message": "Role not found" }
  ],
  "traceId": "01j9ptr0000000000000015"
}

The SDK exposes error.errors as Array<{ field: string; message: string }>.


Request Interceptors

Interceptors allow module authors to instrument every outgoing request and every incoming response globally — useful for logging, custom headers, and telemetry:

import { kernel } from '@platform/sdk-core';

// Request interceptor: runs before every outgoing HTTP call
kernel.http.interceptors.request.use((config) => {
  config.headers['X-Module-Version'] = '1.2.0';
  return config;
});

// Response interceptor: runs after every HTTP response
kernel.http.interceptors.response.use(
  (response) => {
    // Success path: log or transform
    console.debug(`${response.status} ${response.url}`);
    return response;
  },
  (error: PlatformError) => {
    // Error path: log, report, or rethrow
    if (error.status === 503) {
      myMonitoring.alert('Platform service unavailable', error.traceId);
    }
    throw error;
  }
);
Interceptor typeRuns onUse cases
requestBefore every HTTP callAdd custom headers, log request metadata
response (success)After 2xx responseTransform data, log latency
response (error)After non-2xx responseLog errors to monitoring, conditional rethrow

Interceptors are applied in registration order (FIFO for request, LIFO for response — matching standard Axios/Fetch interceptor semantics).


TypeScript Types

Core shared types exported from sdk-core:

// RFC 9457 error
interface PlatformError extends Error {
  type:     string;
  title:    string;
  status:   number;
  detail:   string;
  instance: string;
  traceId:  string;
  errors:   Array<{ field: string; message: string }>;
}

// All paginated responses (AIP-158)
interface PaginatedResponse<T> {
  data: T[];
  nextPageToken?: string;
}

These types are re-exported from every domain SDK so you never need to import from sdk-core directly for most use cases.

On this page