@coretext-ai/public-gsuite-mcp-d495ced0-92b0-4d0e-ad89-f27c9e31f4f9
Version:
MCP server with full GSuite integrations
3,453 lines • 170 kB
JavaScript
import axios from 'axios';
import { Logger } from '../services/logger.js';
export class GoogleDriveClient {
constructor(config) {
this.config = config;
// Generate unique session ID for this client instance
this.sessionId = `google-drive-${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-gsuite-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)
});
// Initialize OAuth client from config if provided
this.oauthClient = config.oauthClient;
this.httpClient = axios.create({
baseURL: this.resolveBaseUrl(),
timeout: this.config.timeout || 30000,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'User-Agent': 'public-gsuite-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://www.googleapis.com';
// Handle dynamic domain replacement (e.g., YOUR_DOMAIN placeholder)
if (baseUrl.includes('YOUR_DOMAIN')) {
const domainEnvVar = `GOOGLE_DRIVE_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(`[GOOGLE_DRIVE] Resolved base URL: ${baseUrl}`);
}
return baseUrl;
}
getAuthHeaders() {
// OAuth authentication (both ConstructionWire and standard OAuth) - handled dynamically
// Tokens will be applied asynchronously via makeAuthenticatedRequest
this.logger.logAuthEvent('oauth_auth_setup', true, {
authType: 'oauth2',
message: 'OAuth tokens will be applied dynamically during requests',
oauthClientPresent: !!this.oauthClient
});
return {};
}
/**
* Initialize the client (for OAuth clients that need initialization)
*/
async initialize() {
if (this.oauthClient) {
await this.oauthClient.initialize();
this.logger.info('CLIENT_INITIALIZE', 'OAuth client initialized');
}
}
/**
* Get the session ID for this client instance
*/
getSessionId() {
return this.sessionId;
}
/**
* Make an authenticated request with proper headers
*/
async makeAuthenticatedRequest(config) {
// Get OAuth token for standard OAuth
this.logger.info('REQUEST_AUTH', 'Applying standard OAuth authentication', {
authType: 'oauth2',
requestUrl: config.url,
hasOAuthClient: !!this.oauthClient
});
if (this.oauthClient) {
const accessToken = await this.oauthClient.getValidAccessToken();
config.headers = {
...config.headers,
'Authorization': `Bearer ${accessToken}`
};
this.logger.logAuthEvent('oauth_token_applied', true, {
authType: 'oauth2',
tokenPreview: accessToken ? accessToken.substring(0, 8) + '...' : 'null',
header: 'Authorization',
tokenSource: 'standard_oauth',
finalHeaders: Object.keys(config.headers)
});
}
else {
this.logger.warn('OAUTH_CLIENT_MISSING', 'OAuth client not available for OAuth-enabled template', {
authType: 'oauth2',
requestUrl: config.url
});
}
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 uploadFileSimple(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'upload_file_simple',
method: 'POST',
path: '/upload/drive/v3/files',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/upload/drive/v3/files';
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["uploadType"] !== undefined) {
queryParams["uploadType"] = params["uploadType"];
extractedParams.push("uploadType");
}
if (params["fileContent"] !== undefined) {
bodyParams["fileContent"] = params["fileContent"];
extractedParams.push("fileContent");
}
// 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.uploadType) {
throw new Error(`Missing required parameter: uploadType`);
}
if (!params.fileContent) {
throw new Error(`Missing required parameter: fileContent`);
}
const path = this.buildPath('/upload/drive/v3/files', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'POST', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'upload_file_simple',
method: 'POST',
path: '/upload/drive/v3/files',
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: 'upload_file_simple',
method: 'POST',
path: '/upload/drive/v3/files',
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 upload_file_simple: ${error instanceof Error ? error.message : String(error)}`);
}
}
async uploadFileMultipart(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'upload_file_multipart',
method: 'POST',
path: '/upload/drive/v3/files',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/upload/drive/v3/files';
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["uploadType"] !== undefined) {
queryParams["uploadType"] = params["uploadType"];
extractedParams.push("uploadType");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["metadata"] !== undefined) {
bodyParams["metadata"] = params["metadata"];
extractedParams.push("metadata");
}
if (params["fileContent"] !== undefined) {
bodyParams["fileContent"] = params["fileContent"];
extractedParams.push("fileContent");
}
// 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.uploadType) {
throw new Error(`Missing required parameter: uploadType`);
}
if (!params.metadata) {
throw new Error(`Missing required parameter: metadata`);
}
if (!params.fileContent) {
throw new Error(`Missing required parameter: fileContent`);
}
const path = this.buildPath('/upload/drive/v3/files', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'POST', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'upload_file_multipart',
method: 'POST',
path: '/upload/drive/v3/files',
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: 'upload_file_multipart',
method: 'POST',
path: '/upload/drive/v3/files',
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 upload_file_multipart: ${error instanceof Error ? error.message : String(error)}`);
}
}
async uploadFileResumable(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'upload_file_resumable',
method: 'POST',
path: '/upload/drive/v3/files',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/upload/drive/v3/files';
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["uploadType"] !== undefined) {
queryParams["uploadType"] = params["uploadType"];
extractedParams.push("uploadType");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["metadata"] !== undefined) {
bodyParams["metadata"] = params["metadata"];
extractedParams.push("metadata");
}
// 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.uploadType) {
throw new Error(`Missing required parameter: uploadType`);
}
if (!params.metadata) {
throw new Error(`Missing required parameter: metadata`);
}
const path = this.buildPath('/upload/drive/v3/files', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'POST', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'upload_file_resumable',
method: 'POST',
path: '/upload/drive/v3/files',
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: 'upload_file_resumable',
method: 'POST',
path: '/upload/drive/v3/files',
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 upload_file_resumable: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getFile(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_file',
method: 'GET',
path: '/drive/v3/files/{fileId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}';
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["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["acknowledgeAbuse"] !== undefined) {
queryParams["acknowledgeAbuse"] = params["acknowledgeAbuse"];
extractedParams.push("acknowledgeAbuse");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_file',
method: 'GET',
path: '/drive/v3/files/{fileId}',
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_file',
method: 'GET',
path: '/drive/v3/files/{fileId}',
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_file: ${error instanceof Error ? error.message : String(error)}`);
}
}
async downloadFile(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'download_file',
method: 'GET',
path: '/drive/v3/files/{fileId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}';
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["alt"] !== undefined) {
queryParams["alt"] = params["alt"];
extractedParams.push("alt");
}
if (params["acknowledgeAbuse"] !== undefined) {
queryParams["acknowledgeAbuse"] = params["acknowledgeAbuse"];
extractedParams.push("acknowledgeAbuse");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.alt) {
throw new Error(`Missing required parameter: alt`);
}
const path = this.buildPath('/drive/v3/files/{fileId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'download_file',
method: 'GET',
path: '/drive/v3/files/{fileId}',
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: 'download_file',
method: 'GET',
path: '/drive/v3/files/{fileId}',
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 download_file: ${error instanceof Error ? error.message : String(error)}`);
}
}
async exportFile(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'export_file',
method: 'GET',
path: '/drive/v3/files/{fileId}/export',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/export';
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["mimeType"] !== undefined) {
queryParams["mimeType"] = params["mimeType"];
extractedParams.push("mimeType");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.mimeType) {
throw new Error(`Missing required parameter: mimeType`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/export', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'export_file',
method: 'GET',
path: '/drive/v3/files/{fileId}/export',
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: 'export_file',
method: 'GET',
path: '/drive/v3/files/{fileId}/export',
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 export_file: ${error instanceof Error ? error.message : String(error)}`);
}
}
async updateFile(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'update_file',
method: 'PATCH',
path: '/drive/v3/files/{fileId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}';
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["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["name"] !== undefined) {
bodyParams["name"] = params["name"];
extractedParams.push("name");
}
if (params["description"] !== undefined) {
bodyParams["description"] = params["description"];
extractedParams.push("description");
}
if (params["parents"] !== undefined) {
bodyParams["parents"] = params["parents"];
extractedParams.push("parents");
}
if (params["starred"] !== undefined) {
bodyParams["starred"] = params["starred"];
extractedParams.push("starred");
}
if (params["trashed"] !== undefined) {
bodyParams["trashed"] = params["trashed"];
extractedParams.push("trashed");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'PATCH', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'update_file',
method: 'PATCH',
path: '/drive/v3/files/{fileId}',
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_file',
method: 'PATCH',
path: '/drive/v3/files/{fileId}',
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_file: ${error instanceof Error ? error.message : String(error)}`);
}
}
async updateFileContent(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'update_file_content',
method: 'PATCH',
path: '/upload/drive/v3/files/{fileId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/upload/drive/v3/files/{fileId}';
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["uploadType"] !== undefined) {
queryParams["uploadType"] = params["uploadType"];
extractedParams.push("uploadType");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["metadata"] !== undefined) {
bodyParams["metadata"] = params["metadata"];
extractedParams.push("metadata");
}
if (params["fileContent"] !== undefined) {
bodyParams["fileContent"] = params["fileContent"];
extractedParams.push("fileContent");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.uploadType) {
throw new Error(`Missing required parameter: uploadType`);
}
if (!params.fileContent) {
throw new Error(`Missing required parameter: fileContent`);
}
const path = this.buildPath('/upload/drive/v3/files/{fileId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'PATCH', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'update_file_content',
method: 'PATCH',
path: '/upload/drive/v3/files/{fileId}',
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_file_content',
method: 'PATCH',
path: '/upload/drive/v3/files/{fileId}',
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_file_content: ${error instanceof Error ? error.message : String(error)}`);
}
}
async deleteFile(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'delete_file',
method: 'DELETE',
path: '/drive/v3/files/{fileId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}';
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["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'DELETE', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'delete_file',
method: 'DELETE',
path: '/drive/v3/files/{fileId}',
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_file',
method: 'DELETE',
path: '/drive/v3/files/{fileId}',
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_file: ${error instanceof Error ? error.message : String(error)}`);
}
}
async copyFile(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'copy_file',
method: 'POST',
path: '/drive/v3/files/{fileId}/copy',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/copy';
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["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["name"] !== undefined) {
bodyParams["name"] = params["name"];
extractedParams.push("name");
}
if (params["parents"] !== undefined) {
bodyParams["parents"] = params["parents"];
extractedParams.push("parents");
}
if (params["description"] !== undefined) {
bodyParams["description"] = params["description"];
extractedParams.push("description");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/copy', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'POST', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'copy_file',
method: 'POST',
path: '/drive/v3/files/{fileId}/copy',
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: 'copy_file',
method: 'POST',
path: '/drive/v3/files/{fileId}/copy',
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 copy_file: ${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: '/drive/v3/files',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files';
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["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["name"] !== undefined) {
bodyParams["name"] = params["name"];
extractedParams.push("name");
}
if (params["mimeType"] !== undefined) {
bodyParams["mimeType"] = params["mimeType"];
extractedParams.push("mimeType");
}
if (params["parents"] !== undefined) {
bodyParams["parents"] = params["parents"];
extractedParams.push("parents");
}
if (params["description"] !== undefined) {
bodyParams["description"] = params["description"];
extractedParams.push("description");
}
if (params["folderColorRgb"] !== undefined) {
bodyParams["folderColorRgb"] = params["folderColorRgb"];
extractedParams.push("folderColorRgb");
}
// 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`);
}
if (!params.mimeType) {
throw new Error(`Missing required parameter: mimeType`);
}
const path = this.buildPath('/drive/v3/files', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'POST', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_folder',
method: 'POST',
path: '/drive/v3/files',
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: '/drive/v3/files',
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 moveFile(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'move_file',
method: 'PATCH',
path: '/drive/v3/files/{fileId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}';
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["addParents"] !== undefined) {
queryParams["addParents"] = params["addParents"];
extractedParams.push("addParents");
}
if (params["removeParents"] !== undefined) {
queryParams["removeParents"] = params["removeParents"];
extractedParams.push("removeParents");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'PATCH', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'move_file',
method: 'PATCH',
path: '/drive/v3/files/{fileId}',
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: 'move_file',
method: 'PATCH',
path: '/drive/v3/files/{fileId}',
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 move_file: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getFolderContents(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_folder_contents',
method: 'GET',
path: '/drive/v3/files',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files';
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["q"] !== undefined) {
queryParams["q"] = params["q"];
extractedParams.push("q");
}
if (params["pageSize"] !== undefined) {
queryParams["pageSize"] = params["pageSize"];
extractedParams.push("pageSize");
}
if (params["pageToken"] !== undefined) {
queryParams["pageToken"] = params["pageToken"];
extractedParams.push("pageToken");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["orderBy"] !== undefined) {
queryParams["orderBy"] = params["orderBy"];
extractedParams.push("orderBy");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["includeItemsFromAllDrives"] !== undefined) {
queryParams["includeItemsFromAllDrives"] = params["includeItemsFromAllDrives"];
extractedParams.push("includeItemsFromAllDrives");
}
// 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.q) {
throw new Error(`Missing required parameter: q`);
}
const path = this.buildPath('/drive/v3/files', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_folder_contents',
method: 'GET',
path: '/drive/v3/files',
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_contents',
method: 'GET',
path: '/drive/v3/files',
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_contents: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getFolderTree(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_folder_tree',
method: 'GET',
path: '/drive/v3/files',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files';
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["q"] !== undefined) {
queryParams["q"] = params["q"];
extractedParams.push("q");
}
if (params["pageSize"] !== undefined) {
queryParams["pageSize"] = params["pageSize"];
extractedParams.push("pageSize");
}
if (params["pageToken"] !== undefined) {
queryParams["pageToken"] = params["pageToken"];
extractedParams.push("pageToken");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["orderBy"] !== undefined) {
queryParams["orderBy"] = params["orderBy"];
extractedParams.push("orderBy");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
// 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.q) {
throw new Error(`Missing required parameter: q`);
}
const path = this.buildPath('/drive/v3/files', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_folder_tree',
method: 'GET',
path: '/drive/v3/files',
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_tree',
method: 'GET',
path: '/drive/v3/files',
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_tree: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listFiles(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_files',
method: 'GET',
path: '/drive/v3/files',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files';
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["q"] !== undefined) {
queryParams["q"] = params["q"];
extractedParams.push("q");
}
if (params["pageSize"] !== undefined) {
queryParams["pageSize"] = params["pageSize"];
extractedParams.push("pageSize");
}
if (params["pageToken"] !== undefined) {
queryParams["pageToken"] = params["pageToken"];
extractedParams.push("pageToken");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["orderBy"] !== undefined) {
queryParams["orderBy"] = params["orderBy"];
extractedParams.push("orderBy");
}
if (params["spaces"] !== undefined) {
queryParams["spaces"] = params["spaces"];
extractedParams.push("spaces");
}
if (params["corpora"] !== undefined) {
queryParams["corpora"] = params["corpora"];
extractedParams.push("corpora");
}
if (params["driveId"] !== undefined) {
queryParams["driveId"] = params["driveId"];
extractedParams.push("driveId");
}
if (params["includeItemsFromAllDrives"] !== undefined) {
queryParams["includeItemsFromAllDrives"] = params["includeItemsFromAllDrives"];
extractedParams.push("includeItemsFromAllDrives");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["includePermissionsForView"] !== undefined) {
queryParams["includePermissionsForView"] = params["includePermissionsForView"];
extractedParams.push("includePermissionsForView");
}
if (params["includeLabels"] !== undefined) {
queryParams["includeLabels"] = params["includeLabels"];
extractedParams.push("includeLabels");
}
// 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('/drive/v3/files', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_files',
method: 'GET',
path: '/drive/v3/files',
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_files',
method: 'GET',
path: '/drive/v3/files',
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_files: ${error instanceof Error ? error.message : String(error)}`);
}
}
async searchFiles(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'search_files',
method: 'GET',
path: '/drive/v3/files',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files';
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["q"] !== undefined) {
queryParams["q"] = params["q"];
extractedParams.push("q");
}
if (params["pageSize"] !== undefined) {
queryParams["pageSize"] = params["pageSize"];
extractedParams.push("pageSize");
}
if (params["pageToken"] !== undefined) {
queryParams["pageToken"] = params["pageToken"];
extractedParams.push("pageToken");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["orderBy"] !== undefined) {
queryParams["orderBy"] = params["orderBy"];
extractedParams.push("orderBy");
}
if (params["includeItemsFromAllDrives"] !== undefined) {
queryParams["includeItemsFromAllDrives"] = params["includeItemsFromAllDrives"];
extractedParams.push("includeItemsFromAllDrives");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
// 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.q) {
throw new Error(`Missing required parameter: q`);
}
const path = this.buildPath('/drive/v3/files', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'search_files',
method: 'GET',
path: '/drive/v3/files',
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_files',
method: 'GET',
path: '/drive/v3/files',
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_files: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listFileRevisions(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_file_revisions',
method: 'GET',
path: '/drive/v3/files/{fileId}/revisions',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/revisions';
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["pageSize"] !== undefined) {
queryParams["pageSize"] = params["pageSize"];
extractedParams.push("pageSize");
}
if (params["pageToken"] !== undefined) {
queryParams["pageToken"] = params["pageToken"];
extractedParams.push("pageToken");
}
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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/revisions', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_file_revisions',
method: 'GET',
path: '/drive/v3/files/{fileId}/revisions',
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_file_revisions',
method: 'GET',
path: '/drive/v3/files/{fileId}/revisions',
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_file_revisions: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getFileRevision(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_file_revision',
method: 'GET',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/revisions/{revisionId}';
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["acknowledgeAbuse"] !== undefined) {
queryParams["acknowledgeAbuse"] = params["acknowledgeAbuse"];
extractedParams.push("acknowledgeAbuse");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.revisionId) {
throw new Error(`Missing required parameter: revisionId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/revisions/{revisionId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_file_revision',
method: 'GET',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
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_file_revision',
method: 'GET',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
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_file_revision: ${error instanceof Error ? error.message : String(error)}`);
}
}
async updateFileRevision(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'update_file_revision',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/revisions/{revisionId}';
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["keepForever"] !== undefined) {
bodyParams["keepForever"] = params["keepForever"];
extractedParams.push("keepForever");
}
if (params["publishAuto"] !== undefined) {
bodyParams["publishAuto"] = params["publishAuto"];
extractedParams.push("publishAuto");
}
if (params["published"] !== undefined) {
bodyParams["published"] = params["published"];
extractedParams.push("published");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.revisionId) {
throw new Error(`Missing required parameter: revisionId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/revisions/{revisionId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'PATCH', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'update_file_revision',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
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_file_revision',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
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_file_revision: ${error instanceof Error ? error.message : String(error)}`);
}
}
async deleteFileRevision(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'delete_file_revision',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/revisions/{revisionId}';
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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.revisionId) {
throw new Error(`Missing required parameter: revisionId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/revisions/{revisionId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'DELETE', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'delete_file_revision',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
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_file_revision',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/revisions/{revisionId}',
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_file_revision: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createPermission(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_permission',
method: 'POST',
path: '/drive/v3/files/{fileId}/permissions',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/permissions';
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["sendNotificationEmail"] !== undefined) {
queryParams["sendNotificationEmail"] = params["sendNotificationEmail"];
extractedParams.push("sendNotificationEmail");
}
if (params["emailMessage"] !== undefined) {
queryParams["emailMessage"] = params["emailMessage"];
extractedParams.push("emailMessage");
}
if (params["transferOwnership"] !== undefined) {
queryParams["transferOwnership"] = params["transferOwnership"];
extractedParams.push("transferOwnership");
}
if (params["moveToNewOwnersRoot"] !== undefined) {
queryParams["moveToNewOwnersRoot"] = params["moveToNewOwnersRoot"];
extractedParams.push("moveToNewOwnersRoot");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["role"] !== undefined) {
bodyParams["role"] = params["role"];
extractedParams.push("role");
}
if (params["type"] !== undefined) {
bodyParams["type"] = params["type"];
extractedParams.push("type");
}
if (params["emailAddress"] !== undefined) {
bodyParams["emailAddress"] = params["emailAddress"];
extractedParams.push("emailAddress");
}
if (params["domain"] !== undefined) {
bodyParams["domain"] = params["domain"];
extractedParams.push("domain");
}
if (params["allowFileDiscovery"] !== undefined) {
bodyParams["allowFileDiscovery"] = params["allowFileDiscovery"];
extractedParams.push("allowFileDiscovery");
}
if (params["expirationTime"] !== undefined) {
bodyParams["expirationTime"] = params["expirationTime"];
extractedParams.push("expirationTime");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.role) {
throw new Error(`Missing required parameter: role`);
}
if (!params.type) {
throw new Error(`Missing required parameter: type`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/permissions', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'POST', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_permission',
method: 'POST',
path: '/drive/v3/files/{fileId}/permissions',
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_permission',
method: 'POST',
path: '/drive/v3/files/{fileId}/permissions',
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_permission: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listPermissions(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_permissions',
method: 'GET',
path: '/drive/v3/files/{fileId}/permissions',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/permissions';
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["pageSize"] !== undefined) {
queryParams["pageSize"] = params["pageSize"];
extractedParams.push("pageSize");
}
if (params["pageToken"] !== undefined) {
queryParams["pageToken"] = params["pageToken"];
extractedParams.push("pageToken");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["useDomainAdminAccess"] !== undefined) {
queryParams["useDomainAdminAccess"] = params["useDomainAdminAccess"];
extractedParams.push("useDomainAdminAccess");
}
if (params["includePermissionsForView"] !== undefined) {
queryParams["includePermissionsForView"] = params["includePermissionsForView"];
extractedParams.push("includePermissionsForView");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/permissions', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_permissions',
method: 'GET',
path: '/drive/v3/files/{fileId}/permissions',
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_permissions',
method: 'GET',
path: '/drive/v3/files/{fileId}/permissions',
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_permissions: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getPermission(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_permission',
method: 'GET',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/permissions/{permissionId}';
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["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["useDomainAdminAccess"] !== undefined) {
queryParams["useDomainAdminAccess"] = params["useDomainAdminAccess"];
extractedParams.push("useDomainAdminAccess");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.permissionId) {
throw new Error(`Missing required parameter: permissionId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/permissions/{permissionId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_permission',
method: 'GET',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
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_permission',
method: 'GET',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
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_permission: ${error instanceof Error ? error.message : String(error)}`);
}
}
async updatePermission(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'update_permission',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/permissions/{permissionId}';
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["transferOwnership"] !== undefined) {
queryParams["transferOwnership"] = params["transferOwnership"];
extractedParams.push("transferOwnership");
}
if (params["removeExpiration"] !== undefined) {
queryParams["removeExpiration"] = params["removeExpiration"];
extractedParams.push("removeExpiration");
}
if (params["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["role"] !== undefined) {
bodyParams["role"] = params["role"];
extractedParams.push("role");
}
if (params["expirationTime"] !== undefined) {
bodyParams["expirationTime"] = params["expirationTime"];
extractedParams.push("expirationTime");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.permissionId) {
throw new Error(`Missing required parameter: permissionId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/permissions/{permissionId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'PATCH', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'update_permission',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
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_permission',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
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_permission: ${error instanceof Error ? error.message : String(error)}`);
}
}
async deletePermission(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'delete_permission',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/permissions/{permissionId}';
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["supportsAllDrives"] !== undefined) {
queryParams["supportsAllDrives"] = params["supportsAllDrives"];
extractedParams.push("supportsAllDrives");
}
if (params["useDomainAdminAccess"] !== undefined) {
queryParams["useDomainAdminAccess"] = params["useDomainAdminAccess"];
extractedParams.push("useDomainAdminAccess");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.permissionId) {
throw new Error(`Missing required parameter: permissionId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/permissions/{permissionId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'DELETE', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'delete_permission',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
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_permission',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/permissions/{permissionId}',
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_permission: ${error instanceof Error ? error.message : String(error)}`);
}
}
async createComment(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'create_comment',
method: 'POST',
path: '/drive/v3/files/{fileId}/comments',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/comments';
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["content"] !== undefined) {
bodyParams["content"] = params["content"];
extractedParams.push("content");
}
if (params["anchor"] !== undefined) {
bodyParams["anchor"] = params["anchor"];
extractedParams.push("anchor");
}
if (params["quotedFileContent"] !== undefined) {
bodyParams["quotedFileContent"] = params["quotedFileContent"];
extractedParams.push("quotedFileContent");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.content) {
throw new Error(`Missing required parameter: content`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/comments', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'POST', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'create_comment',
method: 'POST',
path: '/drive/v3/files/{fileId}/comments',
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_comment',
method: 'POST',
path: '/drive/v3/files/{fileId}/comments',
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_comment: ${error instanceof Error ? error.message : String(error)}`);
}
}
async listComments(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'list_comments',
method: 'GET',
path: '/drive/v3/files/{fileId}/comments',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/comments';
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["pageSize"] !== undefined) {
queryParams["pageSize"] = params["pageSize"];
extractedParams.push("pageSize");
}
if (params["pageToken"] !== undefined) {
queryParams["pageToken"] = params["pageToken"];
extractedParams.push("pageToken");
}
if (params["fields"] !== undefined) {
queryParams["fields"] = params["fields"];
extractedParams.push("fields");
}
if (params["includeDeleted"] !== undefined) {
queryParams["includeDeleted"] = params["includeDeleted"];
extractedParams.push("includeDeleted");
}
if (params["startModifiedTime"] !== undefined) {
queryParams["startModifiedTime"] = params["startModifiedTime"];
extractedParams.push("startModifiedTime");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/comments', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'list_comments',
method: 'GET',
path: '/drive/v3/files/{fileId}/comments',
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_comments',
method: 'GET',
path: '/drive/v3/files/{fileId}/comments',
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_comments: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getComment(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'get_comment',
method: 'GET',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/comments/{commentId}';
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["includeDeleted"] !== undefined) {
queryParams["includeDeleted"] = params["includeDeleted"];
extractedParams.push("includeDeleted");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.commentId) {
throw new Error(`Missing required parameter: commentId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/comments/{commentId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'GET', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'get_comment',
method: 'GET',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
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_comment',
method: 'GET',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
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_comment: ${error instanceof Error ? error.message : String(error)}`);
}
}
async updateComment(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'update_comment',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/comments/{commentId}';
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["content"] !== undefined) {
bodyParams["content"] = params["content"];
extractedParams.push("content");
}
// 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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.commentId) {
throw new Error(`Missing required parameter: commentId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/comments/{commentId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'PATCH', url: path, params: queryParams, data: Object.keys(bodyParams).length > 0 ? bodyParams : undefined });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'update_comment',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
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_comment',
method: 'PATCH',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
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_comment: ${error instanceof Error ? error.message : String(error)}`);
}
}
async deleteComment(params) {
const startTime = Date.now();
this.logger.info('ENDPOINT_START', 'Endpoint execution started', {
endpoint: 'delete_comment',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
paramCount: Object.keys(params || {}).length,
paramKeys: Object.keys(params || {})
});
try {
// Extract and separate parameters by location: path, query, body
const pathTemplate = '/drive/v3/files/{fileId}/comments/{commentId}';
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.fileId) {
throw new Error(`Missing required parameter: fileId`);
}
if (!params.commentId) {
throw new Error(`Missing required parameter: commentId`);
}
const path = this.buildPath('/drive/v3/files/{fileId}/comments/{commentId}', pathParams);
// Use authenticated request for OAuth (both ConstructionWire and standard OAuth)
const response = await this.makeAuthenticatedRequest({ method: 'DELETE', url: path, params: queryParams });
const duration = Date.now() - startTime;
this.logger.info('ENDPOINT_SUCCESS', 'Endpoint execution completed successfully', {
endpoint: 'delete_comment',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
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_comment',
method: 'DELETE',
path: '/drive/v3/files/{fileId}/comments/{commentId}',
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_comment: ${error instanceof Error ? error.message : String(error)}`);
}
}
}
//# sourceMappingURL=google-drive-client.js.map