niledatabase
Version:
Command line interface for Nile databases
202 lines (201 loc) • 8.63 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NileAPI = void 0;
const axios_1 = __importDefault(require("axios"));
const colors_1 = require("./colors");
class NileAPI {
constructor(options) {
this.debug = options.debug || false;
if (!options.token) {
throw new Error('Token is required');
}
this.token = options.token;
// Handle URL override
if (options.controlPlaneUrl) {
// Remove any protocol prefix if present
this.controlPlaneUrl = options.controlPlaneUrl.replace(/^(https?:\/\/)/, '');
// Add https:// prefix
this.controlPlaneUrl = `https://${this.controlPlaneUrl}`;
}
else {
this.controlPlaneUrl = NileAPI.DEFAULT_CONTROL_PLANE_URL;
}
// Set user URL
this.userUrl = NileAPI.DEFAULT_USER_URL;
if (this.debug) {
console.log(colors_1.theme.dim('\nAPI Configuration:'));
console.log(colors_1.theme.dim('Control Plane URL:'), this.controlPlaneUrl);
console.log(colors_1.theme.dim('User API URL:'), this.userUrl);
console.log();
}
// Create control plane client for workspace/database operations
this.controlPlaneClient = axios_1.default.create({
baseURL: this.controlPlaneUrl,
headers: {
Authorization: `Bearer ${this.token}`,
'Content-Type': 'application/json'
},
});
// Create user client for user operations
this.userClient = axios_1.default.create({
baseURL: this.userUrl,
headers: {
Authorization: `Bearer ${this.token}`,
'Content-Type': 'application/json'
},
});
// Add debug logging
this.addDebugLogging(this.controlPlaneClient);
this.addDebugLogging(this.userClient);
this.dbHost = options.dbHost;
}
addDebugLogging(client) {
client.interceptors.request.use(request => {
if (this.debug) {
console.log(colors_1.theme.dim('\nAPI Request:'));
console.log(colors_1.theme.dim(`${request.method?.toUpperCase()} ${request.baseURL}${request.url}`));
console.log(colors_1.theme.dim('Headers:'), {
...request.headers,
Authorization: request.headers.Authorization ? 'Bearer [hidden]' : undefined
});
if (request.data) {
console.log(colors_1.theme.dim('Body:'), request.data);
}
console.log();
}
return request;
});
client.interceptors.response.use(response => {
if (this.debug) {
console.log(colors_1.theme.dim('API Response Status:'), response.status);
if (response.data) {
console.log(colors_1.theme.dim('Response Data:'), response.data);
}
}
return response;
}, error => {
if (this.debug && error.response) {
console.log(colors_1.theme.dim('API Error Response:'), {
status: error.response.status,
data: error.response.data
});
}
throw error;
});
}
async getDatabaseConnection(workspaceSlug, databaseName) {
// Get database credentials from control plane
if (this.debug) {
console.log(colors_1.theme.dim('\nFetching database credentials...'));
}
const credentials = await this.createDatabaseCredentials(workspaceSlug, databaseName);
if (!credentials.id || !credentials.password) {
throw new Error('Invalid credentials received from server');
}
// Get the region from the database info
const region = credentials.database.region; // e.g., AWS_US_WEST_2 or AZURE_EASTUS
const regionParts = region.toLowerCase().split('_');
const cloudProvider = regionParts[0]; // aws or azure
const regionId = regionParts.slice(1).join('-'); // e.g., us-west-2 or eastus
// Use custom host if provided, otherwise construct based on cloud provider
let dbHost;
if (cloudProvider === 'azure') {
dbHost = `db.${regionId}.azure.thenile.dev`;
}
else {
// Default AWS format
dbHost = `${regionId}.db.thenile.dev`;
}
if (this.debug) {
console.log(colors_1.theme.dim('\nPostgreSQL Connection Details:'));
console.log(colors_1.theme.dim('Cloud Provider:'), cloudProvider);
console.log(colors_1.theme.dim('Region:'), regionId);
console.log(colors_1.theme.dim('Host:'), dbHost);
console.log(colors_1.theme.dim('Database:'), databaseName);
console.log(colors_1.theme.dim('User:'), credentials.id);
console.log();
}
return {
host: dbHost,
database: databaseName,
user: credentials.id,
password: credentials.password,
port: 5432
};
}
async getDeveloperInfo() {
const response = await this.controlPlaneClient.get('/developers/me');
return response.data;
}
async listDatabases(workspaceSlug) {
const response = await this.controlPlaneClient.get(`/workspaces/${workspaceSlug}/databases`);
return response.data;
}
async createDatabase(workspaceSlug, name, region) {
const response = await this.controlPlaneClient.post(`/workspaces/${workspaceSlug}/databases`, {
databaseName: name,
region,
});
return response.data;
}
async getDatabase(workspaceSlug, databaseName) {
const response = await this.controlPlaneClient.get(`/workspaces/${workspaceSlug}/databases/${databaseName}`);
return response.data;
}
async deleteDatabase(workspaceSlug, databaseName) {
await this.controlPlaneClient.delete(`/workspaces/${workspaceSlug}/databases/${databaseName}`);
}
async listDatabaseCredentials(workspaceSlug, databaseName) {
const response = await this.controlPlaneClient.get(`/workspaces/${workspaceSlug}/databases/${databaseName}/credentials`);
return response.data;
}
async createDatabaseCredentials(workspaceSlug, databaseName) {
const response = await this.controlPlaneClient.post(`/workspaces/${workspaceSlug}/databases/${databaseName}/credentials`);
return response.data;
}
async listRegions(workspaceSlug) {
const response = await this.controlPlaneClient.get(`/workspaces/${workspaceSlug}/regions`);
return response.data;
}
async listWorkspaces() {
const response = await this.controlPlaneClient.get('/workspaces');
return response.data;
}
async getWorkspace(workspaceSlug) {
const response = await this.controlPlaneClient.get(`/workspaces/${workspaceSlug}`);
return response.data;
}
async getDatabaseId(workspaceSlug, databaseName) {
const database = await this.getDatabase(workspaceSlug, databaseName);
if (!database.id) {
throw new Error(`Could not find database ID for database '${databaseName}'`);
}
return database.id;
}
async createUser(databaseId, user, options) {
const response = await this.userClient.post(`/v2/databases/${databaseId}/users`, user, {
params: {
tenantId: options?.tenantId,
newTenantName: options?.newTenantName
}
});
return response.data;
}
async getUserTenants(databaseId, userId) {
const response = await this.userClient.get(`/v2/databases/${databaseId}/users/${userId}/tenants`);
return response.data;
}
async updateUser(databaseId, userId, updates) {
const response = await this.userClient.patch(`/v2/databases/${databaseId}/users/${userId}`, updates);
return response.data;
}
async removeUserFromTenant(databaseId, userId, tenantId) {
await this.userClient.delete(`/v2/databases/${databaseId}/users/${userId}/tenants/${tenantId}`);
}
}
exports.NileAPI = NileAPI;
NileAPI.DEFAULT_CONTROL_PLANE_URL = 'https://global.thenile.dev';
NileAPI.DEFAULT_USER_URL = 'https://us-west-2.api.thenile.dev';