{"version":3,"file":"ad-client.mjs","sources":["../../../../src/lib/auth/active-directory/ad-client.ts"],"sourcesContent":["/**\n * Active Directory / Microsoft Graph API Client\n *\n * Enterprise-grade client for interacting with Azure AD, AD FS,\n * and Microsoft Graph API. Supports token management, user operations,\n * and group membership resolution.\n *\n * @module auth/active-directory/ad-client\n */\n\nimport type {\n  ADAuthError,\n  ADConfig,\n  ADGroup,\n  ADTokens,\n  ADUser,\n  ADUserAttributes,\n  GraphAPIError,\n  GraphAPIRequest,\n  GraphAPIResponse,\n  TokenRefreshResult,\n} from './types';\n\nimport { getAuthorityUrl, getConfiguredScopes } from '@/lib/auth';\nimport { ms } from '../../shared/type-utils';\nimport {\n  DEFAULT_MAX_RETRY_ATTEMPTS,\n  DEFAULT_RETRY_BASE_DELAY,\n  DEFAULT_TIMEOUT,\n  GRAPH_API,\n} from '@/lib/core/config/constants';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst GRAPH_BASE_URL = GRAPH_API.BASE_URL;\nconst GRAPH_DEFAULT_VERSION = GRAPH_API.DEFAULT_VERSION;\nconst MAX_RETRIES = DEFAULT_MAX_RETRY_ATTEMPTS;\nconst RETRY_DELAY = DEFAULT_RETRY_BASE_DELAY;\n\n/**\n * Common Graph API endpoints.\n */\nexport const GRAPH_ENDPOINTS = {\n  ME: '/me',\n  ME_PHOTO: '/me/photo/$value',\n  ME_MEMBER_OF: '/me/memberOf',\n  ME_TRANSITIVE_MEMBER_OF: '/me/transitiveMemberOf',\n  USERS: '/users',\n  GROUPS: '/groups',\n  DIRECTORY_ROLES: '/directoryRoles',\n} as const;\n\n// =============================================================================\n// AD Client Class\n// =============================================================================\n\n/**\n * Active Directory and Graph API client.\n *\n * Provides a unified interface for interacting with various AD providers\n * and the Microsoft Graph API. Handles token management, caching, and\n * automatic retries.\n *\n * @example\n * ```typescript\n * const client = new ADClient(config);\n * await client.initialize(tokens);\n *\n * const user = await client.getCurrentUser();\n * const groups = await client.getUserGroups();\n * ```\n */\nexport class ADClient {\n  private readonly config: ADConfig;\n  private tokens: ADTokens | null = null;\n  private tokenRefreshPromise: Promise<TokenRefreshResult> | null = null;\n  private readonly onTokenRefresh?: (tokens: ADTokens) => void;\n  private readonly onAuthError?: (error: ADAuthError) => void;\n  private readonly debug: boolean;\n\n  /**\n   * Create a new AD client instance.\n   *\n   * @param config - AD configuration\n   * @param options - Additional options\n   */\n  constructor(\n    config: ADConfig,\n    options?: {\n      onTokenRefresh?: (tokens: ADTokens) => void;\n      onAuthError?: (error: ADAuthError) => void;\n    }\n  ) {\n    this.config = config;\n    this.debug = config.debug ?? false;\n    this.onTokenRefresh = options?.onTokenRefresh;\n    this.onAuthError = options?.onAuthError;\n  }\n\n  // ===========================================================================\n  // Initialization & Token Management\n  // ===========================================================================\n\n  /**\n   * Initialize the client with tokens.\n   *\n   * @param tokens - Initial AD tokens\n   */\n  initialize(tokens: ADTokens): void {\n    this.tokens = tokens;\n    this.log('Client initialized with tokens');\n  }\n\n  /**\n   * Update the current tokens.\n   *\n   * @param tokens - New tokens to use\n   */\n  setTokens(tokens: ADTokens): void {\n    this.tokens = tokens;\n  }\n\n  /**\n   * Get the current access token.\n   *\n   * @returns Current access token or null\n   */\n  getAccessToken(): string | null {\n    return this.tokens?.accessToken ?? null;\n  }\n\n  /**\n   * Check if tokens are expired or about to expire.\n   *\n   * @param bufferMs - Buffer time in milliseconds (default: 5 minutes)\n   * @returns Whether tokens need refresh\n   */\n  isTokenExpired(bufferMs = 300000): boolean {\n    if (!this.tokens) return true;\n    return Date.now() >= this.tokens.expiresAt - bufferMs;\n  }\n\n  /**\n   * Refresh tokens using the refresh token.\n   *\n   * This method handles concurrent refresh requests by returning\n   * the same promise for overlapping calls.\n   *\n   * @returns Token refresh result\n   */\n  async refreshTokens(): Promise<TokenRefreshResult> {\n    if (this.tokenRefreshPromise != null) {\n      return this.tokenRefreshPromise;\n    }\n\n    if (this.tokens?.refreshToken == null || this.tokens.refreshToken === '') {\n      return {\n        success: false,\n        requiresInteraction: true,\n        error: this.createError('no_refresh_token', 'No refresh token available'),\n      };\n    }\n\n    this.tokenRefreshPromise = this.performTokenRefresh();\n\n    try {\n\n      return await this.tokenRefreshPromise;\n    } finally {\n      this.tokenRefreshPromise = null;\n    }\n  }\n\n  /**\n   * Make a request to the Microsoft Graph API.\n   *\n   * @param request - Graph API request configuration\n   * @returns Graph API response\n   */\n  async graphRequest<T = unknown>(request: GraphAPIRequest): Promise<GraphAPIResponse<T>> {\n    const version = request.version ?? GRAPH_DEFAULT_VERSION;\n    const method = request.method ?? 'GET';\n    const url = this.buildGraphUrl(request.endpoint, version, request.query);\n\n    // Ensure we have valid tokens\n    if (this.isTokenExpired()) {\n      const refreshResult = await this.refreshTokens();\n      if (!refreshResult.success) {\n        throw new GraphAPIClientError(\n          'token_expired',\n          'Token expired and refresh failed',\n          refreshResult.error\n        );\n      }\n    }\n\n    const accessToken = this.tokens?.accessToken;\n    if (accessToken == null) {\n      throw new GraphAPIClientError('no_token', 'No access token available');\n    }\n\n    const headers: Record<string, string> = {\n      'Authorization': `Bearer ${accessToken}`,\n      'Content-Type': 'application/json',\n      ...request.headers,\n    };\n\n    const fetchOptions: RequestInit = {\n      method,\n      headers,\n      body: (request.body != null) ? JSON.stringify(request.body) : undefined,\n    };\n\n    return this.executeWithRetry<T>(url, fetchOptions, (request.timeout !== null && request.timeout !== undefined && request.timeout !== 0) ? ms(request.timeout) : undefined);\n  }\n\n  /**\n   * Get the current authenticated user's profile from Graph API.\n   *\n   * @returns Current user with AD attributes\n   */\n  async getCurrentUser(): Promise<ADUser> {\n    const [userResponse, groupsResponse] = await Promise.all([\n      this.graphRequest<GraphUserProfile>({\n        endpoint: GRAPH_ENDPOINTS.ME,\n        query: {\n          $select: [\n            'id',\n            'userPrincipalName',\n            'displayName',\n            'givenName',\n            'surname',\n            'mail',\n            'jobTitle',\n            'department',\n            'officeLocation',\n            'mobilePhone',\n            'businessPhones',\n            'employeeId',\n            'companyName',\n            'userType',\n            'accountEnabled',\n            'createdDateTime',\n            'onPremisesSamAccountName',\n            'onPremisesDomainName',\n          ].join(','),\n        },\n      }),\n      this.getUserGroupsInternal(),\n    ]);\n\n    const profile = userResponse.data;\n\n\n    return this.mapGraphUserToADUser(profile, groupsResponse);\n  }\n\n  // ===========================================================================\n  // Graph API Operations\n  // ===========================================================================\n\n  /**\n   * Get a user by their ID or UPN.\n   *\n   * @param userId - User ID or UPN\n   * @returns User profile\n   */\n  async getUser(userId: string): Promise<ADUser> {\n    const [userResponse, groupsResponse] = await Promise.all([\n      this.graphRequest<GraphUserProfile>({\n        endpoint: `${GRAPH_ENDPOINTS.USERS}/${encodeURIComponent(userId)}`,\n      }),\n      this.graphRequest<GraphGroupListResponse>({\n        endpoint: `${GRAPH_ENDPOINTS.USERS}/${encodeURIComponent(userId)}/memberOf`,\n      }),\n    ]);\n\n    const groups = this.mapGraphGroups(groupsResponse.data.value);\n\n    return this.mapGraphUserToADUser(userResponse.data, groups);\n  }\n\n  /**\n   * Get the current user's profile photo.\n   *\n   * @returns Photo as blob URL or null\n   */\n  async getUserPhoto(): Promise<string | null> {\n    try {\n      const accessToken = this.tokens?.accessToken;\n      if (accessToken == null) {\n        return null;\n      }\n\n      const response = await fetch(\n        `${GRAPH_BASE_URL}/${GRAPH_DEFAULT_VERSION}${GRAPH_ENDPOINTS.ME_PHOTO}`,\n        {\n          headers: {\n            'Authorization': `Bearer ${accessToken}`,\n          },\n        }\n      );\n\n      if (!response.ok) {\n        return null;\n      }\n\n      const blob = await response.blob();\n      return URL.createObjectURL(blob);\n    } catch {\n      return null;\n    }\n  }\n\n  /**\n   * Get the current user's group memberships.\n   *\n   * @param transitive - Include transitive (nested) memberships\n   * @returns Array of AD groups\n   */\n  async getUserGroups(transitive = false): Promise<ADGroup[]> {\n    return this.getUserGroupsInternal(transitive);\n  }\n\n  /**\n   * Check if user is a member of a specific group.\n   *\n   * @param groupId - Group ID to check\n   * @param transitive - Check transitive membership\n   * @returns Whether user is a member\n   */\n  async checkGroupMembership(groupId: string, transitive = true): Promise<boolean> {\n    try {\n      const response = await this.graphRequest<{ value: boolean }>({\n        endpoint: `/me/checkMemberGroups`,\n        method: 'POST',\n        body: {\n          groupIds: [groupId],\n        },\n      });\n\n      return response.data.value;\n    } catch {\n      // Fall back to fetching all groups\n      const groups = await this.getUserGroups(transitive);\n      return groups.some(g => g.id === groupId);\n    }\n  }\n\n  /**\n   * Perform the actual token refresh operation.\n   *\n   * Note: This method intentionally uses raw fetch() rather than apiClient because:\n   * 1. OAuth token endpoints require specific Content-Type (x-www-form-urlencoded)\n   * 2. Token refresh is a foundational auth operation that apiClient depends on\n   * 3. Auth endpoints are identity providers (Azure AD, etc.), not the main API\n   *\n   * @see {@link @/lib/api/api-client} for authenticated application API calls\n   */\n  private async performTokenRefresh(): Promise<TokenRefreshResult> {\n    const authority = getAuthorityUrl(this.config);\n    if (authority == null || authority === '') {\n      return {\n        success: false,\n        error: this.createError('config_error', 'No authority URL configured'),\n      };\n    }\n\n    try {\n      // This would integrate with MSAL or custom OAuth implementation\n      // For now, we provide a placeholder that can be extended\n      const tokenEndpoint = `${authority}/oauth2/v2.0/token`;\n\n      // Raw fetch is intentional - OAuth requires x-www-form-urlencoded body\n      const refreshToken = this.tokens?.refreshToken;\n      if (refreshToken == null) {\n        throw new Error('No refresh token available');\n      }\n\n      const response = await fetch(tokenEndpoint, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/x-www-form-urlencoded',\n        },\n        body: new URLSearchParams({\n          grant_type: 'refresh_token',\n          refresh_token: refreshToken,\n          client_id: this.getClientId(),\n          scope: getConfiguredScopes(this.config).join(' '),\n        }),\n      });\n\n      if (!response.ok) {\n        const errorData = await response.json().catch(() => ({} as { error?: string; error_description?: string })) as { error?: string; error_description?: string };\n        const error = this.createError(\n          (errorData.error != null && errorData.error !== '') ? errorData.error : 'token_refresh_failed',\n          (errorData.error_description != null && errorData.error_description !== '') ? errorData.error_description : 'Failed to refresh token'\n        );\n\n        this.onAuthError?.(error);\n\n        return {\n          success: false,\n          error,\n          requiresInteraction: errorData.error === 'invalid_grant',\n        };\n      }\n\n      const data = await response.json() as {\n        access_token: string;\n        id_token: string;\n        refresh_token?: string;\n        expires_in: number;\n        scope?: string;\n        token_type?: string;\n      };\n      const newTokens: ADTokens = {\n        accessToken: data.access_token,\n        idToken: data.id_token,\n        refreshToken: (data.refresh_token != null && data.refresh_token !== '') ? data.refresh_token : (this.tokens?.refreshToken ?? ''),\n        expiresAt: Date.now() + (data.expires_in * 1000),\n        scopes: (data.scope != null && data.scope !== '') ? data.scope.split(' ') : [],\n        tokenType: (data.token_type != null && data.token_type !== '') ? data.token_type : 'Bearer',\n      };\n\n      this.tokens = newTokens;\n      this.onTokenRefresh?.(newTokens);\n\n      return { success: true, tokens: newTokens };\n    } catch (error: unknown) {\n      const authError = this.createError(\n        'network_error',\n        'Network error during token refresh',\n        error as Error\n      );\n      this.onAuthError?.(authError);\n\n      return { success: false, error: authError };\n    }\n  }\n\n  // ===========================================================================\n  // User Operations\n  // ===========================================================================\n\n  /**\n   * Get the client ID from configuration.\n   */\n  private getClientId(): string {\n    switch (this.config.providerType) {\n      case 'azure-ad':\n        return this.config.azure?.clientId ?? '';\n      case 'azure-ad-b2c':\n        return this.config.azureB2C?.clientId ?? '';\n      case 'adfs':\n        return this.config.adfs?.clientId ?? '';\n      default:\n        return '';\n    }\n  }\n\n  /**\n   * Build the full Graph API URL.\n   */\n  private buildGraphUrl(\n    endpoint: string,\n    version: string,\n    query?: Record<string, string | number | boolean>\n  ): string {\n    const baseUrl = `${GRAPH_BASE_URL}/${version}${endpoint}`;\n\n    if (!query || Object.keys(query).length === 0) {\n      return baseUrl;\n    }\n\n    const searchParams = new URLSearchParams();\n    Object.entries(query).forEach(([key, value]) => {\n      searchParams.append(key, String(value));\n    });\n\n    return `${baseUrl}?${searchParams.toString()}`;\n  }\n\n  /**\n   * Execute a request with automatic retries.\n   */\n  private async executeWithRetry<T>(\n    url: string,\n    options: RequestInit,\n    timeout = DEFAULT_TIMEOUT\n  ): Promise<GraphAPIResponse<T>> {\n    let lastError: Error | null = null;\n\n    for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n      try {\n        const controller = new AbortController();\n        const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n        const response = await fetch(url, {\n          ...options,\n          signal: controller.signal,\n        });\n\n        clearTimeout(timeoutId);\n\n        const correlationId = response.headers.get('request-id') ?? undefined;\n\n        if (!response.ok) {\n          const errorBody = await response.json().catch(() => ({ code: undefined, message: undefined })) as GraphAPIError;\n\n          // Don't retry 4xx errors (except 429 rate limiting)\n          if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n            throw new GraphAPIClientError(\n              errorBody.code || 'unknown_error',\n              errorBody.message || `Graph API error: ${response.status}`,\n              errorBody\n            );\n          }\n\n          // Retry 5xx errors and 429\n          if (response.status === 429) {\n            const retryAfter = response.headers.get('Retry-After');\n            const parsedRetryAfter = (retryAfter != null && retryAfter !== '') ? parseInt(retryAfter, 10) : null;\n            const delay = (parsedRetryAfter != null && parsedRetryAfter > 0) ? parsedRetryAfter * 1000 : RETRY_DELAY * (attempt + 1);\n            await this.delay(delay);\n            continue;\n          }\n\n          throw new Error(`Graph API error: ${response.status}`);\n        }\n\n        const data = await response.json() as T;\n\n        // Extract pagination info for collection responses\n        const pagination = this.extractPagination(data);\n\n        return {\n          data,\n          headers: Object.fromEntries(response.headers.entries()),\n          status: response.status,\n          correlationId,\n          pagination,\n        };\n      } catch (error: unknown) {\n        lastError = error as Error;\n\n        if (error instanceof GraphAPIClientError) {\n          throw error;\n        }\n\n        if ((error as Error).name === 'AbortError') {\n          throw new GraphAPIClientError('timeout', 'Request timed out');\n        }\n\n        // Retry on network errors\n        if (attempt < MAX_RETRIES - 1) {\n          await this.delay(RETRY_DELAY * (attempt + 1));\n\n        }\n      }\n    }\n\n    throw lastError ?? new Error('Request failed after max retries');\n  }\n\n  // ===========================================================================\n  // Group Operations\n  // ===========================================================================\n\n  /**\n   * Extract pagination information from Graph API response.\n   */\n  private extractPagination(data: unknown): GraphAPIResponse['pagination'] | undefined {\n    if (data == null || typeof data !== 'object') return undefined;\n\n    const obj = data as Record<string, unknown>;\n\n    if ('@odata.nextLink' in obj || '@odata.count' in obj) {\n      return {\n        nextLink: obj['@odata.nextLink'] as string | undefined,\n        count: obj['@odata.count'] as number | undefined,\n        skipToken: this.extractSkipToken(obj['@odata.nextLink'] as string | undefined),\n      };\n    }\n\n    return undefined;\n  }\n\n  /**\n   * Extract skip token from next link URL.\n   */\n  private extractSkipToken(nextLink: string | undefined): string | undefined {\n    if (nextLink == null || nextLink === '') return undefined;\n\n    try {\n      const url = new URL(nextLink);\n      return url.searchParams.get('$skiptoken') ?? undefined;\n    } catch {\n      return undefined;\n    }\n  }\n\n  /**\n   * Internal method to get user groups.\n   */\n  private async getUserGroupsInternal(transitive = false): Promise<ADGroup[]> {\n    const endpoint = transitive\n      ? GRAPH_ENDPOINTS.ME_TRANSITIVE_MEMBER_OF\n      : GRAPH_ENDPOINTS.ME_MEMBER_OF;\n\n    const allGroups: GraphGroup[] = [];\n    let nextLink: string | undefined;\n\n    do {\n      const response = await this.graphRequest<GraphGroupListResponse>({\n        endpoint: (nextLink != null && nextLink !== '') ? '' : endpoint,\n        query: (nextLink != null && nextLink !== '') ? undefined : { $top: 100 },\n      });\n\n      allGroups.push(\n        ...response.data.value.filter(\n          (item): item is GraphGroup => item['@odata.type'] === '#microsoft.graph.group'\n        )\n      );\n\n      nextLink = response.pagination?.nextLink;\n    } while (nextLink != null && nextLink !== '');\n\n    return this.mapGraphGroups(allGroups);\n  }\n\n  // ===========================================================================\n  // Mapping Functions\n  // ===========================================================================\n\n  /**\n   * Map Graph API user profile to ADUser.\n   */\n  private mapGraphUserToADUser(profile: GraphUserProfile, groups: ADGroup[]): ADUser {\n    const adAttributes: ADUserAttributes = {\n      upn: profile.userPrincipalName,\n      objectId: profile.id,\n      displayName: profile.displayName ?? '',\n      email: profile.mail ?? undefined,\n      givenName: profile.givenName ?? undefined,\n      surname: profile.surname ?? undefined,\n      jobTitle: profile.jobTitle ?? undefined,\n      department: profile.department ?? undefined,\n      officeLocation: profile.officeLocation ?? undefined,\n      mobilePhone: profile.mobilePhone ?? undefined,\n      businessPhones: profile.businessPhones,\n      employeeId: profile.employeeId ?? undefined,\n      companyName: profile.companyName ?? undefined,\n      userType: profile.userType ?? undefined,\n      accountEnabled: profile.accountEnabled,\n      createdDateTime: profile.createdDateTime ?? undefined,\n      onPremisesSamAccountName: profile.onPremisesSamAccountName ?? undefined,\n      onPremisesDomainName: profile.onPremisesDomainName ?? undefined,\n    };\n\n    return {\n      id: profile.id,\n      email: profile.mail ?? profile.userPrincipalName,\n      firstName: profile.givenName ?? '',\n      lastName: profile.surname ?? '',\n      displayName: profile.displayName ?? '',\n      avatarUrl: undefined, // Set separately via getUserPhoto\n      roles: [], // Set by role mapper\n      permissions: [],\n      metadata: {},\n      createdAt: profile.createdDateTime ?? new Date().toISOString(),\n      updatedAt: new Date().toISOString(),\n      adAttributes,\n      adGroups: groups,\n      adProvider: this.config.providerType,\n      tenantId: this.getTenantId(),\n      isGuest: profile.userType === 'Guest',\n      effectivePermissions: [],\n    };\n  }\n\n  /**\n   * Map Graph API groups to ADGroup array.\n   */\n  private mapGraphGroups(graphGroups: GraphGroup[]): ADGroup[] {\n    return graphGroups.map(group => ({\n      id: group.id,\n      displayName: group.displayName ?? '',\n      description: group.description ?? undefined,\n      groupType: this.determineGroupType(group),\n      mail: group.mail ?? undefined,\n      membershipType: (group.membershipRule != null && group.membershipRule !== '') ? 'dynamic' : 'assigned',\n      isAssignableToRole: group.isAssignableToRole,\n      onPremisesSecurityIdentifier: group.onPremisesSecurityIdentifier ?? undefined,\n    }));\n  }\n\n  /**\n   * Determine the group type from Graph API response.\n   */\n  private determineGroupType(group: GraphGroup): ADGroup['groupType'] {\n    if (group.mailEnabled && group.securityEnabled) {\n      return 'mailEnabled';\n    }\n    if (group.securityEnabled) {\n      return 'security';\n    }\n    if (group.groupTypes?.includes('Unified')) {\n      return 'microsoft365';\n    }\n    return 'distribution';\n  }\n\n  /**\n   * Get tenant ID from configuration.\n   */\n  private getTenantId(): string | undefined {\n    switch (this.config.providerType) {\n      case 'azure-ad':\n        return this.config.azure?.tenantId;\n      case 'azure-ad-b2c':\n        return this.config.azureB2C?.tenantId;\n      default:\n        return undefined;\n    }\n  }\n\n  // ===========================================================================\n  // Utility Methods\n  // ===========================================================================\n\n  /**\n   * Create an AD auth error object.\n   */\n  private createError(\n    code: string,\n    message: string,\n    originalError?: unknown\n  ): ADAuthError {\n    return {\n      code,\n      message,\n      timestamp: Date.now(),\n      recoverable: code !== 'no_refresh_token',\n      originalError,\n    };\n  }\n\n  /**\n   * Delay helper for retries.\n   */\n  private async delay(ms: number): Promise<void> {\n    return new Promise(resolve => setTimeout(resolve, ms));\n  }\n\n  /**\n   * Log debug messages.\n   */\n  private log(message: string, ...args: unknown[]): void {\n    if (this.debug) {\n      // eslint-disable-next-line no-console\n      console.log(`[ADClient] ${message}`, ...args);\n    }\n  }\n}\n\n// =============================================================================\n// Graph API Types (Internal)\n// =============================================================================\n\ninterface GraphUserProfile {\n  id: string;\n  userPrincipalName: string;\n  displayName: string | null;\n  givenName: string | null;\n  surname: string | null;\n  mail: string | null;\n  jobTitle: string | null;\n  department: string | null;\n  officeLocation: string | null;\n  mobilePhone: string | null;\n  businessPhones: string[];\n  employeeId: string | null;\n  companyName: string | null;\n  userType: string | null;\n  accountEnabled: boolean;\n  createdDateTime: string | null;\n  onPremisesSamAccountName: string | null;\n  onPremisesDomainName: string | null;\n}\n\ninterface GraphGroup {\n  '@odata.type'?: string;\n  id: string;\n  displayName: string | null;\n  description: string | null;\n  mail: string | null;\n  mailEnabled: boolean;\n  securityEnabled: boolean;\n  groupTypes: string[];\n  membershipRule: string | null;\n  isAssignableToRole: boolean;\n  onPremisesSecurityIdentifier: string | null;\n}\n\ninterface GraphGroupListResponse {\n  value: GraphGroup[];\n  '@odata.nextLink'?: string;\n  '@odata.count'?: number;\n}\n\n// =============================================================================\n// Error Class\n// =============================================================================\n\n/**\n * Custom error class for Graph API client errors.\n */\nexport class GraphAPIClientError extends Error {\n  constructor(\n    public readonly code: string,\n    message: string,\n    public readonly details?: unknown\n  ) {\n    super(message);\n    this.name = 'GraphAPIClientError';\n  }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a new AD client instance.\n *\n * @param config - AD configuration\n * @param options - Additional options\n * @returns Configured AD client\n */\nexport function createADClient(\n  config: ADConfig,\n  options?: {\n    onTokenRefresh?: (tokens: ADTokens) => void;\n    onAuthError?: (error: ADAuthError) => void;\n  }\n): ADClient {\n  return new ADClient(config, options);\n}\n"],"names":["GRAPH_BASE_URL","GRAPH_API","GRAPH_DEFAULT_VERSION","MAX_RETRIES","DEFAULT_MAX_RETRY_ATTEMPTS","RETRY_DELAY","DEFAULT_RETRY_BASE_DELAY","GRAPH_ENDPOINTS","ADClient","config","options","tokens","bufferMs","request","version","method","url","refreshResult","GraphAPIClientError","accessToken","headers","fetchOptions","ms","userResponse","groupsResponse","profile","userId","groups","response","blob","transitive","groupId","g","authority","getAuthorityUrl","tokenEndpoint","refreshToken","getConfiguredScopes","errorData","error","data","newTokens","authError","endpoint","query","baseUrl","searchParams","key","value","timeout","DEFAULT_TIMEOUT","lastError","attempt","controller","timeoutId","correlationId","errorBody","retryAfter","parsedRetryAfter","delay","pagination","obj","nextLink","allGroups","item","adAttributes","graphGroups","group","code","message","originalError","resolve","args","details","createADClient"],"mappings":";;;;AAoCA,MAAMA,IAAiBC,EAAU,UAC3BC,IAAwBD,EAAU,iBAClCE,IAAcC,GACdC,IAAcC,GAKPC,IAAkB;AAAA,EAC7B,IAAI;AAAA,EACJ,UAAU;AAAA,EACV,cAAc;AAAA,EACd,yBAAyB;AAAA,EACzB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,iBAAiB;AACnB;AAsBO,MAAMC,EAAS;AAAA,EACH;AAAA,EACT,SAA0B;AAAA,EAC1B,sBAA0D;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,YACEC,GACAC,GAIA;AACA,SAAK,SAASD,GACd,KAAK,QAAQA,EAAO,SAAS,IAC7B,KAAK,iBAAiBC,GAAS,gBAC/B,KAAK,cAAcA,GAAS;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,WAAWC,GAAwB;AACjC,SAAK,SAASA,GACd,KAAK,IAAI,gCAAgC;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAUA,GAAwB;AAChC,SAAK,SAASA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAgC;AAC9B,WAAO,KAAK,QAAQ,eAAe;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAeC,IAAW,KAAiB;AACzC,WAAK,KAAK,SACH,KAAK,IAAA,KAAS,KAAK,OAAO,YAAYA,IADpB;AAAA,EAE3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,gBAA6C;AACjD,QAAI,KAAK,uBAAuB;AAC9B,aAAO,KAAK;AAGd,QAAI,KAAK,QAAQ,gBAAgB,QAAQ,KAAK,OAAO,iBAAiB;AACpE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,qBAAqB;AAAA,QACrB,OAAO,KAAK,YAAY,oBAAoB,4BAA4B;AAAA,MAAA;AAI5E,SAAK,sBAAsB,KAAK,oBAAA;AAEhC,QAAI;AAEF,aAAO,MAAM,KAAK;AAAA,IACpB,UAAA;AACE,WAAK,sBAAsB;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAA0BC,GAAwD;AACtF,UAAMC,IAAUD,EAAQ,WAAWX,GAC7Ba,IAASF,EAAQ,UAAU,OAC3BG,IAAM,KAAK,cAAcH,EAAQ,UAAUC,GAASD,EAAQ,KAAK;AAGvE,QAAI,KAAK,kBAAkB;AACzB,YAAMI,IAAgB,MAAM,KAAK,cAAA;AACjC,UAAI,CAACA,EAAc;AACjB,cAAM,IAAIC;AAAA,UACR;AAAA,UACA;AAAA,UACAD,EAAc;AAAA,QAAA;AAAA,IAGpB;AAEA,UAAME,IAAc,KAAK,QAAQ;AACjC,QAAIA,KAAe;AACjB,YAAM,IAAID,EAAoB,YAAY,2BAA2B;AAGvE,UAAME,IAAkC;AAAA,MACtC,eAAiB,UAAUD,CAAW;AAAA,MACtC,gBAAgB;AAAA,MAChB,GAAGN,EAAQ;AAAA,IAAA,GAGPQ,IAA4B;AAAA,MAChC,QAAAN;AAAA,MACA,SAAAK;AAAA,MACA,MAAOP,EAAQ,QAAQ,OAAQ,KAAK,UAAUA,EAAQ,IAAI,IAAI;AAAA,IAAA;AAGhE,WAAO,KAAK,iBAAoBG,GAAKK,GAAeR,EAAQ,YAAY,QAAQA,EAAQ,YAAY,UAAaA,EAAQ,YAAY,IAAKS,EAAGT,EAAQ,OAAO,IAAI,MAAS;AAAA,EAC3K;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBAAkC;AACtC,UAAM,CAACU,GAAcC,CAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,MACvD,KAAK,aAA+B;AAAA,QAClC,UAAUjB,EAAgB;AAAA,QAC1B,OAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA,EACA,KAAK,GAAG;AAAA,QAAA;AAAA,MACZ,CACD;AAAA,MACD,KAAK,sBAAA;AAAA,IAAsB,CAC5B,GAEKkB,IAAUF,EAAa;AAG7B,WAAO,KAAK,qBAAqBE,GAASD,CAAc;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,QAAQE,GAAiC;AAC7C,UAAM,CAACH,GAAcC,CAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,MACvD,KAAK,aAA+B;AAAA,QAClC,UAAU,GAAGjB,EAAgB,KAAK,IAAI,mBAAmBmB,CAAM,CAAC;AAAA,MAAA,CACjE;AAAA,MACD,KAAK,aAAqC;AAAA,QACxC,UAAU,GAAGnB,EAAgB,KAAK,IAAI,mBAAmBmB,CAAM,CAAC;AAAA,MAAA,CACjE;AAAA,IAAA,CACF,GAEKC,IAAS,KAAK,eAAeH,EAAe,KAAK,KAAK;AAE5D,WAAO,KAAK,qBAAqBD,EAAa,MAAMI,CAAM;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eAAuC;AAC3C,QAAI;AACF,YAAMR,IAAc,KAAK,QAAQ;AACjC,UAAIA,KAAe;AACjB,eAAO;AAGT,YAAMS,IAAW,MAAM;AAAA,QACrB,GAAG5B,CAAc,IAAIE,CAAqB,GAAGK,EAAgB,QAAQ;AAAA,QACrE;AAAA,UACE,SAAS;AAAA,YACP,eAAiB,UAAUY,CAAW;AAAA,UAAA;AAAA,QACxC;AAAA,MACF;AAGF,UAAI,CAACS,EAAS;AACZ,eAAO;AAGT,YAAMC,IAAO,MAAMD,EAAS,KAAA;AAC5B,aAAO,IAAI,gBAAgBC,CAAI;AAAA,IACjC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,cAAcC,IAAa,IAA2B;AAC1D,WAAO,KAAK,sBAAsBA,CAAU;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,qBAAqBC,GAAiBD,IAAa,IAAwB;AAC/E,QAAI;AASF,cARiB,MAAM,KAAK,aAAiC;AAAA,QAC3D,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,UAAU,CAACC,CAAO;AAAA,QAAA;AAAA,MACpB,CACD,GAEe,KAAK;AAAA,IACvB,QAAQ;AAGN,cADe,MAAM,KAAK,cAAcD,CAAU,GACpC,KAAK,CAAAE,MAAKA,EAAE,OAAOD,CAAO;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAc,sBAAmD;AAC/D,UAAME,IAAYC,EAAgB,KAAK,MAAM;AAC7C,QAAID,KAAa,QAAQA,MAAc;AACrC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,KAAK,YAAY,gBAAgB,6BAA6B;AAAA,MAAA;AAIzE,QAAI;AAGF,YAAME,IAAgB,GAAGF,CAAS,sBAG5BG,IAAe,KAAK,QAAQ;AAClC,UAAIA,KAAgB;AAClB,cAAM,IAAI,MAAM,4BAA4B;AAG9C,YAAMR,IAAW,MAAM,MAAMO,GAAe;AAAA,QAC1C,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAAA;AAAA,QAElB,MAAM,IAAI,gBAAgB;AAAA,UACxB,YAAY;AAAA,UACZ,eAAeC;AAAA,UACf,WAAW,KAAK,YAAA;AAAA,UAChB,OAAOC,EAAoB,KAAK,MAAM,EAAE,KAAK,GAAG;AAAA,QAAA,CACjD;AAAA,MAAA,CACF;AAED,UAAI,CAACT,EAAS,IAAI;AAChB,cAAMU,IAAY,MAAMV,EAAS,KAAA,EAAO,MAAM,OAAO,CAAA,EAAqD,GACpGW,IAAQ,KAAK;AAAA,UAChBD,EAAU,SAAS,QAAQA,EAAU,UAAU,KAAMA,EAAU,QAAQ;AAAA,UACvEA,EAAU,qBAAqB,QAAQA,EAAU,sBAAsB,KAAMA,EAAU,oBAAoB;AAAA,QAAA;AAG9G,oBAAK,cAAcC,CAAK,GAEjB;AAAA,UACL,SAAS;AAAA,UACT,OAAAA;AAAA,UACA,qBAAqBD,EAAU,UAAU;AAAA,QAAA;AAAA,MAE7C;AAEA,YAAME,IAAO,MAAMZ,EAAS,KAAA,GAQtBa,IAAsB;AAAA,QAC1B,aAAaD,EAAK;AAAA,QAClB,SAASA,EAAK;AAAA,QACd,cAAeA,EAAK,iBAAiB,QAAQA,EAAK,kBAAkB,KAAMA,EAAK,gBAAiB,KAAK,QAAQ,gBAAgB;AAAA,QAC7H,WAAW,KAAK,IAAA,IAASA,EAAK,aAAa;AAAA,QAC3C,QAASA,EAAK,SAAS,QAAQA,EAAK,UAAU,KAAMA,EAAK,MAAM,MAAM,GAAG,IAAI,CAAA;AAAA,QAC5E,WAAYA,EAAK,cAAc,QAAQA,EAAK,eAAe,KAAMA,EAAK,aAAa;AAAA,MAAA;AAGrF,kBAAK,SAASC,GACd,KAAK,iBAAiBA,CAAS,GAExB,EAAE,SAAS,IAAM,QAAQA,EAAA;AAAA,IAClC,SAASF,GAAgB;AACvB,YAAMG,IAAY,KAAK;AAAA,QACrB;AAAA,QACA;AAAA,QACAH;AAAA,MAAA;AAEF,kBAAK,cAAcG,CAAS,GAErB,EAAE,SAAS,IAAO,OAAOA,EAAA;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,cAAsB;AAC5B,YAAQ,KAAK,OAAO,cAAA;AAAA,MAClB,KAAK;AACH,eAAO,KAAK,OAAO,OAAO,YAAY;AAAA,MACxC,KAAK;AACH,eAAO,KAAK,OAAO,UAAU,YAAY;AAAA,MAC3C,KAAK;AACH,eAAO,KAAK,OAAO,MAAM,YAAY;AAAA,MACvC;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA;AAAA;AAAA;AAAA,EAKQ,cACNC,GACA7B,GACA8B,GACQ;AACR,UAAMC,IAAU,GAAG7C,CAAc,IAAIc,CAAO,GAAG6B,CAAQ;AAEvD,QAAI,CAACC,KAAS,OAAO,KAAKA,CAAK,EAAE,WAAW;AAC1C,aAAOC;AAGT,UAAMC,IAAe,IAAI,gBAAA;AACzB,kBAAO,QAAQF,CAAK,EAAE,QAAQ,CAAC,CAACG,GAAKC,CAAK,MAAM;AAC9C,MAAAF,EAAa,OAAOC,GAAK,OAAOC,CAAK,CAAC;AAAA,IACxC,CAAC,GAEM,GAAGH,CAAO,IAAIC,EAAa,UAAU;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBACZ9B,GACAN,GACAuC,IAAUC,GACoB;AAC9B,QAAIC,IAA0B;AAE9B,aAASC,IAAU,GAAGA,IAAUjD,GAAaiD;AAC3C,UAAI;AACF,cAAMC,IAAa,IAAI,gBAAA,GACjBC,IAAY,WAAW,MAAMD,EAAW,MAAA,GAASJ,CAAO,GAExDrB,IAAW,MAAM,MAAMZ,GAAK;AAAA,UAChC,GAAGN;AAAA,UACH,QAAQ2C,EAAW;AAAA,QAAA,CACpB;AAED,qBAAaC,CAAS;AAEtB,cAAMC,IAAgB3B,EAAS,QAAQ,IAAI,YAAY,KAAK;AAE5D,YAAI,CAACA,EAAS,IAAI;AAChB,gBAAM4B,IAAY,MAAM5B,EAAS,KAAA,EAAO,MAAM,OAAO,EAAE,MAAM,QAAW,SAAS,OAAA,EAAY;AAG7F,cAAIA,EAAS,UAAU,OAAOA,EAAS,SAAS,OAAOA,EAAS,WAAW;AACzE,kBAAM,IAAIV;AAAA,cACRsC,EAAU,QAAQ;AAAA,cAClBA,EAAU,WAAW,oBAAoB5B,EAAS,MAAM;AAAA,cACxD4B;AAAA,YAAA;AAKJ,cAAI5B,EAAS,WAAW,KAAK;AAC3B,kBAAM6B,IAAa7B,EAAS,QAAQ,IAAI,aAAa,GAC/C8B,IAAoBD,KAAc,QAAQA,MAAe,KAAM,SAASA,GAAY,EAAE,IAAI,MAC1FE,IAASD,KAAoB,QAAQA,IAAmB,IAAKA,IAAmB,MAAOrD,KAAe+C,IAAU;AACtH,kBAAM,KAAK,MAAMO,CAAK;AACtB;AAAA,UACF;AAEA,gBAAM,IAAI,MAAM,oBAAoB/B,EAAS,MAAM,EAAE;AAAA,QACvD;AAEA,cAAMY,IAAO,MAAMZ,EAAS,KAAA,GAGtBgC,IAAa,KAAK,kBAAkBpB,CAAI;AAE9C,eAAO;AAAA,UACL,MAAAA;AAAA,UACA,SAAS,OAAO,YAAYZ,EAAS,QAAQ,SAAS;AAAA,UACtD,QAAQA,EAAS;AAAA,UACjB,eAAA2B;AAAA,UACA,YAAAK;AAAA,QAAA;AAAA,MAEJ,SAASrB,GAAgB;AAGvB,YAFAY,IAAYZ,GAERA,aAAiBrB;AACnB,gBAAMqB;AAGR,YAAKA,EAAgB,SAAS;AAC5B,gBAAM,IAAIrB,EAAoB,WAAW,mBAAmB;AAI9D,QAAIkC,IAAUjD,IAAc,KAC1B,MAAM,KAAK,MAAME,KAAe+C,IAAU,EAAE;AAAA,MAGhD;AAGF,UAAMD,KAAa,IAAI,MAAM,kCAAkC;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,kBAAkBX,GAA2D;AACnF,QAAIA,KAAQ,QAAQ,OAAOA,KAAS,SAAU;AAE9C,UAAMqB,IAAMrB;AAEZ,QAAI,qBAAqBqB,KAAO,kBAAkBA;AAChD,aAAO;AAAA,QACL,UAAUA,EAAI,iBAAiB;AAAA,QAC/B,OAAOA,EAAI,cAAc;AAAA,QACzB,WAAW,KAAK,iBAAiBA,EAAI,iBAAiB,CAAuB;AAAA,MAAA;AAAA,EAKnF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiBC,GAAkD;AACzE,QAAI,EAAAA,KAAY,QAAQA,MAAa;AAErC,UAAI;AAEF,eADY,IAAI,IAAIA,CAAQ,EACjB,aAAa,IAAI,YAAY,KAAK;AAAA,MAC/C,QAAQ;AACN;AAAA,MACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAsBhC,IAAa,IAA2B;AAC1E,UAAMa,IAAWb,IACbvB,EAAgB,0BAChBA,EAAgB,cAEdwD,IAA0B,CAAA;AAChC,QAAID;AAEJ,OAAG;AACD,YAAMlC,IAAW,MAAM,KAAK,aAAqC;AAAA,QAC/D,UAAWkC,KAAY,QAAQA,MAAa,KAAM,KAAKnB;AAAA,QACvD,OAAQmB,KAAY,QAAQA,MAAa,KAAM,SAAY,EAAE,MAAM,IAAA;AAAA,MAAI,CACxE;AAED,MAAAC,EAAU;AAAA,QACR,GAAGnC,EAAS,KAAK,MAAM;AAAA,UACrB,CAACoC,MAA6BA,EAAK,aAAa,MAAM;AAAA,QAAA;AAAA,MACxD,GAGFF,IAAWlC,EAAS,YAAY;AAAA,IAClC,SAASkC,KAAY,QAAQA,MAAa;AAE1C,WAAO,KAAK,eAAeC,CAAS;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,qBAAqBtC,GAA2BE,GAA2B;AACjF,UAAMsC,IAAiC;AAAA,MACrC,KAAKxC,EAAQ;AAAA,MACb,UAAUA,EAAQ;AAAA,MAClB,aAAaA,EAAQ,eAAe;AAAA,MACpC,OAAOA,EAAQ,QAAQ;AAAA,MACvB,WAAWA,EAAQ,aAAa;AAAA,MAChC,SAASA,EAAQ,WAAW;AAAA,MAC5B,UAAUA,EAAQ,YAAY;AAAA,MAC9B,YAAYA,EAAQ,cAAc;AAAA,MAClC,gBAAgBA,EAAQ,kBAAkB;AAAA,MAC1C,aAAaA,EAAQ,eAAe;AAAA,MACpC,gBAAgBA,EAAQ;AAAA,MACxB,YAAYA,EAAQ,cAAc;AAAA,MAClC,aAAaA,EAAQ,eAAe;AAAA,MACpC,UAAUA,EAAQ,YAAY;AAAA,MAC9B,gBAAgBA,EAAQ;AAAA,MACxB,iBAAiBA,EAAQ,mBAAmB;AAAA,MAC5C,0BAA0BA,EAAQ,4BAA4B;AAAA,MAC9D,sBAAsBA,EAAQ,wBAAwB;AAAA,IAAA;AAGxD,WAAO;AAAA,MACL,IAAIA,EAAQ;AAAA,MACZ,OAAOA,EAAQ,QAAQA,EAAQ;AAAA,MAC/B,WAAWA,EAAQ,aAAa;AAAA,MAChC,UAAUA,EAAQ,WAAW;AAAA,MAC7B,aAAaA,EAAQ,eAAe;AAAA,MACpC,WAAW;AAAA;AAAA,MACX,OAAO,CAAA;AAAA;AAAA,MACP,aAAa,CAAA;AAAA,MACb,UAAU,CAAA;AAAA,MACV,WAAWA,EAAQ,oBAAmB,oBAAI,KAAA,GAAO,YAAA;AAAA,MACjD,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,MACtB,cAAAwC;AAAA,MACA,UAAUtC;AAAA,MACV,YAAY,KAAK,OAAO;AAAA,MACxB,UAAU,KAAK,YAAA;AAAA,MACf,SAASF,EAAQ,aAAa;AAAA,MAC9B,sBAAsB,CAAA;AAAA,IAAC;AAAA,EAE3B;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAeyC,GAAsC;AAC3D,WAAOA,EAAY,IAAI,CAAAC,OAAU;AAAA,MAC/B,IAAIA,EAAM;AAAA,MACV,aAAaA,EAAM,eAAe;AAAA,MAClC,aAAaA,EAAM,eAAe;AAAA,MAClC,WAAW,KAAK,mBAAmBA,CAAK;AAAA,MACxC,MAAMA,EAAM,QAAQ;AAAA,MACpB,gBAAiBA,EAAM,kBAAkB,QAAQA,EAAM,mBAAmB,KAAM,YAAY;AAAA,MAC5F,oBAAoBA,EAAM;AAAA,MAC1B,8BAA8BA,EAAM,gCAAgC;AAAA,IAAA,EACpE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmBA,GAAyC;AAClE,WAAIA,EAAM,eAAeA,EAAM,kBACtB,gBAELA,EAAM,kBACD,aAELA,EAAM,YAAY,SAAS,SAAS,IAC/B,iBAEF;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAkC;AACxC,YAAQ,KAAK,OAAO,cAAA;AAAA,MAClB,KAAK;AACH,eAAO,KAAK,OAAO,OAAO;AAAA,MAC5B,KAAK;AACH,eAAO,KAAK,OAAO,UAAU;AAAA,MAC/B;AACE;AAAA,IAAO;AAAA,EAEb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,YACNC,GACAC,GACAC,GACa;AACb,WAAO;AAAA,MACL,MAAAF;AAAA,MACA,SAAAC;AAAA,MACA,WAAW,KAAK,IAAA;AAAA,MAChB,aAAaD,MAAS;AAAA,MACtB,eAAAE;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,MAAMhD,GAA2B;AAC7C,WAAO,IAAI,QAAQ,CAAAiD,MAAW,WAAWA,GAASjD,CAAE,CAAC;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKQ,IAAI+C,MAAoBG,GAAuB;AACrD,IAAI,KAAK,SAEP,QAAQ,IAAI,cAAcH,CAAO,IAAI,GAAGG,CAAI;AAAA,EAEhD;AACF;AAsDO,MAAMtD,UAA4B,MAAM;AAAA,EAC7C,YACkBkD,GAChBC,GACgBI,GAChB;AACA,UAAMJ,CAAO,GAJG,KAAA,OAAAD,GAEA,KAAA,UAAAK,GAGhB,KAAK,OAAO;AAAA,EACd;AACF;AAaO,SAASC,EACdjE,GACAC,GAIU;AACV,SAAO,IAAIF,EAASC,GAAQC,CAAO;AACrC;"}