Revert to simple object literal pattern (no IIFE, no return)
Simplified to pure object literal expression
Rationale:
- User requested to forget about IIFE wrapper
- Simpler pattern: file evaluates directly to an object
- No function wrapper needed
- No return statement needed
- server.js already handles this correctly at line 59
Pattern:
```javascript
// Define functions at top level
class DocumentCountExceededError extends Error {...}
function generateRequestId() {...}
function parseRoute() {...}
// Final expression evaluates to object
({
DocumentCountExceededError,
generateRequestId,
parseRoute,
// ... all functions
});
```
How server.js handles it (already correct):
```javascript
const script = new vm.Script(code, { filename: file });
const context = vm.createContext({ ...globalVMContext, ...globalVariableContext });
globalVariableContext[varName] = script.runInContext(context);
// script.runInContext() returns the evaluated expression (the object)
```
Changes:
- Reverted from IIFE with return: (function() { return {...}; })()
- Back to object literal: ({...})
- Removed 2-space indentation throughout
- No function wrapper
- No return statement
Benefits:
✅ Simplest possible pattern
✅ Direct object evaluation
✅ No syntax complexity
✅ Server.js already handles it correctly
✅ Clean, minimal code
Testing:
✓ Syntax validated
✓ Server starts successfully
✓ Module loads: 'Loaded global functions: googleDriveAdapterHelper'
✓ All function calls work correctly
✓ Request handling functional
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
*
|
||||
* ARCHITECTURE:
|
||||
* - Loaded by server.js using vm.Script (same as proxy.js)
|
||||
* - Function that returns a single object containing all helper functions
|
||||
* - Returns a single object containing all helper functions
|
||||
* - Injected into globalVariableContext for access by proxy.js
|
||||
* - NO IMPORTS - All dependencies provided via VM context
|
||||
*
|
||||
@@ -17,42 +17,41 @@
|
||||
* @returns {Object} Helpers object with all utility functions
|
||||
*/
|
||||
|
||||
(function() {
|
||||
/**
|
||||
/**
|
||||
* Custom error for document count exceeding limit
|
||||
*/
|
||||
class DocumentCountExceededError extends Error {
|
||||
constructor(count, limit) {
|
||||
class DocumentCountExceededError extends Error {
|
||||
constructor(count, limit) {
|
||||
super(`Document count ${count} exceeds limit of ${limit}`);
|
||||
this.name = "DocumentCountExceededError";
|
||||
this.count = count;
|
||||
this.limit = limit;
|
||||
this.statusCode = 413;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Utility Functions
|
||||
// =============================================================================
|
||||
// =============================================================================
|
||||
// Utility Functions
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Generate a unique request ID for tracing
|
||||
* Uses UUID v4 for uniqueness
|
||||
*
|
||||
* @returns {string} Request ID in format: req_<uuid>
|
||||
*/
|
||||
function generateRequestId() {
|
||||
return `req_${crypto.randomUUID()}`;
|
||||
}
|
||||
function generateRequestId() {
|
||||
return `req_${crypto.randomUUID()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Validate document ID format
|
||||
* Google Drive IDs are alphanumeric with hyphens and underscores
|
||||
*
|
||||
* @param {string} id - Document ID to validate
|
||||
* @returns {boolean} True if valid
|
||||
*/
|
||||
function validateDocumentId(id) {
|
||||
function validateDocumentId(id) {
|
||||
if (!id || typeof id !== "string") {
|
||||
return false;
|
||||
}
|
||||
@@ -61,33 +60,33 @@
|
||||
// Characters: a-z, A-Z, 0-9, -, _
|
||||
const pattern = /^[a-zA-Z0-9_-]{8,128}$/;
|
||||
return pattern.test(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Validate document count against limit
|
||||
*
|
||||
* @param {number} count - Document count
|
||||
* @param {number} limit - Maximum allowed (default: 50000)
|
||||
* @throws {DocumentCountExceededError} If count > limit
|
||||
*/
|
||||
function validateDocumentCount(count, limit = 50000) {
|
||||
function validateDocumentCount(count, limit = 50000) {
|
||||
if (count > limit) {
|
||||
throw new DocumentCountExceededError(count, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// XML Utilities
|
||||
// =============================================================================
|
||||
// =============================================================================
|
||||
// XML Utilities
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Escape special XML characters
|
||||
* Prevents XML injection and ensures valid XML output
|
||||
*
|
||||
* @param {string} str - String to escape
|
||||
* @returns {string} Escaped string safe for XML
|
||||
*/
|
||||
function escapeXml(str) {
|
||||
function escapeXml(str) {
|
||||
if (!str) return "";
|
||||
|
||||
return str
|
||||
@@ -96,13 +95,13 @@
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Error Mapping
|
||||
// =============================================================================
|
||||
// =============================================================================
|
||||
// Error Mapping
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Map Drive API error to HTTP status code and retry info
|
||||
*
|
||||
* Per specification:
|
||||
@@ -114,7 +113,7 @@
|
||||
* @param {Error} error - Drive API error
|
||||
* @returns {Object} { statusCode, retryAfter? }
|
||||
*/
|
||||
function mapDriveErrorToHttp(error) {
|
||||
function mapDriveErrorToHttp(error) {
|
||||
// Handle DocumentCountExceededError
|
||||
if (error instanceof DocumentCountExceededError) {
|
||||
return { statusCode: 413 };
|
||||
@@ -147,13 +146,13 @@
|
||||
|
||||
// All other errors map to 500
|
||||
return { statusCode: 500 };
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Sitemap Functions
|
||||
// =============================================================================
|
||||
// =============================================================================
|
||||
// Sitemap Functions
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Transform Drive document to sitemap entry
|
||||
*
|
||||
* Creates RESTful URL in format: {baseUrl}/documents/{documentId}
|
||||
@@ -165,7 +164,7 @@
|
||||
* @param {string} baseUrl - Base URL for the adapter
|
||||
* @returns {Object} Sitemap entry { loc, lastmod }
|
||||
*/
|
||||
function toSitemapEntry(document, baseUrl) {
|
||||
function toSitemapEntry(document, baseUrl) {
|
||||
if (!document || !document.id) {
|
||||
console.error("Invalid document for sitemap entry", { document });
|
||||
return null;
|
||||
@@ -192,16 +191,16 @@
|
||||
}
|
||||
|
||||
return { loc, lastmod };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Transform array of Drive documents to sitemap entries
|
||||
*
|
||||
* @param {Array<Object>} documents - Array of Drive API documents
|
||||
* @param {string} baseUrl - Base URL for the adapter
|
||||
* @returns {Array<Object>} Array of sitemap entries
|
||||
*/
|
||||
function transformDocumentsToSitemapEntries(documents, baseUrl) {
|
||||
function transformDocumentsToSitemapEntries(documents, baseUrl) {
|
||||
if (!Array.isArray(documents)) {
|
||||
console.error("Documents must be an array", { documents });
|
||||
return [];
|
||||
@@ -210,9 +209,9 @@
|
||||
return documents
|
||||
.map((doc) => toSitemapEntry(doc, baseUrl))
|
||||
.filter((entry) => entry !== null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Generate XML sitemap from sitemap entries
|
||||
*
|
||||
* Handles empty sitemap (0 documents) case - returns valid XML with empty urlset.
|
||||
@@ -220,7 +219,7 @@
|
||||
* @param {Array<Object>} sitemapEntries - Array of { loc, lastmod } objects
|
||||
* @returns {string} Complete XML sitemap string
|
||||
*/
|
||||
function generateSitemapXML(sitemapEntries) {
|
||||
function generateSitemapXML(sitemapEntries) {
|
||||
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
||||
xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';
|
||||
|
||||
@@ -240,9 +239,9 @@
|
||||
xml += "</urlset>";
|
||||
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Main sitemap generation function
|
||||
*
|
||||
* Combines document transformation and XML generation.
|
||||
@@ -251,22 +250,22 @@
|
||||
* @param {string} baseUrl - Base URL for the adapter
|
||||
* @returns {string} Complete XML sitemap
|
||||
*/
|
||||
function generateSitemap(documents, baseUrl) {
|
||||
function generateSitemap(documents, baseUrl) {
|
||||
const entries = transformDocumentsToSitemapEntries(documents, baseUrl);
|
||||
return generateSitemapXML(entries);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Route Parsing
|
||||
// =============================================================================
|
||||
// =============================================================================
|
||||
// Route Parsing
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Parse route from request
|
||||
* @param {string} method - HTTP method
|
||||
* @param {string} url - Request URL
|
||||
* @returns {Object} Route info or error
|
||||
*/
|
||||
function parseRoute(method, url) {
|
||||
function parseRoute(method, url) {
|
||||
if (method !== "GET") {
|
||||
return { route: null, error: "Method not allowed", statusCode: 405 };
|
||||
}
|
||||
@@ -279,35 +278,35 @@
|
||||
return { route: "sitemap" };
|
||||
}
|
||||
|
||||
// All other paths return 404
|
||||
return { route: null, error: "Not found", statusCode: 404 };
|
||||
}
|
||||
// =============================================================================
|
||||
// Return helpers object with all functions
|
||||
// =============================================================================
|
||||
// All other paths return 404
|
||||
return { route: null, error: "Not found", statusCode: 404 };
|
||||
}
|
||||
|
||||
return {
|
||||
// Error classes
|
||||
DocumentCountExceededError,
|
||||
// =============================================================================
|
||||
// Return helpers object with all functions
|
||||
// =============================================================================
|
||||
|
||||
// Utilities
|
||||
generateRequestId,
|
||||
validateDocumentId,
|
||||
validateDocumentCount,
|
||||
({
|
||||
// Error classes
|
||||
DocumentCountExceededError,
|
||||
|
||||
// XML
|
||||
escapeXml,
|
||||
// Utilities
|
||||
generateRequestId,
|
||||
validateDocumentId,
|
||||
validateDocumentCount,
|
||||
|
||||
// Error mapping
|
||||
mapDriveErrorToHttp,
|
||||
// XML
|
||||
escapeXml,
|
||||
|
||||
// Sitemap
|
||||
toSitemapEntry,
|
||||
transformDocumentsToSitemapEntries,
|
||||
generateSitemapXML,
|
||||
generateSitemap,
|
||||
// Error mapping
|
||||
mapDriveErrorToHttp,
|
||||
|
||||
// Routing
|
||||
parseRoute,
|
||||
};
|
||||
})();
|
||||
// Sitemap
|
||||
toSitemapEntry,
|
||||
transformDocumentsToSitemapEntries,
|
||||
generateSitemapXML,
|
||||
generateSitemap,
|
||||
|
||||
// Routing
|
||||
parseRoute,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user