@transcend-io/cli 10.0.1 → 10.1.0

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 (412) hide show
  1. package/README.md +16 -5
  2. package/dist/{RequestDataSilo-_Iv44M9u.mjs → RequestDataSilo-Rrc2dL9g.mjs} +4 -1
  3. package/dist/RequestDataSilo-Rrc2dL9g.mjs.map +1 -0
  4. package/dist/{app-BfTrk2nc.mjs → app-Cx8-4u8K.mjs} +21 -21
  5. package/dist/{app-BfTrk2nc.mjs.map → app-Cx8-4u8K.mjs.map} +1 -1
  6. package/dist/approvePrivacyRequests-Bjq5cPSI.mjs +2 -0
  7. package/dist/approvePrivacyRequests-Bjq5cPSI.mjs.map +1 -0
  8. package/dist/bin/bash-complete.mjs +1 -1
  9. package/dist/bin/cli.mjs +1 -1
  10. package/dist/bin/deprecated-command.mjs +1 -1
  11. package/dist/buildXdiSyncEndpoint-DWs9ImOw.mjs +9 -0
  12. package/dist/buildXdiSyncEndpoint-DWs9ImOw.mjs.map +1 -0
  13. package/dist/bulkRestartRequests-sie3tM3W.mjs +2 -0
  14. package/dist/bulkRestartRequests-sie3tM3W.mjs.map +1 -0
  15. package/dist/bulkRetryEnrichers-C1RrxiTR.mjs +2 -0
  16. package/dist/bulkRetryEnrichers-C1RrxiTR.mjs.map +1 -0
  17. package/dist/cancelPrivacyRequests-DmvFijq_.mjs +2 -0
  18. package/dist/cancelPrivacyRequests-DmvFijq_.mjs.map +1 -0
  19. package/dist/{codecs-BE3Wmoh8.mjs → codecs-CeDPaLYa.mjs} +1 -1
  20. package/dist/{codecs-BE3Wmoh8.mjs.map → codecs-CeDPaLYa.mjs.map} +1 -1
  21. package/dist/collectCsvFilesOrExit-D-csvd13.mjs +2 -0
  22. package/dist/collectCsvFilesOrExit-D-csvd13.mjs.map +1 -0
  23. package/dist/collectParquetFilesOrExit-C8qT5_57.mjs +2 -0
  24. package/dist/collectParquetFilesOrExit-C8qT5_57.mjs.map +1 -0
  25. package/dist/{command-BXxoAjFo.mjs → command-rzZKmlky.mjs} +2 -2
  26. package/dist/{command-BXxoAjFo.mjs.map → command-rzZKmlky.mjs.map} +1 -1
  27. package/dist/commands/admin/chunk-csv/worker.d.mts +48 -0
  28. package/dist/commands/admin/chunk-csv/worker.d.mts.map +1 -0
  29. package/dist/commands/admin/chunk-csv/worker.mjs +2 -0
  30. package/dist/commands/admin/chunk-csv/worker.mjs.map +1 -0
  31. package/dist/commands/admin/parquet-to-csv/worker.d.mts +25 -0
  32. package/dist/commands/admin/parquet-to-csv/worker.d.mts.map +1 -0
  33. package/dist/commands/admin/parquet-to-csv/worker.mjs +2 -0
  34. package/dist/commands/admin/parquet-to-csv/worker.mjs.map +1 -0
  35. package/dist/{consentManagersToBusinessEntities-BDgOFga7.mjs → consentManagersToBusinessEntities-D1bdBgnA.mjs} +2 -2
  36. package/dist/{consentManagersToBusinessEntities-BDgOFga7.mjs.map → consentManagersToBusinessEntities-D1bdBgnA.mjs.map} +1 -1
  37. package/dist/{constants-lIvXgkdp.mjs → constants-DYbzl8QH.mjs} +1 -1
  38. package/dist/{constants-lIvXgkdp.mjs.map → constants-DYbzl8QH.mjs.map} +1 -1
  39. package/dist/constants-XOsAW1__.mjs +2 -0
  40. package/dist/constants-XOsAW1__.mjs.map +1 -0
  41. package/dist/{constants-AFtS5Nad.mjs → constants-mjLYTIJm.mjs} +2 -2
  42. package/dist/{constants-AFtS5Nad.mjs.map → constants-mjLYTIJm.mjs.map} +1 -1
  43. package/dist/{context-CdSyuBlf.mjs → context-bkKpii_t.mjs} +1 -1
  44. package/dist/{context-CdSyuBlf.mjs.map → context-bkKpii_t.mjs.map} +1 -1
  45. package/dist/createExtraKeyHandler-Jp5XpTJi.mjs +14 -0
  46. package/dist/createExtraKeyHandler-Jp5XpTJi.mjs.map +1 -0
  47. package/dist/{dataFlowsToDataSilos-NhvBw1iy.mjs → dataFlowsToDataSilos-DUj1NhOt.mjs} +1 -1
  48. package/dist/dataFlowsToDataSilos-DUj1NhOt.mjs.map +1 -0
  49. package/dist/{dataSilo-DrFetFXw.mjs → dataSilo-Dvi8-PkH.mjs} +1 -1
  50. package/dist/{dataSilo-DrFetFXw.mjs.map → dataSilo-Dvi8-PkH.mjs.map} +1 -1
  51. package/dist/{dataSubject-y_aXI0pa.mjs → dataSubject-CF784Ug0.mjs} +1 -1
  52. package/dist/{dataSubject-y_aXI0pa.mjs.map → dataSubject-CF784Ug0.mjs.map} +1 -1
  53. package/dist/{done-input-validation-DLR0-MJ7.mjs → done-input-validation-C5rgR0Wr.mjs} +1 -1
  54. package/dist/{done-input-validation-DLR0-MJ7.mjs.map → done-input-validation-C5rgR0Wr.mjs.map} +1 -1
  55. package/dist/downloadPrivacyRequestFiles-GUbd_PRc.mjs +2 -0
  56. package/dist/downloadPrivacyRequestFiles-GUbd_PRc.mjs.map +1 -0
  57. package/dist/{extractClientError-DPjv09EH.mjs → extractClientError-X9wJVqGq.mjs} +1 -1
  58. package/dist/{extractClientError-DPjv09EH.mjs.map → extractClientError-X9wJVqGq.mjs.map} +1 -1
  59. package/dist/{fetchAllRequestEnrichers-CK-kk5eg.mjs → fetchAllRequestEnrichers-Bt97Bb7F.mjs} +5 -5
  60. package/dist/fetchAllRequestEnrichers-Bt97Bb7F.mjs.map +1 -0
  61. package/dist/fetchAllRequestIdentifiers-BXx3rSee.mjs +10 -0
  62. package/dist/fetchAllRequestIdentifiers-BXx3rSee.mjs.map +1 -0
  63. package/dist/fetchAllRequests-xGgt_STo.mjs +2 -0
  64. package/dist/fetchAllRequests-xGgt_STo.mjs.map +1 -0
  65. package/dist/fetchRequestDataSilo-0UvyeL60.mjs +2 -0
  66. package/dist/fetchRequestDataSilo-0UvyeL60.mjs.map +1 -0
  67. package/dist/{fetchRequestFilesForRequest-BbxrEKFK.mjs → fetchRequestFilesForRequest-CJH2iB-P.mjs} +4 -4
  68. package/dist/fetchRequestFilesForRequest-CJH2iB-P.mjs.map +1 -0
  69. package/dist/generateCrossAccountApiKeys-DztJoLQS.mjs +2 -0
  70. package/dist/generateCrossAccountApiKeys-DztJoLQS.mjs.map +1 -0
  71. package/dist/impl-B-PzeHxN.mjs +2 -0
  72. package/dist/impl-B-PzeHxN.mjs.map +1 -0
  73. package/dist/impl-B6TXE2oE.mjs +4 -0
  74. package/dist/impl-B6TXE2oE.mjs.map +1 -0
  75. package/dist/impl-BBKJIP0Q.mjs +2 -0
  76. package/dist/impl-BBKJIP0Q.mjs.map +1 -0
  77. package/dist/impl-BBnnC5xq.mjs +2 -0
  78. package/dist/impl-BBnnC5xq.mjs.map +1 -0
  79. package/dist/impl-BGGm947r2.mjs +2 -0
  80. package/dist/impl-BGGm947r2.mjs.map +1 -0
  81. package/dist/{impl-fqOKTw5J.mjs → impl-BKrNGF2F.mjs} +2 -2
  82. package/dist/{impl-fqOKTw5J.mjs.map → impl-BKrNGF2F.mjs.map} +1 -1
  83. package/dist/{impl-DGiPB5Vq2.mjs → impl-BMnXA_Vd.mjs} +2 -2
  84. package/dist/impl-BMnXA_Vd.mjs.map +1 -0
  85. package/dist/{impl-P_NDC3cX.mjs → impl-BRiRfzgu.mjs} +2 -2
  86. package/dist/{impl-P_NDC3cX.mjs.map → impl-BRiRfzgu.mjs.map} +1 -1
  87. package/dist/{impl-DGuwD_qz.mjs → impl-BSKl6rC6.mjs} +2 -2
  88. package/dist/{impl-DGuwD_qz.mjs.map → impl-BSKl6rC6.mjs.map} +1 -1
  89. package/dist/impl-BVHfSIVG.mjs +2 -0
  90. package/dist/{impl-CMmyv1cl.mjs.map → impl-BVHfSIVG.mjs.map} +1 -1
  91. package/dist/impl-BVnfUDUm.mjs +2 -0
  92. package/dist/impl-BVnfUDUm.mjs.map +1 -0
  93. package/dist/impl-BfeWet_F2.mjs +2 -0
  94. package/dist/impl-BfeWet_F2.mjs.map +1 -0
  95. package/dist/{impl-CSChmq_t2.mjs → impl-BffzTHKU.mjs} +2 -2
  96. package/dist/impl-BffzTHKU.mjs.map +1 -0
  97. package/dist/impl-BxOydpyJ.mjs +2 -0
  98. package/dist/impl-BxOydpyJ.mjs.map +1 -0
  99. package/dist/{impl-BUC4ZelU.mjs → impl-C-u5h8We.mjs} +2 -2
  100. package/dist/{impl-BUC4ZelU.mjs.map → impl-C-u5h8We.mjs.map} +1 -1
  101. package/dist/{impl-KDuBh4bu2.mjs → impl-C3DXXn8M.mjs} +2 -2
  102. package/dist/impl-C3DXXn8M.mjs.map +1 -0
  103. package/dist/{impl-BOUm7wly2.mjs → impl-CC0rkA9s.mjs} +2 -2
  104. package/dist/impl-CC0rkA9s.mjs.map +1 -0
  105. package/dist/impl-CODwodEc.mjs +7 -0
  106. package/dist/impl-CODwodEc.mjs.map +1 -0
  107. package/dist/impl-CPIMsZg-.mjs +2 -0
  108. package/dist/{impl-DEWXA_QC.mjs.map → impl-CPIMsZg-.mjs.map} +1 -1
  109. package/dist/{impl-c7rUQYDc2.mjs → impl-CZsYoSZQ.mjs} +2 -2
  110. package/dist/impl-CZsYoSZQ.mjs.map +1 -0
  111. package/dist/impl-CnHiD4zU.mjs +2 -0
  112. package/dist/impl-CnHiD4zU.mjs.map +1 -0
  113. package/dist/impl-CpJljZV2.mjs +2 -0
  114. package/dist/impl-CpJljZV2.mjs.map +1 -0
  115. package/dist/impl-Cpndlxar.mjs +4 -0
  116. package/dist/impl-Cpndlxar.mjs.map +1 -0
  117. package/dist/{impl-CNez1OAw.mjs → impl-CqH3YYuv.mjs} +2 -2
  118. package/dist/{impl-CNez1OAw.mjs.map → impl-CqH3YYuv.mjs.map} +1 -1
  119. package/dist/{impl-MpkLBntW.mjs → impl-CvJtt8H2.mjs} +2 -2
  120. package/dist/{impl-MpkLBntW.mjs.map → impl-CvJtt8H2.mjs.map} +1 -1
  121. package/dist/impl-Cw10WeUv.mjs +2 -0
  122. package/dist/impl-Cw10WeUv.mjs.map +1 -0
  123. package/dist/{impl-CCUsnhoW2.mjs → impl-Cy8-6_Oo2.mjs} +2 -2
  124. package/dist/{impl-CCUsnhoW2.mjs.map → impl-Cy8-6_Oo2.mjs.map} +1 -1
  125. package/dist/{impl-CNykdy3e2.mjs → impl-DJ4VCAcc.mjs} +2 -2
  126. package/dist/impl-DJ4VCAcc.mjs.map +1 -0
  127. package/dist/impl-DKAV-8XC.mjs +3 -0
  128. package/dist/impl-DKAV-8XC.mjs.map +1 -0
  129. package/dist/{impl-JThkrXiI2.mjs → impl-D_AxguFh2.mjs} +2 -2
  130. package/dist/{impl-JThkrXiI2.mjs.map → impl-D_AxguFh2.mjs.map} +1 -1
  131. package/dist/{impl-D-cp0CYr.mjs → impl-DaK9UOwL.mjs} +2 -2
  132. package/dist/{impl-D-cp0CYr.mjs.map → impl-DaK9UOwL.mjs.map} +1 -1
  133. package/dist/{impl-Cgg_bv7j.mjs → impl-DfVep2mE.mjs} +2 -2
  134. package/dist/{impl-Cgg_bv7j.mjs.map → impl-DfVep2mE.mjs.map} +1 -1
  135. package/dist/impl-DhXQb3bm.mjs +2 -0
  136. package/dist/impl-DhXQb3bm.mjs.map +1 -0
  137. package/dist/impl-DpGVNllB.mjs +2 -0
  138. package/dist/impl-DpGVNllB.mjs.map +1 -0
  139. package/dist/impl-DpwyYsfg.mjs +2 -0
  140. package/dist/impl-DpwyYsfg.mjs.map +1 -0
  141. package/dist/impl-DvrSuAJv.mjs +12 -0
  142. package/dist/impl-DvrSuAJv.mjs.map +1 -0
  143. package/dist/{impl-CqXFyvgV2.mjs → impl-Dw9uW5zy2.mjs} +2 -2
  144. package/dist/{impl-CqXFyvgV2.mjs.map → impl-Dw9uW5zy2.mjs.map} +1 -1
  145. package/dist/impl-PdIU1pLr2.mjs +2 -0
  146. package/dist/impl-PdIU1pLr2.mjs.map +1 -0
  147. package/dist/{impl-D9NjIwEi2.mjs → impl-StdJMCiM.mjs} +2 -2
  148. package/dist/impl-StdJMCiM.mjs.map +1 -0
  149. package/dist/impl-daUiLV3c.mjs +2 -0
  150. package/dist/impl-daUiLV3c.mjs.map +1 -0
  151. package/dist/{impl-Rt3C_fDF.mjs → impl-iGMjSniP.mjs} +2 -2
  152. package/dist/{impl-Rt3C_fDF.mjs.map → impl-iGMjSniP.mjs.map} +1 -1
  153. package/dist/impl-ogUHfunr.mjs +2 -0
  154. package/dist/impl-ogUHfunr.mjs.map +1 -0
  155. package/dist/impl-uwkj-RbF.mjs +2 -0
  156. package/dist/impl-uwkj-RbF.mjs.map +1 -0
  157. package/dist/{impl-DGzvE8aJ.mjs → impl-yvc0y1uO.mjs} +2 -2
  158. package/dist/{impl-DGzvE8aJ.mjs.map → impl-yvc0y1uO.mjs.map} +1 -1
  159. package/dist/index.d.mts +664 -3851
  160. package/dist/index.d.mts.map +1 -1
  161. package/dist/index.mjs +4 -78
  162. package/dist/index.mjs.map +1 -1
  163. package/dist/{inquirer-BgNcicZ4.mjs → inquirer-DyRwhvoh.mjs} +2 -2
  164. package/dist/{inquirer-BgNcicZ4.mjs.map → inquirer-DyRwhvoh.mjs.map} +1 -1
  165. package/dist/{listFiles-qzyQMaYH.mjs → listFiles-Odj7j2E1.mjs} +1 -1
  166. package/dist/{listFiles-qzyQMaYH.mjs.map → listFiles-Odj7j2E1.mjs.map} +1 -1
  167. package/dist/{logger-B-LXIf3U.mjs → logger-Bj782ZYD.mjs} +1 -1
  168. package/dist/{logger-B-LXIf3U.mjs.map → logger-Bj782ZYD.mjs.map} +1 -1
  169. package/dist/markRequestDataSiloIdsCompleted-DJSICILv.mjs +2 -0
  170. package/dist/markRequestDataSiloIdsCompleted-DJSICILv.mjs.map +1 -0
  171. package/dist/markSilentPrivacyRequests-ytCzpUkY.mjs +2 -0
  172. package/dist/markSilentPrivacyRequests-ytCzpUkY.mjs.map +1 -0
  173. package/dist/notifyPrivacyRequestsAdditionalTime-D8v68eAg.mjs +2 -0
  174. package/dist/notifyPrivacyRequestsAdditionalTime-D8v68eAg.mjs.map +1 -0
  175. package/dist/parquetToCsvOneFile-bgEgRoAi.mjs +6 -0
  176. package/dist/parquetToCsvOneFile-bgEgRoAi.mjs.map +1 -0
  177. package/dist/parseAttributesFromString-B8h4DudO.mjs +2 -0
  178. package/dist/{parseAttributesFromString-CZStzJc0.mjs.map → parseAttributesFromString-B8h4DudO.mjs.map} +1 -1
  179. package/dist/parseVariablesFromString-CvoeZZ75.mjs +23 -0
  180. package/dist/parseVariablesFromString-CvoeZZ75.mjs.map +1 -0
  181. package/dist/pullAllDatapoints-CqgqXRbp.mjs +45 -0
  182. package/dist/pullAllDatapoints-CqgqXRbp.mjs.map +1 -0
  183. package/dist/pullChunkedCustomSiloOutstandingIdentifiers-DaYEDZ66.mjs +2 -0
  184. package/dist/pullChunkedCustomSiloOutstandingIdentifiers-DaYEDZ66.mjs.map +1 -0
  185. package/dist/pullConsentManagerMetrics-BO0hYPDG.mjs +2 -0
  186. package/dist/pullConsentManagerMetrics-BO0hYPDG.mjs.map +1 -0
  187. package/dist/pullManualEnrichmentIdentifiersToCsv-BNuhsG20.mjs +2 -0
  188. package/dist/pullManualEnrichmentIdentifiersToCsv-BNuhsG20.mjs.map +1 -0
  189. package/dist/pullTranscendConfiguration-DSyMRyPe.mjs +58 -0
  190. package/dist/pullTranscendConfiguration-DSyMRyPe.mjs.map +1 -0
  191. package/dist/{pullUnstructuredSubDataPointRecommendations-DZd2q6S2.mjs → pullUnstructuredSubDataPointRecommendations-jE-tdoVK.mjs} +4 -4
  192. package/dist/pullUnstructuredSubDataPointRecommendations-jE-tdoVK.mjs.map +1 -0
  193. package/dist/pushCronIdentifiersFromCsv-D9Hzna0W.mjs +2 -0
  194. package/dist/pushCronIdentifiersFromCsv-D9Hzna0W.mjs.map +1 -0
  195. package/dist/pushManualEnrichmentIdentifiersFromCsv-BiR7PS_d.mjs +2 -0
  196. package/dist/pushManualEnrichmentIdentifiersFromCsv-BiR7PS_d.mjs.map +1 -0
  197. package/dist/{readCsv-CyOL7eCc.mjs → readCsv-0PIlJQCN.mjs} +1 -1
  198. package/dist/{readCsv-CyOL7eCc.mjs.map → readCsv-0PIlJQCN.mjs.map} +1 -1
  199. package/dist/{readTranscendYaml-D-J1ilS0.mjs → readTranscendYaml-DVkQL2SC.mjs} +2 -2
  200. package/dist/{readTranscendYaml-D-J1ilS0.mjs.map → readTranscendYaml-DVkQL2SC.mjs.map} +1 -1
  201. package/dist/removeUnverifiedRequestIdentifiers-B0Gx09XN.mjs +35 -0
  202. package/dist/removeUnverifiedRequestIdentifiers-B0Gx09XN.mjs.map +1 -0
  203. package/dist/{request-CAsR6CMY.mjs → request-SLqRySNU.mjs} +1 -1
  204. package/dist/{request-CAsR6CMY.mjs.map → request-SLqRySNU.mjs.map} +1 -1
  205. package/dist/retryRequestDataSilos-DFjFhhC0.mjs +2 -0
  206. package/dist/retryRequestDataSilos-DFjFhhC0.mjs.map +1 -0
  207. package/dist/skipPreflightJobs-Bm8lZZk-.mjs +2 -0
  208. package/dist/skipPreflightJobs-Bm8lZZk-.mjs.map +1 -0
  209. package/dist/skipRequestDataSilos-B5FByYTj.mjs +2 -0
  210. package/dist/skipRequestDataSilos-B5FByYTj.mjs.map +1 -0
  211. package/dist/streamPrivacyRequestsToCsv-CBzh80oQ.mjs +2 -0
  212. package/dist/streamPrivacyRequestsToCsv-CBzh80oQ.mjs.map +1 -0
  213. package/dist/syncCodePackages-BOS5foh6.mjs +2 -0
  214. package/dist/syncCodePackages-BOS5foh6.mjs.map +1 -0
  215. package/dist/syncEnrichers-C9HcWCrs.mjs +3 -0
  216. package/dist/syncEnrichers-C9HcWCrs.mjs.map +1 -0
  217. package/dist/updateConsentManagerVersionToLatest-X1HAM_IX.mjs +2 -0
  218. package/dist/updateConsentManagerVersionToLatest-X1HAM_IX.mjs.map +1 -0
  219. package/dist/uploadConsents-BP5XILuw.mjs +2 -0
  220. package/dist/uploadConsents-BP5XILuw.mjs.map +1 -0
  221. package/dist/uploadCookiesFromCsv-B42cZgYW.mjs +2 -0
  222. package/dist/uploadCookiesFromCsv-B42cZgYW.mjs.map +1 -0
  223. package/dist/uploadDataFlowsFromCsv-D2V567pP.mjs +2 -0
  224. package/dist/uploadDataFlowsFromCsv-D2V567pP.mjs.map +1 -0
  225. package/dist/uploadPrivacyRequestsFromCsv-Czc3vGfJ.mjs +2 -0
  226. package/dist/uploadPrivacyRequestsFromCsv-Czc3vGfJ.mjs.map +1 -0
  227. package/dist/{validateTranscendAuth-1W1IylqE.mjs → validateTranscendAuth-DCwAtgvh.mjs} +2 -2
  228. package/dist/{validateTranscendAuth-1W1IylqE.mjs.map → validateTranscendAuth-DCwAtgvh.mjs.map} +1 -1
  229. package/dist/{writeCsv-B51ulrVl.mjs → writeCsv-Da8NUe1V.mjs} +1 -1
  230. package/dist/{writeCsv-B51ulrVl.mjs.map → writeCsv-Da8NUe1V.mjs.map} +1 -1
  231. package/package.json +10 -7
  232. package/dist/RateCounter-DFL_mnk2.mjs +0 -2
  233. package/dist/RateCounter-DFL_mnk2.mjs.map +0 -1
  234. package/dist/RequestDataSilo-_Iv44M9u.mjs.map +0 -1
  235. package/dist/approvePrivacyRequests-CWGZR2N6.mjs +0 -2
  236. package/dist/approvePrivacyRequests-CWGZR2N6.mjs.map +0 -1
  237. package/dist/assessment-BDywVaGR.mjs +0 -284
  238. package/dist/assessment-BDywVaGR.mjs.map +0 -1
  239. package/dist/bluebird-CUitXgsY.mjs +0 -2
  240. package/dist/bluebird-CUitXgsY.mjs.map +0 -1
  241. package/dist/buildXdiSyncEndpoint-Cb-pvpak.mjs +0 -9
  242. package/dist/buildXdiSyncEndpoint-Cb-pvpak.mjs.map +0 -1
  243. package/dist/bulkRestartRequests-CKF_xpN0.mjs +0 -2
  244. package/dist/bulkRestartRequests-CKF_xpN0.mjs.map +0 -1
  245. package/dist/bulkRetryEnrichers-B-Szmin-.mjs +0 -2
  246. package/dist/bulkRetryEnrichers-B-Szmin-.mjs.map +0 -1
  247. package/dist/cancelPrivacyRequests-DNiL13E_.mjs +0 -2
  248. package/dist/cancelPrivacyRequests-DNiL13E_.mjs.map +0 -1
  249. package/dist/codecs-Dx_vGxsl.mjs +0 -2
  250. package/dist/codecs-Dx_vGxsl.mjs.map +0 -1
  251. package/dist/constants-CeMiHaHx.mjs +0 -2
  252. package/dist/constants-CeMiHaHx.mjs.map +0 -1
  253. package/dist/createExtraKeyHandler-tubeaEjA.mjs +0 -23
  254. package/dist/createExtraKeyHandler-tubeaEjA.mjs.map +0 -1
  255. package/dist/createPreferenceAccessTokens-DqmFctn3.mjs +0 -10
  256. package/dist/createPreferenceAccessTokens-DqmFctn3.mjs.map +0 -1
  257. package/dist/createSombraGotInstance-D1Il9zUE.mjs +0 -10
  258. package/dist/createSombraGotInstance-D1Il9zUE.mjs.map +0 -1
  259. package/dist/dataFlowsToDataSilos-NhvBw1iy.mjs.map +0 -1
  260. package/dist/downloadPrivacyRequestFiles-DlpgxqHF.mjs +0 -2
  261. package/dist/downloadPrivacyRequestFiles-DlpgxqHF.mjs.map +0 -1
  262. package/dist/extractErrorMessage-CPnTsT1S.mjs +0 -2
  263. package/dist/extractErrorMessage-CPnTsT1S.mjs.map +0 -1
  264. package/dist/fetchAllActions-BJsPdnxy.mjs +0 -832
  265. package/dist/fetchAllActions-BJsPdnxy.mjs.map +0 -1
  266. package/dist/fetchAllDataFlows-D248lO6_.mjs +0 -2
  267. package/dist/fetchAllDataFlows-D248lO6_.mjs.map +0 -1
  268. package/dist/fetchAllPreferenceTopics-ForE9GpZ.mjs +0 -36
  269. package/dist/fetchAllPreferenceTopics-ForE9GpZ.mjs.map +0 -1
  270. package/dist/fetchAllPurposes-ZdkO2fMp.mjs +0 -29
  271. package/dist/fetchAllPurposes-ZdkO2fMp.mjs.map +0 -1
  272. package/dist/fetchAllPurposesAndPreferences-DD6OyA5t.mjs +0 -2
  273. package/dist/fetchAllPurposesAndPreferences-DD6OyA5t.mjs.map +0 -1
  274. package/dist/fetchAllRequestEnrichers-CK-kk5eg.mjs.map +0 -1
  275. package/dist/fetchAllRequestIdentifiers-DrFFOt0m.mjs +0 -10
  276. package/dist/fetchAllRequestIdentifiers-DrFFOt0m.mjs.map +0 -1
  277. package/dist/fetchAllRequests-DNQQsY4s.mjs +0 -2
  278. package/dist/fetchAllRequests-DNQQsY4s.mjs.map +0 -1
  279. package/dist/fetchApiKeys-DjOr44xA.mjs +0 -33
  280. package/dist/fetchApiKeys-DjOr44xA.mjs.map +0 -1
  281. package/dist/fetchCatalogs-BM4FCbcS.mjs +0 -12
  282. package/dist/fetchCatalogs-BM4FCbcS.mjs.map +0 -1
  283. package/dist/fetchConsentManagerId-CFkg3-RS.mjs +0 -321
  284. package/dist/fetchConsentManagerId-CFkg3-RS.mjs.map +0 -1
  285. package/dist/fetchIdentifiers-pjQV4vUg.mjs +0 -54
  286. package/dist/fetchIdentifiers-pjQV4vUg.mjs.map +0 -1
  287. package/dist/fetchRequestDataSilo-P4yA7Lyc.mjs +0 -2
  288. package/dist/fetchRequestDataSilo-P4yA7Lyc.mjs.map +0 -1
  289. package/dist/fetchRequestFilesForRequest-BbxrEKFK.mjs.map +0 -1
  290. package/dist/generateCrossAccountApiKeys-Bxc_dzMG.mjs +0 -33
  291. package/dist/generateCrossAccountApiKeys-Bxc_dzMG.mjs.map +0 -1
  292. package/dist/impl-4ltdSmpl2.mjs +0 -4
  293. package/dist/impl-4ltdSmpl2.mjs.map +0 -1
  294. package/dist/impl-B19fH75P.mjs +0 -12
  295. package/dist/impl-B19fH75P.mjs.map +0 -1
  296. package/dist/impl-BBMjv5YQ.mjs +0 -2
  297. package/dist/impl-BBMjv5YQ.mjs.map +0 -1
  298. package/dist/impl-BKH3QRLi.mjs +0 -3
  299. package/dist/impl-BKH3QRLi.mjs.map +0 -1
  300. package/dist/impl-BOUm7wly2.mjs.map +0 -1
  301. package/dist/impl-BhTCp0kg.mjs +0 -2
  302. package/dist/impl-BhTCp0kg.mjs.map +0 -1
  303. package/dist/impl-BlHU1bbJ2.mjs +0 -2
  304. package/dist/impl-BlHU1bbJ2.mjs.map +0 -1
  305. package/dist/impl-BwjguKHC.mjs +0 -4
  306. package/dist/impl-BwjguKHC.mjs.map +0 -1
  307. package/dist/impl-C2o0eDzJ.mjs +0 -2
  308. package/dist/impl-C2o0eDzJ.mjs.map +0 -1
  309. package/dist/impl-C8HKnjw82.mjs +0 -2
  310. package/dist/impl-C8HKnjw82.mjs.map +0 -1
  311. package/dist/impl-CCc-wXqD.mjs +0 -2
  312. package/dist/impl-CCc-wXqD.mjs.map +0 -1
  313. package/dist/impl-CMmyv1cl.mjs +0 -2
  314. package/dist/impl-CNykdy3e2.mjs.map +0 -1
  315. package/dist/impl-CSChmq_t2.mjs.map +0 -1
  316. package/dist/impl-Ce9K4OCp.mjs +0 -2
  317. package/dist/impl-Ce9K4OCp.mjs.map +0 -1
  318. package/dist/impl-ChCqHkOc2.mjs +0 -2
  319. package/dist/impl-ChCqHkOc2.mjs.map +0 -1
  320. package/dist/impl-CqEwwWeD.mjs +0 -2
  321. package/dist/impl-CqEwwWeD.mjs.map +0 -1
  322. package/dist/impl-CxLSJk2P.mjs +0 -2
  323. package/dist/impl-CxLSJk2P.mjs.map +0 -1
  324. package/dist/impl-CzU9WTiW.mjs +0 -2
  325. package/dist/impl-CzU9WTiW.mjs.map +0 -1
  326. package/dist/impl-D9NjIwEi2.mjs.map +0 -1
  327. package/dist/impl-DEWXA_QC.mjs +0 -2
  328. package/dist/impl-DGiPB5Vq2.mjs.map +0 -1
  329. package/dist/impl-DTp9OQIZ.mjs +0 -7
  330. package/dist/impl-DTp9OQIZ.mjs.map +0 -1
  331. package/dist/impl-DhscnXSw.mjs +0 -2
  332. package/dist/impl-DhscnXSw.mjs.map +0 -1
  333. package/dist/impl-Dk7MdX-1.mjs +0 -2
  334. package/dist/impl-Dk7MdX-1.mjs.map +0 -1
  335. package/dist/impl-DsNPvet4.mjs +0 -2
  336. package/dist/impl-DsNPvet4.mjs.map +0 -1
  337. package/dist/impl-DxUFb0vv.mjs +0 -2
  338. package/dist/impl-DxUFb0vv.mjs.map +0 -1
  339. package/dist/impl-KDuBh4bu2.mjs.map +0 -1
  340. package/dist/impl-c7rUQYDc2.mjs.map +0 -1
  341. package/dist/impl-oiBTZqQS2.mjs +0 -2
  342. package/dist/impl-oiBTZqQS2.mjs.map +0 -1
  343. package/dist/impl-tbGnvKFm.mjs +0 -2
  344. package/dist/impl-tbGnvKFm.mjs.map +0 -1
  345. package/dist/makeGraphQLRequest-Cq26A_Lq.mjs +0 -2
  346. package/dist/makeGraphQLRequest-Cq26A_Lq.mjs.map +0 -1
  347. package/dist/markRequestDataSiloIdsCompleted-DzqJ5MNY.mjs +0 -2
  348. package/dist/markRequestDataSiloIdsCompleted-DzqJ5MNY.mjs.map +0 -1
  349. package/dist/markSilentPrivacyRequests-BKQUu6Ep.mjs +0 -2
  350. package/dist/markSilentPrivacyRequests-BKQUu6Ep.mjs.map +0 -1
  351. package/dist/mergeTranscendInputs-DGC4xUGu.mjs +0 -2
  352. package/dist/mergeTranscendInputs-DGC4xUGu.mjs.map +0 -1
  353. package/dist/notifyPrivacyRequestsAdditionalTime-TEHAJe4C.mjs +0 -2
  354. package/dist/notifyPrivacyRequestsAdditionalTime-TEHAJe4C.mjs.map +0 -1
  355. package/dist/package-C4J38oR1.mjs +0 -2
  356. package/dist/package-C4J38oR1.mjs.map +0 -1
  357. package/dist/parquetToCsvOneFile-DZVKXrjn.mjs +0 -6
  358. package/dist/parquetToCsvOneFile-DZVKXrjn.mjs.map +0 -1
  359. package/dist/parseAttributesFromString-CZStzJc0.mjs +0 -2
  360. package/dist/pullAllDatapoints-Cntwuzw7.mjs +0 -45
  361. package/dist/pullAllDatapoints-Cntwuzw7.mjs.map +0 -1
  362. package/dist/pullChunkedCustomSiloOutstandingIdentifiers-BT-GZpT1.mjs +0 -2
  363. package/dist/pullChunkedCustomSiloOutstandingIdentifiers-BT-GZpT1.mjs.map +0 -1
  364. package/dist/pullConsentManagerMetrics-FnhPEszu.mjs +0 -2
  365. package/dist/pullConsentManagerMetrics-FnhPEszu.mjs.map +0 -1
  366. package/dist/pullManualEnrichmentIdentifiersToCsv-B_4REnga.mjs +0 -2
  367. package/dist/pullManualEnrichmentIdentifiersToCsv-B_4REnga.mjs.map +0 -1
  368. package/dist/pullTranscendConfiguration-CqsgEf9A.mjs +0 -80
  369. package/dist/pullTranscendConfiguration-CqsgEf9A.mjs.map +0 -1
  370. package/dist/pullUnstructuredSubDataPointRecommendations-DZd2q6S2.mjs.map +0 -1
  371. package/dist/pushCronIdentifiersFromCsv-D2saGR5i.mjs +0 -2
  372. package/dist/pushCronIdentifiersFromCsv-D2saGR5i.mjs.map +0 -1
  373. package/dist/pushManualEnrichmentIdentifiersFromCsv-DOvAzMyt.mjs +0 -2
  374. package/dist/pushManualEnrichmentIdentifiersFromCsv-DOvAzMyt.mjs.map +0 -1
  375. package/dist/removeUnverifiedRequestIdentifiers-ChlwRmhd.mjs +0 -35
  376. package/dist/removeUnverifiedRequestIdentifiers-ChlwRmhd.mjs.map +0 -1
  377. package/dist/retryRequestDataSilos-DnwXA1YZ.mjs +0 -2
  378. package/dist/retryRequestDataSilos-DnwXA1YZ.mjs.map +0 -1
  379. package/dist/skipPreflightJobs-jK5lNlmv.mjs +0 -2
  380. package/dist/skipPreflightJobs-jK5lNlmv.mjs.map +0 -1
  381. package/dist/skipRequestDataSilos-DQGroOos.mjs +0 -2
  382. package/dist/skipRequestDataSilos-DQGroOos.mjs.map +0 -1
  383. package/dist/splitCsvToList-BRq_CIfd.mjs +0 -2
  384. package/dist/splitCsvToList-BRq_CIfd.mjs.map +0 -1
  385. package/dist/streamPrivacyRequestsToCsv-BK07Bm-T.mjs +0 -2
  386. package/dist/streamPrivacyRequestsToCsv-BK07Bm-T.mjs.map +0 -1
  387. package/dist/syncCodePackages-F-97FNjo.mjs +0 -232
  388. package/dist/syncCodePackages-F-97FNjo.mjs.map +0 -1
  389. package/dist/syncCookies-BxY36BeJ.mjs +0 -2
  390. package/dist/syncCookies-BxY36BeJ.mjs.map +0 -1
  391. package/dist/syncDataFlows-Cx5LZCen.mjs +0 -2
  392. package/dist/syncDataFlows-Cx5LZCen.mjs.map +0 -1
  393. package/dist/syncTemplates-BrH7Yr0V.mjs +0 -23
  394. package/dist/syncTemplates-BrH7Yr0V.mjs.map +0 -1
  395. package/dist/time-Bl_c3W8U.mjs +0 -2
  396. package/dist/time-Bl_c3W8U.mjs.map +0 -1
  397. package/dist/types-B4CVJCpj.mjs +0 -2
  398. package/dist/types-B4CVJCpj.mjs.map +0 -1
  399. package/dist/updateConsentManagerVersionToLatest-C221vAAw.mjs +0 -2
  400. package/dist/updateConsentManagerVersionToLatest-C221vAAw.mjs.map +0 -1
  401. package/dist/uploadConsents-BbR7_sSt.mjs +0 -2
  402. package/dist/uploadConsents-BbR7_sSt.mjs.map +0 -1
  403. package/dist/uploadCookiesFromCsv-roHWekOP.mjs +0 -2
  404. package/dist/uploadCookiesFromCsv-roHWekOP.mjs.map +0 -1
  405. package/dist/uploadDataFlowsFromCsv-DcTbrsv2.mjs +0 -2
  406. package/dist/uploadDataFlowsFromCsv-DcTbrsv2.mjs.map +0 -1
  407. package/dist/uploadPrivacyRequestsFromCsv-BUGTS-pY.mjs +0 -17
  408. package/dist/uploadPrivacyRequestsFromCsv-BUGTS-pY.mjs.map +0 -1
  409. package/dist/uploadSiloDiscoveryResults-D2fK92WR.mjs +0 -20
  410. package/dist/uploadSiloDiscoveryResults-D2fK92WR.mjs.map +0 -1
  411. package/dist/withPreferenceRetry-xLMZyTq9.mjs +0 -2
  412. package/dist/withPreferenceRetry-xLMZyTq9.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createExtraKeyHandler-Jp5XpTJi.mjs","names":[],"sources":["../src/lib/pooling/showCombinedLogs.ts","../src/lib/pooling/keymap.ts","../src/lib/pooling/replayFileTailToStdout.ts","../src/lib/pooling/workerIds.ts","../src/lib/pooling/installInteractiveSwitcher.ts","../src/lib/pooling/dashboardPlugin.ts","../src/lib/pooling/uiPlugins.ts","../src/lib/pooling/createExtraKeyHandler.ts"],"sourcesContent":["/* eslint-disable no-continue, no-control-regex */\nimport { readFileSync } from 'node:fs';\n\nimport type { WorkerLogPaths } from '@transcend-io/utils';\n\n/**\n * Log locations\n */\nexport type LogLocation = 'out' | 'err' | 'structured' | 'warn' | 'info';\n\n/**\n * Which logs to show in the combined output.\n * Can include 'out' (stdout), 'err' (stderr), 'structured' (\n */\nexport type WhichLogs = Array<LogLocation>;\n\n/**\n * Show combined logs from all worker processes.\n *\n * @param slotLogPaths - Map of worker IDs to their log file paths.\n * @param whichList - one or more sources to include (e.g., ['err','out'])\n * @param filterLevel - 'error', 'warn', or 'all' to filter log levels.\n */\nexport function showCombinedLogs(\n slotLogPaths: Map<number, WorkerLogPaths | undefined>,\n whichList: WhichLogs,\n filterLevel: 'error' | 'warn' | 'all',\n): void {\n process.stdout.write('\\x1b[2J\\x1b[H');\n\n const isError = (t: string): boolean =>\n /\\b(ERROR|uncaughtException|unhandledRejection)\\b/i.test(t);\n const isWarnTag = (t: string): boolean => /\\b(WARN|WARNING)\\b/i.test(t);\n\n const lines: string[] = [];\n\n for (const [, paths] of slotLogPaths) {\n if (!paths) continue;\n\n const files: Array<{\n /** Absolute file path to read from */\n path: string;\n /** Source type for this file, used for classification */\n src: LogLocation;\n }> = [];\n for (const which of whichList) {\n if (which === 'out' && paths.outPath) {\n files.push({ path: paths.outPath, src: 'out' });\n }\n if (which === 'err' && paths.errPath) {\n files.push({ path: paths.errPath, src: 'err' });\n }\n if (which === 'structured' && paths.structuredPath) {\n files.push({ path: paths.structuredPath, src: 'structured' });\n }\n if (paths.warnPath && which === 'warn') {\n files.push({ path: paths.warnPath, src: 'warn' });\n }\n if (paths.infoPath && which === 'info') {\n files.push({ path: paths.infoPath, src: 'info' });\n }\n }\n\n for (const { path, src } of files) {\n let text = '';\n try {\n text = readFileSync(path, 'utf8');\n } catch {\n continue;\n }\n\n for (const ln of text.split('\\n')) {\n if (!ln) continue;\n\n const clean = ln.replace(/\\x1B\\[[0-9;]*m/g, '');\n\n if (filterLevel === 'all') {\n lines.push(ln);\n continue;\n }\n\n if (filterLevel === 'error') {\n if (isError(clean)) lines.push(ln);\n continue;\n }\n\n // filterLevel === 'warn'\n // Accept:\n // - explicit WARN tag anywhere\n // - OR lines from stderr that are NOT explicit errors (many warn libs print to stderr)\n // - OR lines containing the word \"warning\" (common in some libs)\n if (isWarnTag(clean) || (src === 'err' && !isError(clean))) {\n lines.push(ln);\n continue;\n }\n }\n }\n }\n\n // simple time-sort; each worker often prefixes ISO timestamps\n lines.sort((a, b) => {\n const ta = a.match(/\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/)?.[0] ?? '';\n const tb = b.match(/\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/)?.[0] ?? '';\n return ta.localeCompare(tb);\n });\n\n process.stdout.write(`${lines.join('\\n')}\\n`);\n process.stdout.write('\\nPress Esc/Ctrl+] to return to dashboard.\\n');\n}\n/* eslint-enable no-continue, no-control-regex */\n","import type * as readline from 'node:readline';\n\n/**\n * Map a key press to an action in the interactive dashboard.\n */\nexport type Action =\n | {\n /** Indicates attaching to a session by id. */\n type: 'ATTACH';\n /** The id of the session to attach to. */\n id: number;\n }\n | {\n /** Indicates cycling through sessions. */\n type: 'CYCLE';\n /** The direction to cycle: +1 for next, -1 for previous. */\n delta: number;\n }\n | {\n /** Indicates detaching from the current session. */\n type: 'DETACH';\n }\n | {\n /** Indicates the Ctrl+C key combination was pressed. */\n type: 'CTRL_C';\n }\n | {\n /** Indicates the Ctrl+D key combination was pressed. */\n type: 'CTRL_D';\n }\n | {\n /** Indicates quitting the dashboard. */\n type: 'QUIT';\n }\n | {\n /** Forwards an unhandled key sequence. */\n type: 'FORWARD';\n /** The key sequence to forward. */\n sequence: string;\n };\n\n/**\n * Map a key press to an action in the interactive dashboard.\n *\n * @param str - The string representation of the key press.\n * @param key - The key object containing details about the key press.\n * @param mode - The current mode of the dashboard, either 'dashboard' or 'attached'.\n * @returns An Action object representing the mapped action, or null if no action is mapped.\n */\nexport function keymap(\n str: string,\n key: readline.Key,\n mode: 'dashboard' | 'attached',\n): Action | null {\n if (key.ctrl && key.name === 'c') return { type: 'CTRL_C' };\n\n if (mode === 'dashboard') {\n if (key.name && /^[0-9]$/.test(key.name)) {\n return { type: 'ATTACH', id: Number(key.name) };\n }\n if (key.name === 'tab' && !key.shift) return { type: 'CYCLE', delta: +1 };\n if (key.name === 'tab' && key.shift) return { type: 'CYCLE', delta: -1 };\n if (key.name === 'q') return { type: 'QUIT' };\n return null;\n }\n\n // attached\n if (key.name === 'escape' || (key.ctrl && key.name === ']')) {\n return { type: 'DETACH' };\n }\n if (key.ctrl && key.name === 'd') return { type: 'CTRL_D' };\n\n const sequence = key.sequence ?? str ?? '';\n return sequence ? { type: 'FORWARD', sequence } : null;\n}\n","import { createReadStream, statSync } from 'node:fs';\n\n/**\n * Replay the tail of a file to stdout.\n *\n * @param path - The absolute path to the file to read.\n * @param maxBytes - The maximum number of bytes to read from the end of the file.\n * @param write - A function to write the output to stdout.\n */\nexport async function replayFileTailToStdout(\n path: string,\n maxBytes: number,\n write: (s: string) => void,\n): Promise<void> {\n await new Promise<void>((resolve) => {\n try {\n const st = statSync(path);\n const start = Math.max(0, st.size - maxBytes);\n const stream = createReadStream(path, { start, encoding: 'utf8' });\n stream.on('data', (chunk) => write(chunk as string));\n stream.on('end', () => resolve());\n stream.on('error', () => resolve());\n } catch {\n resolve();\n }\n });\n}\n","import type { ChildProcess } from 'node:child_process';\n\n/**\n * Get the sorted list of worker IDs from a map of ChildProcess instances.\n *\n * @param m - Map of worker IDs to ChildProcess instances.\n * @returns Sorted array of worker IDs.\n */\nexport function getWorkerIds(m: Map<number, ChildProcess>): number[] {\n return [...m.keys()].sort((a, b) => a - b);\n}\n\n/**\n * Cycles through an array of numeric IDs, returning the next ID based on a delta.\n *\n * If the `current` ID is not provided or not found in the array, the first ID is used as the starting point.\n * The function then moves forward or backward in the array by `delta` positions, wrapping around if necessary.\n *\n * @param ids - Array of numeric IDs to cycle through.\n * @param current - The current ID to start cycling from. If `null` or not found, starts from the first ID.\n * @param delta - The number of positions to move forward (positive) or backward (negative) in the array.\n * @returns The next ID in the array after cycling, or `null` if the array is empty.\n */\nexport function cycleWorkers(ids: number[], current: number | null, delta: number): number | null {\n if (!ids.length) return null;\n const cur = current == null ? ids[0] : current;\n let i = ids.indexOf(cur);\n if (i === -1) i = 0;\n i = (i + delta + ids.length) % ids.length;\n return ids[i]!;\n}\n","import type { ChildProcess } from 'node:child_process';\nimport * as readline from 'node:readline';\n\nimport type { WorkerLogPaths } from '@transcend-io/utils';\n\nimport { DEBUG } from '../../constants.js';\nimport { keymap } from './keymap.js';\nimport { replayFileTailToStdout } from './replayFileTailToStdout.js';\nimport type { WhichLogs } from './showCombinedLogs.js';\nimport { cycleWorkers, getWorkerIds } from './workerIds.js';\n\n/**\n * Key action types for the interactive switcher\n */\nexport type InteractiveDashboardMode = 'dashboard' | 'attached';\n\nexport interface SwitcherPorts {\n /** Standard input stream */\n stdin: NodeJS.ReadStream;\n /** Standard output stream */\n stdout: NodeJS.WriteStream;\n /** Standard error stream */\n stderr: NodeJS.WriteStream;\n}\n\n/**\n * Install an interactive switcher for managing worker processes.\n *\n * @param opts - Options for the switcher\n * @returns A cleanup function to remove the switcher\n */\nexport function installInteractiveSwitcher(opts: {\n /** Registry of live workers by id */\n workers: Map<number, ChildProcess>;\n /** Hooks */\n onAttach?: (id: number) => void;\n /** Optional detach handler */\n onDetach?: () => void;\n /** Optional Ctrl+C handler for parent graceful shutdown in dashboard */\n onCtrlC?: () => void; // parent graceful shutdown in dashboard\n /** Provide log paths so we can replay the tail on attach */\n getLogPaths?: (id: number) => WorkerLogPaths | undefined;\n /** How many bytes to replay from the end of each file (default 200 KB) */\n replayBytes?: number;\n /** Which logs to replay first (default ['out','err']) */\n replayWhich?: WhichLogs;\n /** Print a small banner/clear screen before replaying (optional) */\n onEnterAttachScreen?: (id: number) => void;\n /** Optional stdio ports for testing; defaults to process stdio */\n ports?: SwitcherPorts;\n}): () => void {\n const {\n workers,\n onAttach,\n onDetach,\n onCtrlC,\n getLogPaths,\n replayBytes = 200 * 1024,\n replayWhich = ['out', 'err'],\n onEnterAttachScreen,\n ports,\n } = opts;\n\n const stdin = ports?.stdin ?? process.stdin;\n const stdout = ports?.stdout ?? process.stdout;\n const stderr = ports?.stderr ?? process.stderr;\n\n const d = (...a: unknown[]): void => {\n if (DEBUG) {\n try {\n (ports?.stderr ?? process.stderr).write(`[keys] ${a.map(String).join(' ')}\\n`);\n } catch {\n // noop\n }\n }\n };\n\n if (!stdin.isTTY) {\n // Not a TTY; return a no-op cleanup\n return () => {\n // noop\n };\n }\n\n readline.emitKeypressEvents(stdin);\n stdin.setRawMode?.(true);\n\n let mode: InteractiveDashboardMode = 'dashboard';\n let focus: number | null = null;\n\n // live mirroring handlers while attached\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let outHandler: ((chunk: any) => void) | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let errHandler: ((chunk: any) => void) | null = null;\n\n /**\n * Cycle through worker IDs, wrapping around.\n *\n * @param id - The current worker ID to start cycling from.\n * @returns The next worker ID after cycling, or null if no workers are available.\n */\n async function replayLogs(id: number): Promise<void> {\n if (!getLogPaths) return;\n const paths = getLogPaths(id);\n if (!paths) return;\n\n const toReplay: string[] = [];\n for (const which of replayWhich) {\n if (which === 'out') toReplay.push(paths.outPath);\n if (which === 'err') toReplay.push(paths.errPath);\n if (which === 'structured') toReplay.push(paths.structuredPath);\n }\n\n if (toReplay.length) {\n stdout.write('\\n------------ replay ------------\\n');\n for (const p of toReplay) {\n stdout.write(`\\n--- ${p} (last ~${Math.floor(replayBytes / 1024)}KB) ---\\n`);\n await replayFileTailToStdout(p, replayBytes, (s) => stdout.write(s));\n }\n stdout.write('\\n--------------------------------\\n\\n');\n }\n }\n\n const attach = async (id: number): Promise<void> => {\n d('attach()', `id=${id}`); // at function entry\n\n const w = workers.get(id);\n if (!w) return;\n\n // Detach any previous focus\n if (mode === 'attached') detach();\n\n mode = 'attached';\n focus = id;\n\n // UX: clear + banner\n onEnterAttachScreen?.(id);\n\n onAttach?.(id); // prints “Attached to worker …” and clears\n await replayLogs(id); // now the tail stays visible\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n outHandler = (chunk: any) => stdout.write(chunk);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n errHandler = (chunk: any) => stderr.write(chunk);\n w.stdout?.on('data', outHandler);\n w.stderr?.on('data', errHandler);\n\n // auto-detach if child exits\n const onExit = (): void => {\n if (focus === id) detach();\n };\n w.once('exit', onExit);\n };\n\n const detach = (): void => {\n d('detach()', `id=${focus}`); // at function entry\n\n if (focus == null) return;\n const id = focus;\n const w = workers.get(id);\n if (w) {\n if (outHandler) w.stdout?.off('data', outHandler);\n if (errHandler) w.stderr?.off('data', errHandler);\n }\n outHandler = null;\n errHandler = null;\n focus = null;\n mode = 'dashboard';\n onDetach?.();\n };\n\n const onKey = (str: string, key: readline.Key): void => {\n d(\n 'keypress',\n JSON.stringify({\n str,\n name: key.name,\n seq: key.sequence,\n ctrl: key.ctrl,\n meta: key.meta,\n shift: key.shift,\n mode,\n }),\n );\n const act = keymap(str, key, mode);\n d('mapped', JSON.stringify(act));\n\n if (!act) return;\n\n // eslint-disable-next-line default-case\n switch (act.type) {\n case 'CTRL_C': {\n d('CTRL_C');\n if (mode === 'attached' && focus != null) {\n const w = workers.get(focus);\n try {\n w?.kill('SIGINT');\n } catch {\n // noop\n }\n // optional: auto-detach so second Ctrl+C exits parent\n detach();\n return;\n }\n onCtrlC?.();\n return;\n }\n\n case 'ATTACH': {\n d('ATTACH', `id=${act.id}`, `has=${workers.has(act.id)}`);\n\n if (mode !== 'dashboard') return;\n // eslint-disable-next-line no-void\n if (workers.has(act.id)) void attach(act.id);\n return;\n }\n\n case 'CYCLE': {\n d('CYCLE', `delta=${act.delta}`);\n if (mode !== 'dashboard') return;\n const next = cycleWorkers(getWorkerIds(workers), focus, act.delta);\n // eslint-disable-next-line no-void\n if (next != null) void attach(next);\n return;\n }\n\n case 'QUIT': {\n if (mode !== 'dashboard') return;\n onCtrlC?.();\n return;\n }\n\n case 'DETACH': {\n d('DETACH');\n if (mode === 'attached') detach();\n return;\n }\n\n case 'CTRL_D': {\n if (mode === 'attached' && focus != null) {\n const w = workers.get(focus);\n try {\n w?.stdin?.end();\n } catch {\n // noop\n }\n }\n return;\n }\n\n case 'FORWARD': {\n if (mode === 'attached' && focus != null) {\n const w = workers.get(focus);\n try {\n w?.stdin?.write(act.sequence);\n } catch {\n // noop\n }\n }\n }\n }\n };\n\n // Raw bytes fallback (usually not hit because keypress handles it)\n const onData = (chunk: Buffer): void => {\n if (mode === 'attached' && focus != null) {\n const w = workers.get(focus);\n try {\n w?.stdin?.write(chunk);\n } catch {\n // noop\n }\n }\n };\n\n const cleanup = (): void => {\n stdin.off('keypress', onKey);\n stdin.off('data', onData);\n stdin.setRawMode?.(false);\n stdout.write('\\x1b[?25h');\n };\n\n stdin.on('keypress', onKey);\n stdin.on('data', onData);\n\n return cleanup;\n}\n","// lib/pooling/dashboardPlugin.ts\nimport * as readline from 'node:readline';\n\nimport type { ObjByString } from '@transcend-io/type-utils';\nimport type { SlotState } from '@transcend-io/utils';\nimport colors from 'colors';\n\n/**\n * A dashboard plugin defines how to render the worker pool UI.\n * Commands can supply a plugin to customize:\n * - The header block (summary stats, title, etc.)\n * - Per-worker rows (one line per worker slot)\n * - Optional extras (artifact exports, breakdowns, footers)\n *\n * @template TTotals - The shape of the aggregate totals object maintained by the command.\n */\nexport interface DashboardPlugin<TTotals, TSlotState extends ObjByString> {\n /**\n * Render the header block of the dashboard.\n *\n * @param ctx - Context with pool/worker state, totals, and metadata.\n * @returns An array of strings, each representing one line in the header.\n */\n renderHeader: (ctx: CommonCtx<TTotals, TSlotState>) => string[];\n\n /**\n * Render per-worker rows, usually one line per worker slot.\n *\n * @param ctx - Context with pool/worker state, totals, and metadata.\n * @returns An array of strings, each representing one row in the workers section.\n */\n renderWorkers: (ctx: CommonCtx<TTotals, TSlotState>) => string[];\n\n /**\n * Render any optional extra blocks that appear after the worker rows.\n * Useful for printing export paths, aggregated metrics, breakdowns, etc.\n *\n * @param ctx - Context with pool/worker state, totals, and metadata.\n * @returns An array of strings, each representing one additional line.\n */\n renderExtras?: (ctx: CommonCtx<TTotals, TSlotState>) => string[];\n}\n\n/**\n * Shared context object passed into all render methods of a {@link DashboardPlugin}.\n *\n * @template TTotals - The shape of the aggregate totals object maintained by the command.\n */\nexport type CommonCtx<TTotals, TSlotState extends ObjByString> = {\n /** Human-readable title for the dashboard (e.g., \"Parallel uploader\"). */\n title: string;\n\n /** Number of worker processes spawned in the pool. */\n poolSize: number;\n\n /** Logical CPU count, included for informational display. */\n cpuCount: number;\n\n /** Total number of \"files\" or logical units the command expects to process. */\n filesTotal: number;\n\n /** Count of successfully completed files/tasks. */\n filesCompleted: number;\n\n /** Count of failed files/tasks. */\n filesFailed: number;\n\n /**\n * State of each worker slot, keyed by worker id.\n * Includes busy flag, file label, start time, last log badge, and progress.\n */\n workerState: Map<number, SlotState<TSlotState>>;\n\n /**\n * Aggregate totals maintained by the command’s hook logic.\n * Domain-specific metrics (e.g., rows uploaded, bytes processed) can be surfaced here.\n */\n totals: TTotals;\n\n /**\n * Throughput metrics tracked by the runner:\n * - successSoFar: convenience alias for completed count\n * - r10s: completions/sec averaged over last 10s\n * - r60s: completions/sec averaged over last 60s\n */\n throughput: {\n /** Cumulative count of successful completions so far. */\n successSoFar: number;\n /** Recent file-level throughput rate over the last 10 seconds. */\n r10s: number;\n /** Recent file-level throughput rate over the last 60 seconds. */\n r60s: number;\n /** Recent job/record-level throughput rate over the last 10 seconds. */\n jobsR10s: number;\n /** Recent job/record-level throughput rate over the last 60 seconds. */\n jobsR60s: number;\n };\n\n /** True when the pool has fully drained and all workers have exited. */\n final: boolean;\n\n /**\n * Optional export status payload provided by the command.\n * Useful for rendering artifact paths or \"latest export\" summaries.\n */\n exportStatus?: Record<string, unknown>;\n};\n\n/** The most recently rendered frame, cached to suppress flicker from duplicate renders. */\nlet lastFrame = '';\n\n/**\n * Generate the hotkeys hint string that appears at the bottom of the dashboard.\n *\n * @param poolSize - The number of worker slots in the pool.\n * @param final - Whether the run has completed.\n * @returns A dimmed string listing the supported hotkeys for attach/detach/quit.\n */\nexport const hotkeysHint = (poolSize: number, final: boolean): string => {\n const maxDigit = Math.min(poolSize - 1, 9);\n const digitRange = poolSize <= 1 ? '0' : `0-${maxDigit}`;\n const extra = poolSize > 10 ? ' (Tab/Shift+Tab for ≥10)' : '';\n return final\n ? colors.dim(\n 'Run complete — digits to view logs • Tab/Shift+Tab cycle • Esc/Ctrl+] detach • q to quit',\n )\n : colors.dim(\n `Hotkeys: [${digitRange}] attach${extra} • e=errors • w=warnings • i=info • l=logs • ` +\n 'Tab/Shift+Tab • Esc/Ctrl+] detach • Ctrl+C exit',\n );\n};\n\n/**\n * Render the dashboard using a supplied {@link DashboardPlugin}.\n *\n * The frame is composed of:\n * - Header lines\n * - A blank separator\n * - Worker rows\n * - A blank separator\n * - Hotkeys hint\n * - Optional extras (if plugin supplies them)\n *\n * Optimizations:\n * - Suppresses re-renders if the frame is identical to the previous frame (flicker-free).\n * - Hides the terminal cursor during live updates, restoring it when final.\n *\n * @param ctx - Shared context containing pool state, worker state, totals, throughput, etc.\n * @param plugin - The plugin that defines how to render the header, workers, and optional extras.\n * @param viewerMode - If true, renders in viewer mode (no ability to switch between files).\n */\nexport function dashboardPlugin<TTotals, TSlotState extends ObjByString>(\n ctx: CommonCtx<TTotals, TSlotState>,\n plugin: DashboardPlugin<TTotals, TSlotState>,\n viewerMode = false,\n): void {\n const frame = [\n ...plugin.renderHeader(ctx),\n '',\n ...plugin.renderWorkers(ctx),\n ...(viewerMode ? [] : ['', hotkeysHint(ctx.poolSize, ctx.final)]),\n ...(plugin.renderExtras ? [''].concat(plugin.renderExtras(ctx)) : []),\n ].join('\\n');\n\n // Skip duplicate renders during live runs to avoid flicker.\n if (!ctx.final && frame === lastFrame) return;\n lastFrame = frame;\n\n if (!ctx.final) {\n // Hide cursor and repaint in place\n process.stdout.write('\\x1b[?25l');\n readline.cursorTo(process.stdout, 0, 0);\n readline.clearScreenDown(process.stdout);\n } else {\n // Restore cursor on final render\n process.stdout.write('\\x1b[?25h');\n }\n process.stdout.write(`${frame}\\n`);\n}\n","import { basename } from 'node:path';\n\nimport type { ObjByString } from '@transcend-io/type-utils';\nimport colors from 'colors';\n\nimport type { CommonCtx } from './dashboardPlugin.js';\n\n/**\n * Progress snapshot for a worker slot in the chunk-csv command.\n */\nexport type ChunkSlotProgress = {\n /** Absolute path of the file being processed by this worker. */\n filePath?: string;\n /** Number of rows processed so far in this file. */\n processed?: number;\n /** Optional total number of rows in the file (if known). */\n total?: number;\n};\n\n/**\n * Format a number safely for display.\n *\n * @param n - The number to format (or `undefined`).\n * @returns A localized string representation, or \"0\".\n */\nexport function fmtNum(n: number | undefined): string {\n return typeof n === 'number' ? n.toLocaleString() : '0';\n}\n\n/**\n * Draw a horizontal bar of length `width` filled to `pct` percent.\n *\n * @param pct - Percentage 0..100.\n * @param width - Number of characters in the bar.\n * @returns A string like \"████░░░░\".\n */\nexport function pctBar(pct: number, width = 40): string {\n const clamped = Math.max(0, Math.min(100, Math.floor(pct)));\n const filled = Math.floor((clamped / 100) * width);\n return '█'.repeat(filled) + '░'.repeat(width - filled);\n}\n\n/**\n * Compute pool-wide progress values needed by headers.\n *\n * @param ctx - Dashboard context containing pool state, worker state, totals, etc.\n * @returns An object with `done`, `inProgress`, and `pct` properties.\n */\nexport function poolProgress<TTotals, TSlot extends ObjByString>(\n ctx: CommonCtx<TTotals, TSlot>,\n): {\n /** Count of successfully completed files/tasks. */\n done: number;\n /** Count of currently in-progress files/tasks. */\n inProgress: number;\n /** Percentage of completion (0-100). */\n pct: number;\n} {\n const inProgress = [...ctx.workerState.values()].filter((s) => s.busy).length;\n const done = ctx.filesCompleted + ctx.filesFailed;\n const pct = ctx.filesTotal === 0 ? 100 : Math.floor((done / Math.max(1, ctx.filesTotal)) * 100);\n return { done, inProgress, pct };\n}\n\n/**\n * Compose the common header lines (title, pool stats, progress bar, throughput).\n *\n * @param ctx - Dashboard context.\n * @param extraLines - Optional extra lines (e.g., totals block).\n * @returns Header lines.\n */\nexport function makeHeader<TTotals, TSlot extends ObjByString>(\n ctx: CommonCtx<TTotals, TSlot>,\n extraLines: string[] = [],\n): string[] {\n const { title, poolSize, cpuCount, filesTotal, filesCompleted, filesFailed, throughput } = ctx;\n const { inProgress, pct } = poolProgress(ctx);\n\n const lines: string[] = [\n `${colors.bold(title)} — ${poolSize} workers ${colors.dim(`(CPU avail: ${cpuCount})`)}`,\n `${colors.dim('Files')} ${fmtNum(filesTotal)} ${colors.dim(\n 'Completed',\n )} ${fmtNum(filesCompleted)} ${colors.dim('Failed')} ${\n filesFailed ? colors.red(fmtNum(filesFailed)) : fmtNum(filesFailed)\n } ${colors.dim('In-flight')} ${fmtNum(inProgress)}`,\n `[${pctBar(pct)}] ${pct}%`,\n ];\n\n if (throughput) {\n const jobsActive = throughput.jobsR10s > 0 || throughput.jobsR60s > 0;\n const perHour10 = Math.round(\n (jobsActive ? throughput.jobsR10s : throughput.r10s) * 3600,\n ).toLocaleString();\n const perHour60 = Math.round(\n (jobsActive ? throughput.jobsR60s : throughput.r60s) * 3600,\n ).toLocaleString();\n const unit = jobsActive ? 'rec' : 'files';\n const suffix =\n ctx.throughput?.successSoFar != null\n ? ` Newly uploaded: ${fmtNum(ctx.throughput.successSoFar)}`\n : '';\n lines.push(\n colors.cyan(`Throughput: ${perHour10} ${unit}/hr (1h: ${perHour60} ${unit}/hr)${suffix}`),\n );\n }\n\n return extraLines.length ? lines.concat(extraLines) : lines;\n}\n\n/**\n * Render per-worker rows with a compact progress bar and status badge.\n *\n * @param ctx - Dashboard context (slot progress type must have processed/total?).\n * @param getFileLabel - Optional: override how the filename is shown.\n * @returns Array of strings, each representing one worker row.\n */\nexport function makeWorkerRows<TTotals, TSlot extends Omit<ChunkSlotProgress, 'filePath'>>(\n ctx: CommonCtx<TTotals, TSlot>,\n getFileLabel: (file: string | null | undefined) => string = (file) =>\n file ? basename(file) : '-',\n): string[] {\n const miniWidth = 18;\n\n return [...ctx.workerState.entries()].map(([id, s]) => {\n const badge =\n s.lastLevel === 'error'\n ? colors.red('ERROR ')\n : s.lastLevel === 'warn'\n ? colors.yellow('WARN ')\n : s.busy\n ? colors.green('WORKING')\n : colors.dim('IDLE ');\n\n const fname = getFileLabel(s.file);\n const elapsed = s.startedAt ? `${Math.floor((Date.now() - s.startedAt) / 1000)}s` : '-';\n\n const processed = s.progress?.processed ?? 0;\n const total = s.progress?.total ?? 0;\n const pctw = total > 0 ? Math.floor((processed / total) * 100) : 0;\n const mini = total > 0 ? pctBar(pctw, miniWidth) : ' '.repeat(miniWidth);\n const miniTxt =\n total > 0\n ? `${processed.toLocaleString()}/${total.toLocaleString()} (${pctw}%)`\n : colors.dim('—');\n\n return ` [w${id}] ${badge} | ${fname} | ${elapsed} | [${mini}] ${miniTxt}`;\n });\n}\n","import type { ExportStatusMap, SlotPaths } from '@transcend-io/utils';\n\nimport { showCombinedLogs, type LogLocation } from './showCombinedLogs.js';\n\n/** Severity filter applied by the viewer. */\ntype ViewLevel = 'error' | 'warn' | 'all';\n\n/**\n * Options for {@link createExtraKeyHandler}.\n */\nexport type CreateExtraKeyHandlerOpts = {\n /**\n * Per-slot log file paths maintained by the runner; used to stream or export logs.\n */\n logsBySlot: SlotPaths;\n\n /**\n * Request an immediate dashboard repaint (e.g., after updating export status).\n */\n repaint: () => void;\n\n /**\n * Pause/unpause dashboard repainting. The handler pauses while a viewer is open\n * to prevent the dashboard from overwriting the viewer output, then resumes on exit.\n */\n setPaused: (p: boolean) => void;\n\n /**\n * Optional export manager to enable uppercase export keys:\n * - `E` (errors) • `W` (warnings) • `I` (info) • `A` (all)\n *\n * Provide this only if your command supports writing combined log files.\n */\n exportMgr?: {\n /** Destination directory for exported artifacts. */\n exportsDir: string;\n /**\n * Write a combined log file for the selected severity and return the absolute path.\n *\n * @param logs - Log paths to combine.\n * @param which - Severity selection.\n * @returns Absolute path to the written file.\n */\n exportCombinedLogs: (logs: SlotPaths, which: 'error' | 'warn' | 'info' | 'all') => string;\n };\n\n /**\n * Optional “Exports” status map. If provided, the handler updates timestamps\n * when exports are written so your dashboard panel can reflect “last saved” times.\n */\n exportStatus?: ExportStatusMap;\n\n /**\n * Optional custom key bindings for command-specific actions.\n * Each handler receives helpers to print messages and to update the exports panel.\n *\n * Example:\n * ```ts\n * custom: {\n * F: async ({ say, noteExport }) => {\n * const p = await writeFailingUpdatesCsv(...);\n * say(`Wrote failing updates to: ${p}`);\n * noteExport('failuresCsv', p);\n * }\n * }\n * ```\n */\n custom?: Record<\n string,\n (ctx: {\n /** Update {@link exportStatus} (if present) and repaint the dashboard. */\n noteExport: (slot: keyof ExportStatusMap, absPath: string) => void;\n /** Print a line to stdout, automatically newline-terminated. */\n say: (s: string) => void;\n }) => void | Promise<void>\n >;\n};\n\n/**\n * Create a keypress handler for interactive viewers/exports.\n * Shared handler for \"extra\" keyboard shortcuts used by the interactive dashboard.\n *\n * It wires:\n * - **Viewers (lowercase):** `e` (errors), `w` (warnings), `i` (info), `l` (all)\n * - **Exports (uppercase, optional):** `E` (errors), `W` (warnings), `I` (info), `A` (all)\n * - **Dismiss:** `Esc` or `Ctrl+]` exits a viewer and returns to the dashboard\n * - **Custom keys (optional):** Provide a `custom` map to handle command-specific bindings\n *\n * Usage (inside `runPool({... extraKeyHandler })`):\n * ```ts\n * extraKeyHandler: ({ logsBySlot, repaint, setPaused }) =>\n * createExtraKeyHandler({ logsBySlot, repaint, setPaused })\n * ```\n *\n * If you also want export hotkeys + an \"Exports\" panel:\n * ```ts\n * extraKeyHandler: ({ logsBySlot, repaint, setPaused }) =>\n * createExtraKeyHandler({\n * logsBySlot, repaint, setPaused,\n * exportMgr, // enables E/W/I/A\n * exportStatus, // keeps panel timestamps up to date\n * custom: { // optional, e.g. 'F' to export a CSV\n * F: async ({ say, noteExport }) => { ... }\n * }\n * })\n * ```\n *\n * @param opts - Configuration for viewers, exports, and custom keys.\n * @returns A `(buf: Buffer) => void` handler suitable for `process.stdin.on('data', ...)`.\n */\nexport function createExtraKeyHandler(opts: CreateExtraKeyHandlerOpts): (buf: Buffer) => void {\n const { logsBySlot, repaint, setPaused, exportMgr, exportStatus, custom } = opts;\n\n const say = (s: string): void => {\n process.stdout.write(`${s}\\n`);\n };\n\n /**\n * Record that an export was written and trigger a repaint so the dashboard’s\n * \"Exports\" panel shows the updated timestamp/path.\n *\n * @param slot - Slot name in {@link ExportStatusMap} (e.g., \"error\", \"warn\", etc.).\n * @param p - Absolute path to the exported file.\n */\n const noteExport = (slot: keyof ExportStatusMap, p: string): void => {\n const now = Date.now();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cur: any = exportStatus?.[slot] ?? { path: p };\n if (exportStatus) {\n exportStatus[slot] = {\n path: p || cur.path,\n savedAt: now,\n exported: true,\n };\n repaint();\n }\n };\n\n let viewing = false; // optional guard to prevent stacking viewers\n\n /**\n * Show an inline combined log viewer for the selected sources/level.\n * Pauses dashboard repaint to keep the viewer visible until the user exits.\n *\n * @param sources - Log sources to include (e.g., \"err\", \"warn\", \"info\").\n * @param level - Severity level to filter by (e.g., \"error\", \"warn\", \"all\").\n */\n const view = (sources: LogLocation[], level: ViewLevel): void => {\n if (viewing) return;\n viewing = true;\n setPaused(true);\n\n // optional UX: clear screen and show a hint\n process.stdout.write('\\x1b[2J\\x1b[H'); // clear+home\n process.stdout.write('Combined logs viewer (press Esc or Ctrl+] to return)\\n\\n');\n\n (async () => {\n try {\n await showCombinedLogs(logsBySlot, sources, level);\n // NOTE: do NOT unpause here; ESC will handle it.\n } catch {\n // If showCombinedLogs throws, recover and unpause\n viewing = false;\n setPaused(false);\n repaint();\n }\n })();\n };\n\n /**\n * Export combined logs (if an export manager was provided).\n *\n * @param which - Severity to export (e.g., \"error\", \"warn\", \"info\", \"all\").\n * @param label - Human-readable label for the export (e.g., \"error\", \"warn\").\n */\n const exportCombined = (which: 'error' | 'warn' | 'info' | 'all', label: string): void => {\n if (!exportMgr) return;\n try {\n const p = exportMgr.exportCombinedLogs(logsBySlot, which);\n say(`\\nWrote combined ${label} logs to: ${p}`);\n noteExport(which as keyof ExportStatusMap, p);\n } catch {\n say(`\\nFailed to write combined ${label} logs`);\n }\n };\n\n // The keypress handler the runner will attach to stdin.\n return (buf: Buffer): void => {\n const s = buf.toString('utf8');\n\n // Viewers (lowercase)\n if (s === 'e') {\n view(['err'], 'error');\n return;\n }\n if (s === 'w') {\n view(['warn', 'err'], 'warn');\n return;\n }\n if (s === 'i') {\n view(['info'], 'all');\n return;\n }\n if (s === 'l') {\n view(['out', 'err', 'structured'], 'all');\n return;\n }\n\n // Exports (uppercase) — enabled only when exportMgr is present\n if (s === 'E') {\n exportCombined('error', 'error');\n return;\n }\n if (s === 'W') {\n exportCombined('warn', 'warn');\n return;\n }\n if (s === 'I') {\n exportCombined('info', 'info');\n return;\n }\n if (s === 'A') {\n exportCombined('all', 'ALL');\n return;\n }\n\n // Command-specific bindings\n const fn = custom?.[s];\n if (fn) {\n fn({ noteExport, say });\n return;\n }\n\n // Exit a viewer (Esc / Ctrl+]) — resume dashboard\n if (s === '\\x1b' || s === '\\x1d') {\n viewing = false;\n setPaused(false);\n repaint();\n }\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
1
  import{union as e}from"lodash-es";function t(t,{adTechPurposes:n=[`SaleOfInfo`],serviceToTitle:r,serviceToSupportedIntegration:i}){let a=[],o=[],s={};t.forEach(t=>{let{service:r,attributes:i=[]}=t;if(!r||r===`internalService`)return;let c=i.find(e=>e.key===`Found on Domain`);c&&(s[r]||(s[r]=[]),s[r].push(...c.values.map(e=>e.replace(`https://`,``).replace(`http://`,``))),s[r]=[...new Set(s[r])]),e(t.trackingPurposes,n).length>0?(o.push(r),a.includes(r)&&(a=a.filter(e=>e!==r))):o.includes(r)||a.push(r)});let c=[...new Set(o)].map(e=>({title:r[e],...i[e]?{integrationName:e}:{integrationName:`promptAPerson`,"outer-type":e},attributes:[{key:`Tech Type`,values:[`Ad Tech`]},{key:`Found On Domain`,values:s[e]||[]}]}));return{siteTechDataSilos:[...new Set(a)].map(e=>({title:r[e],...i[e]?{integrationName:e}:{integrationName:`promptAPerson`,outerType:e},attributes:[{key:`Tech Type`,values:[`Site Tech`]},{key:`Found On Domain`,values:s[e]||[]}]})),adTechDataSilos:c}}export{t};
2
- //# sourceMappingURL=dataFlowsToDataSilos-NhvBw1iy.mjs.map
2
+ //# sourceMappingURL=dataFlowsToDataSilos-DUj1NhOt.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataFlowsToDataSilos-DUj1NhOt.mjs","names":[],"sources":["../src/lib/consent-manager/dataFlowsToDataSilos.ts"],"sourcesContent":["import { type IndexedCatalogs } from '@transcend-io/sdk';\nimport { union } from 'lodash-es';\n\nimport { DataFlowInput, DataSiloInput } from '../../codecs.js';\n\n/**\n * Convert data flow configurations into a set of data silo configurations\n *\n * @param inputs - Data flow input to convert to data silos\n * @param options - Additional options\n * @returns Business entity configuration input\n */\nexport function dataFlowsToDataSilos(\n inputs: DataFlowInput[],\n {\n adTechPurposes = ['SaleOfInfo'],\n serviceToTitle,\n serviceToSupportedIntegration,\n }: IndexedCatalogs & {\n /** List of purposes that are considered \"Ad Tech\" */\n adTechPurposes?: string[];\n },\n): {\n /** List of data silo configurations for site-tech services */\n siteTechDataSilos: DataSiloInput[];\n /** List of data silo configurations for ad-tech services */\n adTechDataSilos: DataSiloInput[];\n} {\n // List of site tech integrations\n let siteTechIntegrations: string[] = [];\n\n // List of ad tech integrations\n const adTechIntegrations: string[] = [];\n\n // Mapping from service name to list of\n const serviceToFoundOnDomain: { [k in string]: string[] } = {};\n\n // iterate over each flow\n inputs.forEach((flow) => {\n // process data flows with services\n const { service, attributes = [] } = flow;\n if (!service || service === 'internalService') {\n return;\n }\n\n // create mapping to found on domain\n const foundOnDomain = attributes.find((attr) => attr.key === 'Found on Domain');\n\n // Create a list of all domains where the data flow was found\n if (foundOnDomain) {\n if (!serviceToFoundOnDomain[service]) {\n serviceToFoundOnDomain[service] = [];\n }\n serviceToFoundOnDomain[service]!.push(\n ...foundOnDomain.values.map((v) => v.replace('https://', '').replace('http://', '')),\n );\n serviceToFoundOnDomain[service] = [...new Set(serviceToFoundOnDomain[service])];\n }\n\n // Keep track of ad tech\n if (union(flow.trackingPurposes, adTechPurposes).length > 0) {\n // add service to ad tech list\n adTechIntegrations.push(service);\n\n // remove from site tech list\n if (siteTechIntegrations.includes(service)) {\n siteTechIntegrations = siteTechIntegrations.filter((s) => s !== service);\n }\n } else if (!adTechIntegrations.includes(service)) {\n // add to site tech list\n siteTechIntegrations.push(service);\n }\n });\n\n // create the list of ad tech integrations\n const adTechDataSilos = [...new Set(adTechIntegrations)].map((service) => ({\n title: serviceToTitle[service],\n ...(serviceToSupportedIntegration[service]\n ? { integrationName: service }\n : { integrationName: 'promptAPerson', 'outer-type': service }),\n attributes: [\n {\n key: 'Tech Type',\n values: ['Ad Tech'],\n },\n {\n key: 'Found On Domain',\n values: serviceToFoundOnDomain[service] || [],\n },\n ],\n }));\n\n // create the list of site tech integrations\n const siteTechDataSilos = [...new Set(siteTechIntegrations)].map((service) => ({\n title: serviceToTitle[service],\n ...(serviceToSupportedIntegration[service]\n ? { integrationName: service }\n : { integrationName: 'promptAPerson', outerType: service }),\n attributes: [\n {\n key: 'Tech Type',\n values: ['Site Tech'],\n },\n {\n key: 'Found On Domain',\n values: serviceToFoundOnDomain[service] || [],\n },\n ],\n }));\n\n return {\n siteTechDataSilos,\n adTechDataSilos,\n };\n}\n"],"mappings":"kCAYA,SAAgB,EACd,EACA,CACE,iBAAiB,CAAC,aAAa,CAC/B,iBACA,iCAUF,CAEA,IAAI,EAAiC,EAAE,CAGjC,EAA+B,EAAE,CAGjC,EAAsD,EAAE,CAG9D,EAAO,QAAS,GAAS,CAEvB,GAAM,CAAE,UAAS,aAAa,EAAE,EAAK,EACrC,GAAI,CAAC,GAAW,IAAY,kBAC1B,OAIF,IAAM,EAAgB,EAAW,KAAM,GAAS,EAAK,MAAQ,kBAAkB,CAG3E,IACG,EAAuB,KAC1B,EAAuB,GAAW,EAAE,EAEtC,EAAuB,GAAU,KAC/B,GAAG,EAAc,OAAO,IAAK,GAAM,EAAE,QAAQ,WAAY,GAAG,CAAC,QAAQ,UAAW,GAAG,CAAC,CACrF,CACD,EAAuB,GAAW,CAAC,GAAG,IAAI,IAAI,EAAuB,GAAS,CAAC,EAI7E,EAAM,EAAK,iBAAkB,EAAe,CAAC,OAAS,GAExD,EAAmB,KAAK,EAAQ,CAG5B,EAAqB,SAAS,EAAQ,GACxC,EAAuB,EAAqB,OAAQ,GAAM,IAAM,EAAQ,GAEhE,EAAmB,SAAS,EAAQ,EAE9C,EAAqB,KAAK,EAAQ,EAEpC,CAGF,IAAM,EAAkB,CAAC,GAAG,IAAI,IAAI,EAAmB,CAAC,CAAC,IAAK,IAAa,CACzE,MAAO,EAAe,GACtB,GAAI,EAA8B,GAC9B,CAAE,gBAAiB,EAAS,CAC5B,CAAE,gBAAiB,gBAAiB,aAAc,EAAS,CAC/D,WAAY,CACV,CACE,IAAK,YACL,OAAQ,CAAC,UAAU,CACpB,CACD,CACE,IAAK,kBACL,OAAQ,EAAuB,IAAY,EAAE,CAC9C,CACF,CACF,EAAE,CAoBH,MAAO,CACL,kBAlBwB,CAAC,GAAG,IAAI,IAAI,EAAqB,CAAC,CAAC,IAAK,IAAa,CAC7E,MAAO,EAAe,GACtB,GAAI,EAA8B,GAC9B,CAAE,gBAAiB,EAAS,CAC5B,CAAE,gBAAiB,gBAAiB,UAAW,EAAS,CAC5D,WAAY,CACV,CACE,IAAK,YACL,OAAQ,CAAC,YAAY,CACtB,CACD,CACE,IAAK,kBACL,OAAQ,EAAuB,IAAY,EAAE,CAC9C,CACF,CACF,EAAE,CAID,kBACD"}
@@ -299,4 +299,4 @@ import{gql as e}from"graphql-request";const t=e`
299
299
  }
300
300
  }
301
301
  `;export{d as a,n as c,a as d,o as f,l as i,r as l,c as n,s as o,u as r,t as s,f as t,i as u};
302
- //# sourceMappingURL=dataSilo-DrFetFXw.mjs.map
302
+ //# sourceMappingURL=dataSilo-Dvi8-PkH.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataSilo-DrFetFXw.mjs","names":[],"sources":["../src/lib/graphql/gqls/dataPoint.ts","../src/lib/graphql/gqls/dataSilo.ts"],"sourcesContent":["import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_POINTS = gql`\n query TranscendCliDataPoints($filterBy: DataPointFiltersInput, $first: Int!, $offset: Int!) {\n dataPoints(\n filterBy: $filterBy\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n title {\n defaultMessage\n }\n description {\n defaultMessage\n }\n owners {\n email\n }\n teams {\n name\n }\n name\n path\n actionSettings {\n type\n active\n }\n dataCollection {\n title {\n defaultMessage\n }\n }\n dbIntegrationQueries {\n query\n suggestedQuery\n requestType\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_POINT_COUNT = gql`\n query TranscendCliDataPointCount($filterBy: DataPointFiltersInput) {\n dataPoints(filterBy: $filterBy, useMaster: false) {\n totalCount\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - add orderBy\n// isExportCsv: true\nexport const SUB_DATA_POINTS = gql`\n query TranscendCliSubDataPoints(\n $filterBy: SubDataPointFiltersInput\n $first: Int!\n $offset: Int!\n ) {\n subDataPoints(filterBy: $filterBy, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n name\n description\n purposes {\n name\n purpose\n }\n categories {\n name\n category\n }\n accessRequestVisibilityEnabled\n erasureRequestRedactionEnabled\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const SUB_DATA_POINTS_COUNT = gql`\n query TranscendCliSubDataPointsCount($filterBy: SubDataPointFiltersInput) {\n subDataPoints(filterBy: $filterBy, useMaster: false) {\n totalCount\n }\n }\n`;\n\nexport const SUB_DATA_POINTS_WITH_GUESSES = gql`\n query TranscendCliSubDataPointGuesses(\n $filterBy: SubDataPointFiltersInput\n $first: Int!\n $offset: Int!\n ) {\n subDataPoints(filterBy: $filterBy, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n name\n description\n purposes {\n name\n purpose\n }\n categories {\n name\n category\n }\n pendingCategoryGuesses {\n category {\n name\n category\n }\n status\n confidence\n classifierVersion\n }\n accessRequestVisibilityEnabled\n erasureRequestRedactionEnabled\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const UPDATE_OR_CREATE_DATA_POINT = gql`\n mutation TranscendCliUpdateOrCreateDataPoint(\n $dataSiloId: ID!\n $name: String!\n $path: [String!]\n $title: String\n $description: String\n $ownerIds: [ID!]\n $ownerEmails: [String!]\n $teamNames: [String!]\n $teamIds: [ID!]\n $dataCollectionTag: String\n $querySuggestions: [DbIntegrationQuerySuggestionInput!]\n $enabledActions: [RequestActionObjectResolver!]\n $subDataPoints: [DataPointSubDataPointInput!]\n ) {\n updateOrCreateDataPoint(\n input: {\n dataSiloId: $dataSiloId\n name: $name\n path: $path\n title: $title\n teamNames: $teamNames\n ownerEmails: $ownerEmails\n dataCollectionTag: $dataCollectionTag\n description: $description\n ownerIds: $ownerIds\n teamIds: $teamIds\n querySuggestions: $querySuggestions\n enabledActions: $enabledActions\n subDataPoints: $subDataPoints\n }\n ) {\n dataPoint {\n id\n name\n }\n }\n }\n`;\n\nexport const DATAPOINT_EXPORT = gql`\n query TranscendCliDataPointCsvExport($filterBy: DataPointFiltersInput, $first: Int!) {\n dataPoints(filterBy: $filterBy, first: $first, useMaster: false) {\n nodes {\n id\n title {\n defaultMessage\n }\n description {\n defaultMessage\n }\n owners {\n email\n }\n teams {\n name\n }\n name\n path\n }\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILOS = gql`\n query TranscendCliDataSilos($filterBy: DataSiloFiltersInput!, $first: Int!, $offset: Int!) {\n dataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n link\n type\n catalog {\n hasAvcFunctionality\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILO_EXPORT = gql`\n query TranscendCliDataSiloExport($filterBy: DataSiloFiltersInput!, $first: Int!) {\n dataSilos(filterBy: $filterBy, first: $first, useMaster: false) {\n nodes {\n id\n title\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILOS_ENRICHED = gql`\n query TranscendCliDataSilosEnriched(\n $filterBy: DataSiloFiltersInput!\n $first: Int!\n $offset: Int!\n ) {\n dataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n description\n type\n outerType\n link\n country\n countrySubDivision\n url\n notifyEmailAddress\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n apiKeys {\n title\n }\n subjectBlocklist {\n type\n }\n identifiers {\n name\n isConnected\n }\n dependentDataSilos {\n title\n }\n owners {\n email\n }\n teams {\n id\n name\n }\n catalog {\n hasAvcFunctionality\n }\n isLive\n promptAVendorEmailSendFrequency\n promptAVendorEmailSendType\n promptAVendorEmailIncludeIdentifiersAttachment\n promptAVendorEmailCompletionLinkType\n manualWorkRetryFrequency\n discoveredBy {\n title\n }\n businessEntities {\n title\n }\n }\n }\n }\n`;\n\nexport const UPDATE_DATA_SILOS = gql`\n mutation TranscendCliUpdateDataSilo($input: UpdateDataSilosInput!) {\n updateDataSilos(input: $input) {\n clientMutationId\n dataSilos {\n id\n title\n }\n }\n }\n`;\n\nexport const CREATE_DATA_SILOS = gql`\n mutation TranscendCliCreateDataSilo($input: [CreateDataSilosInput!]!) {\n createDataSilos(input: $input) {\n dataSilos {\n id\n title\n }\n }\n }\n`;\n"],"mappings":"sCAIA,MAAa,EAAc,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CjB,EAAmB,CAAG;;;;;;EAUtB,EAAkB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCrB,EAAwB,CAAG;;;;;;EAQ3B,EAA+B,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyClC,EAA8B,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyCjC,EAAmB,CAAG;;;;;;;;;;;;;;;;;;;;;;EClLtB,EAAa,CAAG;;;;;;;;;;;;;;;;;;;;EAwBhB,EAAmB,CAAG;;;;;;;;;EAatB,EAAsB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsEzB,EAAoB,CAAG;;;;;;;;;;EAYvB,EAAoB,CAAG"}
1
+ {"version":3,"file":"dataSilo-Dvi8-PkH.mjs","names":[],"sources":["../src/lib/graphql/gqls/dataPoint.ts","../src/lib/graphql/gqls/dataSilo.ts"],"sourcesContent":["import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_POINTS = gql`\n query TranscendCliDataPoints($filterBy: DataPointFiltersInput, $first: Int!, $offset: Int!) {\n dataPoints(\n filterBy: $filterBy\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n title {\n defaultMessage\n }\n description {\n defaultMessage\n }\n owners {\n email\n }\n teams {\n name\n }\n name\n path\n actionSettings {\n type\n active\n }\n dataCollection {\n title {\n defaultMessage\n }\n }\n dbIntegrationQueries {\n query\n suggestedQuery\n requestType\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_POINT_COUNT = gql`\n query TranscendCliDataPointCount($filterBy: DataPointFiltersInput) {\n dataPoints(filterBy: $filterBy, useMaster: false) {\n totalCount\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - add orderBy\n// isExportCsv: true\nexport const SUB_DATA_POINTS = gql`\n query TranscendCliSubDataPoints(\n $filterBy: SubDataPointFiltersInput\n $first: Int!\n $offset: Int!\n ) {\n subDataPoints(filterBy: $filterBy, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n name\n description\n purposes {\n name\n purpose\n }\n categories {\n name\n category\n }\n accessRequestVisibilityEnabled\n erasureRequestRedactionEnabled\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const SUB_DATA_POINTS_COUNT = gql`\n query TranscendCliSubDataPointsCount($filterBy: SubDataPointFiltersInput) {\n subDataPoints(filterBy: $filterBy, useMaster: false) {\n totalCount\n }\n }\n`;\n\nexport const SUB_DATA_POINTS_WITH_GUESSES = gql`\n query TranscendCliSubDataPointGuesses(\n $filterBy: SubDataPointFiltersInput\n $first: Int!\n $offset: Int!\n ) {\n subDataPoints(filterBy: $filterBy, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n name\n description\n purposes {\n name\n purpose\n }\n categories {\n name\n category\n }\n pendingCategoryGuesses {\n category {\n name\n category\n }\n status\n confidence\n classifierVersion\n }\n accessRequestVisibilityEnabled\n erasureRequestRedactionEnabled\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const UPDATE_OR_CREATE_DATA_POINT = gql`\n mutation TranscendCliUpdateOrCreateDataPoint(\n $dataSiloId: ID!\n $name: String!\n $path: [String!]\n $title: String\n $description: String\n $ownerIds: [ID!]\n $ownerEmails: [String!]\n $teamNames: [String!]\n $teamIds: [ID!]\n $dataCollectionTag: String\n $querySuggestions: [DbIntegrationQuerySuggestionInput!]\n $enabledActions: [RequestActionObjectResolver!]\n $subDataPoints: [DataPointSubDataPointInput!]\n ) {\n updateOrCreateDataPoint(\n input: {\n dataSiloId: $dataSiloId\n name: $name\n path: $path\n title: $title\n teamNames: $teamNames\n ownerEmails: $ownerEmails\n dataCollectionTag: $dataCollectionTag\n description: $description\n ownerIds: $ownerIds\n teamIds: $teamIds\n querySuggestions: $querySuggestions\n enabledActions: $enabledActions\n subDataPoints: $subDataPoints\n }\n ) {\n dataPoint {\n id\n name\n }\n }\n }\n`;\n\nexport const DATAPOINT_EXPORT = gql`\n query TranscendCliDataPointCsvExport($filterBy: DataPointFiltersInput, $first: Int!) {\n dataPoints(filterBy: $filterBy, first: $first, useMaster: false) {\n nodes {\n id\n title {\n defaultMessage\n }\n description {\n defaultMessage\n }\n owners {\n email\n }\n teams {\n name\n }\n name\n path\n }\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILOS = gql`\n query TranscendCliDataSilos($filterBy: DataSiloFiltersInput!, $first: Int!, $offset: Int!) {\n dataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n link\n type\n catalog {\n hasAvcFunctionality\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILO_EXPORT = gql`\n query TranscendCliDataSiloExport($filterBy: DataSiloFiltersInput!, $first: Int!) {\n dataSilos(filterBy: $filterBy, first: $first, useMaster: false) {\n nodes {\n id\n title\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILOS_ENRICHED = gql`\n query TranscendCliDataSilosEnriched(\n $filterBy: DataSiloFiltersInput!\n $first: Int!\n $offset: Int!\n ) {\n dataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n description\n type\n outerType\n link\n country\n countrySubDivision\n url\n notifyEmailAddress\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n apiKeys {\n title\n }\n subjectBlocklist {\n type\n }\n identifiers {\n name\n isConnected\n }\n dependentDataSilos {\n title\n }\n owners {\n email\n }\n teams {\n id\n name\n }\n catalog {\n hasAvcFunctionality\n }\n isLive\n promptAVendorEmailSendFrequency\n promptAVendorEmailSendType\n promptAVendorEmailIncludeIdentifiersAttachment\n promptAVendorEmailCompletionLinkType\n manualWorkRetryFrequency\n discoveredBy {\n title\n }\n businessEntities {\n title\n }\n }\n }\n }\n`;\n\nexport const UPDATE_DATA_SILOS = gql`\n mutation TranscendCliUpdateDataSilo($input: UpdateDataSilosInput!) {\n updateDataSilos(input: $input) {\n clientMutationId\n dataSilos {\n id\n title\n }\n }\n }\n`;\n\nexport const CREATE_DATA_SILOS = gql`\n mutation TranscendCliCreateDataSilo($input: [CreateDataSilosInput!]!) {\n createDataSilos(input: $input) {\n dataSilos {\n id\n title\n }\n }\n }\n`;\n"],"mappings":"sCAIA,MAAa,EAAc,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CjB,EAAmB,CAAG;;;;;;EAUtB,EAAkB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCrB,EAAwB,CAAG;;;;;;EAQ3B,EAA+B,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyClC,EAA8B,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyCjC,EAAmB,CAAG;;;;;;;;;;;;;;;;;;;;;;EClLtB,EAAa,CAAG;;;;;;;;;;;;;;;;;;;;EAwBhB,EAAmB,CAAG;;;;;;;;;EAatB,EAAsB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsEzB,EAAoB,CAAG;;;;;;;;;;EAYvB,EAAoB,CAAG"}
@@ -89,4 +89,4 @@ import{gql as e}from"graphql-request";const t=e`
89
89
  }
90
90
  }
91
91
  `;export{r as a,i as c,s as i,a as n,t as o,c as r,n as s,o as t};
92
- //# sourceMappingURL=dataSubject-y_aXI0pa.mjs.map
92
+ //# sourceMappingURL=dataSubject-CF784Ug0.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataSubject-y_aXI0pa.mjs","names":[],"sources":["../src/lib/graphql/gqls/enricher.ts","../src/lib/graphql/gqls/dataSubject.ts"],"sourcesContent":["import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const ENRICHERS = gql`\n query TranscendCliEnrichers($title: String, $first: Int!, $offset: Int!) {\n enrichers(\n filterBy: { text: $title }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n ) {\n nodes {\n id\n title\n url\n type\n expirationDuration\n lookerQueryTitle\n testRegex\n transitionRequestStatus\n phoneNumbers\n regionList\n inputIdentifier {\n name\n }\n identifiers {\n name\n }\n dataSubjects {\n type\n }\n actions\n }\n }\n }\n`;\n\nexport interface Initializer {\n /** ID of enricher */\n id: string;\n /** Identifiers */\n identifiers: {\n /** Name of identifier */\n name: string;\n }[];\n}\n\nexport const INITIALIZER = gql`\n query TranscendCliInitializer {\n initializer {\n id\n identifiers {\n name\n }\n }\n }\n`;\n\nexport const CREATE_ENRICHER = gql`\n mutation TranscendCliCreateEnricher($input: EnricherInput!) {\n createEnricher(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_ENRICHER = gql`\n mutation TranscendCliUpdateEnricher($input: UpdateEnricherInput!) {\n updateEnricher(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\nexport const DATA_SUBJECTS = gql`\n query TranscendCliDataSubjects {\n internalSubjects {\n id\n title {\n defaultMessage\n }\n active\n type\n adminDashboardDefaultSilentMode\n actions {\n type\n }\n }\n }\n`;\n\nexport const CREATE_DATA_SUBJECT = gql`\n mutation TranscendCliCreateDataSubject($type: String!) {\n createSubject(input: { type: $type, title: $type, subjectClass: OTHER }) {\n subject {\n id\n type\n }\n }\n }\n`;\n\nexport const UPDATE_DATA_SUBJECT = gql`\n mutation TranscendCliUpdateDataSubject($input: UpdateSubjectInput!) {\n updateSubject(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_DATA_SUBJECT = gql`\n mutation TranscendCliToggleDataSubject($input: ToggleSubjectInput!) {\n toggleSubject(input: $input) {\n clientMutationId\n }\n }\n`;\n"],"mappings":"sCAIA,MAAa,EAAY,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6Cf,EAAc,CAAG;;;;;;;;;EAWjB,EAAkB,CAAG;;;;;;EAQrB,EAAkB,CAAG;;;;;;EClErB,EAAgB,CAAG;;;;;;;;;;;;;;;EAiBnB,EAAsB,CAAG;;;;;;;;;EAWzB,EAAsB,CAAG;;;;;;EAQzB,EAAsB,CAAG"}
1
+ {"version":3,"file":"dataSubject-CF784Ug0.mjs","names":[],"sources":["../src/lib/graphql/gqls/enricher.ts","../src/lib/graphql/gqls/dataSubject.ts"],"sourcesContent":["import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const ENRICHERS = gql`\n query TranscendCliEnrichers($title: String, $first: Int!, $offset: Int!) {\n enrichers(\n filterBy: { text: $title }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n ) {\n nodes {\n id\n title\n url\n type\n expirationDuration\n lookerQueryTitle\n testRegex\n transitionRequestStatus\n phoneNumbers\n regionList\n inputIdentifier {\n name\n }\n identifiers {\n name\n }\n dataSubjects {\n type\n }\n actions\n }\n }\n }\n`;\n\nexport interface Initializer {\n /** ID of enricher */\n id: string;\n /** Identifiers */\n identifiers: {\n /** Name of identifier */\n name: string;\n }[];\n}\n\nexport const INITIALIZER = gql`\n query TranscendCliInitializer {\n initializer {\n id\n identifiers {\n name\n }\n }\n }\n`;\n\nexport const CREATE_ENRICHER = gql`\n mutation TranscendCliCreateEnricher($input: EnricherInput!) {\n createEnricher(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_ENRICHER = gql`\n mutation TranscendCliUpdateEnricher($input: UpdateEnricherInput!) {\n updateEnricher(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\nexport const DATA_SUBJECTS = gql`\n query TranscendCliDataSubjects {\n internalSubjects {\n id\n title {\n defaultMessage\n }\n active\n type\n adminDashboardDefaultSilentMode\n actions {\n type\n }\n }\n }\n`;\n\nexport const CREATE_DATA_SUBJECT = gql`\n mutation TranscendCliCreateDataSubject($type: String!) {\n createSubject(input: { type: $type, title: $type, subjectClass: OTHER }) {\n subject {\n id\n type\n }\n }\n }\n`;\n\nexport const UPDATE_DATA_SUBJECT = gql`\n mutation TranscendCliUpdateDataSubject($input: UpdateSubjectInput!) {\n updateSubject(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_DATA_SUBJECT = gql`\n mutation TranscendCliToggleDataSubject($input: ToggleSubjectInput!) {\n toggleSubject(input: $input) {\n clientMutationId\n }\n }\n`;\n"],"mappings":"sCAIA,MAAa,EAAY,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6Cf,EAAc,CAAG;;;;;;;;;EAWjB,EAAkB,CAAG;;;;;;EAQrB,EAAkB,CAAG;;;;;;EClErB,EAAgB,CAAG;;;;;;;;;;;;;;;EAiBnB,EAAsB,CAAG;;;;;;;;;EAWzB,EAAsB,CAAG;;;;;;EAQzB,EAAsB,CAAG"}
@@ -1,2 +1,2 @@
1
1
  function e(e){process.env.DEVELOPMENT_MODE_VALIDATE_ONLY===`true`&&e(0)}export{e as t};
2
- //# sourceMappingURL=done-input-validation-DLR0-MJ7.mjs.map
2
+ //# sourceMappingURL=done-input-validation-C5rgR0Wr.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"done-input-validation-DLR0-MJ7.mjs","names":[],"sources":["../src/lib/cli/done-input-validation.ts"],"sourcesContent":["/**\n * If the environment variable `DEVELOPMENT_MODE_VALIDATE_ONLY` is set,\n * this function will exit the process with a status code of 0.\n *\n * This is useful for development mode, where we want to validate the\n * command flags without actually running the command.\n *\n * This should be called after input validation, and must be agnostic to the environment (e.g., the existence of a file on the file system)\n *\n * @param exit - The function to exit the process.\n */\nexport function doneInputValidation(exit: (code?: number) => void): void {\n if (process.env.DEVELOPMENT_MODE_VALIDATE_ONLY === 'true') {\n exit(0);\n }\n}\n"],"mappings":"AAWA,SAAgB,EAAoB,EAAqC,CACnE,QAAQ,IAAI,iCAAmC,QACjD,EAAK,EAAE"}
1
+ {"version":3,"file":"done-input-validation-C5rgR0Wr.mjs","names":[],"sources":["../src/lib/cli/done-input-validation.ts"],"sourcesContent":["/**\n * If the environment variable `DEVELOPMENT_MODE_VALIDATE_ONLY` is set,\n * this function will exit the process with a status code of 0.\n *\n * This is useful for development mode, where we want to validate the\n * command flags without actually running the command.\n *\n * This should be called after input validation, and must be agnostic to the environment (e.g., the existence of a file on the file system)\n *\n * @param exit - The function to exit the process.\n */\nexport function doneInputValidation(exit: (code?: number) => void): void {\n if (process.env.DEVELOPMENT_MODE_VALIDATE_ONLY === 'true') {\n exit(0);\n }\n}\n"],"mappings":"AAWA,SAAgB,EAAoB,EAAqC,CACnE,QAAQ,IAAI,iCAAmC,QACjD,EAAK,EAAE"}
@@ -0,0 +1,2 @@
1
+ import{a as e}from"./constants-XOsAW1__.mjs";import{t}from"./logger-Bj782ZYD.mjs";import{t as n}from"./request-SLqRySNU.mjs";import{r}from"./fetchAllRequests-xGgt_STo.mjs";import{RequestAction as i,RequestStatus as a,TableEncryptionType as o}from"@transcend-io/privacy-types";import{decodeCodec as s,valuesOf as c}from"@transcend-io/type-utils";import{existsSync as l,mkdirSync as u,writeFileSync as d}from"node:fs";import{dirname as f,join as p}from"node:path";import m from"colors";import*as h from"io-ts";import{buildTranscendGraphQLClient as g,createSombraGotInstance as _,makeGraphQLRequest as v}from"@transcend-io/sdk";import{map as y}from"@transcend-io/utils";import b from"cli-progress";const x=h.type({defaultMessage:h.string,id:h.string}),S=h.type({downloadKey:h.string,error:h.union([h.null,h.string]),mimetype:h.string,size:h.string,fileName:h.string,dataPoint:h.type({id:h.string,title:h.union([x,h.null]),description:h.union([x,h.null]),name:h.string,slug:h.string,encryption:h.union([c(o),h.null]),dataSilo:h.type({id:h.string,title:h.string,description:h.string,type:h.string,outerType:h.union([h.string,h.null])}),path:h.array(h.string)})}),C=h.type({nodes:h.array(S),totalCount:h.number,_links:h.partial({next:h.union([h.string,h.null]),previous:h.union([h.string,h.null])})});async function w(e,{sombra:n,concurrency:r=5,limit:i=100}){t.info(m.magenta(`Pulling file metadata for ${e.length} requests`));let a=new Date().getTime(),o=new b.SingleBar({},b.Presets.shades_classic),c=0;o.start(e.length,0);let l=await y(e,async e=>{let t=[],r=!0,a=0;for(;r;){let o;try{o=s(C,await n.get(`v1/data-subject-request/${e.id}/download-keys`,{searchParams:{limit:i,offset:a}}).json()),t.push(...o.nodes),a+=i,r=!!o._links.next&&o.nodes.length===i}catch(e){throw Error(`Received an error from server: ${e?.response?.body||e?.message}`)}}return c+=1,o.update(c),[e,t]},{concurrency:r});o.stop();let u=new Date().getTime()-a;return t.info(m.green(`Successfully downloaded file metadata ${e.length} requests in "${u/1e3}" seconds!`)),l}async function T(e,{requestId:n,sombra:r,onFileDownloaded:i,concurrency:a=20}){await y(e,async e=>{try{await r.get(`v1/files`,{searchParams:{downloadKey:e.downloadKey}}).buffer().then(t=>i(e,t))}catch(r){if(r?.response?.body?.includes(`fileMetadata#verify`)){t.error(m.red(`Failed to pull file for: ${e.fileName} (request:${n}) - JWT expired. This likely means that the file is no longer available. Try restarting the request from scratch in Transcend Admin Dashboard. Skipping the download of this file.`));return}throw Error(`Received an error from server: ${r?.response?.body||r?.message}`)}},{concurrency:a})}async function E({auth:o,folderPath:s,requestIds:c,createdAtBefore:h,sombraAuth:x,createdAtAfter:S,updatedAtBefore:C,updatedAtAfter:E,statuses:D=[a.Approving,a.Downloadable],concurrency:O=5,transcendUrl:k=e,approveAfterDownload:A=!1}){let j=g(k,o),M=await _(k,o,{logger:t,sombraApiKey:x,sombraUrl:process.env.SOMBRA_URL});l(s)||u(s);let N=await r(j,{actions:[i.Access],createdAtBefore:h,createdAtAfter:S,updatedAtBefore:C,updatedAtAfter:E,statuses:D,requestIds:c}),P=await w(N,{sombra:M,concurrency:O}),F=new Date().getTime(),I=new b.SingleBar({},b.Presets.shades_classic),L=0,R=0;I.start(N.length,0),await y(P,async([e,r])=>{let i=p(s,e.id);l(i)||u(i),await T(r,{sombra:M,requestId:e.id,onFileDownloaded:(e,t)=>{let n=p(i,e.fileName),r=f(n);l(r)||u(r,{recursive:!0}),d(n,t)}}),A&&e.status===a.Approving&&(await v(j,n,{variables:{input:{requestId:e.id}},logger:t}),R+=1),L+=1,I.update(L)},{concurrency:O}),I.stop();let z=new Date().getTime()-F;return t.info(m.green(`Successfully downloaded ${L} requests in "${z/1e3}" seconds!`)),R>0&&t.info(m.green(`Approved ${R} requests in Transcend.`)),N.length}export{C as a,S as i,T as n,w as o,x as r,E as t};
2
+ //# sourceMappingURL=downloadPrivacyRequestFiles-GUbd_PRc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloadPrivacyRequestFiles-GUbd_PRc.mjs","names":[],"sources":["../src/lib/requests/getFileMetadataForPrivacyRequests.ts","../src/lib/requests/streamPrivacyRequestFiles.ts","../src/lib/requests/downloadPrivacyRequestFiles.ts"],"sourcesContent":["import { TableEncryptionType } from '@transcend-io/privacy-types';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport { map } from '@transcend-io/utils';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\nimport type { Got } from 'got';\nimport * as t from 'io-ts';\n\nimport { logger } from '../../logger.js';\nimport { PrivacyRequest } from '../graphql/index.js';\n\nexport const IntlMessage = t.type({\n /** The message key */\n defaultMessage: t.string,\n /** ID */\n id: t.string,\n});\n\n/** Type */\nexport type IntlMessage = t.TypeOf<typeof IntlMessage>;\n\nexport const RequestFileMetadata = t.type({\n /** The key to pass to download the file contents */\n downloadKey: t.string,\n /** Error message related to file */\n error: t.union([t.null, t.string]),\n /** Mimetype of file */\n mimetype: t.string,\n /** Size of file, stored as string as this can be a BigInt */\n size: t.string,\n /** Name of file based on datapoint names in Transcend */\n fileName: t.string,\n /** The metadata on the datapoint */\n dataPoint: t.type({\n /** ID of datapoint */\n id: t.string,\n /** The title of datapoint */\n title: t.union([IntlMessage, t.null]),\n /** Description of datapoint */\n description: t.union([IntlMessage, t.null]),\n /** Name of datapoint */\n name: t.string,\n /** Slug of datapoint */\n slug: t.string,\n /** Table level encryption information */\n encryption: t.union([valuesOf(TableEncryptionType), t.null]),\n /** The name of the data silo */\n dataSilo: t.type({\n /** ID of the data silo */\n id: t.string,\n /** The title of the data silo */\n title: t.string,\n /** The description of the data silo */\n description: t.string,\n /** The type of the data silo */\n type: t.string,\n /** The outer type of the data silo */\n outerType: t.union([t.string, t.null]),\n }),\n /** The path to the datapoint if a database (e.g. name of schema) */\n path: t.array(t.string),\n }),\n});\n\n/** Type override */\nexport type RequestFileMetadata = t.TypeOf<typeof RequestFileMetadata>;\n\nexport const RequestFileMetadataResponse = t.type({\n /** The list of file metadata */\n nodes: t.array(RequestFileMetadata),\n /** The total number of file metadata */\n totalCount: t.number,\n /** Links to next pages */\n _links: t.partial({\n /** The link to the next page of file metadata */\n next: t.union([t.string, t.null]),\n /** The link to the previous page of file metadata */\n previous: t.union([t.string, t.null]),\n }),\n});\n\n/** Type override */\nexport type RequestFileMetadataResponse = t.TypeOf<typeof RequestFileMetadataResponse>;\n\n/**\n * Given a list of privacy requests, download the file metadata\n * for these requests - this is useful to prepare the files in a\n * data access request for download.\n *\n * @param requests - The list of privacy requests to download files for\n * @param options - Options\n * @returns The number of requests canceled\n */\nexport async function getFileMetadataForPrivacyRequests(\n requests: Pick<PrivacyRequest, 'id' | 'status'>[],\n {\n sombra,\n concurrency = 5,\n limit = 100,\n }: {\n /** Sombra instance */\n sombra: Got;\n /** Number of files to pull at once */\n limit?: number;\n /** Concurrency limit for approving */\n concurrency?: number;\n },\n): Promise<[Pick<PrivacyRequest, 'id' | 'status'>, RequestFileMetadata[]][]> {\n logger.info(colors.magenta(`Pulling file metadata for ${requests.length} requests`));\n\n // Time duration\n const t0 = new Date().getTime();\n // create a new progress bar instance and use shades_classic theme\n const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);\n\n // Start timer\n let total = 0;\n progressBar.start(requests.length, 0);\n\n // Loop over the requests\n const results = await map(\n requests,\n async (\n requestToDownload,\n ): Promise<[Pick<PrivacyRequest, 'id' | 'status'>, RequestFileMetadata[]]> => {\n const localResults: RequestFileMetadata[] = [];\n\n // Paginate over the file metadata for this request\n let shouldContinue = true;\n let offset = 0;\n while (shouldContinue) {\n let response: RequestFileMetadataResponse;\n try {\n // Grab the file metadata for this request\n\n const rawResponse = await sombra\n .get(`v1/data-subject-request/${requestToDownload.id}/download-keys`, {\n searchParams: {\n limit,\n offset,\n },\n })\n .json();\n response = decodeCodec(RequestFileMetadataResponse, rawResponse);\n localResults.push(...response.nodes);\n\n // Increase offset and break if no more pages\n offset += limit;\n shouldContinue =\n // eslint-disable-next-line no-underscore-dangle\n !!response._links.next && response.nodes.length === limit;\n } catch (err) {\n throw new Error(`Received an error from server: ${err?.response?.body || err?.message}`);\n }\n }\n\n total += 1;\n progressBar.update(total);\n return [requestToDownload, localResults];\n },\n { concurrency },\n );\n\n progressBar.stop();\n const t1 = new Date().getTime();\n const totalTime = t1 - t0;\n\n logger.info(\n colors.green(\n `Successfully downloaded file metadata ${requests.length} requests in \"${\n totalTime / 1000\n }\" seconds!`,\n ),\n );\n\n return results;\n}\n","import { map } from '@transcend-io/utils';\nimport colors from 'colors';\nimport type { Got } from 'got';\n\nimport { logger } from '../../logger.js';\nimport { RequestFileMetadata } from './getFileMetadataForPrivacyRequests.js';\n\n/**\n * This function will take in a set of file metadata for privacy requests\n * call the Transcend API to stream the file metadata for these requests\n * and pass that through a callback function\n *\n * @param fileMetadata - Metadata to download\n * @param options - Options for the request\n */\nexport async function streamPrivacyRequestFiles(\n fileMetadata: RequestFileMetadata[],\n {\n requestId,\n sombra,\n onFileDownloaded,\n concurrency = 20,\n }: {\n /** Request ID for logging */\n requestId: string;\n /** Sombra got instance */\n sombra: Got;\n /** Handler on each file */\n onFileDownloaded: (metadata: RequestFileMetadata, stream: Buffer) => void;\n /** Concurrent downloads at once */\n concurrency?: number;\n },\n): Promise<void> {\n // Loop over each file\n await map(\n fileMetadata,\n async (metadata) => {\n try {\n // Construct the stream\n await sombra\n .get('v1/files', {\n searchParams: {\n downloadKey: metadata.downloadKey,\n },\n })\n .buffer()\n .then((fileResponse) => onFileDownloaded(metadata, fileResponse));\n } catch (err) {\n if (err?.response?.body?.includes('fileMetadata#verify')) {\n logger.error(\n colors.red(\n `Failed to pull file for: ${metadata.fileName} (request:${requestId}) - JWT expired. ` +\n 'This likely means that the file is no longer available. ' +\n 'Try restarting the request from scratch in Transcend Admin Dashboard. ' +\n 'Skipping the download of this file.',\n ),\n );\n return;\n }\n throw new Error(`Received an error from server: ${err?.response?.body || err?.message}`);\n }\n },\n {\n concurrency,\n },\n );\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport {\n buildTranscendGraphQLClient,\n createSombraGotInstance,\n makeGraphQLRequest,\n} from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\n\nimport { DEFAULT_TRANSCEND_API } from '../../constants.js';\nimport { logger } from '../../logger.js';\nimport { fetchAllRequests, APPROVE_PRIVACY_REQUEST } from '../graphql/index.js';\nimport { getFileMetadataForPrivacyRequests } from './getFileMetadataForPrivacyRequests.js';\nimport { streamPrivacyRequestFiles } from './streamPrivacyRequestFiles.js';\n\n/**\n * Download a set of privacy requests to disk\n *\n * @param options - Options\n * @returns The number of requests canceled\n */\nexport async function downloadPrivacyRequestFiles({\n auth,\n folderPath,\n requestIds,\n createdAtBefore,\n sombraAuth,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n statuses = [RequestStatus.Approving, RequestStatus.Downloadable],\n concurrency = 5,\n transcendUrl = DEFAULT_TRANSCEND_API,\n approveAfterDownload = false,\n}: {\n /** The folder path to download the files to */\n folderPath: string;\n /** Transcend API key authentication */\n auth: string;\n /** Sombra API key authentication */\n sombraAuth?: string;\n /** Concurrency limit for approving */\n concurrency?: number;\n /** The request statuses to cancel */\n statuses?: RequestStatus[];\n /** The set of privacy requests to cancel */\n requestIds?: string[];\n /** Filter for requests created before this date */\n createdAtBefore?: Date;\n /** Filter for requests created after this date */\n createdAtAfter?: Date;\n /** Filter for requests updated before this date */\n updatedAtBefore?: Date;\n /** Filter for requests updated after this date */\n updatedAtAfter?: Date;\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** When true, approve any requests in Transcend that are in status=APPROVING */\n approveAfterDownload?: boolean;\n}): Promise<number> {\n // Find all requests made before createdAt that are in a removing data state\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n // Create sombra instance to communicate with\n const sombra = await createSombraGotInstance(transcendUrl, auth, {\n logger,\n sombraApiKey: sombraAuth,\n sombraUrl: process.env.SOMBRA_URL,\n });\n\n // Create the folder if it does not exist\n if (!existsSync(folderPath)) {\n mkdirSync(folderPath);\n }\n\n // Pull in the requests\n const allRequests = await fetchAllRequests(client, {\n actions: [RequestAction.Access],\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n statuses,\n requestIds,\n });\n\n // Download the file metadata for each request\n const requestFileMetadata = await getFileMetadataForPrivacyRequests(allRequests, {\n sombra,\n concurrency,\n });\n\n // Start timer for download process\n const t0 = new Date().getTime();\n const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);\n let total = 0;\n let totalApproved = 0;\n progressBar.start(allRequests.length, 0);\n\n // Download the files for each request\n await map(\n requestFileMetadata,\n async ([request, metadata]) => {\n // Create a new folder to store request files\n const requestFolder = join(folderPath, request.id);\n if (!existsSync(requestFolder)) {\n mkdirSync(requestFolder);\n }\n\n // Stream each file to disk\n await streamPrivacyRequestFiles(metadata, {\n sombra,\n requestId: request.id,\n onFileDownloaded: (fil, stream) => {\n // Ensure a folder exists for the file\n // filename looks like Health/heartbeat.csv\n const filePath = join(requestFolder, fil.fileName);\n const folder = dirname(filePath);\n if (!existsSync(folder)) {\n mkdirSync(folder, { recursive: true });\n }\n\n // Write to disk\n writeFileSync(filePath, stream);\n },\n });\n\n // Approve the request if requested\n if (approveAfterDownload && request.status === RequestStatus.Approving) {\n await makeGraphQLRequest(client, APPROVE_PRIVACY_REQUEST, {\n variables: { input: { requestId: request.id } },\n logger,\n });\n totalApproved += 1;\n }\n\n // Increment the progress bar\n total += 1;\n progressBar.update(total);\n },\n { concurrency },\n );\n\n progressBar.stop();\n const t1 = new Date().getTime();\n const totalTime = t1 - t0;\n\n logger.info(\n colors.green(`Successfully downloaded ${total} requests in \"${totalTime / 1000}\" seconds!`),\n );\n if (totalApproved > 0) {\n logger.info(colors.green(`Approved ${totalApproved} requests in Transcend.`));\n }\n return allRequests.length;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
1
  import{IsoCountryCode as e,IsoCountrySubdivisionCode as t,RequestAction as n,RequestStatus as r}from"@transcend-io/privacy-types";import{uniq as i}from"lodash-es";import{decodeCodec as a,valuesOf as o}from"@transcend-io/type-utils";import*as s from"io-ts";const c=s.type({id:s.string,link:s.string,status:o(r),type:o(n),subjectType:s.string,email:s.union([s.null,s.string]),coreIdentifier:s.string,isSilent:s.boolean,isTest:s.boolean,country:s.union([s.null,o(e)]),countrySubDivision:s.union([s.null,o(t)]),attributeValues:s.array(s.type({attributeKey:s.type({name:s.string}),name:s.string}))});async function l(e,t,{details:n=``,isTest:r=!1,emailIsVerified:o=!0,skipSendingReceipt:l=!1,isSilent:u=!0,additionalAttributes:d=[]}={}){let f=[...d];(t.attributes||[]).forEach(e=>{let t=f.find(t=>t.key===e.key);t?(t.values.push(...e.values),t.values=i(t.values)):f.push(e)});let p;try{p=await e.post(`v1/data-subject-request`,{json:{type:t.requestType,subject:{coreIdentifier:t.coreIdentifier,email:t.email,emailIsVerified:o,attestedExtraIdentifiers:t.attestedExtraIdentifiers},subjectType:t.subjectType,isSilent:u,isTest:r,skipSendingReceipt:l,...t.locale?{locale:t.locale}:{},details:n,attributes:f,...t.country||t.countrySubDivision?{region:{...t.country?{country:t.country}:t.countrySubDivision?{country:t.countrySubDivision.split(`-`)[0]}:{},...t.countrySubDivision?{countrySubDivision:t.countrySubDivision}:{}}}:{},...t.createdAt?{createdAt:t.createdAt}:{},...t.dataSiloIds?{dataSiloIds:t.dataSiloIds}:{},...t.status?{completedRequestStatus:t.status}:{}}}).json()}catch(e){throw Error(`Received an error from server: ${e?.response?.body||e?.message}`)}let{request:m}=a(s.type({request:c}),p);return m}const u=/{\\"message\\":\\"(.+?)\\",/;function d(e){return u.test(e)?u.exec(e)[1]:null}export{c as n,l as r,d as t};
2
- //# sourceMappingURL=extractClientError-DPjv09EH.mjs.map
2
+ //# sourceMappingURL=extractClientError-X9wJVqGq.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extractClientError-DPjv09EH.mjs","names":[],"sources":["../src/lib/requests/submitPrivacyRequest.ts","../src/lib/requests/extractClientError.ts"],"sourcesContent":["import {\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n RequestAction,\n RequestStatus,\n} from '@transcend-io/privacy-types';\nimport { valuesOf, decodeCodec } from '@transcend-io/type-utils';\nimport type { Got } from 'got';\nimport * as t from 'io-ts';\nimport { uniq } from 'lodash-es';\n\nimport { PrivacyRequestInput } from './mapCsvRowsToRequestInputs.js';\nimport { ParsedAttributeInput } from './parseAttributesFromString.js';\n\nexport const PrivacyRequestResponse = t.type({\n id: t.string,\n link: t.string,\n status: valuesOf(RequestStatus),\n type: valuesOf(RequestAction),\n subjectType: t.string,\n email: t.union([t.null, t.string]),\n coreIdentifier: t.string,\n isSilent: t.boolean,\n isTest: t.boolean,\n country: t.union([t.null, valuesOf(IsoCountryCode)]),\n countrySubDivision: t.union([t.null, valuesOf(IsoCountrySubdivisionCode)]),\n attributeValues: t.array(\n t.type({\n attributeKey: t.type({ name: t.string }),\n name: t.string,\n }),\n ),\n});\n\n/** Type override */\nexport type PrivacyRequestResponse = t.TypeOf<typeof PrivacyRequestResponse>;\n\n/**\n * Submit a privacy request to the Transcend API\n *\n * @param sombra - Sombra instance configured to make requests\n * @param input - Request input\n * @param options - Additional options\n * @returns Successfully submitted request\n */\nexport async function submitPrivacyRequest(\n sombra: Got,\n input: PrivacyRequestInput,\n {\n details = '',\n isTest = false,\n emailIsVerified = true,\n skipSendingReceipt = false,\n isSilent = true,\n additionalAttributes = [],\n }: {\n /** Whether or not the request is a test request */\n isTest?: boolean;\n /** Whether or not the request is in silent mode */\n isSilent?: boolean;\n /** Whether the email is verified up front */\n emailIsVerified?: boolean;\n /** When true, skip sending of the email receipt */\n skipSendingReceipt?: boolean;\n /** Request details */\n details?: string;\n /** Additional attributes to tag the requests with */\n additionalAttributes?: ParsedAttributeInput[];\n } = {},\n): Promise<PrivacyRequestResponse> {\n // Merge the per-request attributes with the\n // global attributes\n const mergedAttributes = [...additionalAttributes];\n (input.attributes || []).forEach((attribute) => {\n const existing = mergedAttributes.find((attr) => attr.key === attribute.key);\n if (existing) {\n existing.values.push(...attribute.values);\n existing.values = uniq(existing.values);\n } else {\n mergedAttributes.push(attribute);\n }\n });\n\n // Make the GraphQL request\n let response: unknown;\n try {\n response = await sombra\n .post('v1/data-subject-request', {\n json: {\n type: input.requestType,\n subject: {\n coreIdentifier: input.coreIdentifier,\n email: input.email,\n emailIsVerified,\n attestedExtraIdentifiers: input.attestedExtraIdentifiers,\n },\n subjectType: input.subjectType,\n isSilent,\n isTest,\n skipSendingReceipt,\n ...(input.locale ? { locale: input.locale } : {}),\n details,\n attributes: mergedAttributes,\n ...(input.country || input.countrySubDivision\n ? {\n region: {\n ...(input.country\n ? {\n country: input.country,\n }\n : input.countrySubDivision\n ? { country: input.countrySubDivision.split('-')[0] }\n : {}),\n ...(input.countrySubDivision\n ? { countrySubDivision: input.countrySubDivision }\n : {}),\n },\n }\n : {}),\n ...(input.createdAt ? { createdAt: input.createdAt } : {}),\n ...(input.dataSiloIds ? { dataSiloIds: input.dataSiloIds } : {}),\n ...(input.status ? { completedRequestStatus: input.status } : {}),\n },\n })\n .json();\n } catch (err) {\n throw new Error(`Received an error from server: ${err?.response?.body || err?.message}`);\n }\n\n const { request: requestResponse } = decodeCodec(\n t.type({\n request: PrivacyRequestResponse,\n }),\n response,\n );\n return requestResponse;\n}\n","const CLIENT_ERROR = /{\\\\\"message\\\\\":\\\\\"(.+?)\\\\\",/;\n\n/**\n * Extract a client error from the request\n *\n * @param err - Error message\n * @returns Client error or null\n */\nexport function extractClientError(err: string): string | null {\n return CLIENT_ERROR.test(err) ? CLIENT_ERROR.exec(err)![1] : null;\n}\n"],"mappings":"gQAcA,MAAa,EAAyB,EAAE,KAAK,CAC3C,GAAI,EAAE,OACN,KAAM,EAAE,OACR,OAAQ,EAAS,EAAc,CAC/B,KAAM,EAAS,EAAc,CAC7B,YAAa,EAAE,OACf,MAAO,EAAE,MAAM,CAAC,EAAE,KAAM,EAAE,OAAO,CAAC,CAClC,eAAgB,EAAE,OAClB,SAAU,EAAE,QACZ,OAAQ,EAAE,QACV,QAAS,EAAE,MAAM,CAAC,EAAE,KAAM,EAAS,EAAe,CAAC,CAAC,CACpD,mBAAoB,EAAE,MAAM,CAAC,EAAE,KAAM,EAAS,EAA0B,CAAC,CAAC,CAC1E,gBAAiB,EAAE,MACjB,EAAE,KAAK,CACL,aAAc,EAAE,KAAK,CAAE,KAAM,EAAE,OAAQ,CAAC,CACxC,KAAM,EAAE,OACT,CAAC,CACH,CACF,CAAC,CAaF,eAAsB,EACpB,EACA,EACA,CACE,UAAU,GACV,SAAS,GACT,kBAAkB,GAClB,qBAAqB,GACrB,WAAW,GACX,uBAAuB,EAAE,EAcvB,EAAE,CAC2B,CAGjC,IAAM,EAAmB,CAAC,GAAG,EAAqB,EACjD,EAAM,YAAc,EAAE,EAAE,QAAS,GAAc,CAC9C,IAAM,EAAW,EAAiB,KAAM,GAAS,EAAK,MAAQ,EAAU,IAAI,CACxE,GACF,EAAS,OAAO,KAAK,GAAG,EAAU,OAAO,CACzC,EAAS,OAAS,EAAK,EAAS,OAAO,EAEvC,EAAiB,KAAK,EAAU,EAElC,CAGF,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,EACd,KAAK,0BAA2B,CAC/B,KAAM,CACJ,KAAM,EAAM,YACZ,QAAS,CACP,eAAgB,EAAM,eACtB,MAAO,EAAM,MACb,kBACA,yBAA0B,EAAM,yBACjC,CACD,YAAa,EAAM,YACnB,WACA,SACA,qBACA,GAAI,EAAM,OAAS,CAAE,OAAQ,EAAM,OAAQ,CAAG,EAAE,CAChD,UACA,WAAY,EACZ,GAAI,EAAM,SAAW,EAAM,mBACvB,CACE,OAAQ,CACN,GAAI,EAAM,QACN,CACE,QAAS,EAAM,QAChB,CACD,EAAM,mBACJ,CAAE,QAAS,EAAM,mBAAmB,MAAM,IAAI,CAAC,GAAI,CACnD,EAAE,CACR,GAAI,EAAM,mBACN,CAAE,mBAAoB,EAAM,mBAAoB,CAChD,EAAE,CACP,CACF,CACD,EAAE,CACN,GAAI,EAAM,UAAY,CAAE,UAAW,EAAM,UAAW,CAAG,EAAE,CACzD,GAAI,EAAM,YAAc,CAAE,YAAa,EAAM,YAAa,CAAG,EAAE,CAC/D,GAAI,EAAM,OAAS,CAAE,uBAAwB,EAAM,OAAQ,CAAG,EAAE,CACjE,CACF,CAAC,CACD,MAAM,OACF,EAAK,CACZ,MAAU,MAAM,kCAAkC,GAAK,UAAU,MAAQ,GAAK,UAAU,CAG1F,GAAM,CAAE,QAAS,GAAoB,EACnC,EAAE,KAAK,CACL,QAAS,EACV,CAAC,CACF,EACD,CACD,OAAO,ECvIT,MAAM,EAAe,8BAQrB,SAAgB,EAAmB,EAA4B,CAC7D,OAAO,EAAa,KAAK,EAAI,CAAG,EAAa,KAAK,EAAI,CAAE,GAAK"}
1
+ {"version":3,"file":"extractClientError-X9wJVqGq.mjs","names":[],"sources":["../src/lib/requests/submitPrivacyRequest.ts","../src/lib/requests/extractClientError.ts"],"sourcesContent":["import {\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n RequestAction,\n RequestStatus,\n} from '@transcend-io/privacy-types';\nimport { valuesOf, decodeCodec } from '@transcend-io/type-utils';\nimport type { Got } from 'got';\nimport * as t from 'io-ts';\nimport { uniq } from 'lodash-es';\n\nimport { PrivacyRequestInput } from './mapCsvRowsToRequestInputs.js';\nimport { ParsedAttributeInput } from './parseAttributesFromString.js';\n\nexport const PrivacyRequestResponse = t.type({\n id: t.string,\n link: t.string,\n status: valuesOf(RequestStatus),\n type: valuesOf(RequestAction),\n subjectType: t.string,\n email: t.union([t.null, t.string]),\n coreIdentifier: t.string,\n isSilent: t.boolean,\n isTest: t.boolean,\n country: t.union([t.null, valuesOf(IsoCountryCode)]),\n countrySubDivision: t.union([t.null, valuesOf(IsoCountrySubdivisionCode)]),\n attributeValues: t.array(\n t.type({\n attributeKey: t.type({ name: t.string }),\n name: t.string,\n }),\n ),\n});\n\n/** Type override */\nexport type PrivacyRequestResponse = t.TypeOf<typeof PrivacyRequestResponse>;\n\n/**\n * Submit a privacy request to the Transcend API\n *\n * @param sombra - Sombra instance configured to make requests\n * @param input - Request input\n * @param options - Additional options\n * @returns Successfully submitted request\n */\nexport async function submitPrivacyRequest(\n sombra: Got,\n input: PrivacyRequestInput,\n {\n details = '',\n isTest = false,\n emailIsVerified = true,\n skipSendingReceipt = false,\n isSilent = true,\n additionalAttributes = [],\n }: {\n /** Whether or not the request is a test request */\n isTest?: boolean;\n /** Whether or not the request is in silent mode */\n isSilent?: boolean;\n /** Whether the email is verified up front */\n emailIsVerified?: boolean;\n /** When true, skip sending of the email receipt */\n skipSendingReceipt?: boolean;\n /** Request details */\n details?: string;\n /** Additional attributes to tag the requests with */\n additionalAttributes?: ParsedAttributeInput[];\n } = {},\n): Promise<PrivacyRequestResponse> {\n // Merge the per-request attributes with the\n // global attributes\n const mergedAttributes = [...additionalAttributes];\n (input.attributes || []).forEach((attribute) => {\n const existing = mergedAttributes.find((attr) => attr.key === attribute.key);\n if (existing) {\n existing.values.push(...attribute.values);\n existing.values = uniq(existing.values);\n } else {\n mergedAttributes.push(attribute);\n }\n });\n\n // Make the GraphQL request\n let response: unknown;\n try {\n response = await sombra\n .post('v1/data-subject-request', {\n json: {\n type: input.requestType,\n subject: {\n coreIdentifier: input.coreIdentifier,\n email: input.email,\n emailIsVerified,\n attestedExtraIdentifiers: input.attestedExtraIdentifiers,\n },\n subjectType: input.subjectType,\n isSilent,\n isTest,\n skipSendingReceipt,\n ...(input.locale ? { locale: input.locale } : {}),\n details,\n attributes: mergedAttributes,\n ...(input.country || input.countrySubDivision\n ? {\n region: {\n ...(input.country\n ? {\n country: input.country,\n }\n : input.countrySubDivision\n ? { country: input.countrySubDivision.split('-')[0] }\n : {}),\n ...(input.countrySubDivision\n ? { countrySubDivision: input.countrySubDivision }\n : {}),\n },\n }\n : {}),\n ...(input.createdAt ? { createdAt: input.createdAt } : {}),\n ...(input.dataSiloIds ? { dataSiloIds: input.dataSiloIds } : {}),\n ...(input.status ? { completedRequestStatus: input.status } : {}),\n },\n })\n .json();\n } catch (err) {\n throw new Error(`Received an error from server: ${err?.response?.body || err?.message}`);\n }\n\n const { request: requestResponse } = decodeCodec(\n t.type({\n request: PrivacyRequestResponse,\n }),\n response,\n );\n return requestResponse;\n}\n","const CLIENT_ERROR = /{\\\\\"message\\\\\":\\\\\"(.+?)\\\\\",/;\n\n/**\n * Extract a client error from the request\n *\n * @param err - Error message\n * @returns Client error or null\n */\nexport function extractClientError(err: string): string | null {\n return CLIENT_ERROR.test(err) ? CLIENT_ERROR.exec(err)![1] : null;\n}\n"],"mappings":"gQAcA,MAAa,EAAyB,EAAE,KAAK,CAC3C,GAAI,EAAE,OACN,KAAM,EAAE,OACR,OAAQ,EAAS,EAAc,CAC/B,KAAM,EAAS,EAAc,CAC7B,YAAa,EAAE,OACf,MAAO,EAAE,MAAM,CAAC,EAAE,KAAM,EAAE,OAAO,CAAC,CAClC,eAAgB,EAAE,OAClB,SAAU,EAAE,QACZ,OAAQ,EAAE,QACV,QAAS,EAAE,MAAM,CAAC,EAAE,KAAM,EAAS,EAAe,CAAC,CAAC,CACpD,mBAAoB,EAAE,MAAM,CAAC,EAAE,KAAM,EAAS,EAA0B,CAAC,CAAC,CAC1E,gBAAiB,EAAE,MACjB,EAAE,KAAK,CACL,aAAc,EAAE,KAAK,CAAE,KAAM,EAAE,OAAQ,CAAC,CACxC,KAAM,EAAE,OACT,CAAC,CACH,CACF,CAAC,CAaF,eAAsB,EACpB,EACA,EACA,CACE,UAAU,GACV,SAAS,GACT,kBAAkB,GAClB,qBAAqB,GACrB,WAAW,GACX,uBAAuB,EAAE,EAcvB,EAAE,CAC2B,CAGjC,IAAM,EAAmB,CAAC,GAAG,EAAqB,EACjD,EAAM,YAAc,EAAE,EAAE,QAAS,GAAc,CAC9C,IAAM,EAAW,EAAiB,KAAM,GAAS,EAAK,MAAQ,EAAU,IAAI,CACxE,GACF,EAAS,OAAO,KAAK,GAAG,EAAU,OAAO,CACzC,EAAS,OAAS,EAAK,EAAS,OAAO,EAEvC,EAAiB,KAAK,EAAU,EAElC,CAGF,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,EACd,KAAK,0BAA2B,CAC/B,KAAM,CACJ,KAAM,EAAM,YACZ,QAAS,CACP,eAAgB,EAAM,eACtB,MAAO,EAAM,MACb,kBACA,yBAA0B,EAAM,yBACjC,CACD,YAAa,EAAM,YACnB,WACA,SACA,qBACA,GAAI,EAAM,OAAS,CAAE,OAAQ,EAAM,OAAQ,CAAG,EAAE,CAChD,UACA,WAAY,EACZ,GAAI,EAAM,SAAW,EAAM,mBACvB,CACE,OAAQ,CACN,GAAI,EAAM,QACN,CACE,QAAS,EAAM,QAChB,CACD,EAAM,mBACJ,CAAE,QAAS,EAAM,mBAAmB,MAAM,IAAI,CAAC,GAAI,CACnD,EAAE,CACR,GAAI,EAAM,mBACN,CAAE,mBAAoB,EAAM,mBAAoB,CAChD,EAAE,CACP,CACF,CACD,EAAE,CACN,GAAI,EAAM,UAAY,CAAE,UAAW,EAAM,UAAW,CAAG,EAAE,CACzD,GAAI,EAAM,YAAc,CAAE,YAAa,EAAM,YAAa,CAAG,EAAE,CAC/D,GAAI,EAAM,OAAS,CAAE,uBAAwB,EAAM,OAAQ,CAAG,EAAE,CACjE,CACF,CAAC,CACD,MAAM,OACF,EAAK,CACZ,MAAU,MAAM,kCAAkC,GAAK,UAAU,MAAQ,GAAK,UAAU,CAG1F,GAAM,CAAE,QAAS,GAAoB,EACnC,EAAE,KAAK,CACL,QAAS,EACV,CAAC,CACF,EACD,CACD,OAAO,ECvIT,MAAM,EAAe,8BAQrB,SAAgB,EAAmB,EAA4B,CAC7D,OAAO,EAAa,KAAK,EAAI,CAAG,EAAa,KAAK,EAAI,CAAE,GAAK"}
@@ -1,4 +1,4 @@
1
- import{t as e}from"./makeGraphQLRequest-Cq26A_Lq.mjs";import{gql as t}from"graphql-request";const n=t`
1
+ import{t as e}from"./logger-Bj782ZYD.mjs";import{makeGraphQLRequest as t}from"@transcend-io/sdk";import{gql as n}from"graphql-request";const r=n`
2
2
  query TranscendCliRequestEnrichers($first: Int!, $offset: Int!, $requestId: ID!) {
3
3
  requestEnrichers(
4
4
  input: { requestId: $requestId }
@@ -22,7 +22,7 @@ import{t as e}from"./makeGraphQLRequest-Cq26A_Lq.mjs";import{gql as t}from"graph
22
22
  totalCount
23
23
  }
24
24
  }
25
- `,r=t`
25
+ `,i=n`
26
26
  mutation TranscendCliRetryRequestEnricher($requestEnricherId: ID!) {
27
27
  retryRequestEnricher(id: $requestEnricherId) {
28
28
  requestEnricher {
@@ -30,7 +30,7 @@ import{t as e}from"./makeGraphQLRequest-Cq26A_Lq.mjs";import{gql as t}from"graph
30
30
  }
31
31
  }
32
32
  }
33
- `,i=t`
33
+ `,a=n`
34
34
  mutation TranscendCliSkipRequestEnricher($requestEnricherId: ID!) {
35
35
  skipRequestEnricher(id: $requestEnricherId) {
36
36
  requestEnricher {
@@ -38,5 +38,5 @@ import{t as e}from"./makeGraphQLRequest-Cq26A_Lq.mjs";import{gql as t}from"graph
38
38
  }
39
39
  }
40
40
  }
41
- `;async function a(t,{requestId:r}){let i=[],a=0,o=!1;do{let{requestEnrichers:{nodes:s}}=await e(t,n,{first:50,offset:a,requestId:r});i.push(...s),a+=50,o=s.length===50}while(o);return i}export{i,n,r,a as t};
42
- //# sourceMappingURL=fetchAllRequestEnrichers-CK-kk5eg.mjs.map
41
+ `;async function o(n,{requestId:i}){let a=[],o=0,s=!1;do{let{requestEnrichers:{nodes:c}}=await t(n,r,{variables:{first:50,offset:o,requestId:i},logger:e});a.push(...c),o+=50,s=c.length===50}while(s);return a}export{a as i,r as n,i as r,o as t};
42
+ //# sourceMappingURL=fetchAllRequestEnrichers-Bt97Bb7F.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchAllRequestEnrichers-Bt97Bb7F.mjs","names":[],"sources":["../src/lib/graphql/gqls/RequestEnricher.ts","../src/lib/graphql/fetchAllRequestEnrichers.ts"],"sourcesContent":["import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const REQUEST_ENRICHERS = gql`\n query TranscendCliRequestEnrichers($first: Int!, $offset: Int!, $requestId: ID!) {\n requestEnrichers(\n input: { requestId: $requestId }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [\n { field: createdAt, direction: ASC }\n { field: title, direction: ASC, model: enricher }\n ]\n ) {\n nodes {\n id\n status\n enricher {\n id\n type\n title\n }\n }\n totalCount\n }\n }\n`;\n\nexport const RETRY_REQUEST_ENRICHER = gql`\n mutation TranscendCliRetryRequestEnricher($requestEnricherId: ID!) {\n retryRequestEnricher(id: $requestEnricherId) {\n requestEnricher {\n id\n }\n }\n }\n`;\n\nexport const SKIP_REQUEST_ENRICHER = gql`\n mutation TranscendCliSkipRequestEnricher($requestEnricherId: ID!) {\n skipRequestEnricher(id: $requestEnricherId) {\n requestEnricher {\n id\n }\n }\n }\n`;\n","import { RequestEnricherStatus } from '@transcend-io/privacy-types';\nimport { makeGraphQLRequest } from '@transcend-io/sdk';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { logger } from '../../logger.js';\nimport { REQUEST_ENRICHERS } from './gqls/index.js';\n\nexport interface RequestEnricher {\n /** ID of request enricher */\n id: string;\n /** Name of identifier */\n enricher: {\n /** ID of enricher */\n id: string;\n /** Title of enricher */\n title: string;\n /** Typeof of enricher */\n type: string;\n };\n /** The status of the enricher */\n status: RequestEnricherStatus;\n}\n\nconst PAGE_SIZE = 50;\n\n/**\n * Fetch all request enrichers for a particular request\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns List of request enrichers\n */\nexport async function fetchAllRequestEnrichers(\n client: GraphQLClient,\n {\n requestId,\n }: {\n /** ID of request to filter on */\n requestId: string;\n },\n): Promise<RequestEnricher[]> {\n const requestEnrichers: RequestEnricher[] = [];\n let offset = 0;\n\n // Paginate\n let shouldContinue = false;\n do {\n const {\n requestEnrichers: { nodes },\n } = await makeGraphQLRequest<{\n /** Request Enrichers */\n requestEnrichers: {\n /** List */\n nodes: RequestEnricher[];\n };\n }>(client, REQUEST_ENRICHERS, {\n variables: { first: PAGE_SIZE, offset, requestId },\n logger,\n });\n requestEnrichers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return requestEnrichers;\n}\n"],"mappings":"uIAIA,MAAa,EAAoB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;EA0BvB,EAAyB,CAAG;;;;;;;;EAU5B,EAAwB,CAAG;;;;;;;;ECRxC,eAAsB,EACpB,EACA,CACE,aAK0B,CAC5B,IAAM,EAAsC,EAAE,CAC1C,EAAS,EAGT,EAAiB,GACrB,EAAG,CACD,GAAM,CACJ,iBAAkB,CAAE,UAClB,MAAM,EAMP,EAAQ,EAAmB,CAC5B,UAAW,CAAE,MAAO,GAAW,SAAQ,YAAW,CAClD,SACD,CAAC,CACF,EAAiB,KAAK,GAAG,EAAM,CAC/B,GAAU,GACV,EAAiB,EAAM,SAAW,SAC3B,GAET,OAAO"}
@@ -0,0 +1,10 @@
1
+ import{t as e}from"./logger-Bj782ZYD.mjs";import{IdentifierType as t}from"@transcend-io/privacy-types";import{decodeCodec as n,valuesOf as r}from"@transcend-io/type-utils";import*as i from"io-ts";import{makeGraphQLRequest as a}from"@transcend-io/sdk";import{gql as o}from"graphql-request";import s from"semver";const c=o`
2
+ query TranscendSombraVersion {
3
+ organization {
4
+ sombra {
5
+ version
6
+ }
7
+ }
8
+ }
9
+ `,l=`7.180.0`,u=i.type({id:i.string,name:i.string,value:i.string,type:r(t)}),d=i.type({identifiers:i.array(u)});async function f(t){let{organization:{sombra:{version:n}}}=await a(t,c,{logger:e});if(n&&s.lt(n,l))throw Error(`Please upgrade Sombra to ${l} or greater to use this command.`)}async function p(e,t,{requestId:r,skipSombraCheck:i=!1}){let a=[],o=0,s=!1;i||await f(e);do{let e;try{e=await t.post(`v1/request-identifiers`,{json:{first:50,offset:o,requestId:r}}).json()}catch(e){throw Error(`Failed to fetch request identifiers: ${e?.response?.body||e?.message}`)}let{identifiers:i}=n(d,e);a.push(...i),o+=50,s=i.length===50}while(s);return a}export{c as i,p as n,f as r,d as t};
10
+ //# sourceMappingURL=fetchAllRequestIdentifiers-BXx3rSee.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchAllRequestIdentifiers-BXx3rSee.mjs","names":[],"sources":["../src/lib/graphql/gqls/sombraVersion.ts","../src/lib/graphql/fetchAllRequestIdentifiers.ts"],"sourcesContent":["import { gql } from 'graphql-request';\n\nexport const SOMBRA_VERSION = gql`\n query TranscendSombraVersion {\n organization {\n sombra {\n version\n }\n }\n }\n`;\n","import { IdentifierType } from '@transcend-io/privacy-types';\nimport { makeGraphQLRequest } from '@transcend-io/sdk';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport type { Got } from 'got';\nimport { GraphQLClient } from 'graphql-request';\nimport * as t from 'io-ts';\nimport semver from 'semver';\n\nimport { logger } from '../../logger.js';\nimport { SOMBRA_VERSION } from './gqls/index.js';\n\nconst MIN_SOMBRA_VERSION_TO_DECRYPT = '7.180.0';\n\nconst RequestIdentifier = t.type({\n /** ID of request */\n id: t.string,\n /** Name of identifier */\n name: t.string,\n /** The underlying identifier value */\n value: t.string,\n /** Type of identifier */\n type: valuesOf(IdentifierType),\n});\n\n/** Type override */\nexport type RequestIdentifier = t.TypeOf<typeof RequestIdentifier>;\n\nconst PAGE_SIZE = 50;\n\nexport const RequestIdentifiersResponse = t.type({\n identifiers: t.array(RequestIdentifier),\n});\n\n/**\n * Validate that the Sombra version meets the minimum requirement for\n * decrypting request identifiers. Call once before bulk-fetching identifiers\n * to avoid repeating this check on every request.\n *\n * @param client - GraphQL client\n */\nexport async function validateSombraVersion(client: GraphQLClient): Promise<void> {\n const {\n organization: {\n sombra: { version },\n },\n } = await makeGraphQLRequest<{\n /** The organization */\n organization: {\n /** Sombra */\n sombra: {\n /** Version string */\n version: string;\n };\n };\n }>(client, SOMBRA_VERSION, { logger });\n\n if (version && semver.lt(version, MIN_SOMBRA_VERSION_TO_DECRYPT)) {\n throw new Error(\n `Please upgrade Sombra to ${MIN_SOMBRA_VERSION_TO_DECRYPT} or greater to use this command.`,\n );\n }\n}\n\n/**\n * Fetch all request identifiers for a particular request\n *\n * @param client - GraphQL client\n * @param sombra - Sombra client\n * @param options - Options\n * @returns List of request identifiers\n */\nexport async function fetchAllRequestIdentifiers(\n client: GraphQLClient,\n sombra: Got,\n {\n requestId,\n skipSombraCheck = false,\n }: {\n /** ID of request to filter on */\n requestId: string;\n /** Skip the Sombra version check (caller already validated) */\n skipSombraCheck?: boolean;\n },\n): Promise<RequestIdentifier[]> {\n const requestIdentifiers: RequestIdentifier[] = [];\n let offset = 0;\n let shouldContinue = false;\n\n if (!skipSombraCheck) {\n await validateSombraVersion(client);\n }\n\n do {\n let response: unknown;\n try {\n response = await sombra!\n .post<{\n /** Decrypted identifiers */\n identifiers: RequestIdentifier[];\n }>('v1/request-identifiers', {\n json: {\n first: PAGE_SIZE,\n offset,\n requestId,\n },\n })\n .json();\n } catch (err) {\n throw new Error(\n `Failed to fetch request identifiers: ${err?.response?.body || err?.message}`,\n );\n }\n\n const { identifiers: nodes } = decodeCodec(RequestIdentifiersResponse, response);\n\n requestIdentifiers.push(...nodes);\n\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return requestIdentifiers;\n}\n"],"mappings":"uTAEA,MAAa,EAAiB,CAAG;;;;;;;;ECS3B,EAAgC,UAEhC,EAAoB,EAAE,KAAK,CAE/B,GAAI,EAAE,OAEN,KAAM,EAAE,OAER,MAAO,EAAE,OAET,KAAM,EAAS,EAAe,CAC/B,CAAC,CAOW,EAA6B,EAAE,KAAK,CAC/C,YAAa,EAAE,MAAM,EAAkB,CACxC,CAAC,CASF,eAAsB,EAAsB,EAAsC,CAChF,GAAM,CACJ,aAAc,CACZ,OAAQ,CAAE,aAEV,MAAM,EASP,EAAQ,EAAgB,CAAE,SAAQ,CAAC,CAEtC,GAAI,GAAW,EAAO,GAAG,EAAS,EAA8B,CAC9D,MAAU,MACR,4BAA4B,EAA8B,kCAC3D,CAYL,eAAsB,EACpB,EACA,EACA,CACE,YACA,kBAAkB,IAOU,CAC9B,IAAM,EAA0C,EAAE,CAC9C,EAAS,EACT,EAAiB,GAEhB,GACH,MAAM,EAAsB,EAAO,CAGrC,EAAG,CACD,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,EACd,KAGE,yBAA0B,CAC3B,KAAM,CACJ,MAAO,GACP,SACA,YACD,CACF,CAAC,CACD,MAAM,OACF,EAAK,CACZ,MAAU,MACR,wCAAwC,GAAK,UAAU,MAAQ,GAAK,UACrE,CAGH,GAAM,CAAE,YAAa,GAAU,EAAY,EAA4B,EAAS,CAEhF,EAAmB,KAAK,GAAG,EAAM,CAEjC,GAAU,GACV,EAAiB,EAAM,SAAW,SAC3B,GAET,OAAO"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./logger-Bj782ZYD.mjs";import{a as t,i as n}from"./request-SLqRySNU.mjs";import{IsoCountryCode as r,IsoCountrySubdivisionCode as i,RequestAction as a,RequestOrigin as o,RequestStatus as s}from"@transcend-io/privacy-types";import{valuesOf as c}from"@transcend-io/type-utils";import l from"colors";import{LOCALE_KEY as u}from"@transcend-io/internationalization";import*as d from"io-ts";import{makeGraphQLRequest as f}from"@transcend-io/sdk";import p from"cli-progress";const m=d.type({title:d.string,name:d.string,consent:d.boolean,enrichedPreferences:d.array(d.type({topic:d.string,selectValues:d.array(d.type({id:d.string,name:d.string,preferenceOption:d.type({id:d.string,slug:d.string,title:d.type({defaultMessage:d.string})})})),selectValue:d.type({id:d.string,name:d.string}),preferenceTopic:d.type({title:d.type({defaultMessage:d.string}),id:d.string,slug:d.string}),name:d.string,id:d.string,booleanValue:d.boolean}))}),h=d.intersection([d.type({id:d.string,createdAt:d.string,email:d.string,type:c(a),link:d.string,isSilent:d.boolean,origin:c(o),isTest:d.boolean,coreIdentifier:d.string,details:d.string,locale:c(u),status:c(s),subjectType:d.string,country:d.union([d.null,c(r)]),countrySubDivision:d.union([d.null,c(i)]),attributeValues:d.array(d.type({id:d.string,attributeKey:d.type({name:d.string,id:d.string}),name:d.string}))}),d.partial({daysRemaining:d.union([d.null,d.number]),successfullyCompletedAt:d.union([d.null,d.string]),purpose:m})]);async function g(n,r){let{requests:{totalCount:i}}=await f(n,t,{variables:{filterBy:r},logger:e});return i}async function _(r,{actions:i=[],statuses:a=[],origins:o=[],text:s,createdAtBefore:c,createdAtAfter:u,updatedAtBefore:d,updatedAtAfter:m,isTest:h,isSilent:g,isClosed:_,requestIds:v=[],onPage:y}={}){let b=!!y,x={text:s,type:i.length>0?i:void 0,status:a.length>0?a:void 0,origin:o.length>0?o:void 0,isTest:h,isSilent:g,isClosed:_,createdAtBefore:c?c.toISOString():void 0,createdAtAfter:u?u.toISOString():void 0,updatedAtBefore:d?d.toISOString():void 0,updatedAtAfter:m?m.toISOString():void 0},S=new Date().getTime(),C=new p.SingleBar({},p.Presets.shades_classic);if(!b){e.info(l.magenta(`Fetching requests...`));let{requests:{totalCount:n}}=await f(r,t,{variables:{filterBy:x},logger:e});n>100&&(e.info(l.magenta(`Fetching ${n} requests`)),C.start(n,0))}let w=[],T=0,E,D=!1;do{let{requests:{nodes:t,pageInfo:i}}=await f(r,n,{variables:{first:100,after:E,filterBy:x},logger:e});b?await y(t):w.push(...t),T+=t.length,E=i.endCursor??void 0,b||C.update(T),D=i.hasNextPage}while(D);if(!b){C.stop();let t=new Date().getTime()-S;e.info(l.green(`Completed fetching of ${T} request in "${t/1e3}" seconds.`))}if(b)return[];let O=w;return v&&v.length>0&&(O=O.filter(e=>v.includes(e.id)),e.info(l.green(`Filtered down to ${O.length} requests based on ${v.length} provided IDs.`))),O}export{g as i,m as n,_ as r,h as t};
2
+ //# sourceMappingURL=fetchAllRequests-xGgt_STo.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchAllRequests-xGgt_STo.mjs","names":[],"sources":["../src/lib/graphql/fetchAllRequests.ts"],"sourcesContent":["import { LOCALE_KEY } from '@transcend-io/internationalization';\nimport {\n RequestAction,\n RequestOrigin,\n RequestStatus,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n} from '@transcend-io/privacy-types';\nimport { makeGraphQLRequest } from '@transcend-io/sdk';\nimport { valuesOf } from '@transcend-io/type-utils';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\nimport { GraphQLClient } from 'graphql-request';\nimport * as t from 'io-ts';\n\nimport { logger } from '../../logger.js';\nimport { REQUESTS, REQUESTS_COUNT } from './gqls/index.js';\n\nexport const RequestPurposeTrigger = t.type({\n title: t.string,\n name: t.string,\n consent: t.boolean,\n enrichedPreferences: t.array(\n t.type({\n topic: t.string,\n selectValues: t.array(\n t.type({\n id: t.string,\n name: t.string,\n preferenceOption: t.type({\n id: t.string,\n slug: t.string,\n title: t.type({\n defaultMessage: t.string,\n }),\n }),\n }),\n ),\n selectValue: t.type({\n id: t.string,\n name: t.string,\n }),\n preferenceTopic: t.type({\n title: t.type({\n defaultMessage: t.string,\n }),\n id: t.string,\n slug: t.string,\n }),\n name: t.string,\n id: t.string,\n booleanValue: t.boolean,\n }),\n ),\n});\n\n/** Override type */\nexport type RequestPurposeTrigger = t.TypeOf<typeof RequestPurposeTrigger>;\n\nexport const PrivacyRequest = t.intersection([\n t.type({\n /** Request ID */\n id: t.string,\n /** Time request was made */\n createdAt: t.string,\n /** Email of request */\n email: t.string,\n /** The type of request */\n type: valuesOf(RequestAction),\n /** Link to request in Transcend dashboard */\n link: t.string,\n /** Whether request is in silent mode */\n isSilent: t.boolean,\n /** Where request was made */\n origin: valuesOf(RequestOrigin),\n /** Whether request is a test request */\n isTest: t.boolean,\n /** The core identifier of the request */\n coreIdentifier: t.string,\n /** Request details */\n details: t.string,\n /** Locale of request */\n locale: valuesOf(LOCALE_KEY),\n /** Status of request */\n status: valuesOf(RequestStatus),\n /** Type of data subject */\n subjectType: t.string,\n /** Country of request */\n country: t.union([t.null, valuesOf(IsoCountryCode)]),\n /** Subdivision of request */\n countrySubDivision: t.union([t.null, valuesOf(IsoCountrySubdivisionCode)]),\n /** Request attributes */\n attributeValues: t.array(\n t.type({\n id: t.string,\n attributeKey: t.type({ name: t.string, id: t.string }),\n name: t.string,\n }),\n ),\n }),\n t.partial({\n /** Days remaining until expired */\n daysRemaining: t.union([t.null, t.number]),\n /** Time when request was successfully completed */\n successfullyCompletedAt: t.union([t.null, t.string]),\n /** Purpose */\n purpose: RequestPurposeTrigger,\n }),\n]);\n\n/** Type override */\nexport type PrivacyRequest = t.TypeOf<typeof PrivacyRequest>;\n\nconst PAGE_SIZE = 100;\n\n/**\n * Fetch just the total count of requests matching a set of filters.\n * Useful for setting up a progress bar before streaming pages.\n *\n * @param client - GraphQL client\n * @param filterBy - Filter object (already serialized to ISO strings)\n * @returns The total count\n */\nexport async function fetchRequestsTotalCount(\n client: GraphQLClient,\n filterBy: Record<string, unknown>,\n): Promise<number> {\n const {\n requests: { totalCount },\n } = await makeGraphQLRequest<{\n /** Requests */\n requests: {\n /** Total count */\n totalCount: number;\n };\n }>(client, REQUESTS_COUNT, { variables: { filterBy }, logger });\n return totalCount;\n}\n\n/**\n * Fetch all requests matching a set of filters.\n *\n * When `onPage` is provided the function streams pages to the callback\n * and never accumulates nodes in memory — ideal for very large exports.\n * Without `onPage` the function returns all nodes in a single array\n * (existing behaviour, kept for backward compatibility).\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns List of requests (empty when using onPage)\n */\nexport async function fetchAllRequests(\n client: GraphQLClient,\n {\n actions = [],\n statuses = [],\n origins = [],\n text,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n isTest,\n isSilent,\n isClosed,\n requestIds = [],\n onPage,\n }: {\n /** Actions to filter on */\n actions?: RequestAction[];\n /** Origins to filter on */\n origins?: RequestOrigin[];\n /** Statuses to filter on */\n statuses?: RequestStatus[];\n /** Filter for requests created before this date */\n createdAtBefore?: Date;\n /** Filter for requests created after this date */\n createdAtAfter?: Date;\n /** Filter for requests updated before this date */\n updatedAtBefore?: Date;\n /** Filter for requests updated after this date */\n updatedAtAfter?: Date;\n /** Filter for requests with a specific identifier */\n text?: string;\n /** Return test requests */\n isTest?: boolean;\n /** Return silent mode requests */\n isSilent?: boolean;\n /** Filter by whether request is active */\n isClosed?: boolean;\n /**\n * Filter the list of requests for a set of IDs - these are applied\n * at runtime while other filters are applied at the GraphQL level.\n */\n requestIds?: string[];\n /** When provided, called with each page of nodes instead of accumulating in memory */\n onPage?: (nodes: PrivacyRequest[]) => void | Promise<void>;\n } = {},\n): Promise<PrivacyRequest[]> {\n const streaming = !!onPage;\n\n const filterBy = {\n text,\n type: actions.length > 0 ? actions : undefined,\n status: statuses.length > 0 ? statuses : undefined,\n origin: origins.length > 0 ? origins : undefined,\n isTest,\n isSilent,\n isClosed,\n createdAtBefore: createdAtBefore ? createdAtBefore.toISOString() : undefined,\n createdAtAfter: createdAtAfter ? createdAtAfter.toISOString() : undefined,\n updatedAtBefore: updatedAtBefore ? updatedAtBefore.toISOString() : undefined,\n updatedAtAfter: updatedAtAfter ? updatedAtAfter.toISOString() : undefined,\n };\n\n // When streaming, the caller manages progress/logging — skip count query & bar\n const t0 = new Date().getTime();\n const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);\n\n if (!streaming) {\n logger.info(colors.magenta('Fetching requests...'));\n const {\n requests: { totalCount },\n } = await makeGraphQLRequest<{\n /** Requests */\n requests: {\n /** Total count */\n totalCount: number;\n };\n }>(client, REQUESTS_COUNT, { variables: { filterBy }, logger });\n\n if (totalCount > PAGE_SIZE) {\n logger.info(colors.magenta(`Fetching ${totalCount} requests`));\n progressBar.start(totalCount, 0);\n }\n }\n\n const requests: PrivacyRequest[] = [];\n let fetchedCount = 0;\n\n // Paginate through all results\n let cursor: string | undefined;\n let shouldContinue = false;\n do {\n const {\n requests: { nodes, pageInfo },\n } = await makeGraphQLRequest<{\n /** Requests */\n requests: {\n /** List */\n nodes: PrivacyRequest[];\n /** Pagination info */\n pageInfo: {\n /** Cursor for the last item */\n endCursor: string | null;\n /** Whether more pages exist */\n hasNextPage: boolean;\n };\n };\n }>(client, REQUESTS, {\n variables: { first: PAGE_SIZE, after: cursor, filterBy },\n logger,\n });\n\n if (streaming) {\n await onPage!(nodes);\n } else {\n requests.push(...nodes);\n }\n\n fetchedCount += nodes.length;\n cursor = pageInfo.endCursor ?? undefined;\n if (!streaming) {\n progressBar.update(fetchedCount);\n }\n shouldContinue = pageInfo.hasNextPage;\n } while (shouldContinue);\n\n if (!streaming) {\n progressBar.stop();\n const t1 = new Date().getTime();\n const totalTime = t1 - t0;\n\n logger.info(\n colors.green(\n `Completed fetching of ${fetchedCount} request in \"${totalTime / 1000}\" seconds.`,\n ),\n );\n }\n\n if (streaming) {\n return [];\n }\n\n // Filter down requests by request ID\n let allRequests = requests;\n if (requestIds && requestIds.length > 0) {\n allRequests = allRequests.filter((request) => requestIds.includes(request.id));\n logger.info(\n colors.green(\n `Filtered down to ${allRequests.length} requests based on ${requestIds.length} provided IDs.`,\n ),\n );\n }\n\n return allRequests;\n}\n"],"mappings":"seAkBA,MAAa,EAAwB,EAAE,KAAK,CAC1C,MAAO,EAAE,OACT,KAAM,EAAE,OACR,QAAS,EAAE,QACX,oBAAqB,EAAE,MACrB,EAAE,KAAK,CACL,MAAO,EAAE,OACT,aAAc,EAAE,MACd,EAAE,KAAK,CACL,GAAI,EAAE,OACN,KAAM,EAAE,OACR,iBAAkB,EAAE,KAAK,CACvB,GAAI,EAAE,OACN,KAAM,EAAE,OACR,MAAO,EAAE,KAAK,CACZ,eAAgB,EAAE,OACnB,CAAC,CACH,CAAC,CACH,CAAC,CACH,CACD,YAAa,EAAE,KAAK,CAClB,GAAI,EAAE,OACN,KAAM,EAAE,OACT,CAAC,CACF,gBAAiB,EAAE,KAAK,CACtB,MAAO,EAAE,KAAK,CACZ,eAAgB,EAAE,OACnB,CAAC,CACF,GAAI,EAAE,OACN,KAAM,EAAE,OACT,CAAC,CACF,KAAM,EAAE,OACR,GAAI,EAAE,OACN,aAAc,EAAE,QACjB,CAAC,CACH,CACF,CAAC,CAKW,EAAiB,EAAE,aAAa,CAC3C,EAAE,KAAK,CAEL,GAAI,EAAE,OAEN,UAAW,EAAE,OAEb,MAAO,EAAE,OAET,KAAM,EAAS,EAAc,CAE7B,KAAM,EAAE,OAER,SAAU,EAAE,QAEZ,OAAQ,EAAS,EAAc,CAE/B,OAAQ,EAAE,QAEV,eAAgB,EAAE,OAElB,QAAS,EAAE,OAEX,OAAQ,EAAS,EAAW,CAE5B,OAAQ,EAAS,EAAc,CAE/B,YAAa,EAAE,OAEf,QAAS,EAAE,MAAM,CAAC,EAAE,KAAM,EAAS,EAAe,CAAC,CAAC,CAEpD,mBAAoB,EAAE,MAAM,CAAC,EAAE,KAAM,EAAS,EAA0B,CAAC,CAAC,CAE1E,gBAAiB,EAAE,MACjB,EAAE,KAAK,CACL,GAAI,EAAE,OACN,aAAc,EAAE,KAAK,CAAE,KAAM,EAAE,OAAQ,GAAI,EAAE,OAAQ,CAAC,CACtD,KAAM,EAAE,OACT,CAAC,CACH,CACF,CAAC,CACF,EAAE,QAAQ,CAER,cAAe,EAAE,MAAM,CAAC,EAAE,KAAM,EAAE,OAAO,CAAC,CAE1C,wBAAyB,EAAE,MAAM,CAAC,EAAE,KAAM,EAAE,OAAO,CAAC,CAEpD,QAAS,EACV,CAAC,CACH,CAAC,CAeF,eAAsB,EACpB,EACA,EACiB,CACjB,GAAM,CACJ,SAAU,CAAE,eACV,MAAM,EAMP,EAAQ,EAAgB,CAAE,UAAW,CAAE,WAAU,CAAE,SAAQ,CAAC,CAC/D,OAAO,EAeT,eAAsB,EACpB,EACA,CACE,UAAU,EAAE,CACZ,WAAW,EAAE,CACb,UAAU,EAAE,CACZ,OACA,kBACA,iBACA,kBACA,iBACA,SACA,WACA,WACA,aAAa,EAAE,CACf,UA+BE,EAAE,CACqB,CAC3B,IAAM,EAAY,CAAC,CAAC,EAEd,EAAW,CACf,OACA,KAAM,EAAQ,OAAS,EAAI,EAAU,IAAA,GACrC,OAAQ,EAAS,OAAS,EAAI,EAAW,IAAA,GACzC,OAAQ,EAAQ,OAAS,EAAI,EAAU,IAAA,GACvC,SACA,WACA,WACA,gBAAiB,EAAkB,EAAgB,aAAa,CAAG,IAAA,GACnE,eAAgB,EAAiB,EAAe,aAAa,CAAG,IAAA,GAChE,gBAAiB,EAAkB,EAAgB,aAAa,CAAG,IAAA,GACnE,eAAgB,EAAiB,EAAe,aAAa,CAAG,IAAA,GACjE,CAGK,EAAK,IAAI,MAAM,CAAC,SAAS,CACzB,EAAc,IAAI,EAAY,UAAU,EAAE,CAAE,EAAY,QAAQ,eAAe,CAErF,GAAI,CAAC,EAAW,CACd,EAAO,KAAK,EAAO,QAAQ,uBAAuB,CAAC,CACnD,GAAM,CACJ,SAAU,CAAE,eACV,MAAM,EAMP,EAAQ,EAAgB,CAAE,UAAW,CAAE,WAAU,CAAE,SAAQ,CAAC,CAE3D,EAAa,MACf,EAAO,KAAK,EAAO,QAAQ,YAAY,EAAW,WAAW,CAAC,CAC9D,EAAY,MAAM,EAAY,EAAE,EAIpC,IAAM,EAA6B,EAAE,CACjC,EAAe,EAGf,EACA,EAAiB,GACrB,EAAG,CACD,GAAM,CACJ,SAAU,CAAE,QAAO,aACjB,MAAM,EAaP,EAAQ,EAAU,CACnB,UAAW,CAAE,MAAO,IAAW,MAAO,EAAQ,WAAU,CACxD,SACD,CAAC,CAEE,EACF,MAAM,EAAQ,EAAM,CAEpB,EAAS,KAAK,GAAG,EAAM,CAGzB,GAAgB,EAAM,OACtB,EAAS,EAAS,WAAa,IAAA,GAC1B,GACH,EAAY,OAAO,EAAa,CAElC,EAAiB,EAAS,kBACnB,GAET,GAAI,CAAC,EAAW,CACd,EAAY,MAAM,CAElB,IAAM,EADK,IAAI,MAAM,CAAC,SAAS,CACR,EAEvB,EAAO,KACL,EAAO,MACL,yBAAyB,EAAa,eAAe,EAAY,IAAK,YACvE,CACF,CAGH,GAAI,EACF,MAAO,EAAE,CAIX,IAAI,EAAc,EAUlB,OATI,GAAc,EAAW,OAAS,IACpC,EAAc,EAAY,OAAQ,GAAY,EAAW,SAAS,EAAQ,GAAG,CAAC,CAC9E,EAAO,KACL,EAAO,MACL,oBAAoB,EAAY,OAAO,qBAAqB,EAAW,OAAO,gBAC/E,CACF,EAGI"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./logger-Bj782ZYD.mjs";import{r as t}from"./RequestDataSilo-Rrc2dL9g.mjs";import{makeGraphQLRequest as n}from"@transcend-io/sdk";async function r(r,{requestId:i,dataSiloId:a,requestStatuses:o,statuses:s}){let{requestDataSilos:{totalCount:c}}=await n(r,t,{variables:{first:1,offset:0,filterBy:{dataSiloId:a,requestId:i,status:s,requestStatus:o}},logger:e});return c}async function i(r,{requestId:i,dataSiloId:a,requestStatuses:o,statuses:s,limit:c,onProgress:l}){let u=[],d=0,f=!1;do{let{requestDataSilos:{nodes:c}}=await n(r,t,{variables:{first:100,offset:d,filterBy:{dataSiloId:a,requestId:i,status:s,requestStatus:o}},logger:e});u.push(...c),d+=100,f=c.length===100,l?.(c.length)}while(f&&(!c||d<c));return u}async function a(e,{requestId:t,dataSiloId:n}){let r=await i(e,{requestId:t,dataSiloId:n});if(r.length!==1)throw Error(`Failed to find RequestDataSilo with requestId:${t},dataSiloId:${n}`);return r[0]}export{i as n,r,a as t};
2
+ //# sourceMappingURL=fetchRequestDataSilo-0UvyeL60.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchRequestDataSilo-0UvyeL60.mjs","names":[],"sources":["../src/lib/graphql/fetchRequestDataSilo.ts"],"sourcesContent":["import { RequestAction, RequestDataSiloStatus, RequestStatus } from '@transcend-io/privacy-types';\nimport { makeGraphQLRequest } from '@transcend-io/sdk';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { logger } from '../../logger.js';\nimport { REQUEST_DATA_SILOS } from './gqls/index.js';\n\nexport interface RequestDataSilo {\n /** ID of RequestDataSilo */\n id: string;\n /** Request */\n request: {\n /** Type of request */\n type: RequestAction;\n };\n}\n\nexport interface RequestDataSiloFilters {\n /** ID of request to filter on */\n requestId?: string;\n /** Data silo ID */\n dataSiloId?: string;\n /**\n * The statuses to filter on\n */\n statuses?: RequestDataSiloStatus[];\n /** The request statuses to filter on */\n requestStatuses?: RequestStatus[];\n}\n\n/**\n * Fetch a count of request data silos\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns List of request identifiers\n */\nexport async function fetchRequestDataSilosCount(\n client: GraphQLClient,\n { requestId, dataSiloId, requestStatuses, statuses }: RequestDataSiloFilters,\n): Promise<number> {\n const {\n requestDataSilos: { totalCount },\n } = await makeGraphQLRequest<{\n /** Request Data Silos */\n requestDataSilos: {\n /** List */\n nodes: RequestDataSilo[];\n /** Total count */\n totalCount: number;\n };\n }>(client, REQUEST_DATA_SILOS, {\n variables: {\n first: 1,\n offset: 0,\n filterBy: {\n dataSiloId,\n requestId,\n status: statuses,\n requestStatus: requestStatuses,\n },\n },\n logger,\n });\n\n return totalCount;\n}\n\nconst PAGE_SIZE = 100;\n\n/**\n * Fetch all request data silos by some filter criteria\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns List of request identifiers\n */\nexport async function fetchRequestDataSilos(\n client: GraphQLClient,\n {\n requestId,\n dataSiloId,\n requestStatuses,\n statuses,\n limit,\n onProgress,\n }: {\n /** ID of request to filter on */\n requestId?: string;\n /** Data silo ID */\n dataSiloId?: string;\n /**\n * The statuses to filter on\n */\n statuses?: RequestDataSiloStatus[];\n /** The request statuses to filter on */\n requestStatuses?: RequestStatus[];\n /** Limit on number of requests */\n limit?: number;\n /** Handle progress updates */\n onProgress?: (numUpdated: number) => void;\n },\n): Promise<RequestDataSilo[]> {\n const requestDataSilos: RequestDataSilo[] = [];\n let offset = 0;\n\n // Try to fetch an DataFlow with the same title\n let shouldContinue = false;\n do {\n const {\n requestDataSilos: { nodes },\n } = await makeGraphQLRequest<{\n /** Request Data Silos */\n requestDataSilos: {\n /** List */\n nodes: RequestDataSilo[];\n /** Total count */\n totalCount: number;\n };\n }>(client, REQUEST_DATA_SILOS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n filterBy: {\n dataSiloId,\n requestId,\n status: statuses,\n requestStatus: requestStatuses,\n },\n },\n logger,\n });\n requestDataSilos.push(...nodes);\n\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n onProgress?.(nodes.length);\n } while (shouldContinue && (!limit || offset < limit));\n\n return requestDataSilos;\n}\n\n/**\n * Fetch all request identifiers for a particular request\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns List of request identifiers\n */\nexport async function fetchRequestDataSilo(\n client: GraphQLClient,\n {\n requestId,\n dataSiloId,\n }: {\n /** ID of request to filter on */\n requestId: string;\n /** Data silo ID */\n dataSiloId: string;\n },\n): Promise<RequestDataSilo> {\n const nodes = await fetchRequestDataSilos(client, {\n requestId,\n dataSiloId,\n });\n if (nodes.length !== 1) {\n throw new Error(\n `Failed to find RequestDataSilo with requestId:${requestId},dataSiloId:${dataSiloId}`,\n );\n }\n\n return nodes[0];\n}\n"],"mappings":"oJAqCA,eAAsB,EACpB,EACA,CAAE,YAAW,aAAY,kBAAiB,YACzB,CACjB,GAAM,CACJ,iBAAkB,CAAE,eAClB,MAAM,EAQP,EAAQ,EAAoB,CAC7B,UAAW,CACT,MAAO,EACP,OAAQ,EACR,SAAU,CACR,aACA,YACA,OAAQ,EACR,cAAe,EAChB,CACF,CACD,SACD,CAAC,CAEF,OAAO,EAYT,eAAsB,EACpB,EACA,CACE,YACA,aACA,kBACA,WACA,QACA,cAiB0B,CAC5B,IAAM,EAAsC,EAAE,CAC1C,EAAS,EAGT,EAAiB,GACrB,EAAG,CACD,GAAM,CACJ,iBAAkB,CAAE,UAClB,MAAM,EAQP,EAAQ,EAAoB,CAC7B,UAAW,CACT,MAAO,IACP,SACA,SAAU,CACR,aACA,YACA,OAAQ,EACR,cAAe,EAChB,CACF,CACD,SACD,CAAC,CACF,EAAiB,KAAK,GAAG,EAAM,CAE/B,GAAU,IACV,EAAiB,EAAM,SAAW,IAClC,IAAa,EAAM,OAAO,OACnB,IAAmB,CAAC,GAAS,EAAS,IAE/C,OAAO,EAUT,eAAsB,EACpB,EACA,CACE,YACA,cAOwB,CAC1B,IAAM,EAAQ,MAAM,EAAsB,EAAQ,CAChD,YACA,aACD,CAAC,CACF,GAAI,EAAM,SAAW,EACnB,MAAU,MACR,iDAAiD,EAAU,cAAc,IAC1E,CAGH,OAAO,EAAM"}
@@ -1,4 +1,4 @@
1
- import{t as e}from"./makeGraphQLRequest-Cq26A_Lq.mjs";import{gql as t}from"graphql-request";const n=t`
1
+ import{t as e}from"./logger-Bj782ZYD.mjs";import{makeGraphQLRequest as t}from"@transcend-io/sdk";import{gql as n}from"graphql-request";const r=n`
2
2
  query TranscendCliRequestFiles($first: Int!, $offset: Int!, $filterBy: RequestFileFiltersInput!) {
3
3
  requestFiles(
4
4
  filterBy: $filterBy
@@ -12,7 +12,7 @@ import{t as e}from"./makeGraphQLRequest-Cq26A_Lq.mjs";import{gql as t}from"graph
12
12
  }
13
13
  }
14
14
  }
15
- `,r=t`
15
+ `,i=n`
16
16
  query TranscendCliBulkRequestFiles(
17
17
  $filterBy: BulkRequestFilesFiltersInput!
18
18
  $first: Int!
@@ -29,5 +29,5 @@ import{t as e}from"./makeGraphQLRequest-Cq26A_Lq.mjs";import{gql as t}from"graph
29
29
  }
30
30
  }
31
31
  }
32
- `;async function i(t,n,i){let a=[],o=null,s=!1;do{let{bulkRequestFiles:{nodes:c,pageInfo:l}}=await e(t,r,{filterBy:{...i},first:n,after:o??void 0});a.push(...c),s=l.hasNextPage,o=l.endCursor}while(s);return a.sort((e,t)=>e.remoteId.localeCompare(t.remoteId))}export{r as n,n as r,i as t};
33
- //# sourceMappingURL=fetchRequestFilesForRequest-BbxrEKFK.mjs.map
32
+ `;async function a(n,r,a){let o=[],s=null,c=!1;do{let{bulkRequestFiles:{nodes:l,pageInfo:u}}=await t(n,i,{variables:{filterBy:{...a},first:r,after:s??void 0},logger:e});o.push(...l),c=u.hasNextPage,s=u.endCursor}while(c);return o.sort((e,t)=>e.remoteId.localeCompare(t.remoteId))}export{i as n,r,a as t};
33
+ //# sourceMappingURL=fetchRequestFilesForRequest-CJH2iB-P.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchRequestFilesForRequest-CJH2iB-P.mjs","names":[],"sources":["../src/lib/graphql/gqls/requestFile.ts","../src/lib/graphql/fetchRequestFilesForRequest.ts"],"sourcesContent":["import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const REQUEST_FILES = gql`\n query TranscendCliRequestFiles($first: Int!, $offset: Int!, $filterBy: RequestFileFiltersInput!) {\n requestFiles(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: id, direction: ASC }]\n ) {\n nodes {\n remoteId\n fileName\n }\n }\n }\n`;\n\nexport const BULK_REQUEST_FILES = gql`\n query TranscendCliBulkRequestFiles(\n $filterBy: BulkRequestFilesFiltersInput!\n $first: Int!\n $after: String\n ) {\n bulkRequestFiles(filterBy: $filterBy, first: $first, after: $after) {\n nodes {\n remoteId\n fileName\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n`;\n","import { makeGraphQLRequest } from '@transcend-io/sdk';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { logger } from '../../logger.js';\nimport { BULK_REQUEST_FILES } from './gqls/index.js';\n\nexport interface RequestFileCursor {\n /** The ID of the request file */\n id: string;\n /** The created at timestamp */\n createdAt: string;\n}\n\nexport interface RequestFile {\n /** The remote ID */\n remoteId: string;\n /** The file name */\n fileName: string;\n}\n\nexport interface RequestFileResponse {\n /** RequestFiles */\n bulkRequestFiles: {\n /** List */\n nodes: RequestFile[];\n /** The page info */\n pageInfo: {\n /** Whether there is a next page */\n hasNextPage: boolean;\n /** The end cursor */\n endCursor: string;\n };\n };\n}\n\n/**\n * Fetch all RequestFiles for a single request\n *\n * @param client - GraphQL client\n * @param pageSize - How many request files to fetch per API call\n * @param filterBy - Filter by\n * @returns All RequestFiles in the organization\n */\nexport async function fetchRequestFilesForRequest(\n client: GraphQLClient,\n /** How many request files to fetch per API call */\n pageSize: number,\n filterBy: {\n /** Filter by request IDs */\n requestIds: string[];\n /** Filter by data silo ID */\n dataSiloIds: string[];\n },\n): Promise<RequestFile[]> {\n const requestFiles: RequestFile[] = [];\n let cursor: string | null = null;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const response: RequestFileResponse = await makeGraphQLRequest<RequestFileResponse>(\n client,\n BULK_REQUEST_FILES,\n {\n variables: {\n filterBy: {\n ...filterBy,\n },\n first: pageSize,\n after: cursor ?? undefined,\n },\n logger,\n },\n );\n const {\n bulkRequestFiles: { nodes, pageInfo },\n } = response;\n requestFiles.push(...nodes);\n shouldContinue = pageInfo.hasNextPage;\n cursor = pageInfo.endCursor;\n } while (shouldContinue);\n\n return requestFiles.sort((a, b) => a.remoteId.localeCompare(b.remoteId));\n}\n"],"mappings":"uIAKA,MAAa,EAAgB,CAAG;;;;;;;;;;;;;;EAgBnB,EAAqB,CAAG;;;;;;;;;;;;;;;;;ECsBrC,eAAsB,EACpB,EAEA,EACA,EAMwB,CACxB,IAAM,EAA8B,EAAE,CAClC,EAAwB,KAGxB,EAAiB,GACrB,EAAG,CAeD,GAAM,CACJ,iBAAkB,CAAE,QAAO,aAfS,MAAM,EAC1C,EACA,EACA,CACE,UAAW,CACT,SAAU,CACR,GAAG,EACJ,CACD,MAAO,EACP,MAAO,GAAU,IAAA,GAClB,CACD,SACD,CACF,CAID,EAAa,KAAK,GAAG,EAAM,CAC3B,EAAiB,EAAS,YAC1B,EAAS,EAAS,gBACX,GAET,OAAO,EAAa,MAAM,EAAG,IAAM,EAAE,SAAS,cAAc,EAAE,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{a as e}from"./constants-XOsAW1__.mjs";import{t}from"./logger-Bj782ZYD.mjs";import n from"colors";import{assumeRole as r,buildTranscendGraphQLClientGeneric as i,createApiKey as a,deleteApiKey as o,fetchAllApiKeys as s,loginUser as c}from"@transcend-io/sdk";import{mapSeries as l}from"@transcend-io/utils";async function u({email:u,password:d,scopes:f,apiKeyTitle:p,parentOrganizationId:m,deleteExistingApiKey:h=!0,createNewApiKey:g=!0,transcendUrl:_=e}){let v=await i(_,{});t.info(n.magenta(`Logging in using email and password.`));let{roles:y,loginCookie:b}=await c(v,{email:u,password:d,logger:t});t.info(n.green(`Successfully logged in and found ${y.length} role${y.length===1?``:`s`}!`));let x=m?y.filter(e=>e.organization.id===m||e.organization.parentOrganizationId===m):y;v.setHeaders({Cookie:b});let S=[],C=[];return t.info(n.magenta(`Generating API keys with title: ${p}, scopes: ${f.join(`,`)}.`)),await l(x,async e=>{try{await r(v,{roleId:e.id,email:u,logger:t}),t.info(n.magenta(`Checking if API key already exists in organization "${e.organization.name}" with title: "${p}".`));let[i]=await s(v,{titles:[p],logger:t});if(i&&h)t.info(n.yellow(`Deleting existing API key in "${e.organization.name}" with title: "${p}".`)),await o(v,i.id,{logger:t}),t.info(n.green(`Successfully deleted API key in "${e.organization.name}" with title: "${p}".`));else if(i)throw Error(`API key already exists with title: "${p}"`);if(g){t.info(n.magenta(`Creating API key in "${e.organization.name}" with title: "${p}".`));let{apiKey:r}=await a(v,{title:p,scopes:f},{logger:t});S.push({organizationName:e.organization.name,organizationId:e.organization.id,apiKey:r}),t.info(n.green(`Successfully created API key in "${e.organization.name}" with title: "${p}".`))}else S.push({organizationName:e.organization.name,organizationId:e.organization.id,apiKey:``})}catch(r){t.error(n.red(`Failed to create API key in organization "${e.organization.name}"! - ${r.message}`)),C.push({organizationName:e.organization.name,organizationId:e.organization.id,error:r.message})}}),t.info(n.green(`Successfully created ${S.length} API key${S.length===1?``:`s`}`)),C.length>0&&t.error(n.red(`Failed to create ${C.length} API key${C.length===1?``:`s`}!`)),{errors:C,apiKeys:S}}export{u as t};
2
+ //# sourceMappingURL=generateCrossAccountApiKeys-DztJoLQS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateCrossAccountApiKeys-DztJoLQS.mjs","names":[],"sources":["../src/lib/api-keys/generateCrossAccountApiKeys.ts"],"sourcesContent":["import { ScopeName } from '@transcend-io/privacy-types';\nimport {\n buildTranscendGraphQLClientGeneric,\n loginUser,\n createApiKey,\n fetchAllApiKeys,\n deleteApiKey,\n assumeRole,\n} from '@transcend-io/sdk';\nimport { mapSeries } from '@transcend-io/utils';\nimport colors from 'colors';\n\nimport { StoredApiKey } from '../../codecs.js';\nimport { DEFAULT_TRANSCEND_API } from '../../constants.js';\nimport { logger } from '../../logger.js';\n\nexport interface ApiKeyGenerateError {\n /** Name of instance */\n organizationName: string;\n /** Error */\n error: string;\n /** Organization ID API key is for */\n organizationId: string;\n}\n\n/**\n * Generate API keys across multiple transcend accounts\n *\n * @param options - Options\n * @returns Number of API keys created\n */\nexport async function generateCrossAccountApiKeys({\n email,\n password,\n scopes,\n apiKeyTitle,\n parentOrganizationId,\n deleteExistingApiKey = true,\n createNewApiKey = true,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** Email address of user generating API keys */\n email: string;\n /** Password of user generating API keys */\n password: string;\n /** Filter for organizations that match this parent organization ID */\n parentOrganizationId?: string;\n /** Title of the API create to create */\n apiKeyTitle: string;\n /** Title of the API create to create */\n scopes: ScopeName[];\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** When true delete existing API keys with that title, if set to false an API key exists with that title, an error is thrown */\n deleteExistingApiKey?: boolean;\n /** When true, generate new API keys, otherwise only will delete past API keys */\n createNewApiKey?: boolean;\n}): Promise<{\n /** Successfully generated */\n apiKeys: StoredApiKey[];\n /** Error results */\n errors: ApiKeyGenerateError[];\n}> {\n // Create GraphQL client\n const client = await buildTranscendGraphQLClientGeneric(transcendUrl, {});\n\n // Login the user\n logger.info(colors.magenta('Logging in using email and password.'));\n const { roles, loginCookie } = await loginUser(client, { email, password, logger });\n logger.info(\n colors.green(\n `Successfully logged in and found ${roles.length} role${roles.length === 1 ? '' : 's'}!`,\n ),\n );\n\n // Filter down by parentOrganizationId\n const filteredRoles = parentOrganizationId\n ? roles.filter(\n (role) =>\n role.organization.id === parentOrganizationId ||\n role.organization.parentOrganizationId === parentOrganizationId,\n )\n : roles;\n\n // Save cookie to call route subsequent times\n client.setHeaders({\n Cookie: loginCookie,\n });\n\n // Save the resulting API keys\n const results: StoredApiKey[] = [];\n const errors: ApiKeyGenerateError[] = [];\n\n // Generate API keys\n logger.info(\n colors.magenta(`Generating API keys with title: ${apiKeyTitle}, scopes: ${scopes.join(',')}.`),\n );\n\n // Map over each role\n await mapSeries(filteredRoles, async (role) => {\n try {\n // Log into the other instance\n await assumeRole(client, { roleId: role.id, email, logger });\n\n // Grab API keys with that title\n logger.info(\n colors.magenta(\n `Checking if API key already exists in organization \"${role.organization.name}\" with title: \"${apiKeyTitle}\".`,\n ),\n );\n\n // Delete existing API key\n const [apiKeyWithTitle] = await fetchAllApiKeys(client, { titles: [apiKeyTitle], logger });\n if (apiKeyWithTitle && deleteExistingApiKey) {\n logger.info(\n colors.yellow(\n `Deleting existing API key in \"${role.organization.name}\" with title: \"${apiKeyTitle}\".`,\n ),\n );\n await deleteApiKey(client, apiKeyWithTitle.id, { logger });\n logger.info(\n colors.green(\n `Successfully deleted API key in \"${role.organization.name}\" with title: \"${apiKeyTitle}\".`,\n ),\n );\n } else if (apiKeyWithTitle) {\n // throw error if one exists but not configured to delete\n throw new Error(`API key already exists with title: \"${apiKeyTitle}\"`);\n }\n\n // Create the API key\n if (createNewApiKey) {\n logger.info(\n colors.magenta(\n `Creating API key in \"${role.organization.name}\" with title: \"${apiKeyTitle}\".`,\n ),\n );\n const { apiKey } = await createApiKey(client, { title: apiKeyTitle, scopes }, { logger });\n results.push({\n organizationName: role.organization.name,\n organizationId: role.organization.id,\n apiKey,\n });\n logger.info(\n colors.green(\n `Successfully created API key in \"${role.organization.name}\" with title: \"${apiKeyTitle}\".`,\n ),\n );\n } else {\n // Delete only\n results.push({\n organizationName: role.organization.name,\n organizationId: role.organization.id,\n apiKey: '',\n });\n }\n } catch (err) {\n logger.error(\n colors.red(\n `Failed to create API key in organization \"${role.organization.name}\"! - ${err.message}`,\n ),\n );\n errors.push({\n organizationName: role.organization.name,\n organizationId: role.organization.id,\n error: err.message,\n });\n }\n });\n logger.info(\n colors.green(\n `Successfully created ${results.length} API key${results.length === 1 ? '' : 's'}`,\n ),\n );\n\n if (errors.length > 0) {\n logger.error(\n colors.red(`Failed to create ${errors.length} API key${errors.length === 1 ? '' : 's'}!`),\n );\n }\n\n return { errors, apiKeys: results };\n}\n"],"mappings":"uTA+BA,eAAsB,EAA4B,CAChD,QACA,WACA,SACA,cACA,uBACA,uBAAuB,GACvB,kBAAkB,GAClB,eAAe,GAuBd,CAED,IAAM,EAAS,MAAM,EAAmC,EAAc,EAAE,CAAC,CAGzE,EAAO,KAAK,EAAO,QAAQ,uCAAuC,CAAC,CACnE,GAAM,CAAE,QAAO,eAAgB,MAAM,EAAU,EAAQ,CAAE,QAAO,WAAU,SAAQ,CAAC,CACnF,EAAO,KACL,EAAO,MACL,oCAAoC,EAAM,OAAO,OAAO,EAAM,SAAW,EAAI,GAAK,IAAI,GACvF,CACF,CAGD,IAAM,EAAgB,EAClB,EAAM,OACH,GACC,EAAK,aAAa,KAAO,GACzB,EAAK,aAAa,uBAAyB,EAC9C,CACD,EAGJ,EAAO,WAAW,CAChB,OAAQ,EACT,CAAC,CAGF,IAAM,EAA0B,EAAE,CAC5B,EAAgC,EAAE,CA0FxC,OAvFA,EAAO,KACL,EAAO,QAAQ,mCAAmC,EAAY,YAAY,EAAO,KAAK,IAAI,CAAC,GAAG,CAC/F,CAGD,MAAM,EAAU,EAAe,KAAO,IAAS,CAC7C,GAAI,CAEF,MAAM,EAAW,EAAQ,CAAE,OAAQ,EAAK,GAAI,QAAO,SAAQ,CAAC,CAG5D,EAAO,KACL,EAAO,QACL,uDAAuD,EAAK,aAAa,KAAK,iBAAiB,EAAY,IAC5G,CACF,CAGD,GAAM,CAAC,GAAmB,MAAM,EAAgB,EAAQ,CAAE,OAAQ,CAAC,EAAY,CAAE,SAAQ,CAAC,CAC1F,GAAI,GAAmB,EACrB,EAAO,KACL,EAAO,OACL,iCAAiC,EAAK,aAAa,KAAK,iBAAiB,EAAY,IACtF,CACF,CACD,MAAM,EAAa,EAAQ,EAAgB,GAAI,CAAE,SAAQ,CAAC,CAC1D,EAAO,KACL,EAAO,MACL,oCAAoC,EAAK,aAAa,KAAK,iBAAiB,EAAY,IACzF,CACF,SACQ,EAET,MAAU,MAAM,uCAAuC,EAAY,GAAG,CAIxE,GAAI,EAAiB,CACnB,EAAO,KACL,EAAO,QACL,wBAAwB,EAAK,aAAa,KAAK,iBAAiB,EAAY,IAC7E,CACF,CACD,GAAM,CAAE,UAAW,MAAM,EAAa,EAAQ,CAAE,MAAO,EAAa,SAAQ,CAAE,CAAE,SAAQ,CAAC,CACzF,EAAQ,KAAK,CACX,iBAAkB,EAAK,aAAa,KACpC,eAAgB,EAAK,aAAa,GAClC,SACD,CAAC,CACF,EAAO,KACL,EAAO,MACL,oCAAoC,EAAK,aAAa,KAAK,iBAAiB,EAAY,IACzF,CACF,MAGD,EAAQ,KAAK,CACX,iBAAkB,EAAK,aAAa,KACpC,eAAgB,EAAK,aAAa,GAClC,OAAQ,GACT,CAAC,OAEG,EAAK,CACZ,EAAO,MACL,EAAO,IACL,6CAA6C,EAAK,aAAa,KAAK,OAAO,EAAI,UAChF,CACF,CACD,EAAO,KAAK,CACV,iBAAkB,EAAK,aAAa,KACpC,eAAgB,EAAK,aAAa,GAClC,MAAO,EAAI,QACZ,CAAC,GAEJ,CACF,EAAO,KACL,EAAO,MACL,wBAAwB,EAAQ,OAAO,UAAU,EAAQ,SAAW,EAAI,GAAK,MAC9E,CACF,CAEG,EAAO,OAAS,GAClB,EAAO,MACL,EAAO,IAAI,oBAAoB,EAAO,OAAO,UAAU,EAAO,SAAW,EAAI,GAAK,IAAI,GAAG,CAC1F,CAGI,CAAE,SAAQ,QAAS,EAAS"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./logger-Bj782ZYD.mjs";import{a as t,r as n}from"./readTranscendYaml-DVkQL2SC.mjs";import{t as r}from"./listFiles-Odj7j2E1.mjs";import{t as i}from"./done-input-validation-C5rgR0Wr.mjs";import{t as a}from"./dataFlowsToDataSilos-DUj1NhOt.mjs";import{difference as o}from"lodash-es";import{existsSync as s,lstatSync as c}from"node:fs";import{join as l}from"node:path";import u from"colors";import{buildTranscendGraphQLClient as d,fetchAndIndexCatalogs as f}from"@transcend-io/sdk";async function p({auth:p,dataFlowsYmlFolder:m,output:h,ignoreYmls:g=[],transcendUrl:_}){i(this.process.exit),(!s(m)||!c(m).isDirectory())&&(e.error(u.red(`Folder does not exist: "${m}"`)),this.process.exit(1));let v=g.map(e=>e.split(`.`)[0]),y=r(m).map(e=>{let{"data-flows":t=[]}=n(l(m,e)),{adTechDataSilos:r,siteTechDataSilos:i}=a(t,{serviceToSupportedIntegration:T,serviceToTitle:w});return{adTechDataSilos:r,siteTechDataSilos:i,organizationName:e.split(`.`)[0]}}),b={};y.forEach(({adTechDataSilos:e,siteTechDataSilos:t,organizationName:n})=>{[...e,...t].forEach(e=>{let t=e[`outer-type`]||e.integrationName;b[t]||(b[t]=[]),b[t].push(n),b[t]=[...new Set(b[t])]})});let x=[...new Set(y.map(({adTechDataSilos:e})=>e.map(e=>e[`outer-type`]||e.integrationName)).flat())],S=o([...new Set(y.map(({siteTechDataSilos:e})=>e.map(e=>e[`outer-type`]||e.integrationName)).flat())],x),C={};y.forEach(({adTechDataSilos:e,siteTechDataSilos:t})=>{[...e,...t].forEach(e=>{let t=e[`outer-type`]||e.integrationName,n=e.attributes?.find(e=>e.key===`Found On Domain`);C[t]||(C[t]=[]),C[t].push(...n?.values||[]),C[t]=[...new Set(C[t])]})});let{serviceToTitle:w,serviceToSupportedIntegration:T}=await f(d(_,p),{logger:e}),E=[...x,...S].map(e=>({title:w[e],...T[e]?{integrationName:e}:{integrationName:`promptAPerson`,"outer-type":e},attributes:[{key:`Tech Type`,values:[`Ad Tech`]},{key:`Business Units`,values:o(b[e]||[],v)},{key:`Found On Domain`,values:C[e]||[]}]}));e.log(`Total Services: ${E.length}`),e.log(`Ad Tech Services: ${x.length}`),e.log(`Site Tech Services: ${S.length}`),t(h,{"data-silos":E})}export{p as deriveDataSilosFromDataFlowsCrossInstance};
2
+ //# sourceMappingURL=impl-B-PzeHxN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impl-B-PzeHxN.mjs","names":[],"sources":["../src/commands/inventory/derive-data-silos-from-data-flows-cross-instance/impl.ts"],"sourcesContent":["import { existsSync, lstatSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { buildTranscendGraphQLClient, fetchAndIndexCatalogs } from '@transcend-io/sdk';\nimport colors from 'colors';\nimport { difference } from 'lodash-es';\n\nimport { DataFlowInput } from '../../../codecs.js';\nimport type { LocalContext } from '../../../context.js';\nimport { listFiles } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { dataFlowsToDataSilos } from '../../../lib/consent-manager/dataFlowsToDataSilos.js';\nimport { readTranscendYaml, writeTranscendYaml } from '../../../lib/readTranscendYaml.js';\nimport { logger } from '../../../logger.js';\n\nexport interface DeriveDataSilosFromDataFlowsCrossInstanceCommandFlags {\n auth: string;\n dataFlowsYmlFolder: string;\n output: string;\n ignoreYmls?: string[];\n transcendUrl: string;\n}\n\nexport async function deriveDataSilosFromDataFlowsCrossInstance(\n this: LocalContext,\n {\n auth,\n dataFlowsYmlFolder,\n output,\n ignoreYmls = [],\n transcendUrl,\n }: DeriveDataSilosFromDataFlowsCrossInstanceCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process.exit);\n\n // Ensure folder is passed\n if (!existsSync(dataFlowsYmlFolder) || !lstatSync(dataFlowsYmlFolder).isDirectory()) {\n logger.error(colors.red(`Folder does not exist: \"${dataFlowsYmlFolder}\"`));\n this.process.exit(1);\n }\n\n // Ignore the data flows in these yml files\n const instancesToIgnore = ignoreYmls.map((x) => x.split('.')[0]);\n\n // Map over each data flow yml file and convert to data silo configurations\n const dataSiloInputs = listFiles(dataFlowsYmlFolder).map((directory) => {\n // read in the data flows for a specific instance\n const { 'data-flows': dataFlows = [] } = readTranscendYaml(join(dataFlowsYmlFolder, directory));\n\n // map the data flows to data silos\n const { adTechDataSilos, siteTechDataSilos } = dataFlowsToDataSilos(\n dataFlows as DataFlowInput[],\n {\n serviceToSupportedIntegration,\n serviceToTitle,\n },\n );\n\n return {\n adTechDataSilos,\n siteTechDataSilos,\n organizationName: directory.split('.')[0],\n };\n });\n\n // Mapping from service name to instances that have that service\n const serviceToInstance: { [k in string]: string[] } = {};\n dataSiloInputs.forEach(({ adTechDataSilos, siteTechDataSilos, organizationName }) => {\n const allDataSilos = [...adTechDataSilos, ...siteTechDataSilos];\n allDataSilos.forEach((dataSilo) => {\n const service = dataSilo['outer-type'] || dataSilo.integrationName;\n // create mapping to instance\n if (!serviceToInstance[service]) {\n serviceToInstance[service] = [];\n }\n serviceToInstance[service]!.push(organizationName);\n serviceToInstance[service] = [...new Set(serviceToInstance[service])];\n });\n });\n\n // List of ad tech integrations\n const adTechIntegrations = [\n ...new Set(\n dataSiloInputs\n .map(({ adTechDataSilos }) =>\n adTechDataSilos.map((silo) => silo['outer-type'] || silo.integrationName),\n )\n .flat(),\n ),\n ];\n\n // List of site tech integrations\n const siteTechIntegrations = difference(\n [\n ...new Set(\n dataSiloInputs\n .map(({ siteTechDataSilos }) =>\n siteTechDataSilos.map((silo) => silo['outer-type'] || silo.integrationName),\n )\n .flat(),\n ),\n ],\n adTechIntegrations,\n );\n\n // Mapping from service name to list of\n const serviceToFoundOnDomain: { [k in string]: string[] } = {};\n dataSiloInputs.forEach(({ adTechDataSilos, siteTechDataSilos }) => {\n const allDataSilos = [...adTechDataSilos, ...siteTechDataSilos];\n allDataSilos.forEach((dataSilo) => {\n const service = dataSilo['outer-type'] || dataSilo.integrationName;\n const foundOnDomain = dataSilo.attributes?.find((attr) => attr.key === 'Found On Domain');\n // create mapping to instance\n if (!serviceToFoundOnDomain[service]) {\n serviceToFoundOnDomain[service] = [];\n }\n serviceToFoundOnDomain[service]!.push(...(foundOnDomain?.values || []));\n serviceToFoundOnDomain[service] = [...new Set(serviceToFoundOnDomain[service])];\n });\n });\n\n // Fetch all integrations in the catalog\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n const { serviceToTitle, serviceToSupportedIntegration } = await fetchAndIndexCatalogs(client, {\n logger,\n });\n\n // construct the aggregated data silo inputs\n const dataSilos = [...adTechIntegrations, ...siteTechIntegrations].map((service) => ({\n title: serviceToTitle[service],\n ...(serviceToSupportedIntegration[service]\n ? { integrationName: service }\n : { integrationName: 'promptAPerson', 'outer-type': service }),\n attributes: [\n {\n key: 'Tech Type',\n values: ['Ad Tech'],\n },\n {\n key: 'Business Units',\n values: difference(serviceToInstance[service] || [], instancesToIgnore),\n },\n {\n key: 'Found On Domain',\n values: serviceToFoundOnDomain[service] || [],\n },\n ],\n }));\n\n // Log output\n logger.log(`Total Services: ${dataSilos.length}`);\n logger.log(`Ad Tech Services: ${adTechIntegrations.length}`);\n logger.log(`Site Tech Services: ${siteTechIntegrations.length}`);\n\n // Write to yaml\n writeTranscendYaml(output, {\n 'data-silos': dataSilos,\n });\n}\n"],"mappings":"ifAuBA,eAAsB,EAEpB,CACE,OACA,qBACA,SACA,aAAa,EAAE,CACf,gBAEa,CACf,EAAoB,KAAK,QAAQ,KAAK,EAGlC,CAAC,EAAW,EAAmB,EAAI,CAAC,EAAU,EAAmB,CAAC,aAAa,IACjF,EAAO,MAAM,EAAO,IAAI,2BAA2B,EAAmB,GAAG,CAAC,CAC1E,KAAK,QAAQ,KAAK,EAAE,EAItB,IAAM,EAAoB,EAAW,IAAK,GAAM,EAAE,MAAM,IAAI,CAAC,GAAG,CAG1D,EAAiB,EAAU,EAAmB,CAAC,IAAK,GAAc,CAEtE,GAAM,CAAE,aAAc,EAAY,EAAE,EAAK,EAAkB,EAAK,EAAoB,EAAU,CAAC,CAGzF,CAAE,kBAAiB,qBAAsB,EAC7C,EACA,CACE,gCACA,iBACD,CACF,CAED,MAAO,CACL,kBACA,oBACA,iBAAkB,EAAU,MAAM,IAAI,CAAC,GACxC,EACD,CAGI,EAAiD,EAAE,CACzD,EAAe,SAAS,CAAE,kBAAiB,oBAAmB,sBAAuB,CAC9D,CAAC,GAAG,EAAiB,GAAG,EAAkB,CAClD,QAAS,GAAa,CACjC,IAAM,EAAU,EAAS,eAAiB,EAAS,gBAE9C,EAAkB,KACrB,EAAkB,GAAW,EAAE,EAEjC,EAAkB,GAAU,KAAK,EAAiB,CAClD,EAAkB,GAAW,CAAC,GAAG,IAAI,IAAI,EAAkB,GAAS,CAAC,EACrE,EACF,CAGF,IAAM,EAAqB,CACzB,GAAG,IAAI,IACL,EACG,KAAK,CAAE,qBACN,EAAgB,IAAK,GAAS,EAAK,eAAiB,EAAK,gBAAgB,CAC1E,CACA,MAAM,CACV,CACF,CAGK,EAAuB,EAC3B,CACE,GAAG,IAAI,IACL,EACG,KAAK,CAAE,uBACN,EAAkB,IAAK,GAAS,EAAK,eAAiB,EAAK,gBAAgB,CAC5E,CACA,MAAM,CACV,CACF,CACD,EACD,CAGK,EAAsD,EAAE,CAC9D,EAAe,SAAS,CAAE,kBAAiB,uBAAwB,CAC5C,CAAC,GAAG,EAAiB,GAAG,EAAkB,CAClD,QAAS,GAAa,CACjC,IAAM,EAAU,EAAS,eAAiB,EAAS,gBAC7C,EAAgB,EAAS,YAAY,KAAM,GAAS,EAAK,MAAQ,kBAAkB,CAEpF,EAAuB,KAC1B,EAAuB,GAAW,EAAE,EAEtC,EAAuB,GAAU,KAAK,GAAI,GAAe,QAAU,EAAE,CAAE,CACvE,EAAuB,GAAW,CAAC,GAAG,IAAI,IAAI,EAAuB,GAAS,CAAC,EAC/E,EACF,CAIF,GAAM,CAAE,iBAAgB,iCAAkC,MAAM,EADjD,EAA4B,EAAc,EAAK,CACgC,CAC5F,SACD,CAAC,CAGI,EAAY,CAAC,GAAG,EAAoB,GAAG,EAAqB,CAAC,IAAK,IAAa,CACnF,MAAO,EAAe,GACtB,GAAI,EAA8B,GAC9B,CAAE,gBAAiB,EAAS,CAC5B,CAAE,gBAAiB,gBAAiB,aAAc,EAAS,CAC/D,WAAY,CACV,CACE,IAAK,YACL,OAAQ,CAAC,UAAU,CACpB,CACD,CACE,IAAK,iBACL,OAAQ,EAAW,EAAkB,IAAY,EAAE,CAAE,EAAkB,CACxE,CACD,CACE,IAAK,kBACL,OAAQ,EAAuB,IAAY,EAAE,CAC9C,CACF,CACF,EAAE,CAGH,EAAO,IAAI,mBAAmB,EAAU,SAAS,CACjD,EAAO,IAAI,qBAAqB,EAAmB,SAAS,CAC5D,EAAO,IAAI,uBAAuB,EAAqB,SAAS,CAGhE,EAAmB,EAAQ,CACzB,aAAc,EACf,CAAC"}
@@ -0,0 +1,4 @@
1
+ import{t as e}from"./constants-XOsAW1__.mjs";import{t}from"./logger-Bj782ZYD.mjs";import{t as n}from"./done-input-validation-C5rgR0Wr.mjs";import{n as r}from"./constants-mjLYTIJm.mjs";import i from"colors";import{buildTranscendGraphQLClient as a,fetchActiveSiloDiscoPlugin as o,uploadSiloDiscoveryResults as s}from"@transcend-io/sdk";import c from"fast-glob";import{stringify as l}from"query-string";async function u({scanPath:e,fileGlobs:n,ignoreDirs:r,config:i}){let{ignoreDirs:a,supportedFiles:o,scanFunction:s}=i,l=n===``?o:o.concat(n.split(`,`)),d=[...r.split(`,`),...a].filter(e=>e.length>0);try{let n=await c(`${e}/**/${l.join(`|`)}`,{ignore:d.map(t=>`${e}/**/${t}`),unique:!0,onlyFiles:!0});t.info(`Scanning: ${n.length} files`);let r=n.map(e=>s(e)).flat().map(e=>e.softwareDevelopmentKits||[]).flat(),i=[...new Set(r.map(e=>e.name))];return t.info(`Found: ${i.length} unique dependencies`),i.map(t=>({name:t,resourceId:`${e}/**/${t}`,useStrictClassifier:!0}))}catch(e){throw Error(`Error scanning globs ${u} with error: ${e}`)}}async function d({scanPath:c,dataSiloId:d,auth:f,fileGlobs:p,ignoreDirs:m,transcendUrl:h}){n(this.process.exit);let g=a(h,f),_=await o(g,d,{logger:t}),v=r[_.dataSilo.type];v||(t.error(i.red(`This plugin "${_.dataSilo.type}" is not supported for offline silo discovery.`)),this.process.exit(1));let y=await u({scanPath:c,fileGlobs:p,ignoreDirs:m,config:v});await s(g,_.id,y,{logger:t});let b=new URL(e);b.pathname=`/data-map/data-inventory/silo-discovery/triage`,b.search=l({filters:JSON.stringify({pluginIds:[_.id]})}),t.info(i.green(`Scan found ${y.length} potential data silos at ${c}! View at '${b.href}'
2
+
3
+ NOTE: it may take 2-3 minutes for scan results to appear in the UI.`))}export{d as discoverSilos};
4
+ //# sourceMappingURL=impl-B6TXE2oE.mjs.map