UNPKG

@coretext-ai/public-gsuite-mcp-d495ced0-92b0-4d0e-ad89-f27c9e31f4f9

Version:
3,453 lines 170 kB
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