@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,747 @@
|
|
|
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, createEmptyFailureResult } from '../../models/service-result.js';
|
|
9
|
+
import { CUNEIFORM_NAMESPACE_PREFIX } from '../../constants/namespace-constants.js';
|
|
10
|
+
import { AdapterErrorCodes, mapSalesforceError, mapDmlInsertError, mapDmlUpdateError, mapDmlDeleteError, extractSalesforceErrorCode, sanitizeSoqlIdentifier, } from '../errors.js';
|
|
11
|
+
import { createLifecycleEmitter } from '../lifecycle.js';
|
|
12
|
+
import { withRetry } from '../retry.js';
|
|
13
|
+
import { getCacheTtl, warnApiVersion } from '../types.js';
|
|
14
|
+
import { CuneiformQueryBuilder } from '../soql/cuneiform-query-builder.js';
|
|
15
|
+
import { LruCache } from './cache.js';
|
|
16
|
+
/**
|
|
17
|
+
* Standard objects allowed for specific write operations.
|
|
18
|
+
* Maps object names to the set of permitted operations.
|
|
19
|
+
* These are objects that services legitimately need to write to
|
|
20
|
+
* that don't use the pnova__ namespace prefix.
|
|
21
|
+
*
|
|
22
|
+
* - PermissionSetAssignment: insert (configure) + delete (unconfigure)
|
|
23
|
+
*/
|
|
24
|
+
const WRITE_ALLOWLIST = new Map([
|
|
25
|
+
['PermissionSetAssignment', new Set(['insert', 'delete'])],
|
|
26
|
+
]);
|
|
27
|
+
/**
|
|
28
|
+
* Cache key prefixes for different operation types.
|
|
29
|
+
*/
|
|
30
|
+
const CACHE_KEYS = {
|
|
31
|
+
DESCRIBE: 'describe:',
|
|
32
|
+
GLOBAL: 'global',
|
|
33
|
+
COUNT: 'count:',
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Adapter for REST API operations against Salesforce.
|
|
37
|
+
*
|
|
38
|
+
* Provides caching for describe operations to reduce API calls.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const adapter = new RestApiAdapter(connectionFacade);
|
|
43
|
+
*
|
|
44
|
+
* // Describe an object (cached)
|
|
45
|
+
* const result = await adapter.describeObject('Account');
|
|
46
|
+
*
|
|
47
|
+
* // Get global describe (cached)
|
|
48
|
+
* const global = await adapter.describeGlobal();
|
|
49
|
+
*
|
|
50
|
+
* // Describe multiple objects
|
|
51
|
+
* const describes = await adapter.describeObjects(['Account', 'Contact', 'Opportunity']);
|
|
52
|
+
*
|
|
53
|
+
* // Invalidate cache
|
|
54
|
+
* adapter.invalidateCache('describe:Account'); // Single object
|
|
55
|
+
* adapter.invalidateCache('describe:*'); // All describes
|
|
56
|
+
* adapter.invalidateCache(); // Everything
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export class RestApiAdapter {
|
|
60
|
+
connection;
|
|
61
|
+
logger;
|
|
62
|
+
cache;
|
|
63
|
+
cacheEnabled;
|
|
64
|
+
lifecycle;
|
|
65
|
+
retryConfig;
|
|
66
|
+
recordCountBatchSize;
|
|
67
|
+
/**
|
|
68
|
+
* Creates a new RestApiAdapter.
|
|
69
|
+
*
|
|
70
|
+
* @param connection - The connection facade to use for API calls
|
|
71
|
+
* @param config - Optional configuration
|
|
72
|
+
*/
|
|
73
|
+
constructor(connection, config) {
|
|
74
|
+
this.connection = connection;
|
|
75
|
+
this.logger = config?.logger;
|
|
76
|
+
this.cacheEnabled = config?.cacheEnabled ?? true;
|
|
77
|
+
this.lifecycle = createLifecycleEmitter('describe', config?.emitLifecycleEvents ?? false);
|
|
78
|
+
this.retryConfig = config?.retry;
|
|
79
|
+
// CLI-1744: Raised default from 10 → 25 to reduce sequential batch count in the SOQL fallback path
|
|
80
|
+
this.recordCountBatchSize = Math.min(Math.max(config?.recordCountBatchSize ?? 25, 1), 50);
|
|
81
|
+
const ttl = getCacheTtl(config?.cacheTtl);
|
|
82
|
+
this.cache = new LruCache(100, ttl);
|
|
83
|
+
// Warn if API version is below recommended minimum
|
|
84
|
+
warnApiVersion(connection.version, 'RestApiAdapter', this.logger);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validates that a write operation targets a permitted object.
|
|
88
|
+
*
|
|
89
|
+
* Only objects with the pnova__ namespace prefix are allowed for all write operations.
|
|
90
|
+
* A small set of standard objects (WRITE_ALLOWLIST) are allowed for specific operations.
|
|
91
|
+
*
|
|
92
|
+
* @param objectName - The API name of the target object
|
|
93
|
+
* @param operation - The write operation type
|
|
94
|
+
* @returns undefined if allowed, or an error code and message if blocked
|
|
95
|
+
*/
|
|
96
|
+
static validateWriteNamespace(objectName, operation) {
|
|
97
|
+
if (objectName.startsWith(CUNEIFORM_NAMESPACE_PREFIX)) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const allowedOps = WRITE_ALLOWLIST.get(objectName);
|
|
101
|
+
if (allowedOps?.has(operation)) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
const errorCodeMap = {
|
|
105
|
+
insert: AdapterErrorCodes.INSERT_NAMESPACE_VIOLATION,
|
|
106
|
+
update: AdapterErrorCodes.UPDATE_NAMESPACE_VIOLATION,
|
|
107
|
+
delete: AdapterErrorCodes.DELETE_NAMESPACE_VIOLATION,
|
|
108
|
+
};
|
|
109
|
+
const errorCode = errorCodeMap[operation];
|
|
110
|
+
const operationLabel = operation.charAt(0).toUpperCase() + operation.slice(1);
|
|
111
|
+
// Show allowlist hint for operations that have allowlisted objects
|
|
112
|
+
const hasAllowlistEntries = [...WRITE_ALLOWLIST.values()].some((ops) => ops.has(operation));
|
|
113
|
+
return {
|
|
114
|
+
errorCode,
|
|
115
|
+
message: `${operationLabel} blocked: object '${objectName}' must use the ${CUNEIFORM_NAMESPACE_PREFIX} namespace` +
|
|
116
|
+
(hasAllowlistEntries ? ' or be in the explicit allowlist' : ''),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Describes a single Salesforce object.
|
|
121
|
+
*
|
|
122
|
+
* @param objectName - The API name of the object
|
|
123
|
+
* @returns ServiceResult containing the describe result
|
|
124
|
+
*/
|
|
125
|
+
async describeObject(objectName) {
|
|
126
|
+
const startTime = Date.now();
|
|
127
|
+
const cacheKey = `${CACHE_KEYS.DESCRIBE}${objectName}`;
|
|
128
|
+
const emptyResult = {
|
|
129
|
+
name: objectName,
|
|
130
|
+
label: '',
|
|
131
|
+
labelPlural: '',
|
|
132
|
+
custom: false,
|
|
133
|
+
createable: false,
|
|
134
|
+
updateable: false,
|
|
135
|
+
deletable: false,
|
|
136
|
+
queryable: false,
|
|
137
|
+
searchable: false,
|
|
138
|
+
fields: [],
|
|
139
|
+
};
|
|
140
|
+
try {
|
|
141
|
+
// Check cache first
|
|
142
|
+
if (this.cacheEnabled) {
|
|
143
|
+
const cached = this.cache.get(cacheKey);
|
|
144
|
+
if (cached) {
|
|
145
|
+
this.logger?.log(`Cache hit for describe: ${objectName}`);
|
|
146
|
+
return createSuccessResult(cached, {
|
|
147
|
+
message: `Describe result for ${objectName} (cached)`,
|
|
148
|
+
metadata: { duration: Date.now() - startTime, cached: true },
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
this.logger?.log(`Describing object: ${objectName}`);
|
|
153
|
+
await this.lifecycle.start('describeObject', { objectName });
|
|
154
|
+
const executeDescribe = () => this.connection.sobject(objectName).describe();
|
|
155
|
+
const result = this.retryConfig ? await withRetry(executeDescribe, this.retryConfig) : await executeDescribe();
|
|
156
|
+
const duration = Date.now() - startTime;
|
|
157
|
+
// Cache the result
|
|
158
|
+
if (this.cacheEnabled) {
|
|
159
|
+
this.cache.set(cacheKey, result);
|
|
160
|
+
}
|
|
161
|
+
this.logger?.log(`Describe complete for ${objectName}: ${result.fields.length} fields`);
|
|
162
|
+
await this.lifecycle.complete('describeObject', startTime, { objectName, fieldCount: result.fields.length });
|
|
163
|
+
return createSuccessResult(result, {
|
|
164
|
+
message: `Describe result for ${objectName}`,
|
|
165
|
+
metadata: { duration, cached: false },
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
170
|
+
await this.lifecycle.error('describeObject', startTime, errorMessage, { objectName });
|
|
171
|
+
return this.handleError(error, startTime, emptyResult, objectName);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Retrieves global describe information for all accessible objects.
|
|
176
|
+
*
|
|
177
|
+
* @returns ServiceResult containing the global describe result
|
|
178
|
+
*/
|
|
179
|
+
async describeGlobal() {
|
|
180
|
+
const startTime = Date.now();
|
|
181
|
+
const cacheKey = CACHE_KEYS.GLOBAL;
|
|
182
|
+
const emptyResult = { maxBatchSize: 0, sobjects: [] };
|
|
183
|
+
try {
|
|
184
|
+
// Check cache first
|
|
185
|
+
if (this.cacheEnabled) {
|
|
186
|
+
const cached = this.cache.get(cacheKey);
|
|
187
|
+
if (cached) {
|
|
188
|
+
this.logger?.log('Cache hit for global describe');
|
|
189
|
+
return createSuccessResult(cached, {
|
|
190
|
+
message: `Global describe result (cached): ${cached.sobjects.length} objects`,
|
|
191
|
+
metadata: { duration: Date.now() - startTime, cached: true },
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
this.logger?.log('Executing global describe');
|
|
196
|
+
await this.lifecycle.start('describeGlobal', {});
|
|
197
|
+
const executeGlobal = () => this.connection.request('/sobjects');
|
|
198
|
+
const result = this.retryConfig ? await withRetry(executeGlobal, this.retryConfig) : await executeGlobal();
|
|
199
|
+
const duration = Date.now() - startTime;
|
|
200
|
+
// Cache the result
|
|
201
|
+
if (this.cacheEnabled) {
|
|
202
|
+
this.cache.set(cacheKey, result);
|
|
203
|
+
}
|
|
204
|
+
this.logger?.log(`Global describe complete: ${result.sobjects.length} objects`);
|
|
205
|
+
await this.lifecycle.complete('describeGlobal', startTime, { objectCount: result.sobjects.length });
|
|
206
|
+
return createSuccessResult(result, {
|
|
207
|
+
message: `Global describe result: ${result.sobjects.length} objects`,
|
|
208
|
+
metadata: { duration, cached: false },
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
213
|
+
await this.lifecycle.error('describeGlobal', startTime, errorMessage);
|
|
214
|
+
return this.handleError(error, startTime, emptyResult, 'global describe', AdapterErrorCodes.GLOBAL_DESCRIBE_FAILED);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Gets the record count for a Salesforce object.
|
|
219
|
+
*
|
|
220
|
+
* @param objectName - The API name of the object
|
|
221
|
+
* @returns ServiceResult containing the record count
|
|
222
|
+
*/
|
|
223
|
+
async getRecordCount(objectName) {
|
|
224
|
+
const startTime = Date.now();
|
|
225
|
+
const cacheKey = `${CACHE_KEYS.COUNT}${objectName}`;
|
|
226
|
+
try {
|
|
227
|
+
// Check cache first
|
|
228
|
+
if (this.cacheEnabled) {
|
|
229
|
+
const cached = this.cache.get(cacheKey);
|
|
230
|
+
if (cached !== undefined) {
|
|
231
|
+
this.logger?.log(`Cache hit for record count: ${objectName}`);
|
|
232
|
+
return createSuccessResult(cached, {
|
|
233
|
+
message: `Record count for ${objectName}: ${cached} (cached)`,
|
|
234
|
+
metadata: { duration: Date.now() - startTime, cached: true },
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
this.logger?.log(`Getting record count for: ${objectName}`);
|
|
239
|
+
// Sanitize objectName to prevent SOQL injection (validates API name format)
|
|
240
|
+
const sanitizedObjectName = sanitizeSoqlIdentifier(objectName);
|
|
241
|
+
// Build COUNT() query using CuneiformQueryBuilder for type-safe SOQL generation.
|
|
242
|
+
// SELECT COUNT() returns the count in totalSize, not as a record field.
|
|
243
|
+
// This is more efficient than SELECT COUNT(Id) which returns records.
|
|
244
|
+
const countQuery = CuneiformQueryBuilder.create().count().from(sanitizedObjectName).toSOQL();
|
|
245
|
+
const executeCount = () => this.connection.query(countQuery);
|
|
246
|
+
const result = this.retryConfig ? await withRetry(executeCount, this.retryConfig) : await executeCount();
|
|
247
|
+
const count = result.totalSize;
|
|
248
|
+
const duration = Date.now() - startTime;
|
|
249
|
+
// Cache the result
|
|
250
|
+
if (this.cacheEnabled) {
|
|
251
|
+
this.cache.set(cacheKey, count);
|
|
252
|
+
}
|
|
253
|
+
this.logger?.log(`Record count for ${objectName}: ${count}`);
|
|
254
|
+
return createSuccessResult(count, {
|
|
255
|
+
message: `Record count for ${objectName}: ${count}`,
|
|
256
|
+
metadata: { duration, cached: false },
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
return this.handleError(error, startTime, 0, `record count for ${objectName}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Describes multiple Salesforce objects.
|
|
265
|
+
*
|
|
266
|
+
* @param objectNames - Array of object API names
|
|
267
|
+
* @returns ServiceResult containing a map of object names to describe results
|
|
268
|
+
*/
|
|
269
|
+
async describeObjects(objectNames) {
|
|
270
|
+
const startTime = Date.now();
|
|
271
|
+
const results = new Map();
|
|
272
|
+
const warnings = [];
|
|
273
|
+
this.logger?.log(`Describing ${objectNames.length} objects`);
|
|
274
|
+
// Process in parallel
|
|
275
|
+
const promises = objectNames.map(async (name) => {
|
|
276
|
+
const result = await this.describeObject(name);
|
|
277
|
+
if (result.success) {
|
|
278
|
+
results.set(name, result.data);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
const errorInfo = result.errorCode ? `[${result.errorCode}] ` : '';
|
|
282
|
+
warnings.push(`Failed to describe ${name}: ${errorInfo}${result.message ?? 'Unknown error'}`);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
await Promise.all(promises);
|
|
286
|
+
const duration = Date.now() - startTime;
|
|
287
|
+
this.logger?.log(`Described ${results.size}/${objectNames.length} objects`);
|
|
288
|
+
return createSuccessResult(results, {
|
|
289
|
+
message: `Described ${results.size}/${objectNames.length} objects`,
|
|
290
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
291
|
+
metadata: { duration },
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Gets record counts for multiple Salesforce objects using the bulk REST endpoint.
|
|
296
|
+
*
|
|
297
|
+
* Uses `GET /limits/recordCount?sObjects=A,B,C` for a single API call instead of
|
|
298
|
+
* N individual SOQL `SELECT COUNT()` queries. Falls back to per-object SOQL queries
|
|
299
|
+
* if the REST endpoint is unavailable or fails.
|
|
300
|
+
*
|
|
301
|
+
* Counts from the bulk response are cached individually so subsequent
|
|
302
|
+
* `getRecordCount()` calls benefit from the same cache.
|
|
303
|
+
*
|
|
304
|
+
* @param objectNames - Array of object API names
|
|
305
|
+
* @returns ServiceResult containing Map of object name to count
|
|
306
|
+
*/
|
|
307
|
+
async getRecordCounts(objectNames) {
|
|
308
|
+
const startTime = Date.now();
|
|
309
|
+
const results = new Map();
|
|
310
|
+
if (objectNames.length === 0) {
|
|
311
|
+
return createSuccessResult(results, {
|
|
312
|
+
message: 'Retrieved counts for 0/0 objects',
|
|
313
|
+
metadata: { duration: Date.now() - startTime },
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
this.logger?.log(`Getting record counts for ${objectNames.length} objects`);
|
|
317
|
+
// Resolve cached counts first, collect uncached for bulk fetch
|
|
318
|
+
const uncached = [];
|
|
319
|
+
for (const name of objectNames) {
|
|
320
|
+
if (this.cacheEnabled) {
|
|
321
|
+
const cacheKey = `${CACHE_KEYS.COUNT}${name}`;
|
|
322
|
+
const cached = this.cache.get(cacheKey);
|
|
323
|
+
if (cached !== undefined) {
|
|
324
|
+
results.set(name, cached);
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
uncached.push(name);
|
|
329
|
+
}
|
|
330
|
+
if (uncached.length > 0) {
|
|
331
|
+
// Try the bulk /limits/recordCount REST endpoint first
|
|
332
|
+
const bulkSuccess = await this.fetchRecordCountsViaRest(uncached, results);
|
|
333
|
+
if (!bulkSuccess) {
|
|
334
|
+
// Fall back to individual SOQL COUNT() queries
|
|
335
|
+
this.logger?.log(`REST /limits/recordCount failed, falling back to individual SOQL for ${uncached.length} objects`);
|
|
336
|
+
await this.fetchRecordCountsViaSoql(uncached, results);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const duration = Date.now() - startTime;
|
|
340
|
+
this.logger?.log(`Retrieved counts for ${results.size}/${objectNames.length} objects`);
|
|
341
|
+
return createSuccessResult(results, {
|
|
342
|
+
message: `Retrieved counts for ${results.size}/${objectNames.length} objects`,
|
|
343
|
+
warnings: results.size < objectNames.length
|
|
344
|
+
? ['Some objects returned 0 counts (may not be supported by /limits/recordCount)']
|
|
345
|
+
: undefined,
|
|
346
|
+
metadata: { duration },
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Inserts a new record into a Salesforce object.
|
|
351
|
+
*
|
|
352
|
+
* Uses the REST API POST /sobjects/{objectName} endpoint to create a record.
|
|
353
|
+
* Does not use caching since write operations should always execute.
|
|
354
|
+
*
|
|
355
|
+
* @param objectName - The API name of the object (e.g., 'Account', 'PermissionSetAssignment')
|
|
356
|
+
* @param record - The field values for the new record
|
|
357
|
+
* @returns ServiceResult containing the created record's ID
|
|
358
|
+
*
|
|
359
|
+
* @example
|
|
360
|
+
* ```typescript
|
|
361
|
+
* const result = await adapter.insertRecord('PermissionSetAssignment', {
|
|
362
|
+
* AssigneeId: '005xx000001234567',
|
|
363
|
+
* PermissionSetId: '0PS000000000001'
|
|
364
|
+
* });
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
async insertRecord(objectName, record) {
|
|
368
|
+
const startTime = Date.now();
|
|
369
|
+
const emptyResult = { id: '' };
|
|
370
|
+
try {
|
|
371
|
+
this.logger?.log(`Inserting record into: ${objectName}`);
|
|
372
|
+
await this.lifecycle.start('insertRecord', { objectName });
|
|
373
|
+
// Sanitize objectName to prevent injection (validates API name format)
|
|
374
|
+
const sanitizedObjectName = sanitizeSoqlIdentifier(objectName);
|
|
375
|
+
// Namespace guard: only pnova__ objects and allowlisted standard objects permitted
|
|
376
|
+
const namespaceViolation = RestApiAdapter.validateWriteNamespace(sanitizedObjectName, 'insert');
|
|
377
|
+
if (namespaceViolation) {
|
|
378
|
+
this.logger?.log(`Insert blocked by namespace guard: ${objectName}`);
|
|
379
|
+
await this.lifecycle.error('insertRecord', startTime, namespaceViolation.message, { objectName });
|
|
380
|
+
return createFailureResult(emptyResult, namespaceViolation.errorCode, namespaceViolation.message);
|
|
381
|
+
}
|
|
382
|
+
// Build REST API endpoint for sObject insert
|
|
383
|
+
const endpoint = `/sobjects/${sanitizedObjectName}`;
|
|
384
|
+
const executeInsert = () => this.connection.request({
|
|
385
|
+
url: endpoint,
|
|
386
|
+
method: 'POST',
|
|
387
|
+
body: JSON.stringify(record),
|
|
388
|
+
headers: { 'content-type': 'application/json' },
|
|
389
|
+
});
|
|
390
|
+
const result = this.retryConfig ? await withRetry(executeInsert, this.retryConfig) : await executeInsert();
|
|
391
|
+
const duration = Date.now() - startTime;
|
|
392
|
+
// Check if the API returned success=false with errors
|
|
393
|
+
if (!result.success) {
|
|
394
|
+
const apiErrorMessage = Array.isArray(result.errors) ? JSON.stringify(result.errors) : 'Insert failed';
|
|
395
|
+
this.logger?.log(`Insert failed for ${objectName}: ${apiErrorMessage}`);
|
|
396
|
+
await this.lifecycle.error('insertRecord', startTime, apiErrorMessage, { objectName });
|
|
397
|
+
return createFailureResult(emptyResult, AdapterErrorCodes.INSERT_RECORD_FAILED, apiErrorMessage, {
|
|
398
|
+
metadata: { duration },
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
this.logger?.log(`Insert complete for ${objectName}: ${result.id}`);
|
|
402
|
+
await this.lifecycle.complete('insertRecord', startTime, { objectName, recordId: result.id });
|
|
403
|
+
return createSuccessResult({ id: result.id }, {
|
|
404
|
+
message: `Inserted record into ${objectName}: ${result.id}`,
|
|
405
|
+
metadata: { duration },
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
410
|
+
await this.lifecycle.error('insertRecord', startTime, errorMessage, { objectName });
|
|
411
|
+
return this.handleInsertError(error, startTime, emptyResult, objectName);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Updates an existing record in a Salesforce object.
|
|
416
|
+
*
|
|
417
|
+
* Uses the REST API PATCH /sobjects/{objectName}/{recordId} endpoint to update a record.
|
|
418
|
+
* Does not use caching since write operations should always execute.
|
|
419
|
+
*
|
|
420
|
+
* @param objectName - The API name of the object (e.g., 'Account', 'Contact')
|
|
421
|
+
* @param recordId - The ID of the record to update
|
|
422
|
+
* @param record - The field values to update
|
|
423
|
+
* @returns ServiceResult containing the update result with record ID and success status
|
|
424
|
+
*/
|
|
425
|
+
async updateRecord(objectName, recordId, record) {
|
|
426
|
+
const startTime = Date.now();
|
|
427
|
+
const emptyResult = { id: recordId, success: false };
|
|
428
|
+
try {
|
|
429
|
+
this.logger?.log(`Updating record ${recordId} in: ${objectName}`);
|
|
430
|
+
await this.lifecycle.start('updateRecord', { objectName, recordId });
|
|
431
|
+
// Sanitize objectName to prevent injection (validates API name format)
|
|
432
|
+
const sanitizedObjectName = sanitizeSoqlIdentifier(objectName);
|
|
433
|
+
// Namespace guard: only pnova__ objects permitted for update
|
|
434
|
+
const namespaceViolation = RestApiAdapter.validateWriteNamespace(sanitizedObjectName, 'update');
|
|
435
|
+
if (namespaceViolation) {
|
|
436
|
+
this.logger?.log(`Update blocked by namespace guard: ${objectName}`);
|
|
437
|
+
await this.lifecycle.error('updateRecord', startTime, namespaceViolation.message, { objectName, recordId });
|
|
438
|
+
return createFailureResult(emptyResult, namespaceViolation.errorCode, namespaceViolation.message);
|
|
439
|
+
}
|
|
440
|
+
// Build REST API endpoint for sObject update
|
|
441
|
+
const endpoint = `/sobjects/${sanitizedObjectName}/${recordId}`;
|
|
442
|
+
// PATCH request returns 204 No Content on success, error response on failure
|
|
443
|
+
const executeUpdate = () => this.connection.request({
|
|
444
|
+
url: endpoint,
|
|
445
|
+
method: 'PATCH',
|
|
446
|
+
body: JSON.stringify(record),
|
|
447
|
+
headers: { 'content-type': 'application/json' },
|
|
448
|
+
});
|
|
449
|
+
await (this.retryConfig ? withRetry(executeUpdate, this.retryConfig) : executeUpdate());
|
|
450
|
+
const duration = Date.now() - startTime;
|
|
451
|
+
this.logger?.log(`Update complete for ${objectName}/${recordId}`);
|
|
452
|
+
await this.lifecycle.complete('updateRecord', startTime, { objectName, recordId });
|
|
453
|
+
return createSuccessResult({ id: recordId, success: true }, {
|
|
454
|
+
message: `Updated record in ${objectName}: ${recordId}`,
|
|
455
|
+
metadata: { duration },
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
460
|
+
await this.lifecycle.error('updateRecord', startTime, errorMessage, { objectName, recordId });
|
|
461
|
+
return this.handleUpdateError(error, startTime, emptyResult, `${objectName}/${recordId}`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Deletes a record from a Salesforce object.
|
|
466
|
+
*
|
|
467
|
+
* Uses the REST API DELETE /sobjects/{objectName}/{recordId} endpoint to delete a record.
|
|
468
|
+
* Does not use caching since write operations should always execute.
|
|
469
|
+
*
|
|
470
|
+
* @param objectName - The API name of the object (e.g., 'Account', 'Contact')
|
|
471
|
+
* @param recordId - The ID of the record to delete
|
|
472
|
+
* @returns ServiceResult containing the delete result with record ID and success status
|
|
473
|
+
*/
|
|
474
|
+
async deleteRecord(objectName, recordId) {
|
|
475
|
+
const startTime = Date.now();
|
|
476
|
+
const emptyResult = { id: recordId, success: false };
|
|
477
|
+
try {
|
|
478
|
+
this.logger?.log(`Deleting record ${recordId} from: ${objectName}`);
|
|
479
|
+
await this.lifecycle.start('deleteRecord', { objectName, recordId });
|
|
480
|
+
// Sanitize objectName to prevent injection (validates API name format)
|
|
481
|
+
const sanitizedObjectName = sanitizeSoqlIdentifier(objectName);
|
|
482
|
+
// Namespace guard: only pnova__ objects permitted for delete
|
|
483
|
+
const namespaceViolation = RestApiAdapter.validateWriteNamespace(sanitizedObjectName, 'delete');
|
|
484
|
+
if (namespaceViolation) {
|
|
485
|
+
this.logger?.log(`Delete blocked by namespace guard: ${objectName}`);
|
|
486
|
+
await this.lifecycle.error('deleteRecord', startTime, namespaceViolation.message, { objectName, recordId });
|
|
487
|
+
return createFailureResult(emptyResult, namespaceViolation.errorCode, namespaceViolation.message);
|
|
488
|
+
}
|
|
489
|
+
// Build REST API endpoint for sObject delete
|
|
490
|
+
const endpoint = `/sobjects/${sanitizedObjectName}/${recordId}`;
|
|
491
|
+
// DELETE request returns 204 No Content on success, error response on failure
|
|
492
|
+
const executeDelete = () => this.connection.request({
|
|
493
|
+
url: endpoint,
|
|
494
|
+
method: 'DELETE',
|
|
495
|
+
});
|
|
496
|
+
await (this.retryConfig ? withRetry(executeDelete, this.retryConfig) : executeDelete());
|
|
497
|
+
const duration = Date.now() - startTime;
|
|
498
|
+
this.logger?.log(`Delete complete for ${objectName}/${recordId}`);
|
|
499
|
+
await this.lifecycle.complete('deleteRecord', startTime, { objectName, recordId });
|
|
500
|
+
return createSuccessResult({ id: recordId, success: true }, {
|
|
501
|
+
message: `Deleted record from ${objectName}: ${recordId}`,
|
|
502
|
+
metadata: { duration },
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
catch (error) {
|
|
506
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
507
|
+
await this.lifecycle.error('deleteRecord', startTime, errorMessage, { objectName, recordId });
|
|
508
|
+
return this.handleDeleteError(error, startTime, emptyResult, `${objectName}/${recordId}`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Makes a generic HTTP request to a custom Salesforce REST endpoint.
|
|
513
|
+
*
|
|
514
|
+
* Supports custom Apex REST endpoints and any other Salesforce REST API path.
|
|
515
|
+
* Does not use caching since custom endpoints have unpredictable response shapes.
|
|
516
|
+
*
|
|
517
|
+
* The namespace guard is enforced for write operations (POST, PATCH, PUT, DELETE) that
|
|
518
|
+
* target sObject endpoints (`/sobjects/{objectName}`). Custom Apex REST endpoints
|
|
519
|
+
* (e.g., `/services/apexrest/pnova/v1/...`) and GET requests are not affected.
|
|
520
|
+
*
|
|
521
|
+
* @param httpRequest - The HTTP request configuration
|
|
522
|
+
* @returns ServiceResult containing the deserialized response of type T
|
|
523
|
+
*/
|
|
524
|
+
async request(httpRequest) {
|
|
525
|
+
const startTime = Date.now();
|
|
526
|
+
const SOBJECT_WRITE_METHODS = new Set(['POST', 'PATCH', 'PUT', 'DELETE']);
|
|
527
|
+
try {
|
|
528
|
+
this.logger?.log(`REST request: ${httpRequest.method} ${httpRequest.url}`);
|
|
529
|
+
// Namespace guard: block write operations to non-pnova__ sObject endpoints
|
|
530
|
+
const sobjectPattern = /^\/sobjects\/([^/]+)/;
|
|
531
|
+
const sobjectMatch = sobjectPattern.exec(httpRequest.url);
|
|
532
|
+
if (sobjectMatch && SOBJECT_WRITE_METHODS.has(httpRequest.method)) {
|
|
533
|
+
const objectName = sobjectMatch[1];
|
|
534
|
+
const operation = httpRequest.method === 'POST' ? 'insert' : httpRequest.method === 'DELETE' ? 'delete' : 'update';
|
|
535
|
+
const violation = RestApiAdapter.validateWriteNamespace(objectName, operation);
|
|
536
|
+
if (violation) {
|
|
537
|
+
this.logger?.log(`Request blocked by namespace guard: ${httpRequest.method} ${httpRequest.url}`);
|
|
538
|
+
await this.lifecycle.error('request', startTime, violation.message, {
|
|
539
|
+
url: httpRequest.url,
|
|
540
|
+
method: httpRequest.method,
|
|
541
|
+
});
|
|
542
|
+
return createEmptyFailureResult(violation.errorCode, violation.message);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
await this.lifecycle.start('request', { url: httpRequest.url, method: httpRequest.method });
|
|
546
|
+
const executeRequest = () => this.connection.request({
|
|
547
|
+
url: httpRequest.url,
|
|
548
|
+
method: httpRequest.method,
|
|
549
|
+
body: httpRequest.body != null
|
|
550
|
+
? typeof httpRequest.body === 'string'
|
|
551
|
+
? httpRequest.body
|
|
552
|
+
: JSON.stringify(httpRequest.body)
|
|
553
|
+
: undefined,
|
|
554
|
+
headers: httpRequest.headers ?? { 'content-type': 'application/json' },
|
|
555
|
+
});
|
|
556
|
+
const raw = this.retryConfig ? await withRetry(executeRequest, this.retryConfig) : await executeRequest();
|
|
557
|
+
// jsforce connection.request() may return a raw JSON string for custom REST endpoints;
|
|
558
|
+
// parse it so callers always receive a typed object.
|
|
559
|
+
const result = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
560
|
+
const duration = Date.now() - startTime;
|
|
561
|
+
this.logger?.log(`REST request complete: ${httpRequest.method} ${httpRequest.url}`);
|
|
562
|
+
await this.lifecycle.complete('request', startTime, { url: httpRequest.url, method: httpRequest.method });
|
|
563
|
+
return createSuccessResult(result, {
|
|
564
|
+
message: `${httpRequest.method} ${httpRequest.url}`,
|
|
565
|
+
metadata: { duration },
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
catch (error) {
|
|
569
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
570
|
+
await this.lifecycle.error('request', startTime, errorMessage, {
|
|
571
|
+
url: httpRequest.url,
|
|
572
|
+
method: httpRequest.method,
|
|
573
|
+
});
|
|
574
|
+
return this.handleError(error, startTime, undefined, `${httpRequest.method} ${httpRequest.url}`, AdapterErrorCodes.REQUEST_FAILED);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Invalidates cached entries.
|
|
579
|
+
*
|
|
580
|
+
* @param pattern - Optional pattern to match keys (supports * wildcard). If not provided, clears all entries.
|
|
581
|
+
*/
|
|
582
|
+
invalidateCache(pattern) {
|
|
583
|
+
this.logger?.log(`Invalidating cache${pattern ? `: ${pattern}` : ' (all)'}`);
|
|
584
|
+
this.cache.invalidate(pattern);
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Fetches record counts via the bulk REST endpoint `/limits/recordCount`.
|
|
588
|
+
*
|
|
589
|
+
* @param objectNames - Object API names to fetch counts for
|
|
590
|
+
* @param results - Map to populate with counts
|
|
591
|
+
* @returns true if the REST endpoint succeeded, false if it failed
|
|
592
|
+
*/
|
|
593
|
+
async fetchRecordCountsViaRest(objectNames, results) {
|
|
594
|
+
try {
|
|
595
|
+
// CLI-1744: Call /limits/recordCount WITHOUT sObjects param to get ALL counts in one call.
|
|
596
|
+
// The previous approach joined all object names into the URL query string, which exceeded
|
|
597
|
+
// URL length limits (8K+) for orgs with 500+ objects and triggered the SOQL fallback (67-72s).
|
|
598
|
+
// A single parameterless call returns all org counts in ~1-2s.
|
|
599
|
+
const endpoint = '/limits/recordCount';
|
|
600
|
+
const response = await (this.retryConfig
|
|
601
|
+
? withRetry(() => this.connection.request(endpoint), this.retryConfig)
|
|
602
|
+
: this.connection.request(endpoint));
|
|
603
|
+
// Build a lookup from the full org response
|
|
604
|
+
const countsByName = new Map();
|
|
605
|
+
for (const entry of response.sObjects) {
|
|
606
|
+
countsByName.set(entry.name, entry.count);
|
|
607
|
+
}
|
|
608
|
+
// Populate results for requested objects and cache individual counts.
|
|
609
|
+
// Objects not in the REST response default to 0 (Salesforce omits objects with 0 records).
|
|
610
|
+
for (const name of objectNames) {
|
|
611
|
+
const count = countsByName.get(name) ?? 0;
|
|
612
|
+
results.set(name, count);
|
|
613
|
+
if (this.cacheEnabled) {
|
|
614
|
+
this.cache.set(`${CACHE_KEYS.COUNT}${name}`, count);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
catch (error) {
|
|
620
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
621
|
+
this.logger?.log(`REST /limits/recordCount unavailable: ${errorMessage}, falling back to individual queries`);
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Fallback: fetches record counts via individual SOQL COUNT() queries.
|
|
627
|
+
*
|
|
628
|
+
* @param objectNames - Object API names to fetch counts for
|
|
629
|
+
* @param results - Map to populate with counts
|
|
630
|
+
*/
|
|
631
|
+
async fetchRecordCountsViaSoql(objectNames, results) {
|
|
632
|
+
/* eslint-disable no-await-in-loop -- Intentional sequential batching to avoid overwhelming Salesforce API */
|
|
633
|
+
for (let i = 0; i < objectNames.length; i += this.recordCountBatchSize) {
|
|
634
|
+
const batch = objectNames.slice(i, i + this.recordCountBatchSize);
|
|
635
|
+
const batchPromises = batch.map(async (name) => {
|
|
636
|
+
const result = await this.getRecordCount(name);
|
|
637
|
+
if (result.success) {
|
|
638
|
+
results.set(name, result.data);
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
await Promise.all(batchPromises);
|
|
642
|
+
}
|
|
643
|
+
/* eslint-enable no-await-in-loop */
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Handles DML insert errors and maps them to appropriate error codes.
|
|
647
|
+
*
|
|
648
|
+
* @param error - The caught error
|
|
649
|
+
* @param startTime - The operation start time for duration calculation
|
|
650
|
+
* @param emptyResult - The empty result to return on failure
|
|
651
|
+
* @param context - Context for logging (object name)
|
|
652
|
+
* @returns ServiceResult with success=false and mapped error code
|
|
653
|
+
*/
|
|
654
|
+
handleInsertError(error, startTime, emptyResult, context) {
|
|
655
|
+
const duration = Date.now() - startTime;
|
|
656
|
+
const errorMessage = error instanceof Error
|
|
657
|
+
? error.message
|
|
658
|
+
: typeof error === 'object' && error !== null
|
|
659
|
+
? JSON.stringify(error)
|
|
660
|
+
: String(error);
|
|
661
|
+
const sfErrorCode = extractSalesforceErrorCode(error);
|
|
662
|
+
const adapterErrorCode = sfErrorCode ? mapDmlInsertError(sfErrorCode) : AdapterErrorCodes.INSERT_RECORD_FAILED;
|
|
663
|
+
this.logger?.log(`REST API insert failed (${context}): ${errorMessage}`);
|
|
664
|
+
return createFailureResult(emptyResult, adapterErrorCode, errorMessage, {
|
|
665
|
+
metadata: { duration, sfErrorCode },
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Handles DML update errors and maps them to appropriate error codes.
|
|
670
|
+
*
|
|
671
|
+
* @param error - The caught error
|
|
672
|
+
* @param startTime - The operation start time for duration calculation
|
|
673
|
+
* @param emptyResult - The empty result to return on failure
|
|
674
|
+
* @param context - Context for logging (object name/record ID)
|
|
675
|
+
* @returns ServiceResult with success=false and mapped error code
|
|
676
|
+
*/
|
|
677
|
+
handleUpdateError(error, startTime, emptyResult, context) {
|
|
678
|
+
const duration = Date.now() - startTime;
|
|
679
|
+
const errorMessage = error instanceof Error
|
|
680
|
+
? error.message
|
|
681
|
+
: typeof error === 'object' && error !== null
|
|
682
|
+
? JSON.stringify(error)
|
|
683
|
+
: String(error);
|
|
684
|
+
const sfErrorCode = extractSalesforceErrorCode(error);
|
|
685
|
+
const adapterErrorCode = sfErrorCode ? mapDmlUpdateError(sfErrorCode) : AdapterErrorCodes.UPDATE_RECORD_FAILED;
|
|
686
|
+
this.logger?.log(`REST API update failed (${context}): ${errorMessage}`);
|
|
687
|
+
return createFailureResult(emptyResult, adapterErrorCode, errorMessage, {
|
|
688
|
+
metadata: { duration, sfErrorCode },
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Handles DML delete errors and maps them to appropriate error codes.
|
|
693
|
+
*
|
|
694
|
+
* @param error - The caught error
|
|
695
|
+
* @param startTime - The operation start time for duration calculation
|
|
696
|
+
* @param emptyResult - The empty result to return on failure
|
|
697
|
+
* @param context - Context for logging (object name/record ID)
|
|
698
|
+
* @returns ServiceResult with success=false and mapped error code
|
|
699
|
+
*/
|
|
700
|
+
handleDeleteError(error, startTime, emptyResult, context) {
|
|
701
|
+
const duration = Date.now() - startTime;
|
|
702
|
+
const errorMessage = error instanceof Error
|
|
703
|
+
? error.message
|
|
704
|
+
: typeof error === 'object' && error !== null
|
|
705
|
+
? JSON.stringify(error)
|
|
706
|
+
: String(error);
|
|
707
|
+
const sfErrorCode = extractSalesforceErrorCode(error);
|
|
708
|
+
const adapterErrorCode = sfErrorCode ? mapDmlDeleteError(sfErrorCode) : AdapterErrorCodes.DELETE_RECORD_FAILED;
|
|
709
|
+
this.logger?.log(`REST API delete failed (${context}): ${errorMessage}`);
|
|
710
|
+
return createFailureResult(emptyResult, adapterErrorCode, errorMessage, {
|
|
711
|
+
metadata: { duration, sfErrorCode },
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Handles errors and maps them to appropriate error codes.
|
|
716
|
+
*
|
|
717
|
+
* Accepts SfError, jsforce errors, or unknown error types. Extracts Salesforce
|
|
718
|
+
* error codes when available and maps them to adapter-specific error codes.
|
|
719
|
+
*
|
|
720
|
+
* @param error - The caught error (SfError, jsforce error, or unknown)
|
|
721
|
+
* @param startTime - The operation start time for duration calculation
|
|
722
|
+
* @param emptyResult - The empty result to return on failure
|
|
723
|
+
* @param context - Context for logging (e.g., "Account", "global describe")
|
|
724
|
+
* @param defaultErrorCode - The default error code if no SF error code is found
|
|
725
|
+
* @returns ServiceResult with success=false and mapped error code
|
|
726
|
+
*/
|
|
727
|
+
handleError(error, startTime, emptyResult, context, defaultErrorCode = AdapterErrorCodes.DESCRIBE_FAILED) {
|
|
728
|
+
const duration = Date.now() - startTime;
|
|
729
|
+
const errorMessage = error instanceof Error
|
|
730
|
+
? error.message
|
|
731
|
+
: typeof error === 'object' && error !== null
|
|
732
|
+
? JSON.stringify(error)
|
|
733
|
+
: String(error);
|
|
734
|
+
const sfErrorCode = extractSalesforceErrorCode(error);
|
|
735
|
+
const adapterErrorCode = sfErrorCode ? mapSalesforceError(sfErrorCode, 'rest') : defaultErrorCode;
|
|
736
|
+
this.logger?.log(`REST API failed (${context}): ${errorMessage}`);
|
|
737
|
+
if (emptyResult === undefined) {
|
|
738
|
+
return createEmptyFailureResult(adapterErrorCode, errorMessage, {
|
|
739
|
+
metadata: { duration, sfErrorCode },
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
return createFailureResult(emptyResult, adapterErrorCode, errorMessage, {
|
|
743
|
+
metadata: { duration, sfErrorCode },
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
//# sourceMappingURL=rest-api-adapter.js.map
|