import type { ServiceResult } from '../models/service-result.js'; import type { IRestApiAdapter } from '../adapters/rest/rest-api-adapter.js'; import type { ISoqlQueryAdapter } from '../adapters/soql/soql-query-adapter.js'; import type { ObjectFilteringService } from './ObjectFilteringService.js'; import type { ContactPointService } from './ContactPointService.js'; import type { NamespaceCategory } from './namespace-constants.js'; /** * Options for listing objects via the object list command. * * Maps directly to CLI flags for the `sf cuneiform object list` command. */ export type ObjectListCommandOptions = { /** Filter by object type: 'all', 'standard', or 'custom' */ filter?: 'all' | 'standard' | 'custom'; /** Filter by namespace prefix (e.g., 'pnova', 'SBQQ') */ namespace?: string; /** Filter by API name pattern (supports * wildcard) */ pattern?: string; /** Only include objects with record count > 0 */ withRecords?: boolean; /** Only include objects with record count = 0 */ withoutRecords?: boolean; /** Only include objects with OwnerId field */ withOwner?: boolean; /** Only include objects with record types defined */ withRecordTypes?: boolean; /** Include business process count enrichment column */ withBusinessProcess?: boolean; /** Object classification: customer-facing, internal/system, or all */ classification?: 'customer' | 'internal' | 'all'; /** Minimum record count threshold */ minRecords?: number; /** Include field count enrichment columns (total fields and custom fields) */ includeFieldCounts?: boolean; /** Include reference/lookup field count enrichment column */ includeReferences?: boolean; /** Include contact point field analysis */ withContactPoints?: boolean; /** Fetch a single object by API name, bypassing the filter chain and limit */ object?: string; /** Progress callback for enrichment step reporting */ onProgress?: (message: string) => void; /** Sort field */ sort?: 'name' | 'recordCount' | 'label'; /** Maximum number of results to return */ limit?: number; }; /** * Summary statistics for object list results. */ export type ObjectListSummary = { /** Total number of objects matching filters */ totalObjects: number; /** Number of objects with records > 0 */ withRecords: number; /** Number of objects with records = 0 */ withoutRecords: number; /** Number of standard objects */ standardObjects: number; /** Number of custom objects */ customObjects: number; /** Number of external objects (__x suffix) */ externalObjects: number; /** Number of objects with a namespace prefix */ withNamespace: number; /** Number of objects without a namespace prefix */ withoutNamespace: number; /** Number of objects with OwnerId field (only set when --with-owner filter used) */ withOwner?: number; /** Number of objects with record types (only set when --with-record-types filter used) */ withRecordTypes?: number; /** Object counts by namespace */ namespaceCounts: NamespaceCount[]; /** Sum of all recordCount values across listed objects */ totalRecordCount: number; /** Sum of all totalFields values (only set when --with-fields used) */ totalFieldCount?: number; /** Sum of all customFields values (only set when --with-fields used) */ totalCustomFieldCount?: number; /** Sum of all lookupFieldCount values (only set when --with-references used) */ totalReferenceCount?: number; /** Sum of all contactPoints.summary.totalContactPoints (only set when --with-contact-points used) */ totalContactPoints?: number; /** Sum of all recordTypeCount values (only set when --with-record-types used) */ totalRecordTypeCount?: number; /** Sum of all businessProcessCount values (only set when --with-business-process used) */ totalBusinessProcessCount?: number; }; /** * Namespace count entry for summary statistics. */ export type NamespaceCount = { /** Namespace prefix, or null for unmanaged objects */ namespace: string | null; /** Number of objects in this namespace */ count: number; }; /** * Individual object item in the list result. */ export type ObjectListItem = { /** API name of the object */ apiName: string; /** User-friendly label */ label: string; /** Plural label */ labelPlural?: string; /** Key prefix for record IDs */ keyPrefix: string | null; /** Number of records in the object */ recordCount: number; /** Whether this is a custom object */ isCustom: boolean; /** Whether this is an external object (__x) */ isExternal: boolean; /** Namespace prefix, or null for unmanaged */ namespace: string | null; /** Whether this object is classified as customer-facing (via EntityDefinition). Only populated when --classification is customer or internal. */ isCustomer?: boolean; /** Whether the object has an OwnerId field */ hasOwner?: boolean; /** Whether the object has record types */ hasRecordTypes?: boolean; /** Number of record types (if hasRecordTypes is true) */ recordTypeCount?: number; /** Number of active business processes (if withBusinessProcess is true) */ businessProcessCount?: number; /** Total number of fields (if includeFieldCounts is true) */ totalFields?: number; /** Number of custom fields (if includeFieldCounts is true) */ customFields?: number; /** Number of lookup/reference fields (if includeReferences is true) */ lookupFieldCount?: number; /** Contact point analysis (if withContactPoints is true) */ contactPoints?: ContactPointSummary | null; }; /** * Summary of contact point fields for an object. */ export type ContactPointSummary = { /** Email fields found */ emailFields: ContactPointFieldInfo[]; /** Phone fields found */ phoneFields: ContactPointFieldInfo[]; /** URL fields found */ urlFields: ContactPointFieldInfo[]; /** Summary counts */ summary: { emailCount: number; phoneCount: number; urlCount: number; totalContactPoints: number; }; }; /** * Basic contact point field information. */ export type ContactPointFieldInfo = { /** Field API name */ apiName: string; /** Field label */ label: string; /** Whether this is a standard field */ isStandard: boolean; }; /** * Objects grouped by namespace category. */ export type NamespaceCategoryGroup = { /** The namespace category */ readonly category: NamespaceCategory; /** Human-readable category label */ readonly label: string; /** Objects in this category */ readonly objects: readonly ObjectListItem[]; /** Number of objects in this category */ readonly count: number; }; /** * Result of the object list command. */ export type ObjectListResult = { /** Summary statistics */ summary: ObjectListSummary; /** Applied filters */ filters: ObjectListCommandOptions; /** List of objects matching filters */ objects: ObjectListItem[]; /** Contact point analysis metadata (if withContactPoints is true) */ contactPointAnalysis?: { /** Number of objects analyzed for contact points */ analyzedCount: number; /** Minimum records threshold used for contact point analysis */ minRecordsThreshold: number; }; }; /** * Configuration for ObjectListCommandService. */ export type IObjectListCommandServiceConfig = { /** Object filtering service for core filtering operations */ objectFilteringService: ObjectFilteringService; /** Contact point service for contact point analysis */ contactPointService: ContactPointService; /** REST API adapter for describe calls (required for enrichment columns) */ restApiAdapter?: IRestApiAdapter; /** SOQL query adapter for record type aggregate queries */ soqlAdapter?: ISoqlQueryAdapter; /** Optional logger for debug output */ logger?: Console; }; /** * Orchestration service for the `sf cuneiform object list` command. * * Composes ObjectFilteringService for filtering and ContactPointService for * contact point analysis. Computes summary statistics and namespace distribution. * * @design * This is an orchestration service (not a domain service). It coordinates multiple * services to fulfill command requirements, handles flag-specific logic, and * transforms results into the command's expected output structure. * * @example * ```typescript * const service = new ObjectListCommandService({ * objectFilteringService, * contactPointService, * restAdapter, * logger: console, * }); * * // List custom objects with contact point analysis * const result = await service.listObjects({ * filter: 'custom', * withRecords: true, * withContactPoints: true, * minRecords: 1000, * }); * * if (result.success) { * console.log(`Found ${result.data.summary.totalObjects} objects`); * console.log(`Standard: ${result.data.summary.standardObjects}`); * console.log(`Custom: ${result.data.summary.customObjects}`); * } * ``` */ export declare class ObjectListCommandService { private readonly objectFilteringService; private readonly contactPointService; private readonly restApiAdapter?; private readonly soqlAdapter?; private readonly logger?; constructor(config: IObjectListCommandServiceConfig); /** * Groups objects by their namespace category. * * Uses categorizeNamespace() to classify each object's namespace, * then groups into standard/industry/managed/custom buckets with * human-readable labels. * * @param objects - Array of ObjectListItem to group * @returns Array of NamespaceCategoryGroup, ordered: standard, industry, managed, custom. * Empty categories are omitted. */ static groupObjectsByNamespaceCategory(objects: ObjectListItem[]): NamespaceCategoryGroup[]; /** * Sorts objects by the specified field. * * @param objects - Objects to sort * @param sort - Sort field * @returns Sorted array (new array, not mutated) */ static sortObjects(objects: ObjectListItem[], sort: 'name' | 'recordCount' | 'label'): ObjectListItem[]; /** * Determines whether any enrichment flag requiring describe calls is active. */ private static needsDescribeCalls; /** * Builds FilterOptions from command options. * * `excludeSystemObjects` is set unconditionally — system suffix types * (`__Feed`, `__History`, `__Share`, `__mdt`, `__ChangeEvent`, `__e`) are never * valid object list targets. The shared `NON_DATA_SUFFIX_PATTERN` filter lives * in `ObjectFilteringService.applySystemObjectExclusion` (CLI-3374 mirrors the * opt-in PR #292 applied to `definition create`). */ private static buildFilterOptions; /** * Validates command options and returns an error message if invalid. * * @param options - Options to validate * @returns Error message if invalid, undefined if valid */ private static validateOptions; /** * Validates that `--object` is not combined with mutually exclusive flags. * * @returns Error message if a conflict is detected, undefined if valid */ private static validateObjectFlagConflicts; /** * Determines if an object is external (ends with __x). * * @param name - Object API name * @returns True if external object */ private static isExternalObject; /** * Determines if an object is a Big Object (ends with __b). * * @param name - Object API name * @returns True if Big Object */ private static isBigObject; /** * Determines if an object is a Custom Metadata Type (ends with __mdt). * * @param name - Object API name * @returns True if Custom Metadata Type */ private static isCustomMetadataType; /** * Determines if an object is a Platform Event (ends with __e). * * @param name - Object API name * @returns True if Platform Event */ private static isPlatformEvent; /** * Extracts namespace from an object API name. * * @param name - Object API name * @returns Namespace prefix or null for unmanaged objects */ private static extractNamespace; /** * Computes namespace distribution from a list of objects. * * @param objects - Array of SObjectInfo * @returns Array of namespace counts, sorted by count descending */ private static computeNamespaceCounts; /** * Creates an empty ObjectListResult for error cases. * * @param options - Applied filter options * @returns Empty result structure */ private static createEmptyResult; /** * Transforms ContactPointAnalysis to ContactPointSummary. * * @param analysis - ContactPointAnalysis from ContactPointService * @returns ContactPointSummary for ObjectListItem */ private static transformContactPointAnalysis; /** * Computes summary statistics from filtered objects. * * @param objects - Filtered SObjectInfo array * @returns ObjectListSummary */ private static computeSummary; /** * Computes enrichment aggregate totals from post-enrichment object items. * Returns a partial summary with only the enrichment totals that are active. */ private static computeEnrichmentTotals; /** * Transforms SObjectInfo array to ObjectListItem array. * * @param objects - SObjectInfo array from filtering * @returns ObjectListItem array */ private static transformToListItems; /** * Lists Salesforce objects with filtering, summary statistics, and optional contact point analysis. * * @param options - Command options mapping to CLI flags * @returns ServiceResult containing ObjectListResult */ listObjects(options?: ObjectListCommandOptions): Promise>; /** * Single-object short-circuit for the `--object` flag. * * Bypasses ObjectFilteringService entirely. Uses describeGlobal to confirm * the object exists, then getRecordCounts to fetch the real record count * in one targeted call. * * @param objectName - API name of the target object (case-insensitive match) * @param options - Full command options (enrichments still apply) * @param startTime - Operation start timestamp for duration tracking */ private listSingleObject; /** * Fetches object describes for enrichment, shared across all field-data flags. * * @param objectNames - Object API names to describe * @returns Map of object name to DescribeSObjectResult */ private fetchObjectDescribes; /** * Fetches record type counts via aggregate SOQL. * * @returns Map of SobjectType to active record type count */ private fetchRecordTypeCounts; /** * Fetches active business process counts via aggregate SOQL. * * BusinessProcess records are linked to objects via the TableEnumOrId field, * which maps to the SobjectType (e.g., 'Opportunity', 'Lead', 'Case', 'Solution'). * * @returns Map of SobjectType to active business process count */ private fetchBusinessProcessCounts; /** * Applies enrichment data (field counts, references, record types, business processes, contact points) to object items. * * When multiple field-data enrichments are active, describe calls are shared (not duplicated). * * @param objectItems - Object items to enrich * @param options - Command options determining which enrichments to apply * @returns Enriched object items */ private applyEnrichments; /** * Fetches contact point analysis for a list of object names. * * Uses parallel execution with per-promise catch to prevent one failure * from blocking others. Returns a map of object name to contact point summary. * * @param objectNames - Object API names to analyze * @returns Map of object name to ContactPointSummary (or null on failure) */ private fetchContactPoints; }