sjursen-digital-watchtower
Version:
A TypeScript Node.js SDK for Watchtower, an Intelligence as a Service (IaaS) platform that uses Google's Gemini AI model to transform traditional logging into an active intelligence system with predictive analytics and automated decision-making capabiliti
971 lines (743 loc) • 21.9 kB
Markdown
# Watchtower Node.js SDK Documentation
## Introduction
The Watchtower Node.js SDK provides a convenient way to interact with the Watchtower API for logging, metrics, analysis, and more. This SDK is designed to be used in Node.js environments.
## Installation
To install the SDK, run the following command in your project directory:
```bash
npm install sjursen-digital-watchtower
```
## Initialization
Import and initialize the SDK with your API base URL:
```typescript
import { WatchtowerSDK } from 'sjursen-digital-watchtower';
const sdk = new WatchtowerSDK('YOUR_API_BASE_URL');
```
Replace `YOUR_API_BASE_URL` with the actual base URL of the Watchtower API.
## Endpoints
The SDK organizes API endpoints into logical categories:
### 1. Health Endpoint
Check the health of the API.
#### `health.check()`
`GET /api/health`
Checks if the API is reachable and operational.
```typescript
async check(): Promise<any>
```
**Example:**
```typescript
try {
const healthStatus = await sdk.health.check();
console.log('API Health Status:', healthStatus);
} catch (error) {
console.error('Failed to check API health:', error);
}
```
### 2. API Key Endpoints
Manage API keys for organizations, apps, and tenants.
#### `apikey.createOrganization(data)`
`POST /api/apikey/org`
Creates a new organization and returns the API key.
```typescript
async createOrganization(data: CreateOrganizationRequest): Promise<APIKey>
```
**Request Interface (`CreateOrganizationRequest`):**
```typescript
interface CreateOrganizationRequest {
// ... organization details ...
}
```
**Response Interface (`APIKey`):**
```typescript
interface APIKey {
organization_apikey: string;
}
```
**Example:**
```typescript
try {
const apiKey = await sdk.apikey.createOrganization({
// organization details
});
console.log('New Organization API Key:', apiKey.organization_apikey);
} catch (error) {
console.error('Failed to create organization:', error);
}
```
#### `apikey.createApp(data)`
`POST /api/apikey/app`
Creates a new app and returns the app API key.
```typescript
async createApp(data: CreateAppRequest): Promise<AppAPIKey>
```
**Request Interface (`CreateAppRequest`):**
```typescript
interface CreateAppRequest {
organization_apikey: string;
// ... app details ...
}
```
**Response Interface (`AppAPIKey`):**
```typescript
interface AppAPIKey {
app_apikey: string;
}
```
**Example:**
```typescript
try {
const appApiKey = await sdk.apikey.createApp({
organization_apikey: 'YOUR_ORG_API_KEY',
// app details
});
console.log('New App API Key:', appApiKey.app_apikey);
} catch (error) {
console.error('Failed to create app:', error);
}
```
#### `apikey.createTenant(data)`
`POST /api/apikey/tenant`
Creates a new tenant and returns the tenant API key.
```typescript
async createTenant(data: CreateTenantRequest): Promise<TenantAPIKey>
```
**Request Interface (`CreateTenantRequest`):**
```typescript
interface CreateTenantRequest {
organization_apikey: string;
app_apikey: string;
// ... tenant details ...
}
```
**Response Interface (`TenantAPIKey`):**
```typescript
interface TenantAPIKey {
tenant_apikey: string;
}
```
**Example:**
```typescript
try {
const tenantApiKey = await sdk.apikey.createTenant({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
// tenant details
});
console.log('New Tenant API Key:', tenantApiKey.tenant_apikey);
} catch (error) {
console.error('Failed to create tenant:', error);
}
```
#### `apikey.rollAPIKey(data)`
`POST /api/apikey/roll`
Rolls (rotates) an existing API key.
```typescript
async rollAPIKey(data: RollAPIKeyRequest): Promise<RolledAPIKey>
```
**Request Interface (`RollAPIKeyRequest`):**
```typescript
interface RollAPIKeyRequest {
organization_apikey: string;
// ... key details to roll ...
}
```
**Response Interface (`RolledAPIKey`):**
```typescript
interface RolledAPIKey {
// ... new key details ...
}
```
**Example:**
```typescript
try {
const rolledKey = await sdk.apikey.rollAPIKey({
organization_apikey: 'YOUR_ORG_API_KEY',
// key details to roll
});
console.log('Rolled API Key:', rolledKey);
} catch (error) {
console.error('Failed to roll API key:', error);
}
```
### JWT-based API Key Endpoints
These endpoints allow you to create API keys using a Supabase JWT token for authentication. Use these if you want to manage API keys with user-level permissions and JWT-based auth.
#### `apikey.createOrgKey(organizationId, jwtToken)`
`POST /api/apikey/org/jwt`
Creates a new API key for an existing organization using a Supabase JWT token.
```typescript
async createOrgKey(organizationId: string, jwtToken: string): Promise<APIKeyResponse>
```
**Parameters:**
- `organizationId` (string): The ID of the existing organization
- `jwtToken` (string): A valid Supabase JWT token (must be included in the Authorization header)
**Returns:**
- `Promise<APIKeyResponse>`
**Example:**
```typescript
const apiKey = await sdk.apikey.createOrgKey('org_123', 'your_jwt_token');
console.log('New Org API Key:', apiKey.key);
```
#### `apikey.createAppKey(appName, tenancyModel, jwtToken)`
`POST /api/apikey/app/jwt`
Creates a new API key for an app in the user's organization using a Supabase JWT token.
```typescript
async createAppKey(appName: string, tenancyModel: 'single' | 'multi', jwtToken: string): Promise<APIKeyResponse>
```
**Parameters:**
- `appName` (string): Name of the app
- `tenancyModel` ('single' | 'multi'): App's tenancy model
- `jwtToken` (string): A valid Supabase JWT token (must be included in the Authorization header)
**Returns:**
- `Promise<APIKeyResponse>`
**Example:**
```typescript
const apiKey = await sdk.apikey.createAppKey('My App', 'multi', 'your_jwt_token');
console.log('New App API Key:', apiKey.key);
```
**Notes:**
- JWT tokens must be obtained from Supabase Auth and included as `Bearer <token>` in the Authorization header.
- These endpoints require the user to have appropriate permissions (e.g., 'admin' or 'owner' role).
- API keys are only returned once upon creation. Store them securely.
- All timestamps are in UTC (ISO 8601 format).
**Error Handling:**
- `400 Bad Request`: Missing required fields or invalid request
- `401 Unauthorized`: Missing or invalid JWT token
- `403 Forbidden`: Insufficient permissions
- `404 Not Found`: Organization not found
- `500 Internal Server Error`: Server/database error
### 3. Logs Endpoints
Manage log entries.
#### `logs.createLog(data)`
`POST /api/logs`
Creates a new log entry.
```typescript
async createLog(data: CreateLogRequest): Promise<void>
```
**Request Interface (`CreateLogRequest`):**
```typescript
interface CreateLogRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id: string;
timestamp: string; // ISO 8601
level: string;
message: string;
context?: Record<string, any>;
metadata?: Record<string, any>;
}
```
**Example:**
```typescript
try {
await sdk.logs.createLog({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
item_id: 'item123',
timestamp: new Date().toISOString(),
level: 'info',
message: 'User logged in',
context: { userId: 'user456' },
});
console.log('Log created successfully');
} catch (error) {
console.error('Failed to create log:', error);
}
```
#### `logs.getLogs(data)`
`GET /api/logs`
Retrieves log entries with filtering options.
```typescript
async getLogs(data: GetLogsRequest): Promise<GetLogsResponse>
```
**Request Interface (`GetLogsRequest`):**
```typescript
interface GetLogsRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id?: string;
level?: string;
after?: string; // ISO 8601
before?: string; // ISO 8601
limit?: number;
offset?: number;
}
```
**Response Interface (`GetLogsResponse`):**
```typescript
interface GetLogsResponse {
logs: Array<{
// log entry details
}>;
}
```
**Example:**
```typescript
try {
const logs = await sdk.logs.getLogs({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
item_id: 'item123',
level: 'error',
after: '2023-10-26T10:00:00Z',
});
console.log('Retrieved Logs:', logs);
} catch (error) {
console.error('Failed to get logs:', error);
}
```
### 4. Metrics Endpoints
Retrieve metadata for apps and tenants.
#### `metrics.getAppMetadata(data)`
`GET /api/metrics/app`
Gets metadata for a specific app.
```typescript
async getAppMetadata(data: GetAppMetadataRequest): Promise<GetAppMetadataResponse>
```
**Request Interface (`GetAppMetadataRequest`):**
```typescript
interface GetAppMetadataRequest {
organization_apikey: string;
app_apikey: string;
}
```
**Response Interface (`GetAppMetadataResponse`):**
```typescript
interface GetAppMetadataResponse {
id: string;
app_id: string;
tenant_count: number;
created_at: string;
updated_at: string;
}
```
**Example:**
```typescript
try {
const appMetadata = await sdk.metrics.getAppMetadata({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
});
console.log('App Metadata:', appMetadata);
} catch (error) {
console.error('Failed to get app metadata:', error);
}
```
#### `metrics.getTenantMetadata(data)`
`GET /api/metrics/tenant`
Gets metadata for a specific tenant.
```typescript
async getTenantMetadata(data: GetTenantMetadataRequest): Promise<GetTenantMetadataResponse>
```
**Request Interface (`GetTenantMetadataRequest`):**
```typescript
interface GetTenantMetadataRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey: string;
}
```
**Response Interface (`GetTenantMetadataResponse`):**
```typescript
interface GetTenantMetadataResponse {
id: string;
app_id: string;
tenant_id: string;
log_count: number;
created_at: string;
updated_at: string;
}
```
**Example:**
```typescript
try {
const tenantMetadata = await sdk.metrics.getTenantMetadata({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
tenant_apikey: 'YOUR_TENANT_API_KEY',
});
console.log('Tenant Metadata:', tenantMetadata);
} catch (error) {
console.error('Failed to get tenant metadata:', error);
}
```
### 5. Items Endpoints
List items associated with an app or tenant.
#### `items.listItems(data)`
`GET /api/items`
Lists items for a given app or tenant.
```typescript
async listItems(data: ListItemsRequest): Promise<ListItemsResponse>
```
**Request Interface (`ListItemsRequest`):**
```typescript
interface ListItemsRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
}
```
**Response Interface (`ListItemsResponse`):**
```typescript
interface ListItemsResponse {
items: Array<{
item_id: string;
friendly_name?: string;
last_seen: string; // ISO 8601
}>;
}
```
**Example:**
```typescript
try {
const items = await sdk.items.listItems({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
tenant_apikey: 'YOUR_TENANT_API_KEY', // Optional
});
console.log('Items:', items.items);
} catch (error) {
console.error('Failed to list items:', error);
}
```
### 6. Intelligence Endpoints
Get predictions and decisions based on data.
#### `intelligence.getPredictConfig()`
`GET /api/intelligence/predict/config`
Gets the configuration for predictions, including available types and timeframes.
```typescript
async getPredictConfig(): Promise<PredictConfigResponse>
```
**Response Interface (`PredictConfigResponse`):**
```typescript
interface PredictConfigResponse {
prediction_types: Array<{ type: string; description: string; use_cases: string[]; example: string }>;
timeframes: Array<{ value: string; description: string; use_cases: string }>;
example_request: PredictRequest;
example_response: PredictResponse;
}
```
**Example:**
```typescript
try {
const config = await sdk.intelligence.getPredictConfig();
console.log('Prediction Config:', config);
} catch (error) {
console.error('Failed to get prediction config:', error);
}
```
#### `intelligence.predict(data)`
`POST /api/intelligence/predict`
Gets a prediction for a specific item based on the provided parameters.
```typescript
async predict(data: PredictRequest): Promise<PredictResponse>
```
**Request Interface (`PredictRequest`):**
```typescript
interface PredictRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id: string;
prediction_type: 'trend' | 'anomaly' | 'failure';
timeframe: '1h' | '24h' | '7d' | '30d';
}
```
**Response Interface (`PredictResponse`):**
```typescript
interface PredictResponse {
timestamp: string; // ISO 8601
item_id: string;
prediction: string;
confidence: number;
explanation: string;
timeframe: string;
recommendations: string[];
}
```
**Example:**
```typescript
try {
const prediction = await sdk.intelligence.predict({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
item_id: 'item123',
prediction_type: 'anomaly',
timeframe: '24h',
});
console.log('Prediction Result:', prediction);
} catch (error) {
console.error('Failed to get prediction:', error);
}
```
#### `intelligence.decide(data)`
`POST /api/intelligence/decide`
Gets a decision based on log data.
```typescript
async decide(data: DecideRequest): Promise<DecideResponse>
```
**Request Interface (`DecideRequest`):**
```typescript
interface DecideRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
log_data: {
metrics: Array<{ name: string; friendly_name?: string; value: any; unit?: string }>;
context: string;
item_name: string;
};
allowed_actions: Record<string, string>;
}
```
**Response Interface (`DecideResponse`):**
```typescript
interface DecideResponse {
timestamp: string; // ISO 8601
decision: string;
reason: string;
confidence: number;
message?: string;
}
```
**Example:**
```typescript
try {
const decision = await sdk.intelligence.decide({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
log_data: {
metrics: [{ name: 'cpu_usage', value: 90 }],
context: 'high_load',
item_name: 'server1',
},
allowed_actions: { restart: 'Restart the server' },
});
console.log('Decision Result:', decision);
} catch (error) {
console.error('Failed to get decision:', error);
}
```
### 7. Analyze Endpoints
Perform analysis on logs and get current status.
#### `analyze.getLatest(data)`
`GET /api/analyze/latest`
Gets the latest analysis for a specific item.
```typescript
async getLatest(data: GetLatestRequest): Promise<AnalysisResult>
```
**Request Interface (`GetLatestRequest`):**
```typescript
interface GetLatestRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id: string;
}
```
**Response Interface (`AnalysisResult`):**
```typescript
interface AnalysisResult {
summary: { /* ... */ };
metrics: Record<string, { /* ... */ }>;
time_series: Array<{ /* ... */ }>;
ai_analysis?: { /* ... */ };
}
```
*(See `src/endpoints/analyze/types.ts` for full `AnalysisResult` interface details)*
**Example:**
```typescript
try {
const latestAnalysis = await sdk.analyze.getLatest({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
item_id: 'item123',
});
console.log('Latest Analysis:', latestAnalysis);
} catch (error) {
console.error('Failed to get latest analysis:', error);
}
```
#### `analyze.analyzeLogs(data)`
`GET /api/analyze`
Analyzes logs for an item within a specified time range.
```typescript
async analyzeLogs(data: AnalyzeLogsRequest): Promise<AnalysisResult>
```
**Request Interface (`AnalyzeLogsRequest`):**
```typescript
interface AnalyzeLogsRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id: string;
after?: string; // ISO 8601
before?: string; // ISO 8601
}
```
**Response Interface (`AnalysisResult`):**
```typescript
interface AnalysisResult {
summary: { /* ... */ };
metrics: Record<string, { /* ... */ }>;
time_series: Array<{ /* ... */ }>;
ai_analysis?: { /* ... */ };
}
```
*(See `src/endpoints/analyze/types.ts` for full `AnalysisResult` interface details)*
**Example:**
```typescript
try {
const analysis = await sdk.analyze.analyzeLogs({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
item_id: 'item123',
after: '2023-10-01T00:00:00Z',
before: '2023-10-31T23:59:59Z',
});
console.log('Log Analysis:', analysis);
} catch (error) {
console.error('Failed to analyze logs:', error);
}
```
#### `analyze.analyzeCurrent(data)`
`GET /api/analyze/current`
Gets the current analysis status for a specific item.
```typescript
async analyzeCurrent(data: AnalyzeCurrentRequest): Promise<AnalyzeCurrentResponse>
```
**Request Interface (`AnalyzeCurrentRequest`):**
```typescript
interface AnalyzeCurrentRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id: string;
}
```
**Response Interface (`AnalyzeCurrentResponse`):**
```typescript
interface AnalyzeCurrentResponse {
timestamp: string; // ISO 8601
overview: string;
status: 'normal' | 'warning' | 'critical';
description: string;
metrics: Record<string, { /* ... */ }>;
recommendations: Array<{ /* ... */ }>;
}
```
**Example:**
```typescript
try {
const currentAnalysis = await sdk.analyze.analyzeCurrent({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
item_id: 'item123',
});
console.log('Current Analysis:', currentAnalysis);
} catch (error) {
console.error('Failed to get current analysis:', error);
}
```
### 8. App Endpoints
Manage and retrieve the status of an app.
#### `app.updateStatus(data)`
`POST /api/app/status`
Updates the status of an app.
```typescript
async updateStatus(data: AppStatusRequest): Promise<AppStatusOverview>
```
**Request Interface (`AppStatusRequest`):**
```typescript
interface AppStatusRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
// ... status details ...
}
```
**Response Interface (`AppStatusOverview`):**
```typescript
interface AppStatusOverview {
timestamp: string; // ISO 8601
overview: string;
status: 'normal' | 'warning' | 'critical';
item_statuses: Array<{ /* ... */ }>;
recommendations: Array<{ /* ... */ }>;
}
```
**Example:**
```typescript
try {
const updatedStatus = await sdk.app.updateStatus({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
// status details
});
console.log('Updated App Status:', updatedStatus);
} catch (error) {
console.error('Failed to update app status:', error);
}
```
#### `app.getLatestStatus(data)`
`GET /api/app/status/latest`
Gets the latest status overview for an app.
```typescript
async getLatestStatus(data: GetLatestAppStatusRequest): Promise<AppStatusOverview>
```
**Request Interface (`GetLatestAppStatusRequest`):**
```typescript
interface GetLatestAppStatusRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
}
```
**Response Interface (`AppStatusOverview`):**
```typescript
interface AppStatusOverview {
timestamp: string; // ISO 8601
overview: string;
status: 'normal' | 'warning' | 'critical';
item_statuses: Array<{ /* ... */ }>;
recommendations: Array<{ /* ... */ }>;
}
```
**Example:**
```typescript
try {
const latestStatus = await sdk.app.getLatestStatus({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
});
console.log('Latest App Status:', latestStatus);
} catch (error) {
console.error('Failed to get latest app status:', error);
}
```
## Error Handling
The SDK throws custom error types for different API responses:
- `InvalidRequestError`: For missing or invalid request parameters (status 400).
- `AuthenticationError`: For invalid API keys (status 401).
- `ServerError`: For internal server errors (status 500).
You can catch these errors to handle specific API responses:
```typescript
import { InvalidRequestError, AuthenticationError, ServerError } from 'sjursen-digital-watchtower/errors';
try {
// SDK call
} catch (error) {
if (error instanceof InvalidRequestError) {
console.error('Invalid Request:', error.message);
} else if (error instanceof AuthenticationError) {
console.error('Authentication Failed:', error.message);
} else if (error instanceof ServerError) {
console.error('Server Error:', error.message);
} else {
console.error('An unexpected error occurred:', error);
}
}
```
## Contributing
[Add contributing guidelines here]
## License
[Add license information here]