@transcend-io/cli 13.0.2 → 13.0.3

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 (146) hide show
  1. package/README.md +2 -2
  2. package/dist/{app-CCGKgPiC.mjs → app-CQ2zppwI.mjs} +16 -16
  3. package/dist/{app-CCGKgPiC.mjs.map → app-CQ2zppwI.mjs.map} +1 -1
  4. package/dist/{approvePrivacyRequests-BBcqydVb.mjs → approvePrivacyRequests-CL41z1o-.mjs} +2 -2
  5. package/dist/{approvePrivacyRequests-BBcqydVb.mjs.map → approvePrivacyRequests-CL41z1o-.mjs.map} +1 -1
  6. package/dist/bin/bash-complete.mjs +1 -1
  7. package/dist/bin/cli.mjs +1 -1
  8. package/dist/bin/deprecated-command.mjs +1 -1
  9. package/dist/{buildExamples-DRU0o6EK.mjs → buildExamples-CevD2FsN.mjs} +2 -2
  10. package/dist/{buildExamples-DRU0o6EK.mjs.map → buildExamples-CevD2FsN.mjs.map} +1 -1
  11. package/dist/{buildXdiSyncEndpoint-CSjQKSn3.mjs → buildXdiSyncEndpoint-Baimi1ur.mjs} +2 -2
  12. package/dist/{buildXdiSyncEndpoint-CSjQKSn3.mjs.map → buildXdiSyncEndpoint-Baimi1ur.mjs.map} +1 -1
  13. package/dist/{bulkRestartRequests-Cx5LfpdX.mjs → bulkRestartRequests-CpYE4t_x.mjs} +2 -2
  14. package/dist/{bulkRestartRequests-Cx5LfpdX.mjs.map → bulkRestartRequests-CpYE4t_x.mjs.map} +1 -1
  15. package/dist/{bulkRetryEnrichers-BSJtvqJD.mjs → bulkRetryEnrichers-DuZfJP0v.mjs} +2 -2
  16. package/dist/{bulkRetryEnrichers-BSJtvqJD.mjs.map → bulkRetryEnrichers-DuZfJP0v.mjs.map} +1 -1
  17. package/dist/{cancelPrivacyRequests-Cy48R4tJ.mjs → cancelPrivacyRequests-BZASFAWw.mjs} +2 -2
  18. package/dist/{cancelPrivacyRequests-Cy48R4tJ.mjs.map → cancelPrivacyRequests-BZASFAWw.mjs.map} +1 -1
  19. package/dist/{command-Gip5wB8W.mjs → command--getUtmo.mjs} +2 -2
  20. package/dist/{command-Gip5wB8W.mjs.map → command--getUtmo.mjs.map} +1 -1
  21. package/dist/{constants-DAx9VK1C.mjs → constants-BUOpqzcO.mjs} +2 -2
  22. package/dist/{constants-DAx9VK1C.mjs.map → constants-BUOpqzcO.mjs.map} +1 -1
  23. package/dist/{createPoolingCommandUi-DZx16Cn8.mjs → createPoolingCommandUi-Drb6uFoA.mjs} +2 -2
  24. package/dist/{createPoolingCommandUi-DZx16Cn8.mjs.map → createPoolingCommandUi-Drb6uFoA.mjs.map} +1 -1
  25. package/dist/{downloadPrivacyRequestFiles-DBeuW9b3.mjs → downloadPrivacyRequestFiles-BvlzD_04.mjs} +2 -2
  26. package/dist/{downloadPrivacyRequestFiles-DBeuW9b3.mjs.map → downloadPrivacyRequestFiles-BvlzD_04.mjs.map} +1 -1
  27. package/dist/{generateCrossAccountApiKeys-CjmSyfwm.mjs → generateCrossAccountApiKeys-QJeUqbsi.mjs} +2 -2
  28. package/dist/{generateCrossAccountApiKeys-CjmSyfwm.mjs.map → generateCrossAccountApiKeys-QJeUqbsi.mjs.map} +1 -1
  29. package/dist/{impl-DPq1O87s.mjs → impl-8QKAZj_8.mjs} +2 -2
  30. package/dist/{impl-DPq1O87s.mjs.map → impl-8QKAZj_8.mjs.map} +1 -1
  31. package/dist/{impl-C2BYhujB.mjs → impl-B1cJ_7it.mjs} +2 -2
  32. package/dist/{impl-C2BYhujB.mjs.map → impl-B1cJ_7it.mjs.map} +1 -1
  33. package/dist/{impl-DGLrKNNs2.mjs → impl-BAjCrulN2.mjs} +2 -2
  34. package/dist/{impl-DGLrKNNs2.mjs.map → impl-BAjCrulN2.mjs.map} +1 -1
  35. package/dist/{impl-CcPwm8a4.mjs → impl-BBZWhsZx.mjs} +2 -2
  36. package/dist/{impl-CcPwm8a4.mjs.map → impl-BBZWhsZx.mjs.map} +1 -1
  37. package/dist/{impl-C5qif_gE.mjs → impl-BD4PMYc7.mjs} +2 -2
  38. package/dist/{impl-C5qif_gE.mjs.map → impl-BD4PMYc7.mjs.map} +1 -1
  39. package/dist/{impl-C8auyA7u.mjs → impl-BGhYmH5L.mjs} +2 -2
  40. package/dist/{impl-C8auyA7u.mjs.map → impl-BGhYmH5L.mjs.map} +1 -1
  41. package/dist/{impl-bUltX0u3.mjs → impl-BNc1Lcus.mjs} +2 -2
  42. package/dist/{impl-bUltX0u3.mjs.map → impl-BNc1Lcus.mjs.map} +1 -1
  43. package/dist/{impl-cU3bjY3P.mjs → impl-B_P9kAcg.mjs} +2 -2
  44. package/dist/{impl-cU3bjY3P.mjs.map → impl-B_P9kAcg.mjs.map} +1 -1
  45. package/dist/{impl-D6e2LNBm.mjs → impl-BhFUhO0f.mjs} +2 -2
  46. package/dist/{impl-D6e2LNBm.mjs.map → impl-BhFUhO0f.mjs.map} +1 -1
  47. package/dist/{impl-9W0QG6fB.mjs → impl-Bq99M_E8.mjs} +2 -2
  48. package/dist/{impl-9W0QG6fB.mjs.map → impl-Bq99M_E8.mjs.map} +1 -1
  49. package/dist/{impl-h0z8OSQY.mjs → impl-CCq87iM2.mjs} +2 -2
  50. package/dist/{impl-h0z8OSQY.mjs.map → impl-CCq87iM2.mjs.map} +1 -1
  51. package/dist/{impl-DEPuP4Oy2.mjs → impl-CDYRjRUX2.mjs} +2 -2
  52. package/dist/{impl-DEPuP4Oy2.mjs.map → impl-CDYRjRUX2.mjs.map} +1 -1
  53. package/dist/{impl-CJ4oVuXN.mjs → impl-CKmjV5Y7.mjs} +2 -2
  54. package/dist/{impl-CJ4oVuXN.mjs.map → impl-CKmjV5Y7.mjs.map} +1 -1
  55. package/dist/{impl-B9jwlKCX2.mjs → impl-CZdJmC_12.mjs} +2 -2
  56. package/dist/{impl-B9jwlKCX2.mjs.map → impl-CZdJmC_12.mjs.map} +1 -1
  57. package/dist/{impl-BUKV7sYp.mjs → impl-CfPkCpml.mjs} +2 -2
  58. package/dist/{impl-BUKV7sYp.mjs.map → impl-CfPkCpml.mjs.map} +1 -1
  59. package/dist/{impl-BsdneZZP.mjs → impl-CjVAD6Yi.mjs} +2 -2
  60. package/dist/{impl-BsdneZZP.mjs.map → impl-CjVAD6Yi.mjs.map} +1 -1
  61. package/dist/{impl-CjjiXsMh.mjs → impl-ClDIZ2ou.mjs} +2 -2
  62. package/dist/{impl-CjjiXsMh.mjs.map → impl-ClDIZ2ou.mjs.map} +1 -1
  63. package/dist/{impl-SKxxByoN.mjs → impl-CqgIRHzl.mjs} +2 -2
  64. package/dist/{impl-SKxxByoN.mjs.map → impl-CqgIRHzl.mjs.map} +1 -1
  65. package/dist/{impl-Do3hnGHt.mjs → impl-CyeZYHK7.mjs} +2 -2
  66. package/dist/{impl-Do3hnGHt.mjs.map → impl-CyeZYHK7.mjs.map} +1 -1
  67. package/dist/{impl-BPmzcgpy.mjs → impl-CyyZPtoY.mjs} +2 -2
  68. package/dist/{impl-BPmzcgpy.mjs.map → impl-CyyZPtoY.mjs.map} +1 -1
  69. package/dist/{impl-Bh1CkZhV.mjs → impl-D2q9CvGm.mjs} +2 -2
  70. package/dist/{impl-Bh1CkZhV.mjs.map → impl-D2q9CvGm.mjs.map} +1 -1
  71. package/dist/{impl-DjBbx05w.mjs → impl-DCqZ0p4k.mjs} +2 -2
  72. package/dist/{impl-DjBbx05w.mjs.map → impl-DCqZ0p4k.mjs.map} +1 -1
  73. package/dist/{impl-Nwbb2xaH.mjs → impl-DXKj9hRr.mjs} +2 -2
  74. package/dist/{impl-Nwbb2xaH.mjs.map → impl-DXKj9hRr.mjs.map} +1 -1
  75. package/dist/{impl-DqbJ33ve.mjs → impl-DhVw26sh.mjs} +2 -2
  76. package/dist/{impl-DqbJ33ve.mjs.map → impl-DhVw26sh.mjs.map} +1 -1
  77. package/dist/{impl-nte7qanu.mjs → impl-DmT4VBif.mjs} +2 -2
  78. package/dist/{impl-nte7qanu.mjs.map → impl-DmT4VBif.mjs.map} +1 -1
  79. package/dist/{impl-DnBmd-wi.mjs → impl-DmUcWaBX.mjs} +2 -2
  80. package/dist/{impl-DnBmd-wi.mjs.map → impl-DmUcWaBX.mjs.map} +1 -1
  81. package/dist/{impl-GphhprmF.mjs → impl-DuGCwtcy.mjs} +2 -2
  82. package/dist/{impl-GphhprmF.mjs.map → impl-DuGCwtcy.mjs.map} +1 -1
  83. package/dist/{impl-C_lIkMLn2.mjs → impl-DxJnz5HV2.mjs} +2 -2
  84. package/dist/{impl-C_lIkMLn2.mjs.map → impl-DxJnz5HV2.mjs.map} +1 -1
  85. package/dist/{impl-Dx8BYv7U.mjs → impl-Fq9dfQ-V.mjs} +2 -2
  86. package/dist/{impl-Dx8BYv7U.mjs.map → impl-Fq9dfQ-V.mjs.map} +1 -1
  87. package/dist/{impl-BuOc87b6.mjs → impl-ISlWXXpR.mjs} +2 -2
  88. package/dist/{impl-BuOc87b6.mjs.map → impl-ISlWXXpR.mjs.map} +1 -1
  89. package/dist/{impl-BkQryDNq.mjs → impl-RKWeHPtR.mjs} +2 -2
  90. package/dist/{impl-BkQryDNq.mjs.map → impl-RKWeHPtR.mjs.map} +1 -1
  91. package/dist/{impl-D8yF0jw9.mjs → impl-esdKjQ_g.mjs} +2 -2
  92. package/dist/{impl-D8yF0jw9.mjs.map → impl-esdKjQ_g.mjs.map} +1 -1
  93. package/dist/{impl-BahDGEJJ.mjs → impl-f-5kotyg.mjs} +2 -2
  94. package/dist/{impl-BahDGEJJ.mjs.map → impl-f-5kotyg.mjs.map} +1 -1
  95. package/dist/{impl-BLM6rMBq.mjs → impl-hCvUhuoT.mjs} +2 -2
  96. package/dist/{impl-BLM6rMBq.mjs.map → impl-hCvUhuoT.mjs.map} +1 -1
  97. package/dist/{impl-BIhXJ0Nw.mjs → impl-jUt0SP_K.mjs} +2 -2
  98. package/dist/{impl-BIhXJ0Nw.mjs.map → impl-jUt0SP_K.mjs.map} +1 -1
  99. package/dist/{impl-B8DsKzNn2.mjs → impl-kXabADxl2.mjs} +2 -2
  100. package/dist/{impl-B8DsKzNn2.mjs.map → impl-kXabADxl2.mjs.map} +1 -1
  101. package/dist/{impl-nYlbrsD7.mjs → impl-szLqtBsW.mjs} +2 -2
  102. package/dist/{impl-nYlbrsD7.mjs.map → impl-szLqtBsW.mjs.map} +1 -1
  103. package/dist/{impl-DvHiVaGW.mjs → impl-w5hHfoVE.mjs} +2 -2
  104. package/dist/{impl-DvHiVaGW.mjs.map → impl-w5hHfoVE.mjs.map} +1 -1
  105. package/dist/{impl-DiaD11OP.mjs → impl-zoW4p4mg.mjs} +2 -2
  106. package/dist/{impl-DiaD11OP.mjs.map → impl-zoW4p4mg.mjs.map} +1 -1
  107. package/dist/index.d.mts +72 -66
  108. package/dist/index.d.mts.map +1 -1
  109. package/dist/index.mjs +1 -1
  110. package/dist/{markRequestDataSiloIdsCompleted-loC-xyyW.mjs → markRequestDataSiloIdsCompleted-Dcukd8gS.mjs} +2 -2
  111. package/dist/{markRequestDataSiloIdsCompleted-loC-xyyW.mjs.map → markRequestDataSiloIdsCompleted-Dcukd8gS.mjs.map} +1 -1
  112. package/dist/{markSilentPrivacyRequests-D7ncAg8k.mjs → markSilentPrivacyRequests-E3h17a-G.mjs} +2 -2
  113. package/dist/{markSilentPrivacyRequests-D7ncAg8k.mjs.map → markSilentPrivacyRequests-E3h17a-G.mjs.map} +1 -1
  114. package/dist/{notifyPrivacyRequestsAdditionalTime-DpCfIR_O.mjs → notifyPrivacyRequestsAdditionalTime-DfvVgEqC.mjs} +2 -2
  115. package/dist/{notifyPrivacyRequestsAdditionalTime-DpCfIR_O.mjs.map → notifyPrivacyRequestsAdditionalTime-DfvVgEqC.mjs.map} +1 -1
  116. package/dist/{policy-bundle-manifest-DW3Wilp8.mjs → policy-bundle-manifest-DnqWtiDa.mjs} +2 -2
  117. package/dist/{policy-bundle-manifest-DW3Wilp8.mjs.map → policy-bundle-manifest-DnqWtiDa.mjs.map} +1 -1
  118. package/dist/{policy-project-discovery-CND7N2HI.mjs → policy-project-discovery-D16kgZwZ.mjs} +2 -2
  119. package/dist/{policy-project-discovery-CND7N2HI.mjs.map → policy-project-discovery-D16kgZwZ.mjs.map} +1 -1
  120. package/dist/{policy-scaffold-config-CwY0QZC0.mjs → policy-scaffold-config-5bTG97rM.mjs} +2 -2
  121. package/dist/{policy-scaffold-config-CwY0QZC0.mjs.map → policy-scaffold-config-5bTG97rM.mjs.map} +1 -1
  122. package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-7qvaMN58.mjs → pullChunkedCustomSiloOutstandingIdentifiers-CtFtj3aL.mjs} +2 -2
  123. package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-7qvaMN58.mjs.map → pullChunkedCustomSiloOutstandingIdentifiers-CtFtj3aL.mjs.map} +1 -1
  124. package/dist/{pullManualEnrichmentIdentifiersToCsv-CWPs7VeX.mjs → pullManualEnrichmentIdentifiersToCsv-BHTHcIcT.mjs} +2 -2
  125. package/dist/{pullManualEnrichmentIdentifiersToCsv-CWPs7VeX.mjs.map → pullManualEnrichmentIdentifiersToCsv-BHTHcIcT.mjs.map} +1 -1
  126. package/dist/{pushCronIdentifiersFromCsv-DQoliMdQ.mjs → pushCronIdentifiersFromCsv-BDxR0oav.mjs} +2 -2
  127. package/dist/{pushCronIdentifiersFromCsv-DQoliMdQ.mjs.map → pushCronIdentifiersFromCsv-BDxR0oav.mjs.map} +1 -1
  128. package/dist/{pushManualEnrichmentIdentifiersFromCsv-R9BXYuFk.mjs → pushManualEnrichmentIdentifiersFromCsv-DD34XZcc.mjs} +2 -2
  129. package/dist/{pushManualEnrichmentIdentifiersFromCsv-R9BXYuFk.mjs.map → pushManualEnrichmentIdentifiersFromCsv-DD34XZcc.mjs.map} +1 -1
  130. package/dist/{removeUnverifiedRequestIdentifiers-CgnfHdbc.mjs → removeUnverifiedRequestIdentifiers-BkwPVZqw.mjs} +2 -2
  131. package/dist/{removeUnverifiedRequestIdentifiers-CgnfHdbc.mjs.map → removeUnverifiedRequestIdentifiers-BkwPVZqw.mjs.map} +1 -1
  132. package/dist/{retryRequestDataSilos-BrLLNQqT.mjs → retryRequestDataSilos-CM1KXlao.mjs} +2 -2
  133. package/dist/{retryRequestDataSilos-BrLLNQqT.mjs.map → retryRequestDataSilos-CM1KXlao.mjs.map} +1 -1
  134. package/dist/{skipPreflightJobs-CqjpB7ug.mjs → skipPreflightJobs-ClvnPd8r.mjs} +2 -2
  135. package/dist/{skipPreflightJobs-CqjpB7ug.mjs.map → skipPreflightJobs-ClvnPd8r.mjs.map} +1 -1
  136. package/dist/{skipRequestDataSilos-DPi6-XVr.mjs → skipRequestDataSilos-clWLNU0C.mjs} +2 -2
  137. package/dist/{skipRequestDataSilos-DPi6-XVr.mjs.map → skipRequestDataSilos-clWLNU0C.mjs.map} +1 -1
  138. package/dist/{streamPrivacyRequestsToCsv-DVPQ860_.mjs → streamPrivacyRequestsToCsv-DRFdc0OG.mjs} +2 -2
  139. package/dist/{streamPrivacyRequestsToCsv-DVPQ860_.mjs.map → streamPrivacyRequestsToCsv-DRFdc0OG.mjs.map} +1 -1
  140. package/dist/{updateConsentManagerVersionToLatest-gJMWny-i.mjs → updateConsentManagerVersionToLatest-Cp8jWMFs.mjs} +2 -2
  141. package/dist/{updateConsentManagerVersionToLatest-gJMWny-i.mjs.map → updateConsentManagerVersionToLatest-Cp8jWMFs.mjs.map} +1 -1
  142. package/dist/{uploadConsents-5HlMj7EK.mjs → uploadConsents-CvIMJAUM.mjs} +2 -2
  143. package/dist/{uploadConsents-5HlMj7EK.mjs.map → uploadConsents-CvIMJAUM.mjs.map} +1 -1
  144. package/dist/{uploadPrivacyRequestsFromCsv-Dh8KEW3n.mjs → uploadPrivacyRequestsFromCsv-VBjDw4Bp.mjs} +2 -2
  145. package/dist/{uploadPrivacyRequestsFromCsv-Dh8KEW3n.mjs.map → uploadPrivacyRequestsFromCsv-VBjDw4Bp.mjs.map} +1 -1
  146. package/package.json +4 -4
