@coretext-ai/public-looker-mcp-b5c6d7e8-f9a0-4123-a456-567890123456
Version:
MCP server with full looker capabilities (35 endpoints)
3,707 lines • 178 kB
JavaScript
import axios from 'axios';
import { Logger } from '../services/logger.js';
export class LookerClient {
constructor(config) {
this.config = config;
// Generate unique session ID for this client instance
this.sessionId = `looker-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
// Initialize logger (fallback to console if not provided)
this.logger = config.logger || new Logger({
logLevel: 'ERROR',
component: 'client',
enableConsole: true,
enableShipping: false,
serverName: 'public-looker-mcp'
});
this.logger.info('CLIENT_INIT', 'Client instance created', {
baseUrl: this.resolveBaseUrl(),
timeout: this.config.timeout || 30000,
hasRateLimit: !!this.config.rateLimit,
configKeys: Object.keys(config)
});
this.httpClient = axios.create({
baseURL: this.resolveBaseUrl(),
timeout: this.config.timeout || 30000,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'User-Agent': 'public-looker-mcp/1.0.0',
...this.getAuthHeaders()
},
});
// Add request interceptor for rate limiting
if (this.config.rateLimit) {
this.setupRateLimit(this.config.rateLimit);
}
// Add request interceptor for logging
this.httpClient.interceptors.request.use((config) => {
this.logger.logRequestStart(config.method?.toUpperCase() || 'GET', `${config.baseURL}${config.url}`, {
hasData: !!config.data,
hasParams: !!(config.params && Object.keys(config.params).length > 0),
headers: Object.keys(config.headers || {})
});
if (config.data) {
this.logger.debug('HTTP_REQUEST_BODY', 'Request body data', {
dataType: typeof config.data,
dataSize: JSON.stringify(config.data).length
});
}
if (config.params && Object.keys(config.params).length > 0) {
this.logger.debug('HTTP_REQUEST_PARAMS', 'Query parameters', {
paramCount: Object.keys(config.params).length,
paramKeys: Object.keys(config.params)
});
}
return config;
}, (error) => {
this.logger.error('HTTP_REQUEST_ERROR', 'Request interceptor error', {
error: error.message,
code: error.code
});
return Promise.reject(error);
});
// Add response interceptor for logging and error handling
this.httpClient.interceptors.response.use((response) => {
this.logger.logRequestSuccess(response.config?.method?.toUpperCase() || 'GET', `${response.config?.baseURL}${response.config?.url}`, response.status, 0, // Duration will be calculated in endpoint methods
{
statusText: response.statusText,
responseSize: JSON.stringify(response.data).length,
headers: Object.keys(response.headers || {})
});
return response;
}, (error) => {
this.logger.logRequestError(error.config?.method?.toUpperCase() || 'GET', `${error.config?.baseURL}${error.config?.url}`, error, 0, // Duration will be calculated in endpoint methods
{
hasResponseData: !!error.response?.data
});
throw error;
});
}
setupRateLimit(requestsPerMinute) {
const interval = 60000 / requestsPerMinute; // ms between requests
let lastRequestTime = 0;
this.logger.info('RATE_LIMIT_SETUP', 'Rate limiting configured', {
requestsPerMinute,
intervalMs: interval
});
this.httpClient.interceptors.request.use(async (config) => {
const now = Date.now();
const timeSinceLastRequest = now - lastRequestTime;
if (timeSinceLastRequest < interval) {
const delayMs = interval - timeSinceLastRequest;
this.logger.logRateLimit('HTTP_REQUEST', delayMs, {
timeSinceLastRequest,
requiredInterval: interval
});
await new Promise(resolve => setTimeout(resolve, delayMs));
}
lastRequestTime = Date.now();
return config;
});
}
resolveBaseUrl() {
let baseUrl = 'https://{instance_name}.looker.com';
// Handle dynamic domain replacement (e.g., YOUR_DOMAIN placeholder)
if (baseUrl.includes('YOUR_DOMAIN')) {
const domainEnvVar = `LOOKER_DOMAIN`;
const domain = process.env[domainEnvVar];
if (!domain) {
throw new Error(`Missing domain configuration. Please set ${domainEnvVar} environment variable.`);
}
baseUrl = baseUrl.replace('YOUR_DOMAIN', domain);
console.error(`[LOOKER] Resolved base URL: ${baseUrl}`);
}
return baseUrl;
}
getAuthHeaders() {
// Bearer/API key authentication (static tokens)
const token = this.config.authToken || this.config['lOOKERCLIENTCREDENTIALS'] || process.env.LOOKER_CLIENT_CREDENTIALS;
if (token) {
this.logger.logAuthEvent('static_token_auth_setup', true, {
authType: 'client_credentials',
tokenPreview: token.substring(0, 8) + '...',
header: 'Authorization',
source: 'static_configuration'
});
return {
'Authorization': `Bearer ${token}`
};
}
this.logger.warn('AUTH_WARNING', 'No authentication token found', {
authType: 'client_credentials',
warning: 'API calls may be rate limited',
checkedSources: ['config.authToken', 'environment variables']
});
return {};
}
/**
* Initialize the client (for OAuth clients that need initialization)
*/
async initialize() {
this.logger.debug('CLIENT_INITIALIZE', 'No initialization required for this auth type');
}
/**
* Get the session ID for this client instance
*/
getSessionId() {
return this.sessionId;
}
/**
* Make an authenticated request with proper headers
*/
async makeAuthenticatedRequest(config) {
// For non-OAuth requests, log what auth headers are being used
this.logger.info('REQUEST_AUTH', 'Using pre-configured authentication headers', {
authType: 'static',
requestUrl: config.url,
authHeaders: config.headers?.Authorization ? 'present' : 'missing',
headerKeys: Object.keys(config.headers || {})
});
return this.httpClient.request(config);
}
buildPath(template, params) {
let path = template;
// Custom encoding that preserves forward slashes for API paths
const encodePathComponent = (value) => {
// For Google API resource names like "people/c123", preserve the forward slash
return encodeURIComponent(value).replace(/%2F/g, '/');
};
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
const processedParams = [];
while ((match = googlePathTemplateRegex.exec(template)) !== null) {
const fullMatch = match[0]; // e.g., "{resourceName=people/*}"
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
path = path.replace(fullMatch, encodePathComponent(String(params[paramName])));
processedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
for (const [key, value] of Object.entries(params)) {
if (!processedParams.includes(key)) {
const standardTemplate = `{${key}}`;
if (path.includes(standardTemplate)) {
path = path.replace(standardTemplate, encodePathComponent(String(value)));
processedParams.push(key);
}
}
}
this.logger.debug('PATH_BUILD', 'Built API path from template', {
template,
resultPath: path,
paramCount: Object.keys(params).length,
paramKeys: Object.keys(params),
processedParams,
hasGoogleTemplates: googlePathTemplateRegex.test(template)
});
return path;
}
async login(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'login',
method: 'POST',
path: '/api/4.0/login',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/login';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["client_id"] !== undefined) {
bodyParams["client_id"] = params["client_id"];
extractedParams.push("client_id");
}
if (params["client_secret"] !== undefined) {
bodyParams["client_secret"] = params["client_secret"];
extractedParams.push("client_secret");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.client_id) {
throw new Error(`Missing required parameter: client_id`);
}
if (!params.client_secret) {
throw new Error(`Missing required parameter: client_secret`);
}
const path = this.buildPath('/api/4.0/login', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'login',
method: 'POST',
path: '/api/4.0/login',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'login',
method: 'POST',
path: '/api/4.0/login',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute login: ${error instanceof Error ? error.message : String(error)}`);
}
}
async logout(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'logout',
method: 'DELETE',
path: '/api/4.0/logout',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/logout';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
const path = this.buildPath('/api/4.0/logout', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.delete(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'logout',
method: 'DELETE',
path: '/api/4.0/logout',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'logout',
method: 'DELETE',
path: '/api/4.0/logout',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute logout: ${error instanceof Error ? error.message : String(error)}`);
}
}
async me(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'me',
method: 'GET',
path: '/api/4.0/user',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/user';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/user', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'me',
method: 'GET',
path: '/api/4.0/user',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'me',
method: 'GET',
path: '/api/4.0/user',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute me: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listUsers(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_users',
method: 'GET',
path: '/api/4.0/users',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/users';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["page"] !== undefined) {
queryParams["page"] = params["page"];
extractedParams.push("page");
}
if (params["per_page"] !== undefined) {
queryParams["per_page"] = params["per_page"];
extractedParams.push("per_page");
}
if (params["sorts"] !== undefined) {
queryParams["sorts"] = params["sorts"];
extractedParams.push("sorts");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/users', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_users',
method: 'GET',
path: '/api/4.0/users',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'list_users',
method: 'GET',
path: '/api/4.0/users',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute list_users: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createUser(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_user',
method: 'POST',
path: '/api/4.0/users',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/users';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["first_name"] !== undefined) {
bodyParams["first_name"] = params["first_name"];
extractedParams.push("first_name");
}
if (params["last_name"] !== undefined) {
bodyParams["last_name"] = params["last_name"];
extractedParams.push("last_name");
}
if (params["email"] !== undefined) {
bodyParams["email"] = params["email"];
extractedParams.push("email");
}
if (params["is_disabled"] !== undefined) {
bodyParams["is_disabled"] = params["is_disabled"];
extractedParams.push("is_disabled");
}
if (params["models_dir_validated"] !== undefined) {
bodyParams["models_dir_validated"] = params["models_dir_validated"];
extractedParams.push("models_dir_validated");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.first_name) {
throw new Error(`Missing required parameter: first_name`);
}
if (!params.last_name) {
throw new Error(`Missing required parameter: last_name`);
}
if (!params.email) {
throw new Error(`Missing required parameter: email`);
}
const path = this.buildPath('/api/4.0/users', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_user',
method: 'POST',
path: '/api/4.0/users',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'create_user',
method: 'POST',
path: '/api/4.0/users',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute create_user: ${error instanceof Error ? error.message : String(error)}`);
}
}
async updateUser(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'update_user',
method: 'PATCH',
path: '/api/4.0/users/{user_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/users/{user_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["first_name"] !== undefined) {
bodyParams["first_name"] = params["first_name"];
extractedParams.push("first_name");
}
if (params["last_name"] !== undefined) {
bodyParams["last_name"] = params["last_name"];
extractedParams.push("last_name");
}
if (params["email"] !== undefined) {
bodyParams["email"] = params["email"];
extractedParams.push("email");
}
if (params["is_disabled"] !== undefined) {
bodyParams["is_disabled"] = params["is_disabled"];
extractedParams.push("is_disabled");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.user_id) {
throw new Error(`Missing required parameter: user_id`);
}
const path = this.buildPath('/api/4.0/users/{user_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.patch(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'update_user',
method: 'PATCH',
path: '/api/4.0/users/{user_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'update_user',
method: 'PATCH',
path: '/api/4.0/users/{user_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute update_user: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listDashboards(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_dashboards',
method: 'GET',
path: '/api/4.0/dashboards',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/dashboards';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["page"] !== undefined) {
queryParams["page"] = params["page"];
extractedParams.push("page");
}
if (params["per_page"] !== undefined) {
queryParams["per_page"] = params["per_page"];
extractedParams.push("per_page");
}
if (params["sorts"] !== undefined) {
queryParams["sorts"] = params["sorts"];
extractedParams.push("sorts");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/dashboards', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_dashboards',
method: 'GET',
path: '/api/4.0/dashboards',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'list_dashboards',
method: 'GET',
path: '/api/4.0/dashboards',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute list_dashboards: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getDashboard(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_dashboard',
method: 'GET',
path: '/api/4.0/dashboards/{dashboard_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/dashboards/{dashboard_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.dashboard_id) {
throw new Error(`Missing required parameter: dashboard_id`);
}
const path = this.buildPath('/api/4.0/dashboards/{dashboard_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_dashboard',
method: 'GET',
path: '/api/4.0/dashboards/{dashboard_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_dashboard',
method: 'GET',
path: '/api/4.0/dashboards/{dashboard_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_dashboard: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createDashboard(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_dashboard',
method: 'POST',
path: '/api/4.0/dashboards',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/dashboards';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["title"] !== undefined) {
bodyParams["title"] = params["title"];
extractedParams.push("title");
}
if (params["description"] !== undefined) {
bodyParams["description"] = params["description"];
extractedParams.push("description");
}
if (params["hidden"] !== undefined) {
bodyParams["hidden"] = params["hidden"];
extractedParams.push("hidden");
}
if (params["refresh_interval"] !== undefined) {
bodyParams["refresh_interval"] = params["refresh_interval"];
extractedParams.push("refresh_interval");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.title) {
throw new Error(`Missing required parameter: title`);
}
const path = this.buildPath('/api/4.0/dashboards', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_dashboard',
method: 'POST',
path: '/api/4.0/dashboards',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'create_dashboard',
method: 'POST',
path: '/api/4.0/dashboards',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute create_dashboard: ${error instanceof Error ? error.message : String(error)}`);
}
}
async updateDashboard(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'update_dashboard',
method: 'PATCH',
path: '/api/4.0/dashboards/{dashboard_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/dashboards/{dashboard_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["title"] !== undefined) {
bodyParams["title"] = params["title"];
extractedParams.push("title");
}
if (params["description"] !== undefined) {
bodyParams["description"] = params["description"];
extractedParams.push("description");
}
if (params["hidden"] !== undefined) {
bodyParams["hidden"] = params["hidden"];
extractedParams.push("hidden");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.dashboard_id) {
throw new Error(`Missing required parameter: dashboard_id`);
}
const path = this.buildPath('/api/4.0/dashboards/{dashboard_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.patch(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'update_dashboard',
method: 'PATCH',
path: '/api/4.0/dashboards/{dashboard_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'update_dashboard',
method: 'PATCH',
path: '/api/4.0/dashboards/{dashboard_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute update_dashboard: ${error instanceof Error ? error.message : String(error)}`);
}
}
async deleteDashboard(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'delete_dashboard',
method: 'DELETE',
path: '/api/4.0/dashboards/{dashboard_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/dashboards/{dashboard_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.dashboard_id) {
throw new Error(`Missing required parameter: dashboard_id`);
}
const path = this.buildPath('/api/4.0/dashboards/{dashboard_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.delete(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'delete_dashboard',
method: 'DELETE',
path: '/api/4.0/dashboards/{dashboard_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'delete_dashboard',
method: 'DELETE',
path: '/api/4.0/dashboards/{dashboard_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute delete_dashboard: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listLooks(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_looks',
method: 'GET',
path: '/api/4.0/looks',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/looks';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["page"] !== undefined) {
queryParams["page"] = params["page"];
extractedParams.push("page");
}
if (params["per_page"] !== undefined) {
queryParams["per_page"] = params["per_page"];
extractedParams.push("per_page");
}
if (params["sorts"] !== undefined) {
queryParams["sorts"] = params["sorts"];
extractedParams.push("sorts");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/looks', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_looks',
method: 'GET',
path: '/api/4.0/looks',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'list_looks',
method: 'GET',
path: '/api/4.0/looks',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute list_looks: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getLook(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_look',
method: 'GET',
path: '/api/4.0/looks/{look_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/looks/{look_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.look_id) {
throw new Error(`Missing required parameter: look_id`);
}
const path = this.buildPath('/api/4.0/looks/{look_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_look',
method: 'GET',
path: '/api/4.0/looks/{look_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_look',
method: 'GET',
path: '/api/4.0/looks/{look_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_look: ${error instanceof Error ? error.message : String(error)}`);
}
}
async runLook(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'run_look',
method: 'GET',
path: '/api/4.0/looks/{look_id}/run/{result_format}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/looks/{look_id}/run/{result_format}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["limit"] !== undefined) {
queryParams["limit"] = params["limit"];
extractedParams.push("limit");
}
if (params["apply_formatting"] !== undefined) {
queryParams["apply_formatting"] = params["apply_formatting"];
extractedParams.push("apply_formatting");
}
if (params["apply_vis"] !== undefined) {
queryParams["apply_vis"] = params["apply_vis"];
extractedParams.push("apply_vis");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.look_id) {
throw new Error(`Missing required parameter: look_id`);
}
if (!params.result_format) {
throw new Error(`Missing required parameter: result_format`);
}
const path = this.buildPath('/api/4.0/looks/{look_id}/run/{result_format}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'run_look',
method: 'GET',
path: '/api/4.0/looks/{look_id}/run/{result_format}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'run_look',
method: 'GET',
path: '/api/4.0/looks/{look_id}/run/{result_format}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute run_look: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createLook(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_look',
method: 'POST',
path: '/api/4.0/looks',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/looks';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["title"] !== undefined) {
bodyParams["title"] = params["title"];
extractedParams.push("title");
}
if (params["description"] !== undefined) {
bodyParams["description"] = params["description"];
extractedParams.push("description");
}
if (params["public"] !== undefined) {
bodyParams["public"] = params["public"];
extractedParams.push("public");
}
if (params["query_id"] !== undefined) {
bodyParams["query_id"] = params["query_id"];
extractedParams.push("query_id");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.title) {
throw new Error(`Missing required parameter: title`);
}
if (!params.query_id) {
throw new Error(`Missing required parameter: query_id`);
}
const path = this.buildPath('/api/4.0/looks', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_look',
method: 'POST',
path: '/api/4.0/looks',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'create_look',
method: 'POST',
path: '/api/4.0/looks',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute create_look: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listQueries(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_queries',
method: 'GET',
path: '/api/4.0/queries',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/queries';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["page"] !== undefined) {
queryParams["page"] = params["page"];
extractedParams.push("page");
}
if (params["per_page"] !== undefined) {
queryParams["per_page"] = params["per_page"];
extractedParams.push("per_page");
}
if (params["sorts"] !== undefined) {
queryParams["sorts"] = params["sorts"];
extractedParams.push("sorts");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/queries', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_queries',
method: 'GET',
path: '/api/4.0/queries',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'list_queries',
method: 'GET',
path: '/api/4.0/queries',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute list_queries: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getQuery(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_query',
method: 'GET',
path: '/api/4.0/queries/{query_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/queries/{query_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.query_id) {
throw new Error(`Missing required parameter: query_id`);
}
const path = this.buildPath('/api/4.0/queries/{query_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_query',
method: 'GET',
path: '/api/4.0/queries/{query_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_query',
method: 'GET',
path: '/api/4.0/queries/{query_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_query: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createQuery(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_query',
method: 'POST',
path: '/api/4.0/queries',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/queries';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["model"] !== undefined) {
bodyParams["model"] = params["model"];
extractedParams.push("model");
}
if (params["explore"] !== undefined) {
bodyParams["explore"] = params["explore"];
extractedParams.push("explore");
}
if (params["dimensions"] !== undefined) {
bodyParams["dimensions"] = params["dimensions"];
extractedParams.push("dimensions");
}
if (params["measures"] !== undefined) {
bodyParams["measures"] = params["measures"];
extractedParams.push("measures");
}
if (params["filters"] !== undefined) {
bodyParams["filters"] = params["filters"];
extractedParams.push("filters");
}
if (params["sorts"] !== undefined) {
bodyParams["sorts"] = params["sorts"];
extractedParams.push("sorts");
}
if (params["limit"] !== undefined) {
bodyParams["limit"] = params["limit"];
extractedParams.push("limit");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.model) {
throw new Error(`Missing required parameter: model`);
}
if (!params.explore) {
throw new Error(`Missing required parameter: explore`);
}
const path = this.buildPath('/api/4.0/queries', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_query',
method: 'POST',
path: '/api/4.0/queries',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'create_query',
method: 'POST',
path: '/api/4.0/queries',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute create_query: ${error instanceof Error ? error.message : String(error)}`);
}
}
async runQuery(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'run_query',
method: 'GET',
path: '/api/4.0/queries/{query_id}/run/{result_format}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/queries/{query_id}/run/{result_format}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["limit"] !== undefined) {
queryParams["limit"] = params["limit"];
extractedParams.push("limit");
}
if (params["apply_formatting"] !== undefined) {
queryParams["apply_formatting"] = params["apply_formatting"];
extractedParams.push("apply_formatting");
}
if (params["apply_vis"] !== undefined) {
queryParams["apply_vis"] = params["apply_vis"];
extractedParams.push("apply_vis");
}
if (params["cache"] !== undefined) {
queryParams["cache"] = params["cache"];
extractedParams.push("cache");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.query_id) {
throw new Error(`Missing required parameter: query_id`);
}
if (!params.result_format) {
throw new Error(`Missing required parameter: result_format`);
}
const path = this.buildPath('/api/4.0/queries/{query_id}/run/{result_format}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'run_query',
method: 'GET',
path: '/api/4.0/queries/{query_id}/run/{result_format}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'run_query',
method: 'GET',
path: '/api/4.0/queries/{query_id}/run/{result_format}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute run_query: ${error instanceof Error ? error.message : String(error)}`);
}
}
async runInlineQuery(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'run_inline_query',
method: 'POST',
path: '/api/4.0/queries/run/{result_format}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/queries/run/{result_format}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["model"] !== undefined) {
bodyParams["model"] = params["model"];
extractedParams.push("model");
}
if (params["explore"] !== undefined) {
bodyParams["explore"] = params["explore"];
extractedParams.push("explore");
}
if (params["dimensions"] !== undefined) {
bodyParams["dimensions"] = params["dimensions"];
extractedParams.push("dimensions");
}
if (params["measures"] !== undefined) {
bodyParams["measures"] = params["measures"];
extractedParams.push("measures");
}
if (params["filters"] !== undefined) {
bodyParams["filters"] = params["filters"];
extractedParams.push("filters");
}
if (params["sorts"] !== undefined) {
bodyParams["sorts"] = params["sorts"];
extractedParams.push("sorts");
}
if (params["limit"] !== undefined) {
bodyParams["limit"] = params["limit"];
extractedParams.push("limit");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.result_format) {
throw new Error(`Missing required parameter: result_format`);
}
if (!params.model) {
throw new Error(`Missing required parameter: model`);
}
if (!params.explore) {
throw new Error(`Missing required parameter: explore`);
}
const path = this.buildPath('/api/4.0/queries/run/{result_format}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'run_inline_query',
method: 'POST',
path: '/api/4.0/queries/run/{result_format}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'run_inline_query',
method: 'POST',
path: '/api/4.0/queries/run/{result_format}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute run_inline_query: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listSpaces(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_spaces',
method: 'GET',
path: '/api/4.0/spaces',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/spaces';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["page"] !== undefined) {
queryParams["page"] = params["page"];
extractedParams.push("page");
}
if (params["per_page"] !== undefined) {
queryParams["per_page"] = params["per_page"];
extractedParams.push("per_page");
}
if (params["sorts"] !== undefined) {
queryParams["sorts"] = params["sorts"];
extractedParams.push("sorts");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/spaces', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_spaces',
method: 'GET',
path: '/api/4.0/spaces',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'list_spaces',
method: 'GET',
path: '/api/4.0/spaces',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute list_spaces: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getSpace(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_space',
method: 'GET',
path: '/api/4.0/spaces/{space_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/spaces/{space_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.space_id) {
throw new Error(`Missing required parameter: space_id`);
}
const path = this.buildPath('/api/4.0/spaces/{space_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_space',
method: 'GET',
path: '/api/4.0/spaces/{space_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_space',
method: 'GET',
path: '/api/4.0/spaces/{space_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_space: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createSpace(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_space',
method: 'POST',
path: '/api/4.0/spaces',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/spaces';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["name"] !== undefined) {
bodyParams["name"] = params["name"];
extractedParams.push("name");
}
if (params["parent_id"] !== undefined) {
bodyParams["parent_id"] = params["parent_id"];
extractedParams.push("parent_id");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.name) {
throw new Error(`Missing required parameter: name`);
}
const path = this.buildPath('/api/4.0/spaces', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_space',
method: 'POST',
path: '/api/4.0/spaces',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'create_space',
method: 'POST',
path: '/api/4.0/spaces',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute create_space: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listFolders(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_folders',
method: 'GET',
path: '/api/4.0/folders',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/folders';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["page"] !== undefined) {
queryParams["page"] = params["page"];
extractedParams.push("page");
}
if (params["per_page"] !== undefined) {
queryParams["per_page"] = params["per_page"];
extractedParams.push("per_page");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/folders', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_folders',
method: 'GET',
path: '/api/4.0/folders',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'list_folders',
method: 'GET',
path: '/api/4.0/folders',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute list_folders: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getFolder(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_folder',
method: 'GET',
path: '/api/4.0/folders/{folder_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/folders/{folder_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.folder_id) {
throw new Error(`Missing required parameter: folder_id`);
}
const path = this.buildPath('/api/4.0/folders/{folder_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_folder',
method: 'GET',
path: '/api/4.0/folders/{folder_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_folder',
method: 'GET',
path: '/api/4.0/folders/{folder_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_folder: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createFolder(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_folder',
method: 'POST',
path: '/api/4.0/folders',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/folders';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["name"] !== undefined) {
bodyParams["name"] = params["name"];
extractedParams.push("name");
}
if (params["parent_id"] !== undefined) {
bodyParams["parent_id"] = params["parent_id"];
extractedParams.push("parent_id");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.name) {
throw new Error(`Missing required parameter: name`);
}
const path = this.buildPath('/api/4.0/folders', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_folder',
method: 'POST',
path: '/api/4.0/folders',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'create_folder',
method: 'POST',
path: '/api/4.0/folders',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute create_folder: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createQueryTask(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_query_task',
method: 'POST',
path: '/api/4.0/query_tasks',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/query_tasks';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["query_id"] !== undefined) {
bodyParams["query_id"] = params["query_id"];
extractedParams.push("query_id");
}
if (params["result_format"] !== undefined) {
bodyParams["result_format"] = params["result_format"];
extractedParams.push("result_format");
}
if (params["limit"] !== undefined) {
queryParams["limit"] = params["limit"];
extractedParams.push("limit");
}
if (params["apply_formatting"] !== undefined) {
queryParams["apply_formatting"] = params["apply_formatting"];
extractedParams.push("apply_formatting");
}
if (params["apply_vis"] !== undefined) {
queryParams["apply_vis"] = params["apply_vis"];
extractedParams.push("apply_vis");
}
if (params["cache"] !== undefined) {
queryParams["cache"] = params["cache"];
extractedParams.push("cache");
}
if (params["generate_drill_links"] !== undefined) {
queryParams["generate_drill_links"] = params["generate_drill_links"];
extractedParams.push("generate_drill_links");
}
if (params["force_production"] !== undefined) {
queryParams["force_production"] = params["force_production"];
extractedParams.push("force_production");
}
if (params["cache_only"] !== undefined) {
queryParams["cache_only"] = params["cache_only"];
extractedParams.push("cache_only");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.result_format) {
throw new Error(`Missing required parameter: result_format`);
}
const path = this.buildPath('/api/4.0/query_tasks', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.post(path, Object.keys(bodyParams).length > 0 ? bodyParams : undefined, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_query_task',
method: 'POST',
path: '/api/4.0/query_tasks',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'create_query_task',
method: 'POST',
path: '/api/4.0/query_tasks',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute create_query_task: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getQueryTask(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_query_task',
method: 'GET',
path: '/api/4.0/query_tasks/{query_task_id}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/query_tasks/{query_task_id}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.query_task_id) {
throw new Error(`Missing required parameter: query_task_id`);
}
const path = this.buildPath('/api/4.0/query_tasks/{query_task_id}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_query_task',
method: 'GET',
path: '/api/4.0/query_tasks/{query_task_id}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_query_task',
method: 'GET',
path: '/api/4.0/query_tasks/{query_task_id}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_query_task: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getQueryTaskResults(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_query_task_results',
method: 'GET',
path: '/api/4.0/query_tasks/{query_task_id}/results',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/query_tasks/{query_task_id}/results';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.query_task_id) {
throw new Error(`Missing required parameter: query_task_id`);
}
const path = this.buildPath('/api/4.0/query_tasks/{query_task_id}/results', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_query_task_results',
method: 'GET',
path: '/api/4.0/query_tasks/{query_task_id}/results',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_query_task_results',
method: 'GET',
path: '/api/4.0/query_tasks/{query_task_id}/results',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_query_task_results: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listModels(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_models',
method: 'GET',
path: '/api/4.0/lookml_models',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/lookml_models';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/lookml_models', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_models',
method: 'GET',
path: '/api/4.0/lookml_models',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'list_models',
method: 'GET',
path: '/api/4.0/lookml_models',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute list_models: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getModel(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_model',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/lookml_models/{model_name}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.model_name) {
throw new Error(`Missing required parameter: model_name`);
}
const path = this.buildPath('/api/4.0/lookml_models/{model_name}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_model',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_model',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_model: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listExplores(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_explores',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}/explores',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/lookml_models/{model_name}/explores';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.model_name) {
throw new Error(`Missing required parameter: model_name`);
}
const path = this.buildPath('/api/4.0/lookml_models/{model_name}/explores', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_explores',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}/explores',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'list_explores',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}/explores',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute list_explores: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getExplore(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_explore',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}/explores/{explore_name}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/lookml_models/{model_name}/explores/{explore_name}';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.model_name) {
throw new Error(`Missing required parameter: model_name`);
}
if (!params.explore_name) {
throw new Error(`Missing required parameter: explore_name`);
}
const path = this.buildPath('/api/4.0/lookml_models/{model_name}/explores/{explore_name}', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_explore',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}/explores/{explore_name}',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'get_explore',
method: 'GET',
path: '/api/4.0/lookml_models/{model_name}/explores/{explore_name}',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute get_explore: ${error instanceof Error ? error.message : String(error)}`);
}
}
async searchDashboards(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'search_dashboards',
method: 'GET',
path: '/api/4.0/dashboards/search',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/dashboards/search';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
if (params["title"] !== undefined) {
queryParams["title"] = params["title"];
extractedParams.push("title");
}
if (params["description"] !== undefined) {
queryParams["description"] = params["description"];
extractedParams.push("description");
}
if (params["content_favorite_id"] !== undefined) {
queryParams["content_favorite_id"] = params["content_favorite_id"];
extractedParams.push("content_favorite_id");
}
if (params["space_id"] !== undefined) {
queryParams["space_id"] = params["space_id"];
extractedParams.push("space_id");
}
if (params["deleted"] !== undefined) {
queryParams["deleted"] = params["deleted"];
extractedParams.push("deleted");
}
if (params["page"] !== undefined) {
queryParams["page"] = params["page"];
extractedParams.push("page");
}
if (params["per_page"] !== undefined) {
queryParams["per_page"] = params["per_page"];
extractedParams.push("per_page");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
const path = this.buildPath('/api/4.0/dashboards/search', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'search_dashboards',
method: 'GET',
path: '/api/4.0/dashboards/search',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'search_dashboards',
method: 'GET',
path: '/api/4.0/dashboards/search',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute search_dashboards: ${error instanceof Error ? error.message : String(error)}`);
}
}
async renderTaskResults(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'render_task_results',
method: 'GET',
path: '/api/4.0/render_tasks/{render_task_id}/results',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/api/4.0/render_tasks/{render_task_id}/results';
const pathParams = {};
const queryParams = {};
const bodyParams = {};
const extractedParams = [];
// Handle Google-style path templates: {resourceName=people/*} and {person.resourceName=people/*}
const googlePathTemplateRegex = /{([^}=]+)=[^}]*}/g;
let match;
while ((match = googlePathTemplateRegex.exec(pathTemplate)) !== null) {
const paramName = match[1]; // e.g., "resourceName" or "person.resourceName"
if (paramName && params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
}
// Handle standard path templates: {resourceName}
const standardPathParams = pathTemplate.match(/{([^}=]+)}/g) || [];
standardPathParams.forEach(paramTemplate => {
const paramName = paramTemplate.slice(1, -1); // Remove { }
// Only process if not already handled by Google template logic
if (!extractedParams.includes(paramName)) {
if (params[paramName] !== undefined) {
pathParams[paramName] = params[paramName];
extractedParams.push(paramName);
}
else {
// Provide default values for optional path parameters
if (paramName === 'userId') {
pathParams[paramName] = 'me'; // Default to authenticated user
extractedParams.push(paramName);
}
}
}
});
// Separate remaining parameters by location (query vs body)
// Any remaining unprocessed parameters default to body for backward compatibility
for (const [key, value] of Object.entries(params)) {
if (!extractedParams.includes(key)) {
bodyParams[key] = value;
}
}
// Validate required parameters
if (!params.render_task_id) {
throw new Error(`Missing required parameter: render_task_id`);
}
const path = this.buildPath('/api/4.0/render_tasks/{render_task_id}/results', pathParams);
// Use standard HTTP client for other auth types
const response = await this.httpClient.get(path, { params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'render_task_results',
method: 'GET',
path: '/api/4.0/render_tasks/{render_task_id}/results',
duration_ms: duration,
responseDataSize: JSON.stringify(response.data).length
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}
]
};
}
catch (error) {
const duration = Date.now() - startTime;
this.logger.error('ENDPOINT_ERROR', 'Endpoint execution failed', {
endpoint: 'render_task_results',
method: 'GET',
path: '/api/4.0/render_tasks/{render_task_id}/results',
duration_ms: duration,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.constructor.name : 'unknown'
});
throw new Error(`Failed to execute render_task_results: ${error instanceof Error ? error.message : String(error)}`);
}
}
}
//# sourceMappingURL=looker-client.js.map