npm package: @outofscope/sdk-config
Description: Thin TypeScript client for platform-config-api
Latest version: 0.1.4

# @outofscope/sdk-config

TypeScript client for `platform-config-api`, published on npm as `@outofscope/sdk-config`. The package exposes a minimal HTTP client for public and administrative configuration and provides types for the platform's serialized data.

## Installation

```bash
npm install @outofscope/sdk-config
# or
pnpm add @outofscope/sdk-config
yarn add @outofscope/sdk-config
```

## Quick setup

The library automatically detects the base URL from the `PLATFORM_CONFIG_BASE_URL` environment variable or from `PLATFORM_STAGE` (`dev`, `uat`, `prod`). You can override it manually with the `baseUrl` option:

```ts
import { createConfigClient } from '@outofscope/sdk-config';

const client = createConfigClient({
  baseUrl: 'https://custom-gateway.example.com/config',
});
```

> If you do not provide `baseUrl`, the client uses `https://dev-api.outofscope.app/config`, `https://uat-api.outofscope.app/config`, or `https://api.outofscope.app/config` based on `PLATFORM_STAGE`.
>
> In browser/edge environments where `process` is not available, the client automatically relies on `PLATFORM_STAGE` and no longer throws a `ReferenceError` if you do not expose environment variables.

### IAM security headers

All requests to `platform-config-api` must include the IAM headers:

- `x-session-id` – session identifier (returned by `/iam/auth/login`)
- `x-app-key` – identifier for the authorized application
- `x-tenant-id` – current tenant, validated together with the session and application key

The client can send either static values (`sessionId`, `appKey`, `tenantId`) or values computed for each call (`getSessionId`, `getAppKey`, `getTenantId`). Values returned from callbacks take precedence.

```ts
import { createConfigClient } from '@outofscope/sdk-config';

const client = createConfigClient({
  baseUrl: 'https://dev-api.outofscope.app/config',
  sessionId: 'sess_123',
  appKey: 'app_456',
  tenantId: 'demo',
});

// or dynamically, for example when refreshing a token before every request
const dynamicClient = createConfigClient({
  baseUrl: 'https://dev-api.outofscope.app/config',
  getSessionId: async () => refreshSession(),
  getAppKey: () => process.env.APP_KEY,
  getTenantId: () => currentTenant(),
});
```
## Usage

### Public config (front-end or edge)

```ts
const client = createConfigClient();
const tenant = await client.public.getTenantByHost(window.location.hostname);
console.log(tenant.displayName, tenant.shopify.domain);
```

### Admin operations (backend)

```ts
const client = createConfigClient({
  baseUrl: 'https://dev-api.outofscope.app/config',
  sessionId: 'sess_123',
  appKey: 'app_456',
  tenantId: 'demo',
});

// List all tenants
const tenants = await client.admin.listTenants();

// Create or update a tenant
const tenant = await client.admin.updateTenant('demo', {
  tenantId: 'demo',
  displayName: 'Demo Storefront',
  shopify: { domain: 'demo.myshopify.com' },
});

// Update a tenant secret
await client.admin.updateTenantSecret('demo', 'storefrontToken', { value: '***' });
```

## Client surface

`createConfigClient` returns:

- `public.getTenantByHost(host?: string)` → `TenantPublicConfig`
- `admin.listTenants()` → `AdminTenantSummary[]`
- `admin.getTenant(tenantId)` → `AdminTenantConfig`
- `admin.updateTenant(tenantId, input)` → `AdminTenantConfig`
- `admin.patchTenant(tenantId, partialInput)` → `AdminTenantConfig`
- `admin.addTenantHost(tenantId, { host })` → `AdminHostsResponse`
- `admin.listTenantHosts(tenantId)` → `AdminHostsResponse`
- `admin.deleteTenantHost(tenantId, host)` → `AdminHostDeleteResponse`
- `admin.updateTenantSecret(tenantId, key, { value })` → `AdminSecretUpsertResponse`

## Error handling

Requests that fail (non-2xx status) throw `ConfigApiError`, exposing `status`, `statusText`, and `body` for debugging.

```ts
try {
  await client.admin.getTenant('missing');
} catch (err) {
  if (err instanceof ConfigApiError) {
    console.error(err.status, err.statusText, err.body);
  }
}
```

## Exported types

The package exports the types described in `src/types.ts` to avoid duplicating schemas (`TenantConfig`, `TenantPublicConfig`, `AdminHostsResponse`, etc.).

## Local development

```bash
npm install
npm test      # runs the Vitest suite
npm run lint  # type-checks the project
npm run build # generates the artifacts in the dist folder
```

> Node.js 18+ is required.