@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.
Files changed (494) hide show
  1. package/LICENSE +81 -30
  2. package/README.md +59 -95
  3. package/lib/adapters/connection-facade.d.ts +458 -0
  4. package/lib/adapters/connection-facade.js +379 -0
  5. package/lib/adapters/connection-facade.js.map +1 -0
  6. package/lib/adapters/errors.d.ts +547 -0
  7. package/lib/adapters/errors.js +937 -0
  8. package/lib/adapters/errors.js.map +1 -0
  9. package/lib/adapters/index.d.ts +33 -0
  10. package/lib/adapters/index.js +50 -0
  11. package/lib/adapters/index.js.map +1 -0
  12. package/lib/adapters/lifecycle.d.ts +119 -0
  13. package/lib/adapters/lifecycle.js +94 -0
  14. package/lib/adapters/lifecycle.js.map +1 -0
  15. package/lib/adapters/rest/cache.d.ts +69 -0
  16. package/lib/adapters/rest/cache.js +133 -0
  17. package/lib/adapters/rest/cache.js.map +1 -0
  18. package/lib/adapters/rest/index.d.ts +11 -0
  19. package/lib/adapters/rest/index.js +18 -0
  20. package/lib/adapters/rest/index.js.map +1 -0
  21. package/lib/adapters/rest/profiling-rest-client.d.ts +137 -0
  22. package/lib/adapters/rest/profiling-rest-client.js +115 -0
  23. package/lib/adapters/rest/profiling-rest-client.js.map +1 -0
  24. package/lib/adapters/rest/rest-api-adapter.d.ts +389 -0
  25. package/lib/adapters/rest/rest-api-adapter.js +747 -0
  26. package/lib/adapters/rest/rest-api-adapter.js.map +1 -0
  27. package/lib/adapters/rest/types.d.ts +34 -0
  28. package/lib/adapters/rest/types.js +9 -0
  29. package/lib/adapters/rest/types.js.map +1 -0
  30. package/lib/adapters/retry.d.ts +91 -0
  31. package/lib/adapters/retry.js +215 -0
  32. package/lib/adapters/retry.js.map +1 -0
  33. package/lib/adapters/soql/cuneiform-query-builder.d.ts +391 -0
  34. package/lib/adapters/soql/cuneiform-query-builder.js +559 -0
  35. package/lib/adapters/soql/cuneiform-query-builder.js.map +1 -0
  36. package/lib/adapters/soql/index.d.ts +13 -0
  37. package/lib/adapters/soql/index.js +21 -0
  38. package/lib/adapters/soql/index.js.map +1 -0
  39. package/lib/adapters/soql/soql-query-adapter.d.ts +141 -0
  40. package/lib/adapters/soql/soql-query-adapter.js +259 -0
  41. package/lib/adapters/soql/soql-query-adapter.js.map +1 -0
  42. package/lib/adapters/soql/types.d.ts +37 -0
  43. package/lib/adapters/soql/types.js +19 -0
  44. package/lib/adapters/soql/types.js.map +1 -0
  45. package/lib/adapters/testing/index.d.ts +37 -0
  46. package/lib/adapters/testing/index.js +20 -0
  47. package/lib/adapters/testing/index.js.map +1 -0
  48. package/lib/adapters/testing/mock-connection.d.ts +77 -0
  49. package/lib/adapters/testing/mock-connection.js +207 -0
  50. package/lib/adapters/testing/mock-connection.js.map +1 -0
  51. package/lib/adapters/testing/mock-logger.d.ts +29 -0
  52. package/lib/adapters/testing/mock-logger.js +57 -0
  53. package/lib/adapters/testing/mock-logger.js.map +1 -0
  54. package/lib/adapters/testing/mock-mcp-adapters.d.ts +32 -0
  55. package/lib/adapters/testing/mock-mcp-adapters.js +52 -0
  56. package/lib/adapters/testing/mock-mcp-adapters.js.map +1 -0
  57. package/lib/adapters/testing/mock-oclif-config.d.ts +22 -0
  58. package/lib/adapters/testing/mock-oclif-config.js +90 -0
  59. package/lib/adapters/testing/mock-oclif-config.js.map +1 -0
  60. package/lib/adapters/testing/mock-rest-adapter.d.ts +26 -0
  61. package/lib/adapters/testing/mock-rest-adapter.js +243 -0
  62. package/lib/adapters/testing/mock-rest-adapter.js.map +1 -0
  63. package/lib/adapters/testing/mock-salesforce-connection.d.ts +40 -0
  64. package/lib/adapters/testing/mock-salesforce-connection.js +61 -0
  65. package/lib/adapters/testing/mock-salesforce-connection.js.map +1 -0
  66. package/lib/adapters/testing/mock-soql-adapter.d.ts +30 -0
  67. package/lib/adapters/testing/mock-soql-adapter.js +120 -0
  68. package/lib/adapters/testing/mock-soql-adapter.js.map +1 -0
  69. package/lib/adapters/testing/mock-tooling-adapter.d.ts +24 -0
  70. package/lib/adapters/testing/mock-tooling-adapter.js +163 -0
  71. package/lib/adapters/testing/mock-tooling-adapter.js.map +1 -0
  72. package/lib/adapters/testing/stub-connection.d.ts +93 -0
  73. package/lib/adapters/testing/stub-connection.js +97 -0
  74. package/lib/adapters/testing/stub-connection.js.map +1 -0
  75. package/lib/adapters/testing/stub-rest-adapter.d.ts +52 -0
  76. package/lib/adapters/testing/stub-rest-adapter.js +58 -0
  77. package/lib/adapters/testing/stub-rest-adapter.js.map +1 -0
  78. package/lib/adapters/testing/stub-soql-adapter.d.ts +56 -0
  79. package/lib/adapters/testing/stub-soql-adapter.js +50 -0
  80. package/lib/adapters/testing/stub-soql-adapter.js.map +1 -0
  81. package/lib/adapters/testing/types.d.ts +71 -0
  82. package/lib/adapters/testing/types.js +9 -0
  83. package/lib/adapters/testing/types.js.map +1 -0
  84. package/lib/adapters/tooling/index.d.ts +10 -0
  85. package/lib/adapters/tooling/index.js +17 -0
  86. package/lib/adapters/tooling/index.js.map +1 -0
  87. package/lib/adapters/tooling/tooling-api-adapter.d.ts +157 -0
  88. package/lib/adapters/tooling/tooling-api-adapter.js +339 -0
  89. package/lib/adapters/tooling/tooling-api-adapter.js.map +1 -0
  90. package/lib/adapters/tooling/types.d.ts +81 -0
  91. package/lib/adapters/tooling/types.js +9 -0
  92. package/lib/adapters/tooling/types.js.map +1 -0
  93. package/lib/adapters/types.d.ts +112 -0
  94. package/lib/adapters/types.js +169 -0
  95. package/lib/adapters/types.js.map +1 -0
  96. package/lib/base/cuneiform-command.d.ts +152 -0
  97. package/lib/base/cuneiform-command.js +243 -0
  98. package/lib/base/cuneiform-command.js.map +1 -0
  99. package/lib/commands/cuneiform/compatibility/check.d.ts +43 -0
  100. package/lib/commands/cuneiform/compatibility/check.js +114 -0
  101. package/lib/commands/cuneiform/compatibility/check.js.map +1 -0
  102. package/lib/commands/cuneiform/definition/create.d.ts +119 -0
  103. package/lib/commands/cuneiform/definition/create.js +693 -0
  104. package/lib/commands/cuneiform/definition/create.js.map +1 -0
  105. package/lib/commands/cuneiform/definition/export.d.ts +57 -0
  106. package/lib/commands/cuneiform/definition/export.js +133 -0
  107. package/lib/commands/cuneiform/definition/export.js.map +1 -0
  108. package/lib/commands/cuneiform/definition/get.d.ts +86 -0
  109. package/lib/commands/cuneiform/definition/get.js +270 -0
  110. package/lib/commands/cuneiform/definition/get.js.map +1 -0
  111. package/lib/commands/cuneiform/definition/import.d.ts +54 -0
  112. package/lib/commands/cuneiform/definition/import.js +118 -0
  113. package/lib/commands/cuneiform/definition/import.js.map +1 -0
  114. package/lib/commands/cuneiform/definition/list.d.ts +110 -0
  115. package/lib/commands/cuneiform/definition/list.js +344 -0
  116. package/lib/commands/cuneiform/definition/list.js.map +1 -0
  117. package/lib/commands/cuneiform/definition/purge.d.ts +105 -0
  118. package/lib/commands/cuneiform/definition/purge.js +533 -0
  119. package/lib/commands/cuneiform/definition/purge.js.map +1 -0
  120. package/lib/commands/cuneiform/definition/update.d.ts +58 -0
  121. package/lib/commands/cuneiform/definition/update.js +206 -0
  122. package/lib/commands/cuneiform/definition/update.js.map +1 -0
  123. package/lib/commands/cuneiform/mcp/serve.d.ts +56 -0
  124. package/lib/commands/cuneiform/mcp/serve.js +109 -0
  125. package/lib/commands/cuneiform/mcp/serve.js.map +1 -0
  126. package/lib/commands/cuneiform/object/describe.d.ts +61 -0
  127. package/lib/commands/cuneiform/object/describe.js +461 -0
  128. package/lib/commands/cuneiform/object/describe.js.map +1 -0
  129. package/lib/commands/cuneiform/object/list.d.ts +111 -0
  130. package/lib/commands/cuneiform/object/list.js +239 -0
  131. package/lib/commands/cuneiform/object/list.js.map +1 -0
  132. package/lib/commands/cuneiform/org/details.d.ts +99 -0
  133. package/lib/commands/cuneiform/org/details.js +521 -0
  134. package/lib/commands/cuneiform/org/details.js.map +1 -0
  135. package/lib/commands/cuneiform/org/reset.d.ts +46 -0
  136. package/lib/commands/cuneiform/org/reset.js +135 -0
  137. package/lib/commands/cuneiform/org/reset.js.map +1 -0
  138. package/lib/commands/cuneiform/profile/request/cancel.d.ts +59 -0
  139. package/lib/commands/cuneiform/profile/request/cancel.js +202 -0
  140. package/lib/commands/cuneiform/profile/request/cancel.js.map +1 -0
  141. package/lib/commands/cuneiform/profile/request/delete.d.ts +59 -0
  142. package/lib/commands/cuneiform/profile/request/delete.js +223 -0
  143. package/lib/commands/cuneiform/profile/request/delete.js.map +1 -0
  144. package/lib/commands/cuneiform/profile/request/list.d.ts +35 -0
  145. package/lib/commands/cuneiform/profile/request/list.js +102 -0
  146. package/lib/commands/cuneiform/profile/request/list.js.map +1 -0
  147. package/lib/commands/cuneiform/profile.d.ts +90 -0
  148. package/lib/commands/cuneiform/profile.js +322 -0
  149. package/lib/commands/cuneiform/profile.js.map +1 -0
  150. package/lib/commands/cuneiform/summary/purge.d.ts +77 -0
  151. package/lib/commands/cuneiform/summary/purge.js +429 -0
  152. package/lib/commands/cuneiform/summary/purge.js.map +1 -0
  153. package/lib/commands/cuneiform/summary/reprofile.d.ts +60 -0
  154. package/lib/commands/cuneiform/summary/reprofile.js +236 -0
  155. package/lib/commands/cuneiform/summary/reprofile.js.map +1 -0
  156. package/lib/commands/cuneiform/summary/stop.d.ts +59 -0
  157. package/lib/commands/cuneiform/summary/stop.js +234 -0
  158. package/lib/commands/cuneiform/summary/stop.js.map +1 -0
  159. package/lib/commands/cuneiform/user/details.d.ts +73 -0
  160. package/lib/commands/cuneiform/user/details.js +391 -0
  161. package/lib/commands/cuneiform/user/details.js.map +1 -0
  162. package/lib/constants/index.d.ts +8 -0
  163. package/lib/constants/index.js +16 -0
  164. package/lib/constants/index.js.map +1 -0
  165. package/lib/constants/namespace-constants.d.ts +91 -0
  166. package/lib/constants/namespace-constants.js +211 -0
  167. package/lib/constants/namespace-constants.js.map +1 -0
  168. package/lib/debug/command-debug-proxy.d.ts +101 -0
  169. package/lib/debug/command-debug-proxy.js +171 -0
  170. package/lib/debug/command-debug-proxy.js.map +1 -0
  171. package/lib/debug/debug-logger.d.ts +85 -0
  172. package/lib/debug/debug-logger.js +133 -0
  173. package/lib/debug/debug-logger.js.map +1 -0
  174. package/lib/debug/index.d.ts +12 -0
  175. package/lib/debug/index.js +20 -0
  176. package/lib/debug/index.js.map +1 -0
  177. package/lib/debug/service-debug-proxy.d.ts +30 -0
  178. package/lib/debug/service-debug-proxy.js +102 -0
  179. package/lib/debug/service-debug-proxy.js.map +1 -0
  180. package/lib/hooks/prerun.d.ts +25 -0
  181. package/lib/hooks/prerun.js +47 -0
  182. package/lib/hooks/prerun.js.map +1 -0
  183. package/lib/mcp/config/mcp-config.d.ts +55 -0
  184. package/lib/mcp/config/mcp-config.js +51 -0
  185. package/lib/mcp/config/mcp-config.js.map +1 -0
  186. package/lib/mcp/config/pagination.d.ts +96 -0
  187. package/lib/mcp/config/pagination.js +108 -0
  188. package/lib/mcp/config/pagination.js.map +1 -0
  189. package/lib/mcp/config/system-prompts.d.ts +18 -0
  190. package/lib/mcp/config/system-prompts.js +92 -0
  191. package/lib/mcp/config/system-prompts.js.map +1 -0
  192. package/lib/mcp/errors.d.ts +23 -0
  193. package/lib/mcp/errors.js +27 -0
  194. package/lib/mcp/errors.js.map +1 -0
  195. package/lib/mcp/schemas/input-schemas.d.ts +327 -0
  196. package/lib/mcp/schemas/input-schemas.js +302 -0
  197. package/lib/mcp/schemas/input-schemas.js.map +1 -0
  198. package/lib/mcp/server.d.ts +40 -0
  199. package/lib/mcp/server.js +316 -0
  200. package/lib/mcp/server.js.map +1 -0
  201. package/lib/mcp/tools/contactpoint-tools.d.ts +14 -0
  202. package/lib/mcp/tools/contactpoint-tools.js +34 -0
  203. package/lib/mcp/tools/contactpoint-tools.js.map +1 -0
  204. package/lib/mcp/tools/definition-io-tools.d.ts +19 -0
  205. package/lib/mcp/tools/definition-io-tools.js +152 -0
  206. package/lib/mcp/tools/definition-io-tools.js.map +1 -0
  207. package/lib/mcp/tools/definition-tools.d.ts +51 -0
  208. package/lib/mcp/tools/definition-tools.js +199 -0
  209. package/lib/mcp/tools/definition-tools.js.map +1 -0
  210. package/lib/mcp/tools/index.d.ts +37 -0
  211. package/lib/mcp/tools/index.js +88 -0
  212. package/lib/mcp/tools/index.js.map +1 -0
  213. package/lib/mcp/tools/object-tools.d.ts +22 -0
  214. package/lib/mcp/tools/object-tools.js +306 -0
  215. package/lib/mcp/tools/object-tools.js.map +1 -0
  216. package/lib/mcp/tools/org-tools.d.ts +14 -0
  217. package/lib/mcp/tools/org-tools.js +177 -0
  218. package/lib/mcp/tools/org-tools.js.map +1 -0
  219. package/lib/mcp/tools/profile-tools.d.ts +59 -0
  220. package/lib/mcp/tools/profile-tools.js +213 -0
  221. package/lib/mcp/tools/profile-tools.js.map +1 -0
  222. package/lib/mcp/tools/summary-tools.d.ts +14 -0
  223. package/lib/mcp/tools/summary-tools.js +38 -0
  224. package/lib/mcp/tools/summary-tools.js.map +1 -0
  225. package/lib/mcp/tools/tool-factory.d.ts +63 -0
  226. package/lib/mcp/tools/tool-factory.js +146 -0
  227. package/lib/mcp/tools/tool-factory.js.map +1 -0
  228. package/lib/mcp/tools/user-tools.d.ts +25 -0
  229. package/lib/mcp/tools/user-tools.js +167 -0
  230. package/lib/mcp/tools/user-tools.js.map +1 -0
  231. package/lib/models/date-literal.d.ts +211 -0
  232. package/lib/models/date-literal.js +615 -0
  233. package/lib/models/date-literal.js.map +1 -0
  234. package/lib/models/object-describe-types.d.ts +173 -0
  235. package/lib/models/object-describe-types.js +9 -0
  236. package/lib/models/object-describe-types.js.map +1 -0
  237. package/lib/models/profile-request-types.d.ts +118 -0
  238. package/lib/models/profile-request-types.js +23 -0
  239. package/lib/models/profile-request-types.js.map +1 -0
  240. package/lib/models/profiling-execution-types.d.ts +154 -0
  241. package/lib/models/profiling-execution-types.js +14 -0
  242. package/lib/models/profiling-execution-types.js.map +1 -0
  243. package/lib/models/service-result.d.ts +114 -0
  244. package/lib/models/service-result.js +81 -0
  245. package/lib/models/service-result.js.map +1 -0
  246. package/lib/models/sfdmu-types.d.ts +53 -0
  247. package/lib/models/sfdmu-types.js +23 -0
  248. package/lib/models/sfdmu-types.js.map +1 -0
  249. package/lib/models/status-types.d.ts +38 -0
  250. package/lib/models/status-types.js +12 -0
  251. package/lib/models/status-types.js.map +1 -0
  252. package/lib/models/summary-bulk-types.d.ts +61 -0
  253. package/lib/models/summary-bulk-types.js +23 -0
  254. package/lib/models/summary-bulk-types.js.map +1 -0
  255. package/lib/models/user-details-types.d.ts +163 -0
  256. package/lib/models/user-details-types.js +9 -0
  257. package/lib/models/user-details-types.js.map +1 -0
  258. package/lib/models/year-range.d.ts +78 -0
  259. package/lib/models/year-range.js +153 -0
  260. package/lib/models/year-range.js.map +1 -0
  261. package/lib/operations/CompatibilityCheckOperation.d.ts +62 -0
  262. package/lib/operations/CompatibilityCheckOperation.js +102 -0
  263. package/lib/operations/CompatibilityCheckOperation.js.map +1 -0
  264. package/lib/operations/DefinitionCreateOperation.d.ts +411 -0
  265. package/lib/operations/DefinitionCreateOperation.js +1121 -0
  266. package/lib/operations/DefinitionCreateOperation.js.map +1 -0
  267. package/lib/operations/DefinitionExportOperation.d.ts +155 -0
  268. package/lib/operations/DefinitionExportOperation.js +281 -0
  269. package/lib/operations/DefinitionExportOperation.js.map +1 -0
  270. package/lib/operations/DefinitionImportOperation.d.ts +144 -0
  271. package/lib/operations/DefinitionImportOperation.js +357 -0
  272. package/lib/operations/DefinitionImportOperation.js.map +1 -0
  273. package/lib/operations/DefinitionListOperation.d.ts +66 -0
  274. package/lib/operations/DefinitionListOperation.js +108 -0
  275. package/lib/operations/DefinitionListOperation.js.map +1 -0
  276. package/lib/operations/DefinitionPurgeOperation.d.ts +199 -0
  277. package/lib/operations/DefinitionPurgeOperation.js +465 -0
  278. package/lib/operations/DefinitionPurgeOperation.js.map +1 -0
  279. package/lib/operations/DefinitionUpdateOperation.d.ts +78 -0
  280. package/lib/operations/DefinitionUpdateOperation.js +142 -0
  281. package/lib/operations/DefinitionUpdateOperation.js.map +1 -0
  282. package/lib/operations/OrgDetailsOperation.d.ts +253 -0
  283. package/lib/operations/OrgDetailsOperation.js +456 -0
  284. package/lib/operations/OrgDetailsOperation.js.map +1 -0
  285. package/lib/operations/OrgResetOperation.d.ts +114 -0
  286. package/lib/operations/OrgResetOperation.js +209 -0
  287. package/lib/operations/OrgResetOperation.js.map +1 -0
  288. package/lib/operations/ProfileOperation.d.ts +187 -0
  289. package/lib/operations/ProfileOperation.js +373 -0
  290. package/lib/operations/ProfileOperation.js.map +1 -0
  291. package/lib/operations/ProfileRequestCancelOperation.d.ts +59 -0
  292. package/lib/operations/ProfileRequestCancelOperation.js +137 -0
  293. package/lib/operations/ProfileRequestCancelOperation.js.map +1 -0
  294. package/lib/operations/ProfileRequestDeleteOperation.d.ts +64 -0
  295. package/lib/operations/ProfileRequestDeleteOperation.js +134 -0
  296. package/lib/operations/ProfileRequestDeleteOperation.js.map +1 -0
  297. package/lib/operations/ProfileRequestListOperation.d.ts +39 -0
  298. package/lib/operations/ProfileRequestListOperation.js +61 -0
  299. package/lib/operations/ProfileRequestListOperation.js.map +1 -0
  300. package/lib/operations/SummaryPurgeOperation.d.ts +134 -0
  301. package/lib/operations/SummaryPurgeOperation.js +257 -0
  302. package/lib/operations/SummaryPurgeOperation.js.map +1 -0
  303. package/lib/operations/SummaryReprofileOperation.d.ts +88 -0
  304. package/lib/operations/SummaryReprofileOperation.js +174 -0
  305. package/lib/operations/SummaryReprofileOperation.js.map +1 -0
  306. package/lib/operations/SummaryStopOperation.d.ts +87 -0
  307. package/lib/operations/SummaryStopOperation.js +175 -0
  308. package/lib/operations/SummaryStopOperation.js.map +1 -0
  309. package/lib/services/BulkExecutionService.d.ts +120 -0
  310. package/lib/services/BulkExecutionService.js +535 -0
  311. package/lib/services/BulkExecutionService.js.map +1 -0
  312. package/lib/services/CompatibilityService.d.ts +81 -0
  313. package/lib/services/CompatibilityService.js +118 -0
  314. package/lib/services/CompatibilityService.js.map +1 -0
  315. package/lib/services/ConfigureMode.d.ts +85 -0
  316. package/lib/services/ConfigureMode.js +390 -0
  317. package/lib/services/ConfigureMode.js.map +1 -0
  318. package/lib/services/ContactPointService.d.ts +111 -0
  319. package/lib/services/ContactPointService.js +286 -0
  320. package/lib/services/ContactPointService.js.map +1 -0
  321. package/lib/services/DataAvailabilityService.d.ts +81 -0
  322. package/lib/services/DataAvailabilityService.js +128 -0
  323. package/lib/services/DataAvailabilityService.js.map +1 -0
  324. package/lib/services/DefinitionFieldGenerationService.d.ts +309 -0
  325. package/lib/services/DefinitionFieldGenerationService.js +795 -0
  326. package/lib/services/DefinitionFieldGenerationService.js.map +1 -0
  327. package/lib/services/DefinitionQueryBuilder.d.ts +59 -0
  328. package/lib/services/DefinitionQueryBuilder.js +234 -0
  329. package/lib/services/DefinitionQueryBuilder.js.map +1 -0
  330. package/lib/services/ObjectDescribeService.d.ts +436 -0
  331. package/lib/services/ObjectDescribeService.js +869 -0
  332. package/lib/services/ObjectDescribeService.js.map +1 -0
  333. package/lib/services/ObjectFilteringService.d.ts +400 -0
  334. package/lib/services/ObjectFilteringService.js +878 -0
  335. package/lib/services/ObjectFilteringService.js.map +1 -0
  336. package/lib/services/ObjectListCommandService.d.ts +429 -0
  337. package/lib/services/ObjectListCommandService.js +873 -0
  338. package/lib/services/ObjectListCommandService.js.map +1 -0
  339. package/lib/services/ObjectListService.d.ts +201 -0
  340. package/lib/services/ObjectListService.js +345 -0
  341. package/lib/services/ObjectListService.js.map +1 -0
  342. package/lib/services/OrgInfoService.d.ts +485 -0
  343. package/lib/services/OrgInfoService.js +1122 -0
  344. package/lib/services/OrgInfoService.js.map +1 -0
  345. package/lib/services/PollingService.d.ts +105 -0
  346. package/lib/services/PollingService.js +117 -0
  347. package/lib/services/PollingService.js.map +1 -0
  348. package/lib/services/ProfileRequestService.d.ts +186 -0
  349. package/lib/services/ProfileRequestService.js +555 -0
  350. package/lib/services/ProfileRequestService.js.map +1 -0
  351. package/lib/services/ProfilingDefinitionService.d.ts +535 -0
  352. package/lib/services/ProfilingDefinitionService.js +981 -0
  353. package/lib/services/ProfilingDefinitionService.js.map +1 -0
  354. package/lib/services/ProfilingExecutionService.d.ts +122 -0
  355. package/lib/services/ProfilingExecutionService.js +320 -0
  356. package/lib/services/ProfilingExecutionService.js.map +1 -0
  357. package/lib/services/ProfilingSummaryService.d.ts +292 -0
  358. package/lib/services/ProfilingSummaryService.js +685 -0
  359. package/lib/services/ProfilingSummaryService.js.map +1 -0
  360. package/lib/services/RecordTypeService.d.ts +129 -0
  361. package/lib/services/RecordTypeService.js +284 -0
  362. package/lib/services/RecordTypeService.js.map +1 -0
  363. package/lib/services/SFDMUService.d.ts +133 -0
  364. package/lib/services/SFDMUService.js +295 -0
  365. package/lib/services/SFDMUService.js.map +1 -0
  366. package/lib/services/TabDetectionService.d.ts +105 -0
  367. package/lib/services/TabDetectionService.js +206 -0
  368. package/lib/services/TabDetectionService.js.map +1 -0
  369. package/lib/services/UnconfigureMode.d.ts +74 -0
  370. package/lib/services/UnconfigureMode.js +378 -0
  371. package/lib/services/UnconfigureMode.js.map +1 -0
  372. package/lib/services/UserConfigurationService.d.ts +155 -0
  373. package/lib/services/UserConfigurationService.js +573 -0
  374. package/lib/services/UserConfigurationService.js.map +1 -0
  375. package/lib/services/UserConfigurationTypes.d.ts +181 -0
  376. package/lib/services/UserConfigurationTypes.js +14 -0
  377. package/lib/services/UserConfigurationTypes.js.map +1 -0
  378. package/lib/services/UserReadinessService.d.ts +330 -0
  379. package/lib/services/UserReadinessService.js +831 -0
  380. package/lib/services/UserReadinessService.js.map +1 -0
  381. package/lib/services/constants.d.ts +53 -0
  382. package/lib/services/constants.js +71 -0
  383. package/lib/services/constants.js.map +1 -0
  384. package/lib/services/namespace-constants.d.ts +1 -0
  385. package/lib/services/namespace-constants.js +11 -0
  386. package/lib/services/namespace-constants.js.map +1 -0
  387. package/lib/services/validation.d.ts +47 -0
  388. package/lib/services/validation.js +119 -0
  389. package/lib/services/validation.js.map +1 -0
  390. package/lib/utils/batch-processor.d.ts +13 -0
  391. package/lib/utils/batch-processor.js +39 -0
  392. package/lib/utils/batch-processor.js.map +1 -0
  393. package/lib/utils/formatting/availability-grid.d.ts +81 -0
  394. package/lib/utils/formatting/availability-grid.js +94 -0
  395. package/lib/utils/formatting/availability-grid.js.map +1 -0
  396. package/lib/utils/formatting/business-process-grid.d.ts +51 -0
  397. package/lib/utils/formatting/business-process-grid.js +58 -0
  398. package/lib/utils/formatting/business-process-grid.js.map +1 -0
  399. package/lib/utils/formatting/command-display.d.ts +154 -0
  400. package/lib/utils/formatting/command-display.js +154 -0
  401. package/lib/utils/formatting/command-display.js.map +1 -0
  402. package/lib/utils/formatting/definition-create-display.d.ts +118 -0
  403. package/lib/utils/formatting/definition-create-display.js +231 -0
  404. package/lib/utils/formatting/definition-create-display.js.map +1 -0
  405. package/lib/utils/formatting/empty-states.d.ts +35 -0
  406. package/lib/utils/formatting/empty-states.js +70 -0
  407. package/lib/utils/formatting/empty-states.js.map +1 -0
  408. package/lib/utils/formatting/errors.d.ts +33 -0
  409. package/lib/utils/formatting/errors.js +72 -0
  410. package/lib/utils/formatting/errors.js.map +1 -0
  411. package/lib/utils/formatting/field-types.d.ts +32 -0
  412. package/lib/utils/formatting/field-types.js +88 -0
  413. package/lib/utils/formatting/field-types.js.map +1 -0
  414. package/lib/utils/formatting/index.d.ts +29 -0
  415. package/lib/utils/formatting/index.js +28 -0
  416. package/lib/utils/formatting/index.js.map +1 -0
  417. package/lib/utils/formatting/indicators.d.ts +113 -0
  418. package/lib/utils/formatting/indicators.js +161 -0
  419. package/lib/utils/formatting/indicators.js.map +1 -0
  420. package/lib/utils/formatting/loading-messages.d.ts +37 -0
  421. package/lib/utils/formatting/loading-messages.js +50 -0
  422. package/lib/utils/formatting/loading-messages.js.map +1 -0
  423. package/lib/utils/formatting/namespace-display.d.ts +31 -0
  424. package/lib/utils/formatting/namespace-display.js +64 -0
  425. package/lib/utils/formatting/namespace-display.js.map +1 -0
  426. package/lib/utils/formatting/numbers.d.ts +73 -0
  427. package/lib/utils/formatting/numbers.js +187 -0
  428. package/lib/utils/formatting/numbers.js.map +1 -0
  429. package/lib/utils/formatting/object-describe-display.d.ts +114 -0
  430. package/lib/utils/formatting/object-describe-display.js +440 -0
  431. package/lib/utils/formatting/object-describe-display.js.map +1 -0
  432. package/lib/utils/formatting/object-list-display.d.ts +213 -0
  433. package/lib/utils/formatting/object-list-display.js +672 -0
  434. package/lib/utils/formatting/object-list-display.js.map +1 -0
  435. package/lib/utils/formatting/org-identity.d.ts +15 -0
  436. package/lib/utils/formatting/org-identity.js +28 -0
  437. package/lib/utils/formatting/org-identity.js.map +1 -0
  438. package/lib/utils/formatting/record-age-grid.d.ts +41 -0
  439. package/lib/utils/formatting/record-age-grid.js +56 -0
  440. package/lib/utils/formatting/record-age-grid.js.map +1 -0
  441. package/lib/utils/formatting/sections.d.ts +108 -0
  442. package/lib/utils/formatting/sections.js +150 -0
  443. package/lib/utils/formatting/sections.js.map +1 -0
  444. package/lib/utils/formatting/tables.d.ts +90 -0
  445. package/lib/utils/formatting/tables.js +113 -0
  446. package/lib/utils/formatting/tables.js.map +1 -0
  447. package/lib/utils/formatting/user-details-display.d.ts +101 -0
  448. package/lib/utils/formatting/user-details-display.js +425 -0
  449. package/lib/utils/formatting/user-details-display.js.map +1 -0
  450. package/lib/utils/pagination/index.d.ts +11 -0
  451. package/lib/utils/pagination/index.js +18 -0
  452. package/lib/utils/pagination/index.js.map +1 -0
  453. package/lib/utils/pagination/keypress-reader.d.ts +20 -0
  454. package/lib/utils/pagination/keypress-reader.js +63 -0
  455. package/lib/utils/pagination/keypress-reader.js.map +1 -0
  456. package/lib/utils/pagination/paginate-output.d.ts +48 -0
  457. package/lib/utils/pagination/paginate-output.js +136 -0
  458. package/lib/utils/pagination/paginate-output.js.map +1 -0
  459. package/messages/compatibility.check.md +71 -0
  460. package/messages/cuneiform.access.md +138 -0
  461. package/messages/definition.create.md +511 -0
  462. package/messages/definition.export.md +84 -0
  463. package/messages/definition.get.md +147 -0
  464. package/messages/definition.import.md +65 -0
  465. package/messages/definition.list.md +264 -0
  466. package/messages/definition.purge.md +318 -0
  467. package/messages/definition.update.md +118 -0
  468. package/messages/mcp.serve.md +66 -0
  469. package/messages/object.describe.md +201 -0
  470. package/messages/object.list.md +443 -0
  471. package/messages/org.details.md +386 -0
  472. package/messages/org.reset.md +71 -0
  473. package/messages/profile.md +231 -0
  474. package/messages/profile.request.cancel.md +143 -0
  475. package/messages/profile.request.delete.md +139 -0
  476. package/messages/profile.request.list.md +89 -0
  477. package/messages/summary.purge.md +218 -0
  478. package/messages/summary.reprofile.md +150 -0
  479. package/messages/summary.stop.md +157 -0
  480. package/messages/user.details.md +501 -0
  481. package/oclif.lock +2887 -2149
  482. package/oclif.manifest.json +2813 -31
  483. package/package.json +94 -19
  484. package/lib/commands/cuneiform/about.d.ts +0 -13
  485. package/lib/commands/cuneiform/about.js +0 -26
  486. package/lib/commands/cuneiform/about.js.map +0 -1
  487. package/lib/commands/hello/world.d.ts +0 -14
  488. package/lib/commands/hello/world.js +0 -27
  489. package/lib/commands/hello/world.js.map +0 -1
  490. package/lib/index.d.ts +0 -2
  491. package/lib/index.js +0 -2
  492. package/lib/index.js.map +0 -1
  493. package/messages/cuneiform.about.md +0 -19
  494. package/messages/hello.world.md +0 -29
