watchtower-node-sdk
Version:
A TypeScript Node.js SDK for the Watchtower API, providing API key management, connection string generation, and more
1,028 lines (826 loc) • 24.8 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 watchtower-node-sdk
```
## Initialization
Import and initialize the SDK:
```typescript
import { WatchtowerSDK } from 'watchtower-node-sdk';
const sdk = new WatchtowerSDK();
```
## 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.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 {
current_apikey: string;
type: 'organization' | 'app' | 'tenant';
}
```
**Response Interface (`RolledAPIKey`):**
```typescript
interface RolledAPIKey {
key: string; // Format depends on type: wt_ORG_, wt_APP_, or wt_TNT_
type: 'organization' | 'app' | 'tenant';
organization_id: string;
app_id?: string; // Optional, only for app and tenant keys
tenant_id?: string; // Optional, only for tenant keys
name: string;
status: 'active';
created_at: string; // ISO 8601 timestamp
updated_at: string; // ISO 8601 timestamp
}
```
**Example:**
```typescript
try {
const rolledKey = await sdk.apikey.rollAPIKey({
current_apikey: 'YOUR_CURRENT_KEY',
type: 'organization'
});
console.log('Rolled API Key:', rolledKey);
} catch (error) {
console.error('Failed to roll API key:', error);
}
```
### 3. Connection String Endpoints
Generate and parse encrypted connection strings.
#### `connectionstring.generateConnectionString(data)`
`POST /api/connectionstring`
Creates an encrypted connection string from API keys.
```typescript
async generateConnectionString(data: ConnectionStringRequest): Promise<ConnectionStringResponse>
```
**Request Interface (`ConnectionStringRequest`):**
```typescript
interface ConnectionStringRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string; // Optional: For tenant-specific access
expires_in?: number; // Optional: Duration in seconds, 0 means no expiration
}
```
**Response Interface (`ConnectionStringResponse`):**
```typescript
interface ConnectionStringResponse {
connection_string: string; // The generated encrypted connection string
expires_at?: number; // Optional: Unix timestamp when the connection string expires
}
```
**Example:**
```typescript
try {
const connectionString = await sdk.connectionstring.generateConnectionString({
organization_apikey: 'YOUR_ORG_KEY',
app_apikey: 'YOUR_APP_KEY',
tenant_apikey: 'YOUR_TENANT_KEY', // optional
expires_in: 3600 // optional: 1 hour expiration
});
console.log('Generated Connection String:', connectionString);
} catch (error) {
console.error('Failed to generate connection string:', error);
}
```
#### `connectionstring.parseConnectionString(connectionString)`
`GET /api/connectionstring/parse`
Decrypts and parses a connection string to extract API keys.
```typescript
async parseConnectionString(connectionString: string): Promise<ParsedConnectionString>
```
**Response Interface (`ParsedConnectionString`):**
```typescript
interface ParsedConnectionString {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string; // Optional: Only present if included in original string
is_valid: boolean; // Indicates if the connection string is currently valid
app_name?: string; // Optional: Name of the app associated with the app_apikey
expires_at?: number; // Optional: Unix timestamp when the string expires
}
```
**Example:**
```typescript
try {
const parsedString = await sdk.connectionstring.parseConnectionString(
'YOUR_CONNECTION_STRING'
);
console.log('Parsed Connection String:', parsedString);
} catch (error) {
console.error('Failed to parse connection string:', error);
}
```
### 4. App Status 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; // Optional, required for multi-tenant apps
}
```
**Response Interface (`AppStatusOverview`):**
```typescript
interface AppStatusOverview {
timestamp: string; // ISO 8601 timestamp
overview: string;
status: 'normal' | 'warning' | 'critical';
item_statuses: Array<{
item_id: string;
friendly_name: string;
status_summary: string;
}>;
recommendations: Array<{
priority: string;
title: string;
description: string;
action: string;
}>;
}
```
**Example:**
```typescript
try {
const updatedStatus = await sdk.app.updateStatus({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
tenant_apikey: 'YOUR_TENANT_API_KEY' // Optional, for multi-tenant apps
});
console.log('Updated App Status:', updatedStatus);
} 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('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; // Optional, required for multi-tenant apps
}
```
**Response Interface (`AppStatusOverview`):**
```typescript
interface AppStatusOverview {
timestamp: string; // ISO 8601 timestamp
overview: string;
status: 'normal' | 'warning' | 'critical';
item_statuses: Array<{
item_id: string;
friendly_name: string;
status_summary: string;
}>;
recommendations: Array<{
priority: string;
title: string;
description: string;
action: string;
}>;
}
```
**Example:**
```typescript
try {
const latestStatus = await sdk.app.getLatestStatus({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
tenant_apikey: 'YOUR_TENANT_API_KEY' // Optional, for multi-tenant apps
});
console.log('Latest App Status:', latestStatus);
} 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('Failed to get latest app status:', error);
}
}
```
### 5. Logs Endpoints
The logs endpoints allow you to create and retrieve logs for your applications.
#### 5.1 Create Log
Creates a new log entry.
```typescript
logs.createLog(data: CreateLogRequest): Promise<void>
```
**Request Interface:**
```typescript
interface CreateLogRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id: string;
friendly_name: string;
timestamp: string; // ISO 8601 format
metrics: Metric[];
metadata?: any;
}
```
**Example:**
```typescript
await sdk.logs.createLog({
organization_apikey: 'org_123',
app_apikey: 'app_456',
item_id: 'item_789',
friendly_name: 'User Login',
timestamp: '2024-03-20T10:00:00Z',
metrics: [
{ name: 'response_time', value: 150 },
{ name: 'status', value: 'success' }
],
metadata: {
user_id: 'user_123',
browser: 'Chrome'
}
});
```
#### 5.2 Create Batch Logs
Creates multiple log entries in a single request.
```typescript
logs.createBatchLogs(data: BatchLogRequest): Promise<BatchLogResponse>
```
**Request Interface:**
```typescript
interface BatchLogRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
logs: BatchLog[];
}
interface BatchLog {
item_id: string;
friendly_name: string;
timestamp: string; // ISO 8601 format
metrics: Metric[];
metadata?: any;
}
```
**Response Interface:**
```typescript
interface BatchLogResponse {
success: boolean;
message: string;
failed_logs?: {
index: number;
error: string;
}[];
}
```
**Example:**
```typescript
const response = await sdk.logs.createBatchLogs({
organization_apikey: 'org_123',
app_apikey: 'app_456',
logs: [
{
item_id: 'item_1',
friendly_name: 'User Login',
timestamp: '2024-03-20T10:00:00Z',
metrics: [
{ name: 'response_time', value: 150 },
{ name: 'status', value: 'success' }
]
},
{
item_id: 'item_2',
friendly_name: 'API Call',
timestamp: '2024-03-20T10:01:00Z',
metrics: [
{ name: 'latency', value: 200 },
{ name: 'status', value: 'error' }
]
}
]
});
```
#### 5.3 Get Logs
Retrieves logs for a specific item with pagination.
```typescript
logs.getLogs(data: GetLogsRequest): Promise<PaginatedLogResponse>
```
**Request Interface:**
```typescript
interface GetLogsRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id: string;
page?: number;
limit?: number;
before?: string; // ISO 8601 timestamp
after?: string; // ISO 8601 timestamp
}
```
**Response Interface:**
```typescript
interface PaginatedLogResponse {
logs: LogResponse[];
total: number;
page: number;
limit: number;
has_more: boolean;
}
interface LogResponse {
id: number;
app_id: number;
tenant_id: number;
item_id: string;
friendly_name: string;
log_data: LogData;
created_at: string;
}
interface LogData {
timestamp: string;
metrics: Metric[];
metadata?: any;
}
interface Metric {
name: string;
value: any;
}
```
**Example:**
```typescript
const response = await sdk.logs.getLogs({
organization_apikey: 'org_123',
app_apikey: 'app_456',
item_id: 'item_789',
page: 1,
limit: 10,
after: '2024-03-20T00:00:00Z'
});
```
#### 5.4 Get Latest Logs
Retrieves the most recent logs for a specific item.
```typescript
logs.getLatestLogs(data: GetLatestLogsRequest): Promise<LatestLogsResponse>
```
**Request Interface:**
```typescript
interface GetLatestLogsRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
item_id: string;
limit?: number;
}
```
**Response Interface:**
```typescript
interface LatestLogsResponse {
logs: LogResponse[];
}
```
**Example:**
```typescript
const response = await sdk.logs.getLatestLogs({
organization_apikey: 'org_123',
app_apikey: 'app_456',
item_id: 'item_789',
limit: 5
});
```
#### 5.5 Get Log by ID
Retrieves a specific log by its ID.
```typescript
logs.getLogById(id: number, data: GetLogByIdRequest): Promise<LogResponse>
```
**Request Interface:**
```typescript
interface GetLogByIdRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey?: string;
}
```
**Example:**
```typescript
const log = await sdk.logs.getLogById(123, {
organization_apikey: 'org_123',
app_apikey: 'app_456'
});
```
**Error Handling:**
All log endpoints may throw the following errors:
- `InvalidRequestError`: When required fields are missing or invalid
- `AuthenticationError`: When API keys are invalid
- `NotFoundError`: When a specific log is not found (getLogById only)
- `ServerError`: When the server encounters an error
**Notes:**
- All timestamps must be in ISO 8601 format (e.g., '2024-03-20T10:00:00Z')
- Batch log creation is limited to 100 logs per request
- The `tenant_apikey` is optional for all endpoints
- Metrics can have any value type (string, number, boolean, etc.)
- Metadata can contain any additional information as key-value pairs
### 6. Metrics Endpoints
Retrieve metrics and metadata for apps and tenants. The metrics endpoints are organized into three categories:
1. **General Metrics** (`getMetrics`): Get current metrics for a specific tenant
2. **App Metadata** (`getAppMetadata`): Get aggregated metadata for an entire app
3. **Tenant Metadata** (`getTenantMetadata`): Get detailed metadata for a specific tenant
#### `metrics.getMetrics(data)`
`GET /api/metrics`
Gets current metrics for a specific tenant. This endpoint requires all three API keys (organization, app, and tenant).
```typescript
async getMetrics(data: GetMetricsRequest): Promise<GetMetricsResponse>
```
**Request Interface (`GetMetricsRequest`):**
```typescript
interface GetMetricsRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey: string; // Required for tenant-specific metrics
}
```
**Response Interface (`GetMetricsResponse`):**
```typescript
interface GetMetricsResponse {
metrics: {
app_id: string;
tenant_id?: string;
analysis_count: number;
log_count: number;
last_updated: string;
};
}
```
**Example:**
```typescript
try {
const metrics = await sdk.metrics.getMetrics({
organization_apikey: 'YOUR_ORG_API_KEY',
app_apikey: 'YOUR_APP_API_KEY',
tenant_apikey: 'YOUR_TENANT_API_KEY'
});
console.log('Tenant Metrics:', metrics);
} 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('Failed to get metrics:', error);
}
}
```
#### `metrics.getAppMetadata(data)`
`GET /api/metrics/app`
Gets aggregated metadata for an entire app. This endpoint only requires organization and app API keys.
```typescript
async getAppMetadata(data: GetAppMetadataRequest): Promise<GetAppMetadataResponse>
```
**Request Interface (`GetAppMetadataRequest`):**
```typescript
interface GetAppMetadataRequest {
organization_apikey: string;
app_apikey: string;
// No tenant_apikey required - returns app-level aggregations
}
```
**Response Interface (`GetAppMetadataResponse`):**
```typescript
interface GetAppMetadataResponse {
metadata: {
id: number;
app_id: string;
tenant_count: number; // Total number of tenants in the app
total_log_count: number; // Total logs across all tenants
total_analysis_count: number; // Total analyses across all tenants
last_log_at: string; // Most recent log timestamp
first_log_at: string; // First log timestamp
last_analysis_at: string; // Most recent analysis timestamp
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) {
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('Failed to get app metadata:', error);
}
}
```
#### `metrics.getTenantMetadata(data)`
`GET /api/metrics/tenant`
Gets detailed metadata for a specific tenant. This endpoint requires all three API keys (organization, app, and tenant).
```typescript
async getTenantMetadata(data: GetTenantMetadataRequest): Promise<GetTenantMetadataResponse>
```
**Request Interface (`GetTenantMetadataRequest`):**
```typescript
interface GetTenantMetadataRequest {
organization_apikey: string;
app_apikey: string;
tenant_apikey: string; // Required for tenant-specific metadata
}
```
**Response Interface (`GetTenantMetadataResponse`):**
```typescript
interface GetTenantMetadataResponse {
metadata: {
id: number;
app_id: string;
tenant_id: string;
log_count: number; // Logs for this specific tenant
last_log_at: string; // Most recent log timestamp
first_log_at: string; // First log timestamp
analysis_count: number; // Analyses for this specific tenant
last_analysis_at: string; // Most recent analysis timestamp
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) {
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('Failed to get tenant metadata:', error);
}
}
```
### 7. 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);
}
```
### 8. 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);
}
```
### 9. 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`):**
```