@@ -1,2 +1,2 @@
1
- import{t as e}from"./buildExamples-DRU0o6EK.mjs";import{r as t}from"./policyEngineCliError-CZrOHhLv.mjs";import{a as n,c as r,g as i,i as a}from"./policy-project-discovery-CND7N2HI.mjs";import{r as o,t as s}from"./runOpa-ojIqU1tO.mjs";import{n as c,t as l}from"./policy-bundle-manifest-DW3Wilp8.mjs";import{i as u,n as d,t as f}from"./printResult-Dmwv78e7.mjs";import{t as p}from"./formatPolicyBundleVersionSummary-DCHl1Vhy.mjs";import{n as m}from"./resolveBundleIdByName-D7NUOpLc.mjs";import{n as h}from"./inquirer-DK1JbPA0.mjs";import{t as g}from"./done-input-validation-LiTaCEzF.mjs";import{r as _}from"./prompts-BhXfYD6g.mjs";import{t as v}from"./command-output-BJcDRXNr.mjs";import y,{join as b}from"node:path";import x from"colors";import{spawnSync as S}from"node:child_process";import C from"node:fs";import w from"node:os";import{gunzipSync as T}from"node:zlib";import{MAX_BUNDLE_COMPRESSED_BYTES as E,MAX_BUNDLE_DECOMPRESSED_BYTES as D}from"@transcend-io/utils";import O from"fast-glob";function k(e){let t=O.sync(`**/*.rego`,{cwd:e,onlyFiles:!0,dot:!1}).sort(),n=y.join(e,r),{publishableRegoPaths:i}=c(C.existsSync(n)?C.readFileSync(n,`utf8`):void 0,t.map(t=>({path:t,contents:C.readFileSync(y.join(e,t),`utf8`)})));return{entries:[r,...i]}}async function A(e){let t=y.join(w.tmpdir(),`transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`);try{let{code:n,stderr:r}=await s([`build`,`--ignore`,`*_test.rego`,`-b`,`-o`,t,`.`],{cwd:e});if(n!==0)throw Error(r.trim()||`opa build failed with exit code ${n}`)}finally{C.existsSync(t)&&C.unlinkSync(t)}}function j(e){if(e<1024)return`${e} B`;let t=e/1024;if(t<1024)return`${t%1==0?t.toFixed(0):t.toFixed(1)} KiB`;let n=t/1024;return`${n%1==0?n.toFixed(0):n.toFixed(1)} MiB`}async function M(e){o();let t=y.resolve(e);if(!C.existsSync(t)||!C.statSync(t).isDirectory())throw Error(`Policy directory does not exist or is not a directory: ${t}`);let{entries:n}=k(t),{code:r,stderr:i}=await s([`check`,`--strict`,t]);if(r!==0)throw Error(i.trim()||`opa check failed with exit code ${r}`);await A(t);let a=y.join(w.tmpdir(),`transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`),c=S(`tar`,[`-czf`,a,`-C`,t,...n],{env:{...process.env,COPYFILE_DISABLE:`1`},encoding:`utf8`});if(c.status!==0)throw Error(`Failed to create policy bundle archive: ${c.stderr.trim()||`tar failed`}`);let l=C.readFileSync(a);if(l.byteLength>E)throw C.unlinkSync(a),Error(`Policy bundle exceeds the ${j(E)} compressed upload limit (bundle is ${j(l.byteLength)}). The server also rejects decompressed bundles larger than ${j(D)}.`);let u=T(l);if(u.byteLength>D)throw C.unlinkSync(a),Error(`Policy bundle exceeds the ${j(D)} decompressed upload limit (bundle is ${j(u.byteLength)} decompressed).`);return a}function N(e){let t=C.readFileSync(e.bundlePath),n=new FormData;return n.append(`bundle`,new Blob([t],{type:`application/gzip`}),y.basename(e.bundlePath)),n.append(`version`,e.version),e.description&&n.append(`description`,e.description),e.bundleName&&n.append(`bundleName`,e.bundleName),n}function P(e){return e.toISOString().slice(0,19).replace(/[T:]/g,`-`)}function F(e,t=new Date){return`${e}-${P(t)}`}function I(e){return e.template===i.Permissions?!0:e.template===i.Generic?!1:e.roots.some(e=>e===`permissions`||e.startsWith(`permissions/`))}function L(e,t){let r=I(t),i=e===n;if(r&&!i)return`This directory looks like a Permissions API policy, but --remote-bundle-name is "${e}". Permissions API only loads the remote bundle named "${n}". Upload still succeeds; pass --remote-bundle-name=${n} if that is the intended path.`;if(!r&&i)return`--remote-bundle-name=${n} reserves the Permissions API path. Upload treats all bundles the same; only that fixed name is queried by the Permissions API. Continue only if you intend this bundle for the Permissions API.`}async function R({"remote-bundle-name":n,auth:i,"transcend-url":o,version:s,description:c,json:y,yes:S,debug:C=!1},w){g(this.process),t(C);let T=v(this.logger,y),E=a(this.process.cwd(),w),D=s??F(n),O=u(o,i),k=_({json:y,noInteractive:!1},this.process.stdin.isTTY,this.process.stderr.isTTY),A;try{T.info(x.green(`Building policy bundle from ${E}...`)),A=await M(E);try{let e=b(E,r),t=L(n,l(this.fs.readFileSync(e,`utf8`)));t&&T.warn(x.yellow(t))}catch{}let t=await m(O,n),i;if(t){T.info(x.green(`Uploading new version for bundle "${n}"...`));let e=N({bundlePath:A,version:D,description:c});i=await d(O.post(`v1/policy-engine/policy-bundles/${t}/versions`,{body:e}).json())}else{if(!k&&!S){this.logger.error(x.red(`Cannot create a new bundle in non-interactive or JSON mode; pass --yes to confirm.`)),this.process.exit(1);return}if(!S&&(T.warn(x.yellow(`No policy bundle named "${n}" exists for this organization.`)),!await h({message:`No policy bundle named "${n}" exists. Create a new bundle and upload its first version?`}))){T.info(x.yellow(`Publish cancelled.`));return}T.info(x.green(`Creating bundle "${n}" and uploading first version...`));let e=N({bundlePath:A,version:D,description:c,bundleName:n});i=await d(O.post(`v1/policy-engine/policy-bundles`,{body:e}).json())}f(this.process.stdout,{json:y,data:i,renderTable:()=>p(i.version)}),T.info(x.green(`Policy bundle version uploaded successfully.`));let a=e([`policy`,`activate`],{version:i.version.version,"remote-bundle-name":n});T.info(x.yellow(`Publishing a policy does not activate it. To activate this version, run:\n ${a}`))}finally{A&&this.fs.existsSync(A)&&this.fs.unlinkSync(A)}}export{R as publish};
2
- //# sourceMappingURL=impl-BuOc87b6.mjs.map
1
+ import{t as e}from"./buildExamples-CevD2FsN.mjs";import{r as t}from"./policyEngineCliError-CZrOHhLv.mjs";import{a as n,c as r,g as i,i as a}from"./policy-project-discovery-D16kgZwZ.mjs";import{r as o,t as s}from"./runOpa-ojIqU1tO.mjs";import{n as c,t as l}from"./policy-bundle-manifest-DnqWtiDa.mjs";import{i as u,n as d,t as f}from"./printResult-Dmwv78e7.mjs";import{t as p}from"./formatPolicyBundleVersionSummary-DCHl1Vhy.mjs";import{n as m}from"./resolveBundleIdByName-D7NUOpLc.mjs";import{n as h}from"./inquirer-DK1JbPA0.mjs";import{t as g}from"./done-input-validation-LiTaCEzF.mjs";import{r as _}from"./prompts-BhXfYD6g.mjs";import{t as v}from"./command-output-BJcDRXNr.mjs";import y,{join as b}from"node:path";import x from"colors";import{spawnSync as S}from"node:child_process";import C from"node:fs";import w from"node:os";import{gunzipSync as T}from"node:zlib";import{MAX_BUNDLE_COMPRESSED_BYTES as E,MAX_BUNDLE_DECOMPRESSED_BYTES as D}from"@transcend-io/utils";import O from"fast-glob";function k(e){let t=O.sync(`**/*.rego`,{cwd:e,onlyFiles:!0,dot:!1}).sort(),n=y.join(e,r),{publishableRegoPaths:i}=c(C.existsSync(n)?C.readFileSync(n,`utf8`):void 0,t.map(t=>({path:t,contents:C.readFileSync(y.join(e,t),`utf8`)})));return{entries:[r,...i]}}async function A(e){let t=y.join(w.tmpdir(),`transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`);try{let{code:n,stderr:r}=await s([`build`,`--ignore`,`*_test.rego`,`-b`,`-o`,t,`.`],{cwd:e});if(n!==0)throw Error(r.trim()||`opa build failed with exit code ${n}`)}finally{C.existsSync(t)&&C.unlinkSync(t)}}function j(e){if(e<1024)return`${e} B`;let t=e/1024;if(t<1024)return`${t%1==0?t.toFixed(0):t.toFixed(1)} KiB`;let n=t/1024;return`${n%1==0?n.toFixed(0):n.toFixed(1)} MiB`}async function M(e){o();let t=y.resolve(e);if(!C.existsSync(t)||!C.statSync(t).isDirectory())throw Error(`Policy directory does not exist or is not a directory: ${t}`);let{entries:n}=k(t),{code:r,stderr:i}=await s([`check`,`--strict`,t]);if(r!==0)throw Error(i.trim()||`opa check failed with exit code ${r}`);await A(t);let a=y.join(w.tmpdir(),`transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`),c=S(`tar`,[`-czf`,a,`-C`,t,...n],{env:{...process.env,COPYFILE_DISABLE:`1`},encoding:`utf8`});if(c.status!==0)throw Error(`Failed to create policy bundle archive: ${c.stderr.trim()||`tar failed`}`);let l=C.readFileSync(a);if(l.byteLength>E)throw C.unlinkSync(a),Error(`Policy bundle exceeds the ${j(E)} compressed upload limit (bundle is ${j(l.byteLength)}). The server also rejects decompressed bundles larger than ${j(D)}.`);let u=T(l);if(u.byteLength>D)throw C.unlinkSync(a),Error(`Policy bundle exceeds the ${j(D)} decompressed upload limit (bundle is ${j(u.byteLength)} decompressed).`);return a}function N(e){let t=C.readFileSync(e.bundlePath),n=new FormData;return n.append(`bundle`,new Blob([t],{type:`application/gzip`}),y.basename(e.bundlePath)),n.append(`version`,e.version),e.description&&n.append(`description`,e.description),e.bundleName&&n.append(`bundleName`,e.bundleName),n}function P(e){return e.toISOString().slice(0,19).replace(/[T:]/g,`-`)}function F(e,t=new Date){return`${e}-${P(t)}`}function I(e){return e.template===i.Permissions?!0:e.template===i.Generic?!1:e.roots.some(e=>e===`permissions`||e.startsWith(`permissions/`))}function L(e,t){let r=I(t),i=e===n;if(r&&!i)return`This directory looks like a Permissions API policy, but --remote-bundle-name is "${e}". Permissions API only loads the remote bundle named "${n}". Upload still succeeds; pass --remote-bundle-name=${n} if that is the intended path.`;if(!r&&i)return`--remote-bundle-name=${n} reserves the Permissions API path. Upload treats all bundles the same; only that fixed name is queried by the Permissions API. Continue only if you intend this bundle for the Permissions API.`}async function R({"remote-bundle-name":n,auth:i,"transcend-url":o,version:s,description:c,json:y,yes:S,debug:C=!1},w){g(this.process),t(C);let T=v(this.logger,y),E=a(this.process.cwd(),w),D=s??F(n),O=u(o,i),k=_({json:y,noInteractive:!1},this.process.stdin.isTTY,this.process.stderr.isTTY),A;try{T.info(x.green(`Building policy bundle from ${E}...`)),A=await M(E);try{let e=b(E,r),t=L(n,l(this.fs.readFileSync(e,`utf8`)));t&&T.warn(x.yellow(t))}catch{}let t=await m(O,n),i;if(t){T.info(x.green(`Uploading new version for bundle "${n}"...`));let e=N({bundlePath:A,version:D,description:c});i=await d(O.post(`v1/policy-engine/policy-bundles/${t}/versions`,{body:e}).json())}else{if(!k&&!S){this.logger.error(x.red(`Cannot create a new bundle in non-interactive or JSON mode; pass --yes to confirm.`)),this.process.exit(1);return}if(!S&&(T.warn(x.yellow(`No policy bundle named "${n}" exists for this organization.`)),!await h({message:`No policy bundle named "${n}" exists. Create a new bundle and upload its first version?`}))){T.info(x.yellow(`Publish cancelled.`));return}T.info(x.green(`Creating bundle "${n}" and uploading first version...`));let e=N({bundlePath:A,version:D,description:c,bundleName:n});i=await d(O.post(`v1/policy-engine/policy-bundles`,{body:e}).json())}f(this.process.stdout,{json:y,data:i,renderTable:()=>p(i.version)}),T.info(x.green(`Policy bundle version uploaded successfully.`));let a=e([`policy`,`activate`],{version:i.version.version,"remote-bundle-name":n});T.info(x.yellow(`Publishing a policy does not activate it. To activate this version, run:\n ${a}`))}finally{A&&this.fs.existsSync(A)&&this.fs.unlinkSync(A)}}export{R as publish};
2
+ //# sourceMappingURL=impl-ISlWXXpR.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-BuOc87b6.mjs","names":["fg"],"sources":["../src/commands/policy/helpers/buildOpaBundleTarball.ts","../src/commands/policy/helpers/buildPolicyBundleFormData.ts","../src/commands/policy/helpers/defaultPolicyVersionLabel.ts","../src/lib/policy/policy-publish-hints.ts","../src/commands/policy/publish/impl.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { gunzipSync } from 'node:zlib';\n\nimport { MAX_BUNDLE_COMPRESSED_BYTES, MAX_BUNDLE_DECOMPRESSED_BYTES } from '@transcend-io/utils';\nimport fg from 'fast-glob';\n\nimport { validatePolicyBundleContents } from '../../../lib/policy/policy-bundle-manifest.js';\nimport { POLICY_MANIFEST_FILENAME } from '../../../lib/policy/policy-scaffold-templates.js';\nimport { assertOpaInstalled } from './assertOpaInstalled.js';\nimport { runOPACapture } from './runOpa.js';\n\n/** Result of collecting publishable entries from a policy bundle directory. */\ninterface PolicyBundleArchiveContents {\n /** Relative paths to include in the upload tarball (manifest first, then rego) */\n entries: string[];\n}\n\n/**\n * Collects `.manifest` and publishable `.rego` files from a policy directory.\n *\n * @param dir - Absolute path to the policy bundle directory\n * @returns Validated archive entries\n */\nfunction collectPolicyBundleArchiveEntries(dir: string): PolicyBundleArchiveContents {\n const regoFiles = fg\n .sync('**/*.rego', {\n cwd: dir,\n onlyFiles: true,\n dot: false,\n })\n .sort();\n const onDiskManifestPath = path.join(dir, POLICY_MANIFEST_FILENAME);\n const { publishableRegoPaths } = validatePolicyBundleContents(\n fs.existsSync(onDiskManifestPath) ? fs.readFileSync(onDiskManifestPath, 'utf8') : undefined,\n regoFiles.map((relativePath) => ({\n path: relativePath,\n contents: fs.readFileSync(path.join(dir, relativePath), 'utf8'),\n })),\n );\n\n return {\n entries: [POLICY_MANIFEST_FILENAME, ...publishableRegoPaths],\n };\n}\n\n/**\n * Verifies that a policy directory compiles end-to-end with `opa build`.\n *\n * The compiled output is discarded — the server receives the `.manifest` +\n * `.rego` archive produced by {@link buildOpaBundleTarball}, not the OPA bundle\n * — but a successful build guarantees the policies compile and link, surfacing\n * errors (syntax, missing imports, undefined references, etc.) before upload.\n *\n * @param dir - Absolute path to the policy bundle directory\n */\nasync function assertBundleCompiles(dir: string): Promise<void> {\n const buildOutputPath = path.join(\n os.tmpdir(),\n `transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n );\n try {\n // Run with `cwd` set to the bundle directory and pass `.` so `opa build`\n // resolves the bundle root correctly. Bundle mode (`-b`) keeps local\n // `input.json` / `input.example.json` fixtures from merging as data.\n // `*_test.rego` files are local-only.\n const { code, stderr } = await runOPACapture(\n ['build', '--ignore', '*_test.rego', '-b', '-o', buildOutputPath, '.'],\n { cwd: dir },\n );\n if (code !== 0) {\n throw new Error(stderr.trim() || `opa build failed with exit code ${code}`);\n }\n } finally {\n if (fs.existsSync(buildOutputPath)) {\n fs.unlinkSync(buildOutputPath);\n }\n }\n}\n\n/**\n * Formats a byte count as a human-readable size with binary units.\n *\n * @param bytes - Number of bytes\n * @returns Human-readable size, e.g. `14 MiB` or `4 KiB`\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const kib = bytes / 1024;\n if (kib < 1024) {\n return `${kib % 1 === 0 ? kib.toFixed(0) : kib.toFixed(1)} KiB`;\n }\n const mib = kib / 1024;\n return `${mib % 1 === 0 ? mib.toFixed(0) : mib.toFixed(1)} MiB`;\n}\n\n/**\n * Builds a gzip-compressed policy bundle tarball for upload to Transcend.\n *\n * The Policy Engine API expects a plain archive containing `.manifest` and\n * one or more `.rego` files. Local projects author an OPA `.manifest` and it\n * is uploaded directly — no rename at pack time. Before packaging, the\n * manifest is validated (shape + root coverage) and the bundle is validated\n * with `opa check` (strict Rego linting) and `opa build` (full compilation) so\n * failures surface client-side rather than after upload.\n *\n * @param dir - Directory containing `.manifest` and `.rego` policy files\n * @returns Absolute path to the generated `.tar.gz` bundle\n */\nexport async function buildOpaBundleTarball(dir: string): Promise<string> {\n assertOpaInstalled();\n\n const resolvedDir = path.resolve(dir);\n if (!fs.existsSync(resolvedDir) || !fs.statSync(resolvedDir).isDirectory()) {\n throw new Error(`Policy directory does not exist or is not a directory: ${resolvedDir}`);\n }\n\n // Validate the manifest shape and that roots cover every Rego package before\n // invoking OPA, so invalid manifests surface a clear error instead of an\n // opaque `opa build failed with exit code 1`.\n const { entries: archiveEntries } = collectPolicyBundleArchiveEntries(resolvedDir);\n\n // Match the Rego v1 validation the Policy Engine API runs on upload.\n const { code: checkCode, stderr: checkStderr } = await runOPACapture([\n 'check',\n '--strict',\n resolvedDir,\n ]);\n if (checkCode !== 0) {\n throw new Error(checkStderr.trim() || `opa check failed with exit code ${checkCode}`);\n }\n\n // Ensure the bundle compiles end-to-end before packaging for upload.\n await assertBundleCompiles(resolvedDir);\n\n const outputPath = path.join(\n os.tmpdir(),\n `transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n );\n const tarResult = spawnSync('tar', ['-czf', outputPath, '-C', resolvedDir, ...archiveEntries], {\n env: { ...process.env, COPYFILE_DISABLE: '1' },\n encoding: 'utf8',\n });\n if (tarResult.status !== 0) {\n throw new Error(\n `Failed to create policy bundle archive: ${tarResult.stderr.trim() || 'tar failed'}`,\n );\n }\n\n const compressedBytes = fs.readFileSync(outputPath);\n if (compressedBytes.byteLength > MAX_BUNDLE_COMPRESSED_BYTES) {\n fs.unlinkSync(outputPath);\n throw new Error(\n `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_COMPRESSED_BYTES)} compressed upload limit ` +\n `(bundle is ${formatBytes(compressedBytes.byteLength)}). ` +\n `The server also rejects decompressed bundles larger than ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)}.`,\n );\n }\n\n const decompressedBytes = gunzipSync(compressedBytes);\n if (decompressedBytes.byteLength > MAX_BUNDLE_DECOMPRESSED_BYTES) {\n fs.unlinkSync(outputPath);\n throw new Error(\n `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)} decompressed upload limit ` +\n `(bundle is ${formatBytes(decompressedBytes.byteLength)} decompressed).`,\n );\n }\n\n return outputPath;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\n/** Fields for building a policy bundle upload form. */\nexport interface BuildPolicyBundleFormDataOptions {\n /** Absolute path to the bundle tarball */\n bundlePath: string;\n /** Version label */\n version: string;\n /** Optional description */\n description?: string;\n /** Bundle name (only for create) */\n bundleName?: string;\n}\n\n/**\n * Builds multipart form data for a policy bundle upload.\n *\n * @param options - Upload fields\n * @returns FormData ready for POST\n */\nexport function buildPolicyBundleFormData(options: BuildPolicyBundleFormDataOptions): FormData {\n const bundleBytes = fs.readFileSync(options.bundlePath);\n const form = new FormData();\n form.append(\n 'bundle',\n new Blob([bundleBytes], { type: 'application/gzip' }),\n path.basename(options.bundlePath),\n );\n form.append('version', options.version);\n if (options.description) {\n form.append('description', options.description);\n }\n if (options.bundleName) {\n form.append('bundleName', options.bundleName);\n }\n return form;\n}\n","/**\n * Formats a date as `yyyy-mm-dd-hh-mm-ss` in UTC.\n *\n * @param date - Date to format\n * @returns Timestamp label\n */\nfunction formatPolicyVersionTimestamp(date: Date): string {\n return date.toISOString().slice(0, 19).replace(/[T:]/g, '-');\n}\n\n/**\n * Returns a default version label from the bundle name and current UTC timestamp.\n *\n * @param bundleName - Tenant-unique policy bundle name\n * @param now - Current time (for testing)\n * @returns Version label in `{bundleName}-yyyy-mm-dd-hh-mm-ss` form\n */\nexport function defaultPolicyVersionLabel(bundleName: string, now: Date = new Date()): string {\n return `${bundleName}-${formatPolicyVersionTimestamp(now)}`;\n}\n","import {\n PERMISSIONS_POLICY_BUNDLE_NAME,\n PolicyTemplate,\n type PolicyTemplateName,\n} from './policy-scaffold-templates.js';\n\n/** Inputs used to soft-warn about Permissions vs generic publish naming. */\nexport interface PolicyPublishBundleNameHintInput {\n /** Optional scaffold template from `.manifest` metadata. */\n template?: PolicyTemplateName;\n /** Declared OPA package roots. */\n roots: string[];\n}\n\n/**\n * Whether local authoring signals suggest a Permissions API bundle.\n *\n * Prefers explicit `metadata.transcend.io.template`. Without metadata, falls\n * back to a root that is exactly `permissions` or nested under it.\n *\n * @param input - Manifest template hint and roots\n * @returns Whether the local tree looks Permissions-oriented\n */\nfunction looksLikePermissionsBundle(input: PolicyPublishBundleNameHintInput): boolean {\n if (input.template === PolicyTemplate.Permissions) {\n return true;\n }\n if (input.template === PolicyTemplate.Generic) {\n return false;\n }\n return input.roots.some(\n (root) =>\n root === PERMISSIONS_POLICY_BUNDLE_NAME ||\n root.startsWith(`${PERMISSIONS_POLICY_BUNDLE_NAME}/`),\n );\n}\n\n/**\n * Soft-warning when `--remote-bundle-name` disagrees with Permissions conventions.\n *\n * Upload does not enforce bundle kinds. Permissions API only loads the\n * remote bundle named {@link PERMISSIONS_POLICY_BUNDLE_NAME}.\n *\n * @param bundleName - Value of `--remote-bundle-name`\n * @param input - Local manifest template/roots\n * @returns Warning text, or undefined when names align\n */\nexport function formatPolicyPublishBundleNameHint(\n bundleName: string,\n input: PolicyPublishBundleNameHintInput,\n): string | undefined {\n const permissionsLocal = looksLikePermissionsBundle(input);\n const permissionsRemote = bundleName === PERMISSIONS_POLICY_BUNDLE_NAME;\n\n if (permissionsLocal && !permissionsRemote) {\n return (\n `This directory looks like a Permissions API policy, but --remote-bundle-name is ` +\n `\"${bundleName}\". Permissions API only loads the remote bundle named ` +\n `\"${PERMISSIONS_POLICY_BUNDLE_NAME}\". Upload still succeeds; pass ` +\n `--remote-bundle-name=${PERMISSIONS_POLICY_BUNDLE_NAME} if that is the intended path.`\n );\n }\n\n if (!permissionsLocal && permissionsRemote) {\n return (\n `--remote-bundle-name=${PERMISSIONS_POLICY_BUNDLE_NAME} reserves the Permissions API ` +\n `path. Upload treats all bundles the same; only that fixed name is queried by ` +\n `the Permissions API. Continue only if you intend this bundle for the Permissions API.`\n );\n }\n\n return undefined;\n}\n","import { join } from 'node:path';\n\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { selectCommandLogger } from '../../../lib/cli/command-output.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { buildExampleCommand } from '../../../lib/docgen/buildExamples.js';\nimport { inquirerConfirmBoolean } from '../../../lib/helpers/inquirer.js';\nimport { parsePolicyBundleManifest } from '../../../lib/policy/policy-bundle-manifest.js';\nimport { resolvePolicyProjectDirectory } from '../../../lib/policy/policy-project-discovery.js';\nimport { formatPolicyPublishBundleNameHint } from '../../../lib/policy/policy-publish-hints.js';\nimport { POLICY_MANIFEST_FILENAME } from '../../../lib/policy/policy-scaffold-templates.js';\nimport { isInteractivePromptInvocation } from '../../../lib/scaffolding/prompts.js';\nimport type { ActivateCommandFlags } from '../activate/impl.js';\nimport {\n buildPolicyBundleFormData,\n buildPolicyEngineClient,\n buildOpaBundleTarball,\n defaultPolicyVersionLabel,\n formatPolicyBundleVersionSummary,\n policyEngineRequest,\n printResult,\n resolveBundleIdByName,\n setPolicyEngineCliDebug,\n} from '../helpers/index.js';\nimport type { CreatePolicyBundleResponse, CreatePolicyBundleVersionResponse } from '../types.js';\n\n/** CLI flags for `transcend policy publish`. */\nexport interface PublishCommandFlags {\n /** Tenant-unique bundle name */\n 'remote-bundle-name': string;\n /** Transcend API key */\n auth: string;\n /** Transcend API URL */\n 'transcend-url': string;\n /** Version label (defaults to `{bundleName}-yyyy-mm-dd-hh-mm-ss`) */\n version?: string;\n /** Optional version description */\n description?: string;\n /** Print raw JSON response */\n json: boolean;\n /** Skip the \"create new bundle\" confirmation */\n yes: boolean;\n /** Include technical error details when a command fails */\n debug?: boolean;\n}\n\n/**\n * Build and upload a new immutable policy bundle version.\n *\n * @param this - CLI context\n * @param flags - Command flags\n * @param directory - Policy bundle directory containing a `.manifest`\n */\nexport async function publish(\n this: LocalContext,\n {\n 'remote-bundle-name': bundleName,\n auth,\n 'transcend-url': transcendUrl,\n version,\n description,\n json,\n yes,\n debug = false,\n }: PublishCommandFlags,\n directory: string,\n): Promise<void> {\n doneInputValidation(this.process);\n setPolicyEngineCliDebug(debug);\n\n const commandLogger = selectCommandLogger(this.logger, json);\n const resolvedDir = resolvePolicyProjectDirectory(this.process.cwd(), directory);\n const versionLabel = version ?? defaultPolicyVersionLabel(bundleName);\n const client = buildPolicyEngineClient(transcendUrl, auth);\n const interactive = isInteractivePromptInvocation(\n { json, noInteractive: false },\n this.process.stdin.isTTY,\n this.process.stderr.isTTY,\n );\n\n let bundlePath: string | undefined;\n try {\n commandLogger.info(colors.green(`Building policy bundle from ${resolvedDir}...`));\n bundlePath = await buildOpaBundleTarball(resolvedDir);\n\n try {\n const manifestPath = join(resolvedDir, POLICY_MANIFEST_FILENAME);\n const manifest = parsePolicyBundleManifest(this.fs.readFileSync(manifestPath, 'utf8'));\n const bundleNameHint = formatPolicyPublishBundleNameHint(bundleName, manifest);\n if (bundleNameHint) {\n commandLogger.warn(colors.yellow(bundleNameHint));\n }\n } catch {\n // Best-effort authoring hint; tarball build already validated the manifest.\n }\n\n const existingBundleId = await resolveBundleIdByName(client, bundleName);\n\n let responseBody: CreatePolicyBundleResponse | CreatePolicyBundleVersionResponse;\n\n if (existingBundleId) {\n commandLogger.info(colors.green(`Uploading new version for bundle \"${bundleName}\"...`));\n const form = buildPolicyBundleFormData({\n bundlePath,\n version: versionLabel,\n description,\n });\n responseBody = await policyEngineRequest(\n client\n .post(`v1/policy-engine/policy-bundles/${existingBundleId}/versions`, { body: form })\n .json<CreatePolicyBundleVersionResponse>(),\n );\n } else {\n if (!interactive && !yes) {\n this.logger.error(\n colors.red(\n 'Cannot create a new bundle in non-interactive or JSON mode; pass --yes to confirm.',\n ),\n );\n this.process.exit(1);\n return;\n }\n\n if (!yes) {\n commandLogger.warn(\n colors.yellow(`No policy bundle named \"${bundleName}\" exists for this organization.`),\n );\n const shouldCreate = await inquirerConfirmBoolean({\n message: `No policy bundle named \"${bundleName}\" exists. Create a new bundle and upload its first version?`,\n });\n if (!shouldCreate) {\n commandLogger.info(colors.yellow('Publish cancelled.'));\n return;\n }\n }\n\n commandLogger.info(\n colors.green(`Creating bundle \"${bundleName}\" and uploading first version...`),\n );\n const createForm = buildPolicyBundleFormData({\n bundlePath,\n version: versionLabel,\n description,\n bundleName,\n });\n responseBody = await policyEngineRequest(\n client\n .post('v1/policy-engine/policy-bundles', {\n body: createForm,\n })\n .json<CreatePolicyBundleResponse>(),\n );\n }\n\n printResult(this.process.stdout, {\n json,\n data: responseBody,\n renderTable: () => formatPolicyBundleVersionSummary(responseBody.version),\n });\n\n commandLogger.info(colors.green('Policy bundle version uploaded successfully.'));\n\n const activateCommand = buildExampleCommand<ActivateCommandFlags>(['policy', 'activate'], {\n version: responseBody.version.version,\n 'remote-bundle-name': bundleName,\n });\n commandLogger.info(\n colors.yellow(\n `Publishing a policy does not activate it. To activate this version, run:\\n ${activateCommand}`,\n ),\n );\n } finally {\n if (bundlePath && this.fs.existsSync(bundlePath)) {\n this.fs.unlinkSync(bundlePath);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"impl-ISlWXXpR.mjs","names":["fg"],"sources":["../src/commands/policy/helpers/buildOpaBundleTarball.ts","../src/commands/policy/helpers/buildPolicyBundleFormData.ts","../src/commands/policy/helpers/defaultPolicyVersionLabel.ts","../src/lib/policy/policy-publish-hints.ts","../src/commands/policy/publish/impl.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { gunzipSync } from 'node:zlib';\n\nimport { MAX_BUNDLE_COMPRESSED_BYTES, MAX_BUNDLE_DECOMPRESSED_BYTES } from '@transcend-io/utils';\nimport fg from 'fast-glob';\n\nimport { validatePolicyBundleContents } from '../../../lib/policy/policy-bundle-manifest.js';\nimport { POLICY_MANIFEST_FILENAME } from '../../../lib/policy/policy-scaffold-templates.js';\nimport { assertOpaInstalled } from './assertOpaInstalled.js';\nimport { runOPACapture } from './runOpa.js';\n\n/** Result of collecting publishable entries from a policy bundle directory. */\ninterface PolicyBundleArchiveContents {\n /** Relative paths to include in the upload tarball (manifest first, then rego) */\n entries: string[];\n}\n\n/**\n * Collects `.manifest` and publishable `.rego` files from a policy directory.\n *\n * @param dir - Absolute path to the policy bundle directory\n * @returns Validated archive entries\n */\nfunction collectPolicyBundleArchiveEntries(dir: string): PolicyBundleArchiveContents {\n const regoFiles = fg\n .sync('**/*.rego', {\n cwd: dir,\n onlyFiles: true,\n dot: false,\n })\n .sort();\n const onDiskManifestPath = path.join(dir, POLICY_MANIFEST_FILENAME);\n const { publishableRegoPaths } = validatePolicyBundleContents(\n fs.existsSync(onDiskManifestPath) ? fs.readFileSync(onDiskManifestPath, 'utf8') : undefined,\n regoFiles.map((relativePath) => ({\n path: relativePath,\n contents: fs.readFileSync(path.join(dir, relativePath), 'utf8'),\n })),\n );\n\n return {\n entries: [POLICY_MANIFEST_FILENAME, ...publishableRegoPaths],\n };\n}\n\n/**\n * Verifies that a policy directory compiles end-to-end with `opa build`.\n *\n * The compiled output is discarded — the server receives the `.manifest` +\n * `.rego` archive produced by {@link buildOpaBundleTarball}, not the OPA bundle\n * — but a successful build guarantees the policies compile and link, surfacing\n * errors (syntax, missing imports, undefined references, etc.) before upload.\n *\n * @param dir - Absolute path to the policy bundle directory\n */\nasync function assertBundleCompiles(dir: string): Promise<void> {\n const buildOutputPath = path.join(\n os.tmpdir(),\n `transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n );\n try {\n // Run with `cwd` set to the bundle directory and pass `.` so `opa build`\n // resolves the bundle root correctly. Bundle mode (`-b`) keeps local\n // `input.json` / `input.example.json` fixtures from merging as data.\n // `*_test.rego` files are local-only.\n const { code, stderr } = await runOPACapture(\n ['build', '--ignore', '*_test.rego', '-b', '-o', buildOutputPath, '.'],\n { cwd: dir },\n );\n if (code !== 0) {\n throw new Error(stderr.trim() || `opa build failed with exit code ${code}`);\n }\n } finally {\n if (fs.existsSync(buildOutputPath)) {\n fs.unlinkSync(buildOutputPath);\n }\n }\n}\n\n/**\n * Formats a byte count as a human-readable size with binary units.\n *\n * @param bytes - Number of bytes\n * @returns Human-readable size, e.g. `14 MiB` or `4 KiB`\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const kib = bytes / 1024;\n if (kib < 1024) {\n return `${kib % 1 === 0 ? kib.toFixed(0) : kib.toFixed(1)} KiB`;\n }\n const mib = kib / 1024;\n return `${mib % 1 === 0 ? mib.toFixed(0) : mib.toFixed(1)} MiB`;\n}\n\n/**\n * Builds a gzip-compressed policy bundle tarball for upload to Transcend.\n *\n * The Policy Engine API expects a plain archive containing `.manifest` and\n * one or more `.rego` files. Local projects author an OPA `.manifest` and it\n * is uploaded directly — no rename at pack time. Before packaging, the\n * manifest is validated (shape + root coverage) and the bundle is validated\n * with `opa check` (strict Rego linting) and `opa build` (full compilation) so\n * failures surface client-side rather than after upload.\n *\n * @param dir - Directory containing `.manifest` and `.rego` policy files\n * @returns Absolute path to the generated `.tar.gz` bundle\n */\nexport async function buildOpaBundleTarball(dir: string): Promise<string> {\n assertOpaInstalled();\n\n const resolvedDir = path.resolve(dir);\n if (!fs.existsSync(resolvedDir) || !fs.statSync(resolvedDir).isDirectory()) {\n throw new Error(`Policy directory does not exist or is not a directory: ${resolvedDir}`);\n }\n\n // Validate the manifest shape and that roots cover every Rego package before\n // invoking OPA, so invalid manifests surface a clear error instead of an\n // opaque `opa build failed with exit code 1`.\n const { entries: archiveEntries } = collectPolicyBundleArchiveEntries(resolvedDir);\n\n // Match the Rego v1 validation the Policy Engine API runs on upload.\n const { code: checkCode, stderr: checkStderr } = await runOPACapture([\n 'check',\n '--strict',\n resolvedDir,\n ]);\n if (checkCode !== 0) {\n throw new Error(checkStderr.trim() || `opa check failed with exit code ${checkCode}`);\n }\n\n // Ensure the bundle compiles end-to-end before packaging for upload.\n await assertBundleCompiles(resolvedDir);\n\n const outputPath = path.join(\n os.tmpdir(),\n `transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n );\n const tarResult = spawnSync('tar', ['-czf', outputPath, '-C', resolvedDir, ...archiveEntries], {\n env: { ...process.env, COPYFILE_DISABLE: '1' },\n encoding: 'utf8',\n });\n if (tarResult.status !== 0) {\n throw new Error(\n `Failed to create policy bundle archive: ${tarResult.stderr.trim() || 'tar failed'}`,\n );\n }\n\n const compressedBytes = fs.readFileSync(outputPath);\n if (compressedBytes.byteLength > MAX_BUNDLE_COMPRESSED_BYTES) {\n fs.unlinkSync(outputPath);\n throw new Error(\n `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_COMPRESSED_BYTES)} compressed upload limit ` +\n `(bundle is ${formatBytes(compressedBytes.byteLength)}). ` +\n `The server also rejects decompressed bundles larger than ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)}.`,\n );\n }\n\n const decompressedBytes = gunzipSync(compressedBytes);\n if (decompressedBytes.byteLength > MAX_BUNDLE_DECOMPRESSED_BYTES) {\n fs.unlinkSync(outputPath);\n throw new Error(\n `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)} decompressed upload limit ` +\n `(bundle is ${formatBytes(decompressedBytes.byteLength)} decompressed).`,\n );\n }\n\n return outputPath;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\n/** Fields for building a policy bundle upload form. */\nexport interface BuildPolicyBundleFormDataOptions {\n /** Absolute path to the bundle tarball */\n bundlePath: string;\n /** Version label */\n version: string;\n /** Optional description */\n description?: string;\n /** Bundle name (only for create) */\n bundleName?: string;\n}\n\n/**\n * Builds multipart form data for a policy bundle upload.\n *\n * @param options - Upload fields\n * @returns FormData ready for POST\n */\nexport function buildPolicyBundleFormData(options: BuildPolicyBundleFormDataOptions): FormData {\n const bundleBytes = fs.readFileSync(options.bundlePath);\n const form = new FormData();\n form.append(\n 'bundle',\n new Blob([bundleBytes], { type: 'application/gzip' }),\n path.basename(options.bundlePath),\n );\n form.append('version', options.version);\n if (options.description) {\n form.append('description', options.description);\n }\n if (options.bundleName) {\n form.append('bundleName', options.bundleName);\n }\n return form;\n}\n","/**\n * Formats a date as `yyyy-mm-dd-hh-mm-ss` in UTC.\n *\n * @param date - Date to format\n * @returns Timestamp label\n */\nfunction formatPolicyVersionTimestamp(date: Date): string {\n return date.toISOString().slice(0, 19).replace(/[T:]/g, '-');\n}\n\n/**\n * Returns a default version label from the bundle name and current UTC timestamp.\n *\n * @param bundleName - Tenant-unique policy bundle name\n * @param now - Current time (for testing)\n * @returns Version label in `{bundleName}-yyyy-mm-dd-hh-mm-ss` form\n */\nexport function defaultPolicyVersionLabel(bundleName: string, now: Date = new Date()): string {\n return `${bundleName}-${formatPolicyVersionTimestamp(now)}`;\n}\n","import {\n PERMISSIONS_POLICY_BUNDLE_NAME,\n PolicyTemplate,\n type PolicyTemplateName,\n} from './policy-scaffold-templates.js';\n\n/** Inputs used to soft-warn about Permissions vs generic publish naming. */\nexport interface PolicyPublishBundleNameHintInput {\n /** Optional scaffold template from `.manifest` metadata. */\n template?: PolicyTemplateName;\n /** Declared OPA package roots. */\n roots: string[];\n}\n\n/**\n * Whether local authoring signals suggest a Permissions API bundle.\n *\n * Prefers explicit `metadata.transcend.io.template`. Without metadata, falls\n * back to a root that is exactly `permissions` or nested under it.\n *\n * @param input - Manifest template hint and roots\n * @returns Whether the local tree looks Permissions-oriented\n */\nfunction looksLikePermissionsBundle(input: PolicyPublishBundleNameHintInput): boolean {\n if (input.template === PolicyTemplate.Permissions) {\n return true;\n }\n if (input.template === PolicyTemplate.Generic) {\n return false;\n }\n return input.roots.some(\n (root) =>\n root === PERMISSIONS_POLICY_BUNDLE_NAME ||\n root.startsWith(`${PERMISSIONS_POLICY_BUNDLE_NAME}/`),\n );\n}\n\n/**\n * Soft-warning when `--remote-bundle-name` disagrees with Permissions conventions.\n *\n * Upload does not enforce bundle kinds. Permissions API only loads the\n * remote bundle named {@link PERMISSIONS_POLICY_BUNDLE_NAME}.\n *\n * @param bundleName - Value of `--remote-bundle-name`\n * @param input - Local manifest template/roots\n * @returns Warning text, or undefined when names align\n */\nexport function formatPolicyPublishBundleNameHint(\n bundleName: string,\n input: PolicyPublishBundleNameHintInput,\n): string | undefined {\n const permissionsLocal = looksLikePermissionsBundle(input);\n const permissionsRemote = bundleName === PERMISSIONS_POLICY_BUNDLE_NAME;\n\n if (permissionsLocal && !permissionsRemote) {\n return (\n `This directory looks like a Permissions API policy, but --remote-bundle-name is ` +\n `\"${bundleName}\". Permissions API only loads the remote bundle named ` +\n `\"${PERMISSIONS_POLICY_BUNDLE_NAME}\". Upload still succeeds; pass ` +\n `--remote-bundle-name=${PERMISSIONS_POLICY_BUNDLE_NAME} if that is the intended path.`\n );\n }\n\n if (!permissionsLocal && permissionsRemote) {\n return (\n `--remote-bundle-name=${PERMISSIONS_POLICY_BUNDLE_NAME} reserves the Permissions API ` +\n `path. Upload treats all bundles the same; only that fixed name is queried by ` +\n `the Permissions API. Continue only if you intend this bundle for the Permissions API.`\n );\n }\n\n return undefined;\n}\n","import { join } from 'node:path';\n\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { selectCommandLogger } from '../../../lib/cli/command-output.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { buildExampleCommand } from '../../../lib/docgen/buildExamples.js';\nimport { inquirerConfirmBoolean } from '../../../lib/helpers/inquirer.js';\nimport { parsePolicyBundleManifest } from '../../../lib/policy/policy-bundle-manifest.js';\nimport { resolvePolicyProjectDirectory } from '../../../lib/policy/policy-project-discovery.js';\nimport { formatPolicyPublishBundleNameHint } from '../../../lib/policy/policy-publish-hints.js';\nimport { POLICY_MANIFEST_FILENAME } from '../../../lib/policy/policy-scaffold-templates.js';\nimport { isInteractivePromptInvocation } from '../../../lib/scaffolding/prompts.js';\nimport type { ActivateCommandFlags } from '../activate/impl.js';\nimport {\n buildPolicyBundleFormData,\n buildPolicyEngineClient,\n buildOpaBundleTarball,\n defaultPolicyVersionLabel,\n formatPolicyBundleVersionSummary,\n policyEngineRequest,\n printResult,\n resolveBundleIdByName,\n setPolicyEngineCliDebug,\n} from '../helpers/index.js';\nimport type { CreatePolicyBundleResponse, CreatePolicyBundleVersionResponse } from '../types.js';\n\n/** CLI flags for `transcend policy publish`. */\nexport interface PublishCommandFlags {\n /** Tenant-unique bundle name */\n 'remote-bundle-name': string;\n /** Transcend API key */\n auth: string;\n /** Transcend API URL */\n 'transcend-url': string;\n /** Version label (defaults to `{bundleName}-yyyy-mm-dd-hh-mm-ss`) */\n version?: string;\n /** Optional version description */\n description?: string;\n /** Print raw JSON response */\n json: boolean;\n /** Skip the \"create new bundle\" confirmation */\n yes: boolean;\n /** Include technical error details when a command fails */\n debug?: boolean;\n}\n\n/**\n * Build and upload a new immutable policy bundle version.\n *\n * @param this - CLI context\n * @param flags - Command flags\n * @param directory - Policy bundle directory containing a `.manifest`\n */\nexport async function publish(\n this: LocalContext,\n {\n 'remote-bundle-name': bundleName,\n auth,\n 'transcend-url': transcendUrl,\n version,\n description,\n json,\n yes,\n debug = false,\n }: PublishCommandFlags,\n directory: string,\n): Promise<void> {\n doneInputValidation(this.process);\n setPolicyEngineCliDebug(debug);\n\n const commandLogger = selectCommandLogger(this.logger, json);\n const resolvedDir = resolvePolicyProjectDirectory(this.process.cwd(), directory);\n const versionLabel = version ?? defaultPolicyVersionLabel(bundleName);\n const client = buildPolicyEngineClient(transcendUrl, auth);\n const interactive = isInteractivePromptInvocation(\n { json, noInteractive: false },\n this.process.stdin.isTTY,\n this.process.stderr.isTTY,\n );\n\n let bundlePath: string | undefined;\n try {\n commandLogger.info(colors.green(`Building policy bundle from ${resolvedDir}...`));\n bundlePath = await buildOpaBundleTarball(resolvedDir);\n\n try {\n const manifestPath = join(resolvedDir, POLICY_MANIFEST_FILENAME);\n const manifest = parsePolicyBundleManifest(this.fs.readFileSync(manifestPath, 'utf8'));\n const bundleNameHint = formatPolicyPublishBundleNameHint(bundleName, manifest);\n if (bundleNameHint) {\n commandLogger.warn(colors.yellow(bundleNameHint));\n }\n } catch {\n // Best-effort authoring hint; tarball build already validated the manifest.\n }\n\n const existingBundleId = await resolveBundleIdByName(client, bundleName);\n\n let responseBody: CreatePolicyBundleResponse | CreatePolicyBundleVersionResponse;\n\n if (existingBundleId) {\n commandLogger.info(colors.green(`Uploading new version for bundle \"${bundleName}\"...`));\n const form = buildPolicyBundleFormData({\n bundlePath,\n version: versionLabel,\n description,\n });\n responseBody = await policyEngineRequest(\n client\n .post(`v1/policy-engine/policy-bundles/${existingBundleId}/versions`, { body: form })\n .json<CreatePolicyBundleVersionResponse>(),\n );\n } else {\n if (!interactive && !yes) {\n this.logger.error(\n colors.red(\n 'Cannot create a new bundle in non-interactive or JSON mode; pass --yes to confirm.',\n ),\n );\n this.process.exit(1);\n return;\n }\n\n if (!yes) {\n commandLogger.warn(\n colors.yellow(`No policy bundle named \"${bundleName}\" exists for this organization.`),\n );\n const shouldCreate = await inquirerConfirmBoolean({\n message: `No policy bundle named \"${bundleName}\" exists. Create a new bundle and upload its first version?`,\n });\n if (!shouldCreate) {\n commandLogger.info(colors.yellow('Publish cancelled.'));\n return;\n }\n }\n\n commandLogger.info(\n colors.green(`Creating bundle \"${bundleName}\" and uploading first version...`),\n );\n const createForm = buildPolicyBundleFormData({\n bundlePath,\n version: versionLabel,\n description,\n bundleName,\n });\n responseBody = await policyEngineRequest(\n client\n .post('v1/policy-engine/policy-bundles', {\n body: createForm,\n })\n .json<CreatePolicyBundleResponse>(),\n );\n }\n\n printResult(this.process.stdout, {\n json,\n data: responseBody,\n renderTable: () => formatPolicyBundleVersionSummary(responseBody.version),\n });\n\n commandLogger.info(colors.green('Policy bundle version uploaded successfully.'));\n\n const activateCommand = buildExampleCommand<ActivateCommandFlags>(['policy', 'activate'], {\n version: responseBody.version.version,\n 'remote-bundle-name': bundleName,\n });\n commandLogger.info(\n colors.yellow(\n `Publishing a policy does not activate it. To activate this version, run:\\n ${activateCommand}`,\n ),\n );\n } finally {\n if (bundlePath && this.fs.existsSync(bundlePath)) {\n this.fs.unlinkSync(bundlePath);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{n as e}from"./buildXdiSyncEndpoint-CSjQKSn3.mjs";import{t}from"./validateTranscendAuth-BrVGfq6X.mjs";import{t as n}from"./done-input-validation-LiTaCEzF.mjs";import r from"colors";async function i({auth:i,xdiLocation:a,file:o,removeIpAddresses:s,domainBlockList:c,xdiAllowedCommands:l,transcendUrl:u}){n(this.process);let{syncGroups:d,html:f}=await e(await t(i,this),{xdiLocation:a,transcendUrl:u,removeIpAddresses:s,domainBlockList:c.length>0?c:void 0,xdiAllowedCommands:l});this.logger.info(r.green(`Successfully constructed sync endpoint for sync groups: ${JSON.stringify(d,null,2)}`)),this.fs.writeFileSync(o,f),this.logger.info(r.green(`Wrote configuration to file "${o}"!`))}export{i as buildXdiSyncEndpoint};
2
- //# sourceMappingURL=impl-BkQryDNq.mjs.map
1
+ import{n as e}from"./buildXdiSyncEndpoint-Baimi1ur.mjs";import{t}from"./validateTranscendAuth-BrVGfq6X.mjs";import{t as n}from"./done-input-validation-LiTaCEzF.mjs";import r from"colors";async function i({auth:i,xdiLocation:a,file:o,removeIpAddresses:s,domainBlockList:c,xdiAllowedCommands:l,transcendUrl:u}){n(this.process);let{syncGroups:d,html:f}=await e(await t(i,this),{xdiLocation:a,transcendUrl:u,removeIpAddresses:s,domainBlockList:c.length>0?c:void 0,xdiAllowedCommands:l});this.logger.info(r.green(`Successfully constructed sync endpoint for sync groups: ${JSON.stringify(d,null,2)}`)),this.fs.writeFileSync(o,f),this.logger.info(r.green(`Wrote configuration to file "${o}"!`))}export{i as buildXdiSyncEndpoint};
2
+ //# sourceMappingURL=impl-RKWeHPtR.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-BkQryDNq.mjs","names":["buildXdiSyncEndpointHelper"],"sources":["../src/commands/consent/build-xdi-sync-endpoint/impl.ts"],"sourcesContent":["import colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { validateTranscendAuth } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { buildXdiSyncEndpoint as buildXdiSyncEndpointHelper } from '../../../lib/consent-manager/index.js';\n\nexport interface BuildXdiSyncEndpointCommandFlags {\n auth: string;\n xdiLocation: string;\n file: string;\n removeIpAddresses: boolean;\n domainBlockList: string[];\n xdiAllowedCommands: string;\n transcendUrl: string;\n}\n\nexport async function buildXdiSyncEndpoint(\n this: LocalContext,\n {\n auth,\n xdiLocation,\n file,\n removeIpAddresses,\n domainBlockList,\n xdiAllowedCommands,\n transcendUrl,\n }: BuildXdiSyncEndpointCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n // Parse authentication as API key or path to list of API keys\n const apiKeyOrList = await validateTranscendAuth(auth, this);\n\n // Build the sync endpoint\n const { syncGroups, html } = await buildXdiSyncEndpointHelper(apiKeyOrList, {\n xdiLocation,\n transcendUrl,\n removeIpAddresses,\n domainBlockList: domainBlockList.length > 0 ? domainBlockList : undefined,\n xdiAllowedCommands,\n });\n\n // Log success\n this.logger.info(\n colors.green(\n `Successfully constructed sync endpoint for sync groups: ${JSON.stringify(\n syncGroups,\n null,\n 2,\n )}`,\n ),\n );\n\n // Write to disk\n this.fs.writeFileSync(file, html);\n this.logger.info(colors.green(`Wrote configuration to file \"${file}\"!`));\n}\n"],"mappings":"2LAiBA,eAAsB,EAEpB,CACE,OACA,cACA,OACA,oBACA,kBACA,qBACA,gBAEa,CACf,EAAoB,KAAK,QAAQ,CAMjC,GAAM,CAAE,aAAY,QAAS,MAAMA,EAA2B,MAHnC,EAAsB,EAAM,KAAK,CAGgB,CAC1E,cACA,eACA,oBACA,gBAAiB,EAAgB,OAAS,EAAI,EAAkB,IAAA,GAChE,qBACD,CAAC,CAGF,KAAK,OAAO,KACV,EAAO,MACL,2DAA2D,KAAK,UAC9D,EACA,KACA,EACD,GACF,CACF,CAGD,KAAK,GAAG,cAAc,EAAM,EAAK,CACjC,KAAK,OAAO,KAAK,EAAO,MAAM,gCAAgC,EAAK,IAAI,CAAC"}
1
+ {"version":3,"file":"impl-RKWeHPtR.mjs","names":["buildXdiSyncEndpointHelper"],"sources":["../src/commands/consent/build-xdi-sync-endpoint/impl.ts"],"sourcesContent":["import colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { validateTranscendAuth } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { buildXdiSyncEndpoint as buildXdiSyncEndpointHelper } from '../../../lib/consent-manager/index.js';\n\nexport interface BuildXdiSyncEndpointCommandFlags {\n auth: string;\n xdiLocation: string;\n file: string;\n removeIpAddresses: boolean;\n domainBlockList: string[];\n xdiAllowedCommands: string;\n transcendUrl: string;\n}\n\nexport async function buildXdiSyncEndpoint(\n this: LocalContext,\n {\n auth,\n xdiLocation,\n file,\n removeIpAddresses,\n domainBlockList,\n xdiAllowedCommands,\n transcendUrl,\n }: BuildXdiSyncEndpointCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n // Parse authentication as API key or path to list of API keys\n const apiKeyOrList = await validateTranscendAuth(auth, this);\n\n // Build the sync endpoint\n const { syncGroups, html } = await buildXdiSyncEndpointHelper(apiKeyOrList, {\n xdiLocation,\n transcendUrl,\n removeIpAddresses,\n domainBlockList: domainBlockList.length > 0 ? domainBlockList : undefined,\n xdiAllowedCommands,\n });\n\n // Log success\n this.logger.info(\n colors.green(\n `Successfully constructed sync endpoint for sync groups: ${JSON.stringify(\n syncGroups,\n null,\n 2,\n )}`,\n ),\n );\n\n // Write to disk\n this.fs.writeFileSync(file, html);\n this.logger.info(colors.green(`Wrote configuration to file \"${file}\"!`));\n}\n"],"mappings":"2LAiBA,eAAsB,EAEpB,CACE,OACA,cACA,OACA,oBACA,kBACA,qBACA,gBAEa,CACf,EAAoB,KAAK,QAAQ,CAMjC,GAAM,CAAE,aAAY,QAAS,MAAMA,EAA2B,MAHnC,EAAsB,EAAM,KAAK,CAGgB,CAC1E,cACA,eACA,oBACA,gBAAiB,EAAgB,OAAS,EAAI,EAAkB,IAAA,GAChE,qBACD,CAAC,CAGF,KAAK,OAAO,KACV,EAAO,MACL,2DAA2D,KAAK,UAC9D,EACA,KACA,EACD,GACF,CACF,CAGD,KAAK,GAAG,cAAc,EAAM,EAAK,CACjC,KAAK,OAAO,KAAK,EAAO,MAAM,gCAAgC,EAAK,IAAI,CAAC"}
@@ -1,2 +1,2 @@
1
- import{l as e}from"./constants-DAx9VK1C.mjs";import{t}from"./generateCrossAccountApiKeys-CjmSyfwm.mjs";import{t as n}from"./done-input-validation-LiTaCEzF.mjs";async function r({email:r,password:i,apiKeyTitle:a,file:o,scopes:s,deleteExistingApiKey:c,createNewApiKey:l,parentOrganizationId:u,transcendUrl:d}){n(this.process);let{errors:f,apiKeys:p}=await t({transcendUrl:d,password:i,email:r,parentOrganizationId:u,deleteExistingApiKey:c,createNewApiKey:l,apiKeyTitle:a,scopes:s.map(t=>e[t].name)});this.fs.writeFileSync(o,`${JSON.stringify(p,null,2)}\n`),f.length>0&&this.process.exit(1)}export{r as generateApiKeys};
2
- //# sourceMappingURL=impl-D8yF0jw9.mjs.map
1
+ import{l as e}from"./constants-BUOpqzcO.mjs";import{t}from"./generateCrossAccountApiKeys-QJeUqbsi.mjs";import{t as n}from"./done-input-validation-LiTaCEzF.mjs";async function r({email:r,password:i,apiKeyTitle:a,file:o,scopes:s,deleteExistingApiKey:c,createNewApiKey:l,parentOrganizationId:u,transcendUrl:d}){n(this.process);let{errors:f,apiKeys:p}=await t({transcendUrl:d,password:i,email:r,parentOrganizationId:u,deleteExistingApiKey:c,createNewApiKey:l,apiKeyTitle:a,scopes:s.map(t=>e[t].name)});this.fs.writeFileSync(o,`${JSON.stringify(p,null,2)}\n`),f.length>0&&this.process.exit(1)}export{r as generateApiKeys};
2
+ //# sourceMappingURL=impl-esdKjQ_g.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-D8yF0jw9.mjs","names":[],"sources":["../src/commands/admin/generate-api-keys/impl.ts"],"sourcesContent":["import { ScopeName } from '@transcend-io/privacy-types';\n\nimport { SCOPES_BY_TITLE } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { generateCrossAccountApiKeys } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\n\n// Command flag interface\nexport interface GenerateApiKeysCommandFlags {\n email: string;\n password: string;\n apiKeyTitle: string;\n file: string;\n scopes: string[];\n deleteExistingApiKey: boolean;\n createNewApiKey: boolean;\n parentOrganizationId?: string;\n transcendUrl: string;\n}\n\n// Command implementation\nexport async function generateApiKeys(\n this: LocalContext,\n {\n email,\n password,\n apiKeyTitle,\n file,\n scopes,\n deleteExistingApiKey,\n createNewApiKey,\n parentOrganizationId,\n transcendUrl,\n }: GenerateApiKeysCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n const scopeNames = scopes.map((scopeTitle) => SCOPES_BY_TITLE[scopeTitle].name as ScopeName);\n\n // Upload privacy requests\n const { errors, apiKeys } = await generateCrossAccountApiKeys({\n transcendUrl,\n password,\n email,\n parentOrganizationId,\n deleteExistingApiKey,\n createNewApiKey,\n apiKeyTitle,\n scopes: scopeNames,\n });\n\n // Write to disk\n this.fs.writeFileSync(file, `${JSON.stringify(apiKeys, null, 2)}\\n`);\n if (errors.length > 0) {\n this.process.exit(1);\n }\n}\n"],"mappings":"gKAqBA,eAAsB,EAEpB,CACE,QACA,WACA,cACA,OACA,SACA,uBACA,kBACA,uBACA,gBAEa,CACf,EAAoB,KAAK,QAAQ,CAKjC,GAAM,CAAE,SAAQ,WAAY,MAAM,EAA4B,CAC5D,eACA,WACA,QACA,uBACA,uBACA,kBACA,cACA,OAXiB,EAAO,IAAK,GAAe,EAAgB,GAAY,KAWtD,CACnB,CAAC,CAGF,KAAK,GAAG,cAAc,EAAM,GAAG,KAAK,UAAU,EAAS,KAAM,EAAE,CAAC,IAAI,CAChE,EAAO,OAAS,GAClB,KAAK,QAAQ,KAAK,EAAE"}
1
+ {"version":3,"file":"impl-esdKjQ_g.mjs","names":[],"sources":["../src/commands/admin/generate-api-keys/impl.ts"],"sourcesContent":["import { ScopeName } from '@transcend-io/privacy-types';\n\nimport { SCOPES_BY_TITLE } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { generateCrossAccountApiKeys } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\n\n// Command flag interface\nexport interface GenerateApiKeysCommandFlags {\n email: string;\n password: string;\n apiKeyTitle: string;\n file: string;\n scopes: string[];\n deleteExistingApiKey: boolean;\n createNewApiKey: boolean;\n parentOrganizationId?: string;\n transcendUrl: string;\n}\n\n// Command implementation\nexport async function generateApiKeys(\n this: LocalContext,\n {\n email,\n password,\n apiKeyTitle,\n file,\n scopes,\n deleteExistingApiKey,\n createNewApiKey,\n parentOrganizationId,\n transcendUrl,\n }: GenerateApiKeysCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n const scopeNames = scopes.map((scopeTitle) => SCOPES_BY_TITLE[scopeTitle].name as ScopeName);\n\n // Upload privacy requests\n const { errors, apiKeys } = await generateCrossAccountApiKeys({\n transcendUrl,\n password,\n email,\n parentOrganizationId,\n deleteExistingApiKey,\n createNewApiKey,\n apiKeyTitle,\n scopes: scopeNames,\n });\n\n // Write to disk\n this.fs.writeFileSync(file, `${JSON.stringify(apiKeys, null, 2)}\\n`);\n if (errors.length > 0) {\n this.process.exit(1);\n }\n}\n"],"mappings":"gKAqBA,eAAsB,EAEpB,CACE,QACA,WACA,cACA,OACA,SACA,uBACA,kBACA,uBACA,gBAEa,CACf,EAAoB,KAAK,QAAQ,CAKjC,GAAM,CAAE,SAAQ,WAAY,MAAM,EAA4B,CAC5D,eACA,WACA,QACA,uBACA,uBACA,kBACA,cACA,OAXiB,EAAO,IAAK,GAAe,EAAgB,GAAY,KAWtD,CACnB,CAAC,CAGF,KAAK,GAAG,cAAc,EAAM,GAAG,KAAK,UAAU,EAAS,KAAM,EAAE,CAAC,IAAI,CAChE,EAAO,OAAS,GAClB,KAAK,QAAQ,KAAK,EAAE"}
@@ -1,2 +1,2 @@
1
- import{t as e}from"./streamPrivacyRequestsToCsv-DVPQ860_.mjs";import{t}from"./done-input-validation-LiTaCEzF.mjs";import n from"colors";async function r({auth:r,transcendUrl:i,file:a,pageLimit:o,concurrency:s,actions:c,sombraAuth:l,skipRequestIdentifiers:u,statuses:d,createdAtBefore:f,createdAtAfter:p,updatedAtBefore:m,updatedAtAfter:h,showTests:g}){t(this.process);let{filePaths:_,totalCount:v}=await e({transcendUrl:i,concurrency:s,pageLimit:o,actions:c,statuses:d,auth:r,sombraAuth:l,skipRequestIdentifiers:u,createdAtBefore:f,createdAtAfter:p,updatedAtBefore:m,updatedAtAfter:h,isTest:g,file:a});this.logger.info(n.green(`Successfully wrote ${v} requests to ${_.length} file(s): ${_.join(`, `)}`))}export{r as _export};
2
- //# sourceMappingURL=impl-BahDGEJJ.mjs.map
1
+ import{t as e}from"./streamPrivacyRequestsToCsv-DRFdc0OG.mjs";import{t}from"./done-input-validation-LiTaCEzF.mjs";import n from"colors";async function r({auth:r,transcendUrl:i,file:a,pageLimit:o,concurrency:s,actions:c,sombraAuth:l,skipRequestIdentifiers:u,statuses:d,createdAtBefore:f,createdAtAfter:p,updatedAtBefore:m,updatedAtAfter:h,showTests:g}){t(this.process);let{filePaths:_,totalCount:v}=await e({transcendUrl:i,concurrency:s,pageLimit:o,actions:c,statuses:d,auth:r,sombraAuth:l,skipRequestIdentifiers:u,createdAtBefore:f,createdAtAfter:p,updatedAtBefore:m,updatedAtAfter:h,isTest:g,file:a});this.logger.info(n.green(`Successfully wrote ${v} requests to ${_.length} file(s): ${_.join(`, `)}`))}export{r as _export};
2
+ //# sourceMappingURL=impl-f-5kotyg.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-BahDGEJJ.mjs","names":[],"sources":["../src/commands/request/export/impl.ts"],"sourcesContent":["import type { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { streamPrivacyRequestsToCsv } from '../../../lib/requests/index.js';\n\nexport interface ExportCommandFlags {\n auth: string;\n sombraAuth?: string;\n actions?: RequestAction[];\n statuses?: RequestStatus[];\n transcendUrl: string;\n file: string;\n concurrency: number;\n createdAtBefore?: Date;\n createdAtAfter?: Date;\n updatedAtBefore?: Date;\n updatedAtAfter?: Date;\n showTests?: boolean;\n skipRequestIdentifiers?: boolean;\n pageLimit: number;\n}\n\n// `export` is a reserved keyword, so we need to prefix it with an underscore\n// eslint-disable-next-line no-underscore-dangle\nexport async function _export(\n this: LocalContext,\n {\n auth,\n transcendUrl,\n file,\n pageLimit,\n concurrency,\n actions,\n sombraAuth,\n skipRequestIdentifiers,\n statuses,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n showTests,\n }: ExportCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n const { filePaths, totalCount } = await streamPrivacyRequestsToCsv({\n transcendUrl,\n concurrency,\n pageLimit,\n actions,\n statuses,\n auth,\n sombraAuth,\n skipRequestIdentifiers,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n isTest: showTests,\n file,\n });\n\n this.logger.info(\n colors.green(\n `Successfully wrote ${totalCount} requests to ` +\n `${filePaths.length} file(s): ${filePaths.join(', ')}`,\n ),\n );\n}\n"],"mappings":"wIA0BA,eAAsB,EAEpB,CACE,OACA,eACA,OACA,YACA,cACA,UACA,aACA,yBACA,WACA,kBACA,iBACA,kBACA,iBACA,aAEa,CACf,EAAoB,KAAK,QAAQ,CAEjC,GAAM,CAAE,YAAW,cAAe,MAAM,EAA2B,CACjE,eACA,cACA,YACA,UACA,WACA,OACA,aACA,yBACA,kBACA,iBACA,kBACA,iBACA,OAAQ,EACR,OACD,CAAC,CAEF,KAAK,OAAO,KACV,EAAO,MACL,sBAAsB,EAAW,eAC5B,EAAU,OAAO,YAAY,EAAU,KAAK,KAAK,GACvD,CACF"}
1
+ {"version":3,"file":"impl-f-5kotyg.mjs","names":[],"sources":["../src/commands/request/export/impl.ts"],"sourcesContent":["import type { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { streamPrivacyRequestsToCsv } from '../../../lib/requests/index.js';\n\nexport interface ExportCommandFlags {\n auth: string;\n sombraAuth?: string;\n actions?: RequestAction[];\n statuses?: RequestStatus[];\n transcendUrl: string;\n file: string;\n concurrency: number;\n createdAtBefore?: Date;\n createdAtAfter?: Date;\n updatedAtBefore?: Date;\n updatedAtAfter?: Date;\n showTests?: boolean;\n skipRequestIdentifiers?: boolean;\n pageLimit: number;\n}\n\n// `export` is a reserved keyword, so we need to prefix it with an underscore\n// eslint-disable-next-line no-underscore-dangle\nexport async function _export(\n this: LocalContext,\n {\n auth,\n transcendUrl,\n file,\n pageLimit,\n concurrency,\n actions,\n sombraAuth,\n skipRequestIdentifiers,\n statuses,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n showTests,\n }: ExportCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n const { filePaths, totalCount } = await streamPrivacyRequestsToCsv({\n transcendUrl,\n concurrency,\n pageLimit,\n actions,\n statuses,\n auth,\n sombraAuth,\n skipRequestIdentifiers,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n isTest: showTests,\n file,\n });\n\n this.logger.info(\n colors.green(\n `Successfully wrote ${totalCount} requests to ` +\n `${filePaths.length} file(s): ${filePaths.join(', ')}`,\n ),\n );\n}\n"],"mappings":"wIA0BA,eAAsB,EAEpB,CACE,OACA,eACA,OACA,YACA,cACA,UACA,aACA,yBACA,WACA,kBACA,iBACA,kBACA,iBACA,aAEa,CACf,EAAoB,KAAK,QAAQ,CAEjC,GAAM,CAAE,YAAW,cAAe,MAAM,EAA2B,CACjE,eACA,cACA,YACA,UACA,WACA,OACA,aACA,yBACA,kBACA,iBACA,kBACA,iBACA,OAAQ,EACR,OACD,CAAC,CAEF,KAAK,OAAO,KACV,EAAO,MACL,sBAAsB,EAAW,eAC5B,EAAU,OAAO,YAAY,EAAU,KAAK,KAAK,GACvD,CACF"}
@@ -1,2 +1,2 @@
1
- import{r as e}from"./constants-DAx9VK1C.mjs";import{r as t}from"./readTranscendYaml-D576bvzR.mjs";import{n,t as r}from"./mergeTranscendInputs-9kQ3t5VY.mjs";import{t as i}from"./parseVariablesFromString-6TYW65LF.mjs";import{t as a}from"./validateTranscendAuth-BrVGfq6X.mjs";import{t as o}from"./listFiles-DDGCBdtx.mjs";import{t as s}from"./done-input-validation-LiTaCEzF.mjs";import c from"node:path";import l from"colors";import{mapSeries as u}from"@transcend-io/utils";import{buildTranscendGraphQLClient as d}from"@transcend-io/sdk";async function f({transcendUrl:e,auth:t,pageSize:r,publishToPrivacyCenter:i,contents:a,deleteExtraAttributeValues:o=!1,classifyService:s=!1,logger:c}){let u=d(e,t);try{let e=await n(a,u,{pageSize:r,publishToPrivacyCenter:i,classifyService:s,deleteExtraAttributeValues:o,logger:c});return e.success||e.errors.forEach(({resource:e,item:t,message:n})=>{c.error(l.red(`Failed to sync ${e}${t?` "${t}"`:``}: ${n}`))}),e.success}catch(e){return c.error(l.red(`An unexpected error occurred syncing the schema: ${e.message}`)),!1}}async function p({file:n=`./transcend.yml`,transcendUrl:d,auth:p,variables:m,pageSize:h,publishToPrivacyCenter:g,classifyService:_,deleteExtraAttributeValues:v}){s(this.process);let y=await a(p,this),b=i(m),x;if(x=Array.isArray(y)&&this.fs.lstatSync(n).isDirectory()?o(this.fs.readdirSync(n)).map(e=>c.join(n,e)):n.split(`,`),x.length<1)throw Error(`No file specified!`);let S=x.map(e=>{this.fs.existsSync(e)?this.logger.info(l.magenta(`Reading file "${e}"...`)):(this.logger.error(l.red(`The file path does not exist on disk: ${e}. You can specify the filepath using --file=./examples/transcend.yml`)),this.process.exit(1));try{let n=t(this.fs.readFileSync(e,`utf8`),b,e);return this.logger.info(l.green(`Successfully read in "${e}"`)),{content:n,name:e.split(`/`).pop().replace(`.yml`,``)}}catch(e){this.logger.error(l.red(`The shape of your yaml file is invalid with the following errors: ${e.message}`)),this.process.exit(1)}});if(typeof y==`string`){let[t,...n]=S.map(({content:e})=>e);await f({transcendUrl:d,auth:y,contents:r(t,...n),publishToPrivacyCenter:g,deleteExtraAttributeValues:v,pageSize:h,classifyService:!!_,logger:this.logger})||(this.logger.info(l.red(`Sync encountered errors. View output above for more information, or check out ${e}`)),this.process.exit(1))}else{if(S.length!==1&&S.length!==y.length)throw Error(`Expected list of yml files to be equal to the list of API keys.Got ${S.length} YML file${S.length===1?``:`s`} and ${y.length} API key${y.length===1?``:`s`}`);let t=[];await u(y,async(e,n)=>{let r=`[${n+1}/${y.length}][${e.organizationName}] `;this.logger.info(l.magenta(`~~~\n\n${r}Attempting to push configuration...\n\n~~~`));let i=S.length===1?S[0].content:S.find(t=>t.name===e.organizationName)?.content;if(!i){this.logger.error(l.red(`${r}Failed to find transcend.yml file for organization: "${e.organizationName}".`)),t.push(e.organizationName);return}await f({transcendUrl:d,auth:e.apiKey,contents:i,pageSize:h,publishToPrivacyCenter:g,deleteExtraAttributeValues:v,classifyService:_,logger:this.logger})?this.logger.info(l.green(`${r}Successfully pushed configuration!`)):(this.logger.error(l.red(`${r}Failed to sync configuration.`)),t.push(e.organizationName))}),t.length>0&&(this.logger.info(l.red(`Sync encountered errors for "${t.join(`,`)}". View output above for more information, or check out ${e}`)),this.process.exit(1))}this.logger.info(l.green(`Successfully synced yaml file to Transcend! View at ${e}`))}export{p as push};
2
- //# sourceMappingURL=impl-BLM6rMBq.mjs.map
1
+ import{r as e}from"./constants-BUOpqzcO.mjs";import{r as t}from"./readTranscendYaml-D576bvzR.mjs";import{n,t as r}from"./mergeTranscendInputs-9kQ3t5VY.mjs";import{t as i}from"./parseVariablesFromString-6TYW65LF.mjs";import{t as a}from"./validateTranscendAuth-BrVGfq6X.mjs";import{t as o}from"./listFiles-DDGCBdtx.mjs";import{t as s}from"./done-input-validation-LiTaCEzF.mjs";import c from"node:path";import l from"colors";import{mapSeries as u}from"@transcend-io/utils";import{buildTranscendGraphQLClient as d}from"@transcend-io/sdk";async function f({transcendUrl:e,auth:t,pageSize:r,publishToPrivacyCenter:i,contents:a,deleteExtraAttributeValues:o=!1,classifyService:s=!1,logger:c}){let u=d(e,t);try{let e=await n(a,u,{pageSize:r,publishToPrivacyCenter:i,classifyService:s,deleteExtraAttributeValues:o,logger:c});return e.success||e.errors.forEach(({resource:e,item:t,message:n})=>{c.error(l.red(`Failed to sync ${e}${t?` "${t}"`:``}: ${n}`))}),e.success}catch(e){return c.error(l.red(`An unexpected error occurred syncing the schema: ${e.message}`)),!1}}async function p({file:n=`./transcend.yml`,transcendUrl:d,auth:p,variables:m,pageSize:h,publishToPrivacyCenter:g,classifyService:_,deleteExtraAttributeValues:v}){s(this.process);let y=await a(p,this),b=i(m),x;if(x=Array.isArray(y)&&this.fs.lstatSync(n).isDirectory()?o(this.fs.readdirSync(n)).map(e=>c.join(n,e)):n.split(`,`),x.length<1)throw Error(`No file specified!`);let S=x.map(e=>{this.fs.existsSync(e)?this.logger.info(l.magenta(`Reading file "${e}"...`)):(this.logger.error(l.red(`The file path does not exist on disk: ${e}. You can specify the filepath using --file=./examples/transcend.yml`)),this.process.exit(1));try{let n=t(this.fs.readFileSync(e,`utf8`),b,e);return this.logger.info(l.green(`Successfully read in "${e}"`)),{content:n,name:e.split(`/`).pop().replace(`.yml`,``)}}catch(e){this.logger.error(l.red(`The shape of your yaml file is invalid with the following errors: ${e.message}`)),this.process.exit(1)}});if(typeof y==`string`){let[t,...n]=S.map(({content:e})=>e);await f({transcendUrl:d,auth:y,contents:r(t,...n),publishToPrivacyCenter:g,deleteExtraAttributeValues:v,pageSize:h,classifyService:!!_,logger:this.logger})||(this.logger.info(l.red(`Sync encountered errors. View output above for more information, or check out ${e}`)),this.process.exit(1))}else{if(S.length!==1&&S.length!==y.length)throw Error(`Expected list of yml files to be equal to the list of API keys.Got ${S.length} YML file${S.length===1?``:`s`} and ${y.length} API key${y.length===1?``:`s`}`);let t=[];await u(y,async(e,n)=>{let r=`[${n+1}/${y.length}][${e.organizationName}] `;this.logger.info(l.magenta(`~~~\n\n${r}Attempting to push configuration...\n\n~~~`));let i=S.length===1?S[0].content:S.find(t=>t.name===e.organizationName)?.content;if(!i){this.logger.error(l.red(`${r}Failed to find transcend.yml file for organization: "${e.organizationName}".`)),t.push(e.organizationName);return}await f({transcendUrl:d,auth:e.apiKey,contents:i,pageSize:h,publishToPrivacyCenter:g,deleteExtraAttributeValues:v,classifyService:_,logger:this.logger})?this.logger.info(l.green(`${r}Successfully pushed configuration!`)):(this.logger.error(l.red(`${r}Failed to sync configuration.`)),t.push(e.organizationName))}),t.length>0&&(this.logger.info(l.red(`Sync encountered errors for "${t.join(`,`)}". View output above for more information, or check out ${e}`)),this.process.exit(1))}this.logger.info(l.green(`Successfully synced yaml file to Transcend! View at ${e}`))}export{p as push};
2
+ //# sourceMappingURL=impl-hCvUhuoT.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-BLM6rMBq.mjs","names":[],"sources":["../src/commands/inventory/push/impl.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { buildTranscendGraphQLClient } from '@transcend-io/sdk';\nimport { mapSeries } from '@transcend-io/utils';\nimport colors from 'colors';\n\nimport { TranscendInput } from '../../../codecs.js';\nimport { ADMIN_DASH_INTEGRATIONS } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { validateTranscendAuth, filterFileNames } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { syncConfigurationToTranscend } from '../../../lib/graphql/index.js';\nimport { parseVariablesFromString } from '../../../lib/helpers/parseVariablesFromString.js';\nimport { mergeTranscendInputs } from '../../../lib/mergeTranscendInputs.js';\nimport { parseTranscendYaml } from '../../../lib/readTranscendYaml.js';\n\n/**\n * Sync configuration to Transcend\n *\n * @param options - Options\n * @returns True if synced successfully, false if error occurs\n */\nasync function syncConfiguration({\n transcendUrl,\n auth,\n pageSize,\n publishToPrivacyCenter,\n contents,\n deleteExtraAttributeValues = false,\n classifyService = false,\n logger,\n}: {\n /** Transcend YAML */\n contents: TranscendInput;\n /** Transcend URL */\n transcendUrl: string;\n /** API key */\n auth: string;\n /** Page size */\n pageSize: number;\n /** Skip privacy center publish step */\n publishToPrivacyCenter: boolean;\n /** classify data flow service if missing */\n classifyService?: boolean;\n /** Delete attributes when syncing */\n deleteExtraAttributeValues?: boolean;\n /** Logger for reporting sync progress and errors */\n logger: LocalContext['logger'];\n}): Promise<boolean> {\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n // Sync to Transcend\n try {\n const result = await syncConfigurationToTranscend(contents, client, {\n pageSize,\n publishToPrivacyCenter,\n classifyService,\n deleteExtraAttributeValues,\n logger,\n });\n if (!result.success) {\n result.errors.forEach(({ resource, item, message }) => {\n logger.error(\n colors.red(`Failed to sync ${resource}${item ? ` \"${item}\"` : ''}: ${message}`),\n );\n });\n }\n return result.success;\n } catch (err) {\n logger.error(colors.red(`An unexpected error occurred syncing the schema: ${err.message}`));\n return false;\n }\n}\n\nexport interface PushCommandFlags {\n auth: string;\n file: string;\n transcendUrl: string;\n pageSize: number;\n variables: string;\n publishToPrivacyCenter: boolean;\n classifyService: boolean;\n deleteExtraAttributeValues: boolean;\n}\n\nexport async function push(\n this: LocalContext,\n {\n file = './transcend.yml',\n transcendUrl,\n auth,\n variables,\n pageSize,\n publishToPrivacyCenter,\n classifyService,\n deleteExtraAttributeValues,\n }: PushCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n // Parse authentication as API key or path to list of API keys\n const apiKeyOrList = await validateTranscendAuth(auth, this);\n\n const vars = parseVariablesFromString(variables);\n\n // check if we are being passed a list of API keys and a list of files\n let fileList: string[];\n if (Array.isArray(apiKeyOrList) && this.fs.lstatSync(file).isDirectory()) {\n fileList = filterFileNames(this.fs.readdirSync(file)).map((filePath) =>\n path.join(file, filePath),\n );\n } else {\n fileList = file.split(',');\n }\n\n // Ensure at least one file is parsed\n if (fileList.length < 1) {\n throw new Error('No file specified!');\n }\n\n // eslint-disable-next-line array-callback-return,consistent-return\n const transcendInputs = fileList.map((filePath) => {\n // Ensure yaml file exists on disk\n if (!this.fs.existsSync(filePath)) {\n this.logger.error(\n colors.red(\n `The file path does not exist on disk: ${filePath}. You can specify the filepath using --file=./examples/transcend.yml`,\n ),\n );\n this.process.exit(1);\n } else {\n this.logger.info(colors.magenta(`Reading file \"${filePath}\"...`));\n }\n\n try {\n // Read in the yaml file and validate it's shape\n const newContents = parseTranscendYaml(\n this.fs.readFileSync(filePath, 'utf8'),\n vars,\n filePath,\n );\n this.logger.info(colors.green(`Successfully read in \"${filePath}\"`));\n return {\n content: newContents,\n name: filePath.split('/').pop()!.replace('.yml', ''),\n };\n } catch (err) {\n this.logger.error(\n colors.red(\n `The shape of your yaml file is invalid with the following errors: ${err.message}`,\n ),\n );\n this.process.exit(1);\n }\n });\n\n // process a single API key\n if (typeof apiKeyOrList === 'string') {\n // if passed multiple inputs, merge them together\n const [base, ...rest] = transcendInputs.map(({ content }) => content);\n const contents = mergeTranscendInputs(base, ...rest);\n\n // sync the configuration\n const success = await syncConfiguration({\n transcendUrl,\n auth: apiKeyOrList,\n contents,\n publishToPrivacyCenter,\n deleteExtraAttributeValues,\n pageSize,\n classifyService: !!classifyService,\n logger: this.logger,\n });\n\n // exist with error code\n if (!success) {\n this.logger.info(\n colors.red(\n `Sync encountered errors. View output above for more information, or check out ${ADMIN_DASH_INTEGRATIONS}`,\n ),\n );\n\n this.process.exit(1);\n }\n } else {\n // if passed multiple inputs, expect them to be one per instance\n if (transcendInputs.length !== 1 && transcendInputs.length !== apiKeyOrList.length) {\n throw new Error(\n 'Expected list of yml files to be equal to the list of API keys.' +\n `Got ${transcendInputs.length} YML file${\n transcendInputs.length === 1 ? '' : 's'\n } and ${apiKeyOrList.length} API key${apiKeyOrList.length === 1 ? '' : 's'}`,\n );\n }\n\n const encounteredErrors: string[] = [];\n await mapSeries(apiKeyOrList, async (apiKey, ind) => {\n const prefix = `[${ind + 1}/${apiKeyOrList.length}][${apiKey.organizationName}] `;\n this.logger.info(\n colors.magenta(`~~~\\n\\n${prefix}Attempting to push configuration...\\n\\n~~~`),\n );\n\n // use the merged contents if 1 yml passed, else use the contents that map to that organization\n const useContents =\n transcendInputs.length === 1\n ? transcendInputs[0].content\n : transcendInputs.find((input) => input.name === apiKey.organizationName)?.content;\n\n // Throw error if cannot find a yml file matching that organization name\n if (!useContents) {\n this.logger.error(\n colors.red(\n `${prefix}Failed to find transcend.yml file for organization: \"${apiKey.organizationName}\".`,\n ),\n );\n encounteredErrors.push(apiKey.organizationName);\n return;\n }\n\n const success = await syncConfiguration({\n transcendUrl,\n auth: apiKey.apiKey,\n contents: useContents,\n pageSize,\n publishToPrivacyCenter,\n deleteExtraAttributeValues,\n classifyService,\n logger: this.logger,\n });\n\n if (success) {\n this.logger.info(colors.green(`${prefix}Successfully pushed configuration!`));\n } else {\n this.logger.error(colors.red(`${prefix}Failed to sync configuration.`));\n encounteredErrors.push(apiKey.organizationName);\n }\n });\n\n if (encounteredErrors.length > 0) {\n this.logger.info(\n colors.red(\n `Sync encountered errors for \"${encounteredErrors.join(\n ',',\n )}\". View output above for more information, or check out ${ADMIN_DASH_INTEGRATIONS}`,\n ),\n );\n\n this.process.exit(1);\n }\n }\n\n // Indicate success\n this.logger.info(\n colors.green(`Successfully synced yaml file to Transcend! View at ${ADMIN_DASH_INTEGRATIONS}`),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"impl-hCvUhuoT.mjs","names":[],"sources":["../src/commands/inventory/push/impl.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { buildTranscendGraphQLClient } from '@transcend-io/sdk';\nimport { mapSeries } from '@transcend-io/utils';\nimport colors from 'colors';\n\nimport { TranscendInput } from '../../../codecs.js';\nimport { ADMIN_DASH_INTEGRATIONS } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { validateTranscendAuth, filterFileNames } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { syncConfigurationToTranscend } from '../../../lib/graphql/index.js';\nimport { parseVariablesFromString } from '../../../lib/helpers/parseVariablesFromString.js';\nimport { mergeTranscendInputs } from '../../../lib/mergeTranscendInputs.js';\nimport { parseTranscendYaml } from '../../../lib/readTranscendYaml.js';\n\n/**\n * Sync configuration to Transcend\n *\n * @param options - Options\n * @returns True if synced successfully, false if error occurs\n */\nasync function syncConfiguration({\n transcendUrl,\n auth,\n pageSize,\n publishToPrivacyCenter,\n contents,\n deleteExtraAttributeValues = false,\n classifyService = false,\n logger,\n}: {\n /** Transcend YAML */\n contents: TranscendInput;\n /** Transcend URL */\n transcendUrl: string;\n /** API key */\n auth: string;\n /** Page size */\n pageSize: number;\n /** Skip privacy center publish step */\n publishToPrivacyCenter: boolean;\n /** classify data flow service if missing */\n classifyService?: boolean;\n /** Delete attributes when syncing */\n deleteExtraAttributeValues?: boolean;\n /** Logger for reporting sync progress and errors */\n logger: LocalContext['logger'];\n}): Promise<boolean> {\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n // Sync to Transcend\n try {\n const result = await syncConfigurationToTranscend(contents, client, {\n pageSize,\n publishToPrivacyCenter,\n classifyService,\n deleteExtraAttributeValues,\n logger,\n });\n if (!result.success) {\n result.errors.forEach(({ resource, item, message }) => {\n logger.error(\n colors.red(`Failed to sync ${resource}${item ? ` \"${item}\"` : ''}: ${message}`),\n );\n });\n }\n return result.success;\n } catch (err) {\n logger.error(colors.red(`An unexpected error occurred syncing the schema: ${err.message}`));\n return false;\n }\n}\n\nexport interface PushCommandFlags {\n auth: string;\n file: string;\n transcendUrl: string;\n pageSize: number;\n variables: string;\n publishToPrivacyCenter: boolean;\n classifyService: boolean;\n deleteExtraAttributeValues: boolean;\n}\n\nexport async function push(\n this: LocalContext,\n {\n file = './transcend.yml',\n transcendUrl,\n auth,\n variables,\n pageSize,\n publishToPrivacyCenter,\n classifyService,\n deleteExtraAttributeValues,\n }: PushCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n // Parse authentication as API key or path to list of API keys\n const apiKeyOrList = await validateTranscendAuth(auth, this);\n\n const vars = parseVariablesFromString(variables);\n\n // check if we are being passed a list of API keys and a list of files\n let fileList: string[];\n if (Array.isArray(apiKeyOrList) && this.fs.lstatSync(file).isDirectory()) {\n fileList = filterFileNames(this.fs.readdirSync(file)).map((filePath) =>\n path.join(file, filePath),\n );\n } else {\n fileList = file.split(',');\n }\n\n // Ensure at least one file is parsed\n if (fileList.length < 1) {\n throw new Error('No file specified!');\n }\n\n // eslint-disable-next-line array-callback-return,consistent-return\n const transcendInputs = fileList.map((filePath) => {\n // Ensure yaml file exists on disk\n if (!this.fs.existsSync(filePath)) {\n this.logger.error(\n colors.red(\n `The file path does not exist on disk: ${filePath}. You can specify the filepath using --file=./examples/transcend.yml`,\n ),\n );\n this.process.exit(1);\n } else {\n this.logger.info(colors.magenta(`Reading file \"${filePath}\"...`));\n }\n\n try {\n // Read in the yaml file and validate it's shape\n const newContents = parseTranscendYaml(\n this.fs.readFileSync(filePath, 'utf8'),\n vars,\n filePath,\n );\n this.logger.info(colors.green(`Successfully read in \"${filePath}\"`));\n return {\n content: newContents,\n name: filePath.split('/').pop()!.replace('.yml', ''),\n };\n } catch (err) {\n this.logger.error(\n colors.red(\n `The shape of your yaml file is invalid with the following errors: ${err.message}`,\n ),\n );\n this.process.exit(1);\n }\n });\n\n // process a single API key\n if (typeof apiKeyOrList === 'string') {\n // if passed multiple inputs, merge them together\n const [base, ...rest] = transcendInputs.map(({ content }) => content);\n const contents = mergeTranscendInputs(base, ...rest);\n\n // sync the configuration\n const success = await syncConfiguration({\n transcendUrl,\n auth: apiKeyOrList,\n contents,\n publishToPrivacyCenter,\n deleteExtraAttributeValues,\n pageSize,\n classifyService: !!classifyService,\n logger: this.logger,\n });\n\n // exist with error code\n if (!success) {\n this.logger.info(\n colors.red(\n `Sync encountered errors. View output above for more information, or check out ${ADMIN_DASH_INTEGRATIONS}`,\n ),\n );\n\n this.process.exit(1);\n }\n } else {\n // if passed multiple inputs, expect them to be one per instance\n if (transcendInputs.length !== 1 && transcendInputs.length !== apiKeyOrList.length) {\n throw new Error(\n 'Expected list of yml files to be equal to the list of API keys.' +\n `Got ${transcendInputs.length} YML file${\n transcendInputs.length === 1 ? '' : 's'\n } and ${apiKeyOrList.length} API key${apiKeyOrList.length === 1 ? '' : 's'}`,\n );\n }\n\n const encounteredErrors: string[] = [];\n await mapSeries(apiKeyOrList, async (apiKey, ind) => {\n const prefix = `[${ind + 1}/${apiKeyOrList.length}][${apiKey.organizationName}] `;\n this.logger.info(\n colors.magenta(`~~~\\n\\n${prefix}Attempting to push configuration...\\n\\n~~~`),\n );\n\n // use the merged contents if 1 yml passed, else use the contents that map to that organization\n const useContents =\n transcendInputs.length === 1\n ? transcendInputs[0].content\n : transcendInputs.find((input) => input.name === apiKey.organizationName)?.content;\n\n // Throw error if cannot find a yml file matching that organization name\n if (!useContents) {\n this.logger.error(\n colors.red(\n `${prefix}Failed to find transcend.yml file for organization: \"${apiKey.organizationName}\".`,\n ),\n );\n encounteredErrors.push(apiKey.organizationName);\n return;\n }\n\n const success = await syncConfiguration({\n transcendUrl,\n auth: apiKey.apiKey,\n contents: useContents,\n pageSize,\n publishToPrivacyCenter,\n deleteExtraAttributeValues,\n classifyService,\n logger: this.logger,\n });\n\n if (success) {\n this.logger.info(colors.green(`${prefix}Successfully pushed configuration!`));\n } else {\n this.logger.error(colors.red(`${prefix}Failed to sync configuration.`));\n encounteredErrors.push(apiKey.organizationName);\n }\n });\n\n if (encounteredErrors.length > 0) {\n this.logger.info(\n colors.red(\n `Sync encountered errors for \"${encounteredErrors.join(\n ',',\n )}\". View output above for more information, or check out ${ADMIN_DASH_INTEGRATIONS}`,\n ),\n );\n\n this.process.exit(1);\n }\n }\n\n // Indicate success\n this.logger.info(\n colors.green(`Successfully synced yaml file to Transcend! View at ${ADMIN_DASH_INTEGRATIONS}`),\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{t as e}from"./pullChunkedCustomSiloOutstandingIdentifiers-7qvaMN58.mjs";import{i as t,s as n}from"./writeCsv-CNZrq3zU.mjs";import{t as r}from"./done-input-validation-LiTaCEzF.mjs";import{chunk as i,uniq as a}from"lodash-es";import o from"colors";import{map as s}from"@transcend-io/utils";import{buildTranscendGraphQLClient as c,fetchRequestFilesForRequest as l}from"@transcend-io/sdk";async function u({file:u,fileTarget:d,transcendUrl:f,auth:p,sombraAuth:m,cronDataSiloId:h,targetDataSiloId:g,actions:_,skipRequestCount:v,pageLimit:y,chunkSize:b}){v&&this.logger.info(o.yellow(`Skipping request count as requested. This may help speed up the call.`)),(Number.isNaN(b)||b<=0||b%y!==0)&&(this.logger.error(o.red(`Invalid chunk size: "${b}". Must be a positive integer that is a multiple of ${y}.`)),this.process.exit(1)),r(this.process);let x=c(f,p),{baseName:S,extension:C}=t(u),{baseName:w,extension:T}=t(d),E=0,D=0,O=0;await e({dataSiloId:h,auth:p,sombraAuth:m,actions:_,apiPageSize:y,savePageSize:b,onSave:async e=>{E+=e.length;let t=await s(i(a(e.map(e=>e.requestId)),y),async e=>(this.logger.info(o.magenta(`Fetching target identifiers for ${e.length} requests`)),(await l(x,{logger:this.logger,pageSize:y*2,filterBy:{requestIds:e,dataSiloIds:[g]}})).map(({fileName:e,remoteId:t})=>{if(!t)throw Error(`Failed to find remoteId for ${e}`);return{RecordId:t,Object:e.replace(`.json`,``).split(`/`).pop()?.replace(` Information`,``),Comment:`Customer data deletion request submitted via transcend.io`}})),{concurrency:1});D+=t.flat().length;let r=a(e.map(e=>Object.keys(e)).flat()),c=`${S}-${O}${C}`,f=`${w}-${O}${T}`;await n(c,e,r),this.logger.info(o.green(`Successfully wrote ${e.length} identifiers to file "${u}"`));let p=t.flat();await n(f,p,a(p.map(e=>Object.keys(e)).flat())),this.logger.info(o.green(`Successfully wrote ${p.length} identifiers to file "${d}"`)),this.logger.info(o.blue(`Processed chunk of ${i.length} identifiers, found ${p.length} target identifiers`)),O+=1},transcendUrl:f,skipRequestCount:v}),this.logger.info(o.green(`Successfully wrote ${E} identifiers to file "${u}"`)),this.logger.info(o.green(`Successfully wrote ${D} identifiers to file "${d}"`))}export{u as pullProfiles};
2
- //# sourceMappingURL=impl-BIhXJ0Nw.mjs.map
1
+ import{t as e}from"./pullChunkedCustomSiloOutstandingIdentifiers-CtFtj3aL.mjs";import{i as t,s as n}from"./writeCsv-CNZrq3zU.mjs";import{t as r}from"./done-input-validation-LiTaCEzF.mjs";import{chunk as i,uniq as a}from"lodash-es";import o from"colors";import{map as s}from"@transcend-io/utils";import{buildTranscendGraphQLClient as c,fetchRequestFilesForRequest as l}from"@transcend-io/sdk";async function u({file:u,fileTarget:d,transcendUrl:f,auth:p,sombraAuth:m,cronDataSiloId:h,targetDataSiloId:g,actions:_,skipRequestCount:v,pageLimit:y,chunkSize:b}){v&&this.logger.info(o.yellow(`Skipping request count as requested. This may help speed up the call.`)),(Number.isNaN(b)||b<=0||b%y!==0)&&(this.logger.error(o.red(`Invalid chunk size: "${b}". Must be a positive integer that is a multiple of ${y}.`)),this.process.exit(1)),r(this.process);let x=c(f,p),{baseName:S,extension:C}=t(u),{baseName:w,extension:T}=t(d),E=0,D=0,O=0;await e({dataSiloId:h,auth:p,sombraAuth:m,actions:_,apiPageSize:y,savePageSize:b,onSave:async e=>{E+=e.length;let t=await s(i(a(e.map(e=>e.requestId)),y),async e=>(this.logger.info(o.magenta(`Fetching target identifiers for ${e.length} requests`)),(await l(x,{logger:this.logger,pageSize:y*2,filterBy:{requestIds:e,dataSiloIds:[g]}})).map(({fileName:e,remoteId:t})=>{if(!t)throw Error(`Failed to find remoteId for ${e}`);return{RecordId:t,Object:e.replace(`.json`,``).split(`/`).pop()?.replace(` Information`,``),Comment:`Customer data deletion request submitted via transcend.io`}})),{concurrency:1});D+=t.flat().length;let r=a(e.map(e=>Object.keys(e)).flat()),c=`${S}-${O}${C}`,f=`${w}-${O}${T}`;await n(c,e,r),this.logger.info(o.green(`Successfully wrote ${e.length} identifiers to file "${u}"`));let p=t.flat();await n(f,p,a(p.map(e=>Object.keys(e)).flat())),this.logger.info(o.green(`Successfully wrote ${p.length} identifiers to file "${d}"`)),this.logger.info(o.blue(`Processed chunk of ${i.length} identifiers, found ${p.length} target identifiers`)),O+=1},transcendUrl:f,skipRequestCount:v}),this.logger.info(o.green(`Successfully wrote ${E} identifiers to file "${u}"`)),this.logger.info(o.green(`Successfully wrote ${D} identifiers to file "${d}"`))}export{u as pullProfiles};
2
+ //# sourceMappingURL=impl-jUt0SP_K.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-BIhXJ0Nw.mjs","names":[],"sources":["../src/commands/request/cron/pull-profiles/impl.ts"],"sourcesContent":["import type { RequestAction } from '@transcend-io/privacy-types';\nimport { buildTranscendGraphQLClient, fetchRequestFilesForRequest } from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport colors from 'colors';\nimport { uniq, chunk } from 'lodash-es';\n\nimport type { LocalContext } from '../../../../context.js';\nimport { doneInputValidation } from '../../../../lib/cli/done-input-validation.js';\nimport {\n pullChunkedCustomSiloOutstandingIdentifiers,\n type CsvFormattedIdentifier,\n} from '../../../../lib/cron/index.js';\nimport { parseFilePath, writeLargeCsv } from '../../../../lib/helpers/index.js';\n\nexport interface PullProfilesCommandFlags {\n file: string;\n fileTarget: string;\n transcendUrl: string;\n auth: string;\n sombraAuth?: string;\n cronDataSiloId: string;\n targetDataSiloId: string;\n actions: RequestAction[];\n skipRequestCount: boolean;\n pageLimit: number;\n chunkSize: number;\n}\n\nexport async function pullProfiles(\n this: LocalContext,\n {\n file,\n fileTarget,\n transcendUrl,\n auth,\n sombraAuth,\n cronDataSiloId,\n targetDataSiloId,\n actions,\n skipRequestCount,\n pageLimit,\n chunkSize,\n }: PullProfilesCommandFlags,\n): Promise<void> {\n if (skipRequestCount) {\n this.logger.info(\n colors.yellow('Skipping request count as requested. This may help speed up the call.'),\n );\n }\n\n if (Number.isNaN(chunkSize) || chunkSize <= 0 || chunkSize % pageLimit !== 0) {\n this.logger.error(\n colors.red(\n `Invalid chunk size: \"${chunkSize}\". Must be a positive integer that is a multiple of ${pageLimit}.`,\n ),\n );\n this.process.exit(1);\n }\n\n doneInputValidation(this.process);\n\n // Create GraphQL client to connect to Transcend backend\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n const { baseName, extension } = parseFilePath(file);\n const { baseName: baseNameTarget, extension: extensionTarget } = parseFilePath(fileTarget);\n\n let allIdentifiersCount = 0;\n let allTargetIdentifiersCount = 0;\n let fileCount = 0;\n // Create onSave callback to handle chunked processing\n const onSave = async (chunkToSave: CsvFormattedIdentifier[]): Promise<void> => {\n // Add to all identifiers\n allIdentifiersCount += chunkToSave.length;\n\n // Get unique request IDs from this chunk\n const requestIds = chunkToSave.map((d) => d.requestId as string);\n const uniqueRequestIds = uniq(requestIds);\n\n // Pull down target identifiers for this chunk\n const chunkedRequestIds = chunk(uniqueRequestIds, pageLimit);\n const results = await map(\n chunkedRequestIds,\n async (requestIds) => {\n this.logger.info(\n colors.magenta(`Fetching target identifiers for ${requestIds.length} requests`),\n );\n const results = await fetchRequestFilesForRequest(client, {\n logger: this.logger,\n pageSize: pageLimit * 2,\n filterBy: {\n requestIds,\n dataSiloIds: [targetDataSiloId],\n },\n });\n return results.map(({ fileName, remoteId }) => {\n if (!remoteId) {\n throw new Error(`Failed to find remoteId for ${fileName}`);\n }\n return {\n RecordId: remoteId,\n Object: fileName.replace('.json', '').split('/').pop()?.replace(' Information', ''),\n Comment: 'Customer data deletion request submitted via transcend.io',\n };\n });\n },\n // We are grabbing all the request files for the 'pageLimit' # of requests at a time\n {\n concurrency: 1,\n },\n );\n\n allTargetIdentifiersCount += results.flat().length;\n\n // Write the identifiers and target identifiers to CSV\n const headers = uniq(chunkToSave.map((d) => Object.keys(d)).flat());\n const numberedFileName = `${baseName}-${fileCount}${extension}`;\n const numberedFileNameTarget = `${baseNameTarget}-${fileCount}${extensionTarget}`;\n await writeLargeCsv(numberedFileName, chunkToSave, headers);\n this.logger.info(\n colors.green(`Successfully wrote ${chunkToSave.length} identifiers to file \"${file}\"`),\n );\n\n const targetIdentifiers = results.flat();\n const headers2 = uniq(targetIdentifiers.map((d) => Object.keys(d)).flat());\n await writeLargeCsv(numberedFileNameTarget, targetIdentifiers, headers2);\n this.logger.info(\n colors.green(\n `Successfully wrote ${targetIdentifiers.length} identifiers to file \"${fileTarget}\"`,\n ),\n );\n\n this.logger.info(\n colors.blue(\n `Processed chunk of ${chunk.length} identifiers, found ${targetIdentifiers.length} target identifiers`,\n ),\n );\n fileCount += 1;\n };\n\n // Pull down outstanding identifiers using the new chunked function\n await pullChunkedCustomSiloOutstandingIdentifiers({\n dataSiloId: cronDataSiloId,\n auth,\n sombraAuth,\n actions,\n apiPageSize: pageLimit,\n savePageSize: chunkSize,\n onSave,\n transcendUrl,\n skipRequestCount,\n });\n\n this.logger.info(\n colors.green(`Successfully wrote ${allIdentifiersCount} identifiers to file \"${file}\"`),\n );\n this.logger.info(\n colors.green(\n `Successfully wrote ${allTargetIdentifiersCount} identifiers to file \"${fileTarget}\"`,\n ),\n );\n}\n"],"mappings":"wYA4BA,eAAsB,EAEpB,CACE,OACA,aACA,eACA,OACA,aACA,iBACA,mBACA,UACA,mBACA,YACA,aAEa,CACX,GACF,KAAK,OAAO,KACV,EAAO,OAAO,wEAAwE,CACvF,EAGC,OAAO,MAAM,EAAU,EAAI,GAAa,GAAK,EAAY,IAAc,KACzE,KAAK,OAAO,MACV,EAAO,IACL,wBAAwB,EAAU,sDAAsD,EAAU,GACnG,CACF,CACD,KAAK,QAAQ,KAAK,EAAE,EAGtB,EAAoB,KAAK,QAAQ,CAGjC,IAAM,EAAS,EAA4B,EAAc,EAAK,CACxD,CAAE,WAAU,aAAc,EAAc,EAAK,CAC7C,CAAE,SAAU,EAAgB,UAAW,GAAoB,EAAc,EAAW,CAEtF,EAAsB,EACtB,EAA4B,EAC5B,EAAY,EAwEhB,MAAM,EAA4C,CAChD,WAAY,EACZ,OACA,aACA,UACA,YAAa,EACb,aAAc,EACd,YA7EoB,IAAyD,CAE7E,GAAuB,EAAY,OAQnC,IAAM,EAAU,MAAM,EADI,EAHD,EADN,EAAY,IAAK,GAAM,EAAE,UACJ,CAGQ,CAAE,EAE/B,CACjB,KAAO,KACL,KAAK,OAAO,KACV,EAAO,QAAQ,mCAAmC,EAAW,OAAO,WAAW,CAChF,EASM,MARe,EAA4B,EAAQ,CACxD,OAAQ,KAAK,OACb,SAAU,EAAY,EACtB,SAAU,CACR,aACA,YAAa,CAAC,EAAiB,CAChC,CACF,CAAC,EACa,KAAK,CAAE,WAAU,cAAe,CAC7C,GAAI,CAAC,EACH,MAAU,MAAM,+BAA+B,IAAW,CAE5D,MAAO,CACL,SAAU,EACV,OAAQ,EAAS,QAAQ,QAAS,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,QAAQ,eAAgB,GAAG,CACnF,QAAS,4DACV,EACD,EAGJ,CACE,YAAa,EACd,CACF,CAED,GAA6B,EAAQ,MAAM,CAAC,OAG5C,IAAM,EAAU,EAAK,EAAY,IAAK,GAAM,OAAO,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAC7D,EAAmB,GAAG,EAAS,GAAG,IAAY,IAC9C,EAAyB,GAAG,EAAe,GAAG,IAAY,IAChE,MAAM,EAAc,EAAkB,EAAa,EAAQ,CAC3D,KAAK,OAAO,KACV,EAAO,MAAM,sBAAsB,EAAY,OAAO,wBAAwB,EAAK,GAAG,CACvF,CAED,IAAM,EAAoB,EAAQ,MAAM,CAExC,MAAM,EAAc,EAAwB,EAD3B,EAAK,EAAkB,IAAK,GAAM,OAAO,KAAK,EAAE,CAAC,CAAC,MAAM,CACF,CAAC,CACxE,KAAK,OAAO,KACV,EAAO,MACL,sBAAsB,EAAkB,OAAO,wBAAwB,EAAW,GACnF,CACF,CAED,KAAK,OAAO,KACV,EAAO,KACL,sBAAsB,EAAM,OAAO,sBAAsB,EAAkB,OAAO,qBACnF,CACF,CACD,GAAa,GAYb,eACA,mBACD,CAAC,CAEF,KAAK,OAAO,KACV,EAAO,MAAM,sBAAsB,EAAoB,wBAAwB,EAAK,GAAG,CACxF,CACD,KAAK,OAAO,KACV,EAAO,MACL,sBAAsB,EAA0B,wBAAwB,EAAW,GACpF,CACF"}
1
+ {"version":3,"file":"impl-jUt0SP_K.mjs","names":[],"sources":["../src/commands/request/cron/pull-profiles/impl.ts"],"sourcesContent":["import type { RequestAction } from '@transcend-io/privacy-types';\nimport { buildTranscendGraphQLClient, fetchRequestFilesForRequest } from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport colors from 'colors';\nimport { uniq, chunk } from 'lodash-es';\n\nimport type { LocalContext } from '../../../../context.js';\nimport { doneInputValidation } from '../../../../lib/cli/done-input-validation.js';\nimport {\n pullChunkedCustomSiloOutstandingIdentifiers,\n type CsvFormattedIdentifier,\n} from '../../../../lib/cron/index.js';\nimport { parseFilePath, writeLargeCsv } from '../../../../lib/helpers/index.js';\n\nexport interface PullProfilesCommandFlags {\n file: string;\n fileTarget: string;\n transcendUrl: string;\n auth: string;\n sombraAuth?: string;\n cronDataSiloId: string;\n targetDataSiloId: string;\n actions: RequestAction[];\n skipRequestCount: boolean;\n pageLimit: number;\n chunkSize: number;\n}\n\nexport async function pullProfiles(\n this: LocalContext,\n {\n file,\n fileTarget,\n transcendUrl,\n auth,\n sombraAuth,\n cronDataSiloId,\n targetDataSiloId,\n actions,\n skipRequestCount,\n pageLimit,\n chunkSize,\n }: PullProfilesCommandFlags,\n): Promise<void> {\n if (skipRequestCount) {\n this.logger.info(\n colors.yellow('Skipping request count as requested. This may help speed up the call.'),\n );\n }\n\n if (Number.isNaN(chunkSize) || chunkSize <= 0 || chunkSize % pageLimit !== 0) {\n this.logger.error(\n colors.red(\n `Invalid chunk size: \"${chunkSize}\". Must be a positive integer that is a multiple of ${pageLimit}.`,\n ),\n );\n this.process.exit(1);\n }\n\n doneInputValidation(this.process);\n\n // Create GraphQL client to connect to Transcend backend\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n const { baseName, extension } = parseFilePath(file);\n const { baseName: baseNameTarget, extension: extensionTarget } = parseFilePath(fileTarget);\n\n let allIdentifiersCount = 0;\n let allTargetIdentifiersCount = 0;\n let fileCount = 0;\n // Create onSave callback to handle chunked processing\n const onSave = async (chunkToSave: CsvFormattedIdentifier[]): Promise<void> => {\n // Add to all identifiers\n allIdentifiersCount += chunkToSave.length;\n\n // Get unique request IDs from this chunk\n const requestIds = chunkToSave.map((d) => d.requestId as string);\n const uniqueRequestIds = uniq(requestIds);\n\n // Pull down target identifiers for this chunk\n const chunkedRequestIds = chunk(uniqueRequestIds, pageLimit);\n const results = await map(\n chunkedRequestIds,\n async (requestIds) => {\n this.logger.info(\n colors.magenta(`Fetching target identifiers for ${requestIds.length} requests`),\n );\n const results = await fetchRequestFilesForRequest(client, {\n logger: this.logger,\n pageSize: pageLimit * 2,\n filterBy: {\n requestIds,\n dataSiloIds: [targetDataSiloId],\n },\n });\n return results.map(({ fileName, remoteId }) => {\n if (!remoteId) {\n throw new Error(`Failed to find remoteId for ${fileName}`);\n }\n return {\n RecordId: remoteId,\n Object: fileName.replace('.json', '').split('/').pop()?.replace(' Information', ''),\n Comment: 'Customer data deletion request submitted via transcend.io',\n };\n });\n },\n // We are grabbing all the request files for the 'pageLimit' # of requests at a time\n {\n concurrency: 1,\n },\n );\n\n allTargetIdentifiersCount += results.flat().length;\n\n // Write the identifiers and target identifiers to CSV\n const headers = uniq(chunkToSave.map((d) => Object.keys(d)).flat());\n const numberedFileName = `${baseName}-${fileCount}${extension}`;\n const numberedFileNameTarget = `${baseNameTarget}-${fileCount}${extensionTarget}`;\n await writeLargeCsv(numberedFileName, chunkToSave, headers);\n this.logger.info(\n colors.green(`Successfully wrote ${chunkToSave.length} identifiers to file \"${file}\"`),\n );\n\n const targetIdentifiers = results.flat();\n const headers2 = uniq(targetIdentifiers.map((d) => Object.keys(d)).flat());\n await writeLargeCsv(numberedFileNameTarget, targetIdentifiers, headers2);\n this.logger.info(\n colors.green(\n `Successfully wrote ${targetIdentifiers.length} identifiers to file \"${fileTarget}\"`,\n ),\n );\n\n this.logger.info(\n colors.blue(\n `Processed chunk of ${chunk.length} identifiers, found ${targetIdentifiers.length} target identifiers`,\n ),\n );\n fileCount += 1;\n };\n\n // Pull down outstanding identifiers using the new chunked function\n await pullChunkedCustomSiloOutstandingIdentifiers({\n dataSiloId: cronDataSiloId,\n auth,\n sombraAuth,\n actions,\n apiPageSize: pageLimit,\n savePageSize: chunkSize,\n onSave,\n transcendUrl,\n skipRequestCount,\n });\n\n this.logger.info(\n colors.green(`Successfully wrote ${allIdentifiersCount} identifiers to file \"${file}\"`),\n );\n this.logger.info(\n colors.green(\n `Successfully wrote ${allTargetIdentifiersCount} identifiers to file \"${fileTarget}\"`,\n ),\n );\n}\n"],"mappings":"wYA4BA,eAAsB,EAEpB,CACE,OACA,aACA,eACA,OACA,aACA,iBACA,mBACA,UACA,mBACA,YACA,aAEa,CACX,GACF,KAAK,OAAO,KACV,EAAO,OAAO,wEAAwE,CACvF,EAGC,OAAO,MAAM,EAAU,EAAI,GAAa,GAAK,EAAY,IAAc,KACzE,KAAK,OAAO,MACV,EAAO,IACL,wBAAwB,EAAU,sDAAsD,EAAU,GACnG,CACF,CACD,KAAK,QAAQ,KAAK,EAAE,EAGtB,EAAoB,KAAK,QAAQ,CAGjC,IAAM,EAAS,EAA4B,EAAc,EAAK,CACxD,CAAE,WAAU,aAAc,EAAc,EAAK,CAC7C,CAAE,SAAU,EAAgB,UAAW,GAAoB,EAAc,EAAW,CAEtF,EAAsB,EACtB,EAA4B,EAC5B,EAAY,EAwEhB,MAAM,EAA4C,CAChD,WAAY,EACZ,OACA,aACA,UACA,YAAa,EACb,aAAc,EACd,YA7EoB,IAAyD,CAE7E,GAAuB,EAAY,OAQnC,IAAM,EAAU,MAAM,EADI,EAHD,EADN,EAAY,IAAK,GAAM,EAAE,UACJ,CAGQ,CAAE,EAE/B,CACjB,KAAO,KACL,KAAK,OAAO,KACV,EAAO,QAAQ,mCAAmC,EAAW,OAAO,WAAW,CAChF,EASM,MARe,EAA4B,EAAQ,CACxD,OAAQ,KAAK,OACb,SAAU,EAAY,EACtB,SAAU,CACR,aACA,YAAa,CAAC,EAAiB,CAChC,CACF,CAAC,EACa,KAAK,CAAE,WAAU,cAAe,CAC7C,GAAI,CAAC,EACH,MAAU,MAAM,+BAA+B,IAAW,CAE5D,MAAO,CACL,SAAU,EACV,OAAQ,EAAS,QAAQ,QAAS,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,QAAQ,eAAgB,GAAG,CACnF,QAAS,4DACV,EACD,EAGJ,CACE,YAAa,EACd,CACF,CAED,GAA6B,EAAQ,MAAM,CAAC,OAG5C,IAAM,EAAU,EAAK,EAAY,IAAK,GAAM,OAAO,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAC7D,EAAmB,GAAG,EAAS,GAAG,IAAY,IAC9C,EAAyB,GAAG,EAAe,GAAG,IAAY,IAChE,MAAM,EAAc,EAAkB,EAAa,EAAQ,CAC3D,KAAK,OAAO,KACV,EAAO,MAAM,sBAAsB,EAAY,OAAO,wBAAwB,EAAK,GAAG,CACvF,CAED,IAAM,EAAoB,EAAQ,MAAM,CAExC,MAAM,EAAc,EAAwB,EAD3B,EAAK,EAAkB,IAAK,GAAM,OAAO,KAAK,EAAE,CAAC,CAAC,MAAM,CACF,CAAC,CACxE,KAAK,OAAO,KACV,EAAO,MACL,sBAAsB,EAAkB,OAAO,wBAAwB,EAAW,GACnF,CACF,CAED,KAAK,OAAO,KACV,EAAO,KACL,sBAAsB,EAAM,OAAO,sBAAsB,EAAkB,OAAO,qBACnF,CACF,CACD,GAAa,GAYb,eACA,mBACD,CAAC,CAEF,KAAK,OAAO,KACV,EAAO,MAAM,sBAAsB,EAAoB,wBAAwB,EAAK,GAAG,CACxF,CACD,KAAK,OAAO,KACV,EAAO,MACL,sBAAsB,EAA0B,wBAAwB,EAAW,GACpF,CACF"}
@@ -1,4 +1,4 @@
1
- import{t as e}from"./constants-DAx9VK1C.mjs";import{t}from"./logger-CPu6zbyQ.mjs";import{t as n}from"./done-input-validation-LiTaCEzF.mjs";import{n as r}from"./constants-DC_bBO09.mjs";import i from"colors";import a from"fast-glob";import{buildTranscendGraphQLClient as o,fetchActiveSiloDiscoPlugin as s,uploadSiloDiscoveryResults as c}from"@transcend-io/sdk";import{stringify as l}from"query-string";async function u({scanPath:e,fileGlobs:n,ignoreDirs:r,config:i}){let{ignoreDirs:o,supportedFiles:s,scanFunction:c}=i,l=n===``?s:s.concat(n.split(`,`)),d=[...r.split(`,`),...o].filter(e=>e.length>0);try{let n=await a(`${e}/**/${l.join(`|`)}`,{ignore:d.map(t=>`${e}/**/${t}`),unique:!0,onlyFiles:!0});t.info(`Scanning: ${n.length} files`);let r=n.map(e=>c(e)).flat().map(e=>e.softwareDevelopmentKits||[]).flat(),i=[...new Set(r.map(e=>e.name))];return t.info(`Found: ${i.length} unique dependencies`),i.map(t=>({name:t,resourceId:`${e}/**/${t}`,useStrictClassifier:!0}))}catch(e){throw Error(`Error scanning globs ${u} with error: ${e}`)}}async function d({scanPath:t,dataSiloId:a,auth:d,fileGlobs:f,ignoreDirs:p,transcendUrl:m}){n(this.process);let h=o(m,d),g=await s(h,{logger:this.logger,filterBy:{dataSiloId:a}}),_=r[g.dataSilo.type];_||(this.logger.error(i.red(`This plugin "${g.dataSilo.type}" is not supported for offline silo discovery.`)),this.process.exit(1));let v=await u({scanPath:t,fileGlobs:f,ignoreDirs:p,config:_});await c(h,{pluginId:g.id,results:v,logger:this.logger});let y=new URL(e);y.pathname=`/data-map/data-inventory/silo-discovery/triage`,y.search=l({filters:JSON.stringify({pluginIds:[g.id]})}),this.logger.info(i.green(`Scan found ${v.length} potential data silos at ${t}! View at '${y.href}'
1
+ import{t as e}from"./constants-BUOpqzcO.mjs";import{t}from"./logger-CPu6zbyQ.mjs";import{t as n}from"./done-input-validation-LiTaCEzF.mjs";import{n as r}from"./constants-DC_bBO09.mjs";import i from"colors";import a from"fast-glob";import{buildTranscendGraphQLClient as o,fetchActiveSiloDiscoPlugin as s,uploadSiloDiscoveryResults as c}from"@transcend-io/sdk";import{stringify as l}from"query-string";async function u({scanPath:e,fileGlobs:n,ignoreDirs:r,config:i}){let{ignoreDirs:o,supportedFiles:s,scanFunction:c}=i,l=n===``?s:s.concat(n.split(`,`)),d=[...r.split(`,`),...o].filter(e=>e.length>0);try{let n=await a(`${e}/**/${l.join(`|`)}`,{ignore:d.map(t=>`${e}/**/${t}`),unique:!0,onlyFiles:!0});t.info(`Scanning: ${n.length} files`);let r=n.map(e=>c(e)).flat().map(e=>e.softwareDevelopmentKits||[]).flat(),i=[...new Set(r.map(e=>e.name))];return t.info(`Found: ${i.length} unique dependencies`),i.map(t=>({name:t,resourceId:`${e}/**/${t}`,useStrictClassifier:!0}))}catch(e){throw Error(`Error scanning globs ${u} with error: ${e}`)}}async function d({scanPath:t,dataSiloId:a,auth:d,fileGlobs:f,ignoreDirs:p,transcendUrl:m}){n(this.process);let h=o(m,d),g=await s(h,{logger:this.logger,filterBy:{dataSiloId:a}}),_=r[g.dataSilo.type];_||(this.logger.error(i.red(`This plugin "${g.dataSilo.type}" is not supported for offline silo discovery.`)),this.process.exit(1));let v=await u({scanPath:t,fileGlobs:f,ignoreDirs:p,config:_});await c(h,{pluginId:g.id,results:v,logger:this.logger});let y=new URL(e);y.pathname=`/data-map/data-inventory/silo-discovery/triage`,y.search=l({filters:JSON.stringify({pluginIds:[g.id]})}),this.logger.info(i.green(`Scan found ${v.length} potential data silos at ${t}! View at '${y.href}'
2
2
 
3
3
  NOTE: it may take 2-3 minutes for scan results to appear in the UI.`))}export{d as discoverSilos};
4
- //# sourceMappingURL=impl-B8DsKzNn2.mjs.map
4
+ //# sourceMappingURL=impl-kXabADxl2.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-B8DsKzNn2.mjs","names":[],"sources":["../src/lib/code-scanning/findFilesToScan.ts","../src/commands/inventory/discover-silos/impl.ts"],"sourcesContent":["import fastGlob from 'fast-glob';\n\nimport { logger } from '../../logger.js';\nimport { CodeScanningConfig } from './types.js';\n\nexport interface SiloDiscoveryRawResults {\n /** The name of the potential data silo entry */\n name: string;\n /** A unique UUID (represents the same resource across different silo discovery runs) */\n resourceId: string;\n /** Any hosts associated with the entry */\n host?: string;\n /** Type of data silo */\n type?: string | undefined;\n}\n\n/**\n * Helper to scan for data silos in all package.json files that it can find in a directory\n *\n * @deprecated TODO: https://transcend.height.app/T-32325 - use code scanning instead\n * @param options - Options\n * @returns the list of integrations\n */\nexport async function findFilesToScan({\n scanPath,\n fileGlobs,\n ignoreDirs,\n config,\n}: {\n /** Where to look for package.json files */\n scanPath: string;\n /** Globs to look for */\n fileGlobs: string;\n /** The directories to ignore (excludes node_modules and serverless-build) */\n ignoreDirs: string;\n /** Silo Discovery configuration */\n config: CodeScanningConfig;\n}): Promise<SiloDiscoveryRawResults[]> {\n const { ignoreDirs: IGNORE_DIRS, supportedFiles, scanFunction } = config;\n const globsToSupport =\n fileGlobs === '' ? supportedFiles : supportedFiles.concat(fileGlobs.split(','));\n const dirsToIgnore = [...ignoreDirs.split(','), ...IGNORE_DIRS].filter((dir) => dir.length > 0);\n try {\n const filesToScan: string[] = await fastGlob(`${scanPath}/**/${globsToSupport.join('|')}`, {\n ignore: dirsToIgnore.map((dir: string) => `${scanPath}/**/${dir}`),\n unique: true,\n onlyFiles: true,\n });\n logger.info(`Scanning: ${filesToScan.length} files`);\n const allPackages = filesToScan.map((filePath: string) => scanFunction(filePath)).flat();\n const allSdks = allPackages\n .map((appPackage) => appPackage.softwareDevelopmentKits || [])\n .flat();\n const uniqueDeps = new Set(allSdks.map((sdk) => sdk.name));\n const deps = [...uniqueDeps];\n logger.info(`Found: ${deps.length} unique dependencies`);\n return deps.map((dep) => ({\n name: dep,\n resourceId: `${scanPath}/**/${dep}`,\n useStrictClassifier: true,\n }));\n } catch (error) {\n throw new Error(`Error scanning globs ${findFilesToScan} with error: ${error}`);\n }\n}\n","import {\n buildTranscendGraphQLClient,\n fetchActiveSiloDiscoPlugin,\n uploadSiloDiscoveryResults,\n} from '@transcend-io/sdk';\nimport colors from 'colors';\nimport { stringify } from 'query-string';\n\nimport { ADMIN_DASH } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { findFilesToScan } from '../../../lib/code-scanning/findFilesToScan.js';\nimport { SILO_DISCOVERY_CONFIGS } from '../../../lib/code-scanning/index.js';\n\nexport interface DiscoverSilosCommandFlags {\n scanPath: string;\n dataSiloId: string;\n auth: string;\n fileGlobs: string;\n ignoreDirs: string;\n transcendUrl: string;\n}\n\nexport async function discoverSilos(\n this: LocalContext,\n { scanPath, dataSiloId, auth, fileGlobs, ignoreDirs, transcendUrl }: DiscoverSilosCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n // Create a GraphQL client\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n const plugin = await fetchActiveSiloDiscoPlugin(client, {\n logger: this.logger,\n filterBy: { dataSiloId },\n });\n\n const config = SILO_DISCOVERY_CONFIGS[plugin.dataSilo.type];\n if (!config) {\n this.logger.error(\n colors.red(\n `This plugin \"${plugin.dataSilo.type}\" is not supported for offline silo discovery.`,\n ),\n );\n this.process.exit(1);\n }\n\n const results = await findFilesToScan({\n scanPath,\n fileGlobs,\n ignoreDirs,\n config,\n });\n\n await uploadSiloDiscoveryResults(client, {\n pluginId: plugin.id,\n results,\n logger: this.logger,\n });\n\n const newUrl = new URL(ADMIN_DASH);\n newUrl.pathname = '/data-map/data-inventory/silo-discovery/triage';\n newUrl.search = stringify({\n filters: JSON.stringify({ pluginIds: [plugin.id] }),\n });\n\n // Indicate success\n this.logger.info(\n colors.green(\n `Scan found ${results.length} potential data silos at ${scanPath}! ` +\n `View at '${newUrl.href}' ` +\n '\\n\\n NOTE: it may take 2-3 minutes for scan results to appear in the UI.',\n ),\n );\n}\n"],"mappings":"gZAuBA,eAAsB,EAAgB,CACpC,WACA,YACA,aACA,UAUqC,CACrC,GAAM,CAAE,WAAY,EAAa,iBAAgB,gBAAiB,EAC5D,EACJ,IAAc,GAAK,EAAiB,EAAe,OAAO,EAAU,MAAM,IAAI,CAAC,CAC3E,EAAe,CAAC,GAAG,EAAW,MAAM,IAAI,CAAE,GAAG,EAAY,CAAC,OAAQ,GAAQ,EAAI,OAAS,EAAE,CAC/F,GAAI,CACF,IAAM,EAAwB,MAAM,EAAS,GAAG,EAAS,MAAM,EAAe,KAAK,IAAI,GAAI,CACzF,OAAQ,EAAa,IAAK,GAAgB,GAAG,EAAS,MAAM,IAAM,CAClE,OAAQ,GACR,UAAW,GACZ,CAAC,CACF,EAAO,KAAK,aAAa,EAAY,OAAO,QAAQ,CAEpD,IAAM,EADc,EAAY,IAAK,GAAqB,EAAa,EAAS,CAAC,CAAC,MACvD,CACxB,IAAK,GAAe,EAAW,yBAA2B,EAAE,CAAC,CAC7D,MAAM,CAEH,EAAO,CAAC,GAAG,IADM,IAAI,EAAQ,IAAK,GAAQ,EAAI,KAAK,CAC9B,CAAC,CAE5B,OADA,EAAO,KAAK,UAAU,EAAK,OAAO,sBAAsB,CACjD,EAAK,IAAK,IAAS,CACxB,KAAM,EACN,WAAY,GAAG,EAAS,MAAM,IAC9B,oBAAqB,GACtB,EAAE,OACI,EAAO,CACd,MAAU,MAAM,wBAAwB,EAAgB,eAAe,IAAQ,ECvCnF,eAAsB,EAEpB,CAAE,WAAU,aAAY,OAAM,YAAW,aAAY,gBACtC,CACf,EAAoB,KAAK,QAAQ,CAGjC,IAAM,EAAS,EAA4B,EAAc,EAAK,CAExD,EAAS,MAAM,EAA2B,EAAQ,CACtD,OAAQ,KAAK,OACb,SAAU,CAAE,aAAY,CACzB,CAAC,CAEI,EAAS,EAAuB,EAAO,SAAS,MACjD,IACH,KAAK,OAAO,MACV,EAAO,IACL,gBAAgB,EAAO,SAAS,KAAK,gDACtC,CACF,CACD,KAAK,QAAQ,KAAK,EAAE,EAGtB,IAAM,EAAU,MAAM,EAAgB,CACpC,WACA,YACA,aACA,SACD,CAAC,CAEF,MAAM,EAA2B,EAAQ,CACvC,SAAU,EAAO,GACjB,UACA,OAAQ,KAAK,OACd,CAAC,CAEF,IAAM,EAAS,IAAI,IAAI,EAAW,CAClC,EAAO,SAAW,iDAClB,EAAO,OAAS,EAAU,CACxB,QAAS,KAAK,UAAU,CAAE,UAAW,CAAC,EAAO,GAAG,CAAE,CAAC,CACpD,CAAC,CAGF,KAAK,OAAO,KACV,EAAO,MACL,cAAc,EAAQ,OAAO,2BAA2B,EAAS,aACnD,EAAO,KAAK;;sEAE3B,CACF"}
1
+ {"version":3,"file":"impl-kXabADxl2.mjs","names":[],"sources":["../src/lib/code-scanning/findFilesToScan.ts","../src/commands/inventory/discover-silos/impl.ts"],"sourcesContent":["import fastGlob from 'fast-glob';\n\nimport { logger } from '../../logger.js';\nimport { CodeScanningConfig } from './types.js';\n\nexport interface SiloDiscoveryRawResults {\n /** The name of the potential data silo entry */\n name: string;\n /** A unique UUID (represents the same resource across different silo discovery runs) */\n resourceId: string;\n /** Any hosts associated with the entry */\n host?: string;\n /** Type of data silo */\n type?: string | undefined;\n}\n\n/**\n * Helper to scan for data silos in all package.json files that it can find in a directory\n *\n * @deprecated TODO: https://transcend.height.app/T-32325 - use code scanning instead\n * @param options - Options\n * @returns the list of integrations\n */\nexport async function findFilesToScan({\n scanPath,\n fileGlobs,\n ignoreDirs,\n config,\n}: {\n /** Where to look for package.json files */\n scanPath: string;\n /** Globs to look for */\n fileGlobs: string;\n /** The directories to ignore (excludes node_modules and serverless-build) */\n ignoreDirs: string;\n /** Silo Discovery configuration */\n config: CodeScanningConfig;\n}): Promise<SiloDiscoveryRawResults[]> {\n const { ignoreDirs: IGNORE_DIRS, supportedFiles, scanFunction } = config;\n const globsToSupport =\n fileGlobs === '' ? supportedFiles : supportedFiles.concat(fileGlobs.split(','));\n const dirsToIgnore = [...ignoreDirs.split(','), ...IGNORE_DIRS].filter((dir) => dir.length > 0);\n try {\n const filesToScan: string[] = await fastGlob(`${scanPath}/**/${globsToSupport.join('|')}`, {\n ignore: dirsToIgnore.map((dir: string) => `${scanPath}/**/${dir}`),\n unique: true,\n onlyFiles: true,\n });\n logger.info(`Scanning: ${filesToScan.length} files`);\n const allPackages = filesToScan.map((filePath: string) => scanFunction(filePath)).flat();\n const allSdks = allPackages\n .map((appPackage) => appPackage.softwareDevelopmentKits || [])\n .flat();\n const uniqueDeps = new Set(allSdks.map((sdk) => sdk.name));\n const deps = [...uniqueDeps];\n logger.info(`Found: ${deps.length} unique dependencies`);\n return deps.map((dep) => ({\n name: dep,\n resourceId: `${scanPath}/**/${dep}`,\n useStrictClassifier: true,\n }));\n } catch (error) {\n throw new Error(`Error scanning globs ${findFilesToScan} with error: ${error}`);\n }\n}\n","import {\n buildTranscendGraphQLClient,\n fetchActiveSiloDiscoPlugin,\n uploadSiloDiscoveryResults,\n} from '@transcend-io/sdk';\nimport colors from 'colors';\nimport { stringify } from 'query-string';\n\nimport { ADMIN_DASH } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { findFilesToScan } from '../../../lib/code-scanning/findFilesToScan.js';\nimport { SILO_DISCOVERY_CONFIGS } from '../../../lib/code-scanning/index.js';\n\nexport interface DiscoverSilosCommandFlags {\n scanPath: string;\n dataSiloId: string;\n auth: string;\n fileGlobs: string;\n ignoreDirs: string;\n transcendUrl: string;\n}\n\nexport async function discoverSilos(\n this: LocalContext,\n { scanPath, dataSiloId, auth, fileGlobs, ignoreDirs, transcendUrl }: DiscoverSilosCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n // Create a GraphQL client\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n const plugin = await fetchActiveSiloDiscoPlugin(client, {\n logger: this.logger,\n filterBy: { dataSiloId },\n });\n\n const config = SILO_DISCOVERY_CONFIGS[plugin.dataSilo.type];\n if (!config) {\n this.logger.error(\n colors.red(\n `This plugin \"${plugin.dataSilo.type}\" is not supported for offline silo discovery.`,\n ),\n );\n this.process.exit(1);\n }\n\n const results = await findFilesToScan({\n scanPath,\n fileGlobs,\n ignoreDirs,\n config,\n });\n\n await uploadSiloDiscoveryResults(client, {\n pluginId: plugin.id,\n results,\n logger: this.logger,\n });\n\n const newUrl = new URL(ADMIN_DASH);\n newUrl.pathname = '/data-map/data-inventory/silo-discovery/triage';\n newUrl.search = stringify({\n filters: JSON.stringify({ pluginIds: [plugin.id] }),\n });\n\n // Indicate success\n this.logger.info(\n colors.green(\n `Scan found ${results.length} potential data silos at ${scanPath}! ` +\n `View at '${newUrl.href}' ` +\n '\\n\\n NOTE: it may take 2-3 minutes for scan results to appear in the UI.',\n ),\n );\n}\n"],"mappings":"gZAuBA,eAAsB,EAAgB,CACpC,WACA,YACA,aACA,UAUqC,CACrC,GAAM,CAAE,WAAY,EAAa,iBAAgB,gBAAiB,EAC5D,EACJ,IAAc,GAAK,EAAiB,EAAe,OAAO,EAAU,MAAM,IAAI,CAAC,CAC3E,EAAe,CAAC,GAAG,EAAW,MAAM,IAAI,CAAE,GAAG,EAAY,CAAC,OAAQ,GAAQ,EAAI,OAAS,EAAE,CAC/F,GAAI,CACF,IAAM,EAAwB,MAAM,EAAS,GAAG,EAAS,MAAM,EAAe,KAAK,IAAI,GAAI,CACzF,OAAQ,EAAa,IAAK,GAAgB,GAAG,EAAS,MAAM,IAAM,CAClE,OAAQ,GACR,UAAW,GACZ,CAAC,CACF,EAAO,KAAK,aAAa,EAAY,OAAO,QAAQ,CAEpD,IAAM,EADc,EAAY,IAAK,GAAqB,EAAa,EAAS,CAAC,CAAC,MACvD,CACxB,IAAK,GAAe,EAAW,yBAA2B,EAAE,CAAC,CAC7D,MAAM,CAEH,EAAO,CAAC,GAAG,IADM,IAAI,EAAQ,IAAK,GAAQ,EAAI,KAAK,CAC9B,CAAC,CAE5B,OADA,EAAO,KAAK,UAAU,EAAK,OAAO,sBAAsB,CACjD,EAAK,IAAK,IAAS,CACxB,KAAM,EACN,WAAY,GAAG,EAAS,MAAM,IAC9B,oBAAqB,GACtB,EAAE,OACI,EAAO,CACd,MAAU,MAAM,wBAAwB,EAAgB,eAAe,IAAQ,ECvCnF,eAAsB,EAEpB,CAAE,WAAU,aAAY,OAAM,YAAW,aAAY,gBACtC,CACf,EAAoB,KAAK,QAAQ,CAGjC,IAAM,EAAS,EAA4B,EAAc,EAAK,CAExD,EAAS,MAAM,EAA2B,EAAQ,CACtD,OAAQ,KAAK,OACb,SAAU,CAAE,aAAY,CACzB,CAAC,CAEI,EAAS,EAAuB,EAAO,SAAS,MACjD,IACH,KAAK,OAAO,MACV,EAAO,IACL,gBAAgB,EAAO,SAAS,KAAK,gDACtC,CACF,CACD,KAAK,QAAQ,KAAK,EAAE,EAGtB,IAAM,EAAU,MAAM,EAAgB,CACpC,WACA,YACA,aACA,SACD,CAAC,CAEF,MAAM,EAA2B,EAAQ,CACvC,SAAU,EAAO,GACjB,UACA,OAAQ,KAAK,OACd,CAAC,CAEF,IAAM,EAAS,IAAI,IAAI,EAAW,CAClC,EAAO,SAAW,iDAClB,EAAO,OAAS,EAAU,CACxB,QAAS,KAAK,UAAU,CAAE,UAAW,CAAC,EAAO,GAAG,CAAE,CAAC,CACpD,CAAC,CAGF,KAAK,OAAO,KACV,EAAO,MACL,cAAc,EAAQ,OAAO,2BAA2B,EAAS,aACnD,EAAO,KAAK;;sEAE3B,CACF"}
@@ -1,2 +1,2 @@
1
- import{t as e}from"./skipRequestDataSilos-DPi6-XVr.mjs";import{t}from"./done-input-validation-LiTaCEzF.mjs";async function n({auth:n,dataSiloId:r,status:i,statuses:a,transcendUrl:o,actionTypes:s}){t(this.process),await e({transcendUrl:o,auth:n,status:i,dataSiloId:r,requestStatuses:a,actionTypes:s})}export{n as skipRequestDataSilos};
2
- //# sourceMappingURL=impl-nYlbrsD7.mjs.map
1
+ import{t as e}from"./skipRequestDataSilos-clWLNU0C.mjs";import{t}from"./done-input-validation-LiTaCEzF.mjs";async function n({auth:n,dataSiloId:r,status:i,statuses:a,transcendUrl:o,actionTypes:s}){t(this.process),await e({transcendUrl:o,auth:n,status:i,dataSiloId:r,requestStatuses:a,actionTypes:s})}export{n as skipRequestDataSilos};
2
+ //# sourceMappingURL=impl-szLqtBsW.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-nYlbrsD7.mjs","names":["skipRequestDataSilosHelper"],"sources":["../src/commands/request/system/skip-request-data-silos/impl.ts"],"sourcesContent":["import type {\n RequestAction,\n RequestDataSiloStatus,\n RequestStatus,\n} from '@transcend-io/privacy-types';\n\nimport type { LocalContext } from '../../../../context.js';\nimport { doneInputValidation } from '../../../../lib/cli/done-input-validation.js';\nimport { skipRequestDataSilos as skipRequestDataSilosHelper } from '../../../../lib/requests/index.js';\n\nexport interface SkipRequestDataSilosCommandFlags {\n auth: string;\n dataSiloId: string;\n transcendUrl: string;\n statuses: RequestStatus[];\n status: (typeof RequestDataSiloStatus)['Skipped'] | (typeof RequestDataSiloStatus)['Resolved'];\n actionTypes?: RequestAction[];\n}\n\nexport async function skipRequestDataSilos(\n this: LocalContext,\n {\n auth,\n dataSiloId,\n status,\n statuses,\n transcendUrl,\n actionTypes,\n }: SkipRequestDataSilosCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n await skipRequestDataSilosHelper({\n transcendUrl,\n auth,\n status,\n dataSiloId,\n requestStatuses: statuses,\n actionTypes,\n });\n}\n"],"mappings":"4GAmBA,eAAsB,EAEpB,CACE,OACA,aACA,SACA,WACA,eACA,eAEa,CACf,EAAoB,KAAK,QAAQ,CAEjC,MAAMA,EAA2B,CAC/B,eACA,OACA,SACA,aACA,gBAAiB,EACjB,cACD,CAAC"}
1
+ {"version":3,"file":"impl-szLqtBsW.mjs","names":["skipRequestDataSilosHelper"],"sources":["../src/commands/request/system/skip-request-data-silos/impl.ts"],"sourcesContent":["import type {\n RequestAction,\n RequestDataSiloStatus,\n RequestStatus,\n} from '@transcend-io/privacy-types';\n\nimport type { LocalContext } from '../../../../context.js';\nimport { doneInputValidation } from '../../../../lib/cli/done-input-validation.js';\nimport { skipRequestDataSilos as skipRequestDataSilosHelper } from '../../../../lib/requests/index.js';\n\nexport interface SkipRequestDataSilosCommandFlags {\n auth: string;\n dataSiloId: string;\n transcendUrl: string;\n statuses: RequestStatus[];\n status: (typeof RequestDataSiloStatus)['Skipped'] | (typeof RequestDataSiloStatus)['Resolved'];\n actionTypes?: RequestAction[];\n}\n\nexport async function skipRequestDataSilos(\n this: LocalContext,\n {\n auth,\n dataSiloId,\n status,\n statuses,\n transcendUrl,\n actionTypes,\n }: SkipRequestDataSilosCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n await skipRequestDataSilosHelper({\n transcendUrl,\n auth,\n status,\n dataSiloId,\n requestStatuses: statuses,\n actionTypes,\n });\n}\n"],"mappings":"4GAmBA,eAAsB,EAEpB,CACE,OACA,aACA,SACA,WACA,eACA,eAEa,CACf,EAAoB,KAAK,QAAQ,CAEjC,MAAMA,EAA2B,CAC/B,eACA,OACA,SACA,aACA,gBAAiB,EACjB,cACD,CAAC"}
@@ -1,4 +1,4 @@
1
- import{g as e}from"./constants-DAx9VK1C.mjs";import{i as t,n,r,t as i}from"./project-plan-output-BHHlkLxe.mjs";import{c as a,d as o,f as s,l as c,t as l,u}from"./project-discovery-CWRjlFnC.mjs";import{b as d,d as f,r as p,t as m,u as h}from"./policy-project-discovery-CND7N2HI.mjs";import{a as g,c as _,i as v,l as y,o as b,r as x,s as S,t as C}from"./policy-runtime-6jmkXlBk.mjs";import{t as w}from"./done-input-validation-LiTaCEzF.mjs";import{i as T,n as E,r as D,t as O}from"./prompts-BhXfYD6g.mjs";import{t as k}from"./run-captured-process-BjaSDWXG.mjs";import{t as A}from"./project-plan-apply-Bg_1eMX9.mjs";import{a as j,n as ee,o as te,r as ne,t as re}from"./policy-scaffold-config-CwY0QZC0.mjs";import{isAbsolute as M,join as N,posix as P,relative as F,sep as I}from"node:path";import L from"colors";const R={Editor:`editor`,Skill:`skill`,Ci:`ci`};var z=`# Idiomatic Rego and document-tree authoring
1
+ import{g as e}from"./constants-BUOpqzcO.mjs";import{i as t,n,r,t as i}from"./project-plan-output-BHHlkLxe.mjs";import{c as a,d as o,f as s,l as c,t as l,u}from"./project-discovery-CWRjlFnC.mjs";import{b as d,d as f,r as p,t as m,u as h}from"./policy-project-discovery-D16kgZwZ.mjs";import{a as g,c as _,i as v,l as y,o as b,r as x,s as S,t as C}from"./policy-runtime-6jmkXlBk.mjs";import{t as w}from"./done-input-validation-LiTaCEzF.mjs";import{i as T,n as E,r as D,t as O}from"./prompts-BhXfYD6g.mjs";import{t as k}from"./run-captured-process-BjaSDWXG.mjs";import{t as A}from"./project-plan-apply-Bg_1eMX9.mjs";import{a as j,n as ee,o as te,r as ne,t as re}from"./policy-scaffold-config-5bTG97rM.mjs";import{isAbsolute as M,join as N,posix as P,relative as F,sep as I}from"node:path";import L from"colors";const R={Editor:`editor`,Skill:`skill`,Ci:`ci`};var z=`# Idiomatic Rego and document-tree authoring
2
2
 
3
3
  ## Start from the document tree
4
4
 
@@ -325,4 +325,4 @@ transcend policy check --noInteractive
325
325
  products into a single \`.manifest\` unless they share activation and callers.
326
326
  `;const W=`transcend-policy-engine`,G=[{path:`SKILL.md`,contents:U},{path:`references/setup-tooling.md`,contents:V},{path:`references/authoring.md`,contents:z},{path:`references/testing-debugging.md`,contents:H},{path:`references/publishing.md`,contents:B}];function K(e){return`${e.hasSkill?`Use the \`${W}\` skill and run`:`Run`} ${e.newCommand} to add a bundle from a template, then adapt the policy document tree and input/output contract to the intended application.`}function q(e,n){return{version:e.version,command:e.command,applied:n.applied,dryRun:n.dryRun,targetDirectory:e.targetDirectory,manifestPath:e.manifestPath,changes:e.changes.map(e=>t(n.cwd,e)),warnings:e.warnings,nextSteps:e.nextSteps,features:[...e.features],aiHandoff:n.aiHandoff,tools:n.tools}}const J={name:W,displayName:`Policy Engine`,owner:`@transcend-io/cli`,files:G};function Y(e,t){let n=new Set(d().map(({path:t})=>N(e.targetDirectory,t))),r=new Set(t.features);return r.has(R.Editor)&&(n.add(N(e.projectRoot,`.vscode`,`settings.json`)),n.add(N(e.projectRoot,`.vscode`,`extensions.json`)),n.add(N(e.projectRoot,`.vscode`,`tasks.json`))),r.has(R.Skill)&&a(e.projectRoot,e.existingSkillDirectories,J).forEach(e=>n.add(e)),r.has(R.Ci)&&e.repositoryRoot&&e.usesGithub&&n.add(N(e.repositoryRoot,j)),[...n].sort((e,t)=>e.localeCompare(t))}function X(e,t){let n=F(e,t);if(n===`..`||n.startsWith(`..${I}`)||M(n))throw Error(`Refusing to modify path outside project root: ${t}`)}function ie(e){let t=new Set([`${h}/input.json`]);return e.forEach(({path:e})=>{t.add(e);let n=P.dirname(e);for(;n!==`.`;)t.add(n),n=P.dirname(n)}),t}function Z(e,t,n){let r=s({snapshot:u(t.snapshots,n.path),after:n.contents,description:n.description,...n.createOnly===void 0?{}:{createOnly:n.createOnly}});r?e.changes.push(r):e.unchanged.push(n.path)}function ae(e,t,n,r,a,o){Z(e,t,{path:n,contents:r.contents,description:a}),e.warnings.push(...r.warnings.map(e=>`${e} (${i(o,n)})`))}function oe(e,t){let{state:n}=e,r=d(),a=`transcend policy new`,s={version:3,command:`init`,rootDirectory:n.projectRoot,targetDirectory:n.targetDirectory,manifestPath:n.targetDirectory,changes:[],unchanged:[],warnings:[],nextSteps:[a],features:[...t.features]},l=Y(n,t);if(X(n.projectRoot,n.targetDirectory),l.forEach(e=>X(n.projectRoot,e)),n.relativeFilePaths.length===0)s.directoryPreconditions=[{path:n.targetDirectory,relativePaths:[...n.relativePaths]}],r.forEach(t=>{let r=N(n.targetDirectory,t.path);if(o(e.snapshots,r).kind!==`absent`)throw Error(`Expected an empty policy target, but found an entry at: ${r}`);Z(s,e,{path:r,contents:t.contents,description:t.description,createOnly:!0})});else{let t=!0;r.forEach(r=>{let a=N(n.targetDirectory,r.path),c=o(e.snapshots,a);if(c.kind===`file`&&c.contents===r.contents){s.unchanged.push(a);return}t=!1,c.kind!==`absent`&&(s.unchanged.push(a),s.warnings.push(`Existing policy scaffold path was left unchanged: ${i(n.invocationDirectory,a)}`))});let c=ie(r),l=n.relativeFilePaths.some(e=>!c.has(e));(!t||l)&&s.warnings.push(`Existing policy target contains custom or partial content, so no workspace files were added or overwritten. Review ${i(n.invocationDirectory,n.targetDirectory)} manually, then run \`${a}\`.`)}let u=new Set(t.features),f=n.projectRoot;if(u.has(R.Editor)){let t=N(f,`.vscode`,`settings.json`),r=N(f,`.vscode`,`extensions.json`),a=N(f,`.vscode`,`tasks.json`);[{path:t,description:`Merge strict target-scoped OPA and Rego editor settings`,merge:(e,t,n)=>ee(e,t,n)},{path:r,description:`Recommend the OPA extension and discourage its syntax-only conflict`,merge:e=>re(e)},{path:a,description:`Create the VS Code task configuration`,merge:(e,t,n)=>ne(e,t,n)}].forEach(({path:t,description:r,merge:a})=>{let c=o(e.snapshots,t);if(c.kind!==`absent`&&c.kind!==`file`){s.unchanged.push(t),s.warnings.push(`Existing VS Code artifact is not a regular file and was left unchanged: ${i(n.invocationDirectory,t)}`);return}ae(s,e,t,a(c.kind===`file`?c.contents:null,f,n.targetDirectory),r,n.invocationDirectory)})}if(u.has(R.Skill)){let t=c({rootDirectory:f,existingDirectories:n.existingSkillDirectories,snapshots:e.snapshots,skill:J,preserveModified:!0});s.changes.push(...t.changes),s.unchanged.push(...t.unchanged),s.warnings.push(...t.warnings.map(e=>t.unchanged.reduce((e,t)=>e.replace(t,i(n.invocationDirectory,t)),e)))}if(u.has(R.Ci))if(!n.repositoryRoot||!n.usesGithub)s.warnings.push(`GitHub Actions setup was selected, but this target is not inside a detected GitHub repository.`);else{let r=N(n.repositoryRoot,j),a=F(n.repositoryRoot,n.targetDirectory).split(I).join(`/`)||`.`,c=te({cliVersion:t.cliVersion,workspaceDirectory:a,bundleDirectories:[]}),l=o(e.snapshots,r);l.kind===`absent`?Z(s,e,{path:r,contents:c,description:`Add credential-free Policy Engine validation`,createOnly:!0}):l.kind===`file`&&l.contents===c?s.unchanged.push(r):(s.unchanged.push(r),s.warnings.push(`Existing GitHub Actions workflow was left unchanged: ${i(n.invocationDirectory,r)}. Adapt it manually to validate each policy bundle.`))}return s.changes.forEach(({path:e})=>X(n.projectRoot,e)),s}const se={[R.Editor]:`VS Code settings and lint task`,[R.Skill]:`Policy Engine Agent Skill`,[R.Ci]:`Validation-only GitHub Actions`},ce=Object.values(R);function Q(e,t){let n=[t.stdout.trim(),t.stderr.trim()].filter(Boolean).join(`
327
327
  `),r=e===`OPA`?x:g;return`${e===`OPA`?`OPA 1.x`:`Regal ${C} or newer`} is required, but \`${e.toLowerCase()} version\` exited with code ${t.code}${n?`: ${n}`:`.`} Install or upgrade it using the official instructions: ${r}`}async function le(e,t,n){let r={opa:null,regal:null},i=[],a=await n(`opa`,[`version`],{cwd:t},e);if(a.error?.code===`ENOENT`)i.push(v);else{let e=`${a.stdout}\n${a.stderr}`,t=_(e);a.code===0?t?i.push(t):r.opa=S(e).version:i.push(t??Q(`OPA`,a))}let o=await n(`regal`,[`version`],{cwd:t},e);if(o.error?.code===`ENOENT`)i.push(b);else{let e=`${o.stdout}\n${o.stderr}`,t=y(e,C,`the generated OPA ${f} capabilities configuration`);o.code===0?t?i.push(t):r.regal=S(e).version:i.push(t??Q(`Regal`,o))}return{tools:r,warnings:i}}async function $(t,a=m,o=k){w(this.process);try{let s=await le(this,this.process.cwd(),o),c=p(this,a),u=new E(this),d=D(t,this.process.stdin.isTTY,this.process.stderr.isTTY),f=await T(u,{features:ce,labels:se,enabled:{[R.Editor]:t.editor,[R.Skill]:t.skill,[R.Ci]:t.ci},interactive:d}),m=Y(c,{features:f}),h=oe({state:c,snapshots:l(this,c.projectRoot,m)},{features:f,cliVersion:e});h.warnings.push(...s.warnings),t.json||this.logger.info(r(h,{cwd:this.process.cwd(),title:`Policy initialization plan`,details:[{label:`Target`,path:h.targetDirectory}]}));let g=h.changes.length===0||t.dryRun;if(h.changes.length>0&&!t.dryRun)if(t.yes)g=!0;else if(d)g=await u.confirm(`Apply this complete plan?`,!0);else throw Error(`The plan requires approval in a non-interactive invocation. Review with --dryRun, then pass --yes.`);g&&!t.dryRun&&h.changes.length>0&&await A(this,h);let _=g&&!t.dryRun&&h.changes.length>0,v=g&&!t.dryRun,y=K({projectPath:n(i(this.process.cwd(),c.targetDirectory)),hasSkill:v&&f.includes(R.Skill),newCommand:h.nextSteps[0]}),b=q(h,{applied:_,dryRun:t.dryRun,cwd:this.process.cwd(),aiHandoff:y,tools:s.tools});if(t.json){this.process.stdout.write(`${JSON.stringify(b)}\n`);return}if(t.dryRun){this.logger.info(L.yellow(`Dry run complete. No changes were written.`));return}if(!g){this.logger.info(L.yellow(`No changes applied.`));return}if(h.changes.length===0){let e=h.warnings.length===s.warnings.length?`Policy project is already initialized.`:`Existing policy project was left unchanged.`;this.logger.info(L.green(e))}else this.logger.info(L.green(`Policy project initialized.`));h.nextSteps.length>0&&(this.logger.info(`\n${L.bold(`Next steps`)}`),h.nextSteps.forEach(e=>this.logger.info(e))),this.logger.info(`\n${L.bold(`AI handoff — paste into your coding agent`)}`),this.logger.info(y)}catch(e){if(e instanceof O)return this.process.exit(130);throw e}}export{$ as init};
328
- //# sourceMappingURL=impl-DvHiVaGW.mjs.map
328
+ //# sourceMappingURL=impl-w5hHfoVE.mjs.map