@@ -0,0 +1,1122 @@
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 { ServiceErrorCodes, sanitizeSoqlIdentifier } from '../adapters/errors.js';
10
+ import { CuneiformQueryBuilder } from '../adapters/soql/cuneiform-query-builder.js';
11
+ import { CUNEIFORM_NAMESPACE, getProductName, CLOUD_NAMESPACE_MAP } from './namespace-constants.js';
12
+ /**
13
+ * License name patterns that indicate Sales Cloud.
14
+ */
15
+ const SALES_CLOUD_LICENSE_PATTERNS = ['Salesforce', 'Sales Cloud', 'Sales User'];
16
+ /**
17
+ * License name patterns that indicate Service Cloud.
18
+ */
19
+ const SERVICE_CLOUD_LICENSE_PATTERNS = ['Salesforce', 'Service Cloud', 'Service User'];
20
+ /**
21
+ * PermissionSetLicense patterns that indicate installed cloud products.
22
+ * Each entry maps label/name patterns to a cloud product name.
23
+ */
24
+ const PSL_CLOUD_PATTERNS = [
25
+ { patterns: ['Einstein Analytics', 'CRM Analytics', 'Einstein Prediction'], cloudName: 'Analytics Cloud' },
26
+ { patterns: ['CPQ', 'Configure Price Quote', 'Revenue Cloud'], cloudName: 'Revenue Cloud' },
27
+ { patterns: ['B2C Commerce', 'B2B Commerce', 'Commerce Cloud'], cloudName: 'Commerce Cloud' },
28
+ { patterns: ['Marketing Cloud', 'Pardot', 'Account Engagement'], cloudName: 'Marketing Cloud' },
29
+ { patterns: ['Tableau', 'Tableau CRM'], cloudName: 'Tableau' },
30
+ { patterns: ['Education Cloud', 'EDA '], cloudName: 'Education Cloud' },
31
+ ];
32
+ /**
33
+ * Service for aggregating org-level metadata.
34
+ *
35
+ * Provides methods to retrieve org identity, API limits, installed packages,
36
+ * active namespaces, and Cuneiform version information.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const service = new OrgInfoService({
41
+ * connectionFacade,
42
+ * soqlAdapter,
43
+ * toolingAdapter, // optional
44
+ * });
45
+ *
46
+ * const result = await service.getOrgInfo();
47
+ * if (result.success) {
48
+ * console.log(`Org: ${result.data.identity.organizationName}`);
49
+ * console.log(`Cuneiform: ${result.data.cuneiformVersion ?? 'Not installed'}`);
50
+ * }
51
+ * ```
52
+ */
53
+ export class OrgInfoService {
54
+ connectionFacade;
55
+ soqlAdapter;
56
+ toolingAdapter;
57
+ restAdapter;
58
+ logger;
59
+ restClient;
60
+ constructor(config) {
61
+ this.connectionFacade = config.connectionFacade;
62
+ this.soqlAdapter = config.soqlAdapter;
63
+ this.toolingAdapter = config.toolingAdapter;
64
+ this.restAdapter = config.restAdapter;
65
+ this.logger = config.logger;
66
+ this.restClient = config.restClient;
67
+ }
68
+ /**
69
+ * Classifies the org type based on Organization record data.
70
+ *
71
+ * @param isSandbox - Whether the org is marked as sandbox
72
+ * @param orgType - The OrganizationType field value
73
+ * @param trialExpirationDate - Trial expiration date if set
74
+ * @returns The classified OrgType
75
+ */
76
+ static classifyOrgType(isSandbox, orgType, trialExpirationDate) {
77
+ if (isSandbox) {
78
+ return 'Sandbox';
79
+ }
80
+ const normalizedType = orgType?.toLowerCase() ?? '';
81
+ if (normalizedType.includes('scratch')) {
82
+ return 'Scratch';
83
+ }
84
+ if (normalizedType.includes('developer')) {
85
+ return 'Developer';
86
+ }
87
+ if (trialExpirationDate) {
88
+ return 'Trial';
89
+ }
90
+ return 'Production';
91
+ }
92
+ // ── Private static methods ──────────────────────────────────────────
93
+ /**
94
+ * Transforms raw limits response to OrgLimit format.
95
+ *
96
+ * Calculates percentage utilization from Max and Remaining values.
97
+ * Returns 0% if Max is 0 to avoid division by zero.
98
+ */
99
+ static transformLimit(name, rawLimit) {
100
+ const used = rawLimit.Max - rawLimit.Remaining;
101
+ const percentUsed = rawLimit.Max > 0 ? Math.round((used / rawLimit.Max) * 100 * 10) / 10 : 0;
102
+ return { name, max: rawLimit.Max, used, percentUsed };
103
+ }
104
+ /**
105
+ * Maps InstalledPackageRecord to InstalledPackage.
106
+ *
107
+ * Formats version as semantic version string (Major.Minor.Patch.Build)
108
+ * and looks up human-readable product name by namespace prefix.
109
+ */
110
+ static mapPackage(record) {
111
+ const version = record.SubscriberPackageVersion;
112
+ const versionNumber = `${version.MajorVersion}.${version.MinorVersion}.${version.PatchVersion}.${version.BuildNumber}`;
113
+ const namespace = record.SubscriberPackage.NamespacePrefix;
114
+ return {
115
+ id: record.Id,
116
+ namespacePrefix: namespace,
117
+ name: record.SubscriberPackage.Name,
118
+ versionNumber,
119
+ isManaged: Boolean(namespace),
120
+ productName: namespace ? getProductName(namespace) : undefined,
121
+ };
122
+ }
123
+ /**
124
+ * Extracts active namespaces from installed packages.
125
+ */
126
+ static extractActiveNamespaces(packages) {
127
+ const namespaces = packages.filter((p) => p.namespacePrefix).map((p) => p.namespacePrefix);
128
+ return [...new Set(namespaces)].sort();
129
+ }
130
+ /**
131
+ * Finds the Cuneiform package version from installed packages.
132
+ */
133
+ static findCuneiformVersion(packages) {
134
+ const cuneiformPackage = packages.find((p) => p.namespacePrefix === CUNEIFORM_NAMESPACE);
135
+ return cuneiformPackage?.versionNumber ?? null;
136
+ }
137
+ /**
138
+ * Detects additional cloud products from PermissionSetLicense data.
139
+ */
140
+ static detectPslClouds(licenses) {
141
+ const pslLicenses = licenses.filter((lic) => lic.type === 'permissionSet');
142
+ const clouds = [];
143
+ for (const pslEntry of PSL_CLOUD_PATTERNS) {
144
+ const match = pslLicenses.find((lic) => pslEntry.patterns.some((pattern) => lic.masterLabel.includes(pattern) || lic.name.includes(pattern)));
145
+ if (match) {
146
+ clouds.push({
147
+ name: pslEntry.cloudName,
148
+ type: 'license',
149
+ installed: true,
150
+ totalLicenses: match.totalLicenses,
151
+ usedLicenses: match.usedLicenses,
152
+ status: match.status,
153
+ });
154
+ }
155
+ }
156
+ return clouds;
157
+ }
158
+ /**
159
+ * Groups objects by namespace from global describe result.
160
+ *
161
+ * Extracts namespace prefixes from custom object names matching pattern:
162
+ * Namespace__ObjectName__c
163
+ *
164
+ * @param globalDescribe - The global describe result
165
+ * @returns Map of namespace prefix to object names and count
166
+ */
167
+ static groupNamespaceObjects(globalDescribe) {
168
+ const namespaceGroups = new Map();
169
+ for (const obj of globalDescribe.sobjects) {
170
+ // Custom objects with namespaces: Namespace__ObjectName__c (standard/custom only)
171
+ // Excludes __mdt (custom metadata), __e (platform events), __b (big objects)
172
+ const match = obj.name.match(/^([A-Za-z0-9]+)__\w+__c$/);
173
+ if (match) {
174
+ const namespace = match[1];
175
+ const group = namespaceGroups.get(namespace) ?? { count: 0, objects: [] };
176
+ group.count++;
177
+ group.objects.push(obj.name);
178
+ namespaceGroups.set(namespace, group);
179
+ }
180
+ }
181
+ return namespaceGroups;
182
+ }
183
+ /**
184
+ * Builds the SOQL string for a LIMIT 0 field-existence probe, sanitizing both
185
+ * identifiers via sanitizeSoqlIdentifier. Returns null when either identifier
186
+ * is invalid — callers MUST treat null as "field cannot exist" without invoking
187
+ * the SOQL adapter.
188
+ *
189
+ * Pure, side-effect-free, and exposed at the class level so the sanitizer
190
+ * hardening introduced in CLI-3174 can be unit-tested directly.
191
+ */
192
+ static buildProbeQuery(objectName, fieldName) {
193
+ try {
194
+ const obj = sanitizeSoqlIdentifier(objectName);
195
+ const field = sanitizeSoqlIdentifier(fieldName);
196
+ return `SELECT ${field} FROM ${obj} LIMIT 0`;
197
+ }
198
+ catch {
199
+ return null;
200
+ }
201
+ }
202
+ // ── Public instance methods ─────────────────────────────────────────
203
+ /**
204
+ * Retrieves complete org information.
205
+ *
206
+ * Executes multiple API calls in parallel for performance:
207
+ * - Identity + Organization SOQL (getOrgIdentity)
208
+ * - Limits API (getOrgLimits)
209
+ * - Installed packages via Tooling API (getInstalledPackages)
210
+ *
211
+ * @returns ServiceResult containing complete OrgInfo
212
+ */
213
+ async getOrgInfo() {
214
+ const startTime = Date.now();
215
+ const warnings = [];
216
+ const emptyResult = {
217
+ identity: { userId: '', organizationId: '', username: '' },
218
+ limits: { limits: {} },
219
+ packages: [],
220
+ activeNamespaces: [],
221
+ cuneiformVersion: null,
222
+ };
223
+ // REST API path: delegate to server when restClient is available
224
+ if (this.restClient) {
225
+ return this.getOrgInfoViaRest(startTime);
226
+ }
227
+ try {
228
+ this.logger?.log('Fetching org info...');
229
+ // Execute parallel API calls
230
+ const [identityResult, limitsResult, packagesResult] = await Promise.all([
231
+ this.getOrgIdentity(),
232
+ this.getOrgLimits(),
233
+ this.getInstalledPackages(),
234
+ ]);
235
+ // Handle identity result
236
+ if (!identityResult.success) {
237
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_INFO_QUERY_FAILED, identityResult.message ?? 'Failed to get org identity', {
238
+ metadata: { duration: Date.now() - startTime },
239
+ });
240
+ }
241
+ // Handle limits result (warning if failed, not fatal)
242
+ let limits = emptyResult.limits;
243
+ if (!limitsResult.success) {
244
+ warnings.push(`Limits query failed: ${limitsResult.message ?? 'Unknown error'}`);
245
+ }
246
+ else {
247
+ limits = limitsResult.data;
248
+ }
249
+ // Handle packages result (warning if failed, not fatal)
250
+ let packages = emptyResult.packages;
251
+ if (!packagesResult.success) {
252
+ warnings.push(`Package query failed: ${packagesResult.message ?? 'Unknown error'}`);
253
+ }
254
+ else {
255
+ packages = packagesResult.data;
256
+ }
257
+ // Extract namespaces and Cuneiform version
258
+ const activeNamespaces = OrgInfoService.extractActiveNamespaces(packages);
259
+ const cuneiformVersion = OrgInfoService.findCuneiformVersion(packages);
260
+ const orgInfo = {
261
+ identity: identityResult.data,
262
+ limits,
263
+ packages,
264
+ activeNamespaces,
265
+ cuneiformVersion,
266
+ };
267
+ const duration = Date.now() - startTime;
268
+ this.logger?.log(`Org info retrieved in ${duration}ms`);
269
+ return createSuccessResult(orgInfo, {
270
+ message: `Org info retrieved for ${identityResult.data.organizationName ?? identityResult.data.organizationId}`,
271
+ warnings: warnings.length > 0 ? warnings : undefined,
272
+ metadata: { duration },
273
+ });
274
+ }
275
+ catch (error) {
276
+ const errorMessage = error instanceof Error ? error.message : String(error);
277
+ this.logger?.log(`Org info query failed: ${errorMessage}`);
278
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_INFO_QUERY_FAILED, errorMessage, {
279
+ metadata: { duration: Date.now() - startTime },
280
+ });
281
+ }
282
+ }
283
+ /**
284
+ * Retrieves org identity information.
285
+ *
286
+ * Combines connection.identity() with Organization SOQL query for complete info.
287
+ *
288
+ * @returns ServiceResult containing OrgIdentity
289
+ */
290
+ async getOrgIdentity() {
291
+ const startTime = Date.now();
292
+ const emptyResult = { userId: '', organizationId: '', username: '' };
293
+ try {
294
+ this.logger?.log('Fetching org identity...');
295
+ // Build Organization SOQL using CuneiformQueryBuilder
296
+ const orgSoql = new CuneiformQueryBuilder()
297
+ .select(['Id', 'Name', 'IsSandbox', 'OrganizationType', 'NamespacePrefix'])
298
+ .from('Organization')
299
+ .limit(1)
300
+ .toSOQL();
301
+ // Execute identity and org query in parallel
302
+ const [identity, orgResult] = await Promise.all([
303
+ this.connectionFacade.identity(),
304
+ this.soqlAdapter.query(orgSoql),
305
+ ]);
306
+ const orgRecord = orgResult.success && orgResult.data.records.length > 0 ? orgResult.data.records[0] : null;
307
+ const result = {
308
+ userId: identity.user_id,
309
+ organizationId: identity.organization_id,
310
+ username: identity.username,
311
+ organizationName: orgRecord?.Name,
312
+ isSandbox: orgRecord?.IsSandbox,
313
+ organizationType: orgRecord?.OrganizationType,
314
+ namespacePrefix: orgRecord?.NamespacePrefix ?? undefined,
315
+ };
316
+ const duration = Date.now() - startTime;
317
+ this.logger?.log(`Org identity retrieved: ${result.organizationName ?? result.organizationId}`);
318
+ return createSuccessResult(result, {
319
+ message: `Identity retrieved for ${result.username}`,
320
+ metadata: { duration },
321
+ });
322
+ }
323
+ catch (error) {
324
+ const errorMessage = error instanceof Error ? error.message : String(error);
325
+ this.logger?.log(`Org identity failed: ${errorMessage}`);
326
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_IDENTITY_FAILED, errorMessage, {
327
+ metadata: { duration: Date.now() - startTime },
328
+ });
329
+ }
330
+ }
331
+ /**
332
+ * Retrieves org API limits.
333
+ *
334
+ * Calls /limits REST endpoint and transforms to OrgLimits format.
335
+ *
336
+ * @returns ServiceResult containing OrgLimits
337
+ */
338
+ async getOrgLimits() {
339
+ const startTime = Date.now();
340
+ const emptyResult = { limits: {} };
341
+ try {
342
+ this.logger?.log('Fetching org limits...');
343
+ const response = await this.connectionFacade.request('/limits');
344
+ // Transform response
345
+ const limits = {};
346
+ for (const [name, rawLimit] of Object.entries(response)) {
347
+ limits[name] = OrgInfoService.transformLimit(name, rawLimit);
348
+ }
349
+ const result = {
350
+ limits,
351
+ dailyApiRequests: limits['DailyApiRequests'],
352
+ dataStorageMB: limits['DataStorageMB'],
353
+ fileStorageMB: limits['FileStorageMB'],
354
+ dailyBulkApiRequests: limits['DailyBulkApiRequests'],
355
+ dailyBulkV2QueryJobs: limits['DailyBulkV2QueryJobs'],
356
+ dailyAsyncApexExecutions: limits['DailyAsyncApexExecutions'],
357
+ dailyStreamingApiEvents: limits['DailyStreamingApiEvents'],
358
+ };
359
+ const duration = Date.now() - startTime;
360
+ this.logger?.log(`Org limits retrieved: ${Object.keys(limits).length} limits`);
361
+ return createSuccessResult(result, {
362
+ message: `Retrieved ${Object.keys(limits).length} limits`,
363
+ metadata: { duration },
364
+ });
365
+ }
366
+ catch (error) {
367
+ const errorMessage = error instanceof Error ? error.message : String(error);
368
+ this.logger?.log(`Org limits failed: ${errorMessage}`);
369
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_LIMITS_FAILED, errorMessage, {
370
+ metadata: { duration: Date.now() - startTime },
371
+ });
372
+ }
373
+ }
374
+ /**
375
+ * Retrieves installed packages via Tooling API.
376
+ *
377
+ * If Tooling adapter is not provided, returns empty array with warning.
378
+ *
379
+ * @returns ServiceResult containing array of InstalledPackage
380
+ */
381
+ async getInstalledPackages() {
382
+ const startTime = Date.now();
383
+ if (!this.toolingAdapter) {
384
+ this.logger?.log('Tooling adapter not provided, skipping package query');
385
+ return createSuccessResult([], {
386
+ message: 'Package query skipped (no Tooling adapter)',
387
+ warnings: ['Tooling adapter not provided, cannot query installed packages'],
388
+ metadata: { duration: Date.now() - startTime },
389
+ });
390
+ }
391
+ try {
392
+ this.logger?.log('Fetching installed packages...');
393
+ // PTA-1436: Cuneiform version is sourced from InstalledSubscriberPackage (Tooling API).
394
+ // The version number is constructed from MajorVersion.MinorVersion.PatchVersion.BuildNumber
395
+ // on the SubscriberPackageVersion relationship. License status is not exposed via standard
396
+ // Salesforce APIs — see getCuneiformPackageInfo() which defaults to 'Active' if installed.
397
+ const soql = new CuneiformQueryBuilder()
398
+ .select([
399
+ 'Id',
400
+ 'SubscriberPackage.Id',
401
+ 'SubscriberPackage.Name',
402
+ 'SubscriberPackage.NamespacePrefix',
403
+ 'SubscriberPackageVersion.Id',
404
+ 'SubscriberPackageVersion.MajorVersion',
405
+ 'SubscriberPackageVersion.MinorVersion',
406
+ 'SubscriberPackageVersion.PatchVersion',
407
+ 'SubscriberPackageVersion.BuildNumber',
408
+ ])
409
+ .from('InstalledSubscriberPackage')
410
+ .orderBy('SubscriberPackage.Name', 'ASC')
411
+ .toSOQL();
412
+ const result = await this.toolingAdapter.query(soql);
413
+ if (!result.success) {
414
+ return createFailureResult([], ServiceErrorCodes.ORG_PACKAGE_QUERY_FAILED, result.message ?? 'Package query failed', {
415
+ metadata: { duration: Date.now() - startTime },
416
+ });
417
+ }
418
+ const packages = result.data.records.map((record) => OrgInfoService.mapPackage(record));
419
+ const duration = Date.now() - startTime;
420
+ this.logger?.log(`Found ${packages.length} installed packages`);
421
+ return createSuccessResult(packages, {
422
+ message: `Found ${packages.length} installed packages`,
423
+ metadata: { duration },
424
+ });
425
+ }
426
+ catch (error) {
427
+ const errorMessage = error instanceof Error ? error.message : String(error);
428
+ this.logger?.log(`Package query failed: ${errorMessage}`);
429
+ return createFailureResult([], ServiceErrorCodes.ORG_PACKAGE_QUERY_FAILED, errorMessage, {
430
+ metadata: { duration: Date.now() - startTime },
431
+ });
432
+ }
433
+ }
434
+ /**
435
+ * Retrieves active namespaces from installed packages.
436
+ *
437
+ * @returns ServiceResult containing array of namespace strings
438
+ */
439
+ async getActiveNamespaces() {
440
+ const startTime = Date.now();
441
+ try {
442
+ const packagesResult = await this.getInstalledPackages();
443
+ if (!packagesResult.success) {
444
+ return createFailureResult([], ServiceErrorCodes.ORG_NAMESPACE_QUERY_FAILED, packagesResult.message ?? 'Failed to get namespaces', {
445
+ metadata: { duration: Date.now() - startTime },
446
+ });
447
+ }
448
+ const namespaces = OrgInfoService.extractActiveNamespaces(packagesResult.data);
449
+ const duration = Date.now() - startTime;
450
+ return createSuccessResult(namespaces, {
451
+ message: `Found ${namespaces.length} active namespaces`,
452
+ metadata: { duration },
453
+ });
454
+ }
455
+ catch (error) {
456
+ const errorMessage = error instanceof Error ? error.message : String(error);
457
+ return createFailureResult([], ServiceErrorCodes.ORG_NAMESPACE_QUERY_FAILED, errorMessage, {
458
+ metadata: { duration: Date.now() - startTime },
459
+ });
460
+ }
461
+ }
462
+ /**
463
+ * Retrieves the Cuneiform version if installed.
464
+ *
465
+ * @returns ServiceResult containing version string or null if not installed
466
+ */
467
+ async getCuneiformVersion() {
468
+ const startTime = Date.now();
469
+ try {
470
+ const packagesResult = await this.getInstalledPackages();
471
+ if (!packagesResult.success) {
472
+ return createFailureResult(null, ServiceErrorCodes.ORG_CUNEIFORM_VERSION_FAILED, packagesResult.message ?? 'Failed to get Cuneiform version', {
473
+ metadata: { duration: Date.now() - startTime },
474
+ });
475
+ }
476
+ const version = OrgInfoService.findCuneiformVersion(packagesResult.data);
477
+ const duration = Date.now() - startTime;
478
+ return createSuccessResult(version, {
479
+ message: version ? `Cuneiform version: ${version}` : 'Cuneiform not installed',
480
+ metadata: { duration },
481
+ });
482
+ }
483
+ catch (error) {
484
+ const errorMessage = error instanceof Error ? error.message : String(error);
485
+ return createFailureResult(null, ServiceErrorCodes.ORG_CUNEIFORM_VERSION_FAILED, errorMessage, {
486
+ metadata: { duration: Date.now() - startTime },
487
+ });
488
+ }
489
+ }
490
+ /**
491
+ * Fetches the describeGlobal result from the REST adapter.
492
+ *
493
+ * Used by OrgDetailsOperation to cache the result across multiple service calls,
494
+ * avoiding redundant API round-trips for features, clouds, and namespace detection.
495
+ *
496
+ * @returns ServiceResult containing DescribeGlobalResult
497
+ */
498
+ async fetchDescribeGlobal() {
499
+ if (!this.restAdapter) {
500
+ return createFailureResult({ maxBatchSize: 0, sobjects: [] }, ServiceErrorCodes.ORG_FEATURES_QUERY_FAILED, 'REST adapter not available');
501
+ }
502
+ return this.restAdapter.describeGlobal();
503
+ }
504
+ /**
505
+ * Detects org features via object/field probing.
506
+ *
507
+ * Checks for:
508
+ * - Multi-Currency: CurrencyType object exists in describeGlobal
509
+ * - Enhanced Notes: ContentNote object is queryable
510
+ * - State/Country Picklists: BillingCountryCode field exists on Account
511
+ * - Territory Management: Territory2 object exists
512
+ * - Person Accounts: IsPersonAccount field exists on Account
513
+ * - Digital Experiences: Network object exists in describeGlobal
514
+ * - Einstein AI: AIRecordInsight object exists in describeGlobal
515
+ *
516
+ * @param cachedGlobal - Optional pre-fetched describeGlobal result to avoid redundant API calls
517
+ * @returns ServiceResult containing OrgFeatures
518
+ */
519
+ async getOrgFeatures(cachedGlobal) {
520
+ const startTime = Date.now();
521
+ const emptyResult = {
522
+ multiCurrency: false,
523
+ enhancedNotes: false,
524
+ stateCountryPicklists: false,
525
+ territoryManagement: false,
526
+ personAccounts: false,
527
+ digitalExperiences: false,
528
+ einsteinAI: false,
529
+ };
530
+ if (!this.restAdapter) {
531
+ this.logger?.log('REST adapter not provided, skipping feature detection');
532
+ return createSuccessResult(emptyResult, {
533
+ message: 'Feature detection skipped (no REST adapter)',
534
+ warnings: ['REST adapter not provided, cannot detect org features'],
535
+ metadata: { duration: Date.now() - startTime },
536
+ });
537
+ }
538
+ try {
539
+ this.logger?.log('Detecting org features...');
540
+ // Use provided cache if available; otherwise fetch fresh
541
+ const globalResult = cachedGlobal ?? (await this.restAdapter.describeGlobal());
542
+ if (!globalResult.success) {
543
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_FEATURES_QUERY_FAILED, globalResult.message ?? 'Failed to detect org features', {
544
+ metadata: { duration: Date.now() - startTime },
545
+ });
546
+ }
547
+ const sobjectNames = new Set(globalResult.data.sobjects.map((obj) => obj.name));
548
+ // Check Multi-Currency: CurrencyType object exists
549
+ const multiCurrency = sobjectNames.has('CurrencyType');
550
+ // Check Enhanced Notes: ContentNote object exists and is queryable
551
+ const contentNoteObj = globalResult.data.sobjects.find((obj) => obj.name === 'ContentNote');
552
+ const enhancedNotes = contentNoteObj?.queryable ?? false;
553
+ // Check Territory Management: Territory2 object exists
554
+ const territoryManagement = sobjectNames.has('Territory2');
555
+ // Check Digital Experiences: Network object exists (Communities/Experience Cloud)
556
+ const digitalExperiences = sobjectNames.has('Network');
557
+ // Check Einstein AI: AIRecordInsight object exists (Einstein scoring features)
558
+ const einsteinAI = sobjectNames.has('AIRecordInsight');
559
+ // Check State/Country Picklists and Person Accounts via lightweight SOQL probes.
560
+ // A LIMIT 0 query succeeds if the field exists, fails with INVALID_FIELD if not.
561
+ // This avoids a full Account describe (~100-300KB for 2 boolean checks).
562
+ const [stateCountryPicklists, personAccounts] = await Promise.all([
563
+ this.probeFieldExists('Account', 'BillingCountryCode'),
564
+ this.probeFieldExists('Account', 'IsPersonAccount'),
565
+ ]);
566
+ const features = {
567
+ multiCurrency,
568
+ enhancedNotes,
569
+ stateCountryPicklists,
570
+ territoryManagement,
571
+ personAccounts,
572
+ digitalExperiences,
573
+ einsteinAI,
574
+ };
575
+ const duration = Date.now() - startTime;
576
+ const enabledCount = Object.values(features).filter(Boolean).length;
577
+ this.logger?.log(`Org features detected: ${enabledCount}/7 enabled`);
578
+ return createSuccessResult(features, {
579
+ message: `Detected ${enabledCount}/7 org features enabled`,
580
+ metadata: { duration },
581
+ });
582
+ }
583
+ catch (error) {
584
+ const errorMessage = error instanceof Error ? error.message : String(error);
585
+ this.logger?.log(`Org features detection failed: ${errorMessage}`);
586
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_FEATURES_QUERY_FAILED, errorMessage, {
587
+ metadata: { duration: Date.now() - startTime },
588
+ });
589
+ }
590
+ }
591
+ /**
592
+ * Retrieves license information from UserLicense and PermissionSetLicense.
593
+ *
594
+ * @returns ServiceResult containing array of LicenseInfo
595
+ */
596
+ async getLicenseInfo() {
597
+ const startTime = Date.now();
598
+ try {
599
+ this.logger?.log('Fetching license information...');
600
+ // Query UserLicense
601
+ const userLicenseQuery = new CuneiformQueryBuilder()
602
+ .select(['Id', 'Name', 'MasterLabel', 'TotalLicenses', 'UsedLicenses', 'Status'])
603
+ .from('UserLicense')
604
+ .where('TotalLicenses', '>', 0)
605
+ .orderBy('Name')
606
+ .toSOQL();
607
+ // Query PermissionSetLicense
608
+ const pslQuery = new CuneiformQueryBuilder()
609
+ .select(['Id', 'MasterLabel', 'DeveloperName', 'TotalLicenses', 'UsedLicenses'])
610
+ .from('PermissionSetLicense')
611
+ .where('TotalLicenses', '>', 0)
612
+ .orderBy('MasterLabel')
613
+ .toSOQL();
614
+ // Execute queries in parallel
615
+ const [userLicenseResult, pslResult] = await Promise.all([
616
+ this.soqlAdapter.query(userLicenseQuery),
617
+ this.soqlAdapter.query(pslQuery),
618
+ ]);
619
+ const licenses = [];
620
+ const warnings = [];
621
+ // Process UserLicense results
622
+ if (userLicenseResult.success) {
623
+ for (const record of userLicenseResult.data.records) {
624
+ licenses.push({
625
+ id: record.Id,
626
+ name: record.Name,
627
+ masterLabel: record.MasterLabel,
628
+ totalLicenses: record.TotalLicenses,
629
+ usedLicenses: record.UsedLicenses,
630
+ status: record.Status,
631
+ type: 'user',
632
+ });
633
+ }
634
+ }
635
+ else {
636
+ warnings.push(`UserLicense query failed: ${userLicenseResult.message ?? 'Unknown error'}`);
637
+ }
638
+ // Process PermissionSetLicense results
639
+ if (pslResult.success) {
640
+ for (const record of pslResult.data.records) {
641
+ licenses.push({
642
+ id: record.Id,
643
+ name: record.DeveloperName,
644
+ masterLabel: record.MasterLabel,
645
+ totalLicenses: record.TotalLicenses,
646
+ usedLicenses: record.UsedLicenses,
647
+ status: 'Active', // PSL doesn't have status field
648
+ type: 'permissionSet',
649
+ });
650
+ }
651
+ }
652
+ else {
653
+ warnings.push(`PermissionSetLicense query failed: ${pslResult.message ?? 'Unknown error'}`);
654
+ }
655
+ const duration = Date.now() - startTime;
656
+ this.logger?.log(`Found ${licenses.length} licenses`);
657
+ return createSuccessResult(licenses, {
658
+ message: `Found ${licenses.length} licenses`,
659
+ warnings: warnings.length > 0 ? warnings : undefined,
660
+ metadata: { duration },
661
+ });
662
+ }
663
+ catch (error) {
664
+ const errorMessage = error instanceof Error ? error.message : String(error);
665
+ this.logger?.log(`License query failed: ${errorMessage}`);
666
+ return createFailureResult([], ServiceErrorCodes.ORG_NAMESPACE_QUERY_FAILED, errorMessage, {
667
+ metadata: { duration: Date.now() - startTime },
668
+ });
669
+ }
670
+ }
671
+ /**
672
+ * Detects installed Salesforce Clouds (Sales Cloud, Service Cloud, Industry Clouds).
673
+ *
674
+ * Combines license-based detection (Sales/Service Cloud via UserLicense) with
675
+ * package-based detection (Industry Clouds via namespace lookup).
676
+ *
677
+ * @param cachedGlobal - Optional pre-fetched describeGlobal result to avoid redundant API calls
678
+ * @returns ServiceResult containing array of DetectedCloud
679
+ */
680
+ async getDetectedClouds(cachedGlobal, cachedPackages) {
681
+ const startTime = Date.now();
682
+ try {
683
+ this.logger?.log('Detecting installed clouds...');
684
+ // Get licenses and packages in parallel (use cached packages if provided)
685
+ const [licensesResult, packagesResult] = await Promise.all([
686
+ this.getLicenseInfo(),
687
+ cachedPackages ?? this.getInstalledPackages(),
688
+ ]);
689
+ const clouds = [];
690
+ const warnings = [];
691
+ // Detect Sales Cloud and Service Cloud via licenses
692
+ if (licensesResult.success) {
693
+ clouds.push(...(await this.detectLicenseClouds(licensesResult.data, cachedGlobal)));
694
+ }
695
+ else {
696
+ warnings.push(`License query failed: ${licensesResult.message ?? 'Unknown error'}`);
697
+ }
698
+ // Detect Industry Clouds via packages
699
+ if (packagesResult.success) {
700
+ for (const [namespace, cloudName] of Object.entries(CLOUD_NAMESPACE_MAP)) {
701
+ const pkg = packagesResult.data.find((p) => p.namespacePrefix === namespace || p.namespacePrefix === `${namespace}__`);
702
+ clouds.push({
703
+ name: cloudName,
704
+ type: 'package',
705
+ installed: Boolean(pkg),
706
+ namespace: pkg ? pkg.namespacePrefix : namespace,
707
+ version: pkg?.versionNumber,
708
+ });
709
+ }
710
+ }
711
+ else {
712
+ warnings.push(`Package query failed: ${packagesResult.message ?? 'Unknown error'}`);
713
+ }
714
+ // Detect additional clouds from PermissionSetLicense data
715
+ if (licensesResult.success) {
716
+ clouds.push(...OrgInfoService.detectPslClouds(licensesResult.data));
717
+ }
718
+ const duration = Date.now() - startTime;
719
+ const installedCount = clouds.filter((c) => c.installed).length;
720
+ this.logger?.log(`Detected ${installedCount}/${clouds.length} clouds installed`);
721
+ return createSuccessResult(clouds, {
722
+ message: `Detected ${installedCount} installed clouds`,
723
+ warnings: warnings.length > 0 ? warnings : undefined,
724
+ metadata: { duration },
725
+ });
726
+ }
727
+ catch (error) {
728
+ const errorMessage = error instanceof Error ? error.message : String(error);
729
+ this.logger?.log(`Cloud detection failed: ${errorMessage}`);
730
+ return createFailureResult([], ServiceErrorCodes.ORG_FEATURES_QUERY_FAILED, errorMessage, {
731
+ metadata: { duration: Date.now() - startTime },
732
+ });
733
+ }
734
+ }
735
+ /**
736
+ * Discovers installed namespaces via describeGlobal() with object counts.
737
+ *
738
+ * Extracts unique namespaces from custom object names (pattern: Namespace__ObjectName__c)
739
+ * and counts objects per namespace. Maps known namespaces to product names.
740
+ *
741
+ * @param cachedGlobal - Optional pre-fetched describeGlobal result to avoid redundant API calls
742
+ * @returns ServiceResult containing NamespaceSummary
743
+ */
744
+ async getInstalledNamespaces(cachedGlobal) {
745
+ const startTime = Date.now();
746
+ const emptyResult = { count: 0, namespaces: [] };
747
+ if (!this.restAdapter) {
748
+ this.logger?.log('REST adapter not provided, skipping namespace discovery');
749
+ return createSuccessResult(emptyResult, {
750
+ message: 'Namespace discovery skipped (no REST adapter)',
751
+ warnings: ['REST adapter not provided, cannot discover namespaces'],
752
+ metadata: { duration: Date.now() - startTime },
753
+ });
754
+ }
755
+ try {
756
+ this.logger?.log('Discovering installed namespaces...');
757
+ // Use provided cache if available; otherwise fetch fresh
758
+ const globalResult = cachedGlobal ?? (await this.restAdapter.describeGlobal());
759
+ if (!globalResult.success) {
760
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_NAMESPACE_QUERY_FAILED, globalResult.message ?? 'Failed to discover namespaces', {
761
+ metadata: { duration: Date.now() - startTime },
762
+ });
763
+ }
764
+ // Group objects by namespace
765
+ const namespaceGroups = OrgInfoService.groupNamespaceObjects(globalResult.data);
766
+ // Fetch record counts for all namespace objects
767
+ const allObjects = Array.from(namespaceGroups.values()).flatMap((g) => g.objects);
768
+ const recordCounts = allObjects.length > 0 ? await this.restAdapter.getRecordCounts(allObjects) : undefined;
769
+ // Build namespace summary with populated/empty classification
770
+ const namespaces = [];
771
+ for (const [prefix, group] of namespaceGroups.entries()) {
772
+ let populated = 0;
773
+ let empty = 0;
774
+ if (recordCounts?.success) {
775
+ for (const objName of group.objects) {
776
+ if ((recordCounts.data.get(objName) ?? 0) > 0)
777
+ populated++;
778
+ else
779
+ empty++;
780
+ }
781
+ }
782
+ else {
783
+ // If record counts failed, fall back to all objects as empty
784
+ empty = group.count;
785
+ }
786
+ // Unrecognized namespaces show blank product name (not "Unknown") per PTA-1437
787
+ const productName = getProductName(prefix) ?? getProductName(`${prefix}__`) ?? '';
788
+ namespaces.push({
789
+ prefix,
790
+ productName,
791
+ objectCount: group.count,
792
+ populatedCount: populated,
793
+ emptyCount: empty,
794
+ });
795
+ }
796
+ // Sort by object count descending
797
+ namespaces.sort((a, b) => b.objectCount - a.objectCount);
798
+ const summary = {
799
+ count: namespaces.length,
800
+ namespaces,
801
+ };
802
+ const duration = Date.now() - startTime;
803
+ this.logger?.log(`Discovered ${summary.count} namespaces`);
804
+ return createSuccessResult(summary, {
805
+ message: `Discovered ${summary.count} namespaces`,
806
+ metadata: { duration },
807
+ });
808
+ }
809
+ catch (error) {
810
+ const errorMessage = error instanceof Error ? error.message : String(error);
811
+ this.logger?.log(`Namespace discovery failed: ${errorMessage}`);
812
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_NAMESPACE_QUERY_FAILED, errorMessage, {
813
+ metadata: { duration: Date.now() - startTime },
814
+ });
815
+ }
816
+ }
817
+ /**
818
+ * Retrieves enhanced Cuneiform package information with license details.
819
+ *
820
+ * @returns ServiceResult containing CuneiformPackageInfo
821
+ */
822
+ async getCuneiformPackageInfo(cachedPackages) {
823
+ const startTime = Date.now();
824
+ const notInstalledResult = {
825
+ installed: false,
826
+ licenseStatus: 'Not Installed',
827
+ };
828
+ try {
829
+ this.logger?.log('Fetching Cuneiform package info...');
830
+ const packagesResult = cachedPackages ?? (await this.getInstalledPackages());
831
+ if (!packagesResult.success) {
832
+ return createFailureResult(notInstalledResult, ServiceErrorCodes.ORG_CUNEIFORM_VERSION_FAILED, packagesResult.message ?? 'Failed to get Cuneiform info', {
833
+ metadata: { duration: Date.now() - startTime },
834
+ });
835
+ }
836
+ const cuneiformPkg = packagesResult.data.find((p) => p.namespacePrefix === CUNEIFORM_NAMESPACE);
837
+ if (!cuneiformPkg) {
838
+ // CLI-1569: InstalledSubscriberPackage is empty in scratch orgs where packages are
839
+ // deployed as source (dev hub push) rather than installed from AppExchange.
840
+ // Fall back to namespace-based detection by querying a known Cuneiform CMT object.
841
+ const namespaceDetected = await this.detectCuneiformNamespace();
842
+ if (namespaceDetected) {
843
+ const duration = Date.now() - startTime;
844
+ this.logger?.log('Cuneiform detected via namespace (not subscriber package)');
845
+ return createSuccessResult({
846
+ installed: true,
847
+ licenseStatus: 'Active',
848
+ }, {
849
+ message: 'Cuneiform detected via namespace (not via subscriber package)',
850
+ metadata: { duration, detectionMethod: 'namespace' },
851
+ });
852
+ }
853
+ const duration = Date.now() - startTime;
854
+ return createSuccessResult(notInstalledResult, {
855
+ message: 'Cuneiform not installed',
856
+ metadata: { duration },
857
+ });
858
+ }
859
+ // Package is installed - license status is assumed Active (Salesforce doesn't expose license expiration via standard APIs)
860
+ const info = {
861
+ installed: true,
862
+ version: cuneiformPkg.versionNumber,
863
+ licenseStatus: 'Active', // Default to Active if installed
864
+ };
865
+ const duration = Date.now() - startTime;
866
+ const versionStr = info.version ?? 'unknown';
867
+ this.logger?.log(`Cuneiform package info: v${versionStr}, ${info.licenseStatus}`);
868
+ return createSuccessResult(info, {
869
+ message: `Cuneiform v${versionStr} installed`,
870
+ metadata: { duration },
871
+ });
872
+ }
873
+ catch (error) {
874
+ const errorMessage = error instanceof Error ? error.message : String(error);
875
+ this.logger?.log(`Cuneiform package info failed: ${errorMessage}`);
876
+ return createFailureResult(notInstalledResult, ServiceErrorCodes.ORG_CUNEIFORM_VERSION_FAILED, errorMessage, {
877
+ metadata: { duration: Date.now() - startTime },
878
+ });
879
+ }
880
+ }
881
+ /**
882
+ * Retrieves business processes with associated record type counts.
883
+ *
884
+ * Queries BusinessProcess records and enriches each with the count and names
885
+ * of RecordTypes linked via BusinessProcessId. If no business processes exist,
886
+ * the RecordType query is skipped entirely.
887
+ *
888
+ * @returns ServiceResult containing BusinessProcessSummary
889
+ */
890
+ async getBusinessProcesses() {
891
+ const startTime = Date.now();
892
+ const emptyResult = { count: 0, processes: [] };
893
+ try {
894
+ this.logger?.log('Fetching business processes...');
895
+ // Query BusinessProcess records
896
+ const bpQuery = new CuneiformQueryBuilder()
897
+ .select(['Id', 'Name', 'TableEnumOrId', 'IsActive', 'Description'])
898
+ .from('BusinessProcess')
899
+ .orderBy('TableEnumOrId', 'ASC')
900
+ .toSOQL();
901
+ const bpResult = await this.soqlAdapter.query(bpQuery);
902
+ if (!bpResult.success) {
903
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_BUSINESS_PROCESS_QUERY_FAILED, bpResult.message ?? 'BusinessProcess query failed', { metadata: { duration: Date.now() - startTime } });
904
+ }
905
+ const bpRecords = bpResult.data.records;
906
+ // Short-circuit if no business processes exist
907
+ if (bpRecords.length === 0) {
908
+ const duration = Date.now() - startTime;
909
+ return createSuccessResult(emptyResult, {
910
+ message: 'No business processes found',
911
+ metadata: { duration },
912
+ });
913
+ }
914
+ // Query RecordTypes linked to business processes
915
+ const warnings = [];
916
+ let rtRecords = [];
917
+ const rtQuery = new CuneiformQueryBuilder()
918
+ .select(['Id', 'Name', 'SobjectType', 'BusinessProcessId', 'IsActive'])
919
+ .from('RecordType')
920
+ .andWhereNull('BusinessProcessId', false)
921
+ .orderBy('Name', 'ASC')
922
+ .toSOQL();
923
+ const rtResult = await this.soqlAdapter.query(rtQuery);
924
+ if (rtResult.success) {
925
+ rtRecords = rtResult.data.records;
926
+ }
927
+ else {
928
+ warnings.push(`RecordType query failed: ${rtResult.message ?? 'Unknown error'}`);
929
+ }
930
+ // Group record types by BusinessProcessId
931
+ const rtByProcessId = new Map();
932
+ for (const rt of rtRecords) {
933
+ const group = rtByProcessId.get(rt.BusinessProcessId) ?? [];
934
+ group.push(rt);
935
+ rtByProcessId.set(rt.BusinessProcessId, group);
936
+ }
937
+ // Build process info with record type enrichment
938
+ const processes = bpRecords.map((bp) => {
939
+ const linkedRts = rtByProcessId.get(bp.Id) ?? [];
940
+ return {
941
+ name: bp.Name,
942
+ objectName: bp.TableEnumOrId,
943
+ isActive: bp.IsActive,
944
+ description: bp.Description ?? undefined,
945
+ recordTypeCount: linkedRts.length,
946
+ recordTypeNames: linkedRts.map((rt) => rt.Name),
947
+ };
948
+ });
949
+ const summary = {
950
+ count: processes.length,
951
+ processes,
952
+ };
953
+ const duration = Date.now() - startTime;
954
+ this.logger?.log(`Found ${summary.count} business processes`);
955
+ return createSuccessResult(summary, {
956
+ message: `Found ${summary.count} business processes`,
957
+ warnings: warnings.length > 0 ? warnings : undefined,
958
+ metadata: { duration },
959
+ });
960
+ }
961
+ catch (error) {
962
+ const errorMessage = error instanceof Error ? error.message : String(error);
963
+ this.logger?.log(`Business process query failed: ${errorMessage}`);
964
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_BUSINESS_PROCESS_QUERY_FAILED, errorMessage, {
965
+ metadata: { duration: Date.now() - startTime },
966
+ });
967
+ }
968
+ }
969
+ // ── Private instance methods ────────────────────────────────────────
970
+ /**
971
+ * Delegates org info retrieval to the ISV REST API.
972
+ *
973
+ * @param startTime - Timestamp for duration tracking
974
+ * @returns ServiceResult containing OrgInfo from REST endpoint
975
+ */
976
+ async getOrgInfoViaRest(startTime) {
977
+ this.logger?.log('Delegating org info to ISV REST API (org-info)');
978
+ const emptyResult = {
979
+ identity: { userId: '', organizationId: '', username: '' },
980
+ limits: { limits: {} },
981
+ packages: [],
982
+ activeNamespaces: [],
983
+ cuneiformVersion: null,
984
+ };
985
+ const restResult = await this.restClient.getOrgInfo();
986
+ if (!restResult.success) {
987
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_INFO_QUERY_FAILED, restResult.message ?? 'REST org-info failed', {
988
+ metadata: { duration: Date.now() - startTime },
989
+ });
990
+ }
991
+ const response = restResult.data;
992
+ if (!response.success) {
993
+ const errorMsg = response.errors?.length > 0 ? response.errors[0] : 'Server-side org info query failed';
994
+ return createFailureResult(emptyResult, ServiceErrorCodes.ORG_INFO_QUERY_FAILED, errorMsg, {
995
+ metadata: { duration: Date.now() - startTime },
996
+ });
997
+ }
998
+ return createSuccessResult(response.result ?? emptyResult, {
999
+ message: 'Org info retrieved via REST API',
1000
+ metadata: { duration: Date.now() - startTime, strategyUsed: 'rest-api' },
1001
+ });
1002
+ }
1003
+ /**
1004
+ * Detects whether the Cuneiform namespace exists by querying a known CMT object.
1005
+ *
1006
+ * CLI-1569: InstalledSubscriberPackage is empty in scratch orgs where packages are
1007
+ * deployed as source metadata. This method queries pnova__Active_Configuration__mdt
1008
+ * as a lightweight namespace presence check — if the query succeeds (even with 0
1009
+ * records), the namespace exists. If it fails with "sObject type not supported",
1010
+ * the namespace is absent.
1011
+ *
1012
+ * @returns true if the pnova namespace is present, false otherwise
1013
+ */
1014
+ async detectCuneiformNamespace() {
1015
+ try {
1016
+ const soql = new CuneiformQueryBuilder()
1017
+ .select(['Id'])
1018
+ .from(`${CUNEIFORM_NAMESPACE}__Active_Configuration__mdt`)
1019
+ .limit(1)
1020
+ .toSOQL();
1021
+ const result = await this.soqlAdapter.query(soql);
1022
+ // If the query succeeds (regardless of record count), the namespace exists
1023
+ return result.success;
1024
+ }
1025
+ catch {
1026
+ // Any exception means namespace detection failed — treat as not installed
1027
+ return false;
1028
+ }
1029
+ }
1030
+ /**
1031
+ * Probes whether a field exists on an object using a LIMIT 0 SOQL query.
1032
+ * Returns true if the query succeeds (field exists), false if it fails or the
1033
+ * sanitizer rejects the inputs. Much lighter than a full describe.
1034
+ *
1035
+ * **Input source contract**: callers must pass Salesforce API names already
1036
+ * classified as safe (hardcoded constants, describeGlobal results, or upstream
1037
+ * validated values). The sanitizer in buildProbeQuery defends against malformed
1038
+ * identifiers as a last line of defence, but this method is NOT a user-input
1039
+ * gateway — never wire it directly to a flag value or untrusted external input.
1040
+ *
1041
+ * Today's only call sites pass hardcoded constants from getOrgFeatures()
1042
+ * (Account / BillingCountryCode / IsPersonAccount). The sanitizer is in place
1043
+ * defensively so a future caller cannot accidentally introduce SOQL injection.
1044
+ */
1045
+ async probeFieldExists(objectName, fieldName) {
1046
+ const soql = OrgInfoService.buildProbeQuery(objectName, fieldName);
1047
+ if (soql === null) {
1048
+ return false;
1049
+ }
1050
+ try {
1051
+ const result = await this.soqlAdapter.query(soql);
1052
+ return result.success;
1053
+ }
1054
+ catch {
1055
+ return false;
1056
+ }
1057
+ }
1058
+ /**
1059
+ * Detects Sales Cloud and Service Cloud from license data and global describe.
1060
+ *
1061
+ * Uses license patterns to find Sales/Service Cloud licenses, then confirms
1062
+ * by checking for Opportunity (Sales) and Case (Service) objects in the org.
1063
+ */
1064
+ async detectLicenseClouds(licenses, cachedGlobal) {
1065
+ const salesCloudLicense = licenses.find((lic) => SALES_CLOUD_LICENSE_PATTERNS.some((pattern) => lic.masterLabel.includes(pattern) || lic.name.includes(pattern)));
1066
+ const serviceCloudLicense = licenses.find((lic) => SERVICE_CLOUD_LICENSE_PATTERNS.some((pattern) => lic.masterLabel.includes(pattern) || lic.name.includes(pattern)));
1067
+ // Check for Opportunity/Case objects to confirm Sales/Service Cloud
1068
+ const { hasOpportunity, hasCase } = await this.resolveCloudObjects(cachedGlobal);
1069
+ const clouds = [];
1070
+ if (salesCloudLicense && hasOpportunity) {
1071
+ clouds.push({
1072
+ name: 'Sales Cloud',
1073
+ type: 'license',
1074
+ installed: true,
1075
+ totalLicenses: salesCloudLicense.totalLicenses,
1076
+ usedLicenses: salesCloudLicense.usedLicenses,
1077
+ status: salesCloudLicense.status,
1078
+ });
1079
+ }
1080
+ else {
1081
+ clouds.push({ name: 'Sales Cloud', type: 'license', installed: false });
1082
+ }
1083
+ if (serviceCloudLicense && hasCase) {
1084
+ clouds.push({
1085
+ name: 'Service Cloud',
1086
+ type: 'license',
1087
+ installed: true,
1088
+ totalLicenses: serviceCloudLicense.totalLicenses,
1089
+ usedLicenses: serviceCloudLicense.usedLicenses,
1090
+ status: serviceCloudLicense.status,
1091
+ });
1092
+ }
1093
+ else {
1094
+ clouds.push({ name: 'Service Cloud', type: 'license', installed: false });
1095
+ }
1096
+ return clouds;
1097
+ }
1098
+ /**
1099
+ * Resolves whether Opportunity and Case objects exist in the org.
1100
+ * Uses cached global describe if available, otherwise fetches fresh.
1101
+ */
1102
+ async resolveCloudObjects(cachedGlobal) {
1103
+ if (cachedGlobal?.success) {
1104
+ const sobjectNames = new Set(cachedGlobal.data.sobjects.map((obj) => obj.name));
1105
+ return { hasOpportunity: sobjectNames.has('Opportunity'), hasCase: sobjectNames.has('Case') };
1106
+ }
1107
+ if (this.restAdapter) {
1108
+ try {
1109
+ const globalResult = await this.restAdapter.describeGlobal();
1110
+ if (globalResult.success) {
1111
+ const sobjectNames = new Set(globalResult.data.sobjects.map((obj) => obj.name));
1112
+ return { hasOpportunity: sobjectNames.has('Opportunity'), hasCase: sobjectNames.has('Case') };
1113
+ }
1114
+ }
1115
+ catch {
1116
+ // Ignore error, use license-only detection
1117
+ }
1118
+ }
1119
+ return { hasOpportunity: false, hasCase: false };
1120
+ }
1121
+ }
1122
+ //# sourceMappingURL=OrgInfoService.js.map