@peernova/cuneiform-sf 1.0.2 → 1.0.4-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +81 -30
- package/README.md +59 -95
- package/lib/adapters/connection-facade.d.ts +458 -0
- package/lib/adapters/connection-facade.js +379 -0
- package/lib/adapters/connection-facade.js.map +1 -0
- package/lib/adapters/errors.d.ts +547 -0
- package/lib/adapters/errors.js +937 -0
- package/lib/adapters/errors.js.map +1 -0
- package/lib/adapters/index.d.ts +33 -0
- package/lib/adapters/index.js +50 -0
- package/lib/adapters/index.js.map +1 -0
- package/lib/adapters/lifecycle.d.ts +119 -0
- package/lib/adapters/lifecycle.js +94 -0
- package/lib/adapters/lifecycle.js.map +1 -0
- package/lib/adapters/rest/cache.d.ts +69 -0
- package/lib/adapters/rest/cache.js +133 -0
- package/lib/adapters/rest/cache.js.map +1 -0
- package/lib/adapters/rest/index.d.ts +11 -0
- package/lib/adapters/rest/index.js +18 -0
- package/lib/adapters/rest/index.js.map +1 -0
- package/lib/adapters/rest/profiling-rest-client.d.ts +137 -0
- package/lib/adapters/rest/profiling-rest-client.js +115 -0
- package/lib/adapters/rest/profiling-rest-client.js.map +1 -0
- package/lib/adapters/rest/rest-api-adapter.d.ts +389 -0
- package/lib/adapters/rest/rest-api-adapter.js +747 -0
- package/lib/adapters/rest/rest-api-adapter.js.map +1 -0
- package/lib/adapters/rest/types.d.ts +34 -0
- package/lib/adapters/rest/types.js +9 -0
- package/lib/adapters/rest/types.js.map +1 -0
- package/lib/adapters/retry.d.ts +91 -0
- package/lib/adapters/retry.js +215 -0
- package/lib/adapters/retry.js.map +1 -0
- package/lib/adapters/soql/cuneiform-query-builder.d.ts +391 -0
- package/lib/adapters/soql/cuneiform-query-builder.js +559 -0
- package/lib/adapters/soql/cuneiform-query-builder.js.map +1 -0
- package/lib/adapters/soql/index.d.ts +13 -0
- package/lib/adapters/soql/index.js +21 -0
- package/lib/adapters/soql/index.js.map +1 -0
- package/lib/adapters/soql/soql-query-adapter.d.ts +141 -0
- package/lib/adapters/soql/soql-query-adapter.js +259 -0
- package/lib/adapters/soql/soql-query-adapter.js.map +1 -0
- package/lib/adapters/soql/types.d.ts +37 -0
- package/lib/adapters/soql/types.js +19 -0
- package/lib/adapters/soql/types.js.map +1 -0
- package/lib/adapters/testing/index.d.ts +37 -0
- package/lib/adapters/testing/index.js +20 -0
- package/lib/adapters/testing/index.js.map +1 -0
- package/lib/adapters/testing/mock-connection.d.ts +77 -0
- package/lib/adapters/testing/mock-connection.js +207 -0
- package/lib/adapters/testing/mock-connection.js.map +1 -0
- package/lib/adapters/testing/mock-logger.d.ts +29 -0
- package/lib/adapters/testing/mock-logger.js +57 -0
- package/lib/adapters/testing/mock-logger.js.map +1 -0
- package/lib/adapters/testing/mock-mcp-adapters.d.ts +32 -0
- package/lib/adapters/testing/mock-mcp-adapters.js +52 -0
- package/lib/adapters/testing/mock-mcp-adapters.js.map +1 -0
- package/lib/adapters/testing/mock-oclif-config.d.ts +22 -0
- package/lib/adapters/testing/mock-oclif-config.js +90 -0
- package/lib/adapters/testing/mock-oclif-config.js.map +1 -0
- package/lib/adapters/testing/mock-rest-adapter.d.ts +26 -0
- package/lib/adapters/testing/mock-rest-adapter.js +243 -0
- package/lib/adapters/testing/mock-rest-adapter.js.map +1 -0
- package/lib/adapters/testing/mock-salesforce-connection.d.ts +40 -0
- package/lib/adapters/testing/mock-salesforce-connection.js +61 -0
- package/lib/adapters/testing/mock-salesforce-connection.js.map +1 -0
- package/lib/adapters/testing/mock-soql-adapter.d.ts +30 -0
- package/lib/adapters/testing/mock-soql-adapter.js +120 -0
- package/lib/adapters/testing/mock-soql-adapter.js.map +1 -0
- package/lib/adapters/testing/mock-tooling-adapter.d.ts +24 -0
- package/lib/adapters/testing/mock-tooling-adapter.js +163 -0
- package/lib/adapters/testing/mock-tooling-adapter.js.map +1 -0
- package/lib/adapters/testing/stub-connection.d.ts +93 -0
- package/lib/adapters/testing/stub-connection.js +97 -0
- package/lib/adapters/testing/stub-connection.js.map +1 -0
- package/lib/adapters/testing/stub-rest-adapter.d.ts +52 -0
- package/lib/adapters/testing/stub-rest-adapter.js +58 -0
- package/lib/adapters/testing/stub-rest-adapter.js.map +1 -0
- package/lib/adapters/testing/stub-soql-adapter.d.ts +56 -0
- package/lib/adapters/testing/stub-soql-adapter.js +50 -0
- package/lib/adapters/testing/stub-soql-adapter.js.map +1 -0
- package/lib/adapters/testing/types.d.ts +71 -0
- package/lib/adapters/testing/types.js +9 -0
- package/lib/adapters/testing/types.js.map +1 -0
- package/lib/adapters/tooling/index.d.ts +10 -0
- package/lib/adapters/tooling/index.js +17 -0
- package/lib/adapters/tooling/index.js.map +1 -0
- package/lib/adapters/tooling/tooling-api-adapter.d.ts +157 -0
- package/lib/adapters/tooling/tooling-api-adapter.js +339 -0
- package/lib/adapters/tooling/tooling-api-adapter.js.map +1 -0
- package/lib/adapters/tooling/types.d.ts +81 -0
- package/lib/adapters/tooling/types.js +9 -0
- package/lib/adapters/tooling/types.js.map +1 -0
- package/lib/adapters/types.d.ts +112 -0
- package/lib/adapters/types.js +169 -0
- package/lib/adapters/types.js.map +1 -0
- package/lib/base/cuneiform-command.d.ts +152 -0
- package/lib/base/cuneiform-command.js +243 -0
- package/lib/base/cuneiform-command.js.map +1 -0
- package/lib/commands/cuneiform/compatibility/check.d.ts +43 -0
- package/lib/commands/cuneiform/compatibility/check.js +114 -0
- package/lib/commands/cuneiform/compatibility/check.js.map +1 -0
- package/lib/commands/cuneiform/definition/create.d.ts +119 -0
- package/lib/commands/cuneiform/definition/create.js +693 -0
- package/lib/commands/cuneiform/definition/create.js.map +1 -0
- package/lib/commands/cuneiform/definition/export.d.ts +57 -0
- package/lib/commands/cuneiform/definition/export.js +133 -0
- package/lib/commands/cuneiform/definition/export.js.map +1 -0
- package/lib/commands/cuneiform/definition/get.d.ts +86 -0
- package/lib/commands/cuneiform/definition/get.js +270 -0
- package/lib/commands/cuneiform/definition/get.js.map +1 -0
- package/lib/commands/cuneiform/definition/import.d.ts +54 -0
- package/lib/commands/cuneiform/definition/import.js +118 -0
- package/lib/commands/cuneiform/definition/import.js.map +1 -0
- package/lib/commands/cuneiform/definition/list.d.ts +110 -0
- package/lib/commands/cuneiform/definition/list.js +344 -0
- package/lib/commands/cuneiform/definition/list.js.map +1 -0
- package/lib/commands/cuneiform/definition/purge.d.ts +105 -0
- package/lib/commands/cuneiform/definition/purge.js +533 -0
- package/lib/commands/cuneiform/definition/purge.js.map +1 -0
- package/lib/commands/cuneiform/definition/update.d.ts +58 -0
- package/lib/commands/cuneiform/definition/update.js +206 -0
- package/lib/commands/cuneiform/definition/update.js.map +1 -0
- package/lib/commands/cuneiform/mcp/serve.d.ts +56 -0
- package/lib/commands/cuneiform/mcp/serve.js +109 -0
- package/lib/commands/cuneiform/mcp/serve.js.map +1 -0
- package/lib/commands/cuneiform/object/describe.d.ts +61 -0
- package/lib/commands/cuneiform/object/describe.js +461 -0
- package/lib/commands/cuneiform/object/describe.js.map +1 -0
- package/lib/commands/cuneiform/object/list.d.ts +111 -0
- package/lib/commands/cuneiform/object/list.js +239 -0
- package/lib/commands/cuneiform/object/list.js.map +1 -0
- package/lib/commands/cuneiform/org/details.d.ts +99 -0
- package/lib/commands/cuneiform/org/details.js +521 -0
- package/lib/commands/cuneiform/org/details.js.map +1 -0
- package/lib/commands/cuneiform/org/reset.d.ts +46 -0
- package/lib/commands/cuneiform/org/reset.js +135 -0
- package/lib/commands/cuneiform/org/reset.js.map +1 -0
- package/lib/commands/cuneiform/profile/request/cancel.d.ts +59 -0
- package/lib/commands/cuneiform/profile/request/cancel.js +202 -0
- package/lib/commands/cuneiform/profile/request/cancel.js.map +1 -0
- package/lib/commands/cuneiform/profile/request/delete.d.ts +59 -0
- package/lib/commands/cuneiform/profile/request/delete.js +223 -0
- package/lib/commands/cuneiform/profile/request/delete.js.map +1 -0
- package/lib/commands/cuneiform/profile/request/list.d.ts +35 -0
- package/lib/commands/cuneiform/profile/request/list.js +102 -0
- package/lib/commands/cuneiform/profile/request/list.js.map +1 -0
- package/lib/commands/cuneiform/profile.d.ts +90 -0
- package/lib/commands/cuneiform/profile.js +322 -0
- package/lib/commands/cuneiform/profile.js.map +1 -0
- package/lib/commands/cuneiform/summary/purge.d.ts +77 -0
- package/lib/commands/cuneiform/summary/purge.js +429 -0
- package/lib/commands/cuneiform/summary/purge.js.map +1 -0
- package/lib/commands/cuneiform/summary/reprofile.d.ts +60 -0
- package/lib/commands/cuneiform/summary/reprofile.js +236 -0
- package/lib/commands/cuneiform/summary/reprofile.js.map +1 -0
- package/lib/commands/cuneiform/summary/stop.d.ts +59 -0
- package/lib/commands/cuneiform/summary/stop.js +234 -0
- package/lib/commands/cuneiform/summary/stop.js.map +1 -0
- package/lib/commands/cuneiform/user/details.d.ts +73 -0
- package/lib/commands/cuneiform/user/details.js +391 -0
- package/lib/commands/cuneiform/user/details.js.map +1 -0
- package/lib/constants/index.d.ts +8 -0
- package/lib/constants/index.js +16 -0
- package/lib/constants/index.js.map +1 -0
- package/lib/constants/namespace-constants.d.ts +91 -0
- package/lib/constants/namespace-constants.js +211 -0
- package/lib/constants/namespace-constants.js.map +1 -0
- package/lib/debug/command-debug-proxy.d.ts +101 -0
- package/lib/debug/command-debug-proxy.js +171 -0
- package/lib/debug/command-debug-proxy.js.map +1 -0
- package/lib/debug/debug-logger.d.ts +85 -0
- package/lib/debug/debug-logger.js +133 -0
- package/lib/debug/debug-logger.js.map +1 -0
- package/lib/debug/index.d.ts +12 -0
- package/lib/debug/index.js +20 -0
- package/lib/debug/index.js.map +1 -0
- package/lib/debug/service-debug-proxy.d.ts +30 -0
- package/lib/debug/service-debug-proxy.js +102 -0
- package/lib/debug/service-debug-proxy.js.map +1 -0
- package/lib/hooks/prerun.d.ts +25 -0
- package/lib/hooks/prerun.js +47 -0
- package/lib/hooks/prerun.js.map +1 -0
- package/lib/mcp/config/mcp-config.d.ts +55 -0
- package/lib/mcp/config/mcp-config.js +51 -0
- package/lib/mcp/config/mcp-config.js.map +1 -0
- package/lib/mcp/config/pagination.d.ts +96 -0
- package/lib/mcp/config/pagination.js +108 -0
- package/lib/mcp/config/pagination.js.map +1 -0
- package/lib/mcp/config/system-prompts.d.ts +18 -0
- package/lib/mcp/config/system-prompts.js +92 -0
- package/lib/mcp/config/system-prompts.js.map +1 -0
- package/lib/mcp/errors.d.ts +23 -0
- package/lib/mcp/errors.js +27 -0
- package/lib/mcp/errors.js.map +1 -0
- package/lib/mcp/schemas/input-schemas.d.ts +327 -0
- package/lib/mcp/schemas/input-schemas.js +302 -0
- package/lib/mcp/schemas/input-schemas.js.map +1 -0
- package/lib/mcp/server.d.ts +40 -0
- package/lib/mcp/server.js +316 -0
- package/lib/mcp/server.js.map +1 -0
- package/lib/mcp/tools/contactpoint-tools.d.ts +14 -0
- package/lib/mcp/tools/contactpoint-tools.js +34 -0
- package/lib/mcp/tools/contactpoint-tools.js.map +1 -0
- package/lib/mcp/tools/definition-io-tools.d.ts +19 -0
- package/lib/mcp/tools/definition-io-tools.js +152 -0
- package/lib/mcp/tools/definition-io-tools.js.map +1 -0
- package/lib/mcp/tools/definition-tools.d.ts +51 -0
- package/lib/mcp/tools/definition-tools.js +199 -0
- package/lib/mcp/tools/definition-tools.js.map +1 -0
- package/lib/mcp/tools/index.d.ts +37 -0
- package/lib/mcp/tools/index.js +88 -0
- package/lib/mcp/tools/index.js.map +1 -0
- package/lib/mcp/tools/object-tools.d.ts +22 -0
- package/lib/mcp/tools/object-tools.js +306 -0
- package/lib/mcp/tools/object-tools.js.map +1 -0
- package/lib/mcp/tools/org-tools.d.ts +14 -0
- package/lib/mcp/tools/org-tools.js +177 -0
- package/lib/mcp/tools/org-tools.js.map +1 -0
- package/lib/mcp/tools/profile-tools.d.ts +59 -0
- package/lib/mcp/tools/profile-tools.js +213 -0
- package/lib/mcp/tools/profile-tools.js.map +1 -0
- package/lib/mcp/tools/summary-tools.d.ts +14 -0
- package/lib/mcp/tools/summary-tools.js +38 -0
- package/lib/mcp/tools/summary-tools.js.map +1 -0
- package/lib/mcp/tools/tool-factory.d.ts +63 -0
- package/lib/mcp/tools/tool-factory.js +146 -0
- package/lib/mcp/tools/tool-factory.js.map +1 -0
- package/lib/mcp/tools/user-tools.d.ts +25 -0
- package/lib/mcp/tools/user-tools.js +167 -0
- package/lib/mcp/tools/user-tools.js.map +1 -0
- package/lib/models/date-literal.d.ts +211 -0
- package/lib/models/date-literal.js +615 -0
- package/lib/models/date-literal.js.map +1 -0
- package/lib/models/object-describe-types.d.ts +173 -0
- package/lib/models/object-describe-types.js +9 -0
- package/lib/models/object-describe-types.js.map +1 -0
- package/lib/models/profile-request-types.d.ts +118 -0
- package/lib/models/profile-request-types.js +23 -0
- package/lib/models/profile-request-types.js.map +1 -0
- package/lib/models/profiling-execution-types.d.ts +154 -0
- package/lib/models/profiling-execution-types.js +14 -0
- package/lib/models/profiling-execution-types.js.map +1 -0
- package/lib/models/service-result.d.ts +114 -0
- package/lib/models/service-result.js +81 -0
- package/lib/models/service-result.js.map +1 -0
- package/lib/models/sfdmu-types.d.ts +53 -0
- package/lib/models/sfdmu-types.js +23 -0
- package/lib/models/sfdmu-types.js.map +1 -0
- package/lib/models/status-types.d.ts +38 -0
- package/lib/models/status-types.js +12 -0
- package/lib/models/status-types.js.map +1 -0
- package/lib/models/summary-bulk-types.d.ts +61 -0
- package/lib/models/summary-bulk-types.js +23 -0
- package/lib/models/summary-bulk-types.js.map +1 -0
- package/lib/models/user-details-types.d.ts +163 -0
- package/lib/models/user-details-types.js +9 -0
- package/lib/models/user-details-types.js.map +1 -0
- package/lib/models/year-range.d.ts +78 -0
- package/lib/models/year-range.js +153 -0
- package/lib/models/year-range.js.map +1 -0
- package/lib/operations/CompatibilityCheckOperation.d.ts +62 -0
- package/lib/operations/CompatibilityCheckOperation.js +102 -0
- package/lib/operations/CompatibilityCheckOperation.js.map +1 -0
- package/lib/operations/DefinitionCreateOperation.d.ts +411 -0
- package/lib/operations/DefinitionCreateOperation.js +1121 -0
- package/lib/operations/DefinitionCreateOperation.js.map +1 -0
- package/lib/operations/DefinitionExportOperation.d.ts +155 -0
- package/lib/operations/DefinitionExportOperation.js +281 -0
- package/lib/operations/DefinitionExportOperation.js.map +1 -0
- package/lib/operations/DefinitionImportOperation.d.ts +144 -0
- package/lib/operations/DefinitionImportOperation.js +357 -0
- package/lib/operations/DefinitionImportOperation.js.map +1 -0
- package/lib/operations/DefinitionListOperation.d.ts +66 -0
- package/lib/operations/DefinitionListOperation.js +108 -0
- package/lib/operations/DefinitionListOperation.js.map +1 -0
- package/lib/operations/DefinitionPurgeOperation.d.ts +199 -0
- package/lib/operations/DefinitionPurgeOperation.js +465 -0
- package/lib/operations/DefinitionPurgeOperation.js.map +1 -0
- package/lib/operations/DefinitionUpdateOperation.d.ts +78 -0
- package/lib/operations/DefinitionUpdateOperation.js +142 -0
- package/lib/operations/DefinitionUpdateOperation.js.map +1 -0
- package/lib/operations/OrgDetailsOperation.d.ts +253 -0
- package/lib/operations/OrgDetailsOperation.js +456 -0
- package/lib/operations/OrgDetailsOperation.js.map +1 -0
- package/lib/operations/OrgResetOperation.d.ts +114 -0
- package/lib/operations/OrgResetOperation.js +209 -0
- package/lib/operations/OrgResetOperation.js.map +1 -0
- package/lib/operations/ProfileOperation.d.ts +187 -0
- package/lib/operations/ProfileOperation.js +373 -0
- package/lib/operations/ProfileOperation.js.map +1 -0
- package/lib/operations/ProfileRequestCancelOperation.d.ts +59 -0
- package/lib/operations/ProfileRequestCancelOperation.js +137 -0
- package/lib/operations/ProfileRequestCancelOperation.js.map +1 -0
- package/lib/operations/ProfileRequestDeleteOperation.d.ts +64 -0
- package/lib/operations/ProfileRequestDeleteOperation.js +134 -0
- package/lib/operations/ProfileRequestDeleteOperation.js.map +1 -0
- package/lib/operations/ProfileRequestListOperation.d.ts +39 -0
- package/lib/operations/ProfileRequestListOperation.js +61 -0
- package/lib/operations/ProfileRequestListOperation.js.map +1 -0
- package/lib/operations/SummaryPurgeOperation.d.ts +134 -0
- package/lib/operations/SummaryPurgeOperation.js +257 -0
- package/lib/operations/SummaryPurgeOperation.js.map +1 -0
- package/lib/operations/SummaryReprofileOperation.d.ts +88 -0
- package/lib/operations/SummaryReprofileOperation.js +174 -0
- package/lib/operations/SummaryReprofileOperation.js.map +1 -0
- package/lib/operations/SummaryStopOperation.d.ts +87 -0
- package/lib/operations/SummaryStopOperation.js +175 -0
- package/lib/operations/SummaryStopOperation.js.map +1 -0
- package/lib/services/BulkExecutionService.d.ts +120 -0
- package/lib/services/BulkExecutionService.js +535 -0
- package/lib/services/BulkExecutionService.js.map +1 -0
- package/lib/services/CompatibilityService.d.ts +81 -0
- package/lib/services/CompatibilityService.js +118 -0
- package/lib/services/CompatibilityService.js.map +1 -0
- package/lib/services/ConfigureMode.d.ts +85 -0
- package/lib/services/ConfigureMode.js +390 -0
- package/lib/services/ConfigureMode.js.map +1 -0
- package/lib/services/ContactPointService.d.ts +111 -0
- package/lib/services/ContactPointService.js +286 -0
- package/lib/services/ContactPointService.js.map +1 -0
- package/lib/services/DataAvailabilityService.d.ts +81 -0
- package/lib/services/DataAvailabilityService.js +128 -0
- package/lib/services/DataAvailabilityService.js.map +1 -0
- package/lib/services/DefinitionFieldGenerationService.d.ts +309 -0
- package/lib/services/DefinitionFieldGenerationService.js +795 -0
- package/lib/services/DefinitionFieldGenerationService.js.map +1 -0
- package/lib/services/DefinitionQueryBuilder.d.ts +59 -0
- package/lib/services/DefinitionQueryBuilder.js +234 -0
- package/lib/services/DefinitionQueryBuilder.js.map +1 -0
- package/lib/services/ObjectDescribeService.d.ts +436 -0
- package/lib/services/ObjectDescribeService.js +869 -0
- package/lib/services/ObjectDescribeService.js.map +1 -0
- package/lib/services/ObjectFilteringService.d.ts +400 -0
- package/lib/services/ObjectFilteringService.js +878 -0
- package/lib/services/ObjectFilteringService.js.map +1 -0
- package/lib/services/ObjectListCommandService.d.ts +429 -0
- package/lib/services/ObjectListCommandService.js +873 -0
- package/lib/services/ObjectListCommandService.js.map +1 -0
- package/lib/services/ObjectListService.d.ts +201 -0
- package/lib/services/ObjectListService.js +345 -0
- package/lib/services/ObjectListService.js.map +1 -0
- package/lib/services/OrgInfoService.d.ts +485 -0
- package/lib/services/OrgInfoService.js +1122 -0
- package/lib/services/OrgInfoService.js.map +1 -0
- package/lib/services/PollingService.d.ts +105 -0
- package/lib/services/PollingService.js +117 -0
- package/lib/services/PollingService.js.map +1 -0
- package/lib/services/ProfileRequestService.d.ts +186 -0
- package/lib/services/ProfileRequestService.js +555 -0
- package/lib/services/ProfileRequestService.js.map +1 -0
- package/lib/services/ProfilingDefinitionService.d.ts +535 -0
- package/lib/services/ProfilingDefinitionService.js +981 -0
- package/lib/services/ProfilingDefinitionService.js.map +1 -0
- package/lib/services/ProfilingExecutionService.d.ts +122 -0
- package/lib/services/ProfilingExecutionService.js +320 -0
- package/lib/services/ProfilingExecutionService.js.map +1 -0
- package/lib/services/ProfilingSummaryService.d.ts +292 -0
- package/lib/services/ProfilingSummaryService.js +685 -0
- package/lib/services/ProfilingSummaryService.js.map +1 -0
- package/lib/services/RecordTypeService.d.ts +129 -0
- package/lib/services/RecordTypeService.js +284 -0
- package/lib/services/RecordTypeService.js.map +1 -0
- package/lib/services/SFDMUService.d.ts +133 -0
- package/lib/services/SFDMUService.js +295 -0
- package/lib/services/SFDMUService.js.map +1 -0
- package/lib/services/TabDetectionService.d.ts +105 -0
- package/lib/services/TabDetectionService.js +206 -0
- package/lib/services/TabDetectionService.js.map +1 -0
- package/lib/services/UnconfigureMode.d.ts +74 -0
- package/lib/services/UnconfigureMode.js +378 -0
- package/lib/services/UnconfigureMode.js.map +1 -0
- package/lib/services/UserConfigurationService.d.ts +155 -0
- package/lib/services/UserConfigurationService.js +573 -0
- package/lib/services/UserConfigurationService.js.map +1 -0
- package/lib/services/UserConfigurationTypes.d.ts +181 -0
- package/lib/services/UserConfigurationTypes.js +14 -0
- package/lib/services/UserConfigurationTypes.js.map +1 -0
- package/lib/services/UserReadinessService.d.ts +330 -0
- package/lib/services/UserReadinessService.js +831 -0
- package/lib/services/UserReadinessService.js.map +1 -0
- package/lib/services/constants.d.ts +53 -0
- package/lib/services/constants.js +71 -0
- package/lib/services/constants.js.map +1 -0
- package/lib/services/namespace-constants.d.ts +1 -0
- package/lib/services/namespace-constants.js +11 -0
- package/lib/services/namespace-constants.js.map +1 -0
- package/lib/services/validation.d.ts +47 -0
- package/lib/services/validation.js +119 -0
- package/lib/services/validation.js.map +1 -0
- package/lib/utils/batch-processor.d.ts +13 -0
- package/lib/utils/batch-processor.js +39 -0
- package/lib/utils/batch-processor.js.map +1 -0
- package/lib/utils/formatting/availability-grid.d.ts +81 -0
- package/lib/utils/formatting/availability-grid.js +94 -0
- package/lib/utils/formatting/availability-grid.js.map +1 -0
- package/lib/utils/formatting/business-process-grid.d.ts +51 -0
- package/lib/utils/formatting/business-process-grid.js +58 -0
- package/lib/utils/formatting/business-process-grid.js.map +1 -0
- package/lib/utils/formatting/command-display.d.ts +154 -0
- package/lib/utils/formatting/command-display.js +154 -0
- package/lib/utils/formatting/command-display.js.map +1 -0
- package/lib/utils/formatting/definition-create-display.d.ts +118 -0
- package/lib/utils/formatting/definition-create-display.js +231 -0
- package/lib/utils/formatting/definition-create-display.js.map +1 -0
- package/lib/utils/formatting/empty-states.d.ts +35 -0
- package/lib/utils/formatting/empty-states.js +70 -0
- package/lib/utils/formatting/empty-states.js.map +1 -0
- package/lib/utils/formatting/errors.d.ts +33 -0
- package/lib/utils/formatting/errors.js +72 -0
- package/lib/utils/formatting/errors.js.map +1 -0
- package/lib/utils/formatting/field-types.d.ts +32 -0
- package/lib/utils/formatting/field-types.js +88 -0
- package/lib/utils/formatting/field-types.js.map +1 -0
- package/lib/utils/formatting/index.d.ts +29 -0
- package/lib/utils/formatting/index.js +28 -0
- package/lib/utils/formatting/index.js.map +1 -0
- package/lib/utils/formatting/indicators.d.ts +113 -0
- package/lib/utils/formatting/indicators.js +161 -0
- package/lib/utils/formatting/indicators.js.map +1 -0
- package/lib/utils/formatting/loading-messages.d.ts +37 -0
- package/lib/utils/formatting/loading-messages.js +50 -0
- package/lib/utils/formatting/loading-messages.js.map +1 -0
- package/lib/utils/formatting/namespace-display.d.ts +31 -0
- package/lib/utils/formatting/namespace-display.js +64 -0
- package/lib/utils/formatting/namespace-display.js.map +1 -0
- package/lib/utils/formatting/numbers.d.ts +73 -0
- package/lib/utils/formatting/numbers.js +187 -0
- package/lib/utils/formatting/numbers.js.map +1 -0
- package/lib/utils/formatting/object-describe-display.d.ts +114 -0
- package/lib/utils/formatting/object-describe-display.js +440 -0
- package/lib/utils/formatting/object-describe-display.js.map +1 -0
- package/lib/utils/formatting/object-list-display.d.ts +213 -0
- package/lib/utils/formatting/object-list-display.js +672 -0
- package/lib/utils/formatting/object-list-display.js.map +1 -0
- package/lib/utils/formatting/org-identity.d.ts +15 -0
- package/lib/utils/formatting/org-identity.js +28 -0
- package/lib/utils/formatting/org-identity.js.map +1 -0
- package/lib/utils/formatting/record-age-grid.d.ts +41 -0
- package/lib/utils/formatting/record-age-grid.js +56 -0
- package/lib/utils/formatting/record-age-grid.js.map +1 -0
- package/lib/utils/formatting/sections.d.ts +108 -0
- package/lib/utils/formatting/sections.js +150 -0
- package/lib/utils/formatting/sections.js.map +1 -0
- package/lib/utils/formatting/tables.d.ts +90 -0
- package/lib/utils/formatting/tables.js +113 -0
- package/lib/utils/formatting/tables.js.map +1 -0
- package/lib/utils/formatting/user-details-display.d.ts +101 -0
- package/lib/utils/formatting/user-details-display.js +425 -0
- package/lib/utils/formatting/user-details-display.js.map +1 -0
- package/lib/utils/pagination/index.d.ts +11 -0
- package/lib/utils/pagination/index.js +18 -0
- package/lib/utils/pagination/index.js.map +1 -0
- package/lib/utils/pagination/keypress-reader.d.ts +20 -0
- package/lib/utils/pagination/keypress-reader.js +63 -0
- package/lib/utils/pagination/keypress-reader.js.map +1 -0
- package/lib/utils/pagination/paginate-output.d.ts +48 -0
- package/lib/utils/pagination/paginate-output.js +136 -0
- package/lib/utils/pagination/paginate-output.js.map +1 -0
- package/messages/compatibility.check.md +71 -0
- package/messages/cuneiform.access.md +138 -0
- package/messages/definition.create.md +511 -0
- package/messages/definition.export.md +84 -0
- package/messages/definition.get.md +147 -0
- package/messages/definition.import.md +65 -0
- package/messages/definition.list.md +264 -0
- package/messages/definition.purge.md +318 -0
- package/messages/definition.update.md +118 -0
- package/messages/mcp.serve.md +66 -0
- package/messages/object.describe.md +201 -0
- package/messages/object.list.md +443 -0
- package/messages/org.details.md +386 -0
- package/messages/org.reset.md +71 -0
- package/messages/profile.md +231 -0
- package/messages/profile.request.cancel.md +143 -0
- package/messages/profile.request.delete.md +139 -0
- package/messages/profile.request.list.md +89 -0
- package/messages/summary.purge.md +218 -0
- package/messages/summary.reprofile.md +150 -0
- package/messages/summary.stop.md +157 -0
- package/messages/user.details.md +501 -0
- package/oclif.lock +2887 -2149
- package/oclif.manifest.json +2813 -31
- package/package.json +94 -19
- package/lib/commands/cuneiform/about.d.ts +0 -13
- package/lib/commands/cuneiform/about.js +0 -26
- package/lib/commands/cuneiform/about.js.map +0 -1
- package/lib/commands/hello/world.d.ts +0 -14
- package/lib/commands/hello/world.js +0 -27
- package/lib/commands/hello/world.js.map +0 -1
- package/lib/index.d.ts +0 -2
- package/lib/index.js +0 -2
- package/lib/index.js.map +0 -1
- package/messages/cuneiform.about.md +0 -19
- package/messages/hello.world.md +0 -29
|
@@ -0,0 +1,1121 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026, PeerNova, Inc. All Rights Reserved.
|
|
3
|
+
* PROPRIETARY AND CONFIDENTIAL. Unauthorized copying, modification,
|
|
4
|
+
* or distribution is strictly prohibited. Use is governed by the
|
|
5
|
+
* Master Subscription Agreement (MSA) between PeerNova, Inc. and the
|
|
6
|
+
* licensee. See LICENSE file in the repo root.
|
|
7
|
+
*/
|
|
8
|
+
import { createSuccessResult, createFailureResult } from '../models/service-result.js';
|
|
9
|
+
import { MAX_PAGINATION_LIMIT } from '../services/constants.js';
|
|
10
|
+
import { DefinitionFieldGenerationService } from '../services/DefinitionFieldGenerationService.js';
|
|
11
|
+
/**
|
|
12
|
+
* Error codes specific to create operations.
|
|
13
|
+
*/
|
|
14
|
+
export const CreateErrorCodes = {
|
|
15
|
+
/** Object filtering failed */
|
|
16
|
+
FILTER_FAILED: 'CREATE_FILTER_FAILED',
|
|
17
|
+
/** No objects found matching filters */
|
|
18
|
+
NO_OBJECTS_FOUND: 'CREATE_NO_OBJECTS_FOUND',
|
|
19
|
+
/** None of the specified --objects exist in the org */
|
|
20
|
+
OBJECTS_NOT_FOUND: 'CREATE_OBJECTS_NOT_FOUND',
|
|
21
|
+
/** All objects already have definitions */
|
|
22
|
+
ALL_OBJECTS_SKIPPED: 'CREATE_ALL_OBJECTS_SKIPPED',
|
|
23
|
+
/** Operation failed unexpectedly */
|
|
24
|
+
OPERATION_FAILED: 'CREATE_OPERATION_FAILED',
|
|
25
|
+
/** No objects have been profiled yet */
|
|
26
|
+
NO_PROFILED_OBJECTS: 'CREATE_NO_PROFILED_OBJECTS',
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Orchestrates bulk creation of profiling definitions for filtered objects.
|
|
30
|
+
*
|
|
31
|
+
* Follows the 4-layer architecture: Command -> Operation -> Service -> API
|
|
32
|
+
* This operation layer handles business logic orchestration:
|
|
33
|
+
* 1. Filters objects using ObjectFilteringService
|
|
34
|
+
* 2. Checks for existing definitions using ProfilingDefinitionService
|
|
35
|
+
* 3. Creates definitions for new objects only (deduplication)
|
|
36
|
+
* 4. Reports created/failed/skipped statistics
|
|
37
|
+
*
|
|
38
|
+
* Pure field generation logic (naming, categorisation, description, candidate inputs)
|
|
39
|
+
* is delegated to DefinitionFieldGenerationService.
|
|
40
|
+
*/
|
|
41
|
+
export class DefinitionCreateOperation {
|
|
42
|
+
definitionService;
|
|
43
|
+
filteringService;
|
|
44
|
+
logger;
|
|
45
|
+
profilingSummaryService;
|
|
46
|
+
recordTypeService;
|
|
47
|
+
dataAvailabilityService;
|
|
48
|
+
restClient;
|
|
49
|
+
/** Exposes the date literal constant map for external consumers and tests. */
|
|
50
|
+
static DATE_LITERAL_MAP = DefinitionFieldGenerationService.DATE_LITERAL_MAP;
|
|
51
|
+
/** The bullet separator used in definition names. */
|
|
52
|
+
static NAME_SEPARATOR = DefinitionFieldGenerationService.NAME_SEPARATOR;
|
|
53
|
+
/**
|
|
54
|
+
* Creates a new DefinitionCreateOperation instance.
|
|
55
|
+
*
|
|
56
|
+
* @param definitionService - Service for creating and querying profiling definitions
|
|
57
|
+
* @param filteringService - Service for filtering Salesforce objects
|
|
58
|
+
* @param logger - Optional logger for debug output
|
|
59
|
+
* @param profilingSummaryService - Optional service for querying profiled objects (required when profiled=true)
|
|
60
|
+
* @param recordTypeService - Optional service for querying record types (required when method=recordtype)
|
|
61
|
+
*/
|
|
62
|
+
constructor(definitionService, filteringService, logger, profilingSummaryService, recordTypeService, dataAvailabilityService, restClient) {
|
|
63
|
+
this.definitionService = definitionService;
|
|
64
|
+
this.filteringService = filteringService;
|
|
65
|
+
this.logger = logger;
|
|
66
|
+
this.profilingSummaryService = profilingSummaryService;
|
|
67
|
+
this.recordTypeService = recordTypeService;
|
|
68
|
+
this.dataAvailabilityService = dataAvailabilityService;
|
|
69
|
+
this.restClient = restClient;
|
|
70
|
+
}
|
|
71
|
+
// ── Public Static Methods ────────────────────────────────────────────
|
|
72
|
+
/**
|
|
73
|
+
* Resolves the definition name from the method and context.
|
|
74
|
+
* Single source of truth for definition naming across all definition types.
|
|
75
|
+
*
|
|
76
|
+
* @param label - Object label (e.g., 'Account', 'Lead')
|
|
77
|
+
* @param method - ISV method (metadata, historical, comparative)
|
|
78
|
+
* @param context - Optional context: timeLabel, year, recordTypeName, outcomeLabels, unbounded
|
|
79
|
+
* @returns The formatted definition name
|
|
80
|
+
*/
|
|
81
|
+
static resolveDefinitionName(...args) {
|
|
82
|
+
return DefinitionFieldGenerationService.resolveDefinitionName(...args);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolves all definition metadata (category, timeCategory, segmentCategory, description)
|
|
86
|
+
* from the method and context. Single source of truth for definition classification.
|
|
87
|
+
*/
|
|
88
|
+
static resolveDefinitionMetadata(...args) {
|
|
89
|
+
return DefinitionFieldGenerationService.resolveDefinitionMetadata(...args);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Formats a human-readable message for a per-object result.
|
|
93
|
+
*/
|
|
94
|
+
static formatObjectMessage(result) {
|
|
95
|
+
switch (result.status) {
|
|
96
|
+
case 'success':
|
|
97
|
+
return `created "${result.definitionName}"`;
|
|
98
|
+
case 'skip':
|
|
99
|
+
return 'definition already exists';
|
|
100
|
+
case 'fail':
|
|
101
|
+
return result.error ?? 'unknown error';
|
|
102
|
+
case 'preview':
|
|
103
|
+
return `would create "${result.definitionName}"`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Derives the time category display value from an input's method and year.
|
|
108
|
+
*/
|
|
109
|
+
static resolveTimeCategory(input) {
|
|
110
|
+
if (!input)
|
|
111
|
+
return undefined;
|
|
112
|
+
if (input.timeCategory)
|
|
113
|
+
return input.timeCategory;
|
|
114
|
+
if (input.method === 'metadata')
|
|
115
|
+
return 'N/A';
|
|
116
|
+
if (input.comparativeYear !== undefined) {
|
|
117
|
+
return input.usePrior
|
|
118
|
+
? `${input.comparativeYear} vs Prior`
|
|
119
|
+
: `${input.comparativeYear} vs ${input.comparativeYear - 1}`;
|
|
120
|
+
}
|
|
121
|
+
if (input.historicalYear !== undefined) {
|
|
122
|
+
return String(input.historicalYear);
|
|
123
|
+
}
|
|
124
|
+
return 'Lifetime';
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Derives the segment category display value from an input. Prefers the
|
|
128
|
+
* pre-resolved `input.segmentCategory` (populated by the field generation
|
|
129
|
+
* service, which honors the --segment-category override and falls back to
|
|
130
|
+
* method-derived defaults like 'N/A', 'Historical', or record type name).
|
|
131
|
+
* Falls back to `input.recordTypeName` for back-compat with consumers that
|
|
132
|
+
* build inputs without going through `resolveDefinitionMetadata`.
|
|
133
|
+
*/
|
|
134
|
+
static resolveSegmentCategory(input) {
|
|
135
|
+
if (!input)
|
|
136
|
+
return undefined;
|
|
137
|
+
return input.segmentCategory ?? input.recordTypeName;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Maps Salesforce objects to their outcome boolean fields.
|
|
141
|
+
*
|
|
142
|
+
* @param objectName - Salesforce object API name (e.g., 'Opportunity', 'Case', 'Lead')
|
|
143
|
+
* @returns Outcome field mapping, or undefined if the object has no outcome field
|
|
144
|
+
*/
|
|
145
|
+
static getOutcomeField(objectName) {
|
|
146
|
+
return DefinitionFieldGenerationService.getOutcomeField(objectName);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Builds a single outcome definition input for a given object, outcome mapping, and optional time/RT context.
|
|
150
|
+
* Consolidates the repeated context + input construction pattern used across buildOutcomeCandidateInputs
|
|
151
|
+
* and buildInputsForRecordType.
|
|
152
|
+
*/
|
|
153
|
+
static buildOutcomeInput(...args) {
|
|
154
|
+
return DefinitionFieldGenerationService.buildOutcomeInput(...args);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Builds an ISV-compatible filterJson string for business process outcome comparisons.
|
|
158
|
+
* SetA filters for the true outcome, SetB filters for the false outcome.
|
|
159
|
+
* Produces the expression builder JSON schema that `fsc_expressionBuilder3` expects.
|
|
160
|
+
*
|
|
161
|
+
* @param fieldName - Boolean field API name (e.g., 'IsWon', 'IsClosed', 'IsConverted')
|
|
162
|
+
* @param objectName - Salesforce object API name (e.g., 'Opportunity', 'Case', 'Lead')
|
|
163
|
+
* @returns JSON string compatible with GlobalProfilingService.createProfilingDefinition()
|
|
164
|
+
*/
|
|
165
|
+
static buildOutcomeFilterJson(...args) {
|
|
166
|
+
return DefinitionFieldGenerationService.buildOutcomeFilterJson(...args);
|
|
167
|
+
}
|
|
168
|
+
// ── Private Static Helpers (execution) ────────────────────────────
|
|
169
|
+
/**
|
|
170
|
+
* Applies outcome pre-filtering for the REST path. For outcome method, only objects
|
|
171
|
+
* with outcome fields (Opportunity, Case, Lead) are eligible. Returns a failure result
|
|
172
|
+
* when no eligible objects remain; otherwise returns the filtered array.
|
|
173
|
+
*/
|
|
174
|
+
/**
|
|
175
|
+
* Composes the `nameSuffix` value sent to the ISV `create-smart` REST endpoint, layering the
|
|
176
|
+
* `No Value Frequency` disambiguator ahead of any user-supplied `--name-suffix`. The bullet
|
|
177
|
+
* separator prefix (`• `) is required because the server joins suffix segments with a
|
|
178
|
+
* plain space — this CLI carries the bullet so the final rendered name reads consistently
|
|
179
|
+
* with locally-built names from `DefinitionFieldGenerationService.buildName`.
|
|
180
|
+
*
|
|
181
|
+
* CLI-3064: Without the disambiguator, value-frequency and no-value-frequency variants of
|
|
182
|
+
* the same (object, method, time-segment) resolve to identical names on both client and
|
|
183
|
+
* server; the second invocation is silently dropped by the name-keyed dedup gate. Layering
|
|
184
|
+
* the disambiguator ahead of the user suffix preserves the user's `--name-suffix` semantics
|
|
185
|
+
* while disambiguating the variant.
|
|
186
|
+
*
|
|
187
|
+
* @param userSuffix - User-supplied `--name-suffix` value (optional)
|
|
188
|
+
* @param noValueFrequency - True when the request originates from `--no-value-frequency`
|
|
189
|
+
* @returns Composed suffix to send as `SmartCreateRequest.options.nameSuffix`, or undefined when neither applies
|
|
190
|
+
*/
|
|
191
|
+
static composeRestNameSuffix(userSuffix, noValueFrequency) {
|
|
192
|
+
const SEP = '• ';
|
|
193
|
+
const variant = noValueFrequency ? 'No Value Frequency' : undefined;
|
|
194
|
+
if (variant && userSuffix)
|
|
195
|
+
return `${SEP}${variant} ${SEP}${userSuffix}`;
|
|
196
|
+
if (variant)
|
|
197
|
+
return `${SEP}${variant}`;
|
|
198
|
+
if (userSuffix)
|
|
199
|
+
return `${SEP}${userSuffix}`;
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
static applyOutcomeFilter(objects, method, emptyResult, startTime) {
|
|
203
|
+
if (method !== 'outcome')
|
|
204
|
+
return objects;
|
|
205
|
+
const eligible = objects.filter((o) => DefinitionCreateOperation.getOutcomeField(o.name) !== undefined);
|
|
206
|
+
if (eligible.length === 0) {
|
|
207
|
+
return createFailureResult(emptyResult, CreateErrorCodes.NO_OBJECTS_FOUND, 'No objects with outcome fields found. Outcome definitions support Opportunity (Won vs Lost), Case (Closed vs Open), and Lead (Converted vs Unconverted) only.', { metadata: { duration: Date.now() - startTime } });
|
|
208
|
+
}
|
|
209
|
+
return eligible;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Invokes the onPreviewReady callback if provided and not in dry-run mode.
|
|
213
|
+
* Returns a cancellation result if the user declines, or undefined to proceed.
|
|
214
|
+
*/
|
|
215
|
+
static async invokePreviewCallback(options, createInputs, skippedInputs, totalCount, skippedCount, recordCounts, emptyResult, startTime) {
|
|
216
|
+
if (!options.onPreviewReady || options.dryRun)
|
|
217
|
+
return undefined;
|
|
218
|
+
try {
|
|
219
|
+
const proceed = await options.onPreviewReady({
|
|
220
|
+
toCreate: createInputs,
|
|
221
|
+
toSkip: skippedInputs,
|
|
222
|
+
total: totalCount,
|
|
223
|
+
recordCounts,
|
|
224
|
+
});
|
|
225
|
+
if (!proceed) {
|
|
226
|
+
return createSuccessResult({ ...emptyResult, cancelled: true, skipped: skippedCount, total: totalCount }, { message: 'Creation cancelled by user.', metadata: { duration: Date.now() - startTime } });
|
|
227
|
+
}
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
return createFailureResult(emptyResult, CreateErrorCodes.OPERATION_FAILED, `Confirmation prompt failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Maps a server-side SmartCreateDefinitionResult to an ObjectResult.
|
|
236
|
+
*/
|
|
237
|
+
static mapServerResult(sr) {
|
|
238
|
+
return {
|
|
239
|
+
objectName: sr.objectName,
|
|
240
|
+
objectLabel: sr.objectName,
|
|
241
|
+
status: sr.status === 'created'
|
|
242
|
+
? 'success'
|
|
243
|
+
: sr.status === 'skipped'
|
|
244
|
+
? 'skip'
|
|
245
|
+
: sr.status === 'preview'
|
|
246
|
+
? 'preview'
|
|
247
|
+
: 'fail',
|
|
248
|
+
definitionName: sr.definitionName,
|
|
249
|
+
definitionId: sr.definitionId,
|
|
250
|
+
definitionKey: sr.definitionKey,
|
|
251
|
+
fieldCount: sr.fieldCount,
|
|
252
|
+
type: sr.type,
|
|
253
|
+
category: sr.category,
|
|
254
|
+
timeCategory: sr.timeCategory,
|
|
255
|
+
segmentCategory: sr.segmentCategory,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/** Derives the definition type for a dry-run preview result from the requested method. */
|
|
259
|
+
static derivePreviewType(method) {
|
|
260
|
+
if (method === 'metadata')
|
|
261
|
+
return 'metadata';
|
|
262
|
+
if (method === 'historical')
|
|
263
|
+
return 'historical';
|
|
264
|
+
return 'comparative';
|
|
265
|
+
}
|
|
266
|
+
/** Derives the definition category for a dry-run preview result from the requested method. */
|
|
267
|
+
static derivePreviewCategory(method) {
|
|
268
|
+
if (method === 'metadata')
|
|
269
|
+
return 'Metadata';
|
|
270
|
+
if (method === 'recordtype')
|
|
271
|
+
return 'Record Types';
|
|
272
|
+
if (method === 'outcome')
|
|
273
|
+
return 'Comparative';
|
|
274
|
+
return 'Baseline';
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Normalizes a REST-path result for dry-run uniformity (CLI-1832).
|
|
278
|
+
*
|
|
279
|
+
* When options.dryRun is true and the server returned status='skipped' (because the
|
|
280
|
+
* definition already exists), the JSON result's per-item status is remapped to 'preview'
|
|
281
|
+
* so callers see uniform dry-run output across create and skip paths. This mirrors the
|
|
282
|
+
* local-path buildDryRunResult behavior (see :936-937). Progress callbacks still fire
|
|
283
|
+
* with status='skip' so human UX differentiates "already exists" from "would create".
|
|
284
|
+
*
|
|
285
|
+
* After normalization, type/category are back-filled from the method when undefined
|
|
286
|
+
* (ISV create-smart omits classification fields per CLI-1756). 'full' is excluded
|
|
287
|
+
* because it produces multiple definition types per object.
|
|
288
|
+
*/
|
|
289
|
+
static normalizeDryRunResult(r, sr, isDryRun, method) {
|
|
290
|
+
if (isDryRun && sr.status === 'skipped') {
|
|
291
|
+
// eslint-disable-next-line no-param-reassign -- normalizing result status in-place for uniform dry-run output (CLI-1832)
|
|
292
|
+
r.status = 'preview';
|
|
293
|
+
}
|
|
294
|
+
if (r.status === 'preview' && r.type === undefined && method !== 'full') {
|
|
295
|
+
// eslint-disable-next-line no-param-reassign -- back-filling classification in-place (CLI-1756: ISV omits these)
|
|
296
|
+
r.type = DefinitionCreateOperation.derivePreviewType(method);
|
|
297
|
+
// eslint-disable-next-line no-param-reassign -- back-filling classification in-place (CLI-1756)
|
|
298
|
+
r.category = DefinitionCreateOperation.derivePreviewCategory(method);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/** Fires the onObjectComplete progress callback for a single processed result. */
|
|
302
|
+
static notifyObjectComplete(r, sr, current, total, options) {
|
|
303
|
+
// CLI-1832: dry-run normalizes server 'skipped' → r.status='preview' for uniform JSON
|
|
304
|
+
// output. The progress callback still surfaces 'skip' from the original server status
|
|
305
|
+
// so human UX differentiates "already exists" from "would create". This mirrors
|
|
306
|
+
// buildDryRunResult's local-path behavior (see :936-937 and :945).
|
|
307
|
+
const callbackStatus = sr.status === 'skipped' ? 'skip' : r.status === 'preview' ? 'preview' : r.status;
|
|
308
|
+
const callbackMessage = sr.status === 'skipped'
|
|
309
|
+
? 'definition already exists'
|
|
310
|
+
: r.status === 'success'
|
|
311
|
+
? `created "${r.definitionName}"`
|
|
312
|
+
: r.status === 'skip'
|
|
313
|
+
? 'definition already exists'
|
|
314
|
+
: r.error ?? sr.errorMessage ?? 'unknown';
|
|
315
|
+
options.onObjectComplete?.({
|
|
316
|
+
objectName: r.objectName,
|
|
317
|
+
status: callbackStatus,
|
|
318
|
+
message: callbackMessage,
|
|
319
|
+
current,
|
|
320
|
+
total,
|
|
321
|
+
type: r.type,
|
|
322
|
+
definitionName: r.definitionName,
|
|
323
|
+
definitionKey: r.definitionKey,
|
|
324
|
+
recordTypeName: r.segmentCategory,
|
|
325
|
+
category: r.category,
|
|
326
|
+
timeCategory: r.timeCategory,
|
|
327
|
+
segmentCategory: r.segmentCategory,
|
|
328
|
+
fieldCount: r.fieldCount,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
// ── Public Instance Methods ──────────────────────────────────────────
|
|
332
|
+
/**
|
|
333
|
+
* Executes the definition create operation.
|
|
334
|
+
*
|
|
335
|
+
* @param options - Create operation options
|
|
336
|
+
* @returns ServiceResult containing creation statistics
|
|
337
|
+
*/
|
|
338
|
+
// eslint-disable-next-line complexity -- 7-step orchestration pipeline with error handling at each step
|
|
339
|
+
async execute(options) {
|
|
340
|
+
const startTime = Date.now();
|
|
341
|
+
const emptyResult = {
|
|
342
|
+
created: 0,
|
|
343
|
+
failed: 0,
|
|
344
|
+
skipped: 0,
|
|
345
|
+
total: 0,
|
|
346
|
+
failures: [],
|
|
347
|
+
results: [],
|
|
348
|
+
};
|
|
349
|
+
try {
|
|
350
|
+
this.logger?.log('Starting definition create operation');
|
|
351
|
+
const operationWarnings = [];
|
|
352
|
+
// Step 1: Resolve objects
|
|
353
|
+
const resolveResult = await this.resolveObjects(options, operationWarnings);
|
|
354
|
+
if (!resolveResult.success) {
|
|
355
|
+
return createFailureResult(emptyResult, resolveResult.errorCode, resolveResult.message, {
|
|
356
|
+
metadata: { duration: Date.now() - startTime },
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
const objectsBeforeLimit = this.applyMinRecordsThreshold(resolveResult.data, options, emptyResult, startTime);
|
|
360
|
+
if (!Array.isArray(objectsBeforeLimit))
|
|
361
|
+
return objectsBeforeLimit;
|
|
362
|
+
// Step 1b: Apply --limit to cap the number of objects processed
|
|
363
|
+
const { limited: objects, warning: objectLimitWarning } = this.applyObjectLimit(objectsBeforeLimit, options.limit);
|
|
364
|
+
if (objectLimitWarning) {
|
|
365
|
+
operationWarnings.push(objectLimitWarning);
|
|
366
|
+
}
|
|
367
|
+
// Step 2: Fetch record counts for resolved objects
|
|
368
|
+
const uniqueObjectNames = [...new Set(objects.map((o) => o.name))];
|
|
369
|
+
const countsResult = await this.filteringService.getRecordCounts(uniqueObjectNames);
|
|
370
|
+
const recordCounts = countsResult.success ? countsResult.data : new Map();
|
|
371
|
+
const method = options.method ?? 'metadata';
|
|
372
|
+
const year = options.year ?? new Date().getFullYear();
|
|
373
|
+
// Resolve year range: prefer explicit yearRange, fall back to year + usePrior
|
|
374
|
+
const yearRange = options.yearRange ?? {
|
|
375
|
+
entries: method === 'metadata' ? [] : [{ year, unbounded: options.usePrior ?? false }],
|
|
376
|
+
};
|
|
377
|
+
options.onProgress?.(`Checking existing definitions for ${objects.length} objects...`);
|
|
378
|
+
// Step 2.5: Build data availability grid (concurrent with Step 3)
|
|
379
|
+
let availabilityGrid;
|
|
380
|
+
if (this.dataAvailabilityService && yearRange.entries.length > 0) {
|
|
381
|
+
const gridResult = await this.dataAvailabilityService.buildGrid(uniqueObjectNames, yearRange);
|
|
382
|
+
if (gridResult.success) {
|
|
383
|
+
availabilityGrid = gridResult.data;
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
this.logger?.log(`Data availability grid failed: ${gridResult.message ?? 'unknown'}`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// REST API path: delegate to server when restClient is available.
|
|
390
|
+
// Fall back to the local path when:
|
|
391
|
+
// method='full' — server creates only 1 definition; local path composes all sub-methods
|
|
392
|
+
// lifetimePrimary=true — ISV Apex DefinitionFieldGenerationService has no lifetime-primary
|
|
393
|
+
// support (CLI-2944); local path pre-computes the lifetime filter
|
|
394
|
+
// JSON, name, timeCategory, and segmentCategory and persists them
|
|
395
|
+
// verbatim via create-definition. Remove this branch once the ISV
|
|
396
|
+
// Apex side mirrors the TS lifetime logic.
|
|
397
|
+
// timeCategory or segmentCategory override set — local path applies overrides verbatim through ctx builders (CLI-2957).
|
|
398
|
+
// CLI-3099: force local path for comparative + dateLiteralRange — the ISV create-smart
|
|
399
|
+
// endpoint ignores method=comparative for date literals and always builds Historical.
|
|
400
|
+
// The local path pre-computes SetA+SetB filterJson via buildComparativeDateLiteralFilterJson.
|
|
401
|
+
const useLocalPath = options.method === 'full' ||
|
|
402
|
+
options.lifetimePrimary === true ||
|
|
403
|
+
options.timeCategory !== undefined ||
|
|
404
|
+
options.segmentCategory !== undefined ||
|
|
405
|
+
(options.dateLiteralRange !== undefined && options.method === 'comparative');
|
|
406
|
+
if (this.restClient && !useLocalPath) {
|
|
407
|
+
return await this.executeCreationViaRest(objects, options, operationWarnings, startTime, availabilityGrid, recordCounts);
|
|
408
|
+
}
|
|
409
|
+
// Step 3: Check for existing definitions (local path — fallback when no REST client)
|
|
410
|
+
const existingDefsResult = await this.fetchAllExistingDefinitions();
|
|
411
|
+
if (!existingDefsResult.success) {
|
|
412
|
+
this.logger?.log('Failed to query existing definitions');
|
|
413
|
+
}
|
|
414
|
+
const existingDefinitions = existingDefsResult.success ? existingDefsResult.data : [];
|
|
415
|
+
const existingNames = new Set(existingDefinitions.map((def) => def.name));
|
|
416
|
+
// Step 4: Build candidate inputs
|
|
417
|
+
const candidateResult = await this.buildCandidateInputsForMethod(objects, method, year, yearRange, options, operationWarnings);
|
|
418
|
+
if (!candidateResult.success) {
|
|
419
|
+
return createFailureResult(emptyResult, candidateResult.errorCode, candidateResult.message, {
|
|
420
|
+
metadata: { duration: Date.now() - startTime },
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
const candidateInputs = candidateResult.data;
|
|
424
|
+
// Step 5: Deduplicate (partition into create vs skip)
|
|
425
|
+
const createInputsBeforeLimit = [];
|
|
426
|
+
const skippedInputs = [];
|
|
427
|
+
for (const input of candidateInputs) {
|
|
428
|
+
if (existingNames.has(input.name)) {
|
|
429
|
+
skippedInputs.push(input);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
createInputsBeforeLimit.push(input);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const skippedCount = skippedInputs.length;
|
|
436
|
+
if (createInputsBeforeLimit.length === 0) {
|
|
437
|
+
const totalDefs = candidateInputs.length;
|
|
438
|
+
if (totalDefs === 0) {
|
|
439
|
+
// No candidates generated (e.g., no record types found for --method recordtype)
|
|
440
|
+
return createFailureResult({ ...emptyResult, total: 0 }, CreateErrorCodes.NO_OBJECTS_FOUND, operationWarnings.length > 0
|
|
441
|
+
? `No candidate definitions were generated: ${operationWarnings.join('; ')}`
|
|
442
|
+
: 'No candidate definitions were generated. Check object filters, record types, or method selection.', { metadata: { duration: Date.now() - startTime } });
|
|
443
|
+
}
|
|
444
|
+
this.logger?.log(`All ${totalDefs} definitions already exist`);
|
|
445
|
+
return createFailureResult({ ...emptyResult, skipped: skippedCount, total: totalDefs }, CreateErrorCodes.ALL_OBJECTS_SKIPPED, `All ${totalDefs} definitions already exist. Use 'sf cuneiform definition purge' to remove them first, then re-create.`, { metadata: { duration: Date.now() - startTime } });
|
|
446
|
+
}
|
|
447
|
+
this.logger?.log(`${createInputsBeforeLimit.length} definitions to create, ${skippedCount} already exist`);
|
|
448
|
+
// Apply --limit safety cap
|
|
449
|
+
const { limited: createInputs, warning: limitWarning } = this.applyInputLimit(createInputsBeforeLimit, options.limit);
|
|
450
|
+
if (limitWarning) {
|
|
451
|
+
operationWarnings.push(limitWarning);
|
|
452
|
+
}
|
|
453
|
+
const totalForPreview = createInputs.length + skippedCount;
|
|
454
|
+
options.onProgress?.(`${totalForPreview} ${totalForPreview === 1 ? 'definition' : 'definitions'} to create`);
|
|
455
|
+
// Step 6: Preview callback (unless dry-run)
|
|
456
|
+
const cancelResult = await DefinitionCreateOperation.invokePreviewCallback(options, createInputs, skippedInputs, candidateInputs.length, skippedCount, recordCounts, emptyResult, startTime);
|
|
457
|
+
if (cancelResult)
|
|
458
|
+
return cancelResult;
|
|
459
|
+
// Step 7: Dry run or create
|
|
460
|
+
if (options.dryRun) {
|
|
461
|
+
return this.buildDryRunResult(createInputs, skippedInputs, candidateInputs.length, operationWarnings, options, startTime, availabilityGrid, recordCounts);
|
|
462
|
+
}
|
|
463
|
+
return await this.executeCreation(createInputs, skippedInputs, candidateInputs.length, operationWarnings, options, startTime, availabilityGrid, recordCounts);
|
|
464
|
+
}
|
|
465
|
+
catch (error) {
|
|
466
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
467
|
+
this.logger?.log(`Definition create operation failed: ${errorMessage}`);
|
|
468
|
+
return createFailureResult(emptyResult, CreateErrorCodes.OPERATION_FAILED, errorMessage, {
|
|
469
|
+
metadata: { duration: Date.now() - startTime },
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
// ── Private Instance Methods ─────────────────────────────────────────
|
|
474
|
+
/**
|
|
475
|
+
* Applies the --min-records threshold, returning the filtered list or an early failure result.
|
|
476
|
+
*/
|
|
477
|
+
applyMinRecordsThreshold(objects, options, emptyResult, startTime) {
|
|
478
|
+
if (!options.minRecords || options.minRecords <= 0)
|
|
479
|
+
return objects;
|
|
480
|
+
const filtered = this.applyMinRecordsFilter(objects, options.minRecords);
|
|
481
|
+
if (filtered.length === 0) {
|
|
482
|
+
return createFailureResult(emptyResult, CreateErrorCodes.NO_OBJECTS_FOUND, `No objects found with at least ${options.minRecords} records`, { metadata: { duration: Date.now() - startTime } });
|
|
483
|
+
}
|
|
484
|
+
return filtered;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Builds record-type candidate inputs by querying the RecordTypeService for each object.
|
|
488
|
+
*/
|
|
489
|
+
async buildRecordTypeCandidateInputs(objects, yearRange, options, warnings) {
|
|
490
|
+
if (!this.recordTypeService) {
|
|
491
|
+
return createFailureResult([], CreateErrorCodes.OPERATION_FAILED, 'RecordTypeService is required when method=recordtype');
|
|
492
|
+
}
|
|
493
|
+
const inputs = [];
|
|
494
|
+
const isSingleObject = objects.length === 1;
|
|
495
|
+
const rtStatus = options.recordTypeStatus ?? 'active';
|
|
496
|
+
for (const obj of objects) {
|
|
497
|
+
// eslint-disable-next-line no-await-in-loop -- Sequential per-object queries with per-object error handling
|
|
498
|
+
const rtResult = await this.recordTypeService.getRecordTypesByStatus(obj.name, rtStatus);
|
|
499
|
+
if (!rtResult.success) {
|
|
500
|
+
warnings.push(`Failed to query record types for ${obj.name}: ${rtResult.message}`);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
let recordTypes = rtResult.data;
|
|
504
|
+
if (recordTypes.length === 0) {
|
|
505
|
+
const statusLabel = rtStatus === 'all' ? '' : ` ${rtStatus}`;
|
|
506
|
+
warnings.push(`Object '${obj.name}' has no${statusLabel} record types \u2014 skipping.`);
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
// Apply --recordtype filter (case-insensitive)
|
|
510
|
+
if (options.recordType) {
|
|
511
|
+
const targetLower = options.recordType.toLowerCase();
|
|
512
|
+
recordTypes = recordTypes.filter((rt) => rt.name.toLowerCase() === targetLower);
|
|
513
|
+
if (recordTypes.length === 0) {
|
|
514
|
+
if (isSingleObject) {
|
|
515
|
+
const available = rtResult.data.map((rt) => rt.name).join(', ');
|
|
516
|
+
return createFailureResult([], CreateErrorCodes.NO_OBJECTS_FOUND, `Record type '${options.recordType}' not found on ${obj.name}. Active record types: ${available}`);
|
|
517
|
+
}
|
|
518
|
+
warnings.push(`Object '${obj.name}' does not have record type '${options.recordType}' \u2014 skipping.`);
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
for (const rt of recordTypes) {
|
|
523
|
+
inputs.push(...DefinitionFieldGenerationService.buildInputsForRecordType(obj, rt.name, yearRange, options));
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return createSuccessResult(inputs);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Builds full candidate inputs by composing metadata + historical + comparative + recordtype methods.
|
|
530
|
+
* Degrades gracefully to metadata + historical + comparative when RecordTypeService is absent.
|
|
531
|
+
*/
|
|
532
|
+
async buildFullCandidateInputs(objects, year, yearRange, options, warnings) {
|
|
533
|
+
// Phase 1: Build metadata + historical + comparative inputs
|
|
534
|
+
const allInputs = [
|
|
535
|
+
...DefinitionFieldGenerationService.buildCandidateInputs(objects, 'metadata', year, yearRange, options),
|
|
536
|
+
...DefinitionFieldGenerationService.buildCandidateInputs(objects, 'historical', year, yearRange, options),
|
|
537
|
+
...DefinitionFieldGenerationService.buildCandidateInputs(objects, 'comparative', year, yearRange, options),
|
|
538
|
+
];
|
|
539
|
+
// Phase 1b: Build business process outcome inputs (always available — no service dependency)
|
|
540
|
+
// yearRange applies when user explicitly provided --year/--from/--to (options.year is set).
|
|
541
|
+
// Without explicit year flags, outcome defaults to lifetime (no year scoping).
|
|
542
|
+
const outcomeYearRange = options.year !== undefined ? yearRange : undefined;
|
|
543
|
+
allInputs.push(...DefinitionFieldGenerationService.buildOutcomeCandidateInputs(objects, options, warnings, outcomeYearRange));
|
|
544
|
+
// Phase 2: Build recordtype inputs (soft degradation if service absent)
|
|
545
|
+
if (!this.recordTypeService) {
|
|
546
|
+
warnings.push('RecordTypeService not available — full method degrading to metadata + historical + comparative + outcome only.');
|
|
547
|
+
return createSuccessResult(allInputs);
|
|
548
|
+
}
|
|
549
|
+
const rtResult = await this.buildRecordTypeCandidateInputs(objects, yearRange, options, warnings);
|
|
550
|
+
const rtInputs = rtResult.success ? rtResult.data : [];
|
|
551
|
+
if (!rtResult.success) {
|
|
552
|
+
warnings.push(`Record type inputs failed: ${rtResult.message ?? 'unknown error'} — using metadata + historical + comparative only.`);
|
|
553
|
+
}
|
|
554
|
+
// Phase 3: Merge and deduplicate by name (defensive — names are structurally distinct)
|
|
555
|
+
const seen = new Set();
|
|
556
|
+
const merged = [];
|
|
557
|
+
for (const input of [...allInputs, ...rtInputs]) {
|
|
558
|
+
if (!seen.has(input.name)) {
|
|
559
|
+
seen.add(input.name);
|
|
560
|
+
merged.push(input);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return createSuccessResult(merged);
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Builds candidate inputs for any method, delegating to the appropriate builder.
|
|
567
|
+
*/
|
|
568
|
+
async buildCandidateInputsForMethod(objects, method, year, yearRange, options, warnings) {
|
|
569
|
+
if (method === 'recordtype') {
|
|
570
|
+
return this.buildRecordTypeCandidateInputs(objects, yearRange, options, warnings);
|
|
571
|
+
}
|
|
572
|
+
if (method === 'outcome') {
|
|
573
|
+
// Only apply yearRange when user explicitly provided --year/--from/--to
|
|
574
|
+
const outcomeYR = options.year !== undefined ? yearRange : undefined;
|
|
575
|
+
return createSuccessResult(DefinitionFieldGenerationService.buildOutcomeCandidateInputs(objects, options, warnings, outcomeYR));
|
|
576
|
+
}
|
|
577
|
+
if (method === 'full') {
|
|
578
|
+
return this.buildFullCandidateInputs(objects, year, yearRange, options, warnings);
|
|
579
|
+
}
|
|
580
|
+
return createSuccessResult(DefinitionFieldGenerationService.buildCandidateInputs(objects, method, year, yearRange, options));
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Builds a dry run result without creating any definitions.
|
|
584
|
+
*/
|
|
585
|
+
buildDryRunResult(createInputs, skippedInputs, totalCount, warnings, options, startTime, availabilityGrid, recordCounts) {
|
|
586
|
+
// Build preview results from the inputs (fieldCount unavailable in dry runs)
|
|
587
|
+
const results = [];
|
|
588
|
+
for (const input of createInputs) {
|
|
589
|
+
results.push({
|
|
590
|
+
objectName: input.objectName,
|
|
591
|
+
objectLabel: input.objectLabel,
|
|
592
|
+
status: 'preview',
|
|
593
|
+
definitionName: input.name,
|
|
594
|
+
type: input.method,
|
|
595
|
+
category: input.category,
|
|
596
|
+
timeCategory: DefinitionCreateOperation.resolveTimeCategory(input),
|
|
597
|
+
segmentCategory: DefinitionCreateOperation.resolveSegmentCategory(input),
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
for (const input of skippedInputs) {
|
|
601
|
+
results.push({
|
|
602
|
+
objectName: input.objectName,
|
|
603
|
+
objectLabel: input.objectLabel,
|
|
604
|
+
status: 'preview',
|
|
605
|
+
definitionName: input.name,
|
|
606
|
+
type: DefinitionCreateOperation.derivePreviewType(options.method ?? 'metadata'),
|
|
607
|
+
category: input.category ?? DefinitionCreateOperation.derivePreviewCategory(options.method ?? 'metadata'),
|
|
608
|
+
timeCategory: DefinitionCreateOperation.resolveTimeCategory(input),
|
|
609
|
+
segmentCategory: DefinitionCreateOperation.resolveSegmentCategory(input),
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
// Fire callbacks — createInputs get 'preview', skippedInputs get 'skip' (progress display only;
|
|
613
|
+
// JSON result uses 'preview' for both so callers see a uniform dry-run output).
|
|
614
|
+
if (options.onObjectComplete) {
|
|
615
|
+
const createCount = createInputs.length;
|
|
616
|
+
for (let i = 0; i < results.length; i++) {
|
|
617
|
+
const r = results[i];
|
|
618
|
+
const isSkipped = i >= createCount;
|
|
619
|
+
options.onObjectComplete({
|
|
620
|
+
objectName: r.objectName,
|
|
621
|
+
status: isSkipped ? 'skip' : 'preview',
|
|
622
|
+
message: isSkipped ? 'definition already exists' : `would create "${r.definitionName}"`,
|
|
623
|
+
current: i + 1,
|
|
624
|
+
total: results.length,
|
|
625
|
+
type: r.type,
|
|
626
|
+
definitionName: r.definitionName,
|
|
627
|
+
definitionKey: r.definitionKey,
|
|
628
|
+
recordTypeName: r.segmentCategory,
|
|
629
|
+
category: r.category,
|
|
630
|
+
timeCategory: r.timeCategory,
|
|
631
|
+
segmentCategory: r.segmentCategory,
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
const dryRunResult = {
|
|
636
|
+
created: createInputs.length,
|
|
637
|
+
failed: 0,
|
|
638
|
+
skipped: skippedInputs.length,
|
|
639
|
+
total: totalCount,
|
|
640
|
+
dryRun: true,
|
|
641
|
+
failures: [],
|
|
642
|
+
results,
|
|
643
|
+
availabilityGrid,
|
|
644
|
+
recordCounts,
|
|
645
|
+
};
|
|
646
|
+
this.logger?.log(`Dry run: would create ${createInputs.length} definitions`);
|
|
647
|
+
return createSuccessResult(dryRunResult, {
|
|
648
|
+
message: `Dry run: would create ${createInputs.length} profiling definitions`,
|
|
649
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
650
|
+
metadata: { duration: Date.now() - startTime },
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Executes sequential creation of definitions with per-item progress callbacks.
|
|
655
|
+
*/
|
|
656
|
+
async executeCreation(createInputs, skippedInputs, totalCount, operationWarnings, options, startTime, availabilityGrid, recordCounts) {
|
|
657
|
+
const results = [];
|
|
658
|
+
const failures = [];
|
|
659
|
+
const totalItems = createInputs.length + skippedInputs.length;
|
|
660
|
+
let itemIndex = 0;
|
|
661
|
+
let createdCount = 0;
|
|
662
|
+
let failedCount = 0;
|
|
663
|
+
// Fire skipped items first
|
|
664
|
+
for (const input of skippedInputs) {
|
|
665
|
+
itemIndex++;
|
|
666
|
+
const r = {
|
|
667
|
+
objectName: input.objectName,
|
|
668
|
+
objectLabel: input.objectLabel,
|
|
669
|
+
status: 'skip',
|
|
670
|
+
definitionName: input.name,
|
|
671
|
+
type: input.method,
|
|
672
|
+
category: input.category,
|
|
673
|
+
timeCategory: DefinitionCreateOperation.resolveTimeCategory(input),
|
|
674
|
+
segmentCategory: DefinitionCreateOperation.resolveSegmentCategory(input),
|
|
675
|
+
};
|
|
676
|
+
results.push(r);
|
|
677
|
+
options.onObjectComplete?.({
|
|
678
|
+
objectName: r.objectName,
|
|
679
|
+
status: 'skip',
|
|
680
|
+
message: 'definition already exists',
|
|
681
|
+
current: itemIndex,
|
|
682
|
+
total: totalItems,
|
|
683
|
+
type: r.type,
|
|
684
|
+
definitionName: r.definitionName,
|
|
685
|
+
recordTypeName: r.segmentCategory,
|
|
686
|
+
category: r.category,
|
|
687
|
+
timeCategory: r.timeCategory,
|
|
688
|
+
segmentCategory: r.segmentCategory,
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
// Create definitions one at a time for real-time progress
|
|
692
|
+
for (const input of createInputs) {
|
|
693
|
+
itemIndex++;
|
|
694
|
+
// eslint-disable-next-line no-await-in-loop -- Sequential for real-time progress feedback
|
|
695
|
+
const createResult = await this.definitionService.createDefinition(input);
|
|
696
|
+
if (createResult.success && createResult.data) {
|
|
697
|
+
const def = createResult.data;
|
|
698
|
+
const fieldCount = createResult.metadata?.fieldCount ?? undefined;
|
|
699
|
+
createdCount++;
|
|
700
|
+
const r = {
|
|
701
|
+
objectName: input.objectName,
|
|
702
|
+
objectLabel: def.objectLabel ?? input.objectLabel,
|
|
703
|
+
status: 'success',
|
|
704
|
+
definitionName: def.name,
|
|
705
|
+
definitionId: def.id,
|
|
706
|
+
definitionKey: def.key,
|
|
707
|
+
type: input.method,
|
|
708
|
+
fieldCount,
|
|
709
|
+
category: def.category ?? input.category,
|
|
710
|
+
timeCategory: def.timeCategory ?? DefinitionCreateOperation.resolveTimeCategory(input),
|
|
711
|
+
segmentCategory: def.segmentCategory ?? DefinitionCreateOperation.resolveSegmentCategory(input),
|
|
712
|
+
};
|
|
713
|
+
results.push(r);
|
|
714
|
+
options.onObjectComplete?.({
|
|
715
|
+
objectName: r.objectName,
|
|
716
|
+
status: 'success',
|
|
717
|
+
message: DefinitionCreateOperation.formatObjectMessage(r),
|
|
718
|
+
current: itemIndex,
|
|
719
|
+
total: totalItems,
|
|
720
|
+
type: r.type,
|
|
721
|
+
definitionName: r.definitionName,
|
|
722
|
+
definitionKey: r.definitionKey,
|
|
723
|
+
recordTypeName: r.segmentCategory,
|
|
724
|
+
category: r.category,
|
|
725
|
+
timeCategory: r.timeCategory,
|
|
726
|
+
segmentCategory: r.segmentCategory,
|
|
727
|
+
fieldCount: r.fieldCount,
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
failedCount++;
|
|
732
|
+
const errorMsg = createResult.message ?? 'Unknown error';
|
|
733
|
+
failures.push({
|
|
734
|
+
objectName: input.objectName,
|
|
735
|
+
error: errorMsg,
|
|
736
|
+
errorCode: createResult.errorCode ?? CreateErrorCodes.OPERATION_FAILED,
|
|
737
|
+
});
|
|
738
|
+
const r = {
|
|
739
|
+
objectName: input.objectName,
|
|
740
|
+
objectLabel: input.objectLabel,
|
|
741
|
+
status: 'fail',
|
|
742
|
+
definitionName: input.name,
|
|
743
|
+
type: input.method,
|
|
744
|
+
error: errorMsg,
|
|
745
|
+
category: input.category,
|
|
746
|
+
timeCategory: DefinitionCreateOperation.resolveTimeCategory(input),
|
|
747
|
+
segmentCategory: DefinitionCreateOperation.resolveSegmentCategory(input),
|
|
748
|
+
};
|
|
749
|
+
results.push(r);
|
|
750
|
+
options.onObjectComplete?.({
|
|
751
|
+
objectName: r.objectName,
|
|
752
|
+
status: 'fail',
|
|
753
|
+
message: errorMsg,
|
|
754
|
+
current: itemIndex,
|
|
755
|
+
total: totalItems,
|
|
756
|
+
type: r.type,
|
|
757
|
+
definitionName: r.definitionName,
|
|
758
|
+
recordTypeName: r.segmentCategory,
|
|
759
|
+
category: r.category,
|
|
760
|
+
timeCategory: r.timeCategory,
|
|
761
|
+
segmentCategory: r.segmentCategory,
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
const result = {
|
|
766
|
+
created: createdCount,
|
|
767
|
+
failed: failedCount,
|
|
768
|
+
skipped: skippedInputs.length,
|
|
769
|
+
total: totalCount,
|
|
770
|
+
failures,
|
|
771
|
+
results,
|
|
772
|
+
availabilityGrid,
|
|
773
|
+
recordCounts,
|
|
774
|
+
};
|
|
775
|
+
const duration = Date.now() - startTime;
|
|
776
|
+
this.logger?.log(`Created ${createdCount} definitions, ${failedCount} failed, ${skippedInputs.length} skipped`);
|
|
777
|
+
options.onProgress?.(`Complete: ${createdCount} created, ${failedCount} failed, ${skippedInputs.length} skipped`);
|
|
778
|
+
return createSuccessResult(result, {
|
|
779
|
+
message: `Created ${createdCount} profiling definitions`,
|
|
780
|
+
warnings: operationWarnings.length > 0 ? operationWarnings : undefined,
|
|
781
|
+
metadata: { duration },
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Executes definition creation via the ISV REST API (create-smart endpoint).
|
|
786
|
+
* Server handles naming, categorization, deduplication, and creation.
|
|
787
|
+
* The CLI only provides objects, method, and options — no local business logic.
|
|
788
|
+
*/
|
|
789
|
+
async executeCreationViaRest(objects, options, operationWarnings, startTime, availabilityGrid, recordCounts) {
|
|
790
|
+
const emptyResult = { created: 0, failed: 0, skipped: 0, total: 0, failures: [], results: [] };
|
|
791
|
+
this.logger?.log('Delegating definition creation to ISV REST API (create-smart)');
|
|
792
|
+
options.onProgress?.('Creating definitions via server-side pipeline...');
|
|
793
|
+
const method = options.method ?? 'metadata';
|
|
794
|
+
// Apply --limit safety cap before sending to ISV (ISV sees only the capped list).
|
|
795
|
+
const { limited: limitedObjects, warning: limitWarning } = this.applyObjectLimit(objects, options.limit);
|
|
796
|
+
if (limitWarning)
|
|
797
|
+
operationWarnings.push(limitWarning);
|
|
798
|
+
// Outcome pre-filter: only Opportunity, Case, Lead have outcome fields (CLI-1792).
|
|
799
|
+
const objectsToCreate = DefinitionCreateOperation.applyOutcomeFilter(limitedObjects, method, emptyResult, startTime);
|
|
800
|
+
if (!Array.isArray(objectsToCreate))
|
|
801
|
+
return objectsToCreate;
|
|
802
|
+
const restResult = await this.restClient.createSmart({
|
|
803
|
+
objects: objectsToCreate.map((o) => ({ name: o.name, label: o.label })),
|
|
804
|
+
method,
|
|
805
|
+
options: {
|
|
806
|
+
category: options.category,
|
|
807
|
+
timeCategory: options.timeCategory,
|
|
808
|
+
segmentCategory: options.segmentCategory,
|
|
809
|
+
year: options.year,
|
|
810
|
+
usePrior: options.usePrior,
|
|
811
|
+
noValueFrequency: options.noValueFrequency,
|
|
812
|
+
namePrefix: options.namePrefix,
|
|
813
|
+
// Prepend bullet separator — ISV joins suffix with a plain space, so we carry the bullet.
|
|
814
|
+
// CLI-3064: When --no-value-frequency is set, the resolved name on both client and server
|
|
815
|
+
// must include a "No Value Frequency" disambiguator \u2014 otherwise the value-frequency and
|
|
816
|
+
// no-value-frequency variants of the same (object, method, time-segment) collide on the
|
|
817
|
+
// name-keyed dedup gate and the second is silently skipped. The disambiguator is layered
|
|
818
|
+
// ahead of any user-supplied --name-suffix so user suffixes compose cleanly on top.
|
|
819
|
+
nameSuffix: DefinitionCreateOperation.composeRestNameSuffix(options.nameSuffix, options.noValueFrequency),
|
|
820
|
+
origin: options.origin,
|
|
821
|
+
recordType: options.recordType,
|
|
822
|
+
description: options.description,
|
|
823
|
+
dryRun: options.dryRun,
|
|
824
|
+
dateLiteralRange: options.dateLiteralRange,
|
|
825
|
+
yearEntries: options.yearRange?.entries.length
|
|
826
|
+
? options.yearRange.entries.map(({ year, unbounded }) => ({ year, unbounded }))
|
|
827
|
+
: undefined,
|
|
828
|
+
},
|
|
829
|
+
});
|
|
830
|
+
if (!restResult.success) {
|
|
831
|
+
return createFailureResult(emptyResult, CreateErrorCodes.OPERATION_FAILED, restResult.message ?? 'REST API call failed', {
|
|
832
|
+
metadata: { duration: Date.now() - startTime },
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
const serverResponse = restResult.data;
|
|
836
|
+
const failures = [];
|
|
837
|
+
let createdCount = 0;
|
|
838
|
+
let failedCount = 0;
|
|
839
|
+
let skippedCount = 0;
|
|
840
|
+
// Map all server results synchronously, then enrich classification in parallel (CLI-1756).
|
|
841
|
+
const serverResults = serverResponse.results ?? [];
|
|
842
|
+
const resultPairs = serverResults.map((sr) => ({ sr, r: DefinitionCreateOperation.mapServerResult(sr) }));
|
|
843
|
+
// CLI-1756: ISV create-smart no longer returns classification fields (type, category,
|
|
844
|
+
// timeCategory, segmentCategory). Enrich all created definitions in parallel via GET
|
|
845
|
+
// so downstream consumers (JSON output, NUT assertions) see full classification metadata.
|
|
846
|
+
await this.enrichClassificationFields(resultPairs);
|
|
847
|
+
const results = [];
|
|
848
|
+
for (const { sr, r } of resultPairs) {
|
|
849
|
+
DefinitionCreateOperation.normalizeDryRunResult(r, sr, options.dryRun === true, method);
|
|
850
|
+
results.push(r);
|
|
851
|
+
if (sr.status === 'created' || sr.status === 'preview') {
|
|
852
|
+
createdCount++;
|
|
853
|
+
}
|
|
854
|
+
else if (sr.status === 'skipped') {
|
|
855
|
+
skippedCount++;
|
|
856
|
+
}
|
|
857
|
+
else if (sr.status === 'failed') {
|
|
858
|
+
failedCount++;
|
|
859
|
+
failures.push({
|
|
860
|
+
objectName: sr.objectName,
|
|
861
|
+
error: sr.errorMessage ?? 'Unknown error',
|
|
862
|
+
errorCode: CreateErrorCodes.OPERATION_FAILED,
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
DefinitionCreateOperation.notifyObjectComplete(r, sr, results.length, serverResults.length, options);
|
|
866
|
+
}
|
|
867
|
+
const createResult = {
|
|
868
|
+
created: createdCount,
|
|
869
|
+
failed: failedCount,
|
|
870
|
+
skipped: skippedCount,
|
|
871
|
+
total: serverResults.length,
|
|
872
|
+
dryRun: options.dryRun,
|
|
873
|
+
failures,
|
|
874
|
+
results,
|
|
875
|
+
availabilityGrid,
|
|
876
|
+
recordCounts,
|
|
877
|
+
};
|
|
878
|
+
return createSuccessResult(createResult, {
|
|
879
|
+
message: options.dryRun
|
|
880
|
+
? `Preview: ${results.length} definitions`
|
|
881
|
+
: `Created ${createdCount} profiling definitions`,
|
|
882
|
+
warnings: operationWarnings.length > 0 ? operationWarnings : undefined,
|
|
883
|
+
metadata: { duration: Date.now() - startTime },
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Enriches classification fields (type, category, timeCategory, segmentCategory) on created
|
|
888
|
+
* results in parallel. CLI-1756: ISV create-smart no longer returns these fields in its response.
|
|
889
|
+
*/
|
|
890
|
+
async enrichClassificationFields(pairs) {
|
|
891
|
+
await Promise.all(pairs
|
|
892
|
+
.filter(({ sr, r }) => sr.status === 'created' && sr.definitionId && r.type === undefined)
|
|
893
|
+
.map(async ({ sr, r }) => {
|
|
894
|
+
const enrichResult = await this.definitionService.getDefinitionById(sr.definitionId);
|
|
895
|
+
if (enrichResult.success && enrichResult.data) {
|
|
896
|
+
const def = enrichResult.data;
|
|
897
|
+
// eslint-disable-next-line no-param-reassign -- enriching response object in-place (CLI-1756: ISV omits classification in create response)
|
|
898
|
+
r.type = def.type;
|
|
899
|
+
// eslint-disable-next-line no-param-reassign -- enriching response object in-place (CLI-1756)
|
|
900
|
+
r.category = def.category;
|
|
901
|
+
// eslint-disable-next-line no-param-reassign -- enriching response object in-place (CLI-1756)
|
|
902
|
+
r.timeCategory = def.timeCategory;
|
|
903
|
+
// eslint-disable-next-line no-param-reassign -- enriching response object in-place (CLI-1756)
|
|
904
|
+
r.segmentCategory = def.segmentCategory;
|
|
905
|
+
}
|
|
906
|
+
else {
|
|
907
|
+
this.logger?.log(`CLI-1756: Failed to enrich classification for ${sr.objectName}: ${enrichResult.message ?? 'unknown'}`);
|
|
908
|
+
}
|
|
909
|
+
}));
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Resolves objects by explicit names, profiled set, or filtering criteria.
|
|
913
|
+
*/
|
|
914
|
+
async resolveObjects(options, warnings) {
|
|
915
|
+
if (options.profiled) {
|
|
916
|
+
return this.resolveProfiledObjects(options, warnings);
|
|
917
|
+
}
|
|
918
|
+
if (options.objects && options.objects.length > 0) {
|
|
919
|
+
return this.resolveExplicitObjects(options.objects, warnings, options.onProgress);
|
|
920
|
+
}
|
|
921
|
+
return this.resolveFilteredObjects(options);
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Resolves objects that have successful metadata profiling results.
|
|
925
|
+
*/
|
|
926
|
+
async resolveProfiledObjects(options, warnings) {
|
|
927
|
+
options.onProgress?.('Querying profiled objects...');
|
|
928
|
+
this.logger?.log('Querying profiled objects from ProfilingSummaryService');
|
|
929
|
+
if (!this.profilingSummaryService) {
|
|
930
|
+
return createFailureResult([], CreateErrorCodes.OPERATION_FAILED, 'ProfilingSummaryService is required when profiled=true');
|
|
931
|
+
}
|
|
932
|
+
const profiledResult = await this.profilingSummaryService.queryProfiledObjects();
|
|
933
|
+
if (!profiledResult.success) {
|
|
934
|
+
return createFailureResult([], CreateErrorCodes.FILTER_FAILED, profiledResult.message);
|
|
935
|
+
}
|
|
936
|
+
let profiledNames = profiledResult.data;
|
|
937
|
+
if (profiledNames.length === 0) {
|
|
938
|
+
return createFailureResult([], CreateErrorCodes.NO_PROFILED_OBJECTS, 'No objects have been profiled yet. Run profiling with --method metadata first.');
|
|
939
|
+
}
|
|
940
|
+
this.logger?.log(`Found ${profiledNames.length} profiled objects`);
|
|
941
|
+
if (options.objects && options.objects.length > 0) {
|
|
942
|
+
const profiledSet = new Set(profiledNames.map((n) => n.toLowerCase()));
|
|
943
|
+
const intersected = [];
|
|
944
|
+
for (const obj of options.objects) {
|
|
945
|
+
if (profiledSet.has(obj.toLowerCase())) {
|
|
946
|
+
intersected.push(obj);
|
|
947
|
+
}
|
|
948
|
+
else {
|
|
949
|
+
warnings.push(`Object '${obj}' is not in the profiled set and will be skipped.`);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (intersected.length === 0) {
|
|
953
|
+
return createFailureResult([], CreateErrorCodes.NO_PROFILED_OBJECTS, 'None of the specified objects have been profiled. Run profiling with --method metadata first.');
|
|
954
|
+
}
|
|
955
|
+
profiledNames = intersected;
|
|
956
|
+
}
|
|
957
|
+
options.onProgress?.(`Resolving ${profiledNames.length} profiled objects...`);
|
|
958
|
+
const resolveResult = await this.filteringService.getObjectsByName(profiledNames);
|
|
959
|
+
if (!resolveResult.success) {
|
|
960
|
+
return createFailureResult([], CreateErrorCodes.FILTER_FAILED, resolveResult.message);
|
|
961
|
+
}
|
|
962
|
+
if (resolveResult.warnings && resolveResult.warnings.length > 0) {
|
|
963
|
+
warnings.push(...resolveResult.warnings);
|
|
964
|
+
}
|
|
965
|
+
if (resolveResult.data.length === 0) {
|
|
966
|
+
return createFailureResult([], CreateErrorCodes.OBJECTS_NOT_FOUND, 'None of the profiled objects exist in the org');
|
|
967
|
+
}
|
|
968
|
+
let filtered = resolveResult.data;
|
|
969
|
+
if (options.filter && options.filter !== 'all') {
|
|
970
|
+
filtered = filtered.filter((obj) => (options.filter === 'custom' ? obj.isCustom : !obj.isCustom));
|
|
971
|
+
}
|
|
972
|
+
if (options.namespace) {
|
|
973
|
+
const ns = options.namespace.toLowerCase();
|
|
974
|
+
filtered = filtered.filter((obj) => obj.namespace?.toLowerCase() === ns);
|
|
975
|
+
}
|
|
976
|
+
if (options.pattern) {
|
|
977
|
+
const pattern = options.pattern;
|
|
978
|
+
if (pattern.includes('*')) {
|
|
979
|
+
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$', 'i');
|
|
980
|
+
filtered = filtered.filter((obj) => regex.test(obj.name));
|
|
981
|
+
}
|
|
982
|
+
else {
|
|
983
|
+
const lower = pattern.toLowerCase();
|
|
984
|
+
filtered = filtered.filter((obj) => obj.name.toLowerCase().includes(lower));
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
if (filtered.length === 0) {
|
|
988
|
+
return createFailureResult([], CreateErrorCodes.NO_OBJECTS_FOUND, 'No profiled objects match the specified filters');
|
|
989
|
+
}
|
|
990
|
+
this.logger?.log(`Resolved ${filtered.length} profiled objects after filtering`);
|
|
991
|
+
return createSuccessResult(filtered);
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Resolves objects by explicit API names.
|
|
995
|
+
*/
|
|
996
|
+
async resolveExplicitObjects(objectNames, warnings, onProgress) {
|
|
997
|
+
onProgress?.('Resolving specified objects...');
|
|
998
|
+
this.logger?.log(`Resolving ${objectNames.length} explicitly specified objects`);
|
|
999
|
+
const resolveResult = await this.filteringService.getObjectsByName(objectNames);
|
|
1000
|
+
if (!resolveResult.success) {
|
|
1001
|
+
this.logger?.log(`Object resolution failed: ${resolveResult.message}`);
|
|
1002
|
+
return createFailureResult([], CreateErrorCodes.FILTER_FAILED, resolveResult.message);
|
|
1003
|
+
}
|
|
1004
|
+
if (resolveResult.warnings && resolveResult.warnings.length > 0) {
|
|
1005
|
+
// Surface "not found" warnings immediately via progress callback
|
|
1006
|
+
for (const w of resolveResult.warnings) {
|
|
1007
|
+
onProgress?.(w);
|
|
1008
|
+
}
|
|
1009
|
+
warnings.push(...resolveResult.warnings);
|
|
1010
|
+
}
|
|
1011
|
+
if (resolveResult.data.length === 0) {
|
|
1012
|
+
const notFoundNames = objectNames.join(', ');
|
|
1013
|
+
this.logger?.log(`None of the specified objects exist in the org: ${notFoundNames}`);
|
|
1014
|
+
return createFailureResult([], CreateErrorCodes.OBJECTS_NOT_FOUND, `None of the specified objects exist in the org: ${notFoundNames}`);
|
|
1015
|
+
}
|
|
1016
|
+
this.logger?.log(`Resolved ${resolveResult.data.length} of ${objectNames.length} specified objects`);
|
|
1017
|
+
return createSuccessResult(resolveResult.data);
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Resolves objects by filtering criteria.
|
|
1021
|
+
*/
|
|
1022
|
+
async resolveFilteredObjects(options) {
|
|
1023
|
+
options.onProgress?.('Filtering objects...');
|
|
1024
|
+
const filterOptions = {
|
|
1025
|
+
type: options.filter,
|
|
1026
|
+
namespace: options.namespace,
|
|
1027
|
+
classification: options.classification,
|
|
1028
|
+
withRecords: options.minRecords && options.minRecords > 0 ? true : options.withRecords,
|
|
1029
|
+
withoutRecords: options.withoutRecords,
|
|
1030
|
+
hasRecordTypes: options.withRecordTypes,
|
|
1031
|
+
// CLI-3085: __mdt and other non-layoutable system objects (history/share/feed/big/platform-event)
|
|
1032
|
+
// are never valid profiling targets — opt in to the in-memory layoutable + keyPrefix predicate
|
|
1033
|
+
// unconditionally so the create flow stays tight regardless of classification path behavior.
|
|
1034
|
+
excludeSystemObjects: true,
|
|
1035
|
+
};
|
|
1036
|
+
if (options.pattern) {
|
|
1037
|
+
filterOptions.nameFilter = {
|
|
1038
|
+
value: options.pattern,
|
|
1039
|
+
operator: options.pattern.includes('*') ? 'wildcard' : 'contains',
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
const filterResult = await this.filteringService.filter(filterOptions);
|
|
1043
|
+
if (!filterResult.success) {
|
|
1044
|
+
this.logger?.log(`Object filtering failed: ${filterResult.message}`);
|
|
1045
|
+
return createFailureResult([], CreateErrorCodes.FILTER_FAILED, filterResult.message);
|
|
1046
|
+
}
|
|
1047
|
+
if (filterResult.data.length === 0) {
|
|
1048
|
+
this.logger?.log('No objects found matching the specified filters');
|
|
1049
|
+
return createFailureResult([], CreateErrorCodes.NO_OBJECTS_FOUND, 'No objects found matching the specified filters');
|
|
1050
|
+
}
|
|
1051
|
+
this.logger?.log(`Found ${filterResult.data.length} objects matching filters`);
|
|
1052
|
+
return createSuccessResult(filterResult.data);
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Filters objects by minimum record count threshold.
|
|
1056
|
+
*/
|
|
1057
|
+
applyMinRecordsFilter(objects, minRecords) {
|
|
1058
|
+
const filtered = objects.filter((obj) => (obj.recordCount ?? 0) >= minRecords);
|
|
1059
|
+
this.logger?.log(`After min-records filter (>=${minRecords}): ${filtered.length} of ${objects.length} objects remain`);
|
|
1060
|
+
return filtered;
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Applies a safety cap to the number of definition inputs to process.
|
|
1064
|
+
*/
|
|
1065
|
+
applyInputLimit(inputs, limit) {
|
|
1066
|
+
if (!limit || limit <= 0 || inputs.length <= limit) {
|
|
1067
|
+
return { limited: inputs };
|
|
1068
|
+
}
|
|
1069
|
+
this.logger?.log(`Applied limit: ${limit} of ${inputs.length} definitions`);
|
|
1070
|
+
return {
|
|
1071
|
+
limited: inputs.slice(0, limit),
|
|
1072
|
+
warning: `Results limited to ${limit} definitions (${inputs.length} matched). Use --limit to increase.`,
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Applies a safety cap to the number of SObjects sent to the ISV REST API.
|
|
1077
|
+
* Mirrors applyInputLimit for the REST path where objects are capped before the ISV call.
|
|
1078
|
+
*/
|
|
1079
|
+
applyObjectLimit(objects, limit) {
|
|
1080
|
+
if (!limit || limit <= 0 || objects.length <= limit) {
|
|
1081
|
+
return { limited: objects };
|
|
1082
|
+
}
|
|
1083
|
+
this.logger?.log(`Applied object limit: ${limit} of ${objects.length} objects`);
|
|
1084
|
+
return {
|
|
1085
|
+
limited: objects.slice(0, limit),
|
|
1086
|
+
warning: `Results limited to ${limit} definitions (${objects.length} matched). Use --limit to increase.`,
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Fetches all existing profiling definitions using pagination.
|
|
1091
|
+
*/
|
|
1092
|
+
async fetchAllExistingDefinitions() {
|
|
1093
|
+
const allDefinitions = [];
|
|
1094
|
+
let offset = 0;
|
|
1095
|
+
const pageSize = MAX_PAGINATION_LIMIT;
|
|
1096
|
+
// eslint-disable-next-line no-constant-condition -- Pagination loop exits on short page or failure
|
|
1097
|
+
while (true) {
|
|
1098
|
+
// eslint-disable-next-line no-await-in-loop -- Sequential pagination: each page depends on knowing if more exist
|
|
1099
|
+
const pageResult = await this.definitionService.getDefinitions({ limit: pageSize, offset });
|
|
1100
|
+
if (!pageResult.success) {
|
|
1101
|
+
if (allDefinitions.length > 0) {
|
|
1102
|
+
this.logger?.log(`Pagination failed at offset ${offset}, using ${allDefinitions.length} definitions fetched so far`);
|
|
1103
|
+
return createSuccessResult(allDefinitions, {
|
|
1104
|
+
warnings: [`Pagination incomplete: failed at offset ${offset}. Deduplication may be partial.`],
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
return pageResult;
|
|
1108
|
+
}
|
|
1109
|
+
allDefinitions.push(...pageResult.data);
|
|
1110
|
+
if (pageResult.data.length < pageSize) {
|
|
1111
|
+
break;
|
|
1112
|
+
}
|
|
1113
|
+
offset += pageSize;
|
|
1114
|
+
}
|
|
1115
|
+
this.logger?.log(`Fetched ${allDefinitions.length} total existing definitions across pagination`);
|
|
1116
|
+
return createSuccessResult(allDefinitions, {
|
|
1117
|
+
message: `Found ${allDefinitions.length} existing definitions`,
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
//# sourceMappingURL=DefinitionCreateOperation.js.map
|