@transcend-io/cli 7.0.0 → 8.0.0-alpha.1

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 (271) hide show
  1. package/dist/bin/bash-complete.js +4 -0
  2. package/dist/bin/bash-complete.js.map +1 -0
  3. package/dist/bin/cli.js +3 -0
  4. package/dist/bin/cli.js.map +1 -0
  5. package/dist/bin/deprecated-command.js +7 -0
  6. package/dist/bin/deprecated-command.js.map +1 -0
  7. package/dist/chunk-26T4RUOI.js +12 -0
  8. package/dist/chunk-26T4RUOI.js.map +1 -0
  9. package/dist/chunk-2LCGZ77N.js +2 -0
  10. package/dist/chunk-2LCGZ77N.js.map +1 -0
  11. package/dist/chunk-2V6ABZRI.js +2 -0
  12. package/dist/chunk-2V6ABZRI.js.map +1 -0
  13. package/dist/chunk-347UQP43.js +2 -0
  14. package/dist/chunk-347UQP43.js.map +1 -0
  15. package/dist/chunk-43JWXG77.js +2 -0
  16. package/dist/chunk-43JWXG77.js.map +1 -0
  17. package/dist/chunk-4GLITB3Y.js +2 -0
  18. package/dist/chunk-4GLITB3Y.js.map +1 -0
  19. package/dist/chunk-65I2PF73.js +2 -0
  20. package/dist/chunk-65I2PF73.js.map +1 -0
  21. package/dist/chunk-72U6ETHG.js +2 -0
  22. package/dist/chunk-72U6ETHG.js.map +1 -0
  23. package/dist/chunk-ARVEJERC.js +2 -0
  24. package/dist/chunk-ARVEJERC.js.map +1 -0
  25. package/dist/chunk-CBAHSBSW.js +2 -0
  26. package/dist/{chunk-UBUNHRCG.cjs.map → chunk-CBAHSBSW.js.map} +1 -1
  27. package/dist/chunk-EZHASXA5.js +2 -0
  28. package/dist/chunk-EZHASXA5.js.map +1 -0
  29. package/dist/chunk-FHZRITAV.js +2 -0
  30. package/dist/chunk-FHZRITAV.js.map +1 -0
  31. package/dist/chunk-HJULYIHF.js +3 -0
  32. package/dist/chunk-HJULYIHF.js.map +1 -0
  33. package/dist/chunk-HOZXN2EM.js +94 -0
  34. package/dist/chunk-HOZXN2EM.js.map +1 -0
  35. package/dist/chunk-L5ULN3IT.js +2 -0
  36. package/dist/chunk-L5ULN3IT.js.map +1 -0
  37. package/dist/chunk-L7ZIX4SU.js +2 -0
  38. package/dist/chunk-L7ZIX4SU.js.map +1 -0
  39. package/dist/chunk-LAYHULHH.js +2 -0
  40. package/dist/chunk-LAYHULHH.js.map +1 -0
  41. package/dist/chunk-MA4JWWRO.js +6 -0
  42. package/dist/chunk-MA4JWWRO.js.map +1 -0
  43. package/dist/chunk-MK5T6DBK.js +2831 -0
  44. package/dist/chunk-MK5T6DBK.js.map +1 -0
  45. package/dist/chunk-N6JZHL5U.js +2 -0
  46. package/dist/chunk-N6JZHL5U.js.map +1 -0
  47. package/dist/chunk-NZZKRVAI.js +4 -0
  48. package/dist/chunk-NZZKRVAI.js.map +1 -0
  49. package/dist/chunk-OEB7WG3G.js +4 -0
  50. package/dist/chunk-OEB7WG3G.js.map +1 -0
  51. package/dist/chunk-SRLEEKKQ.js +9 -0
  52. package/dist/chunk-SRLEEKKQ.js.map +1 -0
  53. package/dist/chunk-WO5MQBXP.js +75 -0
  54. package/dist/chunk-WO5MQBXP.js.map +1 -0
  55. package/dist/impl-24IS3GIF.js +2 -0
  56. package/dist/impl-24IS3GIF.js.map +1 -0
  57. package/dist/impl-3YESYKVQ.js +2 -0
  58. package/dist/impl-3YESYKVQ.js.map +1 -0
  59. package/dist/impl-6MGNPY7O.js +2 -0
  60. package/dist/impl-6MGNPY7O.js.map +1 -0
  61. package/dist/impl-6SYXV3YI.js +2 -0
  62. package/dist/impl-6SYXV3YI.js.map +1 -0
  63. package/dist/impl-BVOF3W2V.js +4 -0
  64. package/dist/impl-BVOF3W2V.js.map +1 -0
  65. package/dist/impl-D4AEXEMN.js +12 -0
  66. package/dist/impl-D4AEXEMN.js.map +1 -0
  67. package/dist/impl-EAY4M3OY.js +2 -0
  68. package/dist/impl-EAY4M3OY.js.map +1 -0
  69. package/dist/impl-F4IQEKTF.js +9 -0
  70. package/dist/impl-F4IQEKTF.js.map +1 -0
  71. package/dist/impl-G4JGSVWD.js +2 -0
  72. package/dist/impl-G4JGSVWD.js.map +1 -0
  73. package/dist/impl-HFXHM3PH.js +2 -0
  74. package/dist/impl-HFXHM3PH.js.map +1 -0
  75. package/dist/impl-HMHOYOZZ.js +2 -0
  76. package/dist/impl-HMHOYOZZ.js.map +1 -0
  77. package/dist/impl-IU4EANSX.js +7 -0
  78. package/dist/impl-IU4EANSX.js.map +1 -0
  79. package/dist/impl-IWDHKBWZ.js +2 -0
  80. package/dist/impl-IWDHKBWZ.js.map +1 -0
  81. package/dist/impl-JFD2JMP6.js +2 -0
  82. package/dist/impl-JFD2JMP6.js.map +1 -0
  83. package/dist/impl-JH4VBMNT.js +2 -0
  84. package/dist/impl-JH4VBMNT.js.map +1 -0
  85. package/dist/impl-LSP4V37Z.js +6 -0
  86. package/dist/impl-LSP4V37Z.js.map +1 -0
  87. package/dist/impl-MIJFNSLS.js +2 -0
  88. package/dist/impl-MIJFNSLS.js.map +1 -0
  89. package/dist/impl-NL32KFH4.js +2 -0
  90. package/dist/impl-NL32KFH4.js.map +1 -0
  91. package/dist/impl-NLCPSIYZ.js +2 -0
  92. package/dist/impl-NLCPSIYZ.js.map +1 -0
  93. package/dist/impl-NXRQU2U5.js +6 -0
  94. package/dist/impl-NXRQU2U5.js.map +1 -0
  95. package/dist/impl-QEOVZIM5.js +2 -0
  96. package/dist/impl-QEOVZIM5.js.map +1 -0
  97. package/dist/impl-QRK4B3FD.js +2 -0
  98. package/dist/impl-QRK4B3FD.js.map +1 -0
  99. package/dist/impl-QZBKOJBQ.js +2 -0
  100. package/dist/impl-QZBKOJBQ.js.map +1 -0
  101. package/dist/impl-RFRQUKQY.js +2 -0
  102. package/dist/impl-RFRQUKQY.js.map +1 -0
  103. package/dist/impl-RIVVHWBR.js +2 -0
  104. package/dist/impl-RIVVHWBR.js.map +1 -0
  105. package/dist/impl-SJHU5PR7.js +2 -0
  106. package/dist/impl-SJHU5PR7.js.map +1 -0
  107. package/dist/impl-SYC5TORT.js +2 -0
  108. package/dist/impl-SYC5TORT.js.map +1 -0
  109. package/dist/impl-TP4QITXR.js +2 -0
  110. package/dist/impl-TP4QITXR.js.map +1 -0
  111. package/dist/impl-UOB7PV4W.js +2 -0
  112. package/dist/impl-UOB7PV4W.js.map +1 -0
  113. package/dist/impl-UUQ2BEZR.js +2 -0
  114. package/dist/impl-UUQ2BEZR.js.map +1 -0
  115. package/dist/impl-WH2I2JB7.js +2 -0
  116. package/dist/impl-WH2I2JB7.js.map +1 -0
  117. package/dist/impl-X6N6NFUV.js +6 -0
  118. package/dist/impl-X6N6NFUV.js.map +1 -0
  119. package/dist/impl-XF3OTAQZ.js +2 -0
  120. package/dist/impl-XF3OTAQZ.js.map +1 -0
  121. package/dist/impl-XH3KTZRN.js +2 -0
  122. package/dist/{impl-EJT3AX73.cjs.map → impl-XH3KTZRN.js.map} +1 -1
  123. package/dist/impl-XQBTTRCU.js +2 -0
  124. package/dist/impl-XQBTTRCU.js.map +1 -0
  125. package/dist/impl-YA2HU57Y.js +2 -0
  126. package/dist/impl-YA2HU57Y.js.map +1 -0
  127. package/dist/impl-YEGS4G24.js +2 -0
  128. package/dist/impl-YEGS4G24.js.map +1 -0
  129. package/dist/impl-YNBHGQJK.js +2 -0
  130. package/dist/impl-YNBHGQJK.js.map +1 -0
  131. package/dist/impl-ZJL2YE7A.js +2 -0
  132. package/dist/impl-ZJL2YE7A.js.map +1 -0
  133. package/dist/{index.d.cts → index.d.ts} +1 -1
  134. package/dist/index.js +5 -0
  135. package/dist/index.js.map +1 -0
  136. package/package.json +45 -48
  137. package/dist/bin/bash-complete.cjs +0 -4
  138. package/dist/bin/bash-complete.cjs.map +0 -1
  139. package/dist/bin/cli.cjs +0 -3
  140. package/dist/bin/cli.cjs.map +0 -1
  141. package/dist/bin/deprecated-command.cjs +0 -7
  142. package/dist/bin/deprecated-command.cjs.map +0 -1
  143. package/dist/chunk-ANCIGXE5.cjs +0 -4
  144. package/dist/chunk-ANCIGXE5.cjs.map +0 -1
  145. package/dist/chunk-AW6I4V4F.cjs +0 -3
  146. package/dist/chunk-AW6I4V4F.cjs.map +0 -1
  147. package/dist/chunk-BY7W4UQF.cjs +0 -2
  148. package/dist/chunk-BY7W4UQF.cjs.map +0 -1
  149. package/dist/chunk-CHTWXNEA.cjs +0 -2
  150. package/dist/chunk-CHTWXNEA.cjs.map +0 -1
  151. package/dist/chunk-DS6VH676.cjs +0 -2
  152. package/dist/chunk-DS6VH676.cjs.map +0 -1
  153. package/dist/chunk-EG4L6YAJ.cjs +0 -2
  154. package/dist/chunk-EG4L6YAJ.cjs.map +0 -1
  155. package/dist/chunk-ETNRSKUM.cjs +0 -2
  156. package/dist/chunk-ETNRSKUM.cjs.map +0 -1
  157. package/dist/chunk-GM2EDRKN.cjs +0 -12
  158. package/dist/chunk-GM2EDRKN.cjs.map +0 -1
  159. package/dist/chunk-IBTP5OXE.cjs +0 -2
  160. package/dist/chunk-IBTP5OXE.cjs.map +0 -1
  161. package/dist/chunk-KOV2SQO2.cjs +0 -4
  162. package/dist/chunk-KOV2SQO2.cjs.map +0 -1
  163. package/dist/chunk-LBDIZJ23.cjs +0 -2844
  164. package/dist/chunk-LBDIZJ23.cjs.map +0 -1
  165. package/dist/chunk-LZYEIVWM.cjs +0 -94
  166. package/dist/chunk-LZYEIVWM.cjs.map +0 -1
  167. package/dist/chunk-MPJABCSW.cjs +0 -75
  168. package/dist/chunk-MPJABCSW.cjs.map +0 -1
  169. package/dist/chunk-R5N2S5UU.cjs +0 -2
  170. package/dist/chunk-R5N2S5UU.cjs.map +0 -1
  171. package/dist/chunk-RW5GSSAA.cjs +0 -2
  172. package/dist/chunk-RW5GSSAA.cjs.map +0 -1
  173. package/dist/chunk-RZWMOCW3.cjs +0 -2
  174. package/dist/chunk-RZWMOCW3.cjs.map +0 -1
  175. package/dist/chunk-SAEKBZGF.cjs +0 -2
  176. package/dist/chunk-SAEKBZGF.cjs.map +0 -1
  177. package/dist/chunk-T462ONFX.cjs +0 -2
  178. package/dist/chunk-T462ONFX.cjs.map +0 -1
  179. package/dist/chunk-TD7ADMVO.cjs +0 -2
  180. package/dist/chunk-TD7ADMVO.cjs.map +0 -1
  181. package/dist/chunk-UBUNHRCG.cjs +0 -2
  182. package/dist/chunk-UEGX6GZ2.cjs +0 -2
  183. package/dist/chunk-UEGX6GZ2.cjs.map +0 -1
  184. package/dist/chunk-VCWGXJ2H.cjs +0 -9
  185. package/dist/chunk-VCWGXJ2H.cjs.map +0 -1
  186. package/dist/chunk-ZUNVPK23.cjs +0 -2
  187. package/dist/chunk-ZUNVPK23.cjs.map +0 -1
  188. package/dist/chunk-ZVK4HIDF.cjs +0 -6
  189. package/dist/chunk-ZVK4HIDF.cjs.map +0 -1
  190. package/dist/impl-2GU6CYMY.cjs +0 -2
  191. package/dist/impl-2GU6CYMY.cjs.map +0 -1
  192. package/dist/impl-2OEHQTIR.cjs +0 -2
  193. package/dist/impl-2OEHQTIR.cjs.map +0 -1
  194. package/dist/impl-2QXJ3WST.cjs +0 -9
  195. package/dist/impl-2QXJ3WST.cjs.map +0 -1
  196. package/dist/impl-442H4ODN.cjs +0 -7
  197. package/dist/impl-442H4ODN.cjs.map +0 -1
  198. package/dist/impl-44QRPPUX.cjs +0 -6
  199. package/dist/impl-44QRPPUX.cjs.map +0 -1
  200. package/dist/impl-4DOGSDPC.cjs +0 -2
  201. package/dist/impl-4DOGSDPC.cjs.map +0 -1
  202. package/dist/impl-5J3MG42D.cjs +0 -2
  203. package/dist/impl-5J3MG42D.cjs.map +0 -1
  204. package/dist/impl-5YMSNFJU.cjs +0 -2
  205. package/dist/impl-5YMSNFJU.cjs.map +0 -1
  206. package/dist/impl-6TBKGA4Y.cjs +0 -2
  207. package/dist/impl-6TBKGA4Y.cjs.map +0 -1
  208. package/dist/impl-7VYQSZVO.cjs +0 -2
  209. package/dist/impl-7VYQSZVO.cjs.map +0 -1
  210. package/dist/impl-BB24LU3N.cjs +0 -2
  211. package/dist/impl-BB24LU3N.cjs.map +0 -1
  212. package/dist/impl-CWZ26FTN.cjs +0 -2
  213. package/dist/impl-CWZ26FTN.cjs.map +0 -1
  214. package/dist/impl-EFTKRWUA.cjs +0 -2
  215. package/dist/impl-EFTKRWUA.cjs.map +0 -1
  216. package/dist/impl-EJT3AX73.cjs +0 -2
  217. package/dist/impl-EKQ6ZNN3.cjs +0 -2
  218. package/dist/impl-EKQ6ZNN3.cjs.map +0 -1
  219. package/dist/impl-EV6T5UOK.cjs +0 -6
  220. package/dist/impl-EV6T5UOK.cjs.map +0 -1
  221. package/dist/impl-FPFUAY4Q.cjs +0 -2
  222. package/dist/impl-FPFUAY4Q.cjs.map +0 -1
  223. package/dist/impl-GDKUHX2J.cjs +0 -2
  224. package/dist/impl-GDKUHX2J.cjs.map +0 -1
  225. package/dist/impl-GXDABG5X.cjs +0 -2
  226. package/dist/impl-GXDABG5X.cjs.map +0 -1
  227. package/dist/impl-IG7QEF6D.cjs +0 -2
  228. package/dist/impl-IG7QEF6D.cjs.map +0 -1
  229. package/dist/impl-JQLYJA5L.cjs +0 -2
  230. package/dist/impl-JQLYJA5L.cjs.map +0 -1
  231. package/dist/impl-LPI3M7L3.cjs +0 -6
  232. package/dist/impl-LPI3M7L3.cjs.map +0 -1
  233. package/dist/impl-M7WMSIK4.cjs +0 -4
  234. package/dist/impl-M7WMSIK4.cjs.map +0 -1
  235. package/dist/impl-MRGZ5OLO.cjs +0 -2
  236. package/dist/impl-MRGZ5OLO.cjs.map +0 -1
  237. package/dist/impl-OI4UWRAU.cjs +0 -12
  238. package/dist/impl-OI4UWRAU.cjs.map +0 -1
  239. package/dist/impl-OX24YDRR.cjs +0 -2
  240. package/dist/impl-OX24YDRR.cjs.map +0 -1
  241. package/dist/impl-PFQKPCUL.cjs +0 -2
  242. package/dist/impl-PFQKPCUL.cjs.map +0 -1
  243. package/dist/impl-PXJZK6BV.cjs +0 -2
  244. package/dist/impl-PXJZK6BV.cjs.map +0 -1
  245. package/dist/impl-QOGUUIE6.cjs +0 -2
  246. package/dist/impl-QOGUUIE6.cjs.map +0 -1
  247. package/dist/impl-QR3LLBZL.cjs +0 -2
  248. package/dist/impl-QR3LLBZL.cjs.map +0 -1
  249. package/dist/impl-RODUB22E.cjs +0 -2
  250. package/dist/impl-RODUB22E.cjs.map +0 -1
  251. package/dist/impl-S56PHXGG.cjs +0 -2
  252. package/dist/impl-S56PHXGG.cjs.map +0 -1
  253. package/dist/impl-SDGCTSWN.cjs +0 -2
  254. package/dist/impl-SDGCTSWN.cjs.map +0 -1
  255. package/dist/impl-VEMQEG27.cjs +0 -2
  256. package/dist/impl-VEMQEG27.cjs.map +0 -1
  257. package/dist/impl-VFWBSWT5.cjs +0 -2
  258. package/dist/impl-VFWBSWT5.cjs.map +0 -1
  259. package/dist/impl-XRRNIJUK.cjs +0 -2
  260. package/dist/impl-XRRNIJUK.cjs.map +0 -1
  261. package/dist/impl-YA7HWMYB.cjs +0 -2
  262. package/dist/impl-YA7HWMYB.cjs.map +0 -1
  263. package/dist/impl-YOWRUVYG.cjs +0 -2
  264. package/dist/impl-YOWRUVYG.cjs.map +0 -1
  265. package/dist/impl-ZHZOMOST.cjs +0 -2
  266. package/dist/impl-ZHZOMOST.cjs.map +0 -1
  267. package/dist/index.cjs +0 -5
  268. package/dist/index.cjs.map +0 -1
  269. /package/dist/bin/{bash-complete.d.cts → bash-complete.d.ts} +0 -0
  270. /package/dist/bin/{cli.d.cts → cli.d.ts} +0 -0
  271. /package/dist/bin/{deprecated-command.d.cts → deprecated-command.d.ts} +0 -0
