{"version":3,"sources":["../src/baseOAuth/types/index.ts","../src/baseOAuth/core/apiFunctions.ts","../src/baseOAuth/core/oauth.ts","../src/baseOAuth/utils/validation.ts","../src/googleDriveOAuth/types/index.ts","../src/googleDriveOAuth/core/apiFunctions.ts","../src/googleDriveOAuth/utils/token.ts","../src/baseOAuth/ui/picker.ts","../src/googleDriveOAuth/ui/picker.ts","../src/googleDriveOAuth/core/oauth.ts","../src/baseOAuth/core/selection.ts","../src/googleDriveOAuth/core/selection.ts","../src/dropBoxOAuth/types/index.ts","../src/dropBoxOAuth/core/apiFunctions.ts","../src/dropBoxOAuth/utils/token.ts","../src/dropBoxOAuth/ui/picker.ts","../src/dropBoxOAuth/core/oauth.ts","../src/dropBoxOAuth/core/selection.ts","../src/notionOAuth/types/index.ts","../src/notionOAuth/core/apiFunctions.ts","../src/notionOAuth/utils/token.ts","../src/notionOAuth/ui/picker.ts","../src/notionOAuth/core/oauth.ts"],"names":["OAuthError","message","code","details","ConfigurationError","TokenError","createSourceConnector","config","connector","platformUrl","_a","url","response","errorData","data","connectorId","manageUser","userId","action","payload","method","requestPayload","__spreadValues","getOneTimeConnectorToken","BaseOAuth","authUrl","popupTitle","left","top","popup","onSuccess","onError","error","checkPopup","nonce","htmlContent","options","width","height","timeoutMs","originPattern","successMessage","resolve","reject","iframe","container","closeButton","cleanupIframe","timeout","messageHandler","event","oneTimeToken","organizationId","validateConfig","createErrorResponse","GoogleDriveConnectorType","createVectorizeGDriveConnector","connectorName","createWhiteLabelGDriveConnector","clientId","clientSecret","manageGDriveUser","selectedFiles","refreshToken","exchangeGDriveCodeForTokens","redirectUri","tokenUrl","params","refreshGDriveToken","BasePicker","tokens","preSelectedFiles","title","styles","head","body","scripts","GoogleDrivePicker","_GoogleDrivePicker","ui","googleDriveWarning","googleDriveScripts","googleHead","GoogleDriveOAuth","gDriveConfig","_b","scopes","errorObj","connectUrl","editUrl","BaseSelection","content","GoogleDriveSelection","_GoogleDriveSelection","targetWindow","DropboxConnectorType","createVectorizeDropboxConnector","createWhiteLabelDropboxConnector","appKey","appSecret","manageDropboxUser","exchangeDropboxCodeForTokens","refreshDropboxToken","DropboxPicker","_DropboxPicker","dropboxScripts","DropboxOAuth","dropboxConfig","DropboxSelection","_DropboxSelection","NotionConnectorType","createVectorizeNotionConnector","innerError","errorDetails","errorMatch","jsonStr","e","errorKeys","key","value","displayValue","err","outerError","enhancedMessage","createWhiteLabelNotionConnector","manageNotionUser","selectedPages","accessToken","exchangeNotionCodeForTokens","refreshNotionToken","userData","workspaceResponse","workspaceData","NotionPicker","existingSelection","existingSelectionStr","NotionOAuth","notionConfig"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAAA,EAkYIpG,CAAQ,CAAA,CAAA,QAAA,EAAWA,CAAK,CAAA,CAAA,CAAA,CAAM,EAAE,CAAA;AAAA;AAAA,8BAAA,EAEfqG,CAAoB,CAAA;AAAA;AAAA,6BAAA,EAErBR,CAAW,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","file":"index.mjs","sourcesContent":["/**\n * Base error class for OAuth related errors\n */\nexport class OAuthError extends Error {\n    constructor(\n      message: string,\n      public code: string,\n      public details?: any\n    ) {\n      super(message);\n      this.name = 'OAuthError';\n    }\n  }\n  \n  /**\n   * Error thrown when there's a problem with configuration\n   */\n  export class ConfigurationError extends OAuthError {\n    constructor(message: string, details?: any) {\n      super(message, 'CONFIGURATION_ERROR', details);\n      this.name = 'ConfigurationError';\n    }\n  }\n  \n  /**\n   * Error thrown during token exchange or refresh\n   */\n  export class TokenError extends OAuthError {\n    constructor(message: string, details?: any) {\n      super(message, 'TOKEN_ERROR', details);\n      this.name = 'TokenError';\n    }\n  }\n  \n  /**\n   * Base configuration options for OAuth authentication\n   */\n  export interface OAuthConfig {\n    redirectUri: string;\n    scopes?: string[];\n    nonce?: string;\n    onSuccess?: (selectedFields?: any) => void;\n    onError?: (error: OAuthError) => void;\n  }\n  \n  /**\n   * Response from OAuth token exchange\n   */\n  export interface OAuthResponse {\n    access_token: string;\n    refresh_token: string;\n    expires_in: number;\n    token_type: string;\n  }\n  \n  /**\n   * Generic file interface that can be extended by specific connectors\n   */\n  export interface GenericFile {\n    id: string;\n    name: string;\n    mimeType: string;\n  }\n  \n  /**\n   * Generic selection result that can be extended by specific connectors\n   */\n  export interface GenericSelection {\n    files: GenericFile[];\n  }\n  \n  /**\n   * Configuration for Vectorize API\n   */\n  export interface VectorizeAPIConfig {\n    authorization: string;\n    organizationId: string;\n  }\n  \n  /**\n   * Generic connector configuration for Vectorize API\n   */\n  export interface ConnectorConfig {\n    name: string;\n    type: string;\n    config?: Record<string, any>;\n  }\n  \n  /**\n   * Actions that can be performed when managing users\n   */\n  export type UserAction = \"add\" | \"edit\" | \"remove\";","import { VectorizeAPIConfig, ConnectorConfig, UserAction } from \"../types\";\n\n/**\n * Create a connector source via the Vectorize API.\n *\n * @param config - An object containing your organization ID and authorization token\n * @param connector - Connector configuration including name, type, and optional config\n * @param platformUrl - URL of the Vectorize API (primarily used for testing)\n *\n * @returns A Promise that resolves with the connector ID that is created\n */\nexport async function createSourceConnector(\n  config: VectorizeAPIConfig,\n  connector: ConnectorConfig,\n  platformUrl: string = \"https://api.vectorize.io/v1\",\n): Promise<string> {\n  const url = `${platformUrl}/org/${config.organizationId}/connectors/sources`;\n\n  const response = await fetch(url, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      \"Authorization\": `Bearer ${config.authorization}`\n    },\n    body: JSON.stringify(connector),\n  });\n\n  if (!response.ok) {\n    const errorData = await response.json();\n    throw new Error(`Failed to create connector. Status: ${response.status}, Error: ${errorData.error || JSON.stringify(errorData)}`);\n  }\n\n  // Parse response JSON\n  const data = (await response.json());\n\n  // Get the connector ID from the response\n  const connectorId = data?.connector?.id;\n  if (!connectorId) {\n    throw new Error(\"No connector ID found in the response.\");\n  }\n\n  return connectorId;\n}\n\n/**\n * Manages a user for a connector, allowing you to add, edit, or remove users.\n *\n * @param config VectorizeAPIConfig containing authorization and organizationId\n * @param connectorId ID of the connector\n * @param userId User ID to manage\n * @param action Action to perform (\"add\", \"edit\", or \"remove\")\n * @param payload Additional payload for the request (varies by connector type)\n * @param platformUrl Optional URL of the Vectorize API (primarily used for testing)\n * @returns Promise that resolves with the API response\n */\nexport async function manageUser(\n  config: VectorizeAPIConfig,\n  connectorId: string,\n  userId: string,\n  action: UserAction,\n  payload: Record<string, any> = {},\n  platformUrl: string = \"https://api.vectorize.io/v1\",\n): Promise<Response> {\n  const url = `${platformUrl}/org/${config.organizationId}/connectors/sources/${connectorId}/users/`;\n\n  let method: string;\n  \n  switch (action) {\n    case \"add\":\n      method = \"POST\";\n      break;\n    case \"edit\":\n      method = \"PATCH\";\n      break;\n    case \"remove\":\n      method = \"DELETE\";\n      break;\n    default:\n      throw new Error(\"Invalid action\");\n  }\n\n  // Create the base payload with userId\n  const requestPayload = { \n    userId,\n    ...payload\n  };\n\n  const response = await fetch(url, {\n    method: method,\n    headers: {\n      \"Content-Type\": \"application/json\",\n      \"Authorization\": `Bearer ${config.authorization}`\n    },\n    body: JSON.stringify(requestPayload),\n  });\n\n  if (!response.ok) {\n    const errorData = await response.json();\n    throw new Error(`Failed to manage user. Status: ${response.status}, Error: ${errorData.error || JSON.stringify(errorData)}`);\n  }\n\n  return response;\n}\n\n/**\n * Gets a one-time authentication token for connector operations\n *\n * @param config VectorizeAPIConfig containing authorization and organizationId\n * @param userId User ID to include in the token\n * @param connectorId Connector ID to include in the token\n * @param platformUrl Optional URL of the Vectorize API (primarily used for testing)\n * @returns Promise that resolves with the token response\n */\nexport async function getOneTimeConnectorToken(\n  config: VectorizeAPIConfig,\n  userId: string,\n  connectorId: string,\n  platformUrl: string = \"https://api.vectorize.io/v1\"\n): Promise<{ token: string; expires_at: number; ttl: number }> {\n  const url = `${platformUrl}/org/${config.organizationId}/generateOneTimeConnectorToken`;\n\n  const response = await fetch(url, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      \"Authorization\": `Bearer ${config.authorization}`\n    },\n    body: JSON.stringify({\n      user_id: userId,\n      connector_id: connectorId\n    })\n  });\n\n  if (!response.ok) {\n    const errorData = await response.json();\n    throw new Error(`Failed to generate token. Status: ${response.status}, Error: ${errorData.error || JSON.stringify(errorData)}`);\n  }\n\n  return await response.json();\n}","import { OAuthConfig, OAuthError, OAuthResponse } from '../types';\n\n/**\n * Base OAuth class that provides common functionality for all OAuth connectors\n */\nexport abstract class BaseOAuth {\n  /**\n   * Validates the OAuth configuration\n   * @param config The OAuth configuration to validate\n   * @throws OAuthError if configuration is invalid\n   */\n  protected static validateConfig(config: OAuthConfig): void {\n    // Base validation for common OAuth fields\n    if (!config.redirectUri) {\n      throw new OAuthError('Missing redirectUri in configuration', 'CONFIGURATION_ERROR');\n    }\n\n    // Custom validation for specific connector implementations\n    this.validateConnectorConfig(config);\n  }\n\n  /**\n   * To be implemented by subclasses for connector-specific configuration validation\n   * @param config The OAuth configuration to validate\n   * @throws OAuthError if configuration is invalid\n   */\n  protected static validateConnectorConfig(config: OAuthConfig): void {\n    // To be implemented by subclasses\n  }\n\n  /**\n   * Creates an OAuth popup window for authentication\n   * @param authUrl The authorization URL to open in the popup\n   * @param popupTitle The title for the popup window\n   * @returns The popup window instance or null if creation failed\n   */\n  protected static createOAuthPopup(authUrl: string, popupTitle: string = 'OAuth Login'): Window | null {\n    // Create a new popup window with centered positioning\n    const width = 1200;\n    const height = 800;\n    const left = window.screenX + (window.outerWidth - width) / 2;\n    const top = window.screenY + (window.outerHeight - height) / 2;\n\n    const popup = window.open(\n      authUrl,\n      popupTitle,\n      `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`\n    );\n\n    if (!popup) {\n      throw new OAuthError(\n        'Failed to open popup window. Please check if popups are blocked.',\n        'POPUP_BLOCKED'\n      );\n    }\n\n    return popup;\n  }\n\n  /**\n   * Cleans up OAuth handler from window object\n   */\n  protected static cleanupOAuthHandler(): void {\n    delete (window as any).__oauthHandler;\n  }\n\n  /**\n   * Sets up OAuth handler in window object for callback\n   * @param config The OAuth configuration\n   */\n  protected static setupOAuthHandler(config: OAuthConfig): void {\n    const { onSuccess, onError } = config;\n\n    // Store configuration for the callback to access\n    (window as any).__oauthHandler = {\n      onSuccess,\n      onError: (error: string | OAuthError) => {\n        if (typeof error === 'string') {\n          error = new OAuthError(error, 'UNKNOWN_ERROR');\n        }\n        onError?.(error);\n      },\n      OAuthError // Make error constructor available to the popup\n    };\n  }\n\n  /**\n   * Monitor popup and cleanup when closed\n   * @param popup The popup window to monitor\n   */\n  protected static monitorPopup(popup: Window): void {\n    const checkPopup = setInterval(() => {\n      if (popup && popup.closed) {\n        clearInterval(checkPopup);\n        this.cleanupOAuthHandler();\n      }\n    }, 500);\n  }\n\n  /**\n   * Abstract method to start the OAuth flow\n   * To be implemented by subclasses\n   * @param config The OAuth configuration\n   * @returns The popup window instance or null if creation failed\n   */\n  public static startOAuth(config: OAuthConfig): Window | null {\n    throw new Error('Method not implemented');\n  }\n\n  /**\n   * Create an error response for the OAuth callback\n   * @param error The error to include in the response\n   * @param nonce Optional nonce for Content Security Policy\n   * @returns A Response object with the error\n   */\n  protected static createErrorResponse(error: OAuthError, nonce?: string): Response {\n    const htmlContent = `\n      <!DOCTYPE html>\n      <html>\n      <head>\n        <title>Authentication Error</title>\n        <style>\n          body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }\n          .error { color: #f44336; }\n        </style>\n        <script${nonce ? ` nonce=\"${nonce}\"` : ''}>\n          window.onload = function() {\n            if (window.opener && window.opener.__oauthHandler) {\n              const errorObj = ${JSON.stringify({\n                message: error.message,\n                code: error.code,\n                details: error.details\n              })};\n\n              window.opener.__oauthHandler.onError(\n                new window.opener.__oauthHandler.OAuthError(\n                  errorObj.message,\n                  errorObj.code,\n                  errorObj.details\n                )\n              );\n              window.close();\n            }\n          };\n        </script>\n      </head>\n      <body>\n        <h2 class=\"error\">Authentication Error</h2>\n        <p>${error.message}</p>\n        <p>This window will close automatically.</p>\n      </body>\n      </html>\n    `;\n\n    return new Response(htmlContent, { headers: { 'Content-Type': 'text/html' } });\n  }\n\n  /**\n   * Abstract method to create a callback response\n   * To be implemented by subclasses\n   * @param code Authorization code from the OAuth redirect\n   * @param config The OAuth configuration\n   * @param error Optional error from the OAuth process\n   * @returns A Response object with the callback page\n   */\n  public static createCallbackResponse(\n    code: string,\n    config: OAuthConfig,\n    error?: string | OAuthError\n  ): Promise<Response> {\n    throw new Error('Method not implemented');\n  }\n\n  /**\n   * Creates an iframe for connecting to a platform\n   * @param url The URL to load in the iframe\n   * @param options Configuration options for the iframe\n   * @returns A promise that resolves when the iframe is closed or errors\n   */\n  protected static createConnectIframe(\n    url: string,\n    options: {\n      width?: string;\n      height?: string;\n      timeoutMs?: number;\n      originPattern?: RegExp;\n      successMessage?: string;\n    } = {}\n  ): Promise<void> {\n    const {\n      width = '40%',\n      height = '40%',\n      timeoutMs = 5 * 60 * 1000, // 5 minutes default\n      originPattern = /vectorize\\.io$/,\n      successMessage = 'connect-complete'\n    } = options;\n\n    return new Promise<void>((resolve, reject) => {\n      try {\n        // Create iframe element\n        const iframe = document.createElement('iframe');\n        iframe.src = url;\n        iframe.style.width = '100%';\n        iframe.style.height = '100%';\n        iframe.style.border = 'none';\n        iframe.style.backgroundColor = 'white';\n        \n        // Create a container for the iframe and close button\n        const container = document.createElement('div');\n        container.style.position = 'fixed';\n        container.style.top = '50%';\n        container.style.left = '50%';\n        container.style.transform = 'translate(-50%, -50%)';\n        container.style.width = width;\n        container.style.height = height;\n        container.style.zIndex = '9999';\n        container.style.borderRadius = '8px';\n        container.style.overflow = 'hidden';\n        container.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)';\n        \n        // Create a close button inside the iframe container\n        const closeButton = document.createElement('button');\n        closeButton.textContent = '✕';\n        closeButton.style.position = 'absolute';\n        closeButton.style.top = '10px';\n        closeButton.style.right = '10px';\n        closeButton.style.zIndex = '10000';\n        closeButton.style.backgroundColor = '#f44336';\n        closeButton.style.color = 'white';\n        closeButton.style.border = 'none';\n        closeButton.style.borderRadius = '50%';\n        closeButton.style.width = '30px';\n        closeButton.style.height = '30px';\n        closeButton.style.fontSize = '16px';\n        closeButton.style.cursor = 'pointer';\n        closeButton.style.display = 'flex';\n        closeButton.style.alignItems = 'center';\n        closeButton.style.justifyContent = 'center';\n        \n        // Add the iframe and close button to the container\n        container.appendChild(iframe);\n        container.appendChild(closeButton);\n        \n        // Function to clean up the container and resolve the promise\n        const cleanupIframe = () => {\n          if (document.body.contains(container)) {\n            document.body.removeChild(container);\n          }\n          \n          clearTimeout(timeout);\n          resolve();\n        };\n        \n        // Add event listener to close button\n        closeButton.addEventListener('click', cleanupIframe);\n        \n        // Add the container to the document\n        document.body.appendChild(container);\n        \n        // Add a message event listener to detect when the iframe is done\n        window.addEventListener('message', function messageHandler(event) {\n          // Check if the message is from the expected origin\n          if (originPattern.test(event.origin)) {\n            if (event.data === successMessage) {\n              // Connection process completed\n              window.removeEventListener('message', messageHandler);\n              cleanupIframe();\n            }\n          }\n        });\n        \n        // Add a timeout\n        const timeout = setTimeout(() => {\n          cleanupIframe();\n          reject(new Error(`Operation timed out after ${timeoutMs/1000} seconds`));\n        }, timeoutMs);\n      } catch (error) {\n        reject(error);\n      }\n    });\n  }\n\n  /**\n   * Abstract method to redirect to Vectorize platform connect\n   * To be implemented by subclasses\n   * @param oneTimeToken The token for authentication\n   * @param organizationId The organization ID\n   * @param platformUrl The platform URL\n   */\n  public static redirectToVectorizeConnect(\n    oneTimeToken: string,\n    organizationId: string,\n    platformUrl: string\n  ): Promise<void> {\n    throw new Error('Method not implemented');\n  }\n\n  /**\n   * Abstract method to redirect to Vectorize platform for editing files\n   * To be implemented by subclasses\n   * @param oneTimeToken The token for authentication\n   * @param organizationId The organization ID\n   * @param platformUrl The platform URL\n   */\n  public static redirectToVectorizeEdit(\n    oneTimeToken: string,\n    organizationId: string,\n    platformUrl: string\n  ): Promise<void> {\n    throw new Error('Method not implemented');\n  }\n}","import { OAuthConfig, OAuthError } from '../types';\n\n/**\n * Validates the basic OAuth configuration\n * @param config The OAuth configuration to validate\n * @throws OAuthError if configuration is invalid\n */\nexport function validateConfig(config: OAuthConfig): void {\n  if (!config) {\n    throw new OAuthError('Missing configuration', 'CONFIGURATION_ERROR');\n  }\n\n  if (!config.redirectUri) {\n    throw new OAuthError('Missing redirectUri in configuration', 'CONFIGURATION_ERROR');\n  }\n\n  // Validate callback functions exist\n  if (!config.onSuccess) {\n    throw new OAuthError('Missing onSuccess callback in configuration', 'CONFIGURATION_ERROR');\n  }\n  \n  if (!config.onError) {\n    throw new OAuthError('Missing onError callback in configuration', 'CONFIGURATION_ERROR');\n  }\n}\n\n/**\n * Creates an error response for OAuth callbacks\n * @param error The error to include in the response\n * @param nonce Optional nonce for Content Security Policy\n * @returns A Response object with the error\n */\nexport function createErrorResponse(error: OAuthError, nonce?: string): Response {\n  const htmlContent = `\n    <!DOCTYPE html>\n    <html>\n    <head>\n      <title>Authentication Error</title>\n      <style>\n        body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }\n        .error { color: #f44336; }\n      </style>\n      <script${nonce ? ` nonce=\"${nonce}\"` : ''}>\n        window.onload = function() {\n          if (window.opener && window.opener.__oauthHandler) {\n            const errorObj = ${JSON.stringify({\n              message: error.message,\n              code: error.code,\n              details: error.details\n            })};\n\n            window.opener.__oauthHandler.onError(\n              new window.opener.__oauthHandler.OAuthError(\n                errorObj.message,\n                errorObj.code,\n                errorObj.details\n              )\n            );\n            window.close();\n          }\n        };\n      </script>\n    </head>\n    <body>\n      <h2 class=\"error\">Authentication Error</h2>\n      <p>${error.message}</p>\n      <p>This window will close automatically.</p>\n    </body>\n    </html>\n  `;\n\n  return new Response(htmlContent, { headers: { 'Content-Type': 'text/html' } });\n}","import { \n  OAuthConfig, \n  OAuthError, \n  OAuthResponse, \n  GenericFile, \n  GenericSelection \n} from '../../baseOAuth/types';\n\n/**\n * Google Drive specific configuration options \n */\nexport interface GoogleDriveOAuthConfig extends OAuthConfig {\n  clientId: string;      // Google OAuth client ID\n  clientSecret: string;  // Google OAuth client secret\n  apiKey: string;        // Google API key for the Picker API\n}\n\n/**\n * Error thrown from the Google Drive picker\n */\nexport class PickerError extends OAuthError {\n  constructor(message: string, details?: any) {\n    super(message, 'PICKER_ERROR', details);\n    this.name = 'PickerError';\n  }\n}\n\n/**\n * Represents a file in Google Drive\n */\nexport interface DriveFile extends GenericFile {\n  // Add Google Drive specific properties if needed\n}\n\n/**\n * Selection result from the Google Drive picker\n */\nexport interface DriveSelection extends GenericSelection {\n  files: DriveFile[];\n}\n\n/**\n * Google Drive connector types\n */\nexport enum GoogleDriveConnectorType {\n  VECTORIZE = \"GOOGLE_DRIVE_OAUTH_MULTI\",\n  WHITE_LABEL = \"GOOGLE_DRIVE_OAUTH_MULTI_CUSTOM\"\n}","import { \n  VectorizeAPIConfig, \n  ConnectorConfig,\n  UserAction \n} from \"../../baseOAuth/types\";\nimport { \n  createSourceConnector, \n  manageUser, \n  getOneTimeConnectorToken as baseGetOneTimeConnectorToken \n} from \"../../baseOAuth/core/apiFunctions\";\nimport { GoogleDriveConnectorType } from \"../types\";\n\n/**\n * Create a Vectorize Google Drive OAuth Connector Source.\n *\n * @param config - An object containing your organization ID and authorization token\n * @param connectorName - Name for the connector\n * @param platformUrl - URL of the Vectorize API (primarily used for testing)\n *\n * @returns A Promise that resolves with the connector ID\n */\nexport async function createVectorizeGDriveConnector(\n  config: VectorizeAPIConfig,\n  connectorName: string,\n  platformUrl: string = \"https://api.vectorize.io/v1\",\n): Promise<string> {\n  const connector: ConnectorConfig = {\n    name: connectorName,\n    type: GoogleDriveConnectorType.VECTORIZE\n  };\n\n  return createSourceConnector(config, connector, platformUrl);\n}\n\n/**\n * Create a White Label Google Drive OAuth Connector Source.\n *\n * @param config - An object containing your organization ID and authorization token\n * @param connectorName - Name for the connector\n * @param clientId - OAuth2 client ID for the white label connector\n * @param clientSecret - OAuth2 client secret for the white label connector\n * @param platformUrl - URL of the Vectorize API (primarily used for testing)\n *\n * @returns A Promise that resolves with the connector ID\n */\nexport async function createWhiteLabelGDriveConnector(\n  config: VectorizeAPIConfig,\n  connectorName: string,\n  clientId: string,\n  clientSecret: string,\n  platformUrl: string = \"https://api.vectorize.io/v1\",\n): Promise<string> {\n  if (!clientId || !clientSecret) {\n    throw new Error(\"Client ID and Client Secret are required for white label connectors\");\n  }\n\n  const connector: ConnectorConfig = {\n    name: connectorName,\n    type: GoogleDriveConnectorType.WHITE_LABEL,\n    config: {\n      \"oauth2-client-id\": clientId,\n      \"oauth2-client-secret\": clientSecret\n    }\n  };\n\n  return createSourceConnector(config, connector, platformUrl);\n}\n\n/**\n * Manages a Google Drive user for a connector, allowing you to add, edit, or remove users.\n *\n * @param config VectorizeAPIConfig containing authorization and organizationId\n * @param connectorId ID of the connector\n * @param selectedFiles Record of selected files with their metadata\n * @param refreshToken Google OAuth refresh token\n * @param userId User ID to manage\n * @param action Action to perform (\"add\", \"edit\", or \"remove\")\n * @param platformUrl Optional URL of the Vectorize API (primarily used for testing)\n * @returns Promise that resolves with the API response\n */\nexport async function manageGDriveUser(\n  config: VectorizeAPIConfig,\n  connectorId: string,\n  selectedFiles: Record<string, { name: string; mimeType: string }> | null,\n  refreshToken: string,\n  userId: string,\n  action: UserAction,\n  platformUrl: string = \"https://api.vectorize.io/v1\",\n): Promise<Response> {\n  // Validate required parameters for add/edit actions\n  if (action === \"add\" || action === \"edit\") {\n    if (!selectedFiles || Object.keys(selectedFiles).length === 0) {\n      throw new Error(`Selected files are required for ${action} action`);\n    }\n    \n    if (!refreshToken) {\n      throw new Error(`Refresh token is required for ${action} action`);\n    }\n  }\n  \n  // Create the Google Drive specific payload\n  const payload: Record<string, any> = {};\n  \n  // Only include selectedFiles and refreshToken for add/edit, not for remove\n  if (action !== \"remove\") {\n    payload.selectedFiles = selectedFiles;\n    payload.refreshToken = refreshToken;\n  }\n\n  return manageUser(config, connectorId, userId, action, payload, platformUrl);\n}\n\n/**\n * Gets a one-time authentication token for connector operations\n * This is a direct re-export of the base function for consistency\n */\nexport const getOneTimeConnectorToken = baseGetOneTimeConnectorToken;","import { OAuthResponse } from '../../baseOAuth/types';\nimport { TokenError } from '../../baseOAuth/types';\n\n/**\n * Exchanges an authorization code for access and refresh tokens\n * @param code The authorization code from OAuth redirect\n * @param clientId The OAuth client ID\n * @param clientSecret The OAuth client secret\n * @param redirectUri The OAuth redirect URI\n * @returns An object containing the tokens\n */\nexport async function exchangeGDriveCodeForTokens(\n  code: string,\n  clientId: string,\n  clientSecret: string,\n  redirectUri: string\n): Promise<OAuthResponse> {\n  try {\n    const tokenUrl = 'https://oauth2.googleapis.com/token';\n    const params = new URLSearchParams({\n      code,\n      client_id: clientId,\n      client_secret: clientSecret,\n      redirect_uri: redirectUri,\n      grant_type: 'authorization_code'\n    });\n\n    const response = await fetch(tokenUrl, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded'\n      },\n      body: params.toString()\n    });\n\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => ({}));\n      throw new TokenError(\n        `Token exchange failed: ${errorData.error || response.statusText}`,\n        errorData\n      );\n    }\n\n    const data = await response.json();\n    return {\n      access_token: data.access_token,\n      refresh_token: data.refresh_token,\n      expires_in: data.expires_in,\n      token_type: data.token_type\n    };\n  } catch (error) {\n    if (error instanceof TokenError) {\n      throw error;\n    }\n    throw new TokenError(\n      error instanceof Error ? error.message : 'Token exchange failed',\n      error\n    );\n  }\n}\n\n/**\n * Refreshes an access token using a refresh token\n * @param refreshToken The refresh token\n * @param clientId The OAuth client ID\n * @param clientSecret The OAuth client secret\n * @returns An object containing the new access token\n */\nexport async function refreshGDriveToken(\n  refreshToken: string,\n  clientId: string,\n  clientSecret: string\n): Promise<{\n  access_token: string;\n  expires_in: number;\n  token_type: string;\n}> {\n  try {\n    const tokenUrl = 'https://oauth2.googleapis.com/token';\n    const params = new URLSearchParams({\n      refresh_token: refreshToken,\n      client_id: clientId,\n      client_secret: clientSecret,\n      grant_type: 'refresh_token'\n    });\n\n    const response = await fetch(tokenUrl, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded'\n      },\n      body: params.toString()\n    });\n\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => ({}));\n      throw new TokenError(\n        `Token refresh failed: ${errorData.error || response.statusText}`,\n        errorData\n      );\n    }\n\n    const data = await response.json();\n    return {\n      access_token: data.access_token,\n      expires_in: data.expires_in,\n      token_type: data.token_type\n    };\n  } catch (error) {\n    if (error instanceof TokenError) {\n      throw error;\n    }\n    throw new TokenError(\n      error instanceof Error ? error.message : 'Token refresh failed',\n      error\n    );\n  }\n}","import { OAuthResponse, OAuthConfig } from '../types';\n\n/**\n * Base Picker class providing common file selection functionality\n * Can be extended by specific connector implementations\n */\nexport abstract class BasePicker {\n  /**\n   * Abstract method to create HTML template for the picker page\n   * Must be implemented by subclasses for connector-specific picker UI\n   * \n   * @param tokens OAuth tokens for API access\n   * @param config Configuration with necessary credentials\n   * @param refreshToken Refresh token to include in selection data\n   * @param preSelectedFiles Optional map of files to initialize as selected\n   * @returns HTML string for the picker interface\n   */\n  abstract createPickerHTML(\n    tokens: OAuthResponse, \n    config: OAuthConfig, \n    refreshToken: string, \n    preSelectedFiles?: Record<string, { name: string; mimeType: string }>\n  ): string;\n\n  /**\n   * Generates common UI elements for the picker\n   * This can be used by subclass implementations to maintain a consistent look\n   * \n   * @returns Object containing HTML template strings\n   */\n  protected getCommonUIElements(): { \n    header: string; \n    warning: string; \n    fileListContainer: string; \n    submitButtonContainer: string; \n    scripts: {\n      basePickerScript: (tokens: any, config: any, refreshToken: string, preSelectedFiles: any) => string;\n    }\n  } {\n    return {\n      header: `\n        <div class=\"flex justify-between items-center\">\n          <h1 class=\"text-2xl font-bold\">Selected Files and Folders</h1>\n          <button\n            id=\"selectMoreButton\"\n            class=\"bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 transition-colors\"\n          >\n            Select Files/Folders\n          </button>\n        </div>\n      `,\n      warning: `\n        <div class=\"bg-yellow-50 border-l-4 border-yellow-400 p-4 my-4\">\n          <div class=\"flex\">\n            <div class=\"flex-shrink-0\">\n              <svg class=\"h-5 w-5 text-yellow-400\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n                <path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />\n              </svg>\n            </div>\n            <div class=\"ml-3\">\n              <p class=\"text-sm text-yellow-700\">\n                <span class=\"font-medium\">Important:</span> Some files might have limitations when accessed through the API. Please check the file compatibility with this connector.\n              </p>\n            </div>\n          </div>\n        </div>\n      `,\n      fileListContainer: `\n        <div id=\"fileList\" class=\"space-y-4\">\n          <p>No files selected</p>\n        </div>\n      `,\n      submitButtonContainer: `\n        <div id=\"submitButton\" class=\"flex justify-end mt-6\" style=\"display: none;\">\n          <button\n            id=\"finishButton\"\n            class=\"bg-green-500 text-white px-6 py-3 rounded-lg hover:bg-green-600 transition-colors\"\n          >\n            Finish Selection\n          </button>\n        </div>\n      `,\n      scripts: {\n        basePickerScript: (tokens, config, refreshToken, preSelectedFiles) => `\n          const tokens = ${JSON.stringify(tokens)};\n          const config = ${JSON.stringify(config)};\n          const refreshToken = ${JSON.stringify(refreshToken)};\n          const preSelectedFiles = ${JSON.stringify(preSelectedFiles || {})};\n          let selectedFiles = [];\n          \n          // Initialize selected files from pre-selected ones if provided\n          if (preSelectedFiles && Object.keys(preSelectedFiles).length > 0) {\n            selectedFiles = Object.entries(preSelectedFiles).map(([id, details]) => ({\n              id,\n              name: details.name,\n              mimeType: details.mimeType\n            }));\n          }\n  \n          function handleError(error) {\n            const errorObj = new (window.opener.OAuthError || Error)(\n              error.message || 'An error occurred in the picker',\n              error.code || 'PICKER_ERROR',\n              error.details\n            );\n            window.opener.__oauthHandler.onError(errorObj);\n            window.close();\n          }\n  \n          function updateFileList() {\n            const fileList = document.getElementById('fileList');\n            const submitButton = document.getElementById('submitButton');\n  \n            if (selectedFiles.length === 0) {\n              fileList.innerHTML = '<p>No files selected</p>';\n              submitButton.style.display = 'none';\n              return;\n            }\n  \n            fileList.innerHTML = selectedFiles.map(file =>\n              \\`<div class=\"group p-4 border rounded-lg flex justify-between items-center hover:bg-gray-50\">\n                <div>\n                  <p class=\"font-medium text-gray-800\">\n                    \\${file.name}\n                  </p>\n                  <p class=\"text-sm text-gray-500\">\n                    Type: \\${file.mimeType}\n                  </p>\n                </div>\n                <button\n                  data-file-id=\"\\${file.id}\"\n                  class=\"remove-file-btn p-2 text-gray-500 hover:text-red-500 hover:bg-red-50 rounded-full transition-colors\"\n                  aria-label=\"Remove file\"\n                >\n                  <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n                    <path d=\"M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/>\n                  </svg>\n                </button>\n              </div>\\`\n            ).join('');\n\n            // Attach event listeners to remove buttons\n            document.querySelectorAll('.remove-file-btn').forEach(btn => {\n              btn.addEventListener('click', (e) => {\n                const fileId = e.currentTarget.getAttribute('data-file-id');\n                removeFile(fileId);\n              });\n            });\n  \n            submitButton.style.display = 'flex';\n          }\n  \n          function removeFile(fileId) {\n            selectedFiles = selectedFiles.filter(file => file.id !== fileId);\n            updateFileList();\n          }\n  \n          async function finishSelection() {\n            try {\n              if (!selectedFiles.length) {\n                throw new Error('No files selected');\n              }\n\n              // Create a map of fileId -> {name, mimeType}\n              const fileMap = {};\n              selectedFiles.forEach(file => {\n                fileMap[file.id] = {\n                  name: file.name,\n                  mimeType: file.mimeType\n                };\n              });\n\n              const bodyData = {\n                selectedFiles: fileMap,\n                refreshToken: refreshToken\n              };\n\n              window.opener.__oauthHandler.onSuccess(bodyData);\n              window.close();\n            } catch (error) {\n              handleError({\n                message: error.message || 'Failed to complete file selection',\n                code: 'SELECTION_ERROR',\n                details: error\n              });\n            }\n          }\n  \n          // Attach event listeners\n          document.getElementById('finishButton')?.addEventListener('click', finishSelection);\n\n          // Initialize file list with pre-selected files if any\n          if (selectedFiles.length > 0) {\n            updateFileList();\n          }\n        `\n      }\n    };\n  }\n\n  /**\n   * Utility method to generate the base HTML structure\n   * \n   * @param title Page title\n   * @param styles Additional CSS styles to include\n   * @param head Additional head content (scripts, meta tags)\n   * @param body Body content\n   * @param scripts JavaScript to include at the end of body\n   * @returns Complete HTML string\n   */\n  protected generateHTMLTemplate(\n    title: string,\n    styles: string = '',\n    head: string = '',\n    body: string,\n    scripts: string,\n    nonce?: string\n  ): string {\n    return `\n      <!DOCTYPE html>\n      <html>\n      <head>\n        <title>${title}</title>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n        <style>\n          * { box-sizing: border-box; margin: 0; padding: 0; }\n          body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; }\n          .p-2 { padding: 0.5rem; }\n          .p-4 { padding: 1rem; }\n          .p-6 { padding: 1.5rem; }\n          .px-4 { padding-left: 1rem; padding-right: 1rem; }\n          .px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }\n          .py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }\n          .py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }\n          .my-4 { margin-top: 1rem; margin-bottom: 1rem; }\n          .mt-6 { margin-top: 1.5rem; }\n          .ml-3 { margin-left: 0.75rem; }\n          .space-y-4 > * + * { margin-top: 1rem; }\n          .space-y-6 > * + * { margin-top: 1.5rem; }\n          .flex { display: flex; }\n          .items-center { align-items: center; }\n          .justify-between { justify-content: space-between; }\n          .justify-end { justify-content: flex-end; }\n          .flex-shrink-0 { flex-shrink: 0; }\n          .border { border: 1px solid #e5e7eb; }\n          .border-l-4 { border-left: 4px solid; }\n          .border-yellow-400 { border-color: #fbbf24; }\n          .rounded-lg { border-radius: 0.5rem; }\n          .rounded-full { border-radius: 9999px; }\n          .bg-blue-500 { background-color: #3b82f6; }\n          .bg-green-500 { background-color: #10b981; }\n          .bg-yellow-50 { background-color: #fffbeb; }\n          .bg-gray-50 { background-color: #f9fafb; }\n          .bg-red-50 { background-color: #fef2f2; }\n          .text-white { color: #ffffff; }\n          .text-2xl { font-size: 1.5rem; line-height: 2rem; }\n          .text-sm { font-size: 0.875rem; line-height: 1.25rem; }\n          .text-gray-500 { color: #6b7280; }\n          .text-gray-800 { color: #1f2937; }\n          .text-yellow-700 { color: #a16207; }\n          .text-yellow-400 { color: #fbbf24; }\n          .text-red-500 { color: #ef4444; }\n          .font-bold { font-weight: 700; }\n          .font-medium { font-weight: 500; }\n          .hover\\\\:bg-blue-600:hover { background-color: #2563eb; }\n          .hover\\\\:bg-green-600:hover { background-color: #059669; }\n          .hover\\\\:bg-gray-50:hover { background-color: #f9fafb; }\n          .hover\\\\:bg-red-50:hover { background-color: #fef2f2; }\n          .hover\\\\:text-red-500:hover { color: #ef4444; }\n          .transition-colors { transition-property: color, background-color, border-color; transition-duration: 150ms; }\n          .group:hover .group-hover\\\\:bg-gray-50 { background-color: #f9fafb; }\n          button { cursor: pointer; border: none; outline: none; }\n          button:focus { outline: 2px solid #3b82f6; outline-offset: 2px; }\n          .h-5 { height: 1.25rem; }\n          .w-5 { width: 1.25rem; }\n          ${styles}\n        </style>\n        ${head}\n      </head>\n      <body>\n        <div class=\"p-6\">\n          <div class=\"space-y-6\">\n            ${body}\n          </div>\n        </div>\n        <script${nonce ? ` nonce=\"${nonce}\"` : ''}>\n          ${scripts}\n        </script>\n      </body>\n      </html>\n    `;\n  }\n}","import { OAuthResponse } from '../../baseOAuth/types';\nimport { GoogleDriveOAuthConfig } from '../types';\nimport { BasePicker } from '../../baseOAuth/ui/picker';\n\n/**\n * Google Drive implementation of the file picker\n */\nexport class GoogleDrivePicker extends BasePicker {\n  /**\n   * Creates an HTML template specifically for the Google Drive picker\n   * \n   * @param tokens OAuth tokens for API access\n   * @param config Google Drive specific configuration\n   * @param refreshToken Refresh token to include in selection data\n   * @param preSelectedFiles Optional map of files to initialize as selected\n   * @returns HTML string for the Google Drive picker interface\n   */\n  createPickerHTML(\n    tokens: OAuthResponse,\n    config: GoogleDriveOAuthConfig,\n    refreshToken: string,\n    preSelectedFiles?: Record<string, { name: string; mimeType: string }>,\n    nonce?: string\n  ): string {\n    const ui = this.getCommonUIElements();\n    \n    // Google Drive specific warning\n    const googleDriveWarning = `\n      <div class=\"bg-yellow-50 border-l-4 border-yellow-400 p-4 my-4\">\n        <div class=\"flex\">\n          <div class=\"flex-shrink-0\">\n            <svg class=\"h-5 w-5 text-yellow-400\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n              <path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />\n            </svg>\n          </div>\n          <div class=\"ml-3\">\n            <p class=\"text-sm text-yellow-700\">\n              <span class=\"font-medium\">Important:</span> Google Workspace documents like presentations and Google Docs cannot be exported if they are larger than 10MB. Please convert such files to a compatible format (e.g., PDF) before selection if you need to process them.\n            </p>\n          </div>\n        </div>\n      </div>\n    `;\n\n    // Google Drive specific scripts\n    const googleDriveScripts = `\n      ${ui.scripts.basePickerScript(tokens, {\n        clientId: config.clientId,\n        apiKey: config.apiKey,\n        refreshToken\n      }, refreshToken, preSelectedFiles)}\n\n      function loadPicker() {\n        try {\n          window.gapi.load('picker', initPicker);\n        } catch (error) {\n          handleError({\n            message: 'Failed to load Google Picker API',\n            code: 'PICKER_LOAD_ERROR',\n            details: error\n          });\n        }\n      }\n\n      function initPicker() {\n        createPicker(tokens.access_token);\n      }\n\n      function createPicker(token) {\n        if (!token) {\n          handleError({\n            message: 'No access token available',\n            code: 'TOKEN_MISSING'\n          });\n          return;\n        }\n\n        try {\n          // Extract app ID from client ID\n          const appId = config.clientId.split('-')[0];\n          \n          const myDriveView = new google.picker.DocsView()\n            .setIncludeFolders(true)\n            .setSelectFolderEnabled(true)\n            .setParent('root')\n            .setLabel('My Drive');\n\n          const sharedDriveView = new google.picker.DocsView(google.picker.ViewId.DOCS)\n            .setEnableTeamDrives(true)\n            .setIncludeFolders(true)\n            .setSelectFolderEnabled(true)\n            .setLabel('Shared Drives');\n\n          const sharedWithMeView = new google.picker.DocsView(google.picker.ViewId.SHARED_WITH_ME)\n            .setIncludeFolders(true)\n            .setOwnedByMe(false)\n            .setSelectFolderEnabled(true)\n            .setLabel('Shared with me');\n\n          const picker = new google.picker.PickerBuilder()\n            .enableFeature(google.picker.Feature.MULTISELECT_ENABLED)\n            .addView(myDriveView)\n            .addView(sharedDriveView)\n            .addView(sharedWithMeView)\n            .setOAuthToken(token)\n            .setDeveloperKey(config.apiKey)\n            .setAppId(appId)\n            .setCallback(handlePickerCallback)\n            .build();\n\n          picker.setVisible(true);\n        } catch (error) {\n          handleError({\n            message: 'Failed to create picker',\n            code: 'PICKER_CREATE_ERROR',\n            details: error\n          });\n        }\n      }\n\n      function handlePickerCallback(data) {\n        if (data[google.picker.Response.ACTION] === google.picker.Action.PICKED) {\n          const newDocs = data[google.picker.Response.DOCUMENTS];\n          const existingIds = new Set(selectedFiles.map(file => file.id));\n          const uniqueNewFiles = newDocs.filter(file => !existingIds.has(file.id));\n          selectedFiles = [...selectedFiles, ...uniqueNewFiles];\n          updateFileList();\n        }\n      }\n\n      function handleSelectMore() {\n        loadPicker();\n      }\n\n      // Attach event listener for Select More button\n      document.getElementById('selectMoreButton')?.addEventListener('click', handleSelectMore);\n\n      // Initialize picker\n      // loadPicker();\n    `;\n\n    // Google-specific head includes\n    const googleHead = `\n      <script src=\"https://apis.google.com/js/api.js\"${nonce ? ` nonce=\"${nonce}\"` : ''}></script>\n      <script src=\"https://apis.google.com/js/platform.js\"${nonce ? ` nonce=\"${nonce}\"` : ''}></script>\n    `;\n\n    // Assemble the complete HTML\n    return this.generateHTMLTemplate(\n      'Google Drive File Selector',\n      '', // No additional styles\n      googleHead,\n      `\n        ${ui.header}\n        ${googleDriveWarning}\n        ${ui.fileListContainer}\n        ${ui.submitButtonContainer}\n      `,\n      googleDriveScripts,\n      nonce\n    );\n  }\n\n  /**\n   * Create a static instance for backward compatibility\n   */\n  static createPickerHTML(\n    tokens: OAuthResponse,\n    config: GoogleDriveOAuthConfig,\n    refreshToken: string,\n    preSelectedFiles?: Record<string, { name: string; mimeType: string }>,\n    nonce?: string\n  ): string {\n    const picker = new GoogleDrivePicker();\n    return picker.createPickerHTML(tokens, config, refreshToken, preSelectedFiles, nonce);\n  }\n}","import { OAuthConfig, OAuthError, OAuthResponse } from '../../baseOAuth/types';\nimport { GoogleDriveOAuthConfig } from '../types';\nimport { exchangeGDriveCodeForTokens } from '../utils/token';\nimport { GoogleDrivePicker } from '../ui/picker';\nimport { BaseOAuth } from '../../baseOAuth/core/oauth';\n\n/**\n * Google Drive specific OAuth implementation\n */\nexport class GoogleDriveOAuth extends BaseOAuth {\n  /**\n   * Validates Google Drive specific configuration\n   * @param config The OAuth configuration to validate\n   * @throws OAuthError if configuration is invalid\n   */\n  protected static override validateConnectorConfig(config: OAuthConfig): void {\n    const gDriveConfig = config as GoogleDriveOAuthConfig;\n    \n    if (!gDriveConfig.clientId) {\n      throw new OAuthError('Missing clientId in configuration', 'CONFIGURATION_ERROR');\n    }\n    \n    if (!gDriveConfig.clientSecret) {\n      throw new OAuthError('Missing clientSecret in configuration', 'CONFIGURATION_ERROR');\n    }\n    \n    if (!gDriveConfig.apiKey) {\n      throw new OAuthError('Missing apiKey in configuration', 'CONFIGURATION_ERROR');\n    }\n  }\n\n  /**\n   * Creates an OAuth popup window for Google authentication\n   * @param config The OAuth configuration\n   * @returns The popup window instance or null if creation failed\n   */\n  public static override startOAuth(config: GoogleDriveOAuthConfig): Window | null {\n    try {\n      this.validateConfig(config);\n\n      const {\n        clientId,\n        redirectUri,\n        scopes = [\n          'https://www.googleapis.com/auth/drive.file',\n        ],\n      } = config;\n\n      // Set up the OAuth handler in the window\n      this.setupOAuthHandler(config);\n\n      // Build OAuth URL with parameters\n      const params = new URLSearchParams({\n        client_id: clientId,\n        redirect_uri: redirectUri,\n        response_type: 'code',\n        access_type: 'offline',\n        prompt: 'consent',\n        scope: scopes.join(' ')\n      });\n\n      const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;\n\n      // Create the popup window\n      const popup = this.createOAuthPopup(authUrl, 'Google Drive OAuth Login');\n      \n      // Monitor the popup\n      if (popup) {\n        this.monitorPopup(popup);\n      }\n\n      return popup;\n    } catch (error) {\n      if (error instanceof OAuthError) {\n        config.onError?.(error);\n      } else {\n        config.onError?.(\n          new OAuthError(\n            error instanceof Error ? error.message : 'An unknown error occurred',\n            'UNKNOWN_ERROR',\n            error\n          )\n        );\n      }\n      return null;\n    }\n  }\n\n  /**\n   * Creates a response for the OAuth callback page\n   * @param code Authorization code from the OAuth redirect\n   * @param config The OAuth configuration\n   * @param error Optional error from the OAuth process\n   * @returns A Response object with the callback page\n   */\n  public static override async createCallbackResponse(\n    code: string,\n    config: GoogleDriveOAuthConfig,\n    error?: string | OAuthError,\n    nonce?: string\n  ): Promise<Response> {\n    if (error) {\n      const errorObj = typeof error === 'string' ? new OAuthError(error, 'CALLBACK_ERROR') : error;\n      return this.createErrorResponse(errorObj, nonce);\n    }\n\n    try {\n      const tokens = await exchangeGDriveCodeForTokens(\n        code,\n        config.clientId,\n        config.clientSecret,\n        config.redirectUri\n      );\n\n      // Use the Google Drive picker template\n      const htmlContent = GoogleDrivePicker.createPickerHTML(tokens, config, tokens.refresh_token, undefined, nonce);\n\n      return new Response(htmlContent, { headers: { 'Content-Type': 'text/html' } });\n    } catch (error) {\n      return this.createErrorResponse(\n        error instanceof OAuthError ? error : new OAuthError(\n          error instanceof Error ? error.message : 'Failed to create callback page',\n          'CALLBACK_ERROR',\n          error\n        ),\n        nonce\n      );\n    }\n  }\n\n  /**\n   * Redirects the user to the Vectorize Google Drive connector authentication flow\n   * with a one-time token for security\n   *\n   * @param oneTimeToken The security token for authentication\n   * @param organizationId Organization ID for the connection\n   * @param platformUrl Optional URL of the Vectorize platform (primarily used for testing)\n   * @returns Promise that resolves when the redirect is ready\n   */\n  public static override async redirectToVectorizeConnect(\n    oneTimeToken: string,\n    organizationId: string,\n    platformUrl: string = 'https://platform.vectorize.io'\n  ): Promise<void> {\n    // Build the redirect URL with the token as a query parameter\n    const connectUrl = new URL(`${platformUrl}/connect/google-drive`);\n    connectUrl.searchParams.append('token', oneTimeToken);\n    connectUrl.searchParams.append('organizationId', organizationId);\n\n    // Use the base iframe implementation with Google Drive specific settings\n    return this.createConnectIframe(connectUrl.toString(), {\n      originPattern: /vectorize\\.io$/,\n      successMessage: 'vectorize-connect-complete'\n    });\n  }\n\n  /**\n   * Redirects the user to the Vectorize Google Drive connector edit flow\n   * with a one-time token for security\n   *\n   * @param oneTimeToken The security token for authentication\n   * @param organizationId Organization ID for the connection\n   * @param platformUrl Optional URL of the Vectorize platform (primarily used for testing)\n   * @returns Promise that resolves when the redirect is ready\n   */\n  public static override async redirectToVectorizeEdit(\n    oneTimeToken: string,\n    organizationId: string,\n    platformUrl: string = 'https://platform.vectorize.io'\n  ): Promise<void> {\n    // Build the redirect URL with the token as a query parameter\n    const editUrl = new URL(`${platformUrl}/connect/google-drive/edit`);\n    editUrl.searchParams.append('token', oneTimeToken);\n    editUrl.searchParams.append('organizationId', organizationId);\n\n    // Use the base iframe implementation with Google Drive specific settings\n    return this.createConnectIframe(editUrl.toString(), {\n      originPattern: /vectorize\\.io$/,\n      successMessage: 'vectorize-edit-complete'\n    });\n  }\n}","import { OAuthConfig, OAuthError, OAuthResponse } from '../types';\nimport { validateConfig } from '../utils/validation';\n\n/**\n * Abstract base class for file selection functionality\n * Can be extended by connector-specific implementations\n */\nexport abstract class BaseSelection {\n  /**\n   * Creates a popup window for file selection\n   * \n   * @param width Width of the popup window\n   * @param height Height of the popup window\n   * @param title Title of the popup window\n   * @returns The created popup window or null if creation failed\n   */\n  protected static createPopupWindow(\n    width: number = 1200,\n    height: number = 800,\n    title: string = 'File Selection'\n  ): Window | null {\n    const left = window.screenX + (window.outerWidth - width) / 2;\n    const top = window.screenY + (window.outerHeight - height) / 2;\n\n    const popup = window.open(\n      'about:blank',\n      title,\n      `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`\n    );\n\n    if (!popup) {\n      throw new OAuthError(\n        'Failed to open popup window. Please check if popups are blocked.',\n        'POPUP_BLOCKED'\n      );\n    }\n\n    return popup;\n  }\n\n  /**\n   * Sets up the OAuth handler in the window object\n   * \n   * @param config OAuth configuration with success and error callbacks\n   */\n  protected static setupOAuthHandler(config: OAuthConfig): void {\n    const { onSuccess, onError } = config;\n\n    // Store configuration for the callback to access\n    (window as any).__oauthHandler = {\n      onSuccess,\n      onError: (error: string | OAuthError) => {\n        if (typeof error === 'string') {\n          error = new OAuthError(error, 'UNKNOWN_ERROR');\n        }\n        onError?.(error);\n      },\n      OAuthError // Make error constructor available to popup\n    };\n  }\n\n  /**\n   * Monitors a popup window and cleans up when it's closed\n   * \n   * @param popup The popup window to monitor\n   */\n  protected static monitorPopup(popup: Window | null): void {\n    if (!popup) {\n      return; // Nothing to monitor\n    }\n    \n    const checkPopup = setInterval(() => {\n      if (popup.closed) {\n        clearInterval(checkPopup);\n        delete (window as any).__oauthHandler;\n      }\n    }, 500);\n  }\n\n  /**\n   * Writes content to a popup window\n   * \n   * @param popup The popup window to write to\n   * @param content The HTML content to write\n   */\n  protected static writeToPopup(popup: Window | null, content: string): void {\n    if (!popup) {\n      throw new OAuthError('Cannot write to null popup', 'INVALID_POPUP');\n    }\n    \n    popup.document.open();\n    popup.document.write(content);\n    popup.document.close();\n  }\n\n  /**\n   * Abstract method to be implemented by connector-specific classes\n   * This is the main entry point for file selection\n   */\n  abstract startFileSelection(\n    config: OAuthConfig,\n    refreshToken: string,\n    selectedFiles?: Record<string, { name: string; mimeType: string }>,\n    targetWindow?: Window\n  ): Promise<Window | null>;\n}","// core/selection.ts\nimport { OAuthConfig, OAuthError, TokenError } from '../../baseOAuth';\nimport { BaseSelection } from '../../baseOAuth/core/selection';\nimport { validateConfig } from '../../baseOAuth/utils/validation';\nimport { refreshGDriveToken } from '../utils/token';\nimport { GoogleDrivePicker } from '../ui/picker';\nimport { GoogleDriveOAuthConfig } from '../types';\n\n/**\n * Google Drive implementation of file selection functionality\n */\nexport class GoogleDriveSelection extends BaseSelection {\n  /**\n   * Static method to start Google Drive file selection\n   * This static method is what will be called from the React components\n   */\n  static async startFileSelection(\n    config: GoogleDriveOAuthConfig,\n    refreshToken: string,\n    selectedFiles?: Record<string, { name: string; mimeType: string }>,\n    targetWindow?: Window\n  ): Promise<Window | null> {\n    try {\n      // Validate the provided configuration\n      validateConfig(config);\n\n      // Set up handler for OAuth callbacks\n      BaseSelection.setupOAuthHandler(config);\n\n      try {\n        // Refresh the access token using the refresh token\n        const tokens = await refreshGDriveToken(\n          refreshToken, \n          config.clientId, \n          config.clientSecret,\n        );\n        \n        // Use provided window or create a new popup\n        const popup = targetWindow || BaseSelection.createPopupWindow(\n          1200, \n          800, \n          'Google Drive File Selection'\n        );\n        \n        if (!popup) {\n          throw new OAuthError(\n            'Failed to create popup window for file selection',\n            'POPUP_CREATION_FAILED'\n          );\n        }\n        \n        // Generate the Google Drive file picker content\n        const content = GoogleDrivePicker.createPickerHTML(\n          {\n            access_token: tokens.access_token,\n            refresh_token: refreshToken,\n            expires_in: tokens.expires_in,\n            token_type: tokens.token_type\n          },\n          config,\n          refreshToken,\n          selectedFiles,\n          config.nonce\n        );\n        \n        // Write content to the popup\n        BaseSelection.writeToPopup(popup, content);\n\n        // Monitor the popup and clean up when closed\n        BaseSelection.monitorPopup(popup);\n\n        return popup;\n      } catch (error) {\n        if (error instanceof OAuthError) {\n          throw error;\n        }\n        \n        throw new TokenError(\n          error instanceof Error ? error.message : 'Failed to refresh token or create selection popup',\n          error\n        );\n      }\n    } catch (error) {\n      // Handle errors and call the error callback from the config\n      if (error instanceof OAuthError) {\n        config.onError?.(error);\n      } else {\n        config.onError?.(new OAuthError(\n          error instanceof Error ? error.message : 'An unknown error occurred',\n          'UNKNOWN_ERROR',\n          error\n        ));\n      }\n      return null;\n    }\n  }\n\n  /**\n   * Instance method implementation (fulfills abstract class requirement)\n   * Delegates to the static method for actual implementation\n   */\n  async startFileSelection(\n    config: GoogleDriveOAuthConfig,\n    refreshToken: string,\n    selectedFiles?: Record<string, { name: string; mimeType: string }>,\n    targetWindow?: Window\n  ): Promise<Window | null> {\n    return GoogleDriveSelection.startFileSelection(\n      config,\n      refreshToken,\n      selectedFiles,\n      targetWindow\n    );\n  }\n}","// dropboxOAuth/types/index.ts\n\nimport { \n    OAuthConfig, \n    OAuthError, \n    OAuthResponse, \n    GenericFile, \n    GenericSelection,\n    TokenError\n  } from '../../baseOAuth/types';\n  \n  /**\n   * Dropbox specific configuration options \n   */\n  export interface DropboxOAuthConfig extends OAuthConfig {\n    appKey: string;      // Dropbox API app key\n    appSecret: string;   // Dropbox API app secret\n  }\n  \n  /**\n   * Error thrown from the Dropbox picker\n   */\n  export class PickerError extends OAuthError {\n    constructor(message: string, details?: any) {\n      super(message, 'PICKER_ERROR', details);\n      this.name = 'PickerError';\n    }\n  }\n  \n  /**\n   * Represents a file in Dropbox\n   */\n  export interface DropboxFile extends GenericFile {\n    // Add Dropbox specific properties if needed\n    path?: string;\n  }\n  \n  /**\n   * Selection result from the Dropbox picker\n   */\n  export interface DropboxFileSelection extends GenericSelection {\n    files: DropboxFile[];\n  }\n  \n  /**\n   * Dropbox connector types\n   */\n  export enum DropboxConnectorType {\n    VECTORIZE = \"DROPBOX_OAUTH_MULTI\",\n    WHITE_LABEL = \"DROPBOX_OAUTH_MULTI_CUSTOM\"\n  }","// dropboxOAuth/core/apiFunctions.ts\n\nimport { \n    VectorizeAPIConfig, \n    ConnectorConfig,\n    UserAction \n  } from \"../../baseOAuth/types\";\n  import { \n    createSourceConnector, \n    manageUser, \n    getOneTimeConnectorToken as baseGetOneTimeConnectorToken \n  } from \"../../baseOAuth/core/apiFunctions\";\n  import { DropboxConnectorType } from \"../types\";\n  \n  /**\n   * Create a Vectorize Dropbox OAuth Connector Source\n   *\n   * @param config - An object containing your organization ID and authorization token\n   * @param connectorName - Name for the connector\n   * @param platformUrl - URL of the Vectorize API (primarily used for testing)\n   *\n   * @returns A Promise that resolves with the connector ID\n   */\n  export async function createVectorizeDropboxConnector(\n    config: VectorizeAPIConfig,\n    connectorName: string,\n    platformUrl: string = \"https://api.vectorize.io/v1\",\n  ): Promise<string> {\n    const connector: ConnectorConfig = {\n      name: connectorName,\n      type: DropboxConnectorType.VECTORIZE\n    };\n  \n    return createSourceConnector(config, connector, platformUrl);\n  }\n  \n  /**\n   * Create a White Label Dropbox OAuth Connector Source\n   *\n   * @param config - An object containing your organization ID and authorization token\n   * @param connectorName - Name for the connector\n   * @param appKey - Dropbox API app key for the white label connector\n   * @param appSecret - Dropbox API app secret for the white label connector\n   * @param platformUrl - URL of the Vectorize API (primarily used for testing)\n   *\n   * @returns A Promise that resolves with the connector ID\n   */\n  export async function createWhiteLabelDropboxConnector(\n    config: VectorizeAPIConfig,\n    connectorName: string,\n    appKey: string,\n    appSecret: string,\n    platformUrl: string = \"https://api.vectorize.io/v1\",\n  ): Promise<string> {\n    if (!appKey || !appSecret) {\n      throw new Error(\"App Key and App Secret are required for white label connectors\");\n    }\n  \n    const connector: ConnectorConfig = {\n      name: connectorName,\n      type: DropboxConnectorType.WHITE_LABEL,\n      config: {\n        \"app-key\": appKey,\n        \"app-secret\": appSecret\n      }\n    };\n  \n    return createSourceConnector(config, connector, platformUrl);\n  }\n  \n  /**\n   * Manages a Dropbox user for a connector, allowing you to add, edit, or remove users.\n   *\n   * @param config VectorizeAPIConfig containing authorization and organizationId\n   * @param connectorId ID of the connector\n   * @param selectedFiles Record of selected files with their metadata\n   * @param refreshToken Dropbox OAuth refresh token\n   * @param userId User ID to manage\n   * @param action Action to perform (\"add\", \"edit\", or \"remove\")\n   * @param platformUrl Optional URL of the Vectorize API (primarily used for testing)\n   * @returns Promise that resolves with the API response\n   */\n  export async function manageDropboxUser(\n    config: VectorizeAPIConfig,\n    connectorId: string,\n    selectedFiles: Record<string, { name: string; mimeType: string; path?: string }> | null,\n    refreshToken: string,\n    userId: string,\n    action: UserAction,\n    platformUrl: string = \"https://api.vectorize.io/v1\",\n  ): Promise<Response> {\n    // Validate required parameters for add/edit actions\n    if (action === \"add\" || action === \"edit\") {\n      if (!selectedFiles || Object.keys(selectedFiles).length === 0) {\n        throw new Error(`Selected files are required for ${action} action`);\n      }\n      \n      if (!refreshToken) {\n        throw new Error(`Refresh token is required for ${action} action`);\n      }\n    }\n  \n    // Create the Dropbox specific payload\n    const payload: Record<string, any> = {};\n    \n    // Only include selectedFiles and refreshToken for add/edit, not for remove\n    if (action !== \"remove\") {\n      payload.selectedFiles = selectedFiles;\n      payload.refreshToken = refreshToken;\n    }\n  \n    return manageUser(config, connectorId, userId, action, payload, platformUrl);\n  }\n  \n  /**\n   * Gets a one-time authentication token for connector operations\n   * This is a direct re-export of the base function for consistency\n   */\n  export const getOneTimeConnectorToken = baseGetOneTimeConnectorToken;","// dropboxOAuth/utils/token.ts\n\nimport { OAuthResponse } from '../../baseOAuth/types';\nimport { TokenError } from '../../baseOAuth/types';\n\n/**\n * Exchanges an authorization code for access and refresh tokens\n * @param code The authorization code from OAuth redirect\n * @param appKey The Dropbox app key\n * @param appSecret The Dropbox app secret\n * @param redirectUri The OAuth redirect URI\n * @returns An object containing the tokens\n */\nexport async function exchangeDropboxCodeForTokens(\n  code: string,\n  appKey: string,\n  appSecret: string,\n  redirectUri: string\n): Promise<OAuthResponse> {\n  try {\n    const tokenUrl = 'https://api.dropboxapi.com/oauth2/token';\n    const params = new URLSearchParams({\n      code,\n      grant_type: 'authorization_code',\n      client_id: appKey,\n      client_secret: appSecret,\n      redirect_uri: redirectUri\n    });\n\n    const response = await fetch(tokenUrl, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded'\n      },\n      body: params.toString()\n    });\n\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => ({}));\n      throw new TokenError(\n        `Token exchange failed: ${errorData.error || response.statusText}`,\n        errorData\n      );\n    }\n\n    const data = await response.json();\n    return {\n      access_token: data.access_token,\n      refresh_token: data.refresh_token,\n      expires_in: data.expires_in || 14400, // 4 hours default if not provided\n      token_type: data.token_type\n    };\n  } catch (error) {\n    if (error instanceof TokenError) {\n      throw error;\n    }\n    throw new TokenError(\n      error instanceof Error ? error.message : 'Token exchange failed',\n      error\n    );\n  }\n}\n\n/**\n * Refreshes an access token using a refresh token\n * @param refreshToken The refresh token\n * @param appKey The Dropbox app key\n * @param appSecret The Dropbox app secret\n * @returns An object containing the new access token\n */\nexport async function refreshDropboxToken(\n  refreshToken: string,\n  appKey: string,\n  appSecret: string\n): Promise<{\n  access_token: string;\n  expires_in: number;\n  token_type: string;\n}> {\n  try {\n    const tokenUrl = 'https://api.dropboxapi.com/oauth2/token';\n    const params = new URLSearchParams({\n      refresh_token: refreshToken,\n      grant_type: 'refresh_token',\n      client_id: appKey,\n      client_secret: appSecret\n    });\n\n    const response = await fetch(tokenUrl, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded'\n      },\n      body: params.toString()\n    });\n\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => ({}));\n      throw new TokenError(\n        `Token refresh failed: ${errorData.error || response.statusText}`,\n        errorData\n      );\n    }\n\n    const data = await response.json();\n    return {\n      access_token: data.access_token,\n      expires_in: data.expires_in || 14400, // 4 hours default if not provided\n      token_type: data.token_type\n    };\n  } catch (error) {\n    if (error instanceof TokenError) {\n      throw error;\n    }\n    throw new TokenError(\n      error instanceof Error ? error.message : 'Token refresh failed',\n      error\n    );\n  }\n}","import { OAuthResponse } from '../../baseOAuth/types';\nimport { DropboxOAuthConfig, DropboxFile, PickerError } from '../types';\nimport { BasePicker } from '../../baseOAuth/ui/picker';\n\n/**\n * Dropbox implementation of the file picker\n */\nexport class DropboxPicker extends BasePicker {\n  /**\n   * Creates an HTML template specifically for the Dropbox picker\n   * \n   * @param tokens OAuth tokens for API access\n   * @param config Dropbox specific configuration\n   * @param refreshToken Refresh token to include in selection data\n   * @param preSelectedFiles Optional map of files to initialize as selected\n   * @returns HTML string for the Dropbox picker interface\n   */\n  createPickerHTML(\n    tokens: OAuthResponse,\n    config: DropboxOAuthConfig,\n    refreshToken: string,\n    preSelectedFiles?: Record<string, { name: string; mimeType: string }>,\n    nonce?: string\n  ): string {\n    const ui = this.getCommonUIElements();\n\n    // Dropbox specific scripts\n    const dropboxScripts = `\n      ${ui.scripts.basePickerScript(tokens, {\n        appKey: config.appKey,\n        appSecret: config.appSecret,\n        redirectUri: config.redirectUri,\n        refreshToken\n      }, refreshToken, preSelectedFiles)}\n\n      // Safely check if Dropbox API is loaded\n      function isDropboxAvailable() {\n        return typeof window.Dropbox !== 'undefined' && window.Dropbox.choose;\n      }\n\n      // Function to load Dropbox SDK if not already loaded\n      function ensureDropboxLoaded() {\n        return new Promise((resolve, reject) => {\n          if (isDropboxAvailable()) {\n            return resolve(true);\n          }\n          \n          // Check if script is already in the process of loading\n          const existingScript = document.getElementById('dropboxjs');\n          if (existingScript) {\n            // Script is already loading, wait for it\n            const checkInterval = setInterval(() => {\n              if (isDropboxAvailable()) {\n                clearInterval(checkInterval);\n                resolve(true);\n              }\n            }, 100);\n            \n            // Set a timeout to avoid infinite waiting\n            setTimeout(() => {\n              clearInterval(checkInterval);\n              reject(new Error('Dropbox SDK loading timeout'));\n            }, 10000);\n            return;\n          }\n          \n          // Load the script if not already loading\n          const script = document.createElement('script');\n          script.id = 'dropboxjs';\n          script.src = 'https://www.dropbox.com/static/api/2/dropins.js';\n          script.setAttribute('data-app-key', '${config.appKey}');\n          ${nonce ? `script.setAttribute('nonce', '${nonce}');` : ''}\n          script.onload = () => {\n            if (isDropboxAvailable()) {\n              resolve(true);\n            } else {\n              reject(new Error('Dropbox SDK loaded but Chooser not available'));\n            }\n          };\n          script.onerror = () => {\n            reject(new Error('Failed to load Dropbox SDK'));\n          };\n          document.head.appendChild(script);\n        });\n      }\n\n      async function loadDropboxChooser() {\n        try {\n          await ensureDropboxLoaded();\n          \n          // Configure the Dropbox chooser options\n          const options = {\n            success: handleDropboxSuccess,\n            cancel: function() {\n              // User canceled the picker\n              console.log('Dropbox selection canceled');\n            },\n            linkType: \"preview\",  // \"preview\" works with folder selection\n            multiselect: true,\n            folderselect: true,\n            extensions: ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.csv', '.png', '.jpg', '.jpeg', '.gif'],\n          };\n          \n          // Open the chooser\n          window.Dropbox.choose(options);\n        } catch (error) {\n          console.error('Dropbox chooser error:', error);\n          \n          handleError({\n            message: 'Failed to open Dropbox chooser: ' + (error.message || 'Unknown error'),\n            code: 'PICKER_ERROR',\n            details: error\n          });\n        }\n      }\n\n      function handleDropboxSuccess(files) {\n        try {\n          if (!files || !files.length) {\n            return;\n          }\n\n          const existingIds = new Set(selectedFiles.map(file => file.id));\n          \n          const newFiles = files.map(file => {\n          \n            // Get the file ID or generate one if not available\n            let fileId = file.id;\n            \n            return {\n              id: fileId,\n              name: file.name,\n              mimeType: getMimeType(file.name),\n              path: file.link ? normalizeDropboxPath(file.link) : undefined,\n              isDir: file.isDir || false\n            };\n          }).filter(file => !existingIds.has(file.id));\n\n          selectedFiles = [...selectedFiles, ...newFiles];\n          updateFileList();\n          \n        } catch (error) {\n          console.error('Error processing files:', error);\n          \n          handleError({\n            message: 'Failed to process selected files',\n            code: 'PICKER_ERROR',\n            details: error\n          });\n        }\n      }\n\n      function generateFileId(link) {\n        // Extract a unique ID from the link or generate one\n        return link.split('?')[0].split('/').pop() || \n               'dropbox-' + Math.random().toString(36).substring(2, 15);\n      }\n\n      function normalizeDropboxPath(link) {\n        // Extract the path from the Dropbox link\n        try {\n          const url = new URL(link);\n          const path = url.pathname.replace(/^\\\\/dl/, '');\n          return path;\n        } catch (e) {\n          return link;\n        }\n      }\n\n      function getMimeType(filename) {\n        const extension = filename.split('.').pop().toLowerCase();\n        const mimeTypeMap = {\n          'pdf': 'application/pdf',\n          'doc': 'application/msword',\n          'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n          'xls': 'application/vnd.ms-excel',\n          'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n          'ppt': 'application/vnd.ms-powerpoint',\n          'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n          'txt': 'text/plain',\n          'csv': 'text/csv',\n          'png': 'image/png',\n          'jpg': 'image/jpeg',\n          'jpeg': 'image/jpeg',\n          'gif': 'image/gif',\n          'zip': 'application/zip',\n          'rar': 'application/vnd.rar',\n          'mp4': 'video/mp4',\n          'mp3': 'audio/mpeg'\n        };\n        \n        return mimeTypeMap[extension] || 'application/octet-stream';\n      }\n\n      function handleSelectMore() {\n        loadDropboxChooser();\n      }\n\n      // Attach event listener for Select More button\n      document.getElementById('selectMoreButton')?.addEventListener('click', handleSelectMore);\n\n      // Initialize page when it loads\n      window.addEventListener('DOMContentLoaded', function() {\n        // Preload the Dropbox SDK but don't open the chooser\n        ensureDropboxLoaded().catch(err => {\n          console.error('Failed to preload Dropbox SDK:', err);\n        });\n      });\n    `;\n\n\n    // Assemble the complete HTML\n    return this.generateHTMLTemplate(\n      'Dropbox File Selector',\n      '', // No additional styles\n      '', // No additional head elements\n      `\n        ${ui.header}\n        ${ui.fileListContainer}\n        ${ui.submitButtonContainer}\n      `,\n      dropboxScripts,\n      nonce\n    );\n  }\n\n  /**\n   * Create a static instance for backward compatibility\n   */\n  static createPickerHTML(\n    tokens: OAuthResponse,\n    config: DropboxOAuthConfig,\n    refreshToken: string,\n    preSelectedFiles?: Record<string, { name: string; mimeType: string }>,\n    nonce?: string\n  ): string {\n    const picker = new DropboxPicker();\n    return picker.createPickerHTML(tokens, config, refreshToken, preSelectedFiles, nonce);\n  }\n}","// dropboxOAuth/core/OAuth.ts\n\nimport { BaseOAuth } from '../../baseOAuth/core/oauth';\nimport { OAuthConfig, OAuthError, OAuthResponse } from '../../baseOAuth/types';\nimport { DropboxOAuthConfig } from '../types';\nimport { exchangeDropboxCodeForTokens } from '../utils/token';\nimport { DropboxPicker } from '../ui/picker';\n\n/**\n * Dropbox specific OAuth implementation\n */\nexport class DropboxOAuth extends BaseOAuth {\n  /**\n   * Validates Dropbox specific configuration\n   * @param config The OAuth configuration to validate\n   * @throws OAuthError if configuration is invalid\n   */\n  protected static override validateConnectorConfig(config: OAuthConfig): void {\n    const dropboxConfig = config as DropboxOAuthConfig;\n    \n    if (!dropboxConfig.appKey) {\n      throw new OAuthError('Missing appKey in configuration', 'CONFIGURATION_ERROR');\n    }\n    \n    if (!dropboxConfig.appSecret) {\n      throw new OAuthError('Missing appSecret in configuration', 'CONFIGURATION_ERROR');\n    }\n  }\n\n  /**\n   * Creates an OAuth popup window for Dropbox authentication\n   * @param config The OAuth configuration\n   * @returns The popup window instance or null if creation failed\n   */\n  public static override startOAuth(config: DropboxOAuthConfig): Window | null {\n    try {\n      this.validateConfig(config);\n\n      const {\n        appKey,\n        redirectUri,\n        scopes = [\"files.metadata.read\", \"files.content.read\"],\n      } = config;\n\n      // Set up the OAuth handler in the window\n      this.setupOAuthHandler(config);\n\n      // Build OAuth URL with parameters\n      const params = new URLSearchParams({\n        client_id: appKey,\n        redirect_uri: redirectUri,\n        response_type: \"code\",\n        token_access_type: \"offline\",\n        scope: scopes.join(' ')\n      });\n\n      const authUrl = `https://www.dropbox.com/oauth2/authorize?${params.toString()}`;\n\n      // Create the popup window\n      const popup = this.createOAuthPopup(authUrl, 'Dropbox OAuth Login');\n      \n      // Monitor the popup\n      if (popup) {\n        this.monitorPopup(popup);\n      }\n\n      return popup;\n    } catch (error) {\n      if (error instanceof OAuthError) {\n        config.onError?.(error);\n      } else {\n        config.onError?.(\n          new OAuthError(\n            error instanceof Error ? error.message : 'An unknown error occurred',\n            'UNKNOWN_ERROR',\n            error\n          )\n        );\n      }\n      return null;\n    }\n  }\n\n  /**\n   * Creates a response for the OAuth callback page\n   * @param code Authorization code from the OAuth redirect\n   * @param config The OAuth configuration\n   * @param error Optional error from the OAuth process\n   * @returns A Response object with the callback page\n   */\n  public static override async createCallbackResponse(\n    code: string,\n    config: DropboxOAuthConfig,\n    error?: string | OAuthError,\n    nonce?: string\n  ): Promise<Response> {\n    if (error) {\n      const errorObj = typeof error === 'string' ? new OAuthError(error, 'CALLBACK_ERROR') : error;\n      return this.createErrorResponse(errorObj, nonce);\n    }\n\n    try {\n      const tokens = await exchangeDropboxCodeForTokens(\n        code,\n        config.appKey,\n        config.appSecret,\n        config.redirectUri\n      );\n\n      // Use the Dropbox picker template\n      const htmlContent = DropboxPicker.createPickerHTML(tokens, config, tokens.refresh_token, undefined, nonce);\n\n      return new Response(htmlContent, { headers: { 'Content-Type': 'text/html' } });\n    } catch (error) {\n      return this.createErrorResponse(\n        error instanceof OAuthError ? error : new OAuthError(\n          error instanceof Error ? error.message : 'Failed to create callback page',\n          'CALLBACK_ERROR',\n          error\n        ),\n        nonce\n      );\n    }\n  }\n\n  /**\n   * Redirects the user to the Vectorize Dropbox connector authentication flow\n   * with a one-time token for security\n   *\n   * @param oneTimeToken The security token for authentication\n   * @param organizationId Organization ID for the connection\n   * @param platformUrl Optional URL of the Vectorize platform (primarily used for testing)\n   * @returns Promise that resolves when the redirect is ready\n   */\n  public static override async redirectToVectorizeConnect(\n    oneTimeToken: string,\n    organizationId: string,\n    platformUrl: string = 'https://platform.vectorize.io'\n  ): Promise<void> {\n    // Build the redirect URL with the token as a query parameter\n    const connectUrl = new URL(`${platformUrl}/connect/dropbox`);\n    connectUrl.searchParams.append('token', oneTimeToken);\n    connectUrl.searchParams.append('organizationId', organizationId);\n\n    // Use the base iframe implementation with Dropbox specific settings\n    return this.createConnectIframe(connectUrl.toString(), {\n      originPattern: /vectorize\\.io$/,\n      successMessage: 'vectorize-connect-complete'\n    });\n  }\n\n  /**\n * Redirects the user to the Vectorize Dropbox connector edit flow\n * with a one-time token for security\n *\n * @param oneTimeToken The security token for authentication\n * @param organizationId Organization ID for the connection\n * @param platformUrl Optional URL of the Vectorize platform (primarily used for testing)\n * @returns Promise that resolves when the redirect is ready\n */\npublic static override async redirectToVectorizeEdit(\n  oneTimeToken: string,\n  organizationId: string,\n  platformUrl: string = 'https://platform.vectorize.io'\n): Promise<void> {\n  // Build the redirect URL with the token as a query parameter\n  const editUrl = new URL(`${platformUrl}/connect/dropbox/edit`);\n  editUrl.searchParams.append('token', oneTimeToken);\n  editUrl.searchParams.append('organizationId', organizationId);\n\n  // Use the base iframe implementation with Dropbox specific settings\n  return this.createConnectIframe(editUrl.toString(), {\n    originPattern: /vectorize\\.io$/,\n    successMessage: 'vectorize-edit-complete'\n  });\n}\n}","import { OAuthError, TokenError } from '../../baseOAuth/types';\nimport { BaseSelection } from '../../baseOAuth/core/selection';\nimport { validateConfig } from '../../baseOAuth/utils/validation';\nimport { refreshDropboxToken } from '../utils/token';\nimport { DropboxPicker } from '../ui/picker';\nimport { DropboxOAuthConfig } from '../types';\n\n/**\n * Dropbox implementation of file selection functionality\n */\nexport class DropboxSelection extends BaseSelection {\n  /**\n   * Static method to start Dropbox file selection\n   * This static method is what will be called from the React components\n   */\n  static async startFileSelection(\n    config: DropboxOAuthConfig,\n    refreshToken: string,\n    selectedFiles?: Record<string, { name: string; mimeType: string; path?: string }>,\n    targetWindow?: Window\n  ): Promise<Window | null> {\n    try {\n      // Validate the provided configuration\n      validateConfig(config);\n\n      // Set up handler for OAuth callbacks\n      BaseSelection.setupOAuthHandler(config);\n\n      try {\n        // Refresh the access token using the refresh token\n        const tokens = await refreshDropboxToken(\n          refreshToken, \n          config.appKey, \n          config.appSecret\n        );\n        \n        // Use provided window or create a new popup\n        const popup = targetWindow || BaseSelection.createPopupWindow(\n          1200, \n          800, \n          'Dropbox File Selection'\n        );\n        \n        if (!popup) {\n          throw new OAuthError(\n            'Failed to create popup window for file selection',\n            'POPUP_CREATION_FAILED'\n          );\n        }\n        \n        // Generate the Dropbox file picker content\n        const content = DropboxPicker.createPickerHTML(\n          {\n            access_token: tokens.access_token,\n            refresh_token: refreshToken,\n            expires_in: tokens.expires_in,\n            token_type: tokens.token_type\n          },\n          config,\n          refreshToken,\n          selectedFiles,\n          config.nonce\n        );\n        \n        // Write content to the popup\n        BaseSelection.writeToPopup(popup, content);\n\n        // Monitor the popup and clean up when closed\n        BaseSelection.monitorPopup(popup);\n\n        return popup;\n      } catch (error) {\n        if (error instanceof OAuthError) {\n          throw error;\n        }\n        \n        throw new TokenError(\n          error instanceof Error ? error.message : 'Failed to refresh token or create selection popup',\n          error\n        );\n      }\n    } catch (error) {\n      // Handle errors and call the error callback from the config\n      if (error instanceof OAuthError) {\n        config.onError?.(error);\n      } else {\n        config.onError?.(new OAuthError(\n          error instanceof Error ? error.message : 'An unknown error occurred',\n          'UNKNOWN_ERROR',\n          error\n        ));\n      }\n      return null;\n    }\n  }\n\n  /**\n   * Instance method implementation (fulfills abstract class requirement)\n   * Delegates to the static method for actual implementation\n   */\n  async startFileSelection(\n    config: DropboxOAuthConfig,\n    refreshToken: string,\n    selectedFiles?: Record<string, { name: string; mimeType: string; path?: string }>,\n    targetWindow?: Window\n  ): Promise<Window | null> {\n    return DropboxSelection.startFileSelection(\n      config,\n      refreshToken,\n      selectedFiles,\n      targetWindow\n    );\n  }\n}","import { \n  OAuthConfig, \n  OAuthError, \n  OAuthResponse, \n  GenericFile, \n  GenericSelection,\n  TokenError\n} from '../../baseOAuth/types';\n\n/**\n * Notion specific configuration options \n */\nexport interface NotionOAuthConfig extends OAuthConfig {\n  clientId: string;      // Notion OAuth client ID\n  clientSecret: string;  // Notion OAuth client secret\n  redirectUri: string;   // Redirect URI for the OAuth flow\n  scopes?: string[];     // OAuth scopes to request\n}\n\n/**\n * Error thrown from the Notion picker\n */\nexport class PickerError extends OAuthError {\n  constructor(message: string, details?: any) {\n    super(message, 'PICKER_ERROR', details);\n    this.name = 'PickerError';\n  }\n}\n\n/**\n * Represents a page in Notion\n */\nexport interface NotionPage {\n  id: string;            // Notion page ID\n  title: string;         // Page title\n  pageId: string;        // Alias for ID (for compatibility)\n  parentType?: string;   // Type of parent (database or workspace)\n  url?: string;          // URL to the page in Notion (optional)\n}\n\n/**\n * Selection result from the Notion picker\n */\nexport interface NotionPageSelection extends GenericSelection {\n  pages: NotionPage[];\n  workspaceId?: string;  // Workspace ID the pages belong to\n  workspaceName?: string;// Name of the workspace\n}\n\n/**\n * Notion connector types\n */\nexport enum NotionConnectorType {\n  VECTORIZE = \"NOTION_OAUTH_MULTI\",\n  WHITE_LABEL = \"NOTION_OAUTH_MULTI_CUSTOM\"\n}\n","import { \n  VectorizeAPIConfig, \n  ConnectorConfig,\n  UserAction \n} from \"../../baseOAuth/types\";\nimport { \n  createSourceConnector, \n  manageUser, \n  getOneTimeConnectorToken as baseGetOneTimeConnectorToken \n} from \"../../baseOAuth/core/apiFunctions\";\nimport { NotionConnectorType } from \"../types\";\n\n/**\n * Create a Vectorize Notion OAuth Connector Source\n *\n * @param config - An object containing your organization ID and authorization token\n * @param connectorName - Name for the connector\n * @param platformUrl - URL of the Vectorize API (primarily used for testing)\n *\n * @returns A Promise that resolves with the connector ID\n */\nexport async function createVectorizeNotionConnector(\n  config: VectorizeAPIConfig,\n  connectorName: string,\n  platformUrl: string = \"https://api.vectorize.io/v1\",\n): Promise<any> {\n  try {\n\n    const connector: ConnectorConfig = {\n      name: connectorName,\n      type: NotionConnectorType.VECTORIZE\n    };\n    \n    try {\n      const result = await createSourceConnector(config, connector, platformUrl);\n      return result;\n    } catch (error: unknown) {\n      // Format the error data properly to avoid [object Object]\n      const innerError = error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Unknown error');\n      \n      // Extract and format error details\n      let errorDetails = \"\";\n      try {\n        // Try to parse the error message if it contains JSON-like structure\n        const errorMatch = innerError.message.match(/Error:\\s*(.*)/);\n        if (errorMatch && errorMatch[1]) {\n          try {\n            // Attempt to parse if it looks like JSON\n            if (errorMatch[1].includes('{') && errorMatch[1].includes('}')) {\n              const jsonStr = errorMatch[1].replace(/\\[object Object\\]/g, '{}');\n              const errorObj = JSON.parse(jsonStr);\n              errorDetails = JSON.stringify(errorObj, null, 2);\n            } else {\n              errorDetails = errorMatch[1];\n            }\n          } catch {\n            errorDetails = errorMatch[1];\n          }\n        }\n      } catch {\n        // If parsing fails, use the original message\n        errorDetails = innerError.message;\n      }\n      \n      console.error(`[Vectorize] Error in createSourceConnector: ${innerError.message}`);\n      console.error(`[Vectorize] Error details (formatted):`, errorDetails);\n      \n      // Additional debug info about the error object\n      if (error instanceof Object) {\n        try {\n          const errorKeys = Object.keys(error);\n          console.error(`[Vectorize] Error object keys:`, errorKeys);\n          \n          // Log all properties of the error object\n          errorKeys.forEach(key => {\n            const value = (error as any)[key];\n            const displayValue = typeof value === 'object' ? JSON.stringify(value, null, 2) : value;\n            console.error(`[Vectorize] Error.${key}:`, displayValue);\n          });\n        } catch (err) {\n          console.error(`[Vectorize] Could not enumerate error properties:`, err);\n        }\n      }\n      \n      console.error(`[Vectorize] Stack trace:`, innerError.stack);\n      throw innerError;\n    }\n  } catch (error: unknown) {\n    const outerError = error instanceof Error \n      ? error \n      : new Error(typeof error === 'string' ? error : 'Unknown error');\n    \n    console.error(`[Vectorize] Unexpected error in createVectorizeNotionConnector: ${outerError.message}`);\n    console.error(`[Vectorize] Stack trace:`, outerError.stack);\n    \n    // Create a more informative error with properly formatted details\n    let enhancedMessage = `Failed to create Vectorize Notion connector: ${outerError.message}`;\n    \n    // If we have a 500 error with [object Object], try to improve the message\n    if (outerError.message.includes('[object Object]')) {\n      enhancedMessage = `Failed to create Vectorize Notion connector (API returned 500 Internal Server Error). Check the server logs for more details.`;\n    }\n    \n    throw new Error(enhancedMessage);\n  }\n}\n\n/**\n * Create a White Label Notion OAuth Connector Source\n *\n * @param config - An object containing your organization ID and authorization token\n * @param connectorName - Name for the connector\n * @param clientId - Notion API client ID for the white label connector\n * @param clientSecret - Notion API client secret for the white label connector\n * @param platformUrl - URL of the Vectorize API (primarily used for testing)\n *\n * @returns A Promise that resolves with the connector ID\n */\nexport async function createWhiteLabelNotionConnector(\n  config: VectorizeAPIConfig,\n  connectorName: string,\n  clientId: string,\n  clientSecret: string,\n  platformUrl: string = \"https://api.vectorize.io/v1\",\n): Promise<string> {\n  if (!clientId || !clientSecret) {\n    throw new Error(\"Client ID and Client Secret are required for white label connectors\");\n  }\n\n  const connector: ConnectorConfig = {\n    name: connectorName,\n    type: NotionConnectorType.WHITE_LABEL,\n    config: {\n      \"client-id\": clientId,\n      \"client-secret\": clientSecret\n    }\n  };\n\n  return createSourceConnector(config, connector, platformUrl);\n}\n\n/**\n * Manages a Notion user for a connector, allowing you to add, edit, or remove users.\n *\n * @param config VectorizeAPIConfig containing authorization and organizationId\n * @param connectorId ID of the connector\n * @param selectedPages Record of selected pages with their metadata\n * @param accessToken Notion OAuth access token\n * @param userId User ID to manage\n * @param action Action to perform (\"add\", \"edit\", or \"remove\")\n * @param platformUrl Optional URL of the Vectorize API (primarily used for testing)\n * @returns Promise that resolves with the API response\n */\nexport async function manageNotionUser(\n  config: VectorizeAPIConfig,\n  connectorId: string,\n  selectedPages: Record<string, { title: string; pageId: string; parentType?: string }> | null,\n  accessToken: string,\n  userId: string,\n  action: UserAction,\n  platformUrl: string = \"https://api.vectorize.io/v1\",\n): Promise<Response> {\n  // Validate required parameters for add/edit actions\n  if (action === \"add\" || action === \"edit\") {\n    if (!selectedPages || Object.keys(selectedPages).length === 0) {\n      throw new Error(`Selected pages are required for ${action} action`);\n    }\n    \n    if (!accessToken) {\n      throw new Error(`Access token is required for ${action} action`);\n    }\n  }\n\n  // Create the Notion specific payload\n  const payload: Record<string, any> = {};\n  \n  // Only include selectedPages and accessToken for add/edit, not for remove\n  if (action !== \"remove\") {\n    payload.selectedPages = selectedPages;\n    payload.accessToken = accessToken;\n  }\n\n  return manageUser(config, connectorId, userId, action, payload, platformUrl);\n}\n\n/**\n * Gets a one-time authentication token for connector operations\n * This is a direct re-export of the base function for consistency\n */\nexport const getOneTimeConnectorToken = baseGetOneTimeConnectorToken;","// notionOAuth/utils/token.ts\n\nimport { OAuthError, TokenError } from '../../baseOAuth/types';\n\n/**\n * Exchange an authorization code for Notion OAuth tokens\n * \n * @param code The authorization code from Notion OAuth redirect\n * @param clientId The OAuth client ID\n * @param clientSecret The OAuth client secret\n * @param redirectUri The redirect URI used in the OAuth flow\n * @returns Promise resolving to the Notion OAuth tokens\n */\nexport async function exchangeNotionCodeForTokens(\n  code: string,\n  clientId: string,\n  clientSecret: string,\n  redirectUri: string\n): Promise<{\n  access_token: string;\n  token_type: string;\n  workspace_id: string;\n  workspace_name: string;\n  workspace_icon?: string;\n  bot_id: string;\n}> {\n  try {\n    const response = await fetch('https://api.notion.com/v1/oauth/token', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'Authorization': `Basic ${btoa(`${clientId}:${clientSecret}`)}`\n      },\n      body: JSON.stringify({\n        grant_type: 'authorization_code',\n        code,\n        redirect_uri: redirectUri\n      })\n    });\n\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => ({}));\n      throw new OAuthError(\n        errorData.error_description || `Failed to exchange code for tokens: ${response.status}`,\n        'TOKEN_EXCHANGE_ERROR',\n        errorData\n      );\n    }\n\n    return await response.json();\n  } catch (error) {\n    if (error instanceof OAuthError) {\n      throw error;\n    }\n    \n    throw new OAuthError(\n      error instanceof Error ? error.message : 'Failed to exchange code for tokens',\n      'TOKEN_EXCHANGE_ERROR',\n      error\n    );\n  }\n}\n\n/**\n * Refresh or validate a Notion access token\n * \n * Note: Notion tokens are long-lived and don't typically need refreshing like Dropbox,\n * but we'll verify the token is valid by making a small API request.\n * If token is invalid, we'll throw an error that can be caught by the caller.\n * \n * @param accessToken Current Notion access token\n * @param clientId The OAuth client ID (for potential future token refresh)\n * @param clientSecret The OAuth client secret (for potential future token refresh)\n * @returns Promise resolving to the validated token information\n */\nexport async function refreshNotionToken(\n  accessToken: string,\n  clientId: string,\n  clientSecret: string\n): Promise<{\n  access_token: string;\n  workspace_id: string;\n  workspace_name: string;\n  workspace_icon?: string;\n  bot_id: string;\n}> {\n  try {\n    // Verify the token by making a request to the Notion API\n    const response = await fetch('https://api.notion.com/v1/users/me', {\n      method: 'GET',\n      headers: {\n        'Authorization': `Bearer ${accessToken}`,\n        'Notion-Version': '2022-06-28'\n      }\n    });\n\n    if (!response.ok) {\n      throw new TokenError(\n        `Token validation failed: ${response.status} ${response.statusText}`,\n        { status: response.status }\n      );\n    }\n\n    const userData = await response.json();\n    \n    // Get basic workspace info\n    const workspaceResponse = await fetch('https://api.notion.com/v1/search', {\n      method: 'POST',\n      headers: {\n        'Authorization': `Bearer ${accessToken}`,\n        'Notion-Version': '2022-06-28',\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify({\n        page_size: 1 // Just need to make a valid API call\n      })\n    });\n    \n    if (!workspaceResponse.ok) {\n      throw new TokenError(\n        `Failed to get workspace info: ${workspaceResponse.status}`,\n        { status: workspaceResponse.status }\n      );\n    }\n    \n    const workspaceData = await workspaceResponse.json();\n    \n    // Return a format similar to the original OAuth response\n    return {\n      access_token: accessToken,\n      workspace_id: userData.bot?.workspace_id || 'unknown',\n      workspace_name: workspaceData.workspace_name || 'Notion Workspace',\n      workspace_icon: workspaceData.workspace_icon,\n      bot_id: userData.bot?.id || userData.id\n    };\n  } catch (error) {\n    if (error instanceof TokenError || error instanceof OAuthError) {\n      throw error;\n    }\n    \n    throw new TokenError(\n      error instanceof Error ? error.message : 'Failed to validate Notion token',\n      error\n    );\n  }\n}","// notionOAuth/ui/picker.ts\n\nimport { NotionOAuthConfig } from '../types';\n\n/**\n * Notion UI picker implementation\n */\nexport class NotionPicker {\n  /**\n   * Creates the HTML content for the Notion picker UI\n   * \n   * @param tokens The OAuth tokens received from Notion\n   * @param config The OAuth configuration\n   * @param accessToken The Notion access token to use for API calls\n   * @param existingSelection Optional record of already selected pages\n   * @returns HTML string for the picker UI\n   */\n  public static createPickerHTML(\n    tokens: any,\n    config: NotionOAuthConfig,\n    accessToken: string,\n    existingSelection?: Record<string, { title: string; pageId: string; parentType?: string }>,\n    nonce?: string\n  ): string {\n    // Convert existing selection to JSON string for embedding in the HTML\n    const existingSelectionStr = existingSelection \n      ? JSON.stringify(existingSelection) \n      : '{}';\n    \n    return `<!DOCTYPE html>\n    <html lang=\"en\">\n    <head>\n      <meta charset=\"UTF-8\">\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n      <title>Select Notion Resources</title>\n      <link href=\"https://cdnjs.cloudflare.com/ajax/libs/inter-ui/3.19.3/inter.css\" rel=\"stylesheet\">\n      <style>\n        body {\n          font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, sans-serif;\n          margin: 0;\n          padding: 0;\n          background-color: #1f2937; /* bg-gray-800 */\n          color: #f3f4f6; /* text-gray-100 */\n          line-height: 1.5;\n        }\n        \n        .container {\n          max-width: 1000px;\n          margin: 0 auto;\n          padding: 1.5rem;\n        }\n        \n        .top-bar {\n          display: flex;\n          justify-content: space-between;\n          align-items: center;\n          margin-bottom: 1rem;\n          border-bottom: 1px solid #374151; /* border-gray-700 */\n          padding-bottom: 0.5rem;\n        }\n        \n        .top-bar h2 {\n          font-size: 1.5rem;\n          font-weight: 600;\n          margin: 0;\n          color: #f3f4f6; /* text-gray-100 */\n        }\n        \n        .content-section {\n          margin-bottom: 1.5rem;\n        }\n        \n        .tab-header {\n          display: flex;\n          justify-content: space-between;\n          align-items: center;\n          margin-bottom: 1rem;\n        }\n        \n        .tab-header h2 {\n          font-size: 1rem;\n          font-weight: 600;\n          color: #f3f4f6; /* text-gray-100 */\n          margin: 0;\n        }\n        \n        .select-all-btn {\n          background-color: #4338ca; /* bg-indigo-700 */\n          color: #f3f4f6; /* text-gray-100 */\n          border: none;\n          border-radius: 0.375rem;\n          padding: 0.5rem 0.75rem;\n          font-size: 0.875rem;\n          cursor: pointer;\n          transition: all 0.1s ease;\n          display: flex;\n          align-items: center;\n          gap: 0.5rem;\n        }\n        \n        /* Different color for deselect button */\n        #deselect-all-resources {\n          background-color: #6B7280; /* bg-gray-500 */\n        }\n        \n        #deselect-all-resources:hover {\n          background-color: #4B5563; /* bg-gray-600 */\n        }\n        \n        .select-all-btn:hover {\n          background-color: #4f46e5; /* bg-indigo-600 */\n        }\n        \n        .grid {\n          display: grid;\n          grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* Smaller cards */\n          gap: 0.5rem;\n        }\n        \n        .item-card {\n          border: 1px solid #374151; /* border-gray-700 */\n          border-radius: 0.375rem;\n          padding: 0.5rem;\n          background-color: #374151; /* bg-gray-700 */\n          cursor: pointer;\n          transition: all 0.1s ease;\n          display: flex;\n          align-items: flex-start;\n          box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px, rgba(0, 0, 0, 0.1) 0px 1px 2px;\n        }\n        \n        .item-card:hover {\n          background-color: #4B5563; /* bg-gray-600 */\n        }\n        \n        .item-card.selected {\n          border-color: #4338ca; /* border-indigo-700 */\n          background-color: rgba(79, 70, 229, 0.3); /* More visible background */\n          box-shadow: 0 0 0 2px #4338ca; /* Add an outline */\n        }\n        \n        .item-icon {\n          margin-right: 0.5rem;\n          color: #f3f4f6; /* text-gray-100 */\n          background: rgba(79, 70, 229, 0.2); /* bg-indigo-600 with opacity */\n          padding: 0.35rem;\n          border-radius: 0.25rem;\n          display: flex;\n          align-items: center;\n          justify-content: center;\n        }\n        \n        .item-icon svg {\n          width: 16px;\n          height: 16px;\n        }\n        \n        .item-details {\n          flex: 1;\n          min-width: 0; /* Allow text to truncate properly */\n        }\n        \n        .item-name {\n          font-weight: 500;\n          margin-bottom: 0.25rem;\n          word-break: break-word;\n          color: #f3f4f6; /* text-gray-100 */\n          white-space: nowrap;\n          overflow: hidden;\n          text-overflow: ellipsis;\n          position: relative; /* Added for tooltip positioning */\n          font-size: 0.8rem; /* Smaller font size */\n        }\n        \n        .tooltip {\n          position: absolute;\n          background-color: #1f2937;\n          border: 1px solid #374151;\n          color: #f3f4f6;\n          padding: 5px 8px;\n          border-radius: 4px;\n          font-size: 0.875rem;\n          white-space: normal;\n          max-width: 300px;\n          z-index: 1000;\n          box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n          word-wrap: break-word;\n          top: 100%;\n          left: 0;\n          margin-top: 5px;\n          display: none;\n        }\n        \n        .selected-list {\n          margin-top: 1rem;\n          border-top: 1px solid #374151; /* border-gray-700 */\n          padding-top: 1rem;\n        }\n        \n        .selected-list h2 {\n          font-size: 1rem;\n          font-weight: 600;\n          margin-top: 0;\n          margin-bottom: 1rem;\n          color: #f3f4f6; /* text-gray-100 */\n        }\n        \n        .selected-item {\n          display: flex;\n          justify-content: space-between;\n          align-items: center;\n          padding: 0.5rem 0.75rem;\n          background-color: #374151; /* bg-gray-700 */\n          border: 1px solid #4B5563; /* border-gray-600 */\n          border-radius: 0.375rem;\n          margin-bottom: 0.5rem;\n        }\n        \n        .remove-btn {\n          background: none;\n          border: none;\n          color: rgba(243, 244, 246, 0.7); /* text-gray-100 with opacity */\n          cursor: pointer;\n          padding: 0.25rem;\n          border-radius: 0.25rem;\n          display: flex;\n          align-items: center;\n          justify-content: center;\n        }\n        \n        .remove-btn:hover {\n          background-color: rgba(243, 244, 246, 0.1); /* text-gray-100 with more opacity */\n          color: #f3f4f6; /* text-gray-100 */\n        }\n        \n        .actions {\n          display: flex;\n          gap: 0.5rem;\n        }\n        \n        .cancel-btn {\n          background-color: #4B5563; /* bg-gray-600 */\n          color: #f3f4f6; /* text-gray-100 */\n          border: none;\n          padding: 0.6rem 1rem;\n          border-radius: 0.375rem;\n          font-weight: 500;\n          cursor: pointer;\n          font-size: 0.875rem;\n          transition: all 0.1s ease;\n        }\n        \n        .cancel-btn:hover {\n          background-color: #6B7280; /* bg-gray-500 */\n        }\n        \n        .submit-btn {\n          background-color: #4338ca; /* bg-indigo-700 */\n          color: white;\n          border: none;\n          padding: 0.6rem 1rem;\n          border-radius: 0.375rem;\n          font-weight: 500;\n          cursor: pointer;\n          font-size: 0.875rem;\n          transition: background-color 0.1s ease;\n        }\n        \n        .submit-btn:hover {\n          background-color: #4f46e5; /* bg-indigo-600 */\n        }\n        \n        .submit-btn:disabled {\n          background-color: #6B7280; /* Lighter gray */\n          opacity: 0.5;\n          cursor: not-allowed;\n          color: rgba(255, 255, 255, 0.5);\n          border: 1px solid #4B5563;\n        }\n        \n        .empty-message {\n          text-align: center;\n          color: rgba(243, 244, 246, 0.5); /* text-gray-100 with opacity */\n          padding: 1rem 0;\n          font-size: 0.875rem;\n        }\n        \n        /* Link icon styles */\n        .notion-link {\n          display: flex;\n          align-items: center;\n          justify-content: center;\n          color: rgba(243, 244, 246, 0.5); /* text-gray-100 with opacity */\n          width: 22px;\n          height: 22px;\n          border-radius: 0.25rem;\n          transition: all 0.1s ease;\n          margin-left: auto;\n          visibility: hidden; /* Hide by default, show on hover */\n        }\n        \n        .item-card:hover .notion-link {\n          visibility: visible; /* Show on hover */\n        }\n        \n        .notion-link:hover {\n          background-color: rgba(243, 244, 246, 0.1); /* text-gray-100 with opacity */\n          color: #f3f4f6; /* text-gray-100 */\n        }\n        \n        .loading-overlay {\n          position: fixed;\n          top: 0;\n          left: 0;\n          width: 100%;\n          height: 100%;\n          background-color: #1f2937;\n          display: flex;\n          justify-content: center;\n          align-items: center;\n          z-index: 9999;\n        }\n        \n        .loading-spinner {\n          display: flex;\n          flex-direction: column;\n          align-items: center;\n          gap: 1rem;\n          color: #f3f4f6;\n        }\n        \n        .loading-spinner svg {\n          animation: spin 1.5s linear infinite;\n        }\n        \n        .button-group {\n          display: flex;\n          gap: 0.5rem;\n        }\n        \n        .action-btn {\n          background-color: #4338ca; /* bg-indigo-700 */\n          color: #f3f4f6; /* text-gray-100 */\n          border: none;\n          border-radius: 0.375rem;\n          padding: 0.5rem 0.75rem;\n          font-size: 0.875rem;\n          cursor: pointer;\n          transition: all 0.1s ease;\n          display: flex;\n          align-items: center;\n          gap: 0.5rem;\n        }\n        \n        .action-btn:hover {\n          background-color: #4f46e5; /* bg-indigo-600 */\n        }\n        \n        @keyframes spin {\n          0% { transform: rotate(0deg); }\n          100% { transform: rotate(360deg); }\n        }\n      </style>\n    </head>\n    <body>\n      <div id=\"loading-overlay\" class=\"loading-overlay\">\n        <div class=\"loading-spinner\">\n          <svg width=\"50\" height=\"50\" viewBox=\"0 0 50 50\">\n            <circle cx=\"25\" cy=\"25\" r=\"20\" fill=\"none\" stroke=\"#4338ca\" stroke-width=\"5\" stroke-dasharray=\"30 10\"></circle>\n          </svg>\n          <p>Loading resources...</p>\n        </div>\n      </div>\n      \n      <div class=\"container\">\n        <div class=\"top-bar\">\n          <h2>Select Notion Resources</h2>\n          <div class=\"actions\">\n            <button id=\"cancel-button\" class=\"cancel-btn\">Cancel</button>\n            <button id=\"submit-button\" class=\"submit-btn\" disabled>Save Selection</button>\n          </div>\n        </div>\n        \n        <div class=\"content-section\">\n          <div class=\"tab-header\">\n            <h2>Available Resources</h2>\n            <div class=\"button-group\">\n              <button class=\"action-btn\" id=\"select-all-resources\">\n                <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n                  <path d=\"M20 6L9 17l-5-5\"></path>\n                </svg>\n                Select All\n              </button>\n              <button class=\"action-btn\" id=\"deselect-all-resources\">\n                <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n                  <path d=\"M19 12H5\"></path>\n                </svg>\n                Deselect All\n              </button>\n            </div>\n          </div>\n          \n          <div class=\"grid\" id=\"resources-grid\">\n            <!-- Resources will be loaded here -->\n          </div>\n        </div>\n        \n        <div class=\"selected-list\">\n          <h2>Selected Items</h2>\n          <div id=\"selected-items-container\">\n            <div class=\"empty-message\">No items selected</div>\n          </div>\n        </div>\n      </div>\n      \n      <script${nonce ? ` nonce=\"${nonce}\"` : ''}>\n        // Store selected items\n        const selectedItems = ${existingSelectionStr};\n        let dataLoaded = false;\n        const accessToken = \"${accessToken}\";\n        \n        // Initialize the UI when the page loads\n        document.addEventListener('DOMContentLoaded', function() {\n          // First, set up the event handlers\n          setupEventHandlers();\n          \n          // Then fetch resources from Notion\n          fetchNotionResources();\n          \n          // Set a timeout to hide loading screen even if fetch fails\n          setTimeout(function() {\n            if (!dataLoaded) hideLoadingScreen();\n          }, 5000);\n        });\n        \n        // Helper function to escape HTML\n        function escapeHtml(unsafe) {\n          if (!unsafe) return '';\n          return unsafe\n            .replace(/&/g, \"&amp;\")\n            .replace(/</g, \"&lt;\")\n            .replace(/>/g, \"&gt;\")\n            .replace(/\"/g, \"&quot;\")\n            .replace(/'/g, \"&#039;\");\n        }\n        \n        // Fetch resources from Notion API\n        async function fetchNotionResources() {\n          try {\n            // Fetch databases and pages in parallel\n            const [databases, pages] = await Promise.all([\n              fetchDatabases(accessToken),\n              fetchPages(accessToken)\n            ]);\n            \n            // Render them to the UI\n            renderResources(databases, pages);\n            \n            // Update the selected items list\n            updateSelectedItemsList();\n            \n            // Mark data as loaded and hide loading screen\n            dataLoaded = true;\n            hideLoadingScreen();\n          } catch (error) {\n            console.error('Error fetching Notion resources:', error);\n            showError('Failed to load resources from Notion. Please try again.');\n            hideLoadingScreen();\n          }\n        }\n        \n        // Fetch databases from Notion\n        async function fetchDatabases(token) {\n          const response = await fetch('https://api.notion.com/v1/search', {\n            method: 'POST',\n            headers: {\n              'Authorization': \\`Bearer \\${token}\\`,\n              'Notion-Version': '2022-06-28',\n              'Content-Type': 'application/json'\n            },\n            body: JSON.stringify({\n              filter: {\n                value: 'database',\n                property: 'object'\n              },\n              page_size: 100\n            })\n          });\n          \n          if (!response.ok) {\n            throw new Error(\\`Failed to fetch databases: \\${response.status}\\`);\n          }\n          \n          const data = await response.json();\n          \n          return data.results.map(db => ({\n            id: db.id,\n            name: db.title?.[0]?.plain_text || 'Untitled Database',\n            type: 'database',\n            url: db.url || \\`https://notion.so/\\${db.id.replace(/-/g, '')}\\`\n          }));\n        }\n        \n        // Fetch pages from Notion\n        async function fetchPages(token) {\n          const response = await fetch('https://api.notion.com/v1/search', {\n            method: 'POST',\n            headers: {\n              'Authorization': \\`Bearer \\${token}\\`,\n              'Notion-Version': '2022-06-28',\n              'Content-Type': 'application/json'\n            },\n            body: JSON.stringify({\n              filter: {\n                value: 'page',\n                property: 'object'\n              },\n              page_size: 100\n            })\n          });\n          \n          if (!response.ok) {\n            throw new Error(\\`Failed to fetch pages: \\${response.status}\\`);\n          }\n          \n          const data = await response.json();\n          \n          return data.results.map(page => ({\n            id: page.id,\n            title: getPageTitle(page) || 'Untitled Page',\n            type: 'page',\n            url: page.url || \\`https://notion.so/\\${page.id.replace(/-/g, '')}\\`\n          }));\n        }\n        \n        // Helper to get page title from Notion API response\n        function getPageTitle(page) {\n          // Try to get title from properties.title (most common case)\n          if (page.properties?.title?.title?.[0]?.plain_text) {\n            return page.properties.title.title[0].plain_text;\n          }\n          \n          // Try to get title from properties.Name (also common)\n          if (page.properties?.Name?.title?.[0]?.plain_text) {\n            return page.properties.Name.title[0].plain_text;\n          }\n          \n          // Try to find any property that has a title type\n          if (page.properties) {\n            for (const [key, value] of Object.entries(page.properties)) {\n              if (value.type === 'title' && value.title?.[0]?.plain_text) {\n                return value.title[0].plain_text;\n              }\n            }\n          }\n          \n          // For database pages in the parent format\n          if (page.parent?.type === 'database_id' && page.child_page?.title) {\n            return page.child_page.title;\n          }\n          \n          // If no title is found\n          return '';\n        }\n        \n        // Render databases and pages to the UI\n        function renderResources(databases, pages) {\n          const grid = document.getElementById('resources-grid');\n          grid.innerHTML = '';\n          \n          // Handle empty case\n          if (databases.length === 0 && pages.length === 0) {\n            grid.innerHTML = '<div class=\"empty-message\">No resources available</div>';\n            return;\n          }\n          \n          // Render databases\n          databases.forEach(db => {\n            const isSelected = selectedItems[db.id] !== undefined;\n            const card = document.createElement('div');\n            card.className = \\`item-card\\${isSelected ? ' selected' : ''}\\`;\n            card.setAttribute('data-id', db.id);\n            card.setAttribute('data-name', db.name);\n            card.setAttribute('data-type', 'database');\n            \n            card.innerHTML = \\`\n              <div class=\"item-icon\">\n                <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n                  <path d=\"M3 3h18v18H3z\"></path>\n                  <path d=\"M3 9h18\"></path>\n                  <path d=\"M3 15h18\"></path>\n                  <path d=\"M9 3v18\"></path>\n                </svg>\n              </div>\n              <div class=\"item-details\">\n                <div class=\"item-name\" title=\"\\${escapeHtml(db.name)}\">\\${escapeHtml(db.name)}</div>\n              </div>\n              <a href=\"\\${escapeHtml(db.url)}\" target=\"_blank\" class=\"notion-link\" title=\"Open in Notion\">\n                <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n                  <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"></path>\n                  <polyline points=\"15 3 21 3 21 9\"></polyline>\n                  <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"></line>\n                </svg>\n              </a>\n            \\`;\n\n            // Set up click handler for card\n            card.addEventListener('click', function() {\n              toggleItemSelection(this);\n            });\n\n            // Prevent link click from triggering card selection\n            const link = card.querySelector('.notion-link');\n            if (link) {\n              link.addEventListener('click', function(e) {\n                e.stopPropagation();\n              });\n            }\n            \n            grid.appendChild(card);\n          });\n          \n          // Render pages\n          pages.forEach(page => {\n            const isSelected = selectedItems[page.id] !== undefined;\n            const card = document.createElement('div');\n            card.className = \\`item-card\\${isSelected ? ' selected' : ''}\\`;\n            card.setAttribute('data-id', page.id);\n            card.setAttribute('data-name', page.title);\n            card.setAttribute('data-type', 'page');\n            \n            card.innerHTML = \\`\n              <div class=\"item-icon\">\n                <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n                  <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"></path>\n                  <polyline points=\"14 2 14 8 20 8\"></polyline>\n                  <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"></line>\n                  <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"></line>\n                  <polyline points=\"10 9 9 9 8 9\"></polyline>\n                </svg>\n              </div>\n              <div class=\"item-details\">\n                <div class=\"item-name\" title=\"\\${escapeHtml(page.title)}\">\\${escapeHtml(page.title)}</div>\n              </div>\n              <a href=\"\\${escapeHtml(page.url)}\" target=\"_blank\" class=\"notion-link\" title=\"Open in Notion\">\n                <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n                  <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"></path>\n                  <polyline points=\"15 3 21 3 21 9\"></polyline>\n                  <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"></line>\n                </svg>\n              </a>\n            \\`;\n\n            // Set up click handler for card\n            card.addEventListener('click', function() {\n              toggleItemSelection(this);\n            });\n\n            // Prevent link click from triggering card selection\n            const pageLink = card.querySelector('.notion-link');\n            if (pageLink) {\n              pageLink.addEventListener('click', function(e) {\n                e.stopPropagation();\n              });\n            }\n            \n            grid.appendChild(card);\n          });\n        }\n        \n        // Toggle selection state of an item\n        function toggleItemSelection(card) {\n          const id = card.getAttribute('data-id');\n          const name = card.getAttribute('data-name');\n          const type = card.getAttribute('data-type');\n          \n          if (selectedItems[id]) {\n            // Item is currently selected, so deselect it\n            delete selectedItems[id];\n            card.classList.remove('selected');\n          } else {\n            // Item is not selected, so select it\n            selectedItems[id] = {\n              id,\n              title: name,\n              type,\n              pageId: id\n            };\n            card.classList.add('selected');\n          }\n          \n          // Update the UI\n          updateSelectedItemsList();\n        }\n        \n        // Update the list of selected items\n        function updateSelectedItemsList() {\n          const container = document.getElementById('selected-items-container');\n          const submitButton = document.getElementById('submit-button');\n          const itemCount = Object.keys(selectedItems).length;\n          \n          if (itemCount === 0) {\n            container.innerHTML = '<div class=\"empty-message\">No items selected</div>';\n            submitButton.disabled = true;\n          } else {\n            let html = '';\n            Object.values(selectedItems).forEach(item => {\n              const name = item.title || item.name;\n              html += \\`\n                <div class=\"selected-item\" data-id=\"\\${item.id}\">\n                  <div class=\"item-name\" title=\"\\${escapeHtml(name)}\">\\${escapeHtml(name)}</div>\n                  <button class=\"remove-btn\" data-item-id=\"\\${item.id}\">\n                    <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n                      <path d=\"M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n                    </svg>\n                  </button>\n                </div>\n              \\`;\n            });\n            container.innerHTML = html;\n            submitButton.disabled = false;\n            \n            // Add event listeners to remove buttons\n            container.querySelectorAll('.remove-btn').forEach(btn => {\n              btn.addEventListener('click', function() {\n                const itemId = this.getAttribute('data-item-id');\n                removeItem(itemId);\n              });\n            });\n          }\n        }\n        \n        // Remove an item from selection\n        function removeItem(id) {\n          delete selectedItems[id];\n          \n          // Also update the card in the grid if present\n          const card = document.querySelector(\\`.item-card[data-id=\"\\${id}\"]\\`);\n          if (card) {\n            card.classList.remove('selected');\n          }\n          \n          updateSelectedItemsList();\n        }\n        \n        // Hide the loading screen\n        function hideLoadingScreen() {\n          const loadingOverlay = document.getElementById('loading-overlay');\n          if (loadingOverlay) {\n            loadingOverlay.style.opacity = '0';\n            loadingOverlay.style.transition = 'opacity 0.3s ease';\n            setTimeout(() => {\n              loadingOverlay.style.display = 'none';\n            }, 300);\n          }\n        }\n        \n        // Show an error message\n        function showError(message) {\n          const topBar = document.querySelector('.top-bar');\n          \n          // Create error element if it doesn't exist\n          let errorEl = document.getElementById('error-container');\n          if (!errorEl) {\n            errorEl = document.createElement('div');\n            errorEl.id = 'error-container';\n            errorEl.className = 'error';\n            topBar.insertAdjacentElement('afterend', errorEl);\n          }\n          \n          errorEl.innerHTML = \\`\n            <div style=\"background-color: rgba(220, 38, 38, 0.1); border: 1px solid rgba(220, 38, 38, 0.2); color: #ef4444; padding: 0.75rem; border-radius: 0.375rem; margin-bottom: 1rem;\">\n              <p style=\"margin: 0;\">\\${escapeHtml(message)}</p>\n            </div>\n          \\`;\n        }\n        \n        // Set up UI event handlers\n        function setupEventHandlers() {\n          // Select All button\n          document.getElementById('select-all-resources').addEventListener('click', function() {\n            document.querySelectorAll('#resources-grid .item-card').forEach(card => {\n              const id = card.getAttribute('data-id');\n              const name = card.getAttribute('data-name');\n              const type = card.getAttribute('data-type');\n              \n              if (!selectedItems[id]) {\n                selectedItems[id] = {\n                  id,\n                  title: name,\n                  type,\n                  pageId: id\n                };\n                card.classList.add('selected');\n              }\n            });\n            \n            updateSelectedItemsList();\n          });\n          \n          // Deselect All button\n          document.getElementById('deselect-all-resources').addEventListener('click', function() {\n            document.querySelectorAll('#resources-grid .item-card').forEach(card => {\n              const id = card.getAttribute('data-id');\n              delete selectedItems[id];\n              card.classList.remove('selected');\n            });\n            \n            updateSelectedItemsList();\n          });\n          \n          // Cancel button\n          document.getElementById('cancel-button').addEventListener('click', function() {\n            // Send cancel message to parent window\n            window.parent.postMessage({\n              type: 'notion-selection-cancelled'\n            }, '*');\n            \n            // Close the window if possible\n            if (window.opener) {\n              window.close();\n            }\n          });\n          \n          // Submit button\n          document.getElementById('submit-button').addEventListener('click', function() {\n            if (Object.keys(selectedItems).length === 0) {\n              return;\n            }\n            \n            // Format the selected items for the response\n            const response = {\n              selectedPages: {},\n              accessToken\n            };\n            \n            // Add each selected item to the response\n            Object.values(selectedItems).forEach(item => {\n              response.selectedPages[item.id] = {\n                title: item.title,\n                pageId: item.id,\n                parentType: item.parentType || item.type\n              };\n            });\n            \n            // Send the result back to the parent window\n            window.parent.postMessage({\n              type: 'notion-selection-complete',\n              payload: response\n            }, '*');\n            \n            // Close the window if possible\n            if (window.opener) {\n              setTimeout(() => window.close(), 500);\n            }\n          });\n        }\n      </script>\n    </body>\n    </html>`;\n  }\n}","import { BaseOAuth } from '../../baseOAuth/core/oauth';\nimport { OAuthConfig, OAuthError, OAuthResponse } from '../../baseOAuth/types';\nimport { NotionOAuthConfig } from '../types';\nimport { exchangeNotionCodeForTokens } from '../utils/token';\nimport { NotionPicker } from '../ui/picker';\n\n/**\n * Notion specific OAuth implementation\n */\nexport class NotionOAuth extends BaseOAuth {\n  /**\n   * Validates Notion specific configuration\n   * @param config The OAuth configuration to validate\n   * @throws OAuthError if configuration is invalid\n   */\n  protected static override validateConnectorConfig(config: OAuthConfig): void {\n    const notionConfig = config as NotionOAuthConfig;\n    \n    if (!notionConfig.clientId) {\n      throw new OAuthError('Missing clientId in configuration', 'CONFIGURATION_ERROR');\n    }\n    \n    if (!notionConfig.clientSecret) {\n      throw new OAuthError('Missing clientSecret in configuration', 'CONFIGURATION_ERROR');\n    }\n  }\n\n  /**\n   * Creates an OAuth popup window for Notion authentication\n   * @param config The OAuth configuration\n   * @returns The popup window instance or null if creation failed\n   */\n  public static override startOAuth(config: NotionOAuthConfig): Window | null {\n    try {\n      this.validateConfig(config);\n\n      const {\n        clientId,\n        redirectUri,\n        scopes = [\"page:read\", \"database:read\"],\n      } = config;\n\n      // Set up the OAuth handler in the window\n      this.setupOAuthHandler(config);\n\n      // Build OAuth URL with parameters\n      const params = new URLSearchParams({\n        client_id: clientId,\n        redirect_uri: redirectUri,\n        response_type: \"code\",\n        owner: \"user\",\n        scope: scopes.join(' ')\n      });\n\n      const authUrl = `https://api.notion.com/v1/oauth/authorize?${params.toString()}`;\n\n      // Create the popup window\n      const popup = this.createOAuthPopup(authUrl, 'Notion OAuth Login');\n      \n      // Monitor the popup\n      if (popup) {\n        this.monitorPopup(popup);\n      }\n\n      return popup;\n    } catch (error) {\n      if (error instanceof OAuthError) {\n        config.onError?.(error);\n      } else {\n        config.onError?.(\n          new OAuthError(\n            error instanceof Error ? error.message : 'An unknown error occurred',\n            'UNKNOWN_ERROR',\n            error\n          )\n        );\n      }\n      return null;\n    }\n  }\n\n  /**\n   * Creates a response for the OAuth callback page\n   * @param code Authorization code from the OAuth redirect\n   * @param config The OAuth configuration\n   * @param error Optional error from the OAuth process\n   * @param nonce Optional nonce for Content Security Policy\n   * @returns A Response object with the callback page\n   */\n  public static override async createCallbackResponse(\n    code: string,\n    config: NotionOAuthConfig,\n    error?: string | OAuthError,\n    nonce?: string\n  ): Promise<Response> {\n    if (error) {\n      const errorObj = typeof error === 'string' ? new OAuthError(error, 'CALLBACK_ERROR') : error;\n      return this.createErrorResponse(errorObj, nonce);\n    }\n\n    try {\n      const tokens = await exchangeNotionCodeForTokens(\n        code,\n        config.clientId,\n        config.clientSecret,\n        config.redirectUri\n      );\n\n      // Use the Notion picker template\n      const htmlContent = NotionPicker.createPickerHTML(tokens, config, tokens.access_token, undefined, nonce);\n\n      return new Response(htmlContent, { headers: { 'Content-Type': 'text/html' } });\n    } catch (error) {\n      return this.createErrorResponse(\n        error instanceof OAuthError ? error : new OAuthError(\n          error instanceof Error ? error.message : 'Failed to create callback page',\n          'CALLBACK_ERROR',\n          error\n        ),\n        nonce\n      );\n    }\n  }\n\n  /**\n   * Redirects the user to the Vectorize Notion connector authentication flow\n   * with a one-time token for security\n   *\n   * @param oneTimeToken The security token for authentication\n   * @param organizationId Organization ID for the connection\n   * @param platformUrl Optional URL of the Vectorize platform (primarily used for testing)\n   * @returns Promise that resolves when the redirect is ready\n   */\n  public static override async redirectToVectorizeConnect(\n    oneTimeToken: string,\n    organizationId: string,\n    platformUrl: string = 'https://platform.vectorize.io'\n  ): Promise<void> {\n    // Build the redirect URL with the token as a query parameter\n    const connectUrl = new URL(`${platformUrl}/connect/notion`);\n    connectUrl.searchParams.append('token', oneTimeToken);\n    connectUrl.searchParams.append('organizationId', organizationId);\n\n    // Use the base iframe implementation with Notion specific settings\n    return this.createConnectIframe(connectUrl.toString(), {\n      originPattern: /vectorize\\.io$/,\n      successMessage: 'vectorize-connect-complete'\n    });\n  }\n\n  /**\n   * Redirects the user to the Vectorize Notion connector edit flow\n   * with a one-time token for security\n   *\n   * @param oneTimeToken The security token for authentication\n   * @param organizationId Organization ID for the connection\n   * @param platformUrl Optional URL of the Vectorize platform (primarily used for testing)\n   * @returns Promise that resolves when the redirect is ready\n   */\n  public static override async redirectToVectorizeEdit(\n    oneTimeToken: string,\n    organizationId: string,\n    platformUrl: string = 'https://platform.vectorize.io'\n  ): Promise<void> {\n    // Build the redirect URL with the token as a query parameter\n    const editUrl = new URL(`${platformUrl}/connect/notion/edit`);\n    editUrl.searchParams.append('token', oneTimeToken);\n    editUrl.searchParams.append('organizationId', organizationId);\n\n    // Use the base iframe implementation with Notion specific settings\n    return this.createConnectIframe(editUrl.toString(), {\n      originPattern: /vectorize\\.io$/,\n      successMessage: 'vectorize-edit-complete'\n    });\n  }\n}"]}