import type { ISoqlQueryAdapter } from '../adapters/soql/soql-query-adapter.js'; import type { IRestApiAdapter } from '../adapters/rest/rest-api-adapter.js'; import type { ServiceResult } from '../models/service-result.js'; import type { OrgType } from './OrgInfoService.js'; /** * Response shape from the ISV profiling status endpoint. * * @see GET /services/apexrest/pnova/v1/profiling/status */ export type FeatureStatus = { /** Whether the overall feature is enabled for this organization */ featureEnabled: boolean; /** Whether API-Based Profiling is enabled */ apiBasedProfilingEnabled: boolean; /** Whether self-registration is enabled */ selfRegistrationEnabled: boolean; /** Installed package version string */ packageVersion: string; }; /** * Permission set names required for Cuneiform operations. */ export declare const REQUIRED_PERMISSION_SETS: readonly ["Cuneiform_for_CRM_PRO_Administrative_User", "Cuneiform_for_CRM_Global_Profiling_Support"]; /** * Maps required permission set API names to their human-readable labels. * Used for user-facing display across both details and configure commands. */ export declare const REQUIRED_PERMISSION_SET_LABELS: Record; /** * Org types that allow configure operations. * Production is the only blocked type. */ export declare const CONFIGURE_ALLOWED_ORG_TYPES: readonly OrgType[]; /** * Status of a single permission set assignment. */ export type PermissionSetAssignmentStatus = { /** Permission set API name */ name: string; /** Permission set label (human-readable display name) */ label?: string; /** Whether the permission set is assigned to the user */ isAssigned: boolean; /** Whether this permission set is required */ isRequired: boolean; }; /** * Result of permission set check. */ export type PermissionSetStatus = { /** Whether all required permission sets are assigned */ hasAllRequired: boolean; /** Status of each checked permission set */ assignments: PermissionSetAssignmentStatus[]; /** Names of missing required permission sets */ missingRequired: string[]; }; /** * Configuration profile information from Cuneiform CMT. */ export type ConfigProfileStatus = { /** Whether a config profile is configured */ isConfigured: boolean; /** Developer name of the active profile */ profileDeveloperName?: string; /** Label of the active profile */ profileLabel?: string; /** Whether API-only profiling is enabled */ apiOnlyProfilingEnabled?: boolean; /** Whether CLI self-provisioning (self-registration) is enabled */ selfRegistrationEnabled?: boolean; }; /** * Complete user readiness status. */ export type UserReadiness = { /** User ID that was checked */ userId: string; /** Whether the user is ready to use Cuneiform */ isReady: boolean; /** Whether Cuneiform is installed in the org */ isCuneiformInstalled: boolean; /** Permission set status */ permissionSets: PermissionSetStatus; /** Configuration profile status */ configProfile: ConfigProfileStatus; /** Human-readable readiness messages */ messages: string[]; }; /** * Authenticated user identity information. * * Contains user profile details retrieved from the Salesforce User object * with Profile and UserRole relationship data. */ export type UserInfo = { /** Salesforce User ID (18-character) */ id: string; /** User's login username */ username: string; /** User's full name (Name field) */ fullName: string; /** User's email address */ email: string; /** Name of the user's assigned Profile */ profileName: string; /** Name of the user's assigned Role (null if no role assigned) */ roleName: string | null; /** Whether the user account is active */ isActive: boolean; }; /** * Configuration for UserReadinessService. */ export type IUserReadinessServiceConfig = { /** SOQL query adapter for permission and CMT queries */ soqlAdapter: ISoqlQueryAdapter; /** Optional logger for debug output */ logger?: Console; /** Optional REST client for server-side readiness checks via ISV REST API */ restClient?: import('../adapters/rest/profiling-rest-client.js').ProfilingRestClient; }; /** * Service for validating user readiness to use Cuneiform. * * Checks whether a user has the required permission sets and configuration * profile to execute Cuneiform operations. Also detects if Cuneiform is * installed in the org. * * @example * ```typescript * const service = new UserReadinessService({ soqlAdapter }); * * const result = await service.checkReadiness(userId); * if (result.success) { * if (result.data.isReady) { * console.log('User is ready to use Cuneiform'); * } else { * console.log('Issues:', result.data.messages.join(', ')); * } * } * ``` */ export declare class UserReadinessService { private readonly soqlAdapter; private readonly logger?; private readonly restClient?; constructor(config: IUserReadinessServiceConfig); /** * Checks whether configure operations are allowed in the given org type. * * Only Production orgs are blocked. Developer, Sandbox, Scratch, and Trial * orgs are all allowed to run configure operations. * * @param orgType - The classified org type * @returns true if configure is allowed, false for Production */ static isConfigureAllowed(orgType: OrgType): boolean; /** * Creates an empty UserReadiness result for error cases. */ private static createEmptyReadiness; /** * Creates an empty UserInfo result for error cases. */ private static createEmptyUserInfo; /** * Checks if an error message indicates Cuneiform namespace is not found. * * This typically means the Cuneiform for Salesforce package is not installed in the org. * The Salesforce API returns "sObject type not supported" or similar when * querying namespaced objects that don't exist. */ private static isCuneiformNamespaceNotFoundError; /** * Maps the ISV REST API payload to the canonical UserReadiness shape. * * The Apex endpoint returns flat booleans and differently-named fields * (e.g. `assigned` instead of `isAssigned`, `cuneiformInstalled` instead * of `isCuneiformInstalled`). This mapper bridges the wire format to * the TypeScript domain type so downstream code (buildResult, display) * works unchanged. */ private static mapRestPayloadToUserReadiness; /** * Retrieves user identity information. * * Queries the User object with Profile and UserRole relationships to build * a complete user identity record. Handles null UserRole gracefully since * users may not have a role assigned. * * @param userId - The Salesforce user ID to query * @returns ServiceResult containing UserInfo * * @example * ```typescript * const result = await service.getUserInfo(userId); * if (result.success) { * console.log(`User: ${result.data.fullName} (${result.data.profileName})`); * if (result.data.roleName) { * console.log(`Role: ${result.data.roleName}`); * } * } * ``` */ getUserInfo(userId: string): Promise>; /** * Checks complete user readiness for Cuneiform operations. * * Validates: * 1. Cuneiform is installed (by querying CMT) * 2. User has required permission sets * 3. Configuration profile is set up * * @param userId - The Salesforce user ID to check * @returns ServiceResult containing UserReadiness */ checkReadiness(userId: string): Promise>; /** * Checks if the user has required Cuneiform permission sets. * * @param userId - The Salesforce user ID to check * @returns ServiceResult containing PermissionSetStatus */ hasRequiredPermissionSets(userId: string): Promise>; /** * Retrieves the ID of a permission set by name and namespace. * * Queries the PermissionSet object directly to find a permission set by * its Name and NamespacePrefix. This method returns the permission set ID * for use in permission set assignment operations. * * @param permissionSetName - The permission set API name (e.g., 'Cuneiform_for_CRM_Global_Profiling_Support') * @param namespacePrefix - The namespace prefix (e.g., 'pnova') * @returns ServiceResult containing the permission set ID or null if not found * * @example * ```typescript * const result = await service.getPermissionSetId( * 'Cuneiform_for_CRM_Global_Profiling_Support', * 'pnova' * ); * if (result.success && result.data) { * console.log(`Permission Set ID: ${result.data}`); * } else if (result.success && result.data === null) { * console.log('Permission set not found in org'); * } * ``` */ getPermissionSetId(permissionSetName: string, namespacePrefix: string): Promise>; /** * Checks if a configuration profile is configured. * * Queries the Cuneiform Active Configuration CMT to determine if a profile * is set up. If the CMT doesn't exist, returns E4654 indicating Cuneiform * is not installed. * * @returns ServiceResult containing ConfigProfileStatus */ hasConfigProfile(): Promise>; /** * Validates that the user has profiling access to use Cuneiform commands. * * Checks in order: * 1. Cuneiform is installed in the org * 2. Required permission sets are assigned * 3. Global Profiling is enabled * * Returns success if all checks pass. Returns a specific error code for the * first failing check, with a user-friendly message including remediation steps. * * @param userId - The Salesforce user ID to validate * @returns ServiceResult — success or failure with specific error code */ validateProfilingAccess(userId: string): Promise>; /** * Checks the feature status via the ISV profiling status REST endpoint. * * Calls `GET /services/apexrest/pnova/v1/profiling/status` to determine whether * API-Based Profiling is enabled for this organization. This is Gate 0 — if the * feature is not enabled, all other gates are moot. * * Graceful degradation: * - On 404 (endpoint not found): returns success with `featureEnabled: true`. * Older ISV packages may not expose this endpoint; we don't block them. * - On other errors: returns failure with `FEATURE_STATUS_CHECK_FAILED`. * * @param restAdapter - The REST API adapter for making the HTTP request * @returns ServiceResult containing FeatureStatus * * @example * ```typescript * const result = await service.checkFeatureStatus(restAdapter); * if (result.success && !result.data.featureEnabled) { * // Block command execution — feature is disabled * } * ``` */ checkFeatureStatus(restAdapter: IRestApiAdapter): Promise>; /** * Attempts REST delegation for user readiness. * Returns the successful result, or null to signal fallback to the local SOQL path. * Falls back when REST returns cuneiformInstalled=false (Apex endpoint bug on some orgs). */ private tryRestReadiness; /** * Delegates user readiness check to the ISV REST API. * * @param userId - The Salesforce user ID to check * @param startTime - Timestamp for duration tracking * @returns ServiceResult containing UserReadiness from REST endpoint */ private checkReadinessViaRest; /** * Checks for required permission sets accessible through PermissionSetGroup membership. * * Two-step query approach for precision: * 1. Get the specific PermissionSetGroup IDs assigned to this user * 2. Check if those specific groups contain any of the missing required permission sets * * Both queries are tightly filtered to avoid pulling excess records: * - Group query: filtered by AssigneeId AND PermissionSetGroupId != null * - Component query: filtered by specific group IDs, permission set names, AND namespace * * @param userId - The Salesforce user ID * @param missingNames - Permission set names not found via direct assignment * @returns Map of permission set names to labels found through group membership */ private getGroupAssignedPermissionSets; }