@@ -0,0 +1,2 @@
1
+ import{$ as Ve,Ae as ye,Be as qe,Ca as Qe,Ce as Ye,De as We,Y as de,Z as ke,_ as oe,_b as P,a as je,b,dd as ge,ea as Me,pe as w,q as Fe,qe as W,se as Ge,ue as Ke,wa as Be,we as ze,xa as Ue,y as _e,ye as E}from"./chunk-MK5T6DBK.js";import{a as u}from"./chunk-43JWXG77.js";import{e as C}from"./chunk-L5ULN3IT.js";import{applyEnum as Jt,valuesOf as le}from"@transcend-io/type-utils";import{LanguageKey as Zt}from"@transcend-io/internationalization";import{CompletedRequestStatus as Ht,RequestAction as Xt,IsoCountryCode as er,IsoCountrySubdivisionCode as tr}from"@transcend-io/privacy-types";import*as R from"io-ts";var A="[NONE]",ce="[APPLY VALUE TO ALL ROWS]",Ce="<blank>",Re=["email","coreIdentifier"],ie=(c=>(c.Email="email",c.CoreIdentifier="coreIdentifier",c.RequestType="requestType",c.SubjectType="subjectType",c.Locale="locale",c.Country="country",c.CountrySubDivision="countrySubDivision",c.RequestStatus="requestStatus",c.CreatedAt="createdAt",c.DataSiloIds="dataSiloIds",c))(ie||{}),Je={email:!1,coreIdentifier:!0,requestType:!0,subjectType:!0,requestStatus:!1,createdAt:!1,dataSiloIds:!1,locale:!1,country:!1,countrySubDivision:!1},Ze={requestType:!0,subjectType:!0},He=R.type({columnNames:R.partial(Jt(ie,()=>R.string)),identifierNames:R.record(R.string,R.string),attributeNames:R.record(R.string,R.string),requestTypeToRequestAction:R.record(R.string,le(Xt)),subjectTypeToSubjectName:R.record(R.string,R.string),languageToLocale:R.record(R.string,le(Zt)),regionToCountry:R.record(R.string,le({...er,[A]:A})),regionToCountrySubDivision:R.record(R.string,le({...tr,[A]:A})),statusToRequestStatus:R.record(R.string,le({...Ht,[A]:A}))}),he=R.type({id:R.string,link:R.string,rowIndex:R.number,coreIdentifier:R.string,attemptedAt:R.string}),Xe=R.type({failingRequests:R.array(R.record(R.string,R.any)),successfulRequests:R.array(he),duplicateRequests:R.array(R.type({rowIndex:R.number,coreIdentifier:R.string,attemptedAt:R.string}))});import rr from"inquirer";import et from"fuzzysearch";function Se(n,e){return et(n.toLowerCase(),e.toLowerCase())||et(e.toLowerCase(),n.toLowerCase())}function ne(n,e,s,l){let a=n.filter(o=>Se(e.toLowerCase(),o.toLowerCase()));return[...a,new rr.Separator,...s?[]:[A],...l?[ce]:[],...n.filter(o=>!a.includes(o))]}import tt from"inquirer";import sr from"inquirer-autocomplete-prompt";import{apply as or}from"@transcend-io/type-utils";async function ee(n,e,s){tt.registerPrompt("autocomplete",sr);let l=n.map(o=>o||"<blank>").filter(o=>!s[o]);if(l.length===0)return s;let a=await tt.prompt(l.map(o=>({name:o,message:`Map value of: ${o}`,type:"autocomplete",default:e.find(i=>Se(o,i)),source:(i,r)=>r?e.filter(t=>typeof t=="string"&&Se(r,t)):e})));return{...s,...or(a,o=>typeof o=="string"?o:Object.values(o)[0])}}function Ie(n){return n.split(",").map(e=>e.trim()).filter(e=>e)}import rt from"colors";import*as te from"io-ts";var st=te.type({key:te.string,values:te.array(te.string)});function ot(n){let e=n.map(s=>{let[l,a]=s.trim().split(":");if(!a)throw new Error("Expected attributes in key:value1;value2,key2:value3;value4");let o=a.split(";");return{key:l,values:o}});return u.info(rt.magenta("Attributes to apply to all requests:")),u.info(rt.magenta(JSON.stringify(e,null,2))),e}import{parse as ir}from"csv-parse/sync";import{readFileSync as nr}from"fs";import*as it from"io-ts";import{decodeCodec as ar}from"@transcend-io/type-utils";function nt(n,e,s={columns:!0}){let l=ir(nr(n,"utf-8"),s);return ar(it.array(e),l).map(i=>Object.entries(i).reduce((r,[t,y])=>Object.assign(r,{[t.replace(/[^a-z_.+\-A-Z -~]/g,"")]:y}),{}))}import{uniq as ur}from"lodash-es";function G(n,e){return ur(n.map(s=>s[e]||"").flat())}import at from"inquirer";import lr from"colors";import{uniq as cr}from"lodash-es";async function ut(n){let e=cr(n.map(a=>Object.keys(a)).flat()),s=n,l=!0;for(;l;){let{filterColumnName:a}=await at.prompt([{name:"filterColumnName",message:`If you need to filter the list of requests to import, choose the column to filter on. Currently ${s.length} rows.`,type:"list",default:e,choices:[A,...e]}]);if(l=A!==a,l){let o=G(s,a),{valuesToKeep:i}=await at.prompt([{name:"valuesToKeep",message:"Keep rows matching this value",type:"checkbox",default:e,choices:o}]);s=s.filter(r=>i.includes(r[a]))}}return u.info(lr.magenta(`Importing ${s.length} requests`)),s}import lt from"colors";import{RequestStatus as J}from"@transcend-io/privacy-types";import ct from"cli-progress";async function Ys({requestActions:n,auth:e,requestIds:s,statuses:l=[J.Compiling,J.RequestMade,J.Delayed,J.Approving,J.Secondary,J.Enriching,J.Waiting,J.SecondaryApproving],createdAtAfter:a,createdAtBefore:o,concurrency:i=100,transcendUrl:r=C}){let t=w(r,e),y=new Date().getTime(),c=new ct.SingleBar({},ct.Presets.shades_classic),g=await E(t,{actions:n,statuses:l,createdAtBefore:o,createdAtAfter:a,isSilent:!1,requestIds:s});u.info(lt.magenta(`Marking "${g.length}" as silent mode.`));let m=0;c.start(g.length,0),await b(g,async f=>{await P(t,oe,{input:{id:f.id,isSilent:!0}}),m+=1,c.update(m)},{concurrency:i}),c.stop();let p=new Date().getTime()-y;return u.info(lt.green(`Successfully marked ${m} requests as silent mode in "${p/1e3}" seconds!`)),g.length}import{getValues as mr,getEntries as pr}from"@transcend-io/type-utils";import fr from"inquirer";import{startCase as dr}from"lodash-es";async function mt(n,e){let s=mr(ie).filter(a=>!e.getValue("columnNames",a)),l=s.length===0?{}:await fr.prompt(s.map(a=>{let o=dr(a.replace("ColumnName","")),i=ne(n,o,Je[a],!!Ze[a]);return{name:a,message:`Choose the column that will be used to map in the field: ${o}`,type:"list",default:i[0],choices:i}}));return await Promise.all(pr(l).map(([a,o])=>e.setValue(o,"columnNames",a))),l}import re from"colors";import{CompletedRequestStatus as gr,RequestAction as yr,IsoCountryCode as qr,IsoCountrySubdivisionCode as Rr}from"@transcend-io/privacy-types";import{LanguageKey as hr}from"@transcend-io/internationalization";async function pt(n,e,{state:s,columnNameMap:l}){let a=f=>s.getValue("columnNames",f)||l[f],{internalSubjects:o}=await P(n,_e);u.info(re.magenta("Determining mapping of columns for request action"));let i=await ee(G(e,a("requestType")),Object.values(yr),s.getValue("requestTypeToRequestAction"));await s.setValue(i,"requestTypeToRequestAction"),u.info(re.magenta("Determining mapping of columns for subject"));let r=await ee(G(e,a("subjectType")),o.map(({type:f})=>f),s.getValue("subjectTypeToSubjectName"));await s.setValue(r,"subjectTypeToSubjectName"),u.info(re.magenta("Determining mapping of columns for locale"));let t=await ee(G(e,a("locale")),Object.values(hr),s.getValue("languageToLocale"));await s.setValue(t,"languageToLocale"),u.info(re.magenta("Determining mapping of columns for request status")),u.info(re.magenta("Determining mapping of columns for request status"));let y=a("requestStatus"),c=y===A?{}:await ee(G(e,y),[...Object.values(gr),A],s.getValue("statusToRequestStatus"));await s.setValue(c,"statusToRequestStatus"),u.info(re.magenta("Determining mapping of columns for country"));let g=a("country"),m=g===A?{}:await ee(G(e,g),[...Object.values(qr),A],s.getValue("regionToCountry"));await s.setValue(m,"regionToCountry"),u.info(re.magenta("Determining mapping of columns for country sub division"));let d=a("countrySubDivision"),p=d===A?{}:await ee(G(e,d),[...Object.values(Rr),A],s.getValue("regionToCountrySubDivision"));await s.setValue(p,"regionToCountrySubDivision")}import{LanguageKey as Sr}from"@transcend-io/internationalization";import{DateFromISOString as br}from"io-ts-types";import*as D from"io-ts";import{NORMALIZE_PHONE_NUMBER as Tr,CompletedRequestStatus as Ar,RequestAction as wr,IdentifierType as be,IsoCountryCode as Cr,IsoCountrySubdivisionCode as Ir}from"@transcend-io/privacy-types";import{valuesOf as me}from"@transcend-io/type-utils";var Pr=D.record(D.string,D.array(D.intersection([D.type({value:D.string}),D.partial({name:D.string})]))),wo=D.intersection([D.type({email:D.string,attestedExtraIdentifiers:Pr,coreIdentifier:D.string,requestType:me(wr),subjectType:D.string}),D.partial({country:me(Cr),countrySubDivision:me(Ir),attributes:D.array(st),status:me(Ar),createdAt:br,dataSiloIds:D.array(D.string),locale:me(Sr)})]);function Dr(n,e,s){if(e===be.Email)return n.toLowerCase();if(e===be.Phone){let l=n.replace(Tr,"").replace(/[()]/g,"").replace(/[–]/g,"").replace(/[:]/g,"").replace(/[‭‬]/g,"").replace(/[A-Za-z]/g,"");return l?l.startsWith("+")?l:`+${s}${l}`:""}return n}function ft(n,e,{columnNameMap:s,identifierNameMap:l,attributeNameMap:a,requestAttributeKeys:o,defaultPhoneCountryCode:i="1"}){let r=t=>e.getValue("columnNames",t)||s[t];return n.map(t=>{let y={};Object.entries(l).filter(([,d])=>d!==A).forEach(([d,p])=>{let f=Object.values(be).includes(d)?d:be.Custom,h=t[p];if(h){let S=Dr(h,f,i);S&&(y[f]||(y[f]=[]),y[f].push({value:S,name:d}))}});let c=[];Object.entries(a).filter(([,d])=>d!==A).forEach(([d,p])=>{let f=t[p];if(f){let h=o.find(S=>S.name===d)?.type==="MULTI_SELECT";c.push({values:h?Ie(f):f,key:d})}});let g=r("requestType"),m=r("subjectType");return[t,{email:t[r("email")],attestedExtraIdentifiers:y,attributes:c,coreIdentifier:t[r("coreIdentifier")],requestType:g===ce?e.getValue("requestTypeToRequestAction",Ce):e.getValue("requestTypeToRequestAction",t[g]),subjectType:m===ce?e.getValue("subjectTypeToSubjectName",Ce):e.getValue("subjectTypeToSubjectName",t[m]),...r("locale")!==A&&t[r("locale")]?{locale:e.getValue("languageToLocale",t[r("locale")])}:{},...r("country")!==A&&t[r("country")]?{country:e.getValue("regionToCountry",t[r("country")])}:{},...r("countrySubDivision")!==A&&t[r("countrySubDivision")]?{countrySubDivision:e.getValue("regionToCountrySubDivision",t[r("countrySubDivision")])}:{},...r("requestStatus")!==A&&e.getValue("statusToRequestStatus",t[r("requestStatus")])!==A&&t[r("requestStatus")]?{status:e.getValue("statusToRequestStatus",t[r("requestStatus")])}:{},...r("createdAt")!==A&&t[r("createdAt")]?{createdAt:new Date(t[r("createdAt")])}:{},...r("dataSiloIds")!==A&&t[r("dataSiloIds")]?{dataSiloIds:Ie(t[r("dataSiloIds")])}:{}}]})}import dt from"colors";import gt from"cli-progress";import*as q from"io-ts";import{decodeCodec as Er,valuesOf as vr}from"@transcend-io/type-utils";import{TableEncryptionType as Nr}from"@transcend-io/privacy-types";var yt=q.type({defaultMessage:q.string,id:q.string}),xr=q.type({downloadKey:q.string,error:q.union([q.null,q.string]),mimetype:q.string,size:q.string,fileName:q.string,dataPoint:q.type({id:q.string,title:q.union([yt,q.null]),description:q.union([yt,q.null]),name:q.string,slug:q.string,encryption:q.union([vr(Nr),q.null]),dataSilo:q.type({id:q.string,title:q.string,description:q.string,type:q.string,outerType:q.union([q.string,q.null])}),path:q.array(q.string)})}),Lr=q.type({nodes:q.array(xr),totalCount:q.number,_links:q.partial({next:q.union([q.string,q.null]),previous:q.union([q.string,q.null])})});async function qt(n,{sombra:e,concurrency:s=5,limit:l=100}){u.info(dt.magenta(`Pulling file metadata for ${n.length} requests`));let a=new Date().getTime(),o=new gt.SingleBar({},gt.Presets.shades_classic),i=0;o.start(n.length,0);let r=await b(n,async c=>{let g=[],m=!0,d=0;for(;m;){let p;try{let f=await e.get(`v1/data-subject-request/${c.id}/download-keys`,{searchParams:{limit:l,offset:d}}).json();p=Er(Lr,f),g.push(...p.nodes),d+=l,m=!!p._links.next&&p.nodes.length===l}catch(f){throw new Error(`Received an error from server: ${f?.response?.body||f?.message}`)}}return i+=1,o.update(i),[c,g]},{concurrency:s});o.stop();let y=new Date().getTime()-a;return u.info(dt.green(`Successfully downloaded file metadata ${n.length} requests in "${y/1e3}" seconds!`)),r}import $r from"colors";async function Rt(n,{requestId:e,sombra:s,onFileDownloaded:l,concurrency:a=20}){await b(n,async o=>{try{await s.get("v1/files",{searchParams:{downloadKey:o.downloadKey}}).buffer().then(i=>l(o,i))}catch(i){if(i?.response?.body?.includes("fileMetadata#verify")){u.error($r.red(`Failed to pull file for: ${o.fileName} (request:${e}) - 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 new Error(`Received an error from server: ${i?.response?.body||i?.message}`)}},{concurrency:a})}import{existsSync as Pe,mkdirSync as De,writeFileSync as Or}from"fs";import{dirname as jr,join as ht}from"path";import St from"colors";import{RequestAction as Fr,RequestStatus as Ee}from"@transcend-io/privacy-types";import bt from"cli-progress";async function Yo({auth:n,folderPath:e,requestIds:s,createdAtBefore:l,sombraAuth:a,createdAtAfter:o,statuses:i=[Ee.Approving,Ee.Downloadable],concurrency:r=5,transcendUrl:t=C,approveAfterDownload:y=!1}){let c=w(t,n),g=await W(t,n,a);Pe(e)||De(e);let m=await E(c,{actions:[Fr.Access],createdAtBefore:l,createdAtAfter:o,statuses:i,requestIds:s}),d=await qt(m,{sombra:g,concurrency:r}),p=new Date().getTime(),f=new bt.SingleBar({},bt.Presets.shades_classic),h=0,S=0;f.start(m.length,0),await b(d,async([v,x])=>{let K=ht(e,v.id);Pe(K)||De(K),await Rt(x,{sombra:g,requestId:v.id,onFileDownloaded:($,_)=>{let z=ht(K,$.fileName),j=jr(z);Pe(j)||De(j,{recursive:!0}),Or(z,_)}}),y&&v.status===Ee.Approving&&(await P(c,de,{input:{requestId:v.id}}),S+=1),h+=1,f.update(h)},{concurrency:r}),f.stop();let T=new Date().getTime()-p;return u.info(St.green(`Successfully downloaded ${h} requests in "${T/1e3}" seconds!`)),S>0&&u.info(St.green(`Approved ${S} requests in Transcend.`)),m.length}import*as I from"io-ts";import{uniq as _r}from"lodash-es";import{valuesOf as Te,decodeCodec as kr}from"@transcend-io/type-utils";import{IsoCountryCode as Vr,IsoCountrySubdivisionCode as Mr,RequestAction as Br,RequestStatus as Ur}from"@transcend-io/privacy-types";var ve=I.type({id:I.string,link:I.string,status:Te(Ur),type:Te(Br),subjectType:I.string,email:I.union([I.null,I.string]),coreIdentifier:I.string,isSilent:I.boolean,isTest:I.boolean,country:I.union([I.null,Te(Vr)]),countrySubDivision:I.union([I.null,Te(Mr)]),attributeValues:I.array(I.type({attributeKey:I.type({name:I.string}),name:I.string}))});async function Tt(n,e,{details:s="",isTest:l=!1,emailIsVerified:a=!0,skipSendingReceipt:o=!1,isSilent:i=!0,additionalAttributes:r=[]}={}){let t=[...r];(e.attributes||[]).forEach(g=>{let m=t.find(d=>d.key===g.key);m?(m.values.push(...g.values),m.values=_r(m.values)):t.push(g)});let y;try{y=await n.post("v1/data-subject-request",{json:{type:e.requestType,subject:{coreIdentifier:e.coreIdentifier,email:e.email,emailIsVerified:a,attestedExtraIdentifiers:e.attestedExtraIdentifiers},subjectType:e.subjectType,isSilent:i,isTest:l,skipSendingReceipt:o,...e.locale?{locale:e.locale}:{},details:s,attributes:t,...e.country||e.countrySubDivision?{region:{...e.country?{country:e.country}:e.countrySubDivision?{country:e.countrySubDivision.split("-")[0]}:{},...e.countrySubDivision?{countrySubDivision:e.countrySubDivision}:{}}}:{},...e.createdAt?{createdAt:e.createdAt}:{},...e.dataSiloIds?{dataSiloIds:e.dataSiloIds}:{},...e.status?{completedRequestStatus:e.status}:{}}}).json()}catch(g){throw new Error(`Received an error from server: ${g?.response?.body||g?.message}`)}let{request:c}=kr(I.type({request:ve}),y);return c}import Ne from"colors";import{RequestStatus as Qr}from"@transcend-io/privacy-types";import At from"cli-progress";async function li({requestActions:n,requestOrigins:e,auth:s,silentModeBefore:l,createdAtAfter:a,createdAtBefore:o,concurrency:i=50,transcendUrl:r=C}){let t=w(r,s),y=new Date().getTime(),c=new At.SingleBar({},At.Presets.shades_classic),g=await E(t,{actions:n,statuses:[Qr.Approving],createdAtAfter:a,origins:e,createdAtBefore:o});u.info(Ne.magenta(`Approving "${g.length}" requests.`));let m=0,d=0;c.start(g.length,0),await b(g,async h=>{l&&new Date(l)>new Date(h.createdAt)&&await P(t,oe,{input:{id:h.id,isSilent:!0}});try{await P(t,de,{input:{requestId:h.id}})}catch(S){S.message.includes("Request must be in an approving state,")&&(d+=1)}m+=1,c.update(m)},{concurrency:i}),c.stop();let f=new Date().getTime()-y;return d>0&&u.info(Ne.yellow(`${d} requests were skipped.`)),u.info(Ne.green(`Successfully approved ${m} requests in "${f/1e3}" seconds!`)),g.length}import wt from"colors";import{RequestAction as Gr}from"@transcend-io/privacy-types";import Ct from"cli-progress";async function Ri({requestActions:n=Object.values(Gr),auth:e,requestIds:s,createdAtBefore:l,days:a=45,daysLeft:o=10,createdAtAfter:i,emailTemplate:r="Additional Time Needed",concurrency:t=100,transcendUrl:y=C}){let c=w(y,e),g=new Date().getTime(),m=new Ct.SingleBar({},Ct.Presets.shades_classic),p=(await ge(c,r)).find(T=>T.title===r);if(!p)throw new Error(`Failed to find a template with title: "${r}"`);let f=await E(c,{actions:n,createdAtBefore:l,createdAtAfter:i,isSilent:!1,isClosed:!1,requestIds:s});f=f.filter(T=>typeof T.daysRemaining=="number"&&T.daysRemaining<o),u.info(wt.magenta(`Notifying "${f.length}" that more time is needed.`));let h=0;m.start(f.length,0),await b(f,async T=>{await P(c,Ve,{input:{requestId:T.id,template:p.template.defaultMessage,subject:p.subject.defaultMessage,additionalTime:a}}),h+=1,m.update(h)},{concurrency:t}),m.stop();let N=new Date().getTime()-g;return u.info(wt.green(`Successfully marked ${h} requests as silent mode in "${N/1e3}" seconds!`)),f.length}import Kr from"inquirer";async function It(n,e,s){let{initializer:l}=await P(n,Fe),a=l.identifiers.filter(({name:i})=>!s.getValue("identifierNames",i)&&!Re.includes(i)),o=a.length===0?{}:await Kr.prompt(a.map(({name:i})=>{let r=ne(e,i,!1);return{name:i,message:`Choose the column that will be used to map in the identifier: ${i}`,type:"list",default:r[0],choices:r}}));return await Promise.all(Object.entries(o).map(([i,r])=>s.setValue(r,"identifierNames",i))),{...s.getValue("identifierNames"),...o}}import Pt from"colors";import{RequestStatus as Z}from"@transcend-io/privacy-types";import Dt from"cli-progress";async function ji({requestActions:n,cancellationTitle:e,auth:s,requestIds:l,silentModeBefore:a,createdAtBefore:o,createdAtAfter:i,statuses:r=[Z.Compiling,Z.RequestMade,Z.Delayed,Z.Approving,Z.Secondary,Z.Enriching,Z.Waiting,Z.SecondaryApproving],concurrency:t=50,transcendUrl:y=C}){let c=w(y,s),g=new Date().getTime(),m=new Dt.SingleBar({},Dt.Presets.shades_classic),d;if(e){let T=(await ge(c,e)).find(v=>v.title===e);if(!T)throw new Error(`Failed to find a template with title: "${e}"`);d=T}let p=await E(c,{actions:n,createdAtBefore:o,createdAtAfter:i,statuses:r,requestIds:l});u.info(Pt.magenta(`Canceling "${p.length}" requests${d?` Using template: ${d.title}`:""}.`));let f=0;m.start(p.length,0),await b(p,async N=>{a&&new Date(a)>new Date(N.createdAt)&&await P(c,oe,{input:{id:N.id,isSilent:!0}}),await P(c,ke,{input:{requestId:N.id,...d?{subject:`Re: ${d.subject.defaultMessage}`,template:d.template.defaultMessage}:{}}}),f+=1,m.update(f)},{concurrency:t}),m.stop();let S=new Date().getTime()-g;return u.info(Pt.green(`Successfully canceled ${f} requests in "${S/1e3}" seconds!`)),p.length}import zr from"inquirer";async function Et(n,e,s,l){let a=l.filter(({name:i})=>!s.getValue("attributeNames",i)),o=a.length===0?{}:await zr.prompt(a.map(({name:i})=>{let r=ne(e,i,!1);return{name:i,message:`Choose the column that will be used to map in the attribute: ${i}`,type:"list",default:r[0],choices:r}}));return await Promise.all(Object.entries(o).map(([i,r])=>s.setValue(r,"attributeNames",i))),{...s.getValue("attributeNames"),...o}}var vt=/{\\"message\\":\\"(.+?)\\",/;function Ae(n){return vt.test(n)?vt.exec(n)[1]:null}import F from"colors";import*as pe from"io-ts";import{uniq as Yr}from"lodash-es";import Nt from"cli-progress";import{join as Wr}from"path";import{PersistedState as xt}from"@transcend-io/persisted-state";async function ln({cacheFilepath:n,requestReceiptFolder:e,file:s,auth:l,sombraAuth:a,concurrency:o=100,defaultPhoneCountryCode:i="1",transcendUrl:r=C,attributes:t=[],emailIsVerified:y=!0,skipFilterStep:c=!1,skipSendingReceipt:g=!0,isTest:m=!1,isSilent:d=!0,debug:p=!1,dryRun:f=!1}){let h=new Date().getTime(),S=new Nt.SingleBar({},Nt.Presets.shades_classic),N=ot(t),T=new xt(n,He,{columnNames:{},requestTypeToRequestAction:{},subjectTypeToSubjectName:{},languageToLocale:{},statusToRequestStatus:{},identifierNames:{},attributeNames:{},regionToCountrySubDivision:{},regionToCountry:{}}),v=Wr(e,`tr-request-upload-${new Date().toISOString()}-${s.split("/").pop()}`.replace(".csv",".json")),x=new xt(v,Xe,{successfulRequests:[],duplicateRequests:[],failingRequests:[]}),K=await W(r,l,a),$=nt(s,pe.record(pe.string,pe.string)),_=Yr($.map(U=>Object.keys(U)).flat());if($.length===0)throw new Error("No Requests found in list! Ensure the first row of the CSV is a header and the rest are requests.");if(p){let U=$[0];u.info(F.magenta(`First request: ${JSON.stringify(U,null,2)}`))}let z=c?$:await ut($),j=w(r,l),L=await ze(j),B=await mt(_,T),Y=await It(j,_,T),k=await Et(j,_,T,L);await pt(j,z,{state:T,columnNameMap:B});let O=ft(z,T,{defaultPhoneCountryCode:i,columnNameMap:B,identifierNameMap:Y,attributeNameMap:k,requestAttributeKeys:L});p||S.start(O.length,0);let H=0;await b(O,async([U,V],Q)=>{let Oe=p?`email:${V.email} | coreIdentifier:${V.coreIdentifier}`:`row:${Q.toString()}`;if(p&&u.info(F.magenta(`[${Q+1}/${O.length}] Importing: ${JSON.stringify(V,null,2)}`)),f){u.info(F.magenta("Bailing out on dry run because dryRun is set"));return}try{let X=await Tt(K,V,{details:`Uploaded by Transcend Cli: "tr-request-upload" : ${JSON.stringify(U,null,2)}`,isTest:m,emailIsVerified:y,skipSendingReceipt:g,isSilent:d,additionalAttributes:N});p&&(u.info(F.green(`[${Q+1}/${O.length}] Successfully submitted the test data subject request: "${Oe}"`)),u.info(F.green(`[${Q+1}/${O.length}] View it at: "${X.link}"`)));let se=x.getValue("successfulRequests");se.push({id:X.id,link:X.link,rowIndex:Q,coreIdentifier:X.coreIdentifier,attemptedAt:new Date().toISOString()}),await x.setValue(se,"successfulRequests")}catch(X){let se=`${X.message} - ${JSON.stringify(X.response?.body,null,2)}`,we=Ae(se);if(we==="Client error: You have already made this request."){p&&u.info(F.yellow(`[${Q+1}/${O.length}] Skipping request as it is a duplicate`));let ue=x.getValue("duplicateRequests");ue.push({coreIdentifier:V.coreIdentifier,rowIndex:Q,attemptedAt:new Date().toISOString()}),await x.setValue(ue,"duplicateRequests")}else{let ue=x.getValue("failingRequests");ue.push({...V,rowIndex:Q,error:we||se,attemptedAt:new Date().toISOString()}),await x.setValue(ue,"failingRequests"),p&&(u.error(F.red(we||se)),u.error(F.red(`[${Q+1}/${O.length}] Failed to submit request for: "${Oe}"`)))}}H+=1,p||S.update(H)},{concurrency:o}),S.stop();let ae=new Date().getTime()-h;u.info(F.green(`Completed upload in "${ae/1e3}" seconds.`)),x.getValue("duplicateRequests").length>0&&u.info(F.yellow(`Encountered "${x.getValue("duplicateRequests").length}" duplicate requests. See "${v}" to review the core identifiers for these requests.`)),x.getValue("failingRequests").length>0&&(u.error(F.red(`Encountered "${x.getValue("failingRequests").length}" errors. See "${v}" to review the error messages and inputs.`)),process.exit(1))}import*as Lt from"io-ts";import{groupBy as Jr}from"lodash-es";import{apply as Zr,decodeCodec as Hr}from"@transcend-io/type-utils";import{IdentifierType as xe}from"@transcend-io/privacy-types";async function $t(n,e,{sendEmailReceipt:s=!1,skipWaitingPeriod:l=!1,emailIsVerified:a=!0,requestIdentifiers:o=[]}={}){let i=await n.post("v1/data-subject-request",{json:{type:e.type,subject:{coreIdentifier:e.coreIdentifier,email:e.email,emailIsVerified:a,...o.length>0?{attestedExtraIdentifiers:Zr(Jr(o.filter(t=>!(t.name==="email"&&t.value===e.email)&&!Re.includes(t.name)).map(t=>({...t,type:Object.values(xe).includes(t.name)?t.name:xe.Custom})),"type"),(t,y)=>t.map(({name:c,value:g})=>({...y===xe.Custom?{name:c}:{},value:g})))}:{}},requestId:e.id,subjectType:e.subjectType,isSilent:e.isSilent,isTest:e.isTest,locale:e.locale,skipWaitingPeriod:l,createdAt:e.createdAt,details:`Restarted by Transcend cli: "tr-request-restart" - ${e.details}`,skipSendingReceipt:!s}}).json(),{request:r}=Hr(Lt.type({request:ve}),i);return r}import{PersistedState as Xr}from"@transcend-io/persisted-state";import Ot from"cli-progress";import Le from"colors";import*as M from"io-ts";import{difference as es}from"lodash-es";import{join as ts}from"path";var rs=M.intersection([he,M.type({error:M.string})]),ss=M.type({restartedRequests:M.array(he),failingRequests:M.array(rs)});async function En({requestReceiptFolder:n,auth:e,sombraAuth:s,requestActions:l,requestStatuses:a,createdAtBefore:o,createdAtAfter:i,transcendUrl:r=C,requestIds:t=[],createdAt:y=new Date,silentModeBefore:c,sendEmailReceipt:g=!1,emailIsVerified:m=!0,copyIdentifiers:d=!1,skipWaitingPeriod:p=!1,concurrency:f=20}){let h=new Date().getTime(),S=new Ot.SingleBar({},Ot.Presets.shades_classic),N=ts(n,`tr-request-restart-${new Date().toISOString()}`),T=new Xr(N,ss,{restartedRequests:[],failingRequests:[]}),v=await W(r,e,s),x=w(r,e),$=(await E(x,{actions:l,statuses:a,createdAtBefore:o,createdAtAfter:i})).filter(L=>new Date(L.createdAt)<y);if(u.info(`Found ${$.length} requests to process`),d&&u.info("copyIdentifiers detected - All Identifiers will be copied."),g&&u.info("sendEmailReceipt detected - Email receipts will be sent."),p&&u.info("skipWaitingPeriod detected - Waiting period will be skipped."),t.length>0&&t.length!==$.length){let L=es(t,$.map(({id:B})=>B));L.length>0&&(u.error(Le.red(`Failed to find the following requests by ID: ${L.join(",")}.`)),process.exit(1))}let _=0;S.start($.length,0),await b($,async(L,B)=>{try{let Y=d?await ye(x,v,{requestId:L.id}):[],k=await $t(v,{...L,isSilent:c&&new Date(L.createdAt)<c?!0:L.isSilent},{requestIdentifiers:Y,skipWaitingPeriod:p,sendEmailReceipt:g,emailIsVerified:m}),O=T.getValue("restartedRequests");O.push({id:k.id,link:k.link,rowIndex:B,coreIdentifier:k.coreIdentifier,attemptedAt:new Date().toISOString()}),await T.setValue(O,"restartedRequests")}catch(Y){let k=`${Y.message} - ${JSON.stringify(Y.response?.body,null,2)}`,O=Ae(k),H=T.getValue("failingRequests");H.push({id:L.id,link:L.link,rowIndex:B,coreIdentifier:L.coreIdentifier,attemptedAt:new Date().toISOString(),error:O||k}),await T.setValue(H,"failingRequests")}_+=1,S.update(_)},{concurrency:f}),S.stop();let j=new Date().getTime()-h;u.info(Le.green(`Completed restarting of requests in "${j/1e3}" seconds.`)),T.getValue("failingRequests").length>0&&(u.error(Le.red(`Encountered "${T.getValue("failingRequests").length}" errors. See "${N}" to review the error messages and inputs.`)),process.exit(1))}import jt from"colors";import Ft from"cli-progress";import{RequestEnricherStatus as _t,RequestStatus as os}from"@transcend-io/privacy-types";async function _n({enricherIds:n,auth:e,concurrency:s=100,transcendUrl:l=C}){let a=w(l,e),o=new Date().getTime(),i=await E(a,{statuses:[os.Enriching]});u.info(jt.magenta(`Processing enricher: "${n.join(",")}" fetched "${i.length}" in enriching status.`));let r=new Ft.SingleBar({},Ft.Presets.shades_classic),t=0;r.start(i.length,0);let y=0;await b(i,async m=>{let p=(await qe(a,{requestId:m.id})).filter(f=>n.includes(f.enricher.id)&&![_t.Resolved,_t.Skipped].includes(f.status));p.length>0&&await je(p,async f=>{try{await P(a,Me,{requestEnricherId:f.id}),y+=1}catch(h){if(!h.message.includes("Client error: Cannot skip Request enricher because it has already completed"))throw h}}),t+=1,r.update(t)},{concurrency:s}),r.stop();let g=new Date().getTime()-o;return u.info(jt.green(`Successfully skipped "${y}" for "${i.length}" requests in "${g/1e3}" seconds!`)),i.length}import{RequestEnricherStatus as is,RequestStatus as ns}from"@transcend-io/privacy-types";import kt from"cli-progress";import $e from"colors";import{difference as as}from"lodash-es";async function Wn({auth:n,requestActions:e=[],createdAtBefore:s,createdAtAfter:l,transcendUrl:a=C,requestEnricherStatuses:o=Object.values(is),requestIds:i=[],enricherId:r,concurrency:t=20}){let y=new Date().getTime(),c=new kt.SingleBar({},kt.Presets.shades_classic),g=w(a,n);u.info($e.magenta("Fetching requests to restart..."));let m=await E(g,{actions:e,statuses:[ns.Enriching],createdAtBefore:s,createdAtAfter:l,requestIds:i}),d=0;if(i.length>0&&i.length!==m.length){let S=as(i,m.map(({id:N})=>N));S.length>0&&(u.error($e.red(`Failed to find the following requests by ID: ${S.join(",")}.`)),process.exit(1))}let p=0;c.start(m.length,0),await b(m,async S=>{let T=(await qe(g,{requestId:S.id})).filter(v=>v.enricher.id===r&&o.includes(v.status));await b(T,async v=>{await Ge(g,v.id),d+=1}),p+=1,c.update(p)},{concurrency:t}),c.stop();let h=new Date().getTime()-y;u.info($e.green(`Completed restarting of ${m.length} requests and ${d} enrichers in "${h/1e3}" seconds.`))}import Vt from"colors";import{RequestStatus as Mt}from"@transcend-io/privacy-types";import Bt from"cli-progress";async function ia({requestActions:n,dataSiloId:e,auth:s,concurrency:l=20,transcendUrl:a=C}){let o=w(a,s),i=new Date().getTime(),r=new Bt.SingleBar({},Bt.Presets.shades_classic),t=await E(o,{actions:n,statuses:[Mt.Compiling,Mt.Approving]});u.info(Vt.magenta(`Retrying requests for Data Silo: "${e}", restarting "${t.length}" requests.`));let y=0,c=0;r.start(t.length,0),await b(t,async d=>{try{let p=await We(o,{requestId:d.id,dataSiloId:e});await P(o,Ue,{requestDataSiloId:p.id})}catch(p){if(!p.message.includes("Failed to find RequestDataSilo"))throw p;c+=1}y+=1,r.update(y)},{concurrency:l}),r.stop();let m=new Date().getTime()-i;return u.info(Vt.green(`Successfully notified Transcend in "${m/1e3}" seconds for ${y} requests, ${c} requests were skipped because data silo was not attached to the request!`)),t.length}import Ut from"colors";import{groupBy as Qt}from"lodash-es";async function ga({auth:n,sombraAuth:e,actions:s=[],statuses:l=[],identifierSearch:a,pageLimit:o=100,transcendUrl:i=C,createdAtBefore:r,createdAtAfter:t,isTest:y}){let c=w(i,n),g=await W(i,n,e),m="";r&&(m+=` before ${r.toISOString()}`),t&&(m+=`${m?", and":""} after ${t.toISOString()}`),u.info(Ut.magenta(`${s.length>0?`Pulling requests of type "${s.join('" , "')}"`:"Pulling all requests"}${m}`));let d=await E(c,{actions:s,text:a,statuses:l,createdAtBefore:r,createdAtAfter:t,isTest:y}),p=await b(d,async h=>{let S=await ye(c,g,{requestId:h.id});return{...h,requestIdentifiers:S}},{concurrency:o});u.info(Ut.magenta(`Pulled ${p.length} requests`));let f=p.map(({attributeValues:h,requestIdentifiers:S,id:N,email:T,type:v,status:x,subjectType:K,details:$,createdAt:_,country:z,locale:j,origin:L,countrySubDivision:B,isSilent:Y,isTest:k,coreIdentifier:O,...H})=>({"Request ID":N,"Created At":_,Email:T,"Core Identifier":O,"Request Type":v,"Data Subject Type":K,Status:x,Country:z,"Country Sub Division":B,Details:$,Origin:L,"Silent Mode":Y,"Is Test Request":k,Language:j,...H,...Object.entries(Qt(h,"attributeKey.name")).reduce((fe,[ae,U])=>Object.assign(fe,{[ae]:U.map(({name:V})=>V).join(",")}),{}),...Object.entries(Qt(S,"name")).reduce((fe,[ae,U])=>Object.assign(fe,{[ae]:U.map(({value:V})=>V).join(",")}),{})}));return{requestsWithRequestIdentifiers:p,requestsFormattedForCsv:f}}import Gt from"colors";import Kt from"cli-progress";import{RequestStatus as zt}from"@transcend-io/privacy-types";async function wa({dataSiloId:n,auth:e,concurrency:s=100,status:l="SKIPPED",transcendUrl:a=C,requestStatuses:o=[zt.Compiling,zt.Secondary]}){let i=w(a,e),r=new Date().getTime(),t=await Ye(i,{dataSiloId:n,requestStatuses:o});u.info(Gt.magenta(`Processing data silo: "${n}" marking "${t.length}" requests as skipped.`));let y=new Kt.SingleBar({},Kt.Presets.shades_classic),c=0;y.start(t.length,0),await b(t,async d=>{try{await P(i,Be,{requestDataSiloId:d.id,status:l})}catch(p){if(!p.message.includes("Client error: Request must be active:"))throw p}c+=1,y.update(c)},{concurrency:s}),y.stop();let m=new Date().getTime()-r;return u.info(Gt.green(`Successfully skipped "${t.length}" requests in "${m/1e3}" seconds!`)),t.length}import Yt from"colors";import{RequestStatus as us}from"@transcend-io/privacy-types";import Wt from"cli-progress";async function $a({requestActions:n,identifierNames:e,auth:s,concurrency:l=20,transcendUrl:a=C}){let o=w(a,s),i=new Date().getTime(),r=new Wt.SingleBar({},Wt.Presets.shades_classic),t=await E(o,{actions:n,statuses:[us.Enriching]});u.info(Yt.magenta("Fetched requests in preflight/enriching state."));let y=0,c=0;r.start(t.length,0),await b(t,async d=>{let f=(await Ke(o,{requestId:d.id})).filter(({isVerifiedAtLeastOnce:h,name:S})=>h===!1&&e.includes(S)).map(({id:h})=>h);f.length>0&&(await P(o,Qe,{input:{requestId:d.id,requestIdentifierIds:f}}),c+=f.length),y+=1,r.update(y)},{concurrency:l}),r.stop();let m=new Date().getTime()-i;return u.info(Yt.green(`Successfully cleared out unverified identifiers "${m/1e3}" seconds for ${y} requests, ${c} identifiers were cleared out!`)),t.length}export{A as a,ce as b,Ce as c,Re as d,ie as e,Je as f,Ze as g,He as h,he as i,Xe as j,Se as k,ne as l,ee as m,Ie as n,st as o,ot as p,nt as q,G as r,ut as s,Ys as t,mt as u,pt as v,Pr as w,wo as x,Dr as y,ft as z,yt as A,xr as B,Lr as C,qt as D,Rt as E,Yo as F,ve as G,Tt as H,li as I,Ri as J,It as K,ji as L,Et as M,Ae as N,ln as O,$t as P,En as Q,_n as R,Wn as S,ia as T,ga as U,wa as V,$a as W};
2
+ //# sourceMappingURL=chunk-N6JZHL5U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/requests/constants.ts","../src/lib/requests/fuzzyMatchColumns.ts","../src/lib/requests/mapEnumValues.ts","../src/lib/requests/splitCsvToList.ts","../src/lib/requests/parseAttributesFromString.ts","../src/lib/requests/readCsv.ts","../src/lib/requests/getUniqueValuesForColumn.ts","../src/lib/requests/filterRows.ts","../src/lib/requests/markSilentPrivacyRequests.ts","../src/lib/requests/mapCsvColumnsToApi.ts","../src/lib/requests/mapRequestEnumValues.ts","../src/lib/requests/mapCsvRowsToRequestInputs.ts","../src/lib/requests/getFileMetadataForPrivacyRequests.ts","../src/lib/requests/streamPrivacyRequestFiles.ts","../src/lib/requests/downloadPrivacyRequestFiles.ts","../src/lib/requests/submitPrivacyRequest.ts","../src/lib/requests/approvePrivacyRequests.ts","../src/lib/requests/notifyPrivacyRequestsAdditionalTime.ts","../src/lib/requests/mapColumnsToIdentifiers.ts","../src/lib/requests/cancelPrivacyRequests.ts","../src/lib/requests/mapColumnsToAttributes.ts","../src/lib/requests/extractClientError.ts","../src/lib/requests/uploadPrivacyRequestsFromCsv.ts","../src/lib/requests/restartPrivacyRequest.ts","../src/lib/requests/bulkRestartRequests.ts","../src/lib/requests/skipPreflightJobs.ts","../src/lib/requests/bulkRetryEnrichers.ts","../src/lib/requests/retryRequestDataSilos.ts","../src/lib/requests/pullPrivacyRequests.ts","../src/lib/requests/skipRequestDataSilos.ts","../src/lib/requests/removeUnverifiedRequestIdentifiers.ts"],"sourcesContent":["import { applyEnum, valuesOf } from '@transcend-io/type-utils';\nimport { LanguageKey } from '@transcend-io/internationalization';\nimport {\n CompletedRequestStatus,\n RequestAction,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n} from '@transcend-io/privacy-types';\nimport * as t from 'io-ts';\n\nexport const NONE = '[NONE]' as const;\nexport const BULK_APPLY = '[APPLY VALUE TO ALL ROWS]' as const;\nexport const BLANK = '<blank>' as const;\n\n/** These are uploaded at the top level of the request */\nexport const IDENTIFIER_BLOCK_LIST = ['email', 'coreIdentifier'];\n\n/**\n * Column names to map\n */\nexport enum ColumnName {\n /** The title of the email column */\n Email = 'email',\n /** The title of the core identifier column */\n CoreIdentifier = 'coreIdentifier',\n /** The title of the requestType column */\n RequestType = 'requestType',\n /** The title of the subjectType column */\n SubjectType = 'subjectType',\n /** The title of the locale column */\n Locale = 'locale',\n /** The country */\n Country = 'country',\n /** The country sub division */\n CountrySubDivision = 'countrySubDivision',\n /** The title of the requestStatus column */\n RequestStatus = 'requestStatus',\n /** The title of the createdAt column */\n CreatedAt = 'createdAt',\n /** The title of the dataSiloIds column */\n DataSiloIds = 'dataSiloIds',\n}\n\n/** These parameters are required in the Transcend DSR API */\nexport const IS_REQUIRED: { [k in ColumnName]: boolean } = {\n [ColumnName.Email]: false,\n [ColumnName.CoreIdentifier]: true,\n [ColumnName.RequestType]: true,\n [ColumnName.SubjectType]: true,\n [ColumnName.RequestStatus]: false,\n [ColumnName.CreatedAt]: false,\n [ColumnName.DataSiloIds]: false,\n [ColumnName.Locale]: false,\n [ColumnName.Country]: false,\n [ColumnName.CountrySubDivision]: false,\n};\n\n/** These parameters can be specified for the entire CSV set if needed */\nexport const CAN_APPLY_IN_BULK: { [k in ColumnName]?: boolean } = {\n [ColumnName.RequestType]: true,\n [ColumnName.SubjectType]: true,\n};\n\n// Cache state\nexport const CachedFileState = t.type({\n /** Mapping between the default request input column names and the CSV column name for that input */\n columnNames: t.partial(applyEnum(ColumnName, () => t.string)),\n /** Mapping between the identifier names and the CSV column name for that input */\n identifierNames: t.record(t.string, t.string),\n /** Mapping between the request attribute inputs and the CSV column name for that input */\n attributeNames: t.record(t.string, t.string),\n /** Mapping between CSV request type and Transcend Request Action */\n requestTypeToRequestAction: t.record(t.string, valuesOf(RequestAction)),\n /** Mapping between CSV data subject type and the name of the data subject in Transcend */\n subjectTypeToSubjectName: t.record(t.string, t.string),\n /** Mapping between language imported and Transcend locale code */\n languageToLocale: t.record(t.string, valuesOf(LanguageKey)),\n /** Mapping between region and country code */\n regionToCountry: t.record(\n t.string,\n valuesOf({ ...IsoCountryCode, [NONE]: NONE }),\n ),\n /** Mapping between region and country sub division code */\n regionToCountrySubDivision: t.record(\n t.string,\n valuesOf({ ...IsoCountrySubdivisionCode, [NONE]: NONE }),\n ),\n /** Mapping between request status in import to Transcend request status */\n statusToRequestStatus: t.record(\n t.string,\n valuesOf({ ...CompletedRequestStatus, [NONE]: NONE }),\n ),\n});\n\n/** Type override */\nexport type CachedFileState = t.TypeOf<typeof CachedFileState>;\n\n/**\n * Successfully processed request\n */\nexport const SuccessfulRequest = t.type({\n id: t.string,\n link: t.string,\n rowIndex: t.number,\n coreIdentifier: t.string,\n attemptedAt: t.string,\n});\n\n/** Type override */\nexport type SuccessfulRequest = t.TypeOf<typeof SuccessfulRequest>;\n\n// Cache state\nexport const CachedRequestState = t.type({\n /** Set of privacy requests that failed to upload */\n failingRequests: t.array(t.record(t.string, t.any)),\n /** Successfully uploaded requests */\n successfulRequests: t.array(SuccessfulRequest),\n /** Duplicate requests */\n duplicateRequests: t.array(\n t.type({\n rowIndex: t.number,\n coreIdentifier: t.string,\n attemptedAt: t.string,\n }),\n ),\n});\n\n/** Type override */\nexport type CachedRequestState = t.TypeOf<typeof CachedRequestState>;\n","import inquirer from 'inquirer';\nimport { NONE, BULK_APPLY } from './constants';\n\nimport fuzzysearch from 'fuzzysearch';\n\n/**\n * Check if word1 and word2 are a fuzzy match of each other.\n * Returns true if word1 is fuzzy match of word2 or vice versa.\n *\n * @param word1 - First word\n * @param word2 - Second word\n * @returns True if words are fuzzy match\n */\nexport function fuzzySearch(word1: string, word2: string): boolean {\n return (\n fuzzysearch(word1.toLowerCase(), word2.toLowerCase()) ||\n fuzzysearch(word2.toLowerCase(), word1.toLowerCase())\n );\n}\n\n/**\n * Fuzzy match column names for a particular field\n *\n * @param allColumnNames - List of all column names\n * @param fuzzyMapName - The name of field being mapped to\n * @param isRequired - When true, don't include \"NONE\" as an option\n * @param canApplyAll - When true, include an option to specify the value in bulk\n * @returns The list of suggestions for inquirer\n */\nexport function fuzzyMatchColumns(\n allColumnNames: string[],\n fuzzyMapName: string,\n isRequired: boolean,\n canApplyAll?: boolean,\n): (string | InstanceType<typeof inquirer.Separator>)[] {\n const matchingColumnNames = allColumnNames.filter((x) =>\n fuzzySearch(fuzzyMapName.toLowerCase(), x.toLowerCase()),\n );\n return [\n ...matchingColumnNames,\n new inquirer.Separator(),\n ...(isRequired ? [] : [NONE]),\n ...(canApplyAll ? [BULK_APPLY] : []),\n ...allColumnNames.filter((x) => !matchingColumnNames.includes(x)),\n ];\n}\n","import inquirer from 'inquirer';\nimport autoCompletePrompt from 'inquirer-autocomplete-prompt';\nimport { apply, ObjByString } from '@transcend-io/type-utils';\nimport { fuzzySearch } from './fuzzyMatchColumns';\n\n/**\n * Map a set of inputs to a set of outputs\n *\n * @param csvInputs - Input list\n * @param expectedOutputs - Output list\n * @param cache - Cache\n * @returns Mapping from row to enum value\n */\nexport async function mapEnumValues<TValue extends string>(\n csvInputs: string[],\n expectedOutputs: TValue[],\n cache: { [k in string]: TValue },\n): Promise<{ [k in string]: TValue }> {\n inquirer.registerPrompt('autocomplete', autoCompletePrompt);\n\n const inputs = csvInputs\n .map((item) => item || '<blank>')\n .filter((value) => !cache[value]);\n if (inputs.length === 0) {\n return cache;\n }\n const result = await inquirer.prompt<{ [k in string]: TValue }>(\n inputs.map((value) => ({\n name: value,\n message: `Map value of: ${value}`,\n type: 'autocomplete',\n default: expectedOutputs.find((x) => fuzzySearch(value, x)),\n source: (answersSoFar: ObjByString, input: string) =>\n !input\n ? expectedOutputs\n : expectedOutputs.filter(\n (x) => typeof x === 'string' && fuzzySearch(input, x),\n ),\n })),\n );\n return {\n ...cache,\n ...apply(result, (r) =>\n typeof r === 'string' ? (r as TValue) : (Object.values(r)[0] as TValue),\n ),\n };\n}\n","/**\n * Split string to CSV\n *\n * Filter out double commas and spaces like:\n * Dog, Cat -> ['Dog', 'Cat']\n * Dog,,Cat -> ['Dog', 'Cat']\n *\n * @param value - Value\n * @returns List of values\n */\nexport function splitCsvToList(value: string): string[] {\n return value\n .split(',')\n .map((x) => x.trim())\n .filter((x) => x);\n}\n","import colors from 'colors';\nimport * as t from 'io-ts';\nimport { logger } from '../../logger';\n\nexport const ParsedAttributeInput = t.type({\n /** Attribute key */\n key: t.string,\n /** Attribute values */\n values: t.array(t.string),\n});\n\n/** Type override */\nexport type ParsedAttributeInput = t.TypeOf<typeof ParsedAttributeInput>;\n\n/**\n * Parse out the extra attributes to apply to all requests uploaded\n *\n * @param attributes - input as string, e.g. ['key:value1;value2','key2:value3;value4']\n * @returns The parsed attributes\n */\nexport function parseAttributesFromString(\n attributes: string[],\n): ParsedAttributeInput[] {\n // Parse out the extra attributes to apply to all requests uploaded\n const parsedAttributes = attributes.map((attribute) => {\n const [attributeKey, attributeValuesRaw] = attribute.trim().split(':');\n if (!attributeValuesRaw) {\n throw new Error(\n 'Expected attributes in key:value1;value2,key2:value3;value4',\n );\n }\n const attributeValues = attributeValuesRaw.split(';');\n return {\n key: attributeKey,\n values: attributeValues,\n };\n });\n logger.info(colors.magenta('Attributes to apply to all requests:'));\n logger.info(colors.magenta(JSON.stringify(parsedAttributes, null, 2)));\n return parsedAttributes;\n}\n","import type { Options } from 'csv-parse';\nimport { parse } from 'csv-parse/sync';\nimport { readFileSync } from 'fs';\nimport * as t from 'io-ts';\n\nimport { decodeCodec } from '@transcend-io/type-utils';\n\n/**\n * Read in a CSV and validate its shape\n *\n * @param pathToFile - Path to file\n * @param codec - The codec to validate against. This is the codec for individual, non-header, rows\n * @param options - CSV parse options\n * @returns The JSON data\n */\nexport function readCsv<T extends t.Any>(\n pathToFile: string,\n codec: T,\n options: Options = { columns: true },\n): t.TypeOf<T>[] {\n // read file contents and parse\n const fileContent = parse(readFileSync(pathToFile, 'utf-8'), options);\n\n // validate codec\n const data = decodeCodec(t.array(codec), fileContent);\n\n // remove any special characters from object keys\n const parsed = data.map((datum) =>\n Object.entries(datum).reduce(\n (acc, [key, value]) =>\n Object.assign(acc, {\n [key.replace(/[^a-z_.+\\-A-Z -~]/g, '')]: value,\n }),\n {} as T,\n ),\n );\n return parsed;\n}\n","import { ObjByString } from '@transcend-io/type-utils';\nimport { uniq } from 'lodash-es';\n\n/**\n * Return the unique set of values for a column in a CSV\n *\n * @param rows - Rows to look up\n * @param columnName - Name of column to grab values for\n * @returns Unique set of values in that column\n */\nexport function getUniqueValuesForColumn(\n rows: ObjByString[],\n columnName: string,\n): string[] {\n return uniq(rows.map((row) => row[columnName] || '').flat());\n}\n","import inquirer from 'inquirer';\nimport { ObjByString } from '@transcend-io/type-utils';\nimport colors from 'colors';\nimport { uniq } from 'lodash-es';\nimport { logger } from '../../logger';\nimport { NONE } from './constants';\nimport { getUniqueValuesForColumn } from './getUniqueValuesForColumn';\n\n/**\n * Filter a list of CSV rows by column values\n * Choose columns that contain metadata to filter the requests\n *\n * @param rows - Rows to filter\n * @returns Filtered rows\n */\nexport async function filterRows(rows: ObjByString[]): Promise<ObjByString[]> {\n // Determine set of column names\n const columnNames = uniq(rows.map((x) => Object.keys(x)).flat());\n\n // update these variables recursively\n let filteredRows = rows;\n let keepFiltering = true;\n\n // loop over\n while (keepFiltering) {\n // Prompt user for column to filter on\n\n const { filterColumnName } = await inquirer.prompt<{\n /** Name of column to filter on */\n filterColumnName: string;\n }>([\n {\n name: 'filterColumnName',\n // eslint-disable-next-line max-len\n message: `If you need to filter the list of requests to import, choose the column to filter on. Currently ${filteredRows.length} rows.`,\n type: 'list',\n default: columnNames,\n choices: [NONE, ...columnNames],\n },\n ]);\n\n // Determine if filtering should continue, or loop should be exited\n keepFiltering = NONE !== filterColumnName;\n if (keepFiltering) {\n const options = getUniqueValuesForColumn(filteredRows, filterColumnName);\n\n const { valuesToKeep } = await inquirer.prompt<{\n /** Values to keep */\n valuesToKeep: string[];\n }>([\n {\n name: 'valuesToKeep',\n message: 'Keep rows matching this value',\n type: 'checkbox',\n default: columnNames,\n choices: options,\n },\n ]);\n\n filteredRows = filteredRows.filter((request) =>\n valuesToKeep.includes(request[filterColumnName]),\n );\n }\n }\n\n logger.info(colors.magenta(`Importing ${filteredRows.length} requests`));\n return filteredRows;\n}\n","import { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport {\n UPDATE_PRIVACY_REQUEST,\n fetchAllRequests,\n makeGraphQLRequest,\n buildTranscendGraphQLClient,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Mark a set of privacy requests to be in silent mode\n *\n * @param options - Options\n * @returns The number of requests marked silent\n */\nexport async function markSilentPrivacyRequests({\n requestActions,\n auth,\n requestIds,\n statuses = [\n RequestStatus.Compiling,\n RequestStatus.RequestMade,\n RequestStatus.Delayed,\n RequestStatus.Approving,\n RequestStatus.Secondary,\n RequestStatus.Enriching,\n RequestStatus.Waiting,\n RequestStatus.SecondaryApproving,\n ],\n createdAtAfter,\n createdAtBefore,\n concurrency = 100,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** The request actions that should be restarted */\n requestActions: RequestAction[];\n /** Transcend API key authentication */\n auth: string;\n /** Concurrency limit for approving */\n concurrency?: number;\n /** The request statuses to mark silent */\n statuses?: RequestStatus[];\n /** The set of privacy requests to mark silent */\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 /** API URL for Transcend backend */\n transcendUrl?: string;\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 // 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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Pull in the requests\n const allRequests = await fetchAllRequests(client, {\n actions: requestActions,\n statuses,\n createdAtBefore,\n createdAtAfter,\n isSilent: false,\n requestIds,\n });\n\n // Notify Transcend\n logger.info(\n colors.magenta(`Marking \"${allRequests.length}\" as silent mode.`),\n );\n\n let total = 0;\n progressBar.start(allRequests.length, 0);\n await map(\n allRequests,\n async (requestToMarkSilent) => {\n await makeGraphQLRequest(client, UPDATE_PRIVACY_REQUEST, {\n input: {\n id: requestToMarkSilent.id,\n isSilent: true,\n },\n });\n\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(\n `Successfully marked ${total} requests as silent mode in \"${\n totalTime / 1000\n }\" seconds!`,\n ),\n );\n return allRequests.length;\n}\n","import { getValues, getEntries } from '@transcend-io/type-utils';\nimport type { PersistedState } from '@transcend-io/persisted-state';\nimport inquirer from 'inquirer';\nimport { startCase } from 'lodash-es';\nimport {\n ColumnName,\n CachedFileState,\n IS_REQUIRED,\n CAN_APPLY_IN_BULK,\n} from './constants';\nimport { fuzzyMatchColumns } from './fuzzyMatchColumns';\n\n/**\n * Mapping from column name to request input parameter\n */\nexport type ColumnNameMap = {\n [k in ColumnName]?: string;\n};\n\n/**\n * Determine the mapping between columns in CSV\n *\n * @param columnNames - The set of column names\n * @param state - The cached file state used to map DSR inputs\n * @returns The column name mapping\n */\nexport async function mapCsvColumnsToApi(\n columnNames: string[],\n state: PersistedState<typeof CachedFileState>,\n): Promise<ColumnNameMap> {\n // Determine the columns that should be mapped\n const columnQuestions = getValues(ColumnName).filter(\n (name) => !state.getValue('columnNames', name),\n );\n\n // Skip mapping when everything is mapped\n const columnNameMap =\n columnQuestions.length === 0\n ? {}\n : // prompt questions to map columns\n await inquirer.prompt<{\n [k in ColumnName]?: string;\n }>(\n columnQuestions.map((name) => {\n const field = startCase(name.replace('ColumnName', ''));\n const matches = fuzzyMatchColumns(\n columnNames,\n field,\n IS_REQUIRED[name],\n !!CAN_APPLY_IN_BULK[name],\n );\n return {\n name,\n message: `Choose the column that will be used to map in the field: ${field}`,\n type: 'list',\n default: matches[0],\n choices: matches,\n };\n }),\n );\n\n await Promise.all(\n getEntries(columnNameMap).map(([k, v]) =>\n state.setValue(v, 'columnNames', k),\n ),\n );\n return columnNameMap;\n}\n","import { GraphQLClient } from 'graphql-request';\nimport colors from 'colors';\nimport type { PersistedState } from '@transcend-io/persisted-state';\nimport {\n CompletedRequestStatus,\n RequestAction,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n} from '@transcend-io/privacy-types';\nimport { LanguageKey } from '@transcend-io/internationalization';\nimport { ObjByString } from '@transcend-io/type-utils';\nimport { logger } from '../../logger';\nimport { makeGraphQLRequest, DataSubject, DATA_SUBJECTS } from '../graphql';\nimport { CachedFileState, NONE, ColumnName } from './constants';\nimport { mapEnumValues } from './mapEnumValues';\nimport { ColumnNameMap } from './mapCsvColumnsToApi';\nimport { getUniqueValuesForColumn } from './getUniqueValuesForColumn';\n\n/**\n * Map the values in a CSV to the enum values in Transcend\n *\n * @param client - GraphQL client\n * @param requests - Set of privacy requests\n * @param options - Options\n */\nexport async function mapRequestEnumValues(\n client: GraphQLClient,\n requests: ObjByString[],\n {\n state,\n columnNameMap,\n }: {\n /** State value to write cache to */\n state: PersistedState<typeof CachedFileState>;\n /** Mapping of column names */\n columnNameMap: ColumnNameMap;\n },\n): Promise<void> {\n // Get mapped value\n const getMappedName = (attribute: ColumnName): string =>\n state.getValue('columnNames', attribute) || columnNameMap[attribute]!;\n\n // Fetch all data subjects in the organization\n const { internalSubjects } = await makeGraphQLRequest<{\n /** Query response */\n internalSubjects: DataSubject[];\n }>(client, DATA_SUBJECTS);\n\n // Map RequestAction\n logger.info(\n colors.magenta('Determining mapping of columns for request action'),\n );\n const requestTypeToRequestAction: { [k in string]: RequestAction } =\n await mapEnumValues(\n getUniqueValuesForColumn(requests, getMappedName(ColumnName.RequestType)),\n Object.values(RequestAction),\n state.getValue('requestTypeToRequestAction'),\n );\n await state.setValue(\n requestTypeToRequestAction,\n 'requestTypeToRequestAction',\n );\n\n // Map data subject type\n logger.info(colors.magenta('Determining mapping of columns for subject'));\n const subjectTypeToSubjectName: { [k in string]: string } =\n await mapEnumValues(\n getUniqueValuesForColumn(requests, getMappedName(ColumnName.SubjectType)),\n internalSubjects.map(({ type }) => type),\n state.getValue('subjectTypeToSubjectName'),\n );\n await state.setValue(subjectTypeToSubjectName, 'subjectTypeToSubjectName');\n\n // Map locale\n logger.info(colors.magenta('Determining mapping of columns for locale'));\n const languageToLocale: { [k in string]: LanguageKey } = await mapEnumValues(\n getUniqueValuesForColumn(requests, getMappedName(ColumnName.Locale)),\n Object.values(LanguageKey),\n state.getValue('languageToLocale'),\n );\n await state.setValue(languageToLocale, 'languageToLocale');\n logger.info(\n colors.magenta('Determining mapping of columns for request status'),\n );\n\n // Map request status\n logger.info(\n colors.magenta('Determining mapping of columns for request status'),\n );\n const requestStatusColumn = getMappedName(ColumnName.RequestStatus);\n const statusToRequestStatus: {\n [k in string]: CompletedRequestStatus | typeof NONE;\n } =\n requestStatusColumn === NONE\n ? {}\n : await mapEnumValues(\n getUniqueValuesForColumn(requests, requestStatusColumn),\n [...Object.values(CompletedRequestStatus), NONE],\n state.getValue('statusToRequestStatus'),\n );\n await state.setValue(statusToRequestStatus, 'statusToRequestStatus');\n\n // Map country\n logger.info(colors.magenta('Determining mapping of columns for country'));\n const countryColumn = getMappedName(ColumnName.Country);\n const regionToCountry: {\n [k in string]: IsoCountryCode | typeof NONE;\n } =\n countryColumn === NONE\n ? {}\n : await mapEnumValues(\n getUniqueValuesForColumn(requests, countryColumn),\n [...Object.values(IsoCountryCode), NONE],\n state.getValue('regionToCountry'),\n );\n await state.setValue(regionToCountry, 'regionToCountry');\n\n // Map country sub division\n logger.info(\n colors.magenta('Determining mapping of columns for country sub division'),\n );\n const countrySubDivisionColumn = getMappedName(ColumnName.CountrySubDivision);\n const regionToCountrySubDivision: {\n [k in string]: IsoCountrySubdivisionCode | typeof NONE;\n } =\n countrySubDivisionColumn === NONE\n ? {}\n : await mapEnumValues(\n getUniqueValuesForColumn(requests, countrySubDivisionColumn),\n [...Object.values(IsoCountrySubdivisionCode), NONE],\n state.getValue('regionToCountrySubDivision'),\n );\n await state.setValue(\n regionToCountrySubDivision,\n 'regionToCountrySubDivision',\n );\n}\n","import { LanguageKey } from '@transcend-io/internationalization';\nimport { DateFromISOString } from 'io-ts-types';\n\nimport * as t from 'io-ts';\nimport type { PersistedState } from '@transcend-io/persisted-state';\nimport {\n NORMALIZE_PHONE_NUMBER,\n CompletedRequestStatus,\n RequestAction,\n IdentifierType,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n} from '@transcend-io/privacy-types';\nimport { ObjByString, valuesOf } from '@transcend-io/type-utils';\n\nimport {\n CachedFileState,\n BLANK,\n BULK_APPLY,\n ColumnName,\n NONE,\n} from './constants';\nimport { AttributeKey } from '../graphql';\nimport { ColumnNameMap } from './mapCsvColumnsToApi';\nimport { splitCsvToList } from './splitCsvToList';\nimport { ParsedAttributeInput } from './parseAttributesFromString';\nimport { AttributeNameMap } from './mapColumnsToAttributes';\nimport { IdentifierNameMap } from './mapColumnsToIdentifiers';\n\n/**\n * Shape of additional identifiers\n *\n * key of object is IdentifierType\n */\nexport const AttestedExtraIdentifiers = t.record(\n t.string,\n t.array(\n t.intersection([\n t.type({\n /** Value of identifier */\n value: t.string,\n }),\n t.partial({\n /** Name of identifier - option for non-custom identifier types */\n name: t.string,\n }),\n ]),\n ),\n);\n\n/** Type override */\nexport type AttestedExtraIdentifiers = t.TypeOf<\n typeof AttestedExtraIdentifiers\n>;\n\nexport const PrivacyRequestInput = t.intersection([\n t.type({\n /** Email of user */\n email: t.string,\n /** Extra identifiers */\n attestedExtraIdentifiers: AttestedExtraIdentifiers,\n /** Core identifier for user */\n coreIdentifier: t.string,\n /** Action type being submitted */\n requestType: valuesOf(RequestAction),\n /** Type of data subject */\n subjectType: t.string,\n }),\n t.partial({\n /** Country */\n country: valuesOf(IsoCountryCode),\n /** Country sub division */\n countrySubDivision: valuesOf(IsoCountrySubdivisionCode),\n /** Attribute inputs */\n attributes: t.array(ParsedAttributeInput),\n /** The status that the request should be created as */\n status: valuesOf(CompletedRequestStatus),\n /** The time that the request was created */\n createdAt: DateFromISOString,\n /** Data silo IDs to submit for */\n dataSiloIds: t.array(t.string),\n /** Language key to map to */\n locale: valuesOf(LanguageKey),\n }),\n]);\n\n/** Type override */\nexport type PrivacyRequestInput = t.TypeOf<typeof PrivacyRequestInput>;\n\n/**\n * Transform the identifier value based on type\n *\n * @param identifierValue - Value of identifier\n * @param identifierType - Type of identifier\n * @param defaultPhoneCountryCode - Default country code for phone numbers\n * @returns Post-processed identifier\n */\nexport function normalizeIdentifierValue(\n identifierValue: string,\n identifierType: IdentifierType,\n defaultPhoneCountryCode: string,\n): string {\n // Lowercase email\n if (identifierType === IdentifierType.Email) {\n return identifierValue.toLowerCase();\n }\n\n // Normalize phone number\n if (identifierType === IdentifierType.Phone) {\n const normalized = identifierValue\n .replace(NORMALIZE_PHONE_NUMBER, '')\n .replace(/[()]/g, '')\n .replace(/[–]/g, '')\n .replace(/[:]/g, '')\n .replace(/[‭‬]/g, '')\n .replace(/[A-Za-z]/g, '');\n return !normalized\n ? ''\n : normalized.startsWith('+')\n ? normalized\n : `+${defaultPhoneCountryCode}${normalized}`;\n }\n return identifierValue;\n}\n\n/**\n * Take the raw rows in a CSV upload, and map those rows to the request\n * input shape that can be passed to the Transcend API to submit a privacy\n * request.\n *\n * @param requestInputs - CSV of requests to be uploaded\n * @param state - The cached set of mapping values\n * @param options - Options\n * @returns [raw input, request input] list\n */\nexport function mapCsvRowsToRequestInputs(\n requestInputs: ObjByString[],\n state: PersistedState<typeof CachedFileState>,\n {\n columnNameMap,\n identifierNameMap,\n attributeNameMap,\n requestAttributeKeys,\n defaultPhoneCountryCode = '1', // US\n }: {\n /** Default country code */\n defaultPhoneCountryCode?: string;\n /** Mapping of column names */\n columnNameMap: ColumnNameMap;\n /** Mapping of identifier names */\n identifierNameMap: IdentifierNameMap;\n /** Mapping of attribute names */\n attributeNameMap: AttributeNameMap;\n /** Request attribute keys */\n requestAttributeKeys: AttributeKey[];\n },\n): [Record<string, string>, PrivacyRequestInput][] {\n // map the CSV to request input\n const getMappedName = (attribute: ColumnName): string =>\n state.getValue('columnNames', attribute) || columnNameMap[attribute]!;\n return requestInputs.map(\n (input): [Record<string, string>, PrivacyRequestInput] => {\n // The extra identifiers to upload for this request\n const attestedExtraIdentifiers: AttestedExtraIdentifiers = {};\n Object.entries(identifierNameMap)\n // filter out skipped identifiers\n .filter(([, columnName]) => columnName !== NONE)\n .forEach(([identifierName, columnName]) => {\n // Determine the identifier type being specified\n const identifierType = Object.values(IdentifierType).includes(\n identifierName as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n )\n ? (identifierName as IdentifierType)\n : IdentifierType.Custom;\n\n // Only add the identifier if the value exists\n const identifierValue = input[columnName];\n if (identifierValue) {\n const normalized = normalizeIdentifierValue(\n identifierValue,\n identifierType,\n defaultPhoneCountryCode,\n );\n if (normalized) {\n // Initialize\n if (!attestedExtraIdentifiers[identifierType]) {\n attestedExtraIdentifiers[identifierType] = [];\n }\n\n // Add the identifier\n attestedExtraIdentifiers[identifierType]!.push({\n value: normalized,\n name: identifierName,\n });\n }\n }\n });\n\n // The extra attributes to upload for this request\n const attributes: ParsedAttributeInput[] = [];\n Object.entries(attributeNameMap)\n // filter out skipped attributes\n .filter(([, columnName]) => columnName !== NONE)\n .forEach(([attributeName, columnName]) => {\n // Only add the identifier if the value exists\n const attributeValueString = input[columnName];\n if (attributeValueString) {\n // Add the attribute\n const isMulti =\n requestAttributeKeys.find((attr) => attr.name === attributeName)\n ?.type === 'MULTI_SELECT';\n attributes.push({\n values: isMulti\n ? splitCsvToList(attributeValueString)\n : attributeValueString,\n key: attributeName,\n });\n }\n });\n\n const requestTypeColumn = getMappedName(ColumnName.RequestType);\n const dataSubjectTypeColumn = getMappedName(ColumnName.SubjectType);\n return [\n input,\n {\n email: input[getMappedName(ColumnName.Email)],\n attestedExtraIdentifiers,\n attributes,\n coreIdentifier: input[getMappedName(ColumnName.CoreIdentifier)],\n requestType:\n requestTypeColumn === BULK_APPLY\n ? state.getValue('requestTypeToRequestAction', BLANK)\n : state.getValue(\n 'requestTypeToRequestAction',\n input[requestTypeColumn],\n ),\n subjectType:\n dataSubjectTypeColumn === BULK_APPLY\n ? state.getValue('subjectTypeToSubjectName', BLANK)\n : state.getValue(\n 'subjectTypeToSubjectName',\n input[dataSubjectTypeColumn],\n ),\n ...(getMappedName(ColumnName.Locale) !== NONE &&\n input[getMappedName(ColumnName.Locale)]\n ? {\n locale: state.getValue(\n 'languageToLocale',\n input[getMappedName(ColumnName.Locale)],\n ),\n }\n : {}),\n ...(getMappedName(ColumnName.Country) !== NONE &&\n input[getMappedName(ColumnName.Country)]\n ? {\n country: state.getValue(\n 'regionToCountry',\n input[getMappedName(ColumnName.Country)],\n ) as IsoCountryCode,\n }\n : {}),\n ...(getMappedName(ColumnName.CountrySubDivision) !== NONE &&\n input[getMappedName(ColumnName.CountrySubDivision)]\n ? {\n countrySubDivision: state.getValue(\n 'regionToCountrySubDivision',\n input[getMappedName(ColumnName.CountrySubDivision)],\n ) as IsoCountrySubdivisionCode,\n }\n : {}),\n ...(getMappedName(ColumnName.RequestStatus) !== NONE &&\n state.getValue(\n 'statusToRequestStatus',\n input[getMappedName(ColumnName.RequestStatus)],\n ) !== NONE &&\n input[getMappedName(ColumnName.RequestStatus)]\n ? {\n status: state.getValue(\n 'statusToRequestStatus',\n input[getMappedName(ColumnName.RequestStatus)],\n ) as CompletedRequestStatus,\n }\n : {}),\n ...(getMappedName(ColumnName.CreatedAt) !== NONE &&\n input[getMappedName(ColumnName.CreatedAt)]\n ? {\n createdAt: new Date(input[getMappedName(ColumnName.CreatedAt)]),\n }\n : {}),\n ...(getMappedName(ColumnName.DataSiloIds) !== NONE &&\n input[getMappedName(ColumnName.DataSiloIds)]\n ? {\n dataSiloIds: splitCsvToList(\n input[getMappedName(ColumnName.DataSiloIds)],\n ),\n }\n : {}),\n },\n ];\n },\n );\n}\n","import { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport cliProgress from 'cli-progress';\n\nimport { PrivacyRequest } from '../graphql';\nimport * as t from 'io-ts';\nimport type { Got } from 'got';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport { logger } from '../../logger';\nimport { TableEncryptionType } from '@transcend-io/privacy-types';\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<\n typeof RequestFileMetadataResponse\n>;\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(\n colors.magenta(`Pulling file metadata for ${requests.length} requests`),\n );\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(\n {},\n cliProgress.Presets.shades_classic,\n );\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<\n [Pick<PrivacyRequest, 'id' | 'status'>, RequestFileMetadata[]]\n > => {\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(\n `v1/data-subject-request/${requestToDownload.id}/download-keys`,\n {\n searchParams: {\n limit,\n offset,\n },\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(\n `Received an error from server: ${\n err?.response?.body || err?.message\n }`,\n );\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 '../bluebird-replace';\nimport colors from 'colors';\nimport { RequestFileMetadata } from './getFileMetadataForPrivacyRequests';\nimport type { Got } from 'got';\nimport { logger } from '../../logger';\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(\n `Received an error from server: ${\n err?.response?.body || err?.message\n }`,\n );\n }\n },\n {\n concurrency,\n },\n );\n}\n","import { map } from '../bluebird-replace';\nimport { existsSync, mkdirSync, writeFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport {\n fetchAllRequests,\n buildTranscendGraphQLClient,\n createSombraGotInstance,\n makeGraphQLRequest,\n APPROVE_PRIVACY_REQUEST,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\nimport { getFileMetadataForPrivacyRequests } from './getFileMetadataForPrivacyRequests';\nimport { streamPrivacyRequestFiles } from './streamPrivacyRequestFiles';\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 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 /** 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, sombraAuth);\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 statuses,\n requestIds,\n });\n\n // Download the file metadata for each request\n const requestFileMetadata = await getFileMetadataForPrivacyRequests(\n allRequests,\n {\n sombra,\n concurrency,\n },\n );\n\n // Start timer for download process\n const t0 = new Date().getTime();\n const progressBar = new cliProgress.SingleBar(\n {},\n cliProgress.Presets.shades_classic,\n );\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 input: { requestId: request.id },\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(\n `Successfully downloaded ${total} requests in \"${\n totalTime / 1000\n }\" seconds!`,\n ),\n );\n if (totalApproved > 0) {\n logger.info(\n colors.green(`Approved ${totalApproved} requests in Transcend.`),\n );\n }\n return allRequests.length;\n}\n","import * as t from 'io-ts';\nimport { uniq } from 'lodash-es';\nimport { valuesOf, decodeCodec } from '@transcend-io/type-utils';\nimport {\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n RequestAction,\n RequestStatus,\n} from '@transcend-io/privacy-types';\nimport type { Got } from 'got';\nimport { PrivacyRequestInput } from './mapCsvRowsToRequestInputs';\nimport { ParsedAttributeInput } from './parseAttributesFromString';\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(\n (attr) => attr.key === attribute.key,\n );\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(\n `Received an error from server: ${err?.response?.body || err?.message}`,\n );\n }\n\n const { request: requestResponse } = decodeCodec(\n t.type({\n request: PrivacyRequestResponse,\n }),\n response,\n );\n return requestResponse;\n}\n","import { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport {\n RequestAction,\n RequestOrigin,\n RequestStatus,\n} from '@transcend-io/privacy-types';\nimport {\n UPDATE_PRIVACY_REQUEST,\n fetchAllRequests,\n makeGraphQLRequest,\n buildTranscendGraphQLClient,\n APPROVE_PRIVACY_REQUEST,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Approve a set of privacy requests\n *\n * @param options - Options\n * @returns The number of requests approved\n */\nexport async function approvePrivacyRequests({\n requestActions,\n requestOrigins,\n auth,\n silentModeBefore,\n createdAtAfter,\n createdAtBefore,\n concurrency = 50,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** The request actions that should be restarted */\n requestActions: RequestAction[];\n /** The request origins that should be restarted */\n requestOrigins?: RequestOrigin[];\n /** Transcend API key authentication */\n auth: string;\n /** Concurrency limit for approving */\n concurrency?: number;\n /** Mark these requests as silent mode if they were created before this date */\n silentModeBefore?: Date;\n /** Filter for requests created before this date */\n createdAtBefore?: Date;\n /** Filter for requests created after this date */\n createdAtAfter?: Date;\n /** API URL for Transcend backend */\n transcendUrl?: string;\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 // 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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Pull in the requests\n const allRequests = await fetchAllRequests(client, {\n actions: requestActions,\n statuses: [RequestStatus.Approving],\n createdAtAfter,\n origins: requestOrigins,\n createdAtBefore,\n });\n\n // Notify Transcend\n logger.info(colors.magenta(`Approving \"${allRequests.length}\" requests.`));\n\n let total = 0;\n let skipped = 0;\n progressBar.start(allRequests.length, 0);\n await map(\n allRequests,\n async (requestToApprove) => {\n // update request to silent mode if silentModeBefore is defined\n // and the request was created before silentModeBefore\n if (\n silentModeBefore &&\n new Date(silentModeBefore) > new Date(requestToApprove.createdAt)\n ) {\n await makeGraphQLRequest(client, UPDATE_PRIVACY_REQUEST, {\n input: {\n id: requestToApprove.id,\n isSilent: true,\n },\n });\n }\n\n try {\n // approve the request\n await makeGraphQLRequest(client, APPROVE_PRIVACY_REQUEST, {\n input: { requestId: requestToApprove.id },\n });\n } catch (err) {\n if (err.message.includes('Request must be in an approving state,')) {\n skipped += 1;\n }\n }\n\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 if (skipped > 0) {\n logger.info(colors.yellow(`${skipped} requests were skipped.`));\n }\n logger.info(\n colors.green(\n `Successfully approved ${total} requests in \"${\n totalTime / 1000\n }\" seconds!`,\n ),\n );\n return allRequests.length;\n}\n","import { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport { RequestAction } from '@transcend-io/privacy-types';\nimport {\n NOTIFY_ADDITIONAL_TIME,\n fetchAllRequests,\n makeGraphQLRequest,\n buildTranscendGraphQLClient,\n fetchAllTemplates,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Mark a set of privacy requests to be in silent mode.\n * Note requests in silent mode are ignored\n *\n * @param options - Options\n * @returns The number of requests marked silent\n */\nexport async function notifyPrivacyRequestsAdditionalTime({\n requestActions = Object.values(RequestAction),\n auth,\n requestIds,\n createdAtBefore,\n days = 45,\n daysLeft = 10,\n createdAtAfter,\n emailTemplate = 'Additional Time Needed',\n concurrency = 100,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** The request actions that should be restarted */\n requestActions?: RequestAction[];\n /** Filter for requests created before this date */\n createdAtBefore: Date;\n /** Filter for requests created after this date */\n createdAtAfter?: Date;\n /** Email template */\n emailTemplate?: string;\n /** Transcend API key authentication */\n auth: string;\n /** Number of days to extend request by */\n days?: number;\n /**\n * Only notify requests that have less than this number of days until they are considered expired.\n * This allows for re-running the command without notifying the same users multiple times\n */\n daysLeft?: number;\n /** Concurrency limit for approving */\n concurrency?: number;\n /** The set of privacy requests to notify */\n requestIds?: string[];\n /** API URL for Transcend backend */\n transcendUrl?: string;\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 // 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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Grab the template with that title\n const matchingTemplates = await fetchAllTemplates(client, emailTemplate);\n const exactTemplateMatch = matchingTemplates.find(\n (template) => template.title === emailTemplate,\n );\n if (!exactTemplateMatch) {\n throw new Error(`Failed to find a template with title: \"${emailTemplate}\"`);\n }\n\n // Pull in the requests\n let allRequests = await fetchAllRequests(client, {\n actions: requestActions,\n createdAtBefore,\n createdAtAfter,\n isSilent: false,\n isClosed: false,\n requestIds,\n });\n\n // Filter requests by daysLeft\n allRequests = allRequests.filter(\n (request) =>\n typeof request.daysRemaining === 'number' &&\n request.daysRemaining < daysLeft,\n );\n\n // Notify Transcend\n logger.info(\n colors.magenta(\n `Notifying \"${allRequests.length}\" that more time is needed.`,\n ),\n );\n\n let total = 0;\n progressBar.start(allRequests.length, 0);\n await map(\n allRequests,\n async (requestToNotify) => {\n await makeGraphQLRequest(client, NOTIFY_ADDITIONAL_TIME, {\n input: {\n requestId: requestToNotify.id,\n template: exactTemplateMatch.template.defaultMessage,\n subject: exactTemplateMatch.subject.defaultMessage,\n additionalTime: days,\n },\n });\n\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(\n `Successfully marked ${total} requests as silent mode in \"${\n totalTime / 1000\n }\" seconds!`,\n ),\n );\n return allRequests.length;\n}\n","import type { GraphQLClient } from 'graphql-request';\nimport inquirer from 'inquirer';\nimport { INITIALIZER, makeGraphQLRequest, Initializer } from '../graphql';\nimport { CachedFileState, IDENTIFIER_BLOCK_LIST } from './constants';\nimport { fuzzyMatchColumns } from './fuzzyMatchColumns';\nimport type { PersistedState } from '@transcend-io/persisted-state';\n\n/**\n * Mapping from identifier name to request input parameter\n */\nexport type IdentifierNameMap = {\n [k in string]: string;\n};\n\n/**\n * Create a mapping from the identifier names that can be included\n * at request submission, to the names of the columns that map to those\n * identifiers.\n *\n * @param client - GraphQL client\n * @param columnNames - The set of all column names\n * @param state - Cached state of this mapping\n * @returns Mapping from identifier name to column name\n */\nexport async function mapColumnsToIdentifiers(\n client: GraphQLClient,\n columnNames: string[],\n state: PersistedState<typeof CachedFileState>,\n): Promise<IdentifierNameMap> {\n // Grab the initializer\n const { initializer } = await makeGraphQLRequest<{\n /** Query response */\n initializer: Initializer;\n }>(client, INITIALIZER);\n\n // Determine the columns that should be mapped\n const columnQuestions = initializer.identifiers.filter(\n ({ name }) =>\n !state.getValue('identifierNames', name) &&\n !IDENTIFIER_BLOCK_LIST.includes(name),\n );\n\n // Skip mapping when everything is mapped\n const identifierNameMap =\n columnQuestions.length === 0\n ? {}\n : // prompt questions to map columns\n await inquirer.prompt<{\n [k in string]: string;\n }>(\n columnQuestions.map(({ name }) => {\n const matches = fuzzyMatchColumns(columnNames, name, false);\n return {\n name,\n message: `Choose the column that will be used to map in the identifier: ${name}`,\n type: 'list',\n default: matches[0],\n choices: matches,\n };\n }),\n );\n await Promise.all(\n Object.entries(identifierNameMap).map(([k, v]) =>\n state.setValue(v, 'identifierNames', k),\n ),\n );\n\n return {\n ...state.getValue('identifierNames'),\n ...identifierNameMap,\n };\n}\n","import { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport {\n UPDATE_PRIVACY_REQUEST,\n fetchAllRequests,\n makeGraphQLRequest,\n buildTranscendGraphQLClient,\n CANCEL_PRIVACY_REQUEST,\n fetchAllTemplates,\n Template,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Cancel a set of privacy requests\n *\n * @param options - Options\n * @returns The number of requests canceled\n */\nexport async function cancelPrivacyRequests({\n requestActions,\n cancellationTitle,\n auth,\n requestIds,\n silentModeBefore,\n createdAtBefore,\n createdAtAfter,\n statuses = [\n RequestStatus.Compiling,\n RequestStatus.RequestMade,\n RequestStatus.Delayed,\n RequestStatus.Approving,\n RequestStatus.Secondary,\n RequestStatus.Enriching,\n RequestStatus.Waiting,\n RequestStatus.SecondaryApproving,\n ],\n concurrency = 50,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** The request actions that should be restarted */\n requestActions: RequestAction[];\n /** Transcend API key authentication */\n auth: 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 /** Mark these requests as silent mode if they were created before this date */\n silentModeBefore?: Date;\n /** Filter for requests created before this date */\n createdAtBefore?: Date;\n /** Filter for requests created after this date */\n createdAtAfter?: Date;\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** The email template to use when canceling the requests */\n cancellationTitle?: string;\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 // 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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Grab the template with that title\n let cancelationTemplate: Template | undefined;\n if (cancellationTitle) {\n const matchingTemplates = await fetchAllTemplates(\n client,\n cancellationTitle,\n );\n const exactTitleMatch = matchingTemplates.find(\n (template) => template.title === cancellationTitle,\n );\n if (!exactTitleMatch) {\n throw new Error(\n `Failed to find a template with title: \"${cancellationTitle}\"`,\n );\n }\n cancelationTemplate = exactTitleMatch;\n }\n\n // Pull in the requests\n const allRequests = await fetchAllRequests(client, {\n actions: requestActions,\n createdAtBefore,\n createdAtAfter,\n statuses,\n requestIds,\n });\n\n // Notify Transcend\n logger.info(\n colors.magenta(\n `Canceling \"${allRequests.length}\" requests${\n cancelationTemplate\n ? ` Using template: ${cancelationTemplate.title}`\n : ''\n }.`,\n ),\n );\n\n let total = 0;\n progressBar.start(allRequests.length, 0);\n await map(\n allRequests,\n async (requestToCancel) => {\n // update request to silent mode if silentModeBefore is defined\n // and the request was created before silentModeBefore\n if (\n silentModeBefore &&\n new Date(silentModeBefore) > new Date(requestToCancel.createdAt)\n ) {\n await makeGraphQLRequest(client, UPDATE_PRIVACY_REQUEST, {\n input: {\n id: requestToCancel.id,\n isSilent: true,\n },\n });\n }\n\n // cancel the request\n await makeGraphQLRequest(client, CANCEL_PRIVACY_REQUEST, {\n input: {\n requestId: requestToCancel.id,\n ...(cancelationTemplate\n ? {\n subject: `Re: ${cancelationTemplate.subject.defaultMessage}`,\n template: cancelationTemplate.template.defaultMessage,\n }\n : {}),\n },\n });\n\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(\n `Successfully canceled ${total} requests in \"${\n totalTime / 1000\n }\" seconds!`,\n ),\n );\n return allRequests.length;\n}\n","import type { GraphQLClient } from 'graphql-request';\nimport inquirer from 'inquirer';\nimport { AttributeKey } from '../graphql';\nimport { CachedFileState } from './constants';\nimport { fuzzyMatchColumns } from './fuzzyMatchColumns';\nimport type { PersistedState } from '@transcend-io/persisted-state';\n\n/**\n * Mapping from attribute name to request input parameter\n */\nexport type AttributeNameMap = {\n [k in string]: string;\n};\n\n/**\n * Create a mapping from the attributes names that can be included\n * at request submission, to the names of the columns that map to those\n * attributes.\n *\n * @param client - GraphQL client\n * @param columnNames - The set of all column names\n * @param state - Cached state of this mapping\n * @param requestAttributeKeys - Attribute keys to map\n * @returns Mapping from attributes name to column name\n */\nexport async function mapColumnsToAttributes(\n client: GraphQLClient,\n columnNames: string[],\n state: PersistedState<typeof CachedFileState>,\n requestAttributeKeys: AttributeKey[],\n): Promise<AttributeNameMap> {\n // Determine the columns that should be mapped\n const columnQuestions = requestAttributeKeys.filter(\n ({ name }) => !state.getValue('attributeNames', name),\n );\n\n // Skip mapping when everything is mapped\n const attributeNameMap =\n columnQuestions.length === 0\n ? {}\n : // prompt questions to map columns\n await inquirer.prompt<{\n [k in string]: string;\n }>(\n columnQuestions.map(({ name }) => {\n const matches = fuzzyMatchColumns(columnNames, name, false);\n return {\n name,\n message: `Choose the column that will be used to map in the attribute: ${name}`,\n type: 'list',\n default: matches[0],\n choices: matches,\n };\n }),\n );\n await Promise.all(\n Object.entries(attributeNameMap).map(([k, v]) =>\n state.setValue(v, 'attributeNames', k),\n ),\n );\n\n return {\n ...state.getValue('attributeNames'),\n ...attributeNameMap,\n };\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","/* eslint-disable max-lines */\nimport colors from 'colors';\nimport { map } from '../bluebird-replace';\nimport * as t from 'io-ts';\nimport { uniq } from 'lodash-es';\nimport cliProgress from 'cli-progress';\nimport { join } from 'path';\nimport { PersistedState } from '@transcend-io/persisted-state';\nimport { logger } from '../../logger';\nimport {\n createSombraGotInstance,\n buildTranscendGraphQLClient,\n fetchAllRequestAttributeKeys,\n} from '../graphql';\nimport { mapRequestEnumValues } from './mapRequestEnumValues';\nimport { CachedRequestState, CachedFileState } from './constants';\nimport { mapCsvColumnsToApi } from './mapCsvColumnsToApi';\nimport { parseAttributesFromString } from './parseAttributesFromString';\nimport { readCsv } from './readCsv';\nimport { submitPrivacyRequest } from './submitPrivacyRequest';\nimport { mapColumnsToAttributes } from './mapColumnsToAttributes';\nimport { mapColumnsToIdentifiers } from './mapColumnsToIdentifiers';\nimport { mapCsvRowsToRequestInputs } from './mapCsvRowsToRequestInputs';\nimport { filterRows } from './filterRows';\nimport { extractClientError } from './extractClientError';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Upload a set of privacy requests from CSV\n *\n * @param options - Options\n */\nexport async function uploadPrivacyRequestsFromCsv({\n cacheFilepath,\n requestReceiptFolder,\n file,\n auth,\n sombraAuth,\n concurrency = 100,\n defaultPhoneCountryCode = '1', // USA\n transcendUrl = DEFAULT_TRANSCEND_API,\n attributes = [],\n emailIsVerified = true,\n skipFilterStep = false,\n skipSendingReceipt = true,\n isTest = false,\n isSilent = true,\n debug = false,\n dryRun = false,\n}: {\n /** File to cache metadata about mapping of CSV shape to script */\n cacheFilepath: string;\n /** File where request receipts are stored */\n requestReceiptFolder: string;\n /** CSV file path */\n file: string;\n /** Transcend API key authentication */\n auth: string;\n /** Default country code for phone numbers */\n defaultPhoneCountryCode?: string;\n /** Concurrency to upload in */\n concurrency?: number;\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** Sombra API key authentication */\n sombraAuth?: string;\n /** Include debug logs */\n debug?: boolean;\n /** Skip the step where requests are filtered */\n skipFilterStep?: boolean;\n /** Whether test requests are being uploaded */\n isTest?: boolean;\n /** Whether requests are uploaded in silent mode */\n isSilent?: boolean;\n /** Whether to send the email receipt */\n skipSendingReceipt?: boolean;\n /** Whether the email was verified up front */\n emailIsVerified?: boolean;\n /** Attributes string pre-parse */\n attributes?: string[];\n /** Whether a dry run is happening */\n dryRun?: boolean;\n}): Promise<void> {\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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Parse out the extra attributes to apply to all requests uploaded\n const parsedAttributes = parseAttributesFromString(attributes);\n\n // Create a new state to persist the metadata that\n // maps the request inputs to the Transcend API shape\n const state = new PersistedState(cacheFilepath, CachedFileState, {\n columnNames: {},\n requestTypeToRequestAction: {},\n subjectTypeToSubjectName: {},\n languageToLocale: {},\n statusToRequestStatus: {},\n identifierNames: {},\n attributeNames: {},\n regionToCountrySubDivision: {},\n regionToCountry: {},\n });\n\n // Create a new state file to store the requests from this run\n const requestCacheFile = join(\n requestReceiptFolder,\n `tr-request-upload-${new Date().toISOString()}-${file\n .split('/')\n .pop()}`.replace('.csv', '.json'),\n );\n const requestState = new PersistedState(\n requestCacheFile,\n CachedRequestState,\n {\n successfulRequests: [],\n duplicateRequests: [],\n failingRequests: [],\n },\n );\n\n // Create sombra instance to communicate with\n const sombra = await createSombraGotInstance(transcendUrl, auth, sombraAuth);\n\n // Read in the list of integration requests\n const requestsList = readCsv(file, t.record(t.string, t.string));\n const columnNames = uniq(requestsList.map((x) => Object.keys(x)).flat());\n\n // Log out an example request\n if (requestsList.length === 0) {\n throw new Error(\n 'No Requests found in list! Ensure the first row of the CSV is a header and the rest are requests.',\n );\n }\n if (debug) {\n const firstRequest = requestsList[0];\n logger.info(\n colors.magenta(`First request: ${JSON.stringify(firstRequest, null, 2)}`),\n );\n }\n // Determine what rows in the CSV should be imported\n // Choose columns that contain metadata to filter the requests\n const filteredRequestList = skipFilterStep\n ? requestsList\n : await filterRows(requestsList);\n\n // Build a GraphQL client\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n // Grab the request attributes\n const requestAttributeKeys = await fetchAllRequestAttributeKeys(client);\n // Determine the columns that should be mapped\n const columnNameMap = await mapCsvColumnsToApi(columnNames, state);\n const identifierNameMap = await mapColumnsToIdentifiers(\n client,\n columnNames,\n state,\n );\n const attributeNameMap = await mapColumnsToAttributes(\n client,\n columnNames,\n state,\n requestAttributeKeys,\n );\n await mapRequestEnumValues(client, filteredRequestList, {\n state,\n columnNameMap,\n });\n\n // map the CSV to request input\n const requestInputs = mapCsvRowsToRequestInputs(filteredRequestList, state, {\n defaultPhoneCountryCode,\n columnNameMap,\n identifierNameMap,\n attributeNameMap,\n requestAttributeKeys,\n });\n\n // start the progress bar with a total value of 200 and start value of 0\n if (!debug) {\n progressBar.start(requestInputs.length, 0);\n }\n let total = 0;\n // Submit each request\n await map(\n requestInputs,\n async ([rawRow, requestInput], ind) => {\n // The identifier to log, only include personal data if debug mode is on\n const requestLogId = debug\n ? `email:${requestInput.email} | coreIdentifier:${requestInput.coreIdentifier}`\n : `row:${ind.toString()}`;\n\n if (debug) {\n logger.info(\n colors.magenta(\n `[${ind + 1}/${requestInputs.length}] Importing: ${JSON.stringify(\n requestInput,\n null,\n 2,\n )}`,\n ),\n );\n }\n\n // Skip on dry run\n if (dryRun) {\n logger.info(\n colors.magenta('Bailing out on dry run because dryRun is set'),\n );\n return;\n }\n\n try {\n // Make the GraphQL request to submit the privacy request\n const requestResponse = await submitPrivacyRequest(\n sombra,\n requestInput,\n {\n details: `Uploaded by Transcend Cli: \"tr-request-upload\" : ${JSON.stringify(\n rawRow,\n null,\n 2,\n )}`,\n isTest,\n emailIsVerified,\n skipSendingReceipt,\n isSilent,\n additionalAttributes: parsedAttributes,\n },\n );\n\n // Log success\n if (debug) {\n logger.info(\n colors.green(\n `[${ind + 1}/${\n requestInputs.length\n }] Successfully submitted the test data subject request: \"${requestLogId}\"`,\n ),\n );\n logger.info(\n colors.green(\n `[${ind + 1}/${requestInputs.length}] View it at: \"${\n requestResponse.link\n }\"`,\n ),\n );\n }\n\n // Cache successful upload\n const successfulRequests = requestState.getValue('successfulRequests');\n successfulRequests.push({\n id: requestResponse.id,\n link: requestResponse.link,\n rowIndex: ind,\n coreIdentifier: requestResponse.coreIdentifier,\n attemptedAt: new Date().toISOString(),\n });\n await requestState.setValue(successfulRequests, 'successfulRequests');\n } catch (err) {\n const msg = `${err.message} - ${JSON.stringify(\n err.response?.body,\n null,\n 2,\n )}`;\n const clientError = extractClientError(msg);\n\n if (\n clientError === 'Client error: You have already made this request.'\n ) {\n if (debug) {\n logger.info(\n colors.yellow(\n `[${ind + 1}/${\n requestInputs.length\n }] Skipping request as it is a duplicate`,\n ),\n );\n }\n const duplicateRequests = requestState.getValue('duplicateRequests');\n duplicateRequests.push({\n coreIdentifier: requestInput.coreIdentifier,\n rowIndex: ind,\n attemptedAt: new Date().toISOString(),\n });\n await requestState.setValue(duplicateRequests, 'duplicateRequests');\n } else {\n const failingRequests = requestState.getValue('failingRequests');\n failingRequests.push({\n ...requestInput,\n rowIndex: ind,\n error: clientError || msg,\n attemptedAt: new Date().toISOString(),\n });\n await requestState.setValue(failingRequests, 'failingRequests');\n if (debug) {\n logger.error(colors.red(clientError || msg));\n logger.error(\n colors.red(\n `[${ind + 1}/${\n requestInputs.length\n }] Failed to submit request for: \"${requestLogId}\"`,\n ),\n );\n }\n }\n }\n\n total += 1;\n if (!debug) {\n progressBar.update(total);\n }\n },\n {\n concurrency,\n },\n );\n\n progressBar.stop();\n const t1 = new Date().getTime();\n const totalTime = t1 - t0;\n\n // Log completion time\n logger.info(\n colors.green(`Completed upload in \"${totalTime / 1000}\" seconds.`),\n );\n\n // Log duplicates\n if (requestState.getValue('duplicateRequests').length > 0) {\n logger.info(\n colors.yellow(\n `Encountered \"${\n requestState.getValue('duplicateRequests').length\n }\" duplicate requests. ` +\n `See \"${requestCacheFile}\" to review the core identifiers for these requests.`,\n ),\n );\n }\n\n // Log errors\n if (requestState.getValue('failingRequests').length > 0) {\n logger.error(\n colors.red(\n `Encountered \"${\n requestState.getValue('failingRequests').length\n }\" errors. ` +\n `See \"${requestCacheFile}\" to review the error messages and inputs.`,\n ),\n );\n process.exit(1);\n }\n}\n/* eslint-enable max-lines */\n","import * as t from 'io-ts';\nimport { groupBy } from 'lodash-es';\nimport { apply, decodeCodec } from '@transcend-io/type-utils';\nimport { IdentifierType } from '@transcend-io/privacy-types';\nimport type { Got } from 'got';\nimport { PrivacyRequest, RequestIdentifier } from '../graphql';\nimport { IDENTIFIER_BLOCK_LIST } from './constants';\nimport { PrivacyRequestResponse } from './submitPrivacyRequest';\n\n/**\n * Restart a privacy request to the Transcend API\n *\n * @param sombra - Sombra instance configured to make requests\n * @param request - Request to restart\n * @param input - Request input\n * @returns Successfully submitted request\n */\nexport async function restartPrivacyRequest(\n sombra: Got,\n request: PrivacyRequest,\n {\n sendEmailReceipt = false,\n skipWaitingPeriod = false,\n emailIsVerified = true,\n requestIdentifiers = [],\n }: {\n /** List of request identifiers to include */\n requestIdentifiers?: RequestIdentifier[];\n /** When true, send an email receipt to data subject */\n sendEmailReceipt?: boolean;\n /** Whether the email is verified */\n emailIsVerified?: boolean;\n /** Whether to skip waiting period */\n skipWaitingPeriod?: boolean;\n } = {},\n): Promise<PrivacyRequestResponse> {\n // Make the GraphQL request\n const response = await sombra\n .post('v1/data-subject-request', {\n json: {\n type: request.type,\n subject: {\n coreIdentifier: request.coreIdentifier,\n email: request.email,\n emailIsVerified,\n ...(requestIdentifiers.length > 0\n ? {\n attestedExtraIdentifiers: apply(\n groupBy(\n requestIdentifiers\n .filter(\n (ri) =>\n // these are already submitted above\n !(\n ri.name === 'email' && ri.value === request.email\n ) && !IDENTIFIER_BLOCK_LIST.includes(ri.name),\n )\n .map((ri) => ({\n ...ri,\n type: Object.values(IdentifierType).includes(\n ri.name as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n )\n ? ri.name\n : IdentifierType.Custom,\n })),\n 'type',\n ),\n (values, type) =>\n values.map(({ name, value }) => ({\n ...(type === IdentifierType.Custom ? { name } : {}),\n value,\n })),\n ),\n }\n : {}),\n },\n requestId: request.id,\n subjectType: request.subjectType,\n isSilent: request.isSilent,\n isTest: request.isTest,\n locale: request.locale,\n skipWaitingPeriod,\n createdAt: request.createdAt,\n details: `Restarted by Transcend cli: \"tr-request-restart\" - ${request.details}`,\n skipSendingReceipt: !sendEmailReceipt,\n },\n })\n .json();\n\n const { request: requestResponse } = decodeCodec(\n t.type({\n request: PrivacyRequestResponse,\n }),\n response,\n );\n return requestResponse;\n}\n","import { PersistedState } from '@transcend-io/persisted-state';\nimport { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport { map } from '../bluebird-replace';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\nimport * as t from 'io-ts';\nimport { difference } from 'lodash-es';\nimport { join } from 'path';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\nimport {\n buildTranscendGraphQLClient,\n createSombraGotInstance,\n fetchAllRequestIdentifiers,\n fetchAllRequests,\n} from '../graphql';\nimport { logger } from '../../logger';\nimport { SuccessfulRequest } from './constants';\nimport { extractClientError } from './extractClientError';\nimport { restartPrivacyRequest } from './restartPrivacyRequest';\n\n/** Minimal state we need to keep a list of requests */\nconst ErrorRequest = t.intersection([\n SuccessfulRequest,\n t.type({\n error: t.string,\n }),\n]);\n\n/** Type override */\ntype ErrorRequest = t.TypeOf<typeof ErrorRequest>;\n\n/** Persist this data between runs of the script */\nconst CachedRequestState = t.type({\n restartedRequests: t.array(SuccessfulRequest),\n failingRequests: t.array(ErrorRequest),\n});\n\n/**\n * Upload a set of privacy requests from CSV\n *\n * @param options - Options\n */\nexport async function bulkRestartRequests({\n requestReceiptFolder,\n auth,\n sombraAuth,\n requestActions,\n requestStatuses,\n createdAtBefore,\n createdAtAfter,\n transcendUrl = DEFAULT_TRANSCEND_API,\n requestIds = [],\n createdAt = new Date(),\n silentModeBefore,\n sendEmailReceipt = false,\n emailIsVerified = true,\n copyIdentifiers = false,\n skipWaitingPeriod = false,\n concurrency = 20,\n}: {\n /** Actions to filter for */\n requestActions: RequestAction[];\n /** Statues to filter for */\n requestStatuses: RequestStatus[];\n /** File where request receipts are stored */\n requestReceiptFolder: string;\n /** Transcend API key authentication */\n auth: string;\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** Sombra API key authentication */\n sombraAuth?: string;\n /** Request IDs to filter for */\n requestIds?: string[];\n /** Whether to re-verify the email when restarting the request */\n emailIsVerified?: boolean;\n /** Filter for requests that were submitted before this date */\n createdAt?: Date;\n /** Requests that have been open for this length of time should be marked as silent mode */\n silentModeBefore?: Date;\n /** Send an email receipt to the restarted requests */\n sendEmailReceipt?: boolean;\n /** Copy over all identifiers rather than restarting the request only with the core identifier */\n copyIdentifiers?: boolean;\n /** Skip the waiting period when restarting requests */\n skipWaitingPeriod?: boolean;\n /** Filter for requests created before this date */\n createdAtBefore?: Date;\n /** Filter for requests created after this date */\n createdAtAfter?: Date;\n /** Concurrency to upload requests at */\n concurrency?: number;\n}): Promise<void> {\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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Create a new state file to store the requests from this run\n const cacheFile = join(\n requestReceiptFolder,\n `tr-request-restart-${new Date().toISOString()}`,\n );\n const state = new PersistedState(cacheFile, CachedRequestState, {\n restartedRequests: [],\n failingRequests: [],\n });\n\n // Create sombra instance to communicate with\n const sombra = await createSombraGotInstance(transcendUrl, auth, sombraAuth);\n\n // Find all requests made before createdAt that are in a removing data state\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n const allRequests = await fetchAllRequests(client, {\n actions: requestActions,\n statuses: requestStatuses,\n createdAtBefore,\n createdAtAfter,\n });\n const requests = allRequests.filter(\n (request) => new Date(request.createdAt) < createdAt,\n );\n logger.info(`Found ${requests.length} requests to process`);\n\n if (copyIdentifiers) {\n logger.info('copyIdentifiers detected - All Identifiers will be copied.');\n }\n if (sendEmailReceipt) {\n logger.info('sendEmailReceipt detected - Email receipts will be sent.');\n }\n if (skipWaitingPeriod) {\n logger.info('skipWaitingPeriod detected - Waiting period will be skipped.');\n }\n\n // Validate request IDs\n if (requestIds.length > 0 && requestIds.length !== requests.length) {\n const missingRequests = difference(\n requestIds,\n requests.map(({ id }) => id),\n );\n if (missingRequests.length > 0) {\n logger.error(\n colors.red(\n `Failed to find the following requests by ID: ${missingRequests.join(\n ',',\n )}.`,\n ),\n );\n process.exit(1);\n }\n }\n\n // Map over the requests\n let total = 0;\n progressBar.start(requests.length, 0);\n await map(\n requests,\n async (request, ind) => {\n try {\n // Pull the request identifiers\n const requestIdentifiers = copyIdentifiers\n ? await fetchAllRequestIdentifiers(client, sombra, {\n requestId: request.id,\n })\n : [];\n\n // Make the GraphQL request to restart the request\n const requestResponse = await restartPrivacyRequest(\n sombra,\n {\n ...request,\n // override silent mode\n isSilent:\n !!silentModeBefore &&\n new Date(request.createdAt) < silentModeBefore\n ? true\n : request.isSilent,\n },\n {\n requestIdentifiers,\n skipWaitingPeriod,\n sendEmailReceipt,\n emailIsVerified,\n },\n );\n\n // Cache successful upload\n const restartedRequests = state.getValue('restartedRequests');\n restartedRequests.push({\n id: requestResponse.id,\n link: requestResponse.link,\n rowIndex: ind,\n coreIdentifier: requestResponse.coreIdentifier,\n attemptedAt: new Date().toISOString(),\n });\n await state.setValue(restartedRequests, 'restartedRequests');\n } catch (err) {\n const msg = `${err.message} - ${JSON.stringify(\n err.response?.body,\n null,\n 2,\n )}`;\n const clientError = extractClientError(msg);\n\n const failingRequests = state.getValue('failingRequests');\n failingRequests.push({\n id: request.id,\n link: request.link,\n rowIndex: ind,\n coreIdentifier: request.coreIdentifier,\n attemptedAt: new Date().toISOString(),\n error: clientError || msg,\n });\n await state.setValue(failingRequests, 'failingRequests');\n }\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 // Log completion time\n logger.info(\n colors.green(\n `Completed restarting of requests in \"${totalTime / 1000}\" seconds.`,\n ),\n );\n\n // Log errors\n if (state.getValue('failingRequests').length > 0) {\n logger.error(\n colors.red(\n `Encountered \"${state.getValue('failingRequests').length}\" errors. ` +\n `See \"${cacheFile}\" to review the error messages and inputs.`,\n ),\n );\n process.exit(1);\n }\n}\n","import { mapSeries, map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport {\n makeGraphQLRequest,\n buildTranscendGraphQLClient,\n fetchAllRequestEnrichers,\n fetchAllRequests,\n SKIP_REQUEST_ENRICHER,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport {\n RequestEnricherStatus,\n RequestStatus,\n} from '@transcend-io/privacy-types';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Given an enricher ID, mark all open request enrichers as skipped\n *\n * @param options - Options\n * @returns Number of items skipped\n */\nexport async function skipPreflightJobs({\n enricherIds,\n auth,\n concurrency = 100,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** Transcend API key authentication */\n auth: string;\n /** Enricher IDs to pull down jobs for */\n enricherIds: string[];\n /** Upload concurrency */\n concurrency?: number;\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** Request statuses to mark as completed */\n requestStatuses?: RequestStatus[];\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 // Time duration\n const t0 = new Date().getTime();\n\n // fetch all RequestDataSilos that are open\n const requests = await fetchAllRequests(client, {\n statuses: [RequestStatus.Enriching],\n });\n\n // Notify Transcend\n logger.info(\n colors.magenta(\n `Processing enricher: \"${enricherIds.join(',')}\" fetched \"${\n requests.length\n }\" in enriching status.`,\n ),\n );\n\n // create a new progress bar instance and use shades_classic theme\n const progressBar = new cliProgress.SingleBar(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n let total = 0;\n progressBar.start(requests.length, 0);\n let totalSkipped = 0;\n await map(\n requests,\n async (request) => {\n // FIXME dont pull all in\n const requestEnrichers = await fetchAllRequestEnrichers(client, {\n requestId: request.id,\n });\n const requestEnrichersFiltered = requestEnrichers.filter(\n (enricher) =>\n enricherIds.includes(enricher.enricher.id) &&\n ![\n RequestEnricherStatus.Resolved,\n RequestEnricherStatus.Skipped,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ].includes(enricher.status as any),\n );\n\n // FIXME\n if (requestEnrichersFiltered.length > 0) {\n await mapSeries(requestEnrichersFiltered, async (requestEnricher) => {\n try {\n await makeGraphQLRequest<{\n /** Whether we successfully uploaded the results */\n success: boolean;\n }>(client, SKIP_REQUEST_ENRICHER, {\n requestEnricherId: requestEnricher.id,\n });\n totalSkipped += 1;\n } catch (err) {\n if (\n !err.message.includes(\n 'Client error: Cannot skip Request enricher because it has already completed',\n )\n ) {\n throw err;\n }\n }\n });\n }\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(\n `Successfully skipped \"${totalSkipped}\" for \"${\n requests.length\n }\" requests in \"${totalTime / 1000}\" seconds!`,\n ),\n );\n return requests.length;\n}\n","import {\n RequestAction,\n RequestEnricherStatus,\n RequestStatus,\n} from '@transcend-io/privacy-types';\nimport { map } from '../bluebird-replace';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\nimport { difference } from 'lodash-es';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\nimport {\n buildTranscendGraphQLClient,\n fetchAllRequestEnrichers,\n fetchAllRequests,\n retryRequestEnricher,\n} from '../graphql';\nimport { logger } from '../../logger';\n\n/**\n * Restart a bunch of request enrichers\n *\n * @param options - Options\n */\nexport async function bulkRetryEnrichers({\n auth,\n requestActions = [],\n createdAtBefore,\n createdAtAfter,\n transcendUrl = DEFAULT_TRANSCEND_API,\n requestEnricherStatuses = Object.values(RequestEnricherStatus),\n requestIds = [],\n enricherId,\n concurrency = 20,\n}: {\n /** Actions to filter for */\n requestActions?: RequestAction[];\n /** Request enricher statuses to restart - defaults to all statuses */\n requestEnricherStatuses?: RequestEnricherStatus[];\n /** Transcend API key authentication */\n auth: string;\n /** The ID of the enricher to restart */\n enricherId: string;\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** Request IDs to filter for */\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 /** Concurrency to upload requests at */\n concurrency?: number;\n}): Promise<void> {\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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Find all requests made before createdAt that are in a removing data state\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n logger.info(colors.magenta('Fetching requests to restart...'));\n\n const requests = await fetchAllRequests(client, {\n actions: requestActions,\n statuses: [RequestStatus.Enriching],\n createdAtBefore,\n createdAtAfter,\n requestIds,\n });\n\n let totalRestarted = 0;\n\n // Validate request IDs\n if (requestIds.length > 0 && requestIds.length !== requests.length) {\n const missingRequests = difference(\n requestIds,\n requests.map(({ id }) => id),\n );\n if (missingRequests.length > 0) {\n logger.error(\n colors.red(\n `Failed to find the following requests by ID: ${missingRequests.join(\n ',',\n )}.`,\n ),\n );\n process.exit(1);\n }\n }\n\n // Map over the requests\n let total = 0;\n progressBar.start(requests.length, 0);\n await map(\n requests,\n async (request) => {\n // Pull the request identifiers\n const requestEnrichers = await fetchAllRequestEnrichers(client, {\n requestId: request.id,\n });\n const requestEnrichersToRestart = requestEnrichers.filter(\n (requestEnricher) =>\n requestEnricher.enricher.id === enricherId &&\n requestEnricherStatuses.includes(requestEnricher.status),\n );\n await map(requestEnrichersToRestart, async (requestEnricher) => {\n await retryRequestEnricher(client, requestEnricher.id);\n totalRestarted += 1;\n });\n\n // Cache successful upload\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 // Log completion time\n logger.info(\n colors.green(\n `Completed restarting of ${\n requests.length\n } requests and ${totalRestarted} enrichers in \"${\n totalTime / 1000\n }\" seconds.`,\n ),\n );\n}\n","import { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport {\n RETRY_REQUEST_DATA_SILO,\n fetchRequestDataSilo,\n fetchAllRequests,\n makeGraphQLRequest,\n buildTranscendGraphQLClient,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Retry a set of RequestDataSilos\n *\n * @param options - Options\n * @returns Number of items marked as completed\n */\nexport async function retryRequestDataSilos({\n requestActions,\n dataSiloId,\n auth,\n concurrency = 20,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** The request actions that should be restarted */\n requestActions: RequestAction[];\n /** Transcend API key authentication */\n auth: string;\n /** Data Silo ID to pull down jobs for */\n dataSiloId: string;\n /** Concurrency to upload requests in parallel */\n concurrency?: number;\n /** API URL for Transcend backend */\n transcendUrl?: string;\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 // 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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Pull in the requests\n const allRequests = await fetchAllRequests(client, {\n actions: requestActions,\n statuses: [RequestStatus.Compiling, RequestStatus.Approving],\n });\n\n // Notify Transcend\n logger.info(\n colors.magenta(\n `Retrying requests for Data Silo: \"${dataSiloId}\", restarting \"${allRequests.length}\" requests.`,\n ),\n );\n\n let total = 0;\n let skipped = 0;\n progressBar.start(allRequests.length, 0);\n await map(\n allRequests,\n async (requestToRestart) => {\n try {\n const requestDataSilo = await fetchRequestDataSilo(client, {\n requestId: requestToRestart.id,\n dataSiloId,\n });\n\n await makeGraphQLRequest<{\n /** Whether we successfully uploaded the results */\n success: boolean;\n }>(client, RETRY_REQUEST_DATA_SILO, {\n requestDataSiloId: requestDataSilo.id,\n });\n } catch (err) {\n // some requests may not have this data silo connected\n if (!err.message.includes('Failed to find RequestDataSilo')) {\n throw err;\n }\n skipped += 1;\n }\n\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(\n `Successfully notified Transcend in \"${\n totalTime / 1000\n }\" seconds for ${total} requests, ${skipped} requests were skipped because data silo was not attached to the request!`,\n ),\n );\n return allRequests.length;\n}\n","import { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { groupBy } from 'lodash-es';\n\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\nimport {\n PrivacyRequest,\n RequestIdentifier,\n buildTranscendGraphQLClient,\n createSombraGotInstance,\n fetchAllRequestIdentifiers,\n fetchAllRequests,\n} from '../graphql';\nimport { logger } from '../../logger';\n\nexport interface ExportedPrivacyRequest extends PrivacyRequest {\n /** Request identifiers */\n requestIdentifiers: RequestIdentifier[];\n}\n\n/**\n * Pull down a list of privacy requests\n *\n * @param options - Options\n * @returns The requests with request identifiers and requests formatted for CSV\n */\nexport async function pullPrivacyRequests({\n auth,\n sombraAuth,\n actions = [],\n statuses = [],\n identifierSearch,\n pageLimit = 100,\n transcendUrl = DEFAULT_TRANSCEND_API,\n createdAtBefore,\n createdAtAfter,\n isTest,\n}: {\n /** Transcend API key authentication */\n auth: string;\n /** Search for a specific identifier */\n identifierSearch?: string;\n /** Sombra API key authentication */\n sombraAuth?: string;\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** Statuses to filter on */\n statuses?: RequestStatus[];\n /** The request action to fetch */\n actions?: RequestAction[];\n /** Page limit when fetching requests */\n pageLimit?: number;\n /** Filter for requests created before this date */\n createdAtBefore?: Date;\n /** Filter for requests created after this date */\n createdAtAfter?: Date;\n /** Return test requests */\n isTest?: boolean;\n}): Promise<{\n /** All request information with attached identifiers */\n requestsWithRequestIdentifiers: ExportedPrivacyRequest[];\n /** Requests that are formatted for CSV */\n requestsFormattedForCsv: {\n [k in string]: string | null | number | boolean;\n }[];\n}> {\n // Find all requests made before createdAt that are in a removing data state\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n const sombra = await createSombraGotInstance(transcendUrl, auth, sombraAuth);\n\n // Log date range\n let dateRange = '';\n if (createdAtBefore) {\n dateRange += ` before ${createdAtBefore.toISOString()}`;\n }\n if (createdAtAfter) {\n dateRange += `${\n dateRange ? ', and' : ''\n } after ${createdAtAfter.toISOString()}`;\n }\n\n // Log out\n logger.info(\n colors.magenta(\n `${\n actions.length > 0\n ? `Pulling requests of type \"${actions.join('\" , \"')}\"`\n : 'Pulling all requests'\n }${dateRange}`,\n ),\n );\n\n // fetch the requests\n const requests = await fetchAllRequests(client, {\n actions,\n text: identifierSearch,\n statuses,\n createdAtBefore,\n createdAtAfter,\n isTest,\n });\n\n // Fetch the request identifiers for those requests\n const requestsWithRequestIdentifiers = await map(\n requests,\n async (request) => {\n const requestIdentifiers = await fetchAllRequestIdentifiers(\n client,\n sombra,\n {\n requestId: request.id,\n },\n );\n return {\n ...request,\n requestIdentifiers,\n };\n },\n {\n concurrency: pageLimit,\n },\n );\n\n logger.info(\n colors.magenta(`Pulled ${requestsWithRequestIdentifiers.length} requests`),\n );\n\n // Write out to CSV\n const data = requestsWithRequestIdentifiers.map(\n ({\n attributeValues,\n requestIdentifiers,\n id,\n email,\n type,\n status,\n subjectType,\n details,\n createdAt,\n country,\n locale,\n origin,\n countrySubDivision,\n isSilent,\n isTest,\n coreIdentifier,\n ...request\n }) => ({\n 'Request ID': id,\n 'Created At': createdAt,\n Email: email,\n 'Core Identifier': coreIdentifier,\n 'Request Type': type,\n 'Data Subject Type': subjectType,\n Status: status,\n Country: country,\n 'Country Sub Division': countrySubDivision,\n Details: details,\n Origin: origin,\n 'Silent Mode': isSilent,\n 'Is Test Request': isTest,\n Language: locale,\n ...request,\n ...Object.entries(groupBy(attributeValues, 'attributeKey.name')).reduce(\n (acc, [name, values]) =>\n Object.assign(acc, {\n [name]: values.map(({ name }) => name).join(','),\n }),\n {},\n ),\n ...Object.entries(groupBy(requestIdentifiers, 'name')).reduce(\n (acc, [name, values]) =>\n Object.assign(acc, {\n [name]: values.map(({ value }) => value).join(','),\n }),\n {},\n ),\n }),\n );\n\n return { requestsWithRequestIdentifiers, requestsFormattedForCsv: data };\n}\n","import { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport {\n CHANGE_REQUEST_DATA_SILO_STATUS,\n makeGraphQLRequest,\n buildTranscendGraphQLClient,\n fetchRequestDataSilos,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport { RequestStatus } from '@transcend-io/privacy-types';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Given a data silo ID, mark all open request data silos as skipped\n *\n * @param options - Options\n * @returns Number of items skipped\n */\nexport async function skipRequestDataSilos({\n dataSiloId,\n auth,\n concurrency = 100,\n status = 'SKIPPED',\n transcendUrl = DEFAULT_TRANSCEND_API,\n requestStatuses = [RequestStatus.Compiling, RequestStatus.Secondary],\n}: {\n /** Transcend API key authentication */\n auth: string;\n /** Data Silo ID to pull down jobs for */\n dataSiloId: string;\n /** Status to set */\n status?: 'SKIPPED' | 'RESOLVED';\n /** Upload concurrency */\n concurrency?: number;\n /** API URL for Transcend backend */\n transcendUrl?: string;\n /** Request statuses to mark as completed */\n requestStatuses?: RequestStatus[];\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 // Time duration\n const t0 = new Date().getTime();\n\n // fetch all RequestDataSilos that are open\n const requestDataSilos = await fetchRequestDataSilos(client, {\n dataSiloId,\n requestStatuses,\n });\n\n // Notify Transcend\n logger.info(\n colors.magenta(\n `Processing data silo: \"${dataSiloId}\" marking \"${requestDataSilos.length}\" requests as skipped.`,\n ),\n );\n\n // create a new progress bar instance and use shades_classic theme\n const progressBar = new cliProgress.SingleBar(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n let total = 0;\n progressBar.start(requestDataSilos.length, 0);\n await map(\n requestDataSilos,\n async (requestDataSilo) => {\n try {\n await makeGraphQLRequest<{\n /** Whether we successfully uploaded the results */\n success: boolean;\n }>(client, CHANGE_REQUEST_DATA_SILO_STATUS, {\n requestDataSiloId: requestDataSilo.id,\n status,\n });\n } catch (err) {\n if (!err.message.includes('Client error: Request must be active:')) {\n throw err;\n }\n }\n\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(\n `Successfully skipped \"${requestDataSilos.length}\" requests in \"${\n totalTime / 1000\n }\" seconds!`,\n ),\n );\n return requestDataSilos.length;\n}\n","import { map } from '../bluebird-replace';\nimport colors from 'colors';\nimport { logger } from '../../logger';\nimport { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport {\n REMOVE_REQUEST_IDENTIFIERS,\n fetchAllRequests,\n fetchAllRequestIdentifierMetadata,\n makeGraphQLRequest,\n buildTranscendGraphQLClient,\n} from '../graphql';\nimport cliProgress from 'cli-progress';\nimport { DEFAULT_TRANSCEND_API } from '../../constants';\n\n/**\n * Remove a set of unverified request identifier\n *\n * @param options - Options\n * @returns Number of items marked as completed\n */\nexport async function removeUnverifiedRequestIdentifiers({\n requestActions,\n identifierNames,\n auth,\n concurrency = 20,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** The request actions that should be restarted */\n requestActions: RequestAction[];\n /** Transcend API key authentication */\n auth: string;\n /** The set of identifier names to remove */\n identifierNames: string[];\n /** Concurrency to upload requests in parallel */\n concurrency?: number;\n /** API URL for Transcend backend */\n transcendUrl?: string;\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 // 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(\n {},\n cliProgress.Presets.shades_classic,\n );\n\n // Pull in the requests\n const allRequests = await fetchAllRequests(client, {\n actions: requestActions,\n statuses: [RequestStatus.Enriching],\n });\n\n // Notify Transcend\n logger.info(colors.magenta('Fetched requests in preflight/enriching state.'));\n\n let total = 0;\n let processed = 0;\n progressBar.start(allRequests.length, 0);\n await map(\n allRequests,\n async (requestToRestart) => {\n const requestIdentifiers = await fetchAllRequestIdentifierMetadata(\n client,\n { requestId: requestToRestart.id },\n );\n const clearOut = requestIdentifiers\n .filter(\n ({ isVerifiedAtLeastOnce, name }) =>\n isVerifiedAtLeastOnce === false && identifierNames.includes(name),\n )\n .map(({ id }) => id);\n\n if (clearOut.length > 0) {\n await makeGraphQLRequest<{\n /** Whether we successfully uploaded the results */\n success: boolean;\n }>(client, REMOVE_REQUEST_IDENTIFIERS, {\n input: {\n requestId: requestToRestart.id,\n requestIdentifierIds: clearOut,\n },\n });\n processed += clearOut.length;\n }\n\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(\n `Successfully cleared out unverified identifiers \"${\n totalTime / 1000\n }\" seconds for ${total} requests, ${processed} identifiers were cleared out!`,\n ),\n );\n return allRequests.length;\n}\n"],"mappings":"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","names":["applyEnum","valuesOf","LanguageKey","CompletedRequestStatus","RequestAction","IsoCountryCode","IsoCountrySubdivisionCode","t","NONE","BULK_APPLY","BLANK","IDENTIFIER_BLOCK_LIST","ColumnName","IS_REQUIRED","CAN_APPLY_IN_BULK","CachedFileState","SuccessfulRequest","CachedRequestState","inquirer","fuzzysearch","fuzzySearch","word1","word2","fuzzyMatchColumns","allColumnNames","fuzzyMapName","isRequired","canApplyAll","matchingColumnNames","x","inquirer","NONE","BULK_APPLY","inquirer","autoCompletePrompt","apply","mapEnumValues","csvInputs","expectedOutputs","cache","inquirer","autoCompletePrompt","inputs","item","value","result","x","fuzzySearch","answersSoFar","input","apply","r","splitCsvToList","value","x","colors","t","ParsedAttributeInput","parseAttributesFromString","attributes","parsedAttributes","attribute","attributeKey","attributeValuesRaw","attributeValues","logger","colors","parse","readFileSync","t","decodeCodec","readCsv","pathToFile","codec","options","fileContent","datum","acc","key","value","uniq","getUniqueValuesForColumn","rows","columnName","row","inquirer","colors","uniq","filterRows","rows","columnNames","uniq","x","filteredRows","keepFiltering","filterColumnName","inquirer","NONE","options","getUniqueValuesForColumn","valuesToKeep","request","logger","colors","colors","RequestStatus","cliProgress","markSilentPrivacyRequests","requestActions","auth","requestIds","statuses","RequestStatus","createdAtAfter","createdAtBefore","concurrency","transcendUrl","DEFAULT_TRANSCEND_API","client","buildTranscendGraphQLClient","t0","progressBar","cliProgress","allRequests","fetchAllRequests","logger","colors","total","map","requestToMarkSilent","makeGraphQLRequest","UPDATE_PRIVACY_REQUEST","totalTime","getValues","getEntries","inquirer","startCase","mapCsvColumnsToApi","columnNames","state","columnQuestions","getValues","ColumnName","name","columnNameMap","inquirer","field","startCase","matches","fuzzyMatchColumns","IS_REQUIRED","CAN_APPLY_IN_BULK","getEntries","k","v","colors","CompletedRequestStatus","RequestAction","IsoCountryCode","IsoCountrySubdivisionCode","LanguageKey","mapRequestEnumValues","client","requests","state","columnNameMap","getMappedName","attribute","internalSubjects","makeGraphQLRequest","DATA_SUBJECTS","logger","colors","requestTypeToRequestAction","mapEnumValues","getUniqueValuesForColumn","RequestAction","subjectTypeToSubjectName","type","languageToLocale","LanguageKey","requestStatusColumn","statusToRequestStatus","NONE","CompletedRequestStatus","countryColumn","regionToCountry","IsoCountryCode","countrySubDivisionColumn","regionToCountrySubDivision","IsoCountrySubdivisionCode","LanguageKey","DateFromISOString","t","NORMALIZE_PHONE_NUMBER","CompletedRequestStatus","RequestAction","IdentifierType","IsoCountryCode","IsoCountrySubdivisionCode","valuesOf","AttestedExtraIdentifiers","PrivacyRequestInput","valuesOf","RequestAction","IsoCountryCode","IsoCountrySubdivisionCode","ParsedAttributeInput","CompletedRequestStatus","DateFromISOString","LanguageKey","normalizeIdentifierValue","identifierValue","identifierType","defaultPhoneCountryCode","IdentifierType","normalized","NORMALIZE_PHONE_NUMBER","mapCsvRowsToRequestInputs","requestInputs","state","columnNameMap","identifierNameMap","attributeNameMap","requestAttributeKeys","getMappedName","attribute","input","attestedExtraIdentifiers","columnName","NONE","identifierName","attributes","attributeName","attributeValueString","isMulti","attr","splitCsvToList","requestTypeColumn","dataSubjectTypeColumn","BULK_APPLY","BLANK","colors","cliProgress","t","decodeCodec","valuesOf","TableEncryptionType","IntlMessage","RequestFileMetadata","valuesOf","RequestFileMetadataResponse","getFileMetadataForPrivacyRequests","requests","sombra","concurrency","limit","logger","colors","t0","progressBar","cliProgress","total","results","map","requestToDownload","localResults","shouldContinue","offset","response","rawResponse","decodeCodec","err","totalTime","colors","streamPrivacyRequestFiles","fileMetadata","requestId","sombra","onFileDownloaded","concurrency","map","metadata","fileResponse","err","logger","colors","existsSync","mkdirSync","writeFileSync","dirname","join","colors","RequestAction","RequestStatus","cliProgress","downloadPrivacyRequestFiles","auth","folderPath","requestIds","createdAtBefore","sombraAuth","createdAtAfter","statuses","RequestStatus","concurrency","transcendUrl","DEFAULT_TRANSCEND_API","approveAfterDownload","client","buildTranscendGraphQLClient","sombra","createSombraGotInstance","existsSync","mkdirSync","allRequests","fetchAllRequests","RequestAction","requestFileMetadata","getFileMetadataForPrivacyRequests","t0","progressBar","cliProgress","total","totalApproved","map","request","metadata","requestFolder","join","streamPrivacyRequestFiles","fil","stream","filePath","folder","dirname","writeFileSync","makeGraphQLRequest","APPROVE_PRIVACY_REQUEST","totalTime","logger","colors","t","uniq","valuesOf","decodeCodec","IsoCountryCode","IsoCountrySubdivisionCode","RequestAction","RequestStatus","PrivacyRequestResponse","submitPrivacyRequest","sombra","input","details","isTest","emailIsVerified","skipSendingReceipt","isSilent","additionalAttributes","mergedAttributes","attribute","existing","attr","response","err","requestResponse","colors","RequestStatus","cliProgress","approvePrivacyRequests","requestActions","requestOrigins","auth","silentModeBefore","createdAtAfter","createdAtBefore","concurrency","transcendUrl","DEFAULT_TRANSCEND_API","client","buildTranscendGraphQLClient","t0","progressBar","cliProgress","allRequests","fetchAllRequests","RequestStatus","logger","colors","total","skipped","map","requestToApprove","makeGraphQLRequest","UPDATE_PRIVACY_REQUEST","APPROVE_PRIVACY_REQUEST","err","totalTime","colors","RequestAction","cliProgress","notifyPrivacyRequestsAdditionalTime","requestActions","RequestAction","auth","requestIds","createdAtBefore","days","daysLeft","createdAtAfter","emailTemplate","concurrency","transcendUrl","DEFAULT_TRANSCEND_API","client","buildTranscendGraphQLClient","t0","progressBar","cliProgress","exactTemplateMatch","fetchAllTemplates","template","allRequests","fetchAllRequests","request","logger","colors","total","map","requestToNotify","makeGraphQLRequest","NOTIFY_ADDITIONAL_TIME","totalTime","inquirer","mapColumnsToIdentifiers","client","columnNames","state","initializer","makeGraphQLRequest","INITIALIZER","columnQuestions","name","IDENTIFIER_BLOCK_LIST","identifierNameMap","inquirer","matches","fuzzyMatchColumns","k","v","colors","RequestStatus","cliProgress","cancelPrivacyRequests","requestActions","cancellationTitle","auth","requestIds","silentModeBefore","createdAtBefore","createdAtAfter","statuses","RequestStatus","concurrency","transcendUrl","DEFAULT_TRANSCEND_API","client","buildTranscendGraphQLClient","t0","progressBar","cliProgress","cancelationTemplate","exactTitleMatch","fetchAllTemplates","template","allRequests","fetchAllRequests","logger","colors","total","map","requestToCancel","makeGraphQLRequest","UPDATE_PRIVACY_REQUEST","CANCEL_PRIVACY_REQUEST","totalTime","inquirer","mapColumnsToAttributes","client","columnNames","state","requestAttributeKeys","columnQuestions","name","attributeNameMap","inquirer","matches","fuzzyMatchColumns","k","v","CLIENT_ERROR","extractClientError","err","colors","t","uniq","cliProgress","join","PersistedState","uploadPrivacyRequestsFromCsv","cacheFilepath","requestReceiptFolder","file","auth","sombraAuth","concurrency","defaultPhoneCountryCode","transcendUrl","DEFAULT_TRANSCEND_API","attributes","emailIsVerified","skipFilterStep","skipSendingReceipt","isTest","isSilent","debug","dryRun","t0","progressBar","cliProgress","parsedAttributes","parseAttributesFromString","state","PersistedState","CachedFileState","requestCacheFile","join","requestState","CachedRequestState","sombra","createSombraGotInstance","requestsList","readCsv","columnNames","uniq","x","firstRequest","logger","colors","filteredRequestList","filterRows","client","buildTranscendGraphQLClient","requestAttributeKeys","fetchAllRequestAttributeKeys","columnNameMap","mapCsvColumnsToApi","identifierNameMap","mapColumnsToIdentifiers","attributeNameMap","mapColumnsToAttributes","mapRequestEnumValues","requestInputs","mapCsvRowsToRequestInputs","total","map","rawRow","requestInput","ind","requestLogId","requestResponse","submitPrivacyRequest","successfulRequests","err","msg","clientError","extractClientError","duplicateRequests","failingRequests","totalTime","t","groupBy","apply","decodeCodec","IdentifierType","restartPrivacyRequest","sombra","request","sendEmailReceipt","skipWaitingPeriod","emailIsVerified","requestIdentifiers","response","apply","groupBy","ri","IDENTIFIER_BLOCK_LIST","IdentifierType","values","type","name","value","requestResponse","decodeCodec","PrivacyRequestResponse","PersistedState","cliProgress","colors","t","difference","join","ErrorRequest","SuccessfulRequest","CachedRequestState","bulkRestartRequests","requestReceiptFolder","auth","sombraAuth","requestActions","requestStatuses","createdAtBefore","createdAtAfter","transcendUrl","DEFAULT_TRANSCEND_API","requestIds","createdAt","silentModeBefore","sendEmailReceipt","emailIsVerified","copyIdentifiers","skipWaitingPeriod","concurrency","t0","progressBar","cliProgress","cacheFile","join","state","PersistedState","sombra","createSombraGotInstance","client","buildTranscendGraphQLClient","requests","fetchAllRequests","request","logger","missingRequests","difference","id","colors","total","map","ind","requestIdentifiers","fetchAllRequestIdentifiers","requestResponse","restartPrivacyRequest","restartedRequests","err","msg","clientError","extractClientError","failingRequests","totalTime","colors","cliProgress","RequestEnricherStatus","RequestStatus","skipPreflightJobs","enricherIds","auth","concurrency","transcendUrl","DEFAULT_TRANSCEND_API","client","buildTranscendGraphQLClient","t0","requests","fetchAllRequests","RequestStatus","logger","colors","progressBar","cliProgress","total","totalSkipped","map","request","requestEnrichersFiltered","fetchAllRequestEnrichers","enricher","RequestEnricherStatus","mapSeries","requestEnricher","makeGraphQLRequest","SKIP_REQUEST_ENRICHER","err","totalTime","RequestEnricherStatus","RequestStatus","cliProgress","colors","difference","bulkRetryEnrichers","auth","requestActions","createdAtBefore","createdAtAfter","transcendUrl","DEFAULT_TRANSCEND_API","requestEnricherStatuses","RequestEnricherStatus","requestIds","enricherId","concurrency","t0","progressBar","cliProgress","client","buildTranscendGraphQLClient","logger","colors","requests","fetchAllRequests","RequestStatus","totalRestarted","missingRequests","difference","id","total","map","request","requestEnrichersToRestart","fetchAllRequestEnrichers","requestEnricher","retryRequestEnricher","totalTime","colors","RequestStatus","cliProgress","retryRequestDataSilos","requestActions","dataSiloId","auth","concurrency","transcendUrl","DEFAULT_TRANSCEND_API","client","buildTranscendGraphQLClient","t0","progressBar","cliProgress","allRequests","fetchAllRequests","RequestStatus","logger","colors","total","skipped","map","requestToRestart","requestDataSilo","fetchRequestDataSilo","makeGraphQLRequest","RETRY_REQUEST_DATA_SILO","err","totalTime","colors","groupBy","pullPrivacyRequests","auth","sombraAuth","actions","statuses","identifierSearch","pageLimit","transcendUrl","DEFAULT_TRANSCEND_API","createdAtBefore","createdAtAfter","isTest","client","buildTranscendGraphQLClient","sombra","createSombraGotInstance","dateRange","logger","colors","requests","fetchAllRequests","requestsWithRequestIdentifiers","map","request","requestIdentifiers","fetchAllRequestIdentifiers","data","attributeValues","id","email","type","status","subjectType","details","createdAt","country","locale","origin","countrySubDivision","isSilent","coreIdentifier","groupBy","acc","name","values","value","colors","cliProgress","RequestStatus","skipRequestDataSilos","dataSiloId","auth","concurrency","status","transcendUrl","DEFAULT_TRANSCEND_API","requestStatuses","RequestStatus","client","buildTranscendGraphQLClient","t0","requestDataSilos","fetchRequestDataSilos","logger","colors","progressBar","cliProgress","total","map","requestDataSilo","makeGraphQLRequest","CHANGE_REQUEST_DATA_SILO_STATUS","err","totalTime","colors","RequestStatus","cliProgress","removeUnverifiedRequestIdentifiers","requestActions","identifierNames","auth","concurrency","transcendUrl","DEFAULT_TRANSCEND_API","client","buildTranscendGraphQLClient","t0","progressBar","cliProgress","allRequests","fetchAllRequests","RequestStatus","logger","colors","total","processed","map","requestToRestart","clearOut","fetchAllRequestIdentifierMetadata","isVerifiedAtLeastOnce","name","id","makeGraphQLRequest","REMOVE_REQUEST_IDENTIFIERS","totalTime"]}
@@ -0,0 +1,4 @@
1
+ import{c as u}from"./chunk-65I2PF73.js";import{a as E}from"./chunk-43JWXG77.js";import{readFileSync as b}from"fs";import{findAllWithRegex as F}from"@transcend-io/type-utils";import{CodePackageType as w}from"@transcend-io/privacy-types";var N=/target ('|")(.*?)('|")/,O=/pod ('|")(.*?)('|")(, ('|")~> (.+?)('|")|)/,y={supportedFiles:["Podfile"],ignoreDirs:["Pods"],scanFunction:e=>{let n=b(e,"utf-8"),o=F({value:new RegExp(N,"g"),matches:["quote1","name","quote2"]},n),c=F({value:new RegExp(O,"g"),matches:["quote1","name","quote2","extra","quote3","version","quote4"]},n);return o.map((t,p)=>({name:t.name,type:w.CocoaPods,softwareDevelopmentKits:c.filter(r=>r.matchIndex>t.matchIndex&&(!o[p+1]||r.matchIndex<o[p+1].matchIndex)).map(r=>({name:r.name,version:r.version}))}))}};import{readFileSync as T}from"fs";import{findAllWithRegex as l}from"@transcend-io/type-utils";import{dirname as h}from"path";var K=/implementation( *)('|")(.+?):(.+?):(.+?|)('|")/,M=/apply plugin: *('|")(.+?)(:(.+?)|)('|")/,j=/implementation group:( *)('|")(.+?)('|"),( *)name:( *)('|")(.+?)('|"),( *)version:( *)('|")(.+?)('|")/,L=/applicationId( *)"(.+?)"/,S={supportedFiles:["build.gradle**"],ignoreDirs:["gradle-app.setting","gradle-wrapper.jar","gradle-wrapper.properties"],scanFunction:e=>{let n=T(e,"utf-8"),o=h(e),c=l({value:new RegExp(K,"g"),matches:["space","quote1","name","path","version","quote2"]},n),a=l({value:new RegExp(M,"g"),matches:["quote1","name","group","version","quote2"]},n),t=l({value:new RegExp(j,"g"),matches:["space1","quote1","group","quote2","space2","space3","quote3","name","quote4","space4","space5","quote5","version","quote6"]},n),p=l({value:new RegExp(L,"g"),matches:["space","name"]},n);if(p.length>1)throw new Error(`Expected only one applicationId per file: ${e}`);return[{name:p[0]?.name||o.split("/").pop(),softwareDevelopmentKits:[...c,...t,...a].map(r=>({name:r.name,version:r.version||void 0}))}]}};import{readFileSync as $}from"fs";import{dirname as J}from"path";var x={supportedFiles:["package.json"],ignoreDirs:["node_modules","serverless-build","lambda-build"],scanFunction:e=>{let n=$(e,"utf-8"),o=J(e),c=JSON.parse(n),{name:a,description:t,dependencies:p={},devDependencies:r={},optionalDependencies:i={}}=c;return[{name:a||o.split("/").pop(),description:t,softwareDevelopmentKits:[...Object.entries(p).map(([s,m])=>({name:s,version:typeof m=="string"?m:void 0})),...Object.entries(r).map(([s,m])=>({name:s,version:typeof m=="string"?m:void 0,isDevDependency:!0})),...Object.entries(i).map(([s,m])=>({name:s,version:typeof m=="string"?m:void 0}))]}]}};import{readFileSync as R}from"fs";import{findAllWithRegex as X}from"@transcend-io/type-utils";import{dirname as U,join as W}from"path";import{CodePackageType as Y}from"@transcend-io/privacy-types";var V=/(.+?)(=+)(.+)/,H=/name *= *('|")(.+?)('|")/,Q=/description *= *('|")(.+?)('|")/,P={supportedFiles:["requirements.txt"],ignoreDirs:["build","lib","lib64"],scanFunction:e=>{let n=R(e,"utf-8"),o=U(e),a=u(o).find(s=>s==="setup.py"),t=a?R(W(o,a),"utf-8"):void 0,p=t?(H.exec(t)||[])[2]:void 0,r=t?(Q.exec(t)||[])[2]:void 0,i=X({value:new RegExp(V,"g"),matches:["name","equals","version"]},n);return[{name:p||o.split("/").pop(),description:r||void 0,type:Y.RequirementsTxt,softwareDevelopmentKits:i.map(s=>({name:s.name,version:s.version}))}]}};import{readFileSync as G}from"fs";import{findAllWithRegex as z}from"@transcend-io/type-utils";import{dirname as B}from"path";import{CodePackageType as Z}from"@transcend-io/privacy-types";var ee=/gem *('|")(.+?)('|")(, *('|")(.+?)('|")|)/,ne=/spec\.name *= *('|")(.+?)('|")/,oe=/spec\.description *= *('|")(.+?)('|")/,te=/spec\.summary *= *('|")(.+?)('|")/,k={supportedFiles:["Gemfile"],ignoreDirs:["bin"],scanFunction:e=>{let n=G(e,"utf-8"),o=B(e),a=u(o).find(s=>s===".gemspec"),t=a?G(a,"utf-8"):void 0,p=t?(ne.exec(t)||[])[2]:void 0,r=t?(oe.exec(t)||te.exec(t)||[])[1]:void 0,i=z({value:new RegExp(ee,"g"),matches:["quote1","name","quote2","hasVersion","quote3","version","quote4"]},n);return[{name:p||o.split("/").pop(),description:r||void 0,type:Z.RequirementsTxt,softwareDevelopmentKits:i.map(s=>({name:s.name,version:s.version}))}]}};import{readFileSync as re}from"fs";import{CodePackageType as ie}from"@transcend-io/privacy-types";import se from"js-yaml";import{dirname as ae}from"path";function pe(e){return e.split(`
2
+ `).map(n=>{let o=n.indexOf("#");return o>-1&&!n.substring(0,o).includes('"')&&!n.substring(0,o).includes("'")?n.substring(0,o).trim():n}).filter(n=>n.length>0).join(`
3
+ `)}var v={supportedFiles:["pubspec.yml"],ignoreDirs:["build"],scanFunction:e=>{let n=ae(e),o=re(e,"utf-8"),{name:c,description:a,dev_dependencies:t={},dependencies:p={}}=se.load(pe(o));return[{name:c||n.split("/").pop(),description:a,type:ie.RequirementsTxt,softwareDevelopmentKits:[...Object.entries(p).map(([r,i])=>({name:r,version:typeof i=="string"?i:typeof i=="number"?i.toString():i?.sdk})),...Object.entries(t).map(([r,i])=>({name:r,version:typeof i=="string"?i:typeof i=="number"?i.toString():i?.sdk,isDevDependency:!0}))]}]}};import{readFileSync as ce}from"fs";import{dirname as me}from"path";var I={supportedFiles:["composer.json"],ignoreDirs:["vendor","node_modules","cache","build","dist"],scanFunction:e=>{let n=ce(e,"utf-8"),o=me(e),c=JSON.parse(n),{name:a,description:t,require:p={},"require-dev":r={}}=c;return[{name:a||o.split("/").pop(),description:t,softwareDevelopmentKits:[...Object.entries(p).map(([i,s])=>({name:i,version:typeof s=="string"?s:void 0})),...Object.entries(r).map(([i,s])=>({name:i,version:typeof s=="string"?s:void 0,isDevDependency:!0}))]}]}};import{readFileSync as de}from"fs";import{CodePackageType as ge}from"@transcend-io/privacy-types";import{decodeCodec as fe}from"@transcend-io/type-utils";import*as d from"io-ts";import{dirname as ue}from"path";var le=d.type({pins:d.array(d.type({identity:d.string,kind:d.string,location:d.string,state:d.type({revision:d.string,version:d.string})})),version:d.number}),D={supportedFiles:["Package.resolved"],ignoreDirs:[],scanFunction:e=>{let n=de(e,"utf-8"),o=fe(le,n);return[{name:ue(e).split("/").pop()||"",type:ge.CocoaPods,softwareDevelopmentKits:o.pins.map(c=>({name:c.identity,version:c.state.version}))}]}};import{CodePackageType as f}from"@transcend-io/privacy-types";var gn={cocoaPods:y,gradle:S,javascriptPackageJson:x,pythonRequirementsTxt:P,gemfile:k,pubspec:v,swift:D},_={[f.CocoaPods]:y,[f.Gradle]:S,[f.PackageJson]:x,[f.RequirementsTxt]:P,[f.Gemfile]:k,[f.Pubspec]:v,[f.ComposerJson]:I,[f.Swift]:D};import Ce from"fast-glob";import A from"colors";import{getEntries as Ee}from"@transcend-io/type-utils";async function Sn({scanPath:e,ignoreDirs:n=[],repositoryName:o}){return(await Promise.all(Ee(_).map(async([a,t])=>{let{ignoreDirs:p,supportedFiles:r,scanFunction:i}=t,s=[...n,...p].filter(m=>m.length>0);try{let m=await Ce(`${e}/**/${r.join("|")}`,{ignore:s.map(g=>`${e}/**/${g}`),unique:!0,onlyFiles:!0});E.info(A.magenta(`Scanning: ${m.length} files of type ${a}`));let C=m.map(g=>i(g).map(q=>({...q,relativePath:g.replace(`${e}/`,"")}))).flat();return E.info(A.green(`Found: ${C.length} packages and ${C.map(({softwareDevelopmentKits:g=[]})=>g).flat().length} sdks`)),C.map(g=>({...g,type:a,repositoryName:o}))}catch(m){throw new Error(`Error scanning globs ${r} with error: ${m}`)}}))).flat()}export{gn as a,Sn as b};
4
+ //# sourceMappingURL=chunk-NZZKRVAI.js.map