UNPKG

dataverse-type-gen

Version:

TypeScript type generator for Dataverse entities and metadata

1,367 lines (1,335 loc) 47.1 kB
import { TokenCredential } from '@azure/identity'; import { Command } from 'commander'; interface DataverseEntity { entityName: string; displayName: string; properties: DataverseProperty[]; } interface DataverseProperty { name: string; type: string; required: boolean; description?: string; } interface EntityDefinitionResponse { '@odata.context': string; value: EntityDefinition[]; } interface EntityDefinition { MetadataId: string; LogicalName: string; SchemaName: string; DisplayName?: LocalizedLabel; Description?: LocalizedLabel; HasActivities: boolean; HasFeedback: boolean; HasNotes: boolean; IsActivity: boolean; IsCustomEntity: boolean; OwnershipType: number; PrimaryIdAttribute: string; PrimaryNameAttribute: string; EntitySetName: string; Attributes?: AttributeMetadata[]; OneToManyRelationships?: OneToManyRelationshipMetadata[]; ManyToOneRelationships?: ManyToOneRelationshipMetadata[]; ManyToManyRelationships?: ManyToManyRelationshipMetadata[]; } interface LocalizedLabel { LocalizedLabels: Array<{ Label: string; LanguageCode: number; }>; UserLocalizedLabel?: { Label: string; LanguageCode: number; }; } interface AttributeMetadata { MetadataId: string; LogicalName: string; SchemaName: string; DisplayName?: LocalizedLabel; Description?: LocalizedLabel; AttributeType: string; IsCustomAttribute: boolean; IsValidForCreate: boolean; IsValidForRead: boolean; IsValidForUpdate: boolean; RequiredLevel: { Value: string; }; IsPrimaryId?: boolean; IsPrimaryName?: boolean; AttributeOf?: string; } interface DataverseErrorResponse { error: { code: string; message: string; '@Microsoft.PowerApps.CDS.ErrorDetails.OperationStatus'?: string; '@Microsoft.PowerApps.CDS.ErrorDetails.SubErrorCode'?: string; '@Microsoft.PowerApps.CDS.HelpLink'?: string; '@Microsoft.PowerApps.CDS.TraceText'?: string; '@Microsoft.PowerApps.CDS.InnerError.Message'?: string; }; } interface DataverseErrorDetails { status: number; statusText: string; url: string; method: string; headers: Record<string, string>; body?: string; error?: DataverseErrorResponse['error']; timestamp: string; requestId?: string; } interface OptionSetConstant { [key: string]: { Value: number; Label: string; }; } interface OneToManyRelationshipMetadata { MetadataId: string; SchemaName: string; ReferencedEntity: string; ReferencedAttribute: string; ReferencingEntity: string; ReferencingAttribute: string; RelationshipType: string; IsCustomRelationship: boolean; } interface ManyToOneRelationshipMetadata { MetadataId: string; SchemaName: string; ReferencedEntity: string; ReferencedAttribute: string; ReferencingEntity: string; ReferencingAttribute: string; RelationshipType: string; IsCustomRelationship: boolean; } interface ManyToManyRelationshipMetadata { MetadataId: string; SchemaName: string; Entity1LogicalName: string; Entity1IntersectAttribute: string; Entity2LogicalName: string; Entity2IntersectAttribute: string; IntersectEntityName: string; RelationshipType: string; IsCustomRelationship: boolean; } interface GetEntityDefinitionsOptions { filter?: string; select?: string[]; expand?: string[]; } declare function getEntityDefinitions(options?: GetEntityDefinitionsOptions): Promise<EntityDefinition[]>; declare function getEntityDefinition(logicalName: string): Promise<EntityDefinition | null>; declare function advancedLog(response: Response, requestUrl?: string, requestMethod?: string, requestBody?: string): Promise<DataverseErrorDetails>; declare function getErrorCodeDescription(code: string): string; declare function getStatusCodeDescription(status: number): string; interface AzureAuthOptions { resourceUrl: string; credential?: TokenCredential; } /** * Simple authentication using DefaultAzureCredential * Supports Azure CLI, Environment Variables, Managed Identity, etc. */ declare function getAzureToken(options: AzureAuthOptions): Promise<string | null>; /** * Create an authenticated fetch function for making API calls */ declare function createAuthenticatedFetcher(resourceUrl: string, options?: { maxRetries?: number; baseDelay?: number; credential?: TokenCredential; }): (url: string, requestOptions?: RequestInit) => Promise<Response>; /** * Options for fetching entity metadata */ interface FetchEntityMetadataOptions { includeAttributes?: boolean; includeRelationships?: boolean; attributeTypes?: string[]; select?: string[]; progressCallback?: ProgressCallback; } /** * Global option set definition from Dataverse API */ interface GlobalOptionSetDefinition { MetadataId: string; Name: string; DisplayName?: { LocalizedLabels: Array<{ Label: string; LanguageCode: number; }>; UserLocalizedLabel?: { Label: string; LanguageCode: number; }; }; Description?: { LocalizedLabels: Array<{ Label: string; LanguageCode: number; }>; UserLocalizedLabel?: { Label: string; LanguageCode: number; }; }; Options: Array<{ Value: number; Label?: { LocalizedLabels: Array<{ Label: string; LanguageCode: number; }>; UserLocalizedLabel?: { Label: string; LanguageCode: number; }; }; Description?: { LocalizedLabels: Array<{ Label: string; LanguageCode: number; }>; UserLocalizedLabel?: { Label: string; LanguageCode: number; }; }; }>; IsCustomOptionSet: boolean; IsGlobal: boolean; OptionSetType: string; } /** * Picklist attribute metadata with expanded option set */ interface PicklistAttributeMetadata extends AttributeMetadata { '@odata.type': 'Microsoft.Dynamics.CRM.PicklistAttributeMetadata'; OptionSet?: { MetadataId: string; Name?: string; DisplayName?: { LocalizedLabels: Array<{ Label: string; LanguageCode: number; }>; UserLocalizedLabel?: { Label: string; LanguageCode: number; }; }; Options: Array<{ Value: number; Label?: { LocalizedLabels: Array<{ Label: string; LanguageCode: number; }>; UserLocalizedLabel?: { Label: string; LanguageCode: number; }; }; }>; IsGlobal: boolean; IsCustomOptionSet: boolean; }; GlobalOptionSet?: string; } /** * Multi-select picklist attribute metadata */ interface MultiSelectPicklistAttributeMetadata extends AttributeMetadata { '@odata.type': 'Microsoft.Dynamics.CRM.MultiSelectPicklistAttributeMetadata'; OptionSet?: PicklistAttributeMetadata['OptionSet']; GlobalOptionSet?: string; } /** * Lookup attribute metadata with target information */ interface LookupAttributeMetadata extends AttributeMetadata { '@odata.type': 'Microsoft.Dynamics.CRM.LookupAttributeMetadata'; Targets?: string[]; Format?: string; } /** * State attribute metadata */ interface StateAttributeMetadata extends AttributeMetadata { '@odata.type': 'Microsoft.Dynamics.CRM.StateAttributeMetadata'; OptionSet?: PicklistAttributeMetadata['OptionSet']; } /** * Status attribute metadata */ interface StatusAttributeMetadata extends AttributeMetadata { '@odata.type': 'Microsoft.Dynamics.CRM.StatusAttributeMetadata'; OptionSet?: PicklistAttributeMetadata['OptionSet']; } /** * Solution definition from Dataverse API */ interface SolutionDefinition { solutionid: string; uniquename: string; friendlyname?: string; version?: string; publisherid?: string; ismanaged?: boolean; description?: string; } /** * Solution component definition from Dataverse API */ interface SolutionComponent { solutioncomponentid: string; solutionid?: string; _solutionid_value?: string; objectid: string; componenttype: number; rootcomponentbehavior?: number; ismetadata?: boolean; } /** * Component type constants for solution components */ declare const COMPONENT_TYPES: { readonly ENTITY: 1; readonly ATTRIBUTE: 2; readonly RELATIONSHIP: 10; readonly OPTION_SET: 9; }; /** * Fetch single entity metadata from Dataverse * * @param entityLogicalName - The logical name of the entity (e.g., 'account', 'contact') * @param options - Options for customizing the fetch * @returns Promise<EntityDefinition | null> */ declare function fetchEntityMetadata(entityLogicalName: string, options?: FetchEntityMetadataOptions): Promise<EntityDefinition | null>; /** * Progress callback for entity fetching */ type ProgressCallback = (current: number, total: number, entityName?: string) => void; /** * Fetch ALL entity metadata from Dataverse for complete type safety * Used when fullMetadata is enabled in configuration */ declare function fetchAllEntityMetadata(options?: FetchEntityMetadataOptions & { onProgress?: ProgressCallback; }): Promise<EntityDefinition[]>; /** * Fetch multiple entities metadata including related entities for type-safe expands */ declare function fetchMultipleEntitiesWithRelated(entityNames: string[], options?: FetchEntityMetadataOptions & { includeRelatedEntities?: boolean; }): Promise<{ primaryEntities: EntityDefinition[]; relatedEntities: Map<string, EntityDefinition>; }>; /** * Fetch entity attributes with proper casting for specific attribute types * This is essential for getting full picklist option data * * Uses parallel processing for attribute type casting to improve performance * * @param entityLogicalName - The logical name of the entity * @param attributeTypes - Specific attribute types to cast (optional) * @returns Promise<AttributeMetadata[]> */ declare function fetchEntityAttributes(entityLogicalName: string, attributeTypes?: string[]): Promise<AttributeMetadata[]>; /** * Fetch global option set definition * * @param optionSetName - The name of the global option set * @returns Promise<GlobalOptionSetDefinition | null> */ declare function fetchGlobalOptionSet(optionSetName: string): Promise<GlobalOptionSetDefinition | null>; /** * Fetch entities by publisher prefix (not actual solution membership) * NOTE: Uses client-side filtering since startswith() is not supported by EntityDefinitions * * @param publisherPrefix - The publisher prefix (e.g., 'pum') * @returns Promise<EntityDefinition[]> */ declare function fetchPublisherEntities(publisherPrefix: string): Promise<EntityDefinition[]>; /** * Fetch multiple entities by logical names * * Uses OR-filter batching for optimal performance when cache is disabled * * @param entityNames - Array of entity logical names * @param options - Options for customizing the fetch * @returns Promise<EntityDefinition[]> */ declare function fetchMultipleEntities(entityNames: string[], options?: FetchEntityMetadataOptions & { onProgress?: ProgressCallback; }): Promise<EntityDefinition[]>; /** * Check if an entity exists * * @param entityLogicalName - The logical name of the entity * @returns Promise<boolean> */ declare function entityExists(entityLogicalName: string): Promise<boolean>; /** * Get all available entities (EntityDefinitions endpoint does not support $top/$skip pagination) * * @param options - Options for filtering (no pagination support) * @returns Promise<EntityDefinition[]> */ declare function fetchAllEntities(options?: { filter?: string; customOnly?: boolean; select?: string[]; }): Promise<EntityDefinition[]>; /** * Find solution by unique name or friendly name * * @param solutionName - Solution unique name or friendly name * @returns Promise<SolutionDefinition | null> */ declare function findSolution(solutionName: string): Promise<SolutionDefinition | null>; /** * Fetch solution components by solution ID * * @param solutionId - The solution GUID * @param componentType - The component type to filter by (optional) * @returns Promise<SolutionComponent[]> */ declare function fetchSolutionComponents(solutionId: string, componentType?: number): Promise<SolutionComponent[]>; /** * Fetch entities from a specific solution by solution name (actual solution membership) * This provides true solution-based filtering, not just publisher prefix matching * * @param solutionName - The solution unique name or friendly name * @returns Promise<EntityDefinition[]> */ declare function fetchSolutionEntities(solutionName: string): Promise<EntityDefinition[]>; /** * Related entity information for type-safe nested expands */ interface RelatedEntityInfo { relationshipName: string; targetEntityLogicalName: string; targetEntitySetName: string; relationshipType: 'OneToMany' | 'ManyToOne' | 'ManyToMany'; } /** * Processed entity metadata for type generation */ interface ProcessedEntityMetadata { logicalName: string; schemaName: string; displayName: string; description?: string; primaryIdAttribute: string; primaryNameAttribute: string; entitySetName: string; isCustomEntity: boolean; attributes: ProcessedAttributeMetadata[]; optionSets: ProcessedOptionSet[]; expandableProperties: string[]; oneToManyRelationships: ProcessedRelationshipMetadata[]; manyToOneRelationships: ProcessedRelationshipMetadata[]; manyToManyRelationships: ProcessedManyToManyRelationshipMetadata[]; /** Related entities with their full metadata for type-safe expands */ relatedEntities: Record<string, RelatedEntityInfo>; } /** * Processed attribute metadata */ interface ProcessedAttributeMetadata { logicalName: string; schemaName: string; displayName: string; description?: string; attributeType: string; isCustomAttribute: boolean; isValidForCreate: boolean; isValidForRead: boolean; isValidForUpdate: boolean; requiredLevel: 'None' | 'SystemRequired' | 'ApplicationRequired' | 'Recommended'; isPrimaryId: boolean; isPrimaryName: boolean; attributeOf?: string; maxLength?: number; minValue?: number; maxValue?: number; precision?: number; format?: string; targets?: string[]; optionSetName?: string; globalOptionSet?: string; isMultiSelect?: boolean; optionSet?: ProcessedOptionSet; } /** * Processed option set for type generation */ interface ProcessedOptionSet { name: string; displayName: string; description?: string; isGlobal: boolean; isCustom: boolean; options: ProcessedOption[]; } /** * Processed option for constants generation */ interface ProcessedOption { value: number; label: string; description?: string; } /** * Processed relationship metadata for type generation */ interface ProcessedRelationshipMetadata { schemaName: string; referencedEntity: string; referencedAttribute: string; referencingEntity: string; referencingAttribute: string; isCustomRelationship: boolean; } /** * Processed many-to-many relationship metadata for type generation */ interface ProcessedManyToManyRelationshipMetadata { schemaName: string; entity1LogicalName: string; entity1IntersectAttribute: string; entity2LogicalName: string; entity2IntersectAttribute: string; intersectEntityName: string; isCustomRelationship: boolean; } /** * Process entity metadata for type generation */ declare function processEntityMetadata(entityMetadata: EntityDefinition, options?: { excludeSystemAuditRelationships?: boolean; }): ProcessedEntityMetadata; /** * Extract all related entity names from processed metadata */ declare function extractRelatedEntityNames(metadata: ProcessedEntityMetadata): string[]; /** * Process individual attribute metadata */ declare function processAttributeMetadata(attributeMetadata: AttributeMetadata): ProcessedAttributeMetadata; /** * Extract option sets from entity attributes */ declare function extractOptionSetsFromAttributes(attributes: AttributeMetadata[]): ProcessedOptionSet[]; /** * Process option set metadata */ declare function processOptionSet(optionSetMetadata: PicklistAttributeMetadata['OptionSet'] | GlobalOptionSetDefinition, fallbackName?: string): ProcessedOptionSet | null; /** * Process global option set */ declare function processGlobalOptionSet(globalOptionSet: GlobalOptionSetDefinition): ProcessedOptionSet; /** * Merge processed option sets, avoiding duplicates */ declare function mergeOptionSets(optionSets: ProcessedOptionSet[]): ProcessedOptionSet[]; /** * Filter attributes by type */ declare function filterAttributesByType(attributes: ProcessedAttributeMetadata[], types: string[]): ProcessedAttributeMetadata[]; /** * Get primary attributes (ID and Name) */ declare function getPrimaryAttributes(attributes: ProcessedAttributeMetadata[]): { primaryId?: ProcessedAttributeMetadata; primaryName?: ProcessedAttributeMetadata; }; /** * Group attributes by type */ declare function groupAttributesByType(attributes: ProcessedAttributeMetadata[]): Record<string, ProcessedAttributeMetadata[]>; /** * Get lookup attributes with their targets */ declare function getLookupAttributes(attributes: ProcessedAttributeMetadata[]): Array<ProcessedAttributeMetadata & { targets: string[]; }>; /** * Get option set attributes */ declare function getOptionSetAttributes(attributes: ProcessedAttributeMetadata[]): ProcessedAttributeMetadata[]; /** * Filter out auxiliary attributes using AttributeOf field * Auxiliary attributes are system-generated fields like lookup name fields that reference other attributes * * @param attributes - Array of processed attribute metadata * @returns Filtered array without auxiliary attributes */ declare function filterAuxiliaryAttributes(attributes: ProcessedAttributeMetadata[]): ProcessedAttributeMetadata[]; /** * Validate processed metadata */ declare function validateProcessedMetadata(metadata: ProcessedEntityMetadata): { isValid: boolean; errors: string[]; warnings: string[]; }; /** * Generate TypeScript interface for an entity */ declare function generateEntityInterface(entityMetadata: ProcessedEntityMetadata, options?: TypeGenerationOptions): string; /** * Generate TypeScript constants for an option set */ declare function generateOptionSetConstants(optionSet: ProcessedOptionSet, options?: TypeGenerationOptions): string; /** * Generate TypeScript file for a global option set */ declare function generateGlobalOptionSetFile(optionSet: ProcessedOptionSet, options?: TypeGenerationOptions): string; /** * Generate metadata object for runtime use */ declare function generateMetadataObject(entityMetadata: ProcessedEntityMetadata, options?: TypeGenerationOptions): string; /** * Generate imports for the generated code */ declare function generateImports(requiredImports: string[]): string; /** * TypeScript generation options */ interface TypeGenerationOptions { entityPrefix?: string; includeComments?: boolean; includeValidation?: boolean; includeMetadata?: boolean; useExactTypes?: boolean; includeLookupValues?: boolean; includeBindingTypes?: boolean; excludeAuxiliaryAttributes?: boolean; fullMetadata?: boolean; excludeSystemAuditRelationships?: boolean; primaryEntities?: string[]; relatedEntitiesDir?: string; } /** * Generated TypeScript code result */ interface GeneratedCode { interfaces: string; constants: string; types: string; metadata?: string; validation?: string; imports: string[]; } /** * Generate complete TypeScript file for an entity */ declare function generateEntityFile(entityMetadata: ProcessedEntityMetadata, options?: TypeGenerationOptions, allEntities?: ProcessedEntityMetadata[]): GeneratedCode; /** * Default code generation configuration */ declare const DEFAULT_CODEGEN_CONFIG: CodeGenConfig; /** * Generate TypeScript declarations for multiple entities with optional related entities */ declare function generateMultipleEntityTypes(entities: ProcessedEntityMetadata[], config?: Partial<CodeGenConfig>, relatedEntities?: ProcessedEntityMetadata[], onProgress?: (current: number, total: number, item?: string) => void): Promise<CodeGenResult>; /** * Write TypeScript declaration file for a global option set */ declare function writeGlobalOptionSetDeclaration(optionSet: ProcessedOptionSet, config: CodeGenConfig): Promise<GeneratedFileResult>; /** * Write React Query hooks file for an entity */ declare function writeEntityHooksFile(entityMetadata: ProcessedEntityMetadata, config: CodeGenConfig): Promise<GeneratedFileResult>; /** * Write query builders file for an entity */ declare function writeEntityQueryBuildersFile(entityMetadata: ProcessedEntityMetadata, config: CodeGenConfig): Promise<GeneratedFileResult>; /** * Write TypeScript declaration file for an entity */ declare function writeEntityTypeDeclaration(entityMetadata: ProcessedEntityMetadata, config: CodeGenConfig, allEntities?: ProcessedEntityMetadata[]): Promise<GeneratedFileResult>; /** * Write query-types file */ declare function writeQueryTypesFile(config: CodeGenConfig): Promise<GeneratedFileResult>; /** * Helper function to determine if an entity is a primary entity */ declare function isPrimaryEntity(entityLogicalName: string, primaryEntities?: string[]): boolean; /** * Helper function to get the correct directory path for an entity */ declare function getEntityDirectory(entityLogicalName: string, config: CodeGenConfig): string; /** * Create output directory structure */ declare function createOutputDirectory(outputDir: string, subdirectories?: string[]): Promise<{ created: string[]; errors: string[]; }>; /** * Clean generated files */ declare function cleanGeneratedFiles(outputDir: string, pattern?: string): Promise<{ deletedFiles: string[]; errors: string[]; }>; /** * Get statistics about generated files */ declare function getGeneratedFileStats(outputDir: string): Promise<{ totalFiles: number; totalSize: number; averageSize: number; largestFile: { path: string; size: number; } | null; smallestFile: { path: string; size: number; } | null; }>; /** * Combine generated code parts into final content */ declare function combineGeneratedCode(code: GeneratedCode): string; /** * Format TypeScript code using ts-morph for proper TypeScript formatting */ declare function formatCode(code: string, showProgress?: boolean): Promise<string>; /** * Validate generated TypeScript code using ts-morph compiler integration */ declare function validateGeneratedCode(filePath: string): Promise<{ isValid: boolean; errors: string[]; warnings: string[]; }>; /** * Generate barrel export index file */ declare function generateIndexFile(successfulFiles: GeneratedFileResult[], config: CodeGenConfig): Promise<GeneratedFileResult>; /** * Calculate and return final code generation results */ declare function calculateGenerationResults(files: GeneratedFileResult[], indexFile: GeneratedFileResult | undefined, startTime: number): { files: GeneratedFileResult[]; indexFile?: GeneratedFileResult; totalFiles: number; successfulFiles: number; failedFiles: number; totalSize: number; duration: number; }; /** * Code generation configuration */ interface CodeGenConfig { outputDir: string; fileExtension: '.ts' | '.d.ts'; indexFile: boolean; prettier: boolean; eslint: boolean; overwrite: boolean; generateHooks: boolean; relatedEntitiesDir?: string; primaryEntities?: string[]; typeGenerationOptions: TypeGenerationOptions; debug?: boolean; } /** * Generated file result */ interface GeneratedFileResult { filePath: string; content: string; size: number; success: boolean; error?: string; } /** * Code generation session result */ interface CodeGenResult { files: GeneratedFileResult[]; indexFile?: GeneratedFileResult; totalFiles: number; successfulFiles: number; failedFiles: number; totalSize: number; duration: number; } /** * Dataverse type generator configuration */ interface DataverseTypeGenConfig { /** Dataverse instance URL (optional, can use environment variables) */ dataverseUrl?: string; /** Output directory for generated files */ outputDir: string; /** File extension for generated files */ fileExtension: '.ts' | '.d.ts'; /** Specific entity logical names to generate */ entities?: string[]; /** Publisher prefix to filter entities */ publisher?: string; /** Solution name (unique name or friendly name) to filter entities by actual solution membership */ solution?: string; /** Directory name for related entities (default: "related") */ relatedEntitiesDir?: string; /** Generate ALL entities from Dataverse for complete type safety */ fullMetadata?: boolean; /** Authentication configuration */ auth?: { clientId?: string; tenantId?: string; scopes?: string[]; }; /** Type generation options */ typeGeneration: TypeGenerationOptions & { /** Entity prefix for generated interfaces */ entityPrefix?: string; /** Include barrel export index file */ indexFile?: boolean; /** Generate React Query hooks alongside types */ generateHooks?: boolean; /** Exclude auxiliary attributes (those with AttributeOf field) for cleaner interfaces */ excludeAuxiliaryAttributes?: boolean; }; } /** * Default configuration */ declare const DEFAULT_CONFIG: DataverseTypeGenConfig; /** * Load configuration from file system */ declare function loadConfiguration(configPath?: string): Promise<DataverseTypeGenConfig>; /** * Validate configuration */ declare function validateConfiguration(config: DataverseTypeGenConfig): { isValid: boolean; errors: string[]; warnings: string[]; }; /** * Convert DataverseTypeGenConfig to CodeGenConfig */ declare function toCodeGenConfig(config: DataverseTypeGenConfig): CodeGenConfig; /** * Save configuration to file */ declare function saveConfiguration(config: DataverseTypeGenConfig, filePath?: string): Promise<void>; /** * Get current environment */ declare function getCurrentEnvironment(): string; /** * Create sample configuration */ declare function createSampleConfig(): DataverseTypeGenConfig; /** * Main CLI setup */ declare function setupCLI(): Command; /** * Utility types for simplifying complex TypeScript patterns */ /** * Extracts all field names ending with 'id' (primary/foreign keys) * @example EntityIdFields<{userid: string, name: string, companyid: string}> = 'userid' | 'companyid' */ type EntityIdFields<T> = { [K in keyof T]: K extends string ? T[K] extends string ? K extends `${string}id` ? K : never : never : never; }[keyof T]; /** * All fields except ID fields (safe for create operations) */ type NonIdFields<T> = Omit<T, EntityIdFields<T>>; /** * Only ID fields (required for update operations) */ type OnlyIdFields<T> = Pick<T, EntityIdFields<T>>; /** * TypeScript types for OData queries with full type safety * Supports filtering, selecting, expanding, and ordering operations */ type StringOperators<T = string> = { $eq?: T; $ne?: T; $in?: T[]; $nin?: T[]; $contains?: T; $startswith?: T; $endswith?: T; $like?: T; $null?: boolean; $notnull?: boolean; }; type NumberOperators<T = number> = { $eq?: T; $ne?: T; $gt?: T; $gte?: T; $lt?: T; $lte?: T; $in?: T[]; $nin?: T[]; $null?: boolean; $notnull?: boolean; }; type BooleanOperators = { $eq?: boolean; $ne?: boolean; $null?: boolean; $notnull?: boolean; }; type DateOperators = { $eq?: Date | string; $ne?: Date | string; $gt?: Date | string; $gte?: Date | string; $lt?: Date | string; $lte?: Date | string; $in?: (Date | string)[]; $nin?: (Date | string)[]; $null?: boolean; $notnull?: boolean; $today?: boolean; $yesterday?: boolean; $tomorrow?: boolean; $thisweek?: boolean; $thismonth?: boolean; $thisyear?: boolean; $lastweek?: boolean; $lastmonth?: boolean; $lastyear?: boolean; $nextweek?: boolean; $nextmonth?: boolean; $nextyear?: boolean; $lastxdays?: number; $nextxdays?: number; $lastxmonths?: number; $nextxmonths?: number; $lastxyears?: number; $nextxyears?: number; }; type LookupOperators = { $eq?: string; $ne?: string; $in?: string[]; $nin?: string[]; $null?: boolean; $notnull?: boolean; }; type FilterOperatorForType<T> = T extends string ? StringOperators<T> | T : T extends number ? NumberOperators<T> | T : T extends boolean ? BooleanOperators | T : T extends Date ? DateOperators | T : T extends string | Date ? DateOperators | T : T extends (infer U)[] ? FilterOperatorForType<U> | U[] : StringOperators<T> | T; type ODataFilter<TEntity> = { [K in keyof TEntity]?: FilterOperatorForType<TEntity[K]>; } & { $and?: ODataFilter<TEntity>[]; $or?: ODataFilter<TEntity>[]; $not?: ODataFilter<TEntity>; }; type ODataSelect<TEntity> = (keyof TEntity)[]; type ExpandOptions = { $select?: string[]; $filter?: Record<string, unknown>; $orderby?: Record<string, 'asc' | 'desc'> | string[]; $top?: number; }; type RelationshipExpandOption<TTargetEntity = unknown> = { $select?: (keyof TTargetEntity)[]; $filter?: ODataFilter<TTargetEntity>; $orderby?: ODataOrderBy<TTargetEntity>; $top?: number; }; type ExpandObject = Record<string, RelationshipExpandOption>; type TypeSafeExpand<TEntityMetadata> = TEntityMetadata extends { relatedEntities: infer TRelated; } ? { [K in keyof TRelated]?: TRelated[K] extends { targetEntityLogicalName: string; } ? RelationshipExpandOption<unknown> : never; } : ExpandObject; type ODataExpand<TEntityMetadata = unknown> = string[] | TypeSafeExpand<TEntityMetadata> | ExpandObject; type ExpandablePropertiesOf<T> = T extends { relatedEntities: unknown; } ? ODataExpand<T> : string[] | Record<string, ExpandOptions>; type ODataOrderBy<TEntity> = { [K in keyof TEntity]?: 'asc' | 'desc'; } | string[]; interface ODataQueryOptions<TEntity, TMetadata = unknown> { $filter?: ODataFilter<TEntity>; $select?: ODataSelect<TEntity>; $expand?: ODataExpand<TMetadata>; $orderby?: ODataOrderBy<TEntity>; $top?: number; $skip?: number; $count?: boolean; $search?: string; } interface EntityListOptions<TEntity, TMetadata = unknown> { /** Select specific fields (provides IntelliSense) */ $select?: ODataSelect<TEntity>; /** Expand related entities */ $expand?: ODataExpand<TMetadata>; /** Filter entities (type-safe field names and operators) */ $filter?: ODataFilter<TEntity>; /** Sort results by fields with direction */ $orderby?: ODataOrderBy<TEntity>; /** Limit number of results */ $top?: number; /** Skip results for pagination */ $skip?: number; /** Include count in response */ $count?: boolean; /** Search across fields */ $search?: string; } interface EntityMetadata { logicalName: string; schemaName: string; entitySetName: string; collectionName: string; displayName: string; primaryIdAttribute: string; primaryNameAttribute: string; isCustomEntity: boolean; entityType: string; attributeCount: number; optionSetCount: number; primaryKey: { logicalName: string; attributeType: string; displayName: string; }; primaryName?: { logicalName: string; attributeType: string; displayName: string; maxLength?: number; }; lookupAttributes: readonly string[]; requiredAttributes: readonly string[]; optionSets?: readonly string[]; generated: string; } interface UrlBuilderOptions<TEntity, TMetadata = unknown> extends ODataQueryOptions<TEntity, TMetadata> { baseUrl?: string; apiVersion?: string; } interface QueryKeyOptions<TEntity, TMetadata = unknown> { entity: string; operation: 'single' | 'list' | 'count' | 'related'; id?: string; filters?: ODataFilter<TEntity>; options?: Omit<ODataQueryOptions<TEntity, TMetadata>, '$filter'>; relationship?: string; } interface UseEntityOptions<TEntity, TMetadata = unknown> extends Omit<ODataQueryOptions<TEntity, TMetadata>, '$filter'> { enabled?: boolean; staleTime?: number; cacheTime?: number; refetchOnWindowFocus?: boolean; refetchOnMount?: boolean; } interface UseEntityListOptions<TEntity, TMetadata = unknown> extends ODataQueryOptions<TEntity, TMetadata> { enabled?: boolean; staleTime?: number; cacheTime?: number; refetchOnWindowFocus?: boolean; refetchOnMount?: boolean; } type EntityCreateInput<TEntity, TBindings = Record<string, never>> = Partial<NonIdFields<TEntity>> & Partial<TBindings>; type EntityUpdateInput<TEntity, TBindings = Record<string, never>> = Partial<NonIdFields<TEntity>> & Partial<TBindings> & OnlyIdFields<TEntity>; interface ODataResponse<T> { '@odata.context': string; '@odata.count'?: number; '@odata.nextLink'?: string; value: T[]; } interface ODataSingleResponse<T> extends Omit<ODataResponse<T>, 'value'> { value?: T; } interface DataverseError { error: { code: string; message: string; innererror?: { message: string; type: string; stacktrace?: string; }; }; } interface DataverseUrlConfig { baseUrl?: string; apiVersion?: string; instanceUrl?: string; } /** * URL builders for Dataverse Web API with full OData support * Provides type-safe URL construction for entities, filtering, and relationships */ /** * Build a complete Dataverse Web API URL with query parameters */ declare function buildUrl(endpoint: string, queryParams?: URLSearchParams, options?: { baseUrl?: string; apiVersion?: string; }): string; /** * Build URL for retrieving a single entity by ID */ declare function buildEntityUrl<TEntity>(metadata: EntityMetadata, id: string, options?: UrlBuilderOptions<TEntity>): string; /** * Build URL for retrieving multiple entities (entity set) */ declare function buildEntitySetUrl<TEntity>(metadata: EntityMetadata, options?: UrlBuilderOptions<TEntity>): string; /** * Build URL for retrieving related entities */ declare function buildRelatedUrl<TEntity>(metadata: EntityMetadata, id: string, relationshipName: string, options?: UrlBuilderOptions<TEntity>): string; /** * Build URL for counting entities */ declare function buildCountUrl<TEntity>(metadata: EntityMetadata, options?: Pick<UrlBuilderOptions<TEntity>, '$filter' | 'baseUrl' | 'apiVersion'>): string; /** * Build OData filter string from filter object */ declare function buildFilterString<TEntity>(filter: ODataFilter<TEntity>): string; /** * Create query key for React Query based on parameters */ declare function createQueryKey<TEntity>(entityName: string, operation: 'single' | 'list' | 'count' | 'related', options?: { id?: string; filters?: ODataFilter<TEntity>; queryOptions?: Omit<ODataQueryOptions<TEntity>, '$filter'>; relationship?: string; }): (string | object)[]; /** * React Query hook factories for Dataverse entities * Provides type-safe useQuery hooks with full OData support */ interface UseQueryResult<TData = unknown, TError = unknown> { data: TData | undefined; error: TError | null; isLoading: boolean; isError: boolean; isSuccess: boolean; isIdle: boolean; isFetching: boolean; refetch: () => void; [key: string]: unknown; } interface UseQueryOptions<TData = unknown, TError = unknown> { enabled?: boolean; staleTime?: number; cacheTime?: number; refetchOnWindowFocus?: boolean; refetchOnMount?: boolean; retry?: boolean | number; onSuccess?: (data: TData) => void; onError?: (error: TError) => void; select?: (data: unknown) => TData; queryKey?: unknown[]; queryFn?: () => Promise<TData>; [key: string]: unknown; } /** * Create entity-specific hooks for a given entity type */ declare function createEntityHooks<TEntity = Record<string, unknown>>(metadata: EntityMetadata): { useEntity: (id: string | undefined, options?: UseEntityOptions<TEntity> & UseQueryOptions<TEntity, Error>) => UseQueryResult<TEntity, Error>; useEntityList: (filters?: ODataFilter<TEntity>, options?: UseEntityListOptions<TEntity> & UseQueryOptions<ODataResponse<TEntity>, Error>) => UseQueryResult<ODataResponse<TEntity>, Error>; useEntityCount: (filters?: ODataFilter<TEntity>, options?: UseQueryOptions<number, Error>) => UseQueryResult<number, Error>; useRelatedEntities: <TRelated = Record<string, unknown>>(id: string | undefined, relationshipName: string, filters?: ODataFilter<TRelated>, options?: UseEntityListOptions<TRelated> & UseQueryOptions<ODataResponse<TRelated>, Error>) => UseQueryResult<ODataResponse<TRelated>, Error>; metadata: EntityMetadata; }; /** * Create a typed query client helper */ declare function createQueryClient(): unknown; /** * Utility function to invalidate entity queries */ declare function invalidateEntityQueries<TEntity>(queryClient: { invalidateQueries: (queryKey: (string | object)[]) => Promise<void>; }, entityName: string, options?: { operation?: 'single' | 'list' | 'count' | 'related'; id?: string; }): Promise<void>; /** * Create a prefetch function for entities */ declare function createPrefetchFunction<TEntity>(queryClient: { prefetchQuery: (options: { queryKey: unknown[]; queryFn: () => Promise<unknown>; }) => Promise<void>; }, metadata: EntityMetadata): { prefetchEntity: (id: string, options?: UseEntityOptions<TEntity>) => Promise<void>; prefetchEntityList: (filters?: ODataFilter<TEntity>, options?: UseEntityListOptions<TEntity>) => Promise<void>; }; /** * Standalone URL utilities for Dataverse Web API * Perfect for users who don't want to use React Query but need type-safe URLs */ /** * Configure default settings for URL generation */ declare function configureDataverseUrls(config: DataverseUrlConfig): void; /** * Standalone URL utilities for Dataverse entities * Provides type-safe URL generation without React Query dependency */ declare const DataverseUrls: { /** * Get URL for a single entity by ID * * @example * const url = DataverseUrls.entity(entityMetadata, "<entity-id>", { * $select: ['<primary_name_field>', '<description_field>'], * $expand: ['<related_entity>'] * }) */ entity<TEntity>(metadata: EntityMetadata, id: string, options?: Omit<ODataQueryOptions<TEntity>, "$filter" | "$orderby" | "$top" | "$skip" | "$count"> & DataverseUrlConfig): string; /** * Get URL for entity collection (list) * * @example * const url = DataverseUrls.entitySet(entityMetadata, { * $filter: { * '<name_field>': { $contains: "search_term" }, * statecode: '<EntityStatecode>'.Active.Value * }, * $select: ['<primary_name_field>', '<description_field>'], * $orderby: { '<name_field>': 'asc' }, * $top: 50 * }) */ entitySet<TEntity>(metadata: EntityMetadata, options?: ODataQueryOptions<TEntity> & DataverseUrlConfig): string; /** * Get URL for counting entities * * @example * const url = DataverseUrls.count(entityMetadata, { * $filter: { statecode: '<EntityStatecode>'.Active.Value } * }) */ count<TEntity>(metadata: EntityMetadata, options?: { $filter?: ODataFilter<TEntity>; } & DataverseUrlConfig): string; /** * Get URL for related entities * * @example * const url = DataverseUrls.related(entityMetadata, "<entity-id>", "<entity_relationship>", { * $filter: { statecode: '<RelatedEntityStatecode>'.Active.Value }, * $select: ['<primary_name_field>', '<date_field>'], * $orderby: { '<date_field>': 'asc' } * }) */ related<TRelated = Record<string, unknown>>(metadata: EntityMetadata, id: string, relationshipName: string, options?: Omit<ODataQueryOptions<TRelated>, "$expand" | "$count"> & DataverseUrlConfig): string; /** * Build a custom URL with query parameters * * @example * const url = DataverseUrls.custom('/CustomAPI', { param1: 'value1' }) */ custom(endpoint: string, queryParams?: Record<string, string | number | boolean>, config?: DataverseUrlConfig): string; /** * Build batch request URL * * @example * const url = DataverseUrls.batch() */ batch(config?: DataverseUrlConfig): string; }; /** * Helper functions for common URL patterns */ declare const DataverseHelpers: { /** * Create a URL for WebResource access */ webResource(name: string, config?: DataverseUrlConfig): string; /** * Create a URL for executing a custom API */ customApi(apiName: string, parameters?: Record<string, unknown>, config?: DataverseUrlConfig): string; /** * Create a URL for executing a workflow/action */ action(actionName: string, config?: DataverseUrlConfig): string; /** * Create a URL for executing a function */ function(functionName: string, parameters?: Record<string, unknown>, config?: DataverseUrlConfig): string; }; /** * Simplified API options for type generation */ interface GenerateTypesOptions { /** Specific entities to generate (logical names) */ entities?: string[]; /** Publisher prefix to filter entities */ publisher?: string; /** Solution name (unique name or friendly name) to filter entities by actual solution membership */ solution?: string; /** Output directory */ outputDir?: string; /** Dataverse instance URL */ dataverseUrl?: string; /** Include comments in generated code */ includeComments?: boolean; /** Include metadata objects */ includeMetadata?: boolean; } /** * Generate TypeScript types for Dataverse entities * Main public API function * * @param options - Generation options * @returns Promise with generation results */ declare function generateTypes(options?: GenerateTypesOptions): Promise<{ files: Array<{ filePath: string; success: boolean; size: number; error?: string; }>; indexFile?: { filePath: string; success: boolean; size: number; error?: string; }; totalFiles: number; successfulFiles: number; failedFiles: number; totalSize: number; duration: number; processedEntities: number; }>; export { type AttributeMetadata, type AzureAuthOptions, type BooleanOperators, COMPONENT_TYPES, type CodeGenConfig, type CodeGenResult, DEFAULT_CODEGEN_CONFIG, DEFAULT_CONFIG, type DataverseEntity, type DataverseError, type DataverseErrorDetails, type DataverseErrorResponse, DataverseHelpers, type DataverseProperty, type DataverseTypeGenConfig, type DataverseUrlConfig, DataverseUrls, type DateOperators, type EntityCreateInput, type EntityDefinition, type EntityDefinitionResponse, type EntityListOptions, type EntityMetadata, type EntityUpdateInput, type ExpandObject, type ExpandOptions, type ExpandablePropertiesOf, type FetchEntityMetadataOptions, type FilterOperatorForType, type GenerateTypesOptions, type GeneratedCode, type GeneratedFileResult, type GetEntityDefinitionsOptions, type GlobalOptionSetDefinition, type LocalizedLabel, type LookupAttributeMetadata, type LookupOperators, type ManyToManyRelationshipMetadata, type ManyToOneRelationshipMetadata, type MultiSelectPicklistAttributeMetadata, type NumberOperators, type ODataExpand, type ODataFilter, type ODataOrderBy, type ODataQueryOptions, type ODataResponse, type ODataSelect, type ODataSingleResponse, type OneToManyRelationshipMetadata, type OptionSetConstant, type PicklistAttributeMetadata, type ProcessedAttributeMetadata, type ProcessedEntityMetadata, type ProcessedManyToManyRelationshipMetadata, type ProcessedOption, type ProcessedOptionSet, type ProcessedRelationshipMetadata, type ProgressCallback, type QueryKeyOptions, type RelatedEntityInfo, type RelationshipExpandOption, type SolutionComponent, type SolutionDefinition, type StateAttributeMetadata, type StatusAttributeMetadata, type StringOperators, type TypeGenerationOptions, type TypeSafeExpand, type UrlBuilderOptions, type UseEntityListOptions, type UseEntityOptions, type UseQueryOptions, type UseQueryResult, advancedLog, buildCountUrl, buildEntitySetUrl, buildEntityUrl, buildFilterString, buildRelatedUrl, buildUrl, calculateGenerationResults, cleanGeneratedFiles, combineGeneratedCode, configureDataverseUrls as configure, configureDataverseUrls, createAuthenticatedFetcher, createEntityHooks, createOutputDirectory, createPrefetchFunction, createQueryClient, createQueryKey, createSampleConfig, entityExists, extractOptionSetsFromAttributes, extractRelatedEntityNames, fetchAllEntities, fetchAllEntityMetadata, fetchEntityAttributes, fetchEntityMetadata, fetchGlobalOptionSet, fetchMultipleEntities, fetchMultipleEntitiesWithRelated, fetchPublisherEntities, fetchSolutionComponents, fetchSolutionEntities, filterAttributesByType, filterAuxiliaryAttributes, findSolution, formatCode, generateEntityFile, generateEntityInterface, generateGlobalOptionSetFile, generateImports, generateIndexFile, generateMetadataObject, generateMultipleEntityTypes, generateOptionSetConstants, generateTypes, getAzureToken, getCurrentEnvironment, getEntityDefinition, getEntityDefinitions, getEntityDirectory, getErrorCodeDescription, getGeneratedFileStats, getLookupAttributes, getOptionSetAttributes, getPrimaryAttributes, getStatusCodeDescription, groupAttributesByType, invalidateEntityQueries, isPrimaryEntity, loadConfiguration, mergeOptionSets, processAttributeMetadata, processEntityMetadata, processGlobalOptionSet, processOptionSet, saveConfiguration, setupCLI, toCodeGenConfig, validateConfiguration, validateGeneratedCode, validateProcessedMetadata, writeEntityHooksFile, writeEntityQueryBuildersFile, writeEntityTypeDeclaration, writeGlobalOptionSetDeclaration, writeQueryTypesFile };