@transcend-io/cli 10.27.5 → 10.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +271 -36
- package/dist/app-C5baDSA2.mjs +148 -0
- package/dist/app-C5baDSA2.mjs.map +1 -0
- package/dist/{approvePrivacyRequests-B842tXn4.mjs → approvePrivacyRequests-B8x7oxTn.mjs} +2 -2
- package/dist/{approvePrivacyRequests-B842tXn4.mjs.map → approvePrivacyRequests-B8x7oxTn.mjs.map} +1 -1
- package/dist/bin/bash-complete.mjs +1 -1
- package/dist/bin/cli.mjs +1 -1
- package/dist/bin/deprecated-command.mjs +1 -1
- package/dist/{buildExamples-CRrUU89C.mjs → buildExamples-7KXBjl-b.mjs} +2 -2
- package/dist/{buildExamples-CRrUU89C.mjs.map → buildExamples-7KXBjl-b.mjs.map} +1 -1
- package/dist/{buildXdiSyncEndpoint-B9seJTxP.mjs → buildXdiSyncEndpoint-DcrkZ2Gu.mjs} +2 -2
- package/dist/{buildXdiSyncEndpoint-B9seJTxP.mjs.map → buildXdiSyncEndpoint-DcrkZ2Gu.mjs.map} +1 -1
- package/dist/{bulkRestartRequests-CE7cDUMd.mjs → bulkRestartRequests-CysUfl98.mjs} +2 -2
- package/dist/{bulkRestartRequests-CE7cDUMd.mjs.map → bulkRestartRequests-CysUfl98.mjs.map} +1 -1
- package/dist/{bulkRetryEnrichers-BcSANZPC.mjs → bulkRetryEnrichers-DaLE67Ht.mjs} +2 -2
- package/dist/{bulkRetryEnrichers-BcSANZPC.mjs.map → bulkRetryEnrichers-DaLE67Ht.mjs.map} +1 -1
- package/dist/{cancelPrivacyRequests-BKibbagv.mjs → cancelPrivacyRequests-D0zNUNdS.mjs} +2 -2
- package/dist/{cancelPrivacyRequests-BKibbagv.mjs.map → cancelPrivacyRequests-D0zNUNdS.mjs.map} +1 -1
- package/dist/codecs-CTxFjCg4.mjs +2 -0
- package/dist/codecs-CTxFjCg4.mjs.map +1 -0
- package/dist/{collectCsvFilesOrExit-Dg5U3Qx_.mjs → collectCsvFilesOrExit-B1VOVGWN.mjs} +1 -1
- package/dist/{collectCsvFilesOrExit-Dg5U3Qx_.mjs.map → collectCsvFilesOrExit-B1VOVGWN.mjs.map} +1 -1
- package/dist/{collectParquetFilesOrExit-BlG2RRSC.mjs → collectParquetFilesOrExit-DVlv5ctt.mjs} +1 -1
- package/dist/{collectParquetFilesOrExit-BlG2RRSC.mjs.map → collectParquetFilesOrExit-DVlv5ctt.mjs.map} +1 -1
- package/dist/{command-DKNKpgUB.mjs → command-CIv9yk86.mjs} +2 -2
- package/dist/{command-DKNKpgUB.mjs.map → command-CIv9yk86.mjs.map} +1 -1
- package/dist/commands/admin/chunk-csv/worker.mjs +1 -1
- package/dist/commands/admin/parquet-to-csv/worker.mjs +1 -1
- package/dist/{consentManagersToBusinessEntities-Rv-ajWya.mjs → consentManagersToBusinessEntities-CBJ81aGO.mjs} +1 -1
- package/dist/{consentManagersToBusinessEntities-Rv-ajWya.mjs.map → consentManagersToBusinessEntities-CBJ81aGO.mjs.map} +1 -1
- package/dist/{constants-B6wESCW2.mjs → constants-DXzsg2CQ.mjs} +2 -2
- package/dist/{constants-B6wESCW2.mjs.map → constants-DXzsg2CQ.mjs.map} +1 -1
- package/dist/{constants-BuoISmXP.mjs → constants-D_HVDaOy.mjs} +1 -1
- package/dist/{constants-BuoISmXP.mjs.map → constants-D_HVDaOy.mjs.map} +1 -1
- package/dist/{constants-CdgK1myP.mjs → constants-jjHIzHGm.mjs} +2 -2
- package/dist/{constants-CdgK1myP.mjs.map → constants-jjHIzHGm.mjs.map} +1 -1
- package/dist/{context-4GAUnhTE.mjs → context-B33NT3ki.mjs} +1 -1
- package/dist/{context-4GAUnhTE.mjs.map → context-B33NT3ki.mjs.map} +1 -1
- package/dist/{createPoolingCommandUi-vTsGgYZT.mjs → createPoolingCommandUi-uiDjLlqf.mjs} +2 -2
- package/dist/{createPoolingCommandUi-vTsGgYZT.mjs.map → createPoolingCommandUi-uiDjLlqf.mjs.map} +1 -1
- package/dist/{dataFlowsToDataSilos-DRuAfwIn.mjs → dataFlowsToDataSilos-BF6fzWcm.mjs} +1 -1
- package/dist/{dataFlowsToDataSilos-DRuAfwIn.mjs.map → dataFlowsToDataSilos-BF6fzWcm.mjs.map} +1 -1
- package/dist/deno-runtime-DV52X8-P.mjs +2 -0
- package/dist/deno-runtime-DV52X8-P.mjs.map +1 -0
- package/dist/{done-input-validation-BFgMCQWH.mjs → done-input-validation-BUz-aVC5.mjs} +1 -1
- package/dist/{done-input-validation-BFgMCQWH.mjs.map → done-input-validation-BUz-aVC5.mjs.map} +1 -1
- package/dist/{downloadPrivacyRequestFiles-Dn3VexN2.mjs → downloadPrivacyRequestFiles-B_BVxW5Z.mjs} +2 -2
- package/dist/{downloadPrivacyRequestFiles-Dn3VexN2.mjs.map → downloadPrivacyRequestFiles-B_BVxW5Z.mjs.map} +1 -1
- package/dist/{extractClientError-DeS63kje.mjs → extractClientError-HZ2U7yqV.mjs} +1 -1
- package/dist/{extractClientError-DeS63kje.mjs.map → extractClientError-HZ2U7yqV.mjs.map} +1 -1
- package/dist/{fetchAllRequests-DUQGTJjx.mjs → fetchAllRequests-2TZr-LfT.mjs} +2 -2
- package/dist/{fetchAllRequests-DUQGTJjx.mjs.map → fetchAllRequests-2TZr-LfT.mjs.map} +1 -1
- package/dist/{formatPolicyBundleVersionSummary-Bo7DYxoy.mjs → formatPolicyBundleVersionSummary-CJmMCLtJ.mjs} +1 -1
- package/dist/{formatPolicyBundleVersionSummary-Bo7DYxoy.mjs.map → formatPolicyBundleVersionSummary-CJmMCLtJ.mjs.map} +1 -1
- package/dist/{fuzzyMatchColumns-BDD4a2W0.mjs → fuzzyMatchColumns-CQCzpjWC.mjs} +2 -2
- package/dist/{fuzzyMatchColumns-BDD4a2W0.mjs.map → fuzzyMatchColumns-CQCzpjWC.mjs.map} +1 -1
- package/dist/{generateCrossAccountApiKeys-QhnLqtUN.mjs → generateCrossAccountApiKeys-Bnqgmj-H.mjs} +2 -2
- package/dist/{generateCrossAccountApiKeys-QhnLqtUN.mjs.map → generateCrossAccountApiKeys-Bnqgmj-H.mjs.map} +1 -1
- package/dist/impl--JGnR3wp.mjs +3 -0
- package/dist/impl--JGnR3wp.mjs.map +1 -0
- package/dist/{impl-DRimS_G8.mjs → impl-2iVTxNn4.mjs} +2 -2
- package/dist/{impl-DRimS_G8.mjs.map → impl-2iVTxNn4.mjs.map} +1 -1
- package/dist/{impl-DlaWf-oS2.mjs → impl-7UqkSO3x2.mjs} +2 -2
- package/dist/{impl-DlaWf-oS2.mjs.map → impl-7UqkSO3x2.mjs.map} +1 -1
- package/dist/{impl-BPn_YPIq2.mjs → impl-B-j5ACi02.mjs} +2 -2
- package/dist/{impl-BPn_YPIq2.mjs.map → impl-B-j5ACi02.mjs.map} +1 -1
- package/dist/impl-B4BgGuF_.mjs +3 -0
- package/dist/impl-B4BgGuF_.mjs.map +1 -0
- package/dist/{impl-9TDsbGfF2.mjs → impl-BDrvzlpf2.mjs} +2 -2
- package/dist/{impl-9TDsbGfF2.mjs.map → impl-BDrvzlpf2.mjs.map} +1 -1
- package/dist/{impl-4rLX5Wah2.mjs → impl-BH_A5rgL.mjs} +2 -2
- package/dist/impl-BH_A5rgL.mjs.map +1 -0
- package/dist/{impl-CZ-KvZE02.mjs → impl-BOawPhYE.mjs} +2 -2
- package/dist/impl-BOawPhYE.mjs.map +1 -0
- package/dist/{impl-BQTw6jpw.mjs → impl-BPoEH3Nf2.mjs} +2 -2
- package/dist/impl-BPoEH3Nf2.mjs.map +1 -0
- package/dist/{impl-BoCD0t4j.mjs → impl-BXUYpR27.mjs} +2 -2
- package/dist/{impl-BoCD0t4j.mjs.map → impl-BXUYpR27.mjs.map} +1 -1
- package/dist/{impl-nJ7LzilX2.mjs → impl-Bc6p8A1l2.mjs} +2 -2
- package/dist/{impl-nJ7LzilX2.mjs.map → impl-Bc6p8A1l2.mjs.map} +1 -1
- package/dist/{impl-BbWzTCSd2.mjs → impl-BqWQh9Ss.mjs} +2 -2
- package/dist/impl-BqWQh9Ss.mjs.map +1 -0
- package/dist/impl-C6HtWd1t.mjs +2 -0
- package/dist/impl-C6HtWd1t.mjs.map +1 -0
- package/dist/{impl-DxXWaXFU.mjs → impl-CL29fOWM.mjs} +2 -2
- package/dist/{impl-DxXWaXFU.mjs.map → impl-CL29fOWM.mjs.map} +1 -1
- package/dist/{impl-BgxjEv88.mjs → impl-CO4ZqlLV.mjs} +2 -2
- package/dist/{impl-BgxjEv88.mjs.map → impl-CO4ZqlLV.mjs.map} +1 -1
- package/dist/{impl-CzbVqbm0.mjs → impl-COujMWgp.mjs} +2 -2
- package/dist/{impl-CzbVqbm0.mjs.map → impl-COujMWgp.mjs.map} +1 -1
- package/dist/{impl-CccuY3Za.mjs → impl-CPSEzCc9.mjs} +2 -2
- package/dist/{impl-CccuY3Za.mjs.map → impl-CPSEzCc9.mjs.map} +1 -1
- package/dist/{impl-DbF7uw7f2.mjs → impl-CQVy2k3o.mjs} +2 -2
- package/dist/impl-CQVy2k3o.mjs.map +1 -0
- package/dist/{impl-QeWNZCg4.mjs → impl-CUOVJsRg.mjs} +2 -2
- package/dist/{impl-QeWNZCg4.mjs.map → impl-CUOVJsRg.mjs.map} +1 -1
- package/dist/{impl-BddyFp_q.mjs → impl-CUiYbk6G.mjs} +2 -2
- package/dist/{impl-BddyFp_q.mjs.map → impl-CUiYbk6G.mjs.map} +1 -1
- package/dist/{impl-DbPLuDc22.mjs → impl-CXTBcYo6.mjs} +2 -2
- package/dist/impl-CXTBcYo6.mjs.map +1 -0
- package/dist/{impl-CVChVd63.mjs → impl-CfvxD3RI.mjs} +2 -2
- package/dist/{impl-CVChVd63.mjs.map → impl-CfvxD3RI.mjs.map} +1 -1
- package/dist/{impl-PYtpY5hs2.mjs → impl-Cli2XRp02.mjs} +2 -2
- package/dist/{impl-PYtpY5hs2.mjs.map → impl-Cli2XRp02.mjs.map} +1 -1
- package/dist/{impl-CBC5K-IH.mjs → impl-CuDs6SsI.mjs} +2 -2
- package/dist/{impl-CBC5K-IH.mjs.map → impl-CuDs6SsI.mjs.map} +1 -1
- package/dist/{impl-DiyWNLJq.mjs → impl-CvLI_Jig.mjs} +2 -2
- package/dist/{impl-DiyWNLJq.mjs.map → impl-CvLI_Jig.mjs.map} +1 -1
- package/dist/{impl-CbijbA-M2.mjs → impl-CwKYKBYb.mjs} +2 -2
- package/dist/impl-CwKYKBYb.mjs.map +1 -0
- package/dist/{impl-CMYYX3Kz.mjs → impl-CwXp3Tbr.mjs} +2 -2
- package/dist/{impl-CMYYX3Kz.mjs.map → impl-CwXp3Tbr.mjs.map} +1 -1
- package/dist/{impl-D33Zr0vh2.mjs → impl-CyQRmuM72.mjs} +2 -2
- package/dist/{impl-D33Zr0vh2.mjs.map → impl-CyQRmuM72.mjs.map} +1 -1
- package/dist/impl-DEJpYLPB.mjs +2 -0
- package/dist/impl-DEJpYLPB.mjs.map +1 -0
- package/dist/impl-DEhw1iNn.mjs +2 -0
- package/dist/impl-DEhw1iNn.mjs.map +1 -0
- package/dist/impl-DK7nSMle2.mjs +303 -0
- package/dist/impl-DK7nSMle2.mjs.map +1 -0
- package/dist/{impl-3IyENr9T.mjs → impl-DKepRc812.mjs} +2 -2
- package/dist/impl-DKepRc812.mjs.map +1 -0
- package/dist/{impl-DG9RwTkA2.mjs → impl-DLG0Egy6.mjs} +2 -2
- package/dist/impl-DLG0Egy6.mjs.map +1 -0
- package/dist/impl-DMe_OqJx.mjs +2 -0
- package/dist/impl-DMe_OqJx.mjs.map +1 -0
- package/dist/{impl-BkyqCY72.mjs → impl-DNe-gRXe2.mjs} +2 -2
- package/dist/impl-DNe-gRXe2.mjs.map +1 -0
- package/dist/{impl-Cq5wI-kP.mjs → impl-DNzkRayg.mjs} +2 -2
- package/dist/impl-DNzkRayg.mjs.map +1 -0
- package/dist/{impl-_tY0CJdZ.mjs → impl-DPtx5iZO.mjs} +2 -2
- package/dist/{impl-_tY0CJdZ.mjs.map → impl-DPtx5iZO.mjs.map} +1 -1
- package/dist/{impl-Ba8naMzu.mjs → impl-DRpK-QLC.mjs} +2 -2
- package/dist/{impl-Ba8naMzu.mjs.map → impl-DRpK-QLC.mjs.map} +1 -1
- package/dist/{impl-DQG3PiAW2.mjs → impl-DVQmuZQY.mjs} +2 -2
- package/dist/impl-DVQmuZQY.mjs.map +1 -0
- package/dist/{impl-wf0PvJms.mjs → impl-DVeGQCrr.mjs} +2 -2
- package/dist/{impl-wf0PvJms.mjs.map → impl-DVeGQCrr.mjs.map} +1 -1
- package/dist/{impl-uKjAibIR.mjs → impl-DXRDWiB1.mjs} +2 -2
- package/dist/{impl-uKjAibIR.mjs.map → impl-DXRDWiB1.mjs.map} +1 -1
- package/dist/{impl-CLVMZXJo.mjs → impl-DXowiNOz.mjs} +2 -2
- package/dist/{impl-CLVMZXJo.mjs.map → impl-DXowiNOz.mjs.map} +1 -1
- package/dist/{impl-BsEYMBx2.mjs → impl-DaH1_ZzK.mjs} +2 -2
- package/dist/{impl-BsEYMBx2.mjs.map → impl-DaH1_ZzK.mjs.map} +1 -1
- package/dist/{impl-p0AyZWFL.mjs → impl-DdIa0zla.mjs} +2 -2
- package/dist/{impl-p0AyZWFL.mjs.map → impl-DdIa0zla.mjs.map} +1 -1
- package/dist/{impl-CH40t5qf.mjs → impl-DqhZR11m.mjs} +2 -2
- package/dist/{impl-CH40t5qf.mjs.map → impl-DqhZR11m.mjs.map} +1 -1
- package/dist/{impl-BlFBTc6f.mjs → impl-Dqqb0lVN.mjs} +2 -2
- package/dist/{impl-BlFBTc6f.mjs.map → impl-Dqqb0lVN.mjs.map} +1 -1
- package/dist/{impl-CrY1za0t.mjs → impl-DryC3OJu.mjs} +2 -2
- package/dist/{impl-CrY1za0t.mjs.map → impl-DryC3OJu.mjs.map} +1 -1
- package/dist/{impl-CXdy0YMX.mjs → impl-DuZjI6p0.mjs} +2 -2
- package/dist/{impl-CXdy0YMX.mjs.map → impl-DuZjI6p0.mjs.map} +1 -1
- package/dist/{impl-CusKk_JR2.mjs → impl-Dw8NYkzw.mjs} +2 -2
- package/dist/impl-Dw8NYkzw.mjs.map +1 -0
- package/dist/impl-Dx_TfvW1.mjs +2 -0
- package/dist/impl-Dx_TfvW1.mjs.map +1 -0
- package/dist/{impl-BiBNqcob.mjs → impl-DypttZd6.mjs} +2 -2
- package/dist/{impl-BiBNqcob.mjs.map → impl-DypttZd6.mjs.map} +1 -1
- package/dist/{impl-xRwX5ZLK.mjs → impl-DzUTmaID2.mjs} +2 -2
- package/dist/impl-DzUTmaID2.mjs.map +1 -0
- package/dist/{impl-GnxjtYL7.mjs → impl-INhq_CiK.mjs} +2 -2
- package/dist/{impl-GnxjtYL7.mjs.map → impl-INhq_CiK.mjs.map} +1 -1
- package/dist/{impl-V_ffkzbd2.mjs → impl-KmCNH-yw.mjs} +2 -2
- package/dist/impl-KmCNH-yw.mjs.map +1 -0
- package/dist/{impl-Dpes0u_6.mjs → impl-RPG-BTmX.mjs} +2 -2
- package/dist/{impl-Dpes0u_6.mjs.map → impl-RPG-BTmX.mjs.map} +1 -1
- package/dist/{impl-DWBQKUuq.mjs → impl-XrTL-TDl.mjs} +2 -2
- package/dist/{impl-DWBQKUuq.mjs.map → impl-XrTL-TDl.mjs.map} +1 -1
- package/dist/impl-Z8oWVENM.mjs +2 -0
- package/dist/impl-Z8oWVENM.mjs.map +1 -0
- package/dist/impl-a_Y8bnSn.mjs +91 -0
- package/dist/impl-a_Y8bnSn.mjs.map +1 -0
- package/dist/{impl-DzJG5HaX.mjs → impl-hwpT9u5o2.mjs} +2 -2
- package/dist/impl-hwpT9u5o2.mjs.map +1 -0
- package/dist/{impl-s5h7dIlv2.mjs → impl-xq89cSSz2.mjs} +2 -2
- package/dist/{impl-s5h7dIlv2.mjs.map → impl-xq89cSSz2.mjs.map} +1 -1
- package/dist/index.d.mts +12801 -1844
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{initializeCliRuntime-B7zDhMok.mjs → initializeCliRuntime-6wI_VIHV.mjs} +1 -1
- package/dist/{initializeCliRuntime-B7zDhMok.mjs.map → initializeCliRuntime-6wI_VIHV.mjs.map} +1 -1
- package/dist/{inquirer-DNa31Mkx.mjs → inquirer-BeaBetMO.mjs} +2 -2
- package/dist/{inquirer-DNa31Mkx.mjs.map → inquirer-BeaBetMO.mjs.map} +1 -1
- package/dist/jsonc-D9dDWb1J.mjs +6 -0
- package/dist/jsonc-D9dDWb1J.mjs.map +1 -0
- package/dist/{listFiles-DrxRhlZ2.mjs → listFiles-BdFUbX5x.mjs} +1 -1
- package/dist/{listFiles-DrxRhlZ2.mjs.map → listFiles-BdFUbX5x.mjs.map} +1 -1
- package/dist/logger-zplFSeXU.mjs +2 -0
- package/dist/logger-zplFSeXU.mjs.map +1 -0
- package/dist/manifest-BNIpO_zW.mjs +2 -0
- package/dist/manifest-BNIpO_zW.mjs.map +1 -0
- package/dist/{mapConsentCsvRowsToInputs-DA7BRD7M.mjs → mapConsentCsvRowsToInputs-Dqb6WL4r.mjs} +1 -1
- package/dist/{mapConsentCsvRowsToInputs-DA7BRD7M.mjs.map → mapConsentCsvRowsToInputs-Dqb6WL4r.mjs.map} +1 -1
- package/dist/{markRequestDataSiloIdsCompleted-CK7PNwTz.mjs → markRequestDataSiloIdsCompleted-B5N-cQWr.mjs} +2 -2
- package/dist/{markRequestDataSiloIdsCompleted-CK7PNwTz.mjs.map → markRequestDataSiloIdsCompleted-B5N-cQWr.mjs.map} +1 -1
- package/dist/{markSilentPrivacyRequests-Cb-J9ckA.mjs → markSilentPrivacyRequests-BiaButWF.mjs} +2 -2
- package/dist/{markSilentPrivacyRequests-Cb-J9ckA.mjs.map → markSilentPrivacyRequests-BiaButWF.mjs.map} +1 -1
- package/dist/mergeTranscendInputs-DFQcbh8b.mjs +3 -0
- package/dist/mergeTranscendInputs-DFQcbh8b.mjs.map +1 -0
- package/dist/missing-manifest-DgcukXfg.mjs +2 -0
- package/dist/missing-manifest-DgcukXfg.mjs.map +1 -0
- package/dist/module-graph-Cb0g74Ft.mjs +2 -0
- package/dist/module-graph-Cb0g74Ft.mjs.map +1 -0
- package/dist/{notifyPrivacyRequestsAdditionalTime-it1FA62W.mjs → notifyPrivacyRequestsAdditionalTime-D3Vtvg5G.mjs} +2 -2
- package/dist/{notifyPrivacyRequestsAdditionalTime-it1FA62W.mjs.map → notifyPrivacyRequestsAdditionalTime-D3Vtvg5G.mjs.map} +1 -1
- package/dist/{parquetToCsvOneFile-Dtz90qfJ.mjs → parquetToCsvOneFile-ChmPC6dL.mjs} +2 -2
- package/dist/{parquetToCsvOneFile-Dtz90qfJ.mjs.map → parquetToCsvOneFile-ChmPC6dL.mjs.map} +1 -1
- package/dist/{parseAttributesFromString-BxJcnKmn.mjs → parseAttributesFromString-CO16oAlx.mjs} +2 -2
- package/dist/{parseAttributesFromString-BxJcnKmn.mjs.map → parseAttributesFromString-CO16oAlx.mjs.map} +1 -1
- package/dist/parseVariablesFromString-BOSfQ4QF.mjs +2 -0
- package/dist/parseVariablesFromString-BOSfQ4QF.mjs.map +1 -0
- package/dist/path-safety-D5Qwl40b.mjs +2 -0
- package/dist/path-safety-D5Qwl40b.mjs.map +1 -0
- package/dist/policy-bundle-manifest-D6dkbjNi.mjs +7 -0
- package/dist/policy-bundle-manifest-D6dkbjNi.mjs.map +1 -0
- package/dist/policy-runtime-BMKa-Upy.mjs +2 -0
- package/dist/policy-runtime-BMKa-Upy.mjs.map +1 -0
- package/dist/{policyEngineCliError-BnBghLd1.mjs → policyEngineCliError-DY8V-qkK.mjs} +1 -1
- package/dist/{policyEngineCliError-BnBghLd1.mjs.map → policyEngineCliError-DY8V-qkK.mjs.map} +1 -1
- package/dist/{printResult-oXnpZu_9.mjs → printResult-CHe3nRN4.mjs} +5 -5
- package/dist/printResult-CHe3nRN4.mjs.map +1 -0
- package/dist/project-plan-apply-Dvndx455.mjs +3 -0
- package/dist/project-plan-apply-Dvndx455.mjs.map +1 -0
- package/dist/prompts-ClBXdELk.mjs +4 -0
- package/dist/prompts-ClBXdELk.mjs.map +1 -0
- package/dist/{pullAllDatapoints-XqreMBT5.mjs → pullAllDatapoints-uk5ggk6O.mjs} +2 -2
- package/dist/{pullAllDatapoints-XqreMBT5.mjs.map → pullAllDatapoints-uk5ggk6O.mjs.map} +1 -1
- package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-DuPDOm6f.mjs → pullChunkedCustomSiloOutstandingIdentifiers-D85P1W_8.mjs} +2 -2
- package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-DuPDOm6f.mjs.map → pullChunkedCustomSiloOutstandingIdentifiers-D85P1W_8.mjs.map} +1 -1
- package/dist/{pullConsentManagerMetrics-Dk5IejaY.mjs → pullConsentManagerMetrics-Dv5n1ZGp.mjs} +2 -2
- package/dist/{pullConsentManagerMetrics-Dk5IejaY.mjs.map → pullConsentManagerMetrics-Dv5n1ZGp.mjs.map} +1 -1
- package/dist/{pullManualEnrichmentIdentifiersToCsv-CAD1navz.mjs → pullManualEnrichmentIdentifiersToCsv-DbNSrKEk.mjs} +2 -2
- package/dist/{pullManualEnrichmentIdentifiersToCsv-CAD1navz.mjs.map → pullManualEnrichmentIdentifiersToCsv-DbNSrKEk.mjs.map} +1 -1
- package/dist/{pullTranscendConfiguration-NcFjHE8k.mjs → pullTranscendConfiguration-B63M3ild.mjs} +3 -3
- package/dist/{pullTranscendConfiguration-NcFjHE8k.mjs.map → pullTranscendConfiguration-B63M3ild.mjs.map} +1 -1
- package/dist/{pullUnstructuredSubDataPointRecommendations-Cf4irXl4.mjs → pullUnstructuredSubDataPointRecommendations-YTBzfkRZ.mjs} +2 -2
- package/dist/{pullUnstructuredSubDataPointRecommendations-Cf4irXl4.mjs.map → pullUnstructuredSubDataPointRecommendations-YTBzfkRZ.mjs.map} +1 -1
- package/dist/{pushCronIdentifiersFromCsv-BGaJycWo.mjs → pushCronIdentifiersFromCsv-5ruUKHtL.mjs} +2 -2
- package/dist/{pushCronIdentifiersFromCsv-BGaJycWo.mjs.map → pushCronIdentifiersFromCsv-5ruUKHtL.mjs.map} +1 -1
- package/dist/{pushManualEnrichmentIdentifiersFromCsv-B9okRkhL.mjs → pushManualEnrichmentIdentifiersFromCsv-B0i2239u.mjs} +2 -2
- package/dist/{pushManualEnrichmentIdentifiersFromCsv-B9okRkhL.mjs.map → pushManualEnrichmentIdentifiersFromCsv-B0i2239u.mjs.map} +1 -1
- package/dist/{readCsv-CmRYYFJc.mjs → readCsv-DLg8pwjd.mjs} +1 -1
- package/dist/{readCsv-CmRYYFJc.mjs.map → readCsv-DLg8pwjd.mjs.map} +1 -1
- package/dist/readTranscendYaml-BNn6-Ofi.mjs +4 -0
- package/dist/readTranscendYaml-BNn6-Ofi.mjs.map +1 -0
- package/dist/{removeUnverifiedRequestIdentifiers-DJhxiy_D.mjs → removeUnverifiedRequestIdentifiers-QmeqrmxM.mjs} +2 -2
- package/dist/{removeUnverifiedRequestIdentifiers-DJhxiy_D.mjs.map → removeUnverifiedRequestIdentifiers-QmeqrmxM.mjs.map} +1 -1
- package/dist/{renderTable-DKXvortp.mjs → renderTable-D68QasPc.mjs} +1 -1
- package/dist/{renderTable-DKXvortp.mjs.map → renderTable-D68QasPc.mjs.map} +1 -1
- package/dist/{request-CCCU2SdV.mjs → request-BiPv6jmP.mjs} +1 -1
- package/dist/{request-CCCU2SdV.mjs.map → request-BiPv6jmP.mjs.map} +1 -1
- package/dist/{resolveBundleIdByName-By5Vl8Iz.mjs → resolveBundleIdByName-qXZBrUz_.mjs} +2 -2
- package/dist/{resolveBundleIdByName-By5Vl8Iz.mjs.map → resolveBundleIdByName-qXZBrUz_.mjs.map} +1 -1
- package/dist/{resolvePolicyBundleVersion-DO7IvEwb.mjs → resolvePolicyBundleVersion-BG7XqBBP.mjs} +2 -2
- package/dist/{resolvePolicyBundleVersion-DO7IvEwb.mjs.map → resolvePolicyBundleVersion-BG7XqBBP.mjs.map} +1 -1
- package/dist/{retryRequestDataSilos-6JfyZclD.mjs → retryRequestDataSilos-BfckLjOJ.mjs} +2 -2
- package/dist/{retryRequestDataSilos-6JfyZclD.mjs.map → retryRequestDataSilos-BfckLjOJ.mjs.map} +1 -1
- package/dist/run-captured-process-BXwWXuTh.mjs +2 -0
- package/dist/run-captured-process-BXwWXuTh.mjs.map +1 -0
- package/dist/runOpa-CswzJxIs.mjs +2 -0
- package/dist/runOpa-CswzJxIs.mjs.map +1 -0
- package/dist/scaffold-model-BAbYTR0q.mjs +2 -0
- package/dist/scaffold-model-BAbYTR0q.mjs.map +1 -0
- package/dist/scaffold-planning-CNv83t_v.mjs +123 -0
- package/dist/scaffold-planning-CNv83t_v.mjs.map +1 -0
- package/dist/scaffold-templates-DzDGTZie.mjs +84 -0
- package/dist/scaffold-templates-DzDGTZie.mjs.map +1 -0
- package/dist/{skipPreflightJobs-xpbtJ3dK.mjs → skipPreflightJobs-Do_kwu3m.mjs} +2 -2
- package/dist/{skipPreflightJobs-xpbtJ3dK.mjs.map → skipPreflightJobs-Do_kwu3m.mjs.map} +1 -1
- package/dist/{skipRequestDataSilos-B7RA6I3Z.mjs → skipRequestDataSilos-BNDhdllD.mjs} +2 -2
- package/dist/{skipRequestDataSilos-B7RA6I3Z.mjs.map → skipRequestDataSilos-BNDhdllD.mjs.map} +1 -1
- package/dist/{streamPrivacyRequestsToCsv-DT31SP6w.mjs → streamPrivacyRequestsToCsv-CbJfhV6A.mjs} +2 -2
- package/dist/{streamPrivacyRequestsToCsv-DT31SP6w.mjs.map → streamPrivacyRequestsToCsv-CbJfhV6A.mjs.map} +1 -1
- package/dist/{syncCodePackages-ozt9aBXf.mjs → syncCodePackages-BHE2Tn1Q.mjs} +2 -2
- package/dist/{syncCodePackages-ozt9aBXf.mjs.map → syncCodePackages-BHE2Tn1Q.mjs.map} +1 -1
- package/dist/{updateConsentManagerVersionToLatest-CCzWEBEj.mjs → updateConsentManagerVersionToLatest-DEFwH4Se.mjs} +2 -2
- package/dist/{updateConsentManagerVersionToLatest-CCzWEBEj.mjs.map → updateConsentManagerVersionToLatest-DEFwH4Se.mjs.map} +1 -1
- package/dist/{uploadConsents-CDqFNWX_.mjs → uploadConsents-ChmFIw_j.mjs} +2 -2
- package/dist/{uploadConsents-CDqFNWX_.mjs.map → uploadConsents-ChmFIw_j.mjs.map} +1 -1
- package/dist/{uploadPrivacyRequestsFromCsv-CVpBFaYB.mjs → uploadPrivacyRequestsFromCsv-D3KSb1qH.mjs} +2 -2
- package/dist/{uploadPrivacyRequestsFromCsv-CVpBFaYB.mjs.map → uploadPrivacyRequestsFromCsv-D3KSb1qH.mjs.map} +1 -1
- package/dist/{validateTranscendAuth-3guZJPKH.mjs → validateTranscendAuth-D6Wr1cxY.mjs} +2 -2
- package/dist/{validateTranscendAuth-3guZJPKH.mjs.map → validateTranscendAuth-D6Wr1cxY.mjs.map} +1 -1
- package/dist/{writeCsv-rhlEBjYp.mjs → writeCsv-D-2siSwE.mjs} +1 -1
- package/dist/{writeCsv-rhlEBjYp.mjs.map → writeCsv-D-2siSwE.mjs.map} +1 -1
- package/package.json +10 -4
- package/dist/app-dIu3pdTM.mjs +0 -148
- package/dist/app-dIu3pdTM.mjs.map +0 -1
- package/dist/codecs-zRkskjaJ.mjs +0 -2
- package/dist/codecs-zRkskjaJ.mjs.map +0 -1
- package/dist/constants-FbK2iR--.mjs +0 -2
- package/dist/constants-FbK2iR--.mjs.map +0 -1
- package/dist/impl-3IyENr9T.mjs.map +0 -1
- package/dist/impl-4rLX5Wah2.mjs.map +0 -1
- package/dist/impl-BPjGRqOL2.mjs +0 -3
- package/dist/impl-BPjGRqOL2.mjs.map +0 -1
- package/dist/impl-BQTw6jpw.mjs.map +0 -1
- package/dist/impl-BbWzTCSd2.mjs.map +0 -1
- package/dist/impl-BkyqCY72.mjs.map +0 -1
- package/dist/impl-BqiclSRZ.mjs +0 -2
- package/dist/impl-BqiclSRZ.mjs.map +0 -1
- package/dist/impl-CZ-KvZE02.mjs.map +0 -1
- package/dist/impl-CbijbA-M2.mjs.map +0 -1
- package/dist/impl-CclEOdC32.mjs +0 -2
- package/dist/impl-CclEOdC32.mjs.map +0 -1
- package/dist/impl-Cq5wI-kP.mjs.map +0 -1
- package/dist/impl-CusKk_JR2.mjs.map +0 -1
- package/dist/impl-DG9RwTkA2.mjs.map +0 -1
- package/dist/impl-DQG3PiAW2.mjs.map +0 -1
- package/dist/impl-DbF7uw7f2.mjs.map +0 -1
- package/dist/impl-DbPLuDc22.mjs.map +0 -1
- package/dist/impl-DzJG5HaX.mjs.map +0 -1
- package/dist/impl-GYM4LDKp2.mjs +0 -2
- package/dist/impl-GYM4LDKp2.mjs.map +0 -1
- package/dist/impl-V_ffkzbd2.mjs.map +0 -1
- package/dist/impl-_rrZ0KXo.mjs +0 -3
- package/dist/impl-_rrZ0KXo.mjs.map +0 -1
- package/dist/impl-xRwX5ZLK.mjs.map +0 -1
- package/dist/logger-CB_h_zbj.mjs +0 -2
- package/dist/logger-CB_h_zbj.mjs.map +0 -1
- package/dist/mergeTranscendInputs-CkpitZbH.mjs +0 -3
- package/dist/mergeTranscendInputs-CkpitZbH.mjs.map +0 -1
- package/dist/parseVariablesFromString-cu5gPC3M.mjs +0 -2
- package/dist/parseVariablesFromString-cu5gPC3M.mjs.map +0 -1
- package/dist/printResult-oXnpZu_9.mjs.map +0 -1
- package/dist/readTranscendYaml-DtJz9mor.mjs +0 -4
- package/dist/readTranscendYaml-DtJz9mor.mjs.map +0 -1
- package/dist/runOpa-Q2r3qPsi.mjs +0 -2
- package/dist/runOpa-Q2r3qPsi.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeTranscendInputs-DFQcbh8b.mjs","names":[],"sources":["../src/lib/preference-management/validatePreferenceManagementSlugs.ts","../src/lib/graphql/ensureAllDataSubjectsExist.ts","../src/lib/graphql/normalizeDeletionDependencies.ts","../src/lib/graphql/syncDataSilos.ts","../src/lib/graphql/syncConfigurationToTranscend.ts","../src/lib/mergeTranscendInputs.ts"],"sourcesContent":["import type { TranscendInput } from '../../codecs.js';\n\n/** Slugs for preference topics and option values must be alphabetical letters only. */\nexport const PREFERENCE_SLUG_REGEX = /^[A-Za-z]+$/;\n\n/**\n * Validate preference topic and option value slugs before push.\n *\n * @param input - Parsed transcend.yml input\n * @returns List of validation error messages (empty when valid)\n */\nexport function validatePreferenceManagementSlugs(input: TranscendInput): string[] {\n const errors: string[] = [];\n\n const validateSlug = (slug: string, context: string): void => {\n if (!PREFERENCE_SLUG_REGEX.test(slug)) {\n errors.push(\n `${context}: slug \"${slug}\" is invalid — slugs must contain only alphabetical letters (A-Z, a-z). ` +\n 'Topic slugs are normalized to PascalCase server-side, so YAML slugs should already be PascalCase ' +\n 'or matching will break on subsequent pulls.',\n );\n }\n };\n\n for (const option of input['preference-options'] ?? []) {\n validateSlug(option.slug, 'preference-options');\n }\n\n for (const purpose of input.purposes ?? []) {\n for (const topic of purpose['preference-topics'] ?? []) {\n validateSlug(topic.slug, `purposes (topic \"${topic.title}\")`);\n for (const option of topic.options ?? []) {\n validateSlug(option.slug, `purposes (topic \"${topic.title}\" option \"${option.title}\")`);\n }\n }\n }\n\n return errors;\n}\n","import { createDataSubject, fetchAllDataSubjects, type DataSubject } from '@transcend-io/sdk';\nimport colors from 'colors';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, flatten, uniq, difference } from 'lodash-es';\n\nimport { TranscendInput } from '../../codecs.js';\nimport { logger } from '../../logger.js';\n\n/**\n * Fetch all of the data subjects in the organization\n *\n * @param input - Input to fetch\n * @param client - GraphQL client\n * @param fetchAll - When true, always fetch all subjects\n * @returns The list of data subjects\n */\nexport async function ensureAllDataSubjectsExist(\n {\n 'data-silos': dataSilos = [],\n 'data-subjects': dataSubjects = [],\n 'processing-activities': processingActivities = [],\n preflights = [],\n }: TranscendInput,\n client: GraphQLClient,\n fetchAll = false,\n): Promise<{ [type in string]: DataSubject }> {\n const expectedDataSubjects = uniq([\n ...flatten(dataSilos.map((silo) => silo['data-subjects'] || []) || []),\n ...flatten(processingActivities.map(({ dataSubjectTypes }) => dataSubjectTypes ?? []) ?? []),\n ...flatten(preflights.map((preflight) => preflight['data-subjects'] || []) || []),\n ...dataSubjects.map((subject) => subject.type),\n ]);\n if (expectedDataSubjects.length === 0 && !fetchAll) {\n return {};\n }\n\n const internalSubjects = await fetchAllDataSubjects(client, { logger });\n const dataSubjectByName = keyBy(internalSubjects, 'type');\n\n const missingDataSubjects = difference(\n expectedDataSubjects,\n internalSubjects.map(({ type }) => type),\n );\n\n if (missingDataSubjects.length > 0) {\n logger.info(colors.magenta(`Creating ${missingDataSubjects.length} new data subjects...`));\n for (const dataSubjectType of missingDataSubjects) {\n logger.info(colors.magenta(`Creating data subject ${dataSubjectType}...`));\n const created = await createDataSubject(client, { input: dataSubjectType, logger });\n logger.info(colors.green(`Created data subject ${dataSubjectType}!`));\n dataSubjectByName[dataSubjectType] = created;\n }\n }\n\n return dataSubjectByName;\n}\n","import type { DependedOnDataSiloInput } from '@transcend-io/sdk';\nimport { uniq } from 'lodash-es';\n\nimport type { DeletionDependencies, DeletionDependencyInput } from '../../codecs.js';\n\n/**\n * Convert the `deletion-dependencies` entries for a single data silo into the\n * `dependedOnDataSilos` input accepted by the `updateDataSilos` mutation.\n *\n * A list of titles becomes a single global entry. A list of objects may declare\n * at most one global configuration (`{ titles }`) plus per-workflow overrides;\n * workflows that are absent from the list are left untouched.\n *\n * @param dependencies - The `deletion-dependencies` entries from transcend.yml\n * @param dataSiloTitle - Title of the data silo being synced, used in error messages\n * @returns The dependency entries to send to the API\n */\nexport function normalizeDeletionDependencies(\n dependencies: DeletionDependencies,\n dataSiloTitle: string,\n): DependedOnDataSiloInput[] {\n if (dependencies.length === 0) {\n return [];\n }\n\n // Legacy / no-overrides form: a flat list of data silo titles\n if (typeof dependencies[0] === 'string') {\n return [{ titles: uniq(dependencies as string[]) }];\n }\n\n let globalTitles: string[] | undefined;\n const workflowOverrides: DependedOnDataSiloInput[] = [];\n const seenWorkflows = new Set<string>();\n\n /**\n * Record an override for a single workflow, rejecting duplicates before the API does\n * so that the error names the data silo\n *\n * @param workflow - Internal name of the workflow being overridden\n * @param override - Titles or reset flag to send for that workflow\n */\n const addWorkflowOverride = (\n workflow: string,\n override: Omit<DependedOnDataSiloInput, 'workflowConfigInternalName'>,\n ): void => {\n if (seenWorkflows.has(workflow)) {\n throw new Error(\n `Data silo \"${dataSiloTitle}\" has multiple deletion-dependencies entries for workflow ` +\n `\"${workflow}\". Combine them into a single entry.`,\n );\n }\n seenWorkflows.add(workflow);\n workflowOverrides.push({ workflowConfigInternalName: workflow, ...override });\n };\n\n (dependencies as DeletionDependencyInput[]).forEach((dependency) => {\n // io-ts codecs allow extra properties, so this combination decodes cleanly\n // even though the two halves contradict each other\n if ('reset-to-global' in dependency && 'titles' in dependency) {\n throw new Error(\n `Data silo \"${dataSiloTitle}\" has a deletion-dependencies entry for workflow ` +\n `\"${dependency.workflow}\" that sets both \"reset-to-global\" and \"titles\". ` +\n 'Use \"titles: []\" to override the global configuration with no dependencies, ' +\n 'or \"reset-to-global: true\" to fall back to the global configuration.',\n );\n }\n\n if ('reset-to-global' in dependency) {\n addWorkflowOverride(dependency.workflow, { resetToGlobal: true });\n return;\n }\n\n if (dependency.workflow) {\n addWorkflowOverride(dependency.workflow, { titles: dependency.titles });\n return;\n }\n\n if (globalTitles !== undefined) {\n throw new Error(\n `Data silo \"${dataSiloTitle}\" has multiple global deletion-dependencies entries. ` +\n 'Combine them into a single `{ titles: [...] }` entry.',\n );\n }\n globalTitles = dependency.titles;\n });\n\n return [\n ...(globalTitles !== undefined ? [{ titles: uniq(globalTitles) }] : []),\n ...workflowOverrides,\n ];\n}\n","import {\n makeGraphQLRequest,\n ApiKey,\n convertToDataSubjectBlockList,\n type DataSubject,\n fetchAllDataSilos,\n type DataSilo,\n CREATE_DATA_SILOS,\n UPDATE_DATA_SILOS,\n UPDATE_OR_CREATE_DATA_POINT,\n} from '@transcend-io/sdk';\nimport { apply } from '@transcend-io/type-utils';\nimport { mapSeries, map } from '@transcend-io/utils';\n/* eslint-disable max-lines */\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk, keyBy } from 'lodash-es';\n\nimport { DataSiloInput } from '../../codecs.js';\nimport { logger } from '../../logger.js';\n\nconst BATCH_SILOS_LIMIT = 20;\n\n/**\n * Sync a data silo configuration\n *\n * @param dataSilos - Data silos to sync\n * @param client - GraphQL client\n * @param options - Options\n * @returns Data silo info\n */\nexport async function syncDataSilos(\n dataSilos: DataSiloInput[],\n client: GraphQLClient,\n {\n pageSize,\n dataSubjectsByName,\n apiKeysByTitle,\n }: {\n /** Page size */\n pageSize: number;\n /** The data subjects in the organization */\n dataSubjectsByName: { [type in string]: DataSubject };\n /** API key title to API key */\n apiKeysByTitle: { [title in string]: ApiKey };\n },\n): Promise<{\n /** Whether successfully updated */\n success: boolean;\n /** A mapping between data silo title to data silo ID */\n dataSiloTitleToId: { [k in string]: string };\n}> {\n let encounteredError = false;\n\n // Time duration\n const t0 = new Date().getTime();\n logger.info(colors.magenta(`Syncing \"${dataSilos.length}\" data silos...`));\n\n // Determine the set of data silos that already exist\n const existingDataSilos = await fetchAllDataSilos(client, {\n titles: dataSilos.map(({ title }) => title),\n pageSize,\n logger,\n });\n\n // Create a mapping of title -> existing silo, if it exists\n const existingDataSiloByTitle = keyBy<Pick<DataSilo, 'id' | 'title'>>(existingDataSilos, 'title');\n\n // Create new silos that do not exist\n const newDataSiloInputs = dataSilos.filter(({ title }) => !existingDataSiloByTitle[title]);\n if (newDataSiloInputs.length > 0) {\n logger.info(\n colors.magenta(`Creating \"${newDataSiloInputs.length}\" data silos that did not exist...`),\n );\n\n // Batch the creation\n const chunked = chunk(newDataSiloInputs, BATCH_SILOS_LIMIT);\n await mapSeries(chunked, async (dependencyUpdateChunk) => {\n const {\n createDataSilos: { dataSilos },\n } = await makeGraphQLRequest<{\n /** Mutation result */\n createDataSilos: {\n /** New data silos */\n dataSilos: Pick<DataSilo, 'id' | 'title'>[];\n };\n }>(client, CREATE_DATA_SILOS, {\n variables: {\n input: dependencyUpdateChunk.map((input) => ({\n name: input['outer-type'] || input.integrationName,\n title: input.title,\n country: input.country,\n countrySubDivision: input.countrySubDivision,\n sombraId: input['sombra-id'],\n })),\n },\n logger,\n });\n\n // save mapping of title and id\n dataSilos.forEach((silo) => {\n existingDataSiloByTitle[silo.title] = silo;\n });\n });\n\n logger.info(colors.green(`Successfully created \"${newDataSiloInputs.length}\" data silos!`));\n }\n\n // Batch the updates\n const chunkedUpdates = chunk(dataSilos, BATCH_SILOS_LIMIT);\n await mapSeries(chunkedUpdates, async (dataSiloUpdateChunk, ind) => {\n logger.info(\n colors.magenta(\n `[Batch ${ind + 1}/${chunkedUpdates.length}] Syncing \"${\n dataSiloUpdateChunk.length\n }\" data silos`,\n ),\n );\n await makeGraphQLRequest<{\n /** Mutation result */\n updateDataSilos: {\n /** New data silos */\n dataSilos: Pick<DataSilo, 'id' | 'title'>[];\n };\n }>(client, UPDATE_DATA_SILOS, {\n variables: {\n input: {\n dataSilos: dataSiloUpdateChunk.map((input) => ({\n id: existingDataSiloByTitle[input.title].id,\n country: input.country,\n countrySubDivision: input.countrySubDivision,\n url: input.url,\n headers: input.headers,\n description: input.description,\n identifiers: input['identity-keys'],\n isLive: !input.disabled,\n ownerEmails: input.owners,\n teamNames: input.teams,\n // clear out the global config if not specified, otherwise the update needs to be\n // applied after all data silos are created\n dependedOnDataSilos: input['deletion-dependencies'] ? undefined : [{ titles: [] }],\n apiKeyId: input['api-key-title']\n ? apiKeysByTitle[input['api-key-title']].id\n : undefined,\n dataSubjectBlockListIds: input['data-subjects']\n ? convertToDataSubjectBlockList(input['data-subjects'], dataSubjectsByName)\n : undefined,\n attributes: input.attributes,\n businessEntityTitles: input.businessEntityTitles,\n sombraId: input['sombra-id'],\n // AVC settings\n notifyEmailAddress: input['email-settings']?.['notify-email-address'],\n promptAVendorEmailSendFrequency: input['email-settings']?.['send-frequency'],\n promptAVendorEmailSendType: input['email-settings']?.['send-type'],\n promptAVendorEmailIncludeIdentifiersAttachment:\n input['email-settings']?.['include-identifiers-attachment'],\n promptAVendorEmailCompletionLinkType: input['email-settings']?.['completion-link-type'],\n manualWorkRetryFrequency: input['email-settings']?.['manual-work-retry-frequency'],\n })),\n },\n },\n logger,\n });\n logger.info(\n colors.green(\n `[Batch ${ind + 1}/${chunkedUpdates.length}] Synced \"${\n dataSiloUpdateChunk.length\n }\" data silos!`,\n ),\n );\n });\n\n // Sync datapoints\n\n // create a new progress bar instance and use shades_classic theme\n const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);\n const dataSilosWithDataPoints = dataSilos.filter(({ datapoints = [] }) => datapoints.length > 0);\n const totalDataPoints = dataSilos\n .map(({ datapoints = [] }) => datapoints.length)\n .reduce((acc, count) => acc + count, 0);\n logger.info(\n colors.magenta(\n `Syncing \"${totalDataPoints}\" datapoints from \"${dataSilosWithDataPoints.length}\" data silos...`,\n ),\n );\n progressBar.start(totalDataPoints, 0);\n let total = 0;\n\n await map(\n dataSilosWithDataPoints,\n async ({ datapoints, title }) => {\n if (datapoints) {\n await mapSeries(datapoints, async (datapoint) => {\n const fields = datapoint.fields\n ? datapoint.fields.map(\n ({ key, description, categories, purposes, attributes, ...rest }) =>\n // TODO: Support setting title separately from the 'key/name'\n ({\n name: key,\n description,\n categories: !categories\n ? undefined\n : categories.map((category) => ({\n ...category,\n name: category.name || 'Other',\n })),\n purposes: !purposes\n ? undefined\n : purposes.map((purpose) => ({\n ...purpose,\n name: purpose.name || 'Other',\n })),\n attributes,\n accessRequestVisibilityEnabled: rest['access-request-visibility-enabled'],\n erasureRequestRedactionEnabled: rest['erasure-request-redaction-enabled'],\n }),\n )\n : undefined;\n\n const payload = {\n dataSiloId: existingDataSiloByTitle[title].id,\n path: datapoint.path,\n name: datapoint.key,\n title: datapoint.title,\n description: datapoint.description,\n ...(datapoint.owners\n ? {\n ownerEmails: datapoint.owners,\n }\n : {}),\n ...(datapoint.teams\n ? {\n teamNames: datapoint.teams,\n }\n : {}),\n ...(datapoint['data-collection-tag']\n ? { dataCollectionTag: datapoint['data-collection-tag'] }\n : {}),\n querySuggestions: !datapoint['privacy-action-queries']\n ? undefined\n : Object.entries(datapoint['privacy-action-queries']).map(([key, value]) => ({\n requestType: key,\n suggestedQuery: value,\n })),\n enabledActions: datapoint['privacy-actions'] || [], // clear out when not specified\n subDataPoints: fields,\n };\n\n // Ensure no duplicate sub-datapoints are provided\n const subDataPointsToUpdate = (payload.subDataPoints || []).map(({ name }) => name);\n const duplicateDataPoints = subDataPointsToUpdate.filter(\n (name, index) => subDataPointsToUpdate.indexOf(name) !== index,\n );\n if (duplicateDataPoints.length > 0) {\n logger.info(\n colors.red(\n `\\nCannot update datapoint \"${\n datapoint.key\n }\" as it has duplicate sub-datapoints with the same name: \\n${duplicateDataPoints.join(\n '\\n',\n )}`,\n ),\n );\n encounteredError = true;\n } else {\n try {\n await makeGraphQLRequest(client, UPDATE_OR_CREATE_DATA_POINT, {\n variables: payload,\n logger,\n });\n } catch (err) {\n logger.info(\n colors.red(\n `\\nFailed to update datapoint \"${datapoint.key}\" for data silo \"${title}\"! - \\n${err.message}`,\n ),\n );\n encounteredError = true;\n }\n }\n total += 1;\n progressBar.update(total);\n });\n }\n },\n {\n concurrency: 10,\n },\n );\n\n progressBar.stop();\n const t1 = new Date().getTime();\n const totalTime = t1 - t0;\n\n logger.info(\n colors.green(\n `Synced \"${dataSilos.length}\" data silos and \"${totalDataPoints}\" datapoints in \"${\n totalTime / 1000\n }\" seconds!`,\n ),\n );\n return {\n success: !encounteredError,\n dataSiloTitleToId: apply(existingDataSiloByTitle, ({ id }) => id),\n };\n}\n/* eslint-enable max-lines */\n","import {\n fetchAllActions,\n fetchAllAttributes,\n fetchAllDataSubjects,\n fetchApiKeys,\n fetchIdentifiersAndCreateMissing,\n syncAction,\n syncActionItemCollections,\n syncActionItems,\n syncAttribute,\n syncBusinessEntities,\n syncDataCategories,\n syncConsentManager,\n syncCookies,\n syncDataFlows,\n syncDataSubject,\n syncDataSiloDependencies,\n syncEnricher,\n syncIdentifier,\n syncIntlMessages,\n syncPartitions,\n syncPolicies,\n syncPrivacyCenter,\n syncProcessingActivities,\n syncProcessingPurposes,\n syncConsentWorkflowTriggers,\n syncWorkflowConfigs,\n syncPreferenceOptionValues,\n syncPurposes,\n syncPreferenceTopics,\n syncTeams,\n syncTemplate,\n syncVendors,\n type DependedOnDataSiloInput,\n type Identifier,\n} from '@transcend-io/sdk';\nimport { map, type Logger, type SyncError, type SyncResult } from '@transcend-io/utils';\nimport colors from 'colors';\nimport { GraphQLClient } from 'graphql-request';\n\n/* eslint-disable max-lines */\nimport { TranscendInput, normalizeTranscendInput } from '../../codecs.js';\nimport { logger } from '../../logger.js';\nimport { validatePreferenceManagementSlugs } from '../preference-management/validatePreferenceManagementSlugs.js';\nimport { ensureAllDataSubjectsExist } from './ensureAllDataSubjectsExist.js';\nimport { normalizeDeletionDependencies } from './normalizeDeletionDependencies.js';\nimport { syncDataSilos } from './syncDataSilos.js';\n\nconst CONCURRENCY = 10;\n\n/**\n * Sync the yaml input back to Transcend using the GraphQL APIs\n *\n * @param input - The yml input\n * @param client - GraphQL client\n * @param pageSize - Page size\n * @returns Structured sync result with per-resource errors\n */\nexport async function syncConfigurationToTranscend(\n rawInput: TranscendInput,\n client: GraphQLClient,\n {\n pageSize = 50,\n // TODO: https://transcend.height.app/T-23779\n publishToPrivacyCenter = true,\n classifyService = false,\n deleteExtraAttributeValues = false,\n logger: syncLogger,\n warnings = [],\n }: {\n /** Page size */\n pageSize?: number;\n /** When true, skip publishing to privacy center */\n publishToPrivacyCenter?: boolean;\n /** When true, delete any attributes being synced up */\n deleteExtraAttributeValues?: boolean;\n /** classify data flow service if missing */\n classifyService?: boolean;\n /** Optional logger (e.g. collecting logger for MCP debug responses) */\n logger?: Logger;\n /** Non-fatal warnings to include in the result */\n warnings?: string[];\n },\n): Promise<SyncResult> {\n const input = normalizeTranscendInput(rawInput);\n const activeLogger = syncLogger ?? logger;\n const errors: SyncError[] = [];\n let encounteredError = false;\n\n const recordError = (resource: string, message: string, item?: string): void => {\n errors.push({ resource, item, message });\n encounteredError = true;\n };\n\n activeLogger.info(colors.magenta(`Fetching data with page size ${pageSize}...`));\n\n const {\n templates,\n attributes,\n actions,\n identifiers,\n 'data-subjects': dataSubjects,\n 'business-entities': businessEntities,\n preflights,\n cookies,\n 'consent-manager': consentManager,\n 'data-silos': dataSilos,\n 'data-flows': dataFlows,\n vendors,\n 'data-categories': dataCategories,\n 'processing-activities': processingActivities,\n 'processing-purposes': processingPurposes,\n 'action-items': actionItems,\n 'action-item-collections': actionItemCollections,\n teams,\n 'privacy-center': privacyCenter,\n messages,\n policies,\n partitions,\n 'preference-workflow-configs': preferenceWorkflowConfigs,\n 'workflow-configs': workflowConfigs,\n } = input;\n\n const preferenceOptions = input['preference-options'];\n const purposes = input.purposes;\n\n const preferenceSlugErrors = validatePreferenceManagementSlugs(input);\n if (preferenceSlugErrors.length > 0) {\n for (const message of preferenceSlugErrors) {\n recordError('preference-slugs', message);\n }\n return {\n success: false,\n errors,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n\n const [identifierByName, dataSubjectsByName, apiKeyTitleMap] = await Promise.all([\n // Ensure all identifiers are created and create a map from name -> identifier.id\n preflights || identifiers\n ? fetchIdentifiersAndCreateMissing(client, {\n input,\n skipPublish: !publishToPrivacyCenter,\n logger,\n })\n : ({} as { [k in string]: Identifier }),\n // Grab all data subjects in the organization\n dataSilos || dataSubjects || preflights || processingActivities\n ? ensureAllDataSubjectsExist(input, client)\n : {},\n // Grab API keys\n dataSilos &&\n dataSilos\n .map((dataSilo) => dataSilo['api-key-title'] || [])\n .reduce((acc, lst) => acc + lst.length, 0) > 0\n ? fetchApiKeys(client, { apiKeyInputs: input, logger })\n : {},\n ]);\n\n if (preferenceWorkflowConfigs?.length) {\n const preferenceWorkflowConfigsSuccess = await syncConsentWorkflowTriggers(\n client,\n preferenceWorkflowConfigs,\n {\n logger: activeLogger,\n pageSize,\n },\n );\n if (!preferenceWorkflowConfigsSuccess) {\n recordError('preference-workflow-configs', 'Failed to sync preference workflow configs');\n }\n }\n\n if (workflowConfigs?.length) {\n const workflowConfigsSuccess = await syncWorkflowConfigs(client, workflowConfigs, {\n logger: activeLogger,\n });\n if (!workflowConfigsSuccess) {\n recordError('workflow-configs', 'Failed to sync workflow configs');\n }\n }\n\n if (preferenceOptions?.length) {\n const preferenceOptionsSuccess = await syncPreferenceOptionValues(client, preferenceOptions, {\n logger: activeLogger,\n });\n if (!preferenceOptionsSuccess) {\n recordError('preference-options', 'Failed to sync preference option values');\n }\n }\n\n // Sync consent purposes and their nested preference topics.\n // Order matters: option values (above) exist first, then purposes, then topics\n // (which link to their purpose by ID and to option values by slug).\n if (purposes?.length) {\n const { success: purposesSuccess, purposeIdByTrackingType } = await syncPurposes(\n client,\n purposes,\n { logger: activeLogger },\n );\n if (!purposesSuccess) {\n recordError('purposes', 'Failed to sync one or more purposes');\n }\n\n const topics = purposes.flatMap((purpose) =>\n (purpose['preference-topics'] ?? []).map((topic) => ({\n ...topic,\n 'tracking-type': purpose.trackingType,\n })),\n );\n if (topics.length > 0) {\n const topicsSuccess = await syncPreferenceTopics(client, topics, {\n logger: activeLogger,\n purposeIdByTrackingType,\n });\n if (!topicsSuccess) {\n recordError('preference-topics', 'Failed to sync one or more preference topics');\n }\n }\n }\n\n // Sync consent manager\n if (consentManager) {\n activeLogger.info(colors.magenta('Syncing consent manager...'));\n try {\n await syncConsentManager(client, consentManager, { logger: activeLogger });\n activeLogger.info(colors.green('Successfully synced consent manager!'));\n } catch (err) {\n recordError('consent-manager', (err as Error).message);\n activeLogger.error(colors.red(`Failed to sync consent manager! - ${(err as Error).message}`));\n }\n }\n\n if (teams) {\n const teamsSuccess = await syncTeams(client, teams, { logger });\n encounteredError = encounteredError || !teamsSuccess;\n }\n\n // Sync email templates\n if (templates) {\n logger.info(colors.magenta(`Syncing \"${templates.length}\" email templates...`));\n await map(\n templates,\n async (template) => {\n logger.info(colors.magenta(`Syncing template \"${template.title}\"...`));\n try {\n await syncTemplate(client, template, { logger });\n logger.info(colors.green(`Successfully synced template \"${template.title}\"!`));\n } catch (err) {\n encounteredError = true;\n logger.error(colors.red(`Failed to sync template \"${template.title}\"! - ${err.message}`));\n }\n },\n {\n concurrency: CONCURRENCY,\n },\n );\n logger.info(colors.green(`Synced \"${templates.length}\" email templates!`));\n }\n\n // Sync business entities\n if (businessEntities) {\n const businessEntitySuccess = await syncBusinessEntities(client, businessEntities, { logger });\n encounteredError = encounteredError || !businessEntitySuccess;\n }\n\n // Sync vendors\n if (vendors) {\n const vendorsSuccess = await syncVendors(client, vendors, { logger });\n encounteredError = encounteredError || !vendorsSuccess;\n }\n\n // Sync data categories\n if (dataCategories) {\n const dataCategoriesSuccess = await syncDataCategories(client, dataCategories, { logger });\n encounteredError = encounteredError || !dataCategoriesSuccess;\n }\n\n // Sync processing purposes\n if (processingPurposes) {\n const processingPurposesSuccess = await syncProcessingPurposes(client, processingPurposes, {\n logger,\n });\n encounteredError = encounteredError || !processingPurposesSuccess;\n }\n\n // Sync partitions\n if (partitions) {\n const partitionsSuccess = await syncPartitions(client, partitions, { logger });\n encounteredError = encounteredError || !partitionsSuccess;\n }\n\n // Sync cookies\n if (cookies) {\n const cookiesSuccess = await syncCookies(client, cookies, { logger });\n encounteredError = encounteredError || !cookiesSuccess;\n }\n\n // Sync action item collections\n if (actionItemCollections) {\n const actionItemCollectionsSuccess = await syncActionItemCollections(\n client,\n actionItemCollections,\n { logger },\n );\n encounteredError = encounteredError || !actionItemCollectionsSuccess;\n }\n\n // Sync attributes\n if (attributes) {\n // Fetch existing\n logger.info(colors.magenta(`Syncing \"${attributes.length}\" attributes...`));\n const existingAttributes = await fetchAllAttributes(client, { logger });\n await map(\n attributes,\n async (attribute) => {\n const existing = existingAttributes.find((attr) => attr.name === attribute.name);\n\n logger.info(colors.magenta(`Syncing attribute \"${attribute.name}\"...`));\n try {\n await syncAttribute(client, attribute, {\n existingAttribute: existing,\n deleteExtraAttributeValues,\n logger,\n });\n logger.info(colors.green(`Successfully synced attribute \"${attribute.name}\"!`));\n } catch (err) {\n encounteredError = true;\n logger.error(\n colors.red(`Failed to sync attribute \"${attribute.name}\"! - ${err.message}`),\n );\n }\n },\n {\n concurrency: CONCURRENCY,\n },\n );\n logger.info(colors.green(`Synced \"${attributes.length}\" attributes!`));\n }\n\n // Sync action items\n if (actionItems) {\n const actionItemsSuccess = await syncActionItems(client, actionItems, { logger });\n encounteredError = encounteredError || !actionItemsSuccess;\n }\n\n // Sync preflight checks\n if (preflights) {\n logger.info(colors.magenta(`Syncing \"${preflights.length}\" preflight checks...`));\n await map(\n preflights,\n async (preflight) => {\n logger.info(colors.magenta(`Syncing preflight check \"${preflight.title}\"...`));\n try {\n await syncEnricher(client, {\n input: preflight,\n identifierByName,\n dataSubjectsByName,\n logger,\n });\n logger.info(colors.green(`Successfully synced preflight check \"${preflight.title}\"!`));\n } catch (err) {\n encounteredError = true;\n logger.error(\n colors.red(`Failed to sync preflight check \"${preflight.title}\"! - ${err.message}`),\n );\n }\n },\n {\n concurrency: CONCURRENCY,\n },\n );\n logger.info(colors.green(`Synced \"${preflights.length}\" preflight checks!`));\n }\n\n // Sync identifiers\n if (identifiers) {\n // Fetch existing\n logger.info(colors.magenta(`Syncing \"${identifiers.length}\" identifiers...`));\n await map(\n identifiers,\n async (identifier) => {\n const existing = identifierByName[identifier.name];\n if (!existing) {\n throw new Error(\n `Failed to find identifier with name: ${identifier.type}. Should have been auto-created by cli.`,\n );\n }\n\n logger.info(colors.magenta(`Syncing identifier \"${identifier.type}\"...`));\n try {\n await syncIdentifier(client, {\n input: identifier,\n dataSubjectsByName,\n identifierId: existing.id,\n skipPublish: !publishToPrivacyCenter,\n logger,\n });\n logger.info(colors.green(`Successfully synced identifier \"${identifier.type}\"!`));\n } catch (err) {\n encounteredError = true;\n logger.info(\n colors.red(`Failed to sync identifier \"${identifier.type}\"! - ${err.message}`),\n );\n }\n },\n {\n concurrency: CONCURRENCY,\n },\n );\n logger.info(colors.green(`Synced \"${identifiers.length}\" identifiers!`));\n }\n\n // Sync actions\n if (actions) {\n // Fetch existing\n logger.info(colors.magenta(`Syncing \"${actions.length}\" actions...`));\n const existingActions = await fetchAllActions(client, { logger });\n await map(\n actions,\n async (action) => {\n const existing = existingActions.find((act) => act.type === action.type);\n if (!existing) {\n throw new Error(\n `Failed to find action with type: ${action.type}. Should have already existing in the organization.`,\n );\n }\n\n logger.info(colors.magenta(`Syncing action \"${action.type}\"...`));\n try {\n await syncAction(\n client,\n {\n action,\n actionId: existing.id,\n skipPublish: !publishToPrivacyCenter,\n },\n { logger },\n );\n logger.info(colors.green(`Successfully synced action \"${action.type}\"!`));\n } catch (err) {\n encounteredError = true;\n logger.error(colors.red(`Failed to sync action \"${action.type}\"! - ${err.message}`));\n }\n },\n {\n concurrency: CONCURRENCY,\n },\n );\n logger.info(colors.green(`Synced \"${actions.length}\" actions!`));\n }\n\n // Sync data subjects\n if (dataSubjects) {\n // Fetch existing\n logger.info(colors.magenta(`Syncing \"${dataSubjects.length}\" data subjects...`));\n const existingDataSubjects = await fetchAllDataSubjects(client, { logger });\n await map(\n dataSubjects,\n async (dataSubject) => {\n const existing = existingDataSubjects.find((subj) => subj.type === dataSubject.type);\n if (!existing) {\n throw new Error(\n `Failed to find data subject with type: ${dataSubject.type}. Should have already existing in the organization.`,\n );\n }\n\n logger.info(colors.magenta(`Syncing data subject \"${dataSubject.type}\"...`));\n try {\n await syncDataSubject(client, {\n input: dataSubject,\n dataSubjectId: existing.id,\n skipPublish: !publishToPrivacyCenter,\n logger,\n });\n logger.info(colors.green(`Successfully synced data subject \"${dataSubject.type}\"!`));\n } catch (err) {\n encounteredError = true;\n // supportsAuthorizedAgent is gated on the Authorized Agents feature being\n // enabled for the organization; surface a clearer hint than the raw API error\n const hint =\n dataSubject.supportsAuthorizedAgent !== undefined &&\n /authorized.agent/i.test(err.message)\n ? ' (enable the Authorized Agents feature for this organization before setting \"supportsAuthorizedAgent\")'\n : '';\n logger.info(\n colors.red(\n `Failed to sync data subject \"${dataSubject.type}\"! - ${err.message}${hint}`,\n ),\n );\n }\n },\n {\n concurrency: CONCURRENCY,\n },\n );\n logger.info(colors.green(`Synced \"${dataSubjects.length}\" data subjects!`));\n }\n\n // Sync data flows\n if (dataFlows) {\n const syncedDataFlows = await syncDataFlows(client, dataFlows, { classifyService, logger });\n encounteredError = encounteredError || !syncedDataFlows;\n }\n\n // Sync privacy center\n if (privacyCenter) {\n try {\n const privacyCenterSuccess = await syncPrivacyCenter(client, privacyCenter, {\n logger,\n skipPublish: !publishToPrivacyCenter,\n });\n if (!privacyCenterSuccess) {\n recordError('privacy-center', 'Failed to sync privacy center');\n }\n } catch (err) {\n recordError('privacy-center', (err as Error).message);\n }\n }\n\n // Sync messages\n if (messages) {\n const messagesSuccess = await syncIntlMessages(client, messages, { logger });\n encounteredError = encounteredError || !messagesSuccess;\n }\n\n // Sync policies\n if (policies) {\n const policiesSuccess = await syncPolicies(client, policies, { logger });\n encounteredError = encounteredError || !policiesSuccess;\n }\n\n // Store dependency updates\n const dependencyUpdates: [string, DependedOnDataSiloInput[]][] = [];\n // Sync data silos\n if (dataSilos) {\n const { success, dataSiloTitleToId } = await syncDataSilos(dataSilos, client, {\n dataSubjectsByName,\n apiKeysByTitle: apiKeyTitleMap,\n pageSize,\n });\n dataSilos?.forEach((dataSilo) => {\n // Queue up dependency update\n const dependencies = dataSilo['deletion-dependencies'];\n if (dependencies) {\n try {\n dependencyUpdates.push([\n dataSiloTitleToId[dataSilo.title],\n normalizeDeletionDependencies(dependencies, dataSilo.title),\n ]);\n } catch (err) {\n recordError('data-silos', (err as Error).message, dataSilo.title);\n activeLogger.error(colors.red((err as Error).message));\n }\n }\n });\n encounteredError = encounteredError || !success;\n }\n\n // Dependencies updated at the end after all data silos are created\n if (dependencyUpdates.length > 0) {\n const dependenciesSuccess = await syncDataSiloDependencies(client, {\n input: dependencyUpdates,\n logger,\n });\n encounteredError = encounteredError || !dependenciesSuccess;\n }\n\n // Update processing activities\n if (processingActivities) {\n const processingActivitySuccess = await syncProcessingActivities(client, processingActivities, {\n logger,\n });\n encounteredError = encounteredError || !processingActivitySuccess;\n }\n\n if (publishToPrivacyCenter) {\n // TODO: https://transcend.height.app/T-23779\n }\n\n return {\n success: !encounteredError,\n errors,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n}\n/* eslint-enable max-lines */\n","import { getEntries } from '@transcend-io/type-utils';\n\nimport { normalizeTranscendInput, TranscendInput } from '../codecs.js';\n\n/**\n * Combine a set of TranscendInput yaml files into a single yaml\n *\n * @param base - Base input\n * @param inputs - The list of inputs\n * @returns Merged input\n */\nexport function mergeTranscendInputs(\n base: TranscendInput,\n ...inputs: TranscendInput[]\n): TranscendInput {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cloned: any = JSON.parse(JSON.stringify(base));\n inputs.forEach((input) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getEntries(input).forEach(([key, value]: [any, any]) => {\n if (cloned[key] === undefined) {\n cloned[key] = value;\n } else if (Array.isArray(value)) {\n cloned[key] = [...cloned[key], ...value];\n } else {\n cloned[key] = value;\n }\n });\n });\n return normalizeTranscendInput(cloned);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{m as e}from"./prompts-ClBXdELk.mjs";import{dirname as t,relative as n}from"node:path";function r(r){let{command:i,cwd:a,manifestPath:o}=r,s=n(a,o)||`transcend-functions.yml`,c=r.discoveredManifestPaths.filter(e=>e!==o);return c.length===1?`Custom Function manifest does not exist at ${s}. Did you mean \`transcend custom-functions ${i} ${e(n(a,t(c[0]))||`.`)}\`?`:c.length>1?`Custom Function manifest does not exist at ${s}. Found manifests at: ${c.map(e=>n(a,e)).join(`, `)}. Pass a directory or --manifest explicitly.`:`Custom Function manifest does not exist at ${s}. Run \`transcend custom-functions init\` to create the default project.`}export{r as t};
|
|
2
|
+
//# sourceMappingURL=missing-manifest-DgcukXfg.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-manifest-DgcukXfg.mjs","names":[],"sources":["../src/lib/custom-functions/missing-manifest.ts"],"sourcesContent":["import { dirname, relative } from 'node:path';\n\nimport { quoteShellArgument } from '../scaffolding/project-plan-output.js';\n\n/** Command that can be redirected to a discovered Custom Function project. */\nexport type ManifestConsumerCommand = 'check' | 'new' | 'run';\n\n/**\n * Format actionable guidance when a requested Custom Function manifest is absent.\n *\n * @param options - Requested and discovered manifest paths\n * @returns Missing-manifest explanation\n */\nexport function formatMissingManifestMessage(options: {\n /** Command working directory. */\n cwd: string;\n /** Requested absolute manifest path. */\n manifestPath: string;\n /** Other absolute manifests discovered in the surrounding project. */\n discoveredManifestPaths: readonly string[];\n /** Command the user originally invoked. */\n command: ManifestConsumerCommand;\n}): string {\n const { command, cwd, manifestPath } = options;\n const requested = relative(cwd, manifestPath) || 'transcend-functions.yml';\n const discovered = options.discoveredManifestPaths.filter(\n (candidate) => candidate !== manifestPath,\n );\n if (discovered.length === 1) {\n const directory = relative(cwd, dirname(discovered[0]!)) || '.';\n return (\n `Custom Function manifest does not exist at ${requested}. ` +\n `Did you mean \\`transcend custom-functions ${command} ${quoteShellArgument(directory)}\\`?`\n );\n }\n if (discovered.length > 1) {\n const paths = discovered.map((path) => relative(cwd, path)).join(', ');\n return (\n `Custom Function manifest does not exist at ${requested}. ` +\n `Found manifests at: ${paths}. Pass a directory or --manifest explicitly.`\n );\n }\n return (\n `Custom Function manifest does not exist at ${requested}. ` +\n 'Run `transcend custom-functions init` to create the default project.'\n );\n}\n"],"mappings":"6FAaA,SAAgB,EAA6B,EASlC,CACT,GAAM,CAAE,UAAS,MAAK,gBAAiB,EACjC,EAAY,EAAS,EAAK,EAAa,EAAI,0BAC3C,EAAa,EAAQ,wBAAwB,OAChD,GAAc,IAAc,EAC9B,CAeD,OAdI,EAAW,SAAW,EAGtB,8CAA8C,EAAU,8CACX,EAAQ,GAAG,EAHxC,EAAS,EAAK,EAAQ,EAAW,GAAI,CAAC,EAAI,IAG2B,CAAC,KAGtF,EAAW,OAAS,EAGpB,8CAA8C,EAAU,wBAF5C,EAAW,IAAK,GAAS,EAAS,EAAK,EAAK,CAAC,CAAC,KAAK,KAGnC,CAAC,8CAI/B,8CAA8C,EAAU"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){let t=JSON.parse(e),n=Array.isArray(t.roots)?t.roots[0]:void 0;if(typeof n!=`string`||!Array.isArray(t.modules))throw Error(`Deno returned an unexpected module graph.`);let r=t.modules.find(({specifier:e})=>e===n);if(!r)throw Error(`Deno did not return the Custom Function root module.`);return[...new Set((r.dependencies??[]).filter(({code:e,specifier:t})=>typeof e?.specifier==`string`&&(e.specifier.startsWith(`file:`)||typeof t!=`string`||!/^(?:data|https?|jsr|node|npm):/u.test(t))).map(({specifier:e,code:t})=>typeof e==`string`?e:String(t.specifier)))]}export{e as t};
|
|
2
|
+
//# sourceMappingURL=module-graph-Cb0g74Ft.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-graph-Cb0g74Ft.mjs","names":[],"sources":["../src/lib/custom-functions/module-graph.ts"],"sourcesContent":["/** One resolved dependency in `deno info --json` output. */\ninterface DenoInfoDependency {\n /** Original import specifier. */\n specifier?: unknown;\n /** Runtime dependency resolution. */\n code?: {\n /** Resolved runtime module specifier. */\n specifier?: unknown;\n };\n}\n\n/** One module in `deno info --json` output. */\ninterface DenoInfoModule {\n /** Resolved module specifier. */\n specifier?: unknown;\n /** Direct module dependencies. */\n dependencies?: DenoInfoDependency[];\n}\n\n/**\n * Find runtime imports that rely on local files or project import maps.\n *\n * Custom Functions are signed and executed as one data-URL module, so local\n * runtime dependencies cannot accompany the entry source. Type-only imports\n * are intentionally ignored because Deno strips them before execution.\n *\n * @param output - `deno info --json` output for one source root\n * @returns Original import specifiers that resolve to local files\n */\nexport function findNonSelfContainedRuntimeImports(output: string): string[] {\n const graph = JSON.parse(output) as {\n /** Root module specifiers. */\n roots?: unknown;\n /** Resolved modules. */\n modules?: DenoInfoModule[];\n };\n const root = Array.isArray(graph.roots) ? graph.roots[0] : undefined;\n if (typeof root !== 'string' || !Array.isArray(graph.modules)) {\n throw new Error('Deno returned an unexpected module graph.');\n }\n const rootModule = graph.modules.find(({ specifier }) => specifier === root);\n if (!rootModule) {\n throw new Error('Deno did not return the Custom Function root module.');\n }\n return [\n ...new Set(\n (rootModule.dependencies ?? [])\n .filter(\n ({ code, specifier }) =>\n typeof code?.specifier === 'string' &&\n (code.specifier.startsWith('file:') ||\n typeof specifier !== 'string' ||\n !/^(?:data|https?|jsr|node|npm):/u.test(specifier)),\n )\n .map(({ specifier, code }) =>\n typeof specifier === 'string' ? specifier : String(code!.specifier),\n ),\n ),\n ];\n}\n"],"mappings":"AA6BA,SAAgB,EAAmC,EAA0B,CAC3E,IAAM,EAAQ,KAAK,MAAM,EAAO,CAM1B,EAAO,MAAM,QAAQ,EAAM,MAAM,CAAG,EAAM,MAAM,GAAK,IAAA,GAC3D,GAAI,OAAO,GAAS,UAAY,CAAC,MAAM,QAAQ,EAAM,QAAQ,CAC3D,MAAU,MAAM,4CAA4C,CAE9D,IAAM,EAAa,EAAM,QAAQ,MAAM,CAAE,eAAgB,IAAc,EAAK,CAC5E,GAAI,CAAC,EACH,MAAU,MAAM,uDAAuD,CAEzE,MAAO,CACL,GAAG,IAAI,KACJ,EAAW,cAAgB,EAAE,EAC3B,QACE,CAAE,OAAM,eACP,OAAO,GAAM,WAAc,WAC1B,EAAK,UAAU,WAAW,QAAQ,EACjC,OAAO,GAAc,UACrB,CAAC,kCAAkC,KAAK,EAAU,EACvD,CACA,KAAK,CAAE,YAAW,UACjB,OAAO,GAAc,SAAW,EAAY,OAAO,EAAM,UAAU,CACpE,CACJ,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e}from"./constants-
|
|
2
|
-
//# sourceMappingURL=notifyPrivacyRequestsAdditionalTime-
|
|
1
|
+
import{a as e}from"./constants-jjHIzHGm.mjs";import{t}from"./logger-zplFSeXU.mjs";import{r as n}from"./request-BiPv6jmP.mjs";import{r}from"./fetchAllRequests-2TZr-LfT.mjs";import{RequestAction as i}from"@transcend-io/privacy-types";import a from"colors";import{buildTranscendGraphQLClient as o,fetchAllTemplates as s,makeGraphQLRequest as c}from"@transcend-io/sdk";import{map as l}from"@transcend-io/utils";import u from"cli-progress";async function d({requestActions:d=Object.values(i),auth:f,requestIds:p,createdAtBefore:m,days:h=45,daysLeft:g=10,createdAtAfter:_,updatedAtBefore:v,updatedAtAfter:y,emailTemplate:b=`Additional Time Needed`,concurrency:x=100,transcendUrl:S=e}){let C=o(S,f),w=new Date().getTime(),T=new u.SingleBar({},u.Presets.shades_classic),E=(await s(C,{logger:t,filterBy:{title:b}})).find(e=>e.title===b);if(!E)throw Error(`Failed to find a template with title: "${b}"`);let D=await r(C,{actions:d,createdAtBefore:m,createdAtAfter:_,updatedAtBefore:v,updatedAtAfter:y,isSilent:!1,isClosed:!1,requestIds:p});D=D.filter(e=>typeof e.daysRemaining==`number`&&e.daysRemaining<g),t.info(a.magenta(`Notifying "${D.length}" that more time is needed.`));let O=0;T.start(D.length,0),await l(D,async e=>{await c(C,n,{variables:{input:{requestId:e.id,template:E.template.defaultMessage,subject:E.subject.defaultMessage,additionalTime:h}},logger:t}),O+=1,T.update(O)},{concurrency:x}),T.stop();let k=new Date().getTime()-w;return t.info(a.green(`Successfully marked ${O} requests as silent mode in "${k/1e3}" seconds!`)),D.length}export{d as t};
|
|
2
|
+
//# sourceMappingURL=notifyPrivacyRequestsAdditionalTime-D3Vtvg5G.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifyPrivacyRequestsAdditionalTime-
|
|
1
|
+
{"version":3,"file":"notifyPrivacyRequestsAdditionalTime-D3Vtvg5G.mjs","names":[],"sources":["../src/lib/requests/notifyPrivacyRequestsAdditionalTime.ts"],"sourcesContent":["import { RequestAction } from '@transcend-io/privacy-types';\nimport {\n buildTranscendGraphQLClient,\n fetchAllTemplates,\n makeGraphQLRequest,\n} from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\n\nimport { DEFAULT_TRANSCEND_API } from '../../constants.js';\nimport { logger } from '../../logger.js';\nimport { NOTIFY_ADDITIONAL_TIME, fetchAllRequests } from '../graphql/index.js';\n\n/**\n * Mark a set of privacy requests to be in silent mode.\n * Note requests in silent mode are ignored\n *\n * @param options - Options\n * @returns The number of requests marked silent\n */\nexport async function notifyPrivacyRequestsAdditionalTime({\n requestActions = Object.values(RequestAction),\n auth,\n requestIds,\n createdAtBefore,\n days = 45,\n daysLeft = 10,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n emailTemplate = 'Additional Time Needed',\n concurrency = 100,\n transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n /** The request actions that should be restarted */\n requestActions?: RequestAction[];\n /** Filter for requests created before this date */\n createdAtBefore: Date;\n /** Filter for requests created after this date */\n createdAtAfter?: Date;\n /** Filter for requests updated before this date */\n updatedAtBefore?: Date;\n /** Filter for requests updated after this date */\n updatedAtAfter?: Date;\n /** Email template */\n emailTemplate?: string;\n /** Transcend API key authentication */\n auth: string;\n /** Number of days to extend request by */\n days?: number;\n /**\n * Only notify requests that have less than this number of days until they are considered expired.\n * This allows for re-running the command without notifying the same users multiple times\n */\n daysLeft?: number;\n /** Concurrency limit for approving */\n concurrency?: number;\n /** The set of privacy requests to notify */\n requestIds?: string[];\n /** API URL for Transcend backend */\n transcendUrl?: string;\n}): Promise<number> {\n // Find all requests made before createdAt that are in a removing data state\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n // Time duration\n const t0 = new Date().getTime();\n // create a new progress bar instance and use shades_classic theme\n const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);\n\n // Grab the template with that title\n const matchingTemplates = await fetchAllTemplates(client, {\n logger,\n filterBy: { title: emailTemplate },\n });\n const exactTemplateMatch = matchingTemplates.find((template) => template.title === emailTemplate);\n if (!exactTemplateMatch) {\n throw new Error(`Failed to find a template with title: \"${emailTemplate}\"`);\n }\n\n // Pull in the requests\n let allRequests = await fetchAllRequests(client, {\n actions: requestActions,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n isSilent: false,\n isClosed: false,\n requestIds,\n });\n\n // Filter requests by daysLeft\n allRequests = allRequests.filter(\n (request) => typeof request.daysRemaining === 'number' && request.daysRemaining < daysLeft,\n );\n\n // Notify Transcend\n logger.info(colors.magenta(`Notifying \"${allRequests.length}\" that more time is needed.`));\n\n let total = 0;\n progressBar.start(allRequests.length, 0);\n await map(\n allRequests,\n async (requestToNotify) => {\n await makeGraphQLRequest(client, NOTIFY_ADDITIONAL_TIME, {\n variables: {\n input: {\n requestId: requestToNotify.id,\n template: exactTemplateMatch.template.defaultMessage,\n subject: exactTemplateMatch.subject.defaultMessage,\n additionalTime: days,\n },\n },\n logger,\n });\n\n total += 1;\n progressBar.update(total);\n },\n { concurrency },\n );\n\n progressBar.stop();\n const t1 = new Date().getTime();\n const totalTime = t1 - t0;\n\n logger.info(\n colors.green(\n `Successfully marked ${total} requests as silent mode in \"${totalTime / 1000}\" seconds!`,\n ),\n );\n return allRequests.length;\n}\n"],"mappings":"mbAqBA,eAAsB,EAAoC,CACxD,iBAAiB,OAAO,OAAO,EAAc,CAC7C,OACA,aACA,kBACA,OAAO,GACP,WAAW,GACX,iBACA,kBACA,iBACA,gBAAgB,yBAChB,cAAc,IACd,eAAe,GA6BG,CAElB,IAAM,EAAS,EAA4B,EAAc,EAAK,CAGxD,EAAK,IAAI,MAAM,CAAC,SAAS,CAEzB,EAAc,IAAI,EAAY,UAAU,EAAE,CAAE,EAAY,QAAQ,eAAe,CAO/E,GAAqB,MAJK,EAAkB,EAAQ,CACxD,SACA,SAAU,CAAE,MAAO,EAAe,CACnC,CAAC,EAC2C,KAAM,GAAa,EAAS,QAAU,EAAc,CACjG,GAAI,CAAC,EACH,MAAU,MAAM,0CAA0C,EAAc,GAAG,CAI7E,IAAI,EAAc,MAAM,EAAiB,EAAQ,CAC/C,QAAS,EACT,kBACA,iBACA,kBACA,iBACA,SAAU,GACV,SAAU,GACV,aACD,CAAC,CAGF,EAAc,EAAY,OACvB,GAAY,OAAO,EAAQ,eAAkB,UAAY,EAAQ,cAAgB,EACnF,CAGD,EAAO,KAAK,EAAO,QAAQ,cAAc,EAAY,OAAO,6BAA6B,CAAC,CAE1F,IAAI,EAAQ,EACZ,EAAY,MAAM,EAAY,OAAQ,EAAE,CACxC,MAAM,EACJ,EACA,KAAO,IAAoB,CACzB,MAAM,EAAmB,EAAQ,EAAwB,CACvD,UAAW,CACT,MAAO,CACL,UAAW,EAAgB,GAC3B,SAAU,EAAmB,SAAS,eACtC,QAAS,EAAmB,QAAQ,eACpC,eAAgB,EACjB,CACF,CACD,SACD,CAAC,CAEF,GAAS,EACT,EAAY,OAAO,EAAM,EAE3B,CAAE,cAAa,CAChB,CAED,EAAY,MAAM,CAElB,IAAM,EADK,IAAI,MAAM,CAAC,SACF,CAAG,EAOvB,OALA,EAAO,KACL,EAAO,MACL,uBAAuB,EAAM,+BAA+B,EAAY,IAAK,YAC9E,CACF,CACM,EAAY"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{t as e}from"./logger-
|
|
1
|
+
import{t as e}from"./logger-zplFSeXU.mjs";import{existsSync as t,mkdirSync as n,rmSync as r}from"node:fs";import{dirname as i,join as a,parse as o}from"node:path";import s from"colors";async function c(c,f){let{filePath:p,outputDir:m,clearOutputDir:h,onProgress:g}=c,_=m||i(p),{name:v}=o(p),y=a(_,`${v}.csv`);if(n(_,{recursive:!0}),h&&t(y))try{r(y,{force:!0})}catch(t){e.warn(s.yellow(`Could not remove existing output file ${y}: ${t.message}`))}let b=await f.create(`:memory:`),x=await b.connect();try{await u(x,`PRAGMA temp_directory='';`);let t=e=>`'${e.replace(/'/g,`''`)}'`;await l(x,`
|
|
2
2
|
COPY (SELECT * FROM read_parquet(${t(p)}))
|
|
3
3
|
TO ${t(y)}
|
|
4
4
|
(HEADER, DELIMITER ',', QUOTE '"', ESCAPE '"', NULL '');
|
|
5
5
|
`),g?.(0,void 0),e.info(s.green(`Wrote CSV → ${y}`))}finally{await d(x),await d(b)}}async function l(e,t){await d(await e.run(t))}async function u(e,t){try{await l(e,t)}catch{}}async function d(e){if(!(!e||typeof e.dispose!=`function`))try{await e.dispose()}catch{}}export{c as t};
|
|
6
|
-
//# sourceMappingURL=parquetToCsvOneFile-
|
|
6
|
+
//# sourceMappingURL=parquetToCsvOneFile-ChmPC6dL.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parquetToCsvOneFile-
|
|
1
|
+
{"version":3,"file":"parquetToCsvOneFile-ChmPC6dL.mjs","names":[],"sources":["../src/lib/helpers/parquetToCsvOneFile.ts"],"sourcesContent":["import { mkdirSync, rmSync, existsSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\n\nimport type { DuckDBConnection, DuckDBInstance } from '@duckdb/node-api';\nimport colors from 'colors';\n\nimport { logger } from '../../logger.js';\n\n/** Progress callback used by the parent runner to surface progress to the UI. */\ntype OnProgress = (processed: number, total?: number) => void;\n\n/**\n * Options for converting a single Parquet file into a single CSV file.\n */\nexport type ParquetToCsvOneFileOptions = {\n /** Absolute or relative path to the input `.parquet` file. */\n filePath: string;\n /**\n * Directory where the output CSV will be written.\n * If omitted, the CSV is written next to the input file.\n */\n outputDir?: string;\n /**\n * When true, removes a pre-existing output file with the same name before writing.\n * Useful for re-runs; ignored if the file does not exist.\n */\n clearOutputDir: boolean;\n /**\n * Optional progress hook. Called with the number of processed records.\n * `total` is not computed here; it will be `undefined`.\n */\n onProgress?: OnProgress;\n};\n\n/**\n * Convert a single Parquet file to a single CSV file (1:1) using DuckDB.\n *\n * Output naming: `${basename}.csv` in `outputDir ?? dirname(filePath)`.\n *\n * Errors:\n * - Throws on I/O failures or DuckDB execution errors.\n *\n * Why DuckDB?\n * - Robust reader for many Parquet dialects (e.g., Spark output, nested types, timestamps).\n * - Streaming COPY handles large files without loading everything into JS memory.\n *\n * What this does:\n * - Opens an in-memory DuckDB database (no `.db` file created).\n * - Optionally disables temp spilling to disk (so only your CSV is written).\n * - Executes a single `COPY (SELECT * FROM read_parquet(...)) TO ...` statement.\n * - Produces exactly one CSV per input Parquet (no chunking or rotation).\n *\n * Notes & defaults:\n * - DuckDBInstance: `:memory:` (ephemeral). No persistent DB file is created.\n * - Temp files: disabled via `PRAGMA temp_directory=''` (best-effort; ignored if unsupported).\n * - CSV format: header row, comma delimiter, double-quote quoting, empty string for NULL.\n * - Progress: DuckDB COPY doesn't expose row-level progress via the JS API; we emit a\n * best-effort final callback.\n *\n * Requirements:\n * - `@duckdb/node-api` npm package installed and available at runtime.\n * - Supported platform binary (mac arm64/x64, linux x64, windows x64).\n *\n * @param opts - Conversion options\n * @param DuckDb - DuckDB instance to use\n * @returns Promise<void> when the CSV has been written\n */\nexport async function parquetToCsvOneFile(\n opts: ParquetToCsvOneFileOptions,\n DuckDb: typeof DuckDBInstance,\n): Promise<void> {\n const { filePath, outputDir, clearOutputDir, onProgress } = opts;\n\n const baseDir = outputDir || dirname(filePath);\n const { name: baseName } = parse(filePath);\n const outPath = join(baseDir, `${baseName}.csv`);\n\n // Ensure output directory exists\n mkdirSync(baseDir, { recursive: true });\n\n // Remove any pre-existing output file if requested\n if (clearOutputDir && existsSync(outPath)) {\n try {\n rmSync(outPath, { force: true });\n } catch (err) {\n logger.warn(\n colors.yellow(\n `Could not remove existing output file ${outPath}: ${(err as Error).message}`,\n ),\n );\n }\n }\n\n // In-memory DB: no .db file created on disk\n const db = await DuckDb.create(':memory:');\n const conn = await db.connect();\n\n try {\n // Optional: prevent DuckDB from creating temp files on disk (best-effort).\n // Some versions may ignore or error; we ignore such errors safely.\n await runIgnoreError(conn, \"PRAGMA temp_directory='';\");\n\n // Optionally: cap memory to encourage in-memory execution or fail-fast\n // (commented out by default; uncomment to enforce a limit)\n // await runIgnoreError(conn, \"PRAGMA memory_limit='4GB';\");\n\n // Ensure stable CSV settings: header, comma delimiter, double quotes, empty string for NULLs.\n // Escape single quotes for SQL string literals\n const q = (p: string): string => `'${p.replace(/'/g, \"''\")}'`;\n\n // Use COPY with a subquery so DuckDB streams Parquet -> CSV efficiently.\n const sql = `\n COPY (SELECT * FROM read_parquet(${q(filePath)}))\n TO ${q(outPath)}\n (HEADER, DELIMITER ',', QUOTE '\"', ESCAPE '\"', NULL '');\n `;\n\n await run(conn, sql);\n\n // Best-effort progress notification (DuckDB JS API doesn't expose progress for COPY)\n onProgress?.(0, undefined);\n\n logger.info(colors.green(`Wrote CSV → ${outPath}`));\n } finally {\n // Close connection + db handles gracefully\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await disposeSafe(conn as any);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await disposeSafe(db as any);\n }\n}\n\n/* =============================================================================\n * DuckDB helpers\n * =============================================================================\n */\n\n/**\n * Execute a SQL statement on a DuckDB connection and dispose the result.\n *\n * @param conn - DuckDB connection\n * @param sql - SQL string to run\n * @returns Promise<void>\n */\nasync function run(conn: DuckDBConnection, sql: string): Promise<void> {\n const result = await conn.run(sql);\n // The high-level API returns a Result; ensure we dispose it to free buffers.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await disposeSafe(result as any);\n}\n\n/**\n * Execute a SQL statement but ignore any error that occurs.\n * Useful for best-effort PRAGMAs that may not be supported across versions.\n *\n * @param conn - DuckDB connection\n * @param sql - SQL string to run\n * @returns Promise<void>\n */\nasync function runIgnoreError(conn: DuckDBConnection, sql: string): Promise<void> {\n try {\n await run(conn, sql);\n } catch {\n // ignore\n }\n}\n\n/**\n * Dispose a DuckDB resource (connection or instance) if present.\n *\n * @param handle - Object exposing an async `dispose()` method\n * @returns Promise<void>\n */\nasync function disposeSafe(\n handle:\n | {\n /** Dispose handler */\n dispose: () => Promise<void>;\n }\n | null\n | undefined,\n): Promise<void> {\n if (!handle || typeof handle.dispose !== 'function') return;\n try {\n await handle.dispose();\n } catch {\n // ignore\n }\n}\n"],"mappings":"yLAmEA,eAAsB,EACpB,EACA,EACe,CACf,GAAM,CAAE,WAAU,YAAW,iBAAgB,cAAe,EAEtD,EAAU,GAAa,EAAQ,EAAS,CACxC,CAAE,KAAM,GAAa,EAAM,EAAS,CACpC,EAAU,EAAK,EAAS,GAAG,EAAS,MAAM,CAMhD,GAHA,EAAU,EAAS,CAAE,UAAW,GAAM,CAAC,CAGnC,GAAkB,EAAW,EAAQ,CACvC,GAAI,CACF,EAAO,EAAS,CAAE,MAAO,GAAM,CAAC,OACzB,EAAK,CACZ,EAAO,KACL,EAAO,OACL,yCAAyC,EAAQ,IAAK,EAAc,UACrE,CACF,CAKL,IAAM,EAAK,MAAM,EAAO,OAAO,WAAW,CACpC,EAAO,MAAM,EAAG,SAAS,CAE/B,GAAI,CAGF,MAAM,EAAe,EAAM,4BAA4B,CAQvD,IAAM,EAAK,GAAsB,IAAI,EAAE,QAAQ,KAAM,KAAK,CAAC,GAS3D,MAAM,EAAI,EAAM;yCALqB,EAAE,EAAS,CAAC;WAC1C,EAAE,EAAQ,CAAC;;MAIE,CAGpB,IAAa,EAAG,IAAA,GAAU,CAE1B,EAAO,KAAK,EAAO,MAAM,eAAe,IAAU,CAAC,QAC3C,CAGR,MAAM,EAAY,EAAY,CAE9B,MAAM,EAAY,EAAU,EAgBhC,eAAe,EAAI,EAAwB,EAA4B,CAIrE,MAAM,EAAY,MAHG,EAAK,IAAI,EAAI,CAGF,CAWlC,eAAe,EAAe,EAAwB,EAA4B,CAChF,GAAI,CACF,MAAM,EAAI,EAAM,EAAI,MACd,GAWV,eAAe,EACb,EAOe,CACX,MAAC,GAAU,OAAO,EAAO,SAAY,YACzC,GAAI,CACF,MAAM,EAAO,SAAS,MAChB"}
|
package/dist/{parseAttributesFromString-BxJcnKmn.mjs → parseAttributesFromString-CO16oAlx.mjs}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./logger-
|
|
2
|
-
//# sourceMappingURL=parseAttributesFromString-
|
|
1
|
+
import{t as e}from"./logger-zplFSeXU.mjs";import t from"colors";import*as n from"io-ts";const r=n.type({key:n.string,values:n.array(n.string)});function i(n){let r=n.map(e=>{let[t,n]=e.trim().split(`:`);if(!n)throw Error(`Expected attributes in key:value1;value2,key2:value3;value4`);return{key:t,values:n.split(`;`)}});return e.info(t.magenta(`Attributes to apply to all requests:`)),e.info(t.magenta(JSON.stringify(r,null,2))),r}export{i as n,r as t};
|
|
2
|
+
//# sourceMappingURL=parseAttributesFromString-CO16oAlx.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseAttributesFromString-
|
|
1
|
+
{"version":3,"file":"parseAttributesFromString-CO16oAlx.mjs","names":[],"sources":["../src/lib/requests/parseAttributesFromString.ts"],"sourcesContent":["import colors from 'colors';\nimport * as t from 'io-ts';\n\nimport { logger } from '../../logger.js';\n\nexport const ParsedAttributeInput = t.type({\n /** Attribute key */\n key: t.string,\n /** Attribute values */\n values: t.array(t.string),\n});\n\n/** Type override */\nexport type ParsedAttributeInput = t.TypeOf<typeof ParsedAttributeInput>;\n\n/**\n * Parse out the extra attributes to apply to all requests uploaded\n *\n * @param attributes - input as string, e.g. ['key:value1;value2','key2:value3;value4']\n * @returns The parsed attributes\n */\nexport function parseAttributesFromString(attributes: string[]): ParsedAttributeInput[] {\n // Parse out the extra attributes to apply to all requests uploaded\n const parsedAttributes = attributes.map((attribute) => {\n const [attributeKey, attributeValuesRaw] = attribute.trim().split(':');\n if (!attributeValuesRaw) {\n throw new Error('Expected attributes in key:value1;value2,key2:value3;value4');\n }\n const attributeValues = attributeValuesRaw.split(';');\n return {\n key: attributeKey,\n values: attributeValues,\n };\n });\n logger.info(colors.magenta('Attributes to apply to all requests:'));\n logger.info(colors.magenta(JSON.stringify(parsedAttributes, null, 2)));\n return parsedAttributes;\n}\n"],"mappings":"wFAKA,MAAa,EAAuB,EAAE,KAAK,CAEzC,IAAK,EAAE,OAEP,OAAQ,EAAE,MAAM,EAAE,OAAO,CAC1B,CAAC,CAWF,SAAgB,EAA0B,EAA8C,CAEtF,IAAM,EAAmB,EAAW,IAAK,GAAc,CACrD,GAAM,CAAC,EAAc,GAAsB,EAAU,MAAM,CAAC,MAAM,IAAI,CACtE,GAAI,CAAC,EACH,MAAU,MAAM,8DAA8D,CAGhF,MAAO,CACL,IAAK,EACL,OAHsB,EAAmB,MAAM,IAGxB,CACxB,EACD,CAGF,OAFA,EAAO,KAAK,EAAO,QAAQ,uCAAuC,CAAC,CACnE,EAAO,KAAK,EAAO,QAAQ,KAAK,UAAU,EAAkB,KAAM,EAAE,CAAC,CAAC,CAC/D"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){let t=[],n=``;for(let r=0;r<e.length;r+=1){let i=e[r],a=e[r+1];i===`\\`&&(a===`,`||a===`\\`)?(n+=a,r+=1):i===`,`?(t.push(n),n=``):n+=i}t.push(n);let r={};return t.filter(Boolean).forEach(e=>{let t=e.indexOf(`:`);if(t<=0||t===e.length-1)throw Error(`Invalid variable: ${e}. Expected format: key:value`);let n=e.slice(0,t);r[n]=e.slice(t+1)}),r}export{e as t};
|
|
2
|
+
//# sourceMappingURL=parseVariablesFromString-BOSfQ4QF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseVariablesFromString-BOSfQ4QF.mjs","names":[],"sources":["../src/lib/helpers/parseVariablesFromString.ts"],"sourcesContent":["/**\n * Parse variables from a CLI string.\n *\n * @param variables - Variables as a string\n * @returns Variables as an object\n */\nexport function parseVariablesFromString(variables: string): {\n [k in string]: string;\n} {\n const entries: string[] = [];\n let current = '';\n for (let index = 0; index < variables.length; index += 1) {\n const character = variables[index]!;\n const next = variables[index + 1];\n if (character === '\\\\' && (next === ',' || next === '\\\\')) {\n current += next;\n index += 1;\n } else if (character === ',') {\n entries.push(current);\n current = '';\n } else {\n current += character;\n }\n }\n entries.push(current);\n const parsed: { [k in string]: string } = {};\n entries.filter(Boolean).forEach((entry) => {\n const separator = entry.indexOf(':');\n if (separator <= 0 || separator === entry.length - 1) {\n throw new Error(`Invalid variable: ${entry}. Expected format: key:value`);\n }\n const k = entry.slice(0, separator);\n const v = entry.slice(separator + 1);\n parsed[k] = v;\n });\n return parsed;\n}\n"],"mappings":"AAMA,SAAgB,EAAyB,EAEvC,CACA,IAAM,EAAoB,EAAE,CACxB,EAAU,GACd,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAU,OAAQ,GAAS,EAAG,CACxD,IAAM,EAAY,EAAU,GACtB,EAAO,EAAU,EAAQ,GAC3B,IAAc,OAAS,IAAS,KAAO,IAAS,OAClD,GAAW,EACX,GAAS,GACA,IAAc,KACvB,EAAQ,KAAK,EAAQ,CACrB,EAAU,IAEV,GAAW,EAGf,EAAQ,KAAK,EAAQ,CACrB,IAAM,EAAoC,EAAE,CAU5C,OATA,EAAQ,OAAO,QAAQ,CAAC,QAAS,GAAU,CACzC,IAAM,EAAY,EAAM,QAAQ,IAAI,CACpC,GAAI,GAAa,GAAK,IAAc,EAAM,OAAS,EACjD,MAAU,MAAM,qBAAqB,EAAM,8BAA8B,CAE3E,IAAM,EAAI,EAAM,MAAM,EAAG,EAAU,CAEnC,EAAO,GADG,EAAM,MAAM,EAAY,EACrB,EACb,CACK"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{basename as e,dirname as t,isAbsolute as n,relative as r,resolve as i,sep as a}from"node:path";function o(n,r){let a=i(r),o=[];for(;;)try{return n.fs.lstatSync(a),i(n.fs.realpathSync(a),...o)}catch(n){let r=n.code;if(r!==`ENOENT`&&r!==`ENOTDIR`)throw n;let i=t(a);if(i===a)throw n;o.unshift(e(a)),a=i}}function s(e,t,i){let s=r(o(e,t),o(e,i));return s!==`..`&&!s.startsWith(`..${a}`)&&!n(s)}function c(e,t,n){if(!s(e,t,n))throw Error(`Refusing to access path outside project root through a symlink: ${n}`)}export{s as n,c as t};
|
|
2
|
+
//# sourceMappingURL=path-safety-D5Qwl40b.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-safety-D5Qwl40b.mjs","names":[],"sources":["../src/lib/scaffolding/path-safety.ts"],"sourcesContent":["import { basename, dirname, isAbsolute, relative, resolve, sep } from 'node:path';\n\nimport type { LocalContext } from '../../context.js';\n\n/**\n * Resolve a path through its nearest existing ancestor.\n *\n * This retains nonexistent suffixes while resolving every existing symlink in\n * the prefix, which is required before safely creating a new file.\n *\n * @param context - CLI context\n * @param path - Absolute or relative path\n * @returns Physical absolute path\n */\nfunction resolvePhysicalPath(context: LocalContext, path: string): string {\n let current = resolve(path);\n const suffix: string[] = [];\n while (true) {\n try {\n context.fs.lstatSync(current);\n return resolve(context.fs.realpathSync(current), ...suffix);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT' && code !== 'ENOTDIR') {\n throw error;\n }\n const parent = dirname(current);\n if (parent === current) {\n throw error;\n }\n suffix.unshift(basename(current));\n current = parent;\n }\n }\n}\n\n/**\n * Determine whether a path physically remains under an approved root.\n *\n * @param context - CLI context\n * @param root - Approved directory\n * @param path - Candidate destination or referenced file\n * @returns Whether existing symlinks keep the path under the root\n */\nexport function isPathPhysicallyContained(\n context: LocalContext,\n root: string,\n path: string,\n): boolean {\n const physicalRoot = resolvePhysicalPath(context, root);\n const physicalPath = resolvePhysicalPath(context, path);\n const child = relative(physicalRoot, physicalPath);\n return child !== '..' && !child.startsWith(`..${sep}`) && !isAbsolute(child);\n}\n\n/**\n * Reject a path whose existing symlink ancestors escape an approved root.\n *\n * @param context - CLI context\n * @param root - Approved directory\n * @param path - Candidate path\n */\nexport function assertPathPhysicallyContained(\n context: LocalContext,\n root: string,\n path: string,\n): void {\n if (!isPathPhysicallyContained(context, root, path)) {\n throw new Error(`Refusing to access path outside project root through a symlink: ${path}`);\n }\n}\n"],"mappings":"sGAcA,SAAS,EAAoB,EAAuB,EAAsB,CACxE,IAAI,EAAU,EAAQ,EAAK,CACrB,EAAmB,EAAE,CAC3B,OACE,GAAI,CAEF,OADA,EAAQ,GAAG,UAAU,EAAQ,CACtB,EAAQ,EAAQ,GAAG,aAAa,EAAQ,CAAE,GAAG,EAAO,OACpD,EAAO,CACd,IAAM,EAAQ,EAAgC,KAC9C,GAAI,IAAS,UAAY,IAAS,UAChC,MAAM,EAER,IAAM,EAAS,EAAQ,EAAQ,CAC/B,GAAI,IAAW,EACb,MAAM,EAER,EAAO,QAAQ,EAAS,EAAQ,CAAC,CACjC,EAAU,GAahB,SAAgB,EACd,EACA,EACA,EACS,CAGT,IAAM,EAAQ,EAFO,EAAoB,EAAS,EAEf,CADd,EAAoB,EAAS,EACD,CAAC,CAClD,OAAO,IAAU,MAAQ,CAAC,EAAM,WAAW,KAAK,IAAM,EAAI,CAAC,EAAW,EAAM,CAU9E,SAAgB,EACd,EACA,EACA,EACM,CACN,GAAI,CAAC,EAA0B,EAAS,EAAM,EAAK,CACjD,MAAU,MAAM,mEAAmE,IAAO"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const e=/^\s*package\s+/mu;function t(e,t){let n=/^[A-Za-z_][A-Za-z0-9_]*/u.exec(e.slice(t));return n?{identifier:n[0],end:t+n[0].length}:void 0}function n(e,t){let n=t;for(;n<e.length&&/\s/u.test(e[n]);)n+=1;return n}function r(e,t){if(e[t]==="`"){let n=e.indexOf("`",t+1);return n===-1?void 0:{value:e.slice(t+1,n),end:n+1}}if(e[t]!==`"`)return;let n=t+1;for(;n<e.length;){if(e[n]===`\\`){n+=2;continue}if(e[n]===`"`){let r=e.slice(t,n+1);try{return{value:JSON.parse(r),end:n+1}}catch{return}}n+=1}}function i(e,i){let a=t(e,i);if(!a)return;let o=[a.identifier],s=a.end;for(;s<e.length;){let i=n(e,s);if(e[i]===`.`){let r=t(e,n(e,i+1));if(!r)break;o.push(r.identifier),s=r.end;continue}if(e[i]===`[`){let t=r(e,n(e,i+1));if(!t)break;let a=n(e,t.end);if(e[a]!==`]`)break;o.push(t.value),s=a+1;continue}break}return{source:e.slice(i,s),segments:o,end:s}}function a(t){let n=e.exec(t);if(!n)return;let r=i(t,n.index+n[0].length);return r?{source:r.source,segments:r.segments}:void 0}function o(e,t){let n=e[t],r=t+1;for(;r<e.length;){if(n===`"`&&e[r]===`\\`){r+=2;continue}if(e[r]===n)return r+1;r+=1}return r}function s(e){let n=[],r=0;for(;r<e.length;){if(e[r]===`#`){let t=e.indexOf(`
|
|
2
|
+
`,r);r=t===-1?e.length:t+1;continue}if(e[r]===`"`||e[r]==="`"){r=o(e,r);continue}let a=t(e,r);if(!a){r+=1;continue}if(a.identifier!==`data`){r=a.end;continue}let s=i(e,r);if(!s||s.segments.length===1){r=a.end;continue}let c=e.lastIndexOf(`
|
|
3
|
+
`,r-1)+1;/^\s*import\s+$/u.test(e.slice(c,r))||n.push({reference:s,line:e.slice(0,r).split(`
|
|
4
|
+
`).length}),r=s.end}return n}function c(e){return e.endsWith(`.rego`)&&!e.endsWith(`_test.rego`)}function l(e){if(e===void 0)throw Error(`Policy bundle directory must contain a manifest.json file.`);let t;try{t=JSON.parse(e)}catch(e){throw Error(`manifest.json is not valid JSON: ${e instanceof Error?e.message:String(e)}`,{cause:e})}if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`manifest.json must contain a JSON object.`);let n=t.roots;if(!Array.isArray(n)||n.length===0)throw Error(`manifest.json must declare "roots" as a non-empty array of strings (e.g. {"roots":["policy_engine"]}).`);if(!n.every(e=>typeof e==`string`&&e.length>0))throw Error(`manifest.json "roots" must be an array of non-empty strings.`);if(!n.every(e=>e.split(`/`).every(e=>/^[A-Za-z_][A-Za-z0-9_]*$/u.test(e))))throw Error(`manifest.json "roots" must contain slash-separated Rego identifiers so Policy Engine can re-namespace them safely.`);return{roots:n}}function u(e,t){return e.length>=t.length&&t.every((t,n)=>t===e[n])}function d(e,t){let n=t.join(`.`),r=e.source.slice(n.length);return e.source.startsWith(n)&&(r===``||r.startsWith(`.`)||/^\s*\[/u.test(r))}function f(e,t){return u(e.slice(1),t)}function p(e,t){let n=l(e),r=n.roots.join(`, `),i=t.filter(({path:e})=>c(e)).slice().sort((e,t)=>e.path.localeCompare(t.path));if(i.length===0)throw Error(`Policy bundle directory must contain at least one .rego policy file.`);let o=n.roots.map(e=>e.split(`/`)),u=i.flatMap(({path:e,contents:t})=>{let n=a(t);return!n||o.some(e=>d(n,e))?[]:[` - ${e} (package ${n.source}) is not covered by roots [${r}]`]});if(u.length>0)throw Error([`manifest.json "roots" do not cover all Rego packages in the bundle; uncovered packages will fail-closed at decide time. Either broaden "roots" or move the policy under a covered package:`,...u].join(`
|
|
5
|
+
`));let p=i.flatMap(({path:e,contents:t})=>s(t).filter(({reference:e})=>o.some(t=>f(e.segments,t))).map(({reference:t,line:n})=>` - ${e}:${n} references ${t.source}; import that package and use its local name`));if(p.length>0)throw Error([`Publishable Rego must not reference its declared bundle roots directly because Policy Engine re-namespaces package imports during activation:`,...p].join(`
|
|
6
|
+
`));return{manifest:n,publishableRegoPaths:i.map(({path:e})=>e)}}export{p as t};
|
|
7
|
+
//# sourceMappingURL=policy-bundle-manifest-D6dkbjNi.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-bundle-manifest-D6dkbjNi.mjs","names":[],"sources":["../src/lib/policy/rego-reference.ts","../src/lib/policy/policy-bundle-manifest.ts"],"sourcesContent":["/** Parsed static Rego reference. */\ninterface StaticRegoReference {\n /** Source representation of the reference. */\n source: string;\n /** Logical document path segments. */\n segments: string[];\n /** Offset immediately after the reference. */\n end: number;\n}\n\n/** Matches the beginning of a Rego package declaration. */\nconst PACKAGE_DECLARATION_PATTERN = /^\\s*package\\s+/mu;\n\n/**\n * Read an identifier at a source offset.\n *\n * @param source - Rego source\n * @param start - Candidate identifier offset\n * @returns Identifier and following offset\n */\nfunction readIdentifier(\n source: string,\n start: number,\n): { identifier: string; end: number } | undefined {\n const match = /^[A-Za-z_][A-Za-z0-9_]*/u.exec(source.slice(start));\n return match ? { identifier: match[0], end: start + match[0].length } : undefined;\n}\n\n/**\n * Advance past Rego whitespace.\n *\n * @param source - Rego source\n * @param start - Initial source offset\n * @returns First non-whitespace offset\n */\nfunction skipWhitespace(source: string, start: number): number {\n let current = start;\n while (current < source.length && /\\s/u.test(source[current]!)) {\n current += 1;\n }\n return current;\n}\n\n/**\n * Read a quoted or raw Rego string.\n *\n * @param source - Rego source\n * @param start - Opening quote offset\n * @returns Decoded string and following offset\n */\nfunction readQuotedString(\n source: string,\n start: number,\n): { value: string; end: number } | undefined {\n if (source[start] === '`') {\n const closingQuote = source.indexOf('`', start + 1);\n return closingQuote === -1\n ? undefined\n : { value: source.slice(start + 1, closingQuote), end: closingQuote + 1 };\n }\n if (source[start] !== '\"') {\n return undefined;\n }\n let current = start + 1;\n while (current < source.length) {\n if (source[current] === '\\\\') {\n current += 2;\n continue;\n }\n if (source[current] === '\"') {\n const raw = source.slice(start, current + 1);\n try {\n return { value: JSON.parse(raw) as string, end: current + 1 };\n } catch {\n return undefined;\n }\n }\n current += 1;\n }\n return undefined;\n}\n\n/**\n * Parse a static Rego reference with dotted or quoted bracket segments.\n *\n * @param source - Rego source\n * @param start - First identifier offset\n * @returns Parsed reference\n */\nfunction parseStaticRegoReference(source: string, start: number): StaticRegoReference | undefined {\n const first = readIdentifier(source, start);\n if (!first) {\n return undefined;\n }\n const segments = [first.identifier];\n let current = first.end;\n while (current < source.length) {\n const separator = skipWhitespace(source, current);\n if (source[separator] === '.') {\n const identifierStart = skipWhitespace(source, separator + 1);\n const identifier = readIdentifier(source, identifierStart);\n if (!identifier) {\n break;\n }\n segments.push(identifier.identifier);\n current = identifier.end;\n continue;\n }\n if (source[separator] === '[') {\n const stringStart = skipWhitespace(source, separator + 1);\n const value = readQuotedString(source, stringStart);\n if (!value) {\n break;\n }\n const closingBracket = skipWhitespace(source, value.end);\n if (source[closingBracket] !== ']') {\n break;\n }\n segments.push(value.value);\n current = closingBracket + 1;\n continue;\n }\n break;\n }\n return {\n source: source.slice(start, current),\n segments,\n end: current,\n };\n}\n\n/**\n * Read the package reference declared by Rego source.\n *\n * @param contents - Rego source\n * @returns Package reference, or undefined when no declaration is present\n */\nexport function parseRegoPackageReference(\n contents: string,\n): Omit<StaticRegoReference, 'end'> | undefined {\n const declaration = PACKAGE_DECLARATION_PATTERN.exec(contents);\n if (!declaration) {\n return undefined;\n }\n const reference = parseStaticRegoReference(contents, declaration.index + declaration[0].length);\n return reference ? { source: reference.source, segments: reference.segments } : undefined;\n}\n\n/**\n * Skip a string literal while scanning executable Rego source.\n *\n * @param source - Rego source\n * @param start - Opening delimiter offset\n * @returns Offset immediately after the string\n */\nfunction skipStringLiteral(source: string, start: number): number {\n const delimiter = source[start]!;\n let current = start + 1;\n while (current < source.length) {\n if (delimiter === '\"' && source[current] === '\\\\') {\n current += 2;\n continue;\n }\n if (source[current] === delimiter) {\n return current + 1;\n }\n current += 1;\n }\n return current;\n}\n\n/**\n * Find executable static `data` references outside imports.\n *\n * @param contents - Rego source\n * @returns References with one-based source lines\n */\nexport function findDirectDataReferences(\n contents: string,\n): { reference: StaticRegoReference; line: number }[] {\n const references: { reference: StaticRegoReference; line: number }[] = [];\n let current = 0;\n while (current < contents.length) {\n if (contents[current] === '#') {\n const newline = contents.indexOf('\\n', current);\n current = newline === -1 ? contents.length : newline + 1;\n continue;\n }\n if (contents[current] === '\"' || contents[current] === '`') {\n current = skipStringLiteral(contents, current);\n continue;\n }\n const identifier = readIdentifier(contents, current);\n if (!identifier) {\n current += 1;\n continue;\n }\n if (identifier.identifier !== 'data') {\n current = identifier.end;\n continue;\n }\n const reference = parseStaticRegoReference(contents, current);\n if (!reference || reference.segments.length === 1) {\n current = identifier.end;\n continue;\n }\n const lineStart = contents.lastIndexOf('\\n', current - 1) + 1;\n if (!/^\\s*import\\s+$/u.test(contents.slice(lineStart, current))) {\n references.push({\n reference,\n line: contents.slice(0, current).split('\\n').length,\n });\n }\n current = reference.end;\n }\n return references;\n}\n","import { findDirectDataReferences, parseRegoPackageReference } from './rego-reference.js';\n\n/** Shape of the policy bundle `manifest.json` accepted by Policy Engine. */\nexport interface PolicyBundleManifest {\n /** Roots of the bundle, such as `policy_engine/transcend`. */\n roots: string[];\n}\n\n/** In-memory Rego file used to validate a policy bundle. */\nexport interface PolicyBundleRegoFile {\n /** POSIX-style path relative to the policy bundle directory. */\n path: string;\n /** Rego source contents. */\n contents: string;\n}\n\n/** Validated publishable policy bundle contents. */\nexport interface ValidatedPolicyBundleContents {\n /** Parsed and validated bundle manifest. */\n manifest: PolicyBundleManifest;\n /** Publishable Rego paths, excluding local test modules. */\n publishableRegoPaths: string[];\n}\n\n/**\n * Returns whether a relative path is a publishable Rego policy file.\n *\n * OPA test files (`*_test.rego`) are local-only and excluded from uploads.\n *\n * @param relativePath - Path relative to the bundle directory\n * @returns Whether the file belongs in the uploaded archive\n */\nexport function isPublishableRegoFile(relativePath: string): boolean {\n return relativePath.endsWith('.rego') && !relativePath.endsWith('_test.rego');\n}\n\n/**\n * Parse and validate the Policy Engine bundle manifest.\n *\n * @param contents - Raw manifest contents, or undefined when absent\n * @returns Parsed manifest\n */\nexport function parsePolicyBundleManifest(contents: string | undefined): PolicyBundleManifest {\n if (contents === undefined) {\n throw new Error('Policy bundle directory must contain a manifest.json file.');\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(contents);\n } catch (error) {\n throw new Error(\n `manifest.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('manifest.json must contain a JSON object.');\n }\n\n const roots = (parsed as { roots?: unknown }).roots;\n if (!Array.isArray(roots) || roots.length === 0) {\n throw new Error(\n 'manifest.json must declare \"roots\" as a non-empty array of strings (e.g. {\"roots\":[\"policy_engine\"]}).',\n );\n }\n if (!roots.every((root) => typeof root === 'string' && root.length > 0)) {\n throw new Error('manifest.json \"roots\" must be an array of non-empty strings.');\n }\n if (\n !roots.every((root) =>\n root.split('/').every((segment: string) => /^[A-Za-z_][A-Za-z0-9_]*$/u.test(segment)),\n )\n ) {\n throw new Error(\n 'manifest.json \"roots\" must contain slash-separated Rego identifiers so Policy Engine can re-namespace them safely.',\n );\n }\n\n return { roots };\n}\n\n/**\n * Determine whether one document path starts with another.\n *\n * @param segments - Complete document path\n * @param prefix - Candidate root\n * @returns Whether the root covers the document path\n */\nfunction hasSegmentPrefix(segments: readonly string[], prefix: readonly string[]): boolean {\n return (\n segments.length >= prefix.length &&\n prefix.every((segment, index) => segment === segments[index])\n );\n}\n\n/**\n * Match the package syntax supported by Policy Engine activation.\n *\n * Bracketed segments remain supported below a declared dotted root.\n *\n * @param reference - Parsed package reference\n * @param root - Declared manifest root\n * @returns Whether activation can re-namespace the package\n */\nfunction rootCoversPackage(reference: { source: string }, root: readonly string[]): boolean {\n const dottedRoot = root.join('.');\n const suffix = reference.source.slice(dottedRoot.length);\n return (\n reference.source.startsWith(dottedRoot) &&\n (suffix === '' || suffix.startsWith('.') || /^\\s*\\[/u.test(suffix))\n );\n}\n\n/**\n * Determine whether `data.<root>` is referenced directly.\n *\n * @param segments - Parsed `data` reference segments\n * @param root - Declared manifest root\n * @returns Whether the reference targets the declared root\n */\nfunction referencesDeclaredRoot(segments: readonly string[], root: readonly string[]): boolean {\n return hasSegmentPrefix(segments.slice(1), root);\n}\n\n/**\n * Validate the manifest, publishable file requirement, and root coverage.\n *\n * This is the shared pure upload contract used by both `policy lint` and\n * `policy publish`.\n *\n * @param manifestContents - Raw manifest contents, or undefined when absent\n * @param regoFiles - All Rego files in the policy directory\n * @returns Validated manifest and publishable paths\n */\nexport function validatePolicyBundleContents(\n manifestContents: string | undefined,\n regoFiles: readonly PolicyBundleRegoFile[],\n): ValidatedPolicyBundleContents {\n const manifest = parsePolicyBundleManifest(manifestContents);\n const renderedRoots = manifest.roots.join(', ');\n const publishableFiles = regoFiles\n .filter(({ path }) => isPublishableRegoFile(path))\n .slice()\n .sort((left, right) => left.path.localeCompare(right.path));\n if (publishableFiles.length === 0) {\n throw new Error('Policy bundle directory must contain at least one .rego policy file.');\n }\n\n const rootPrefixes = manifest.roots.map((root) => root.split('/'));\n const uncovered = publishableFiles.flatMap(({ path, contents }) => {\n const packageReference = parseRegoPackageReference(contents);\n if (\n !packageReference ||\n rootPrefixes.some((prefix) => rootCoversPackage(packageReference, prefix))\n ) {\n return [];\n }\n return [\n ` - ${path} (package ${packageReference.source}) is not covered by roots [${renderedRoots}]`,\n ];\n });\n if (uncovered.length > 0) {\n throw new Error(\n [\n 'manifest.json \"roots\" do not cover all Rego packages in the bundle; ' +\n 'uncovered packages will fail-closed at decide time. Either broaden \"roots\" or move the policy under a covered package:',\n ...uncovered,\n ].join('\\n'),\n );\n }\n\n const unsupportedReferences = publishableFiles.flatMap(({ path, contents }) =>\n findDirectDataReferences(contents)\n .filter(({ reference }) =>\n rootPrefixes.some((prefix) => referencesDeclaredRoot(reference.segments, prefix)),\n )\n .map(\n ({ reference, line }) =>\n ` - ${path}:${line} references ${reference.source}; import that package and use its local name`,\n ),\n );\n if (unsupportedReferences.length > 0) {\n throw new Error(\n [\n 'Publishable Rego must not reference its declared bundle roots directly because Policy Engine re-namespaces package imports during activation:',\n ...unsupportedReferences,\n ].join('\\n'),\n );\n }\n\n return {\n manifest,\n publishableRegoPaths: publishableFiles.map(({ path }) => path),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"semver";const t=`0.39.0`,n=`https://www.openpolicyagent.org/docs#1-download-opa`,r=`https://www.openpolicyagent.org/projects/regal#installing-regal`,i=`OPA 1.x is required but \`opa\` was not found on PATH. Install or upgrade it using the official instructions: ${n}`,a=`The Open Policy Agent CLI (\`opa\`) is required but was not found on PATH. Install it using the official instructions: ${n}`,o=`Regal is required but \`regal\` was not found on PATH. Install or upgrade it using the official instructions: ${r}`;function s(t){let n=t.match(/^\s*Version:\s+v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\s*$/imu);if(!(!n||!e.valid(n[1])))return{version:n[1],major:e.major(n[1])}}function c(e){let t=s(e);if(t?.major!==1)return`OPA 1.x is required${t?`; found ${t.version}`:`; unable to parse the installed version`}. Install or upgrade it using the official instructions: ${n}`}function l(t,n=`0.30.0`,i=`OPA 1 support`){let a=s(t);if(!(a&&e.gte(a.version,n)))return`Regal ${n} or newer is required for ${i}${a?`; found ${a.version}`:`; unable to parse the installed version`}. Install or upgrade it using the official instructions: ${r}`}export{r as a,c,i,l,a as n,o,n as r,s,t};
|
|
2
|
+
//# sourceMappingURL=policy-runtime-BMKa-Upy.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-runtime-BMKa-Upy.mjs","names":[],"sources":["../src/lib/policy/policy-runtime.ts"],"sourcesContent":["import semver from 'semver';\n\n/** Supported local OPA major version. */\nexport const SUPPORTED_OPA_MAJOR_VERSION = 1;\n\n/** Oldest Regal release with first-class OPA 1.0 support. */\nexport const MINIMUM_REGAL_VERSION = '0.30.0';\n\n/** Oldest Regal release containing OPA 1.13.1 capabilities. */\nexport const MINIMUM_POLICY_STARTER_REGAL_VERSION = '0.39.0';\n\n/** Official OPA installation instructions. */\nexport const OPA_INSTALL_URL = 'https://www.openpolicyagent.org/docs#1-download-opa';\n\n/** Official Regal installation instructions. */\nexport const REGAL_INSTALL_URL = 'https://www.openpolicyagent.org/projects/regal#installing-regal';\n\n/** Missing OPA guidance shared by policy commands. */\nexport const OPA_MISSING_MESSAGE =\n 'OPA 1.x is required but `opa` was not found on PATH. ' +\n `Install or upgrade it using the official instructions: ${OPA_INSTALL_URL}`;\n\n/** Missing OPA guidance for commands that support multiple OPA releases. */\nexport const OPA_CLI_MISSING_MESSAGE =\n 'The Open Policy Agent CLI (`opa`) is required but was not found on PATH. ' +\n `Install it using the official instructions: ${OPA_INSTALL_URL}`;\n\n/** Missing Regal guidance for policy verification. */\nexport const REGAL_MISSING_MESSAGE =\n 'Regal is required but `regal` was not found on PATH. ' +\n `Install or upgrade it using the official instructions: ${REGAL_INSTALL_URL}`;\n\n/** Parsed policy tool version. */\nexport interface PolicyToolVersion {\n /** Complete semantic version reported by the tool. */\n version: string;\n /** Semantic major version. */\n major: number;\n}\n\n/**\n * Parse the version field from OPA or Regal version output.\n *\n * Both tools emit a `Version:` line and may prefix the value with `v`.\n *\n * @param output - Captured version output\n * @returns Parsed semantic version\n */\nexport function parsePolicyToolVersion(output: string): PolicyToolVersion | undefined {\n const match = output.match(\n /^\\s*Version:\\s+v?(\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)\\s*$/imu,\n );\n if (!match || !semver.valid(match[1])) {\n return undefined;\n }\n return {\n version: match[1],\n major: semver.major(match[1]),\n };\n}\n\n/**\n * Explain why an OPA version cannot run policy verification.\n *\n * @param output - Captured `opa version` output\n * @returns Requirement error, or undefined for supported OPA\n */\nexport function unsupportedOpaVersionMessage(output: string): string | undefined {\n const runtime = parsePolicyToolVersion(output);\n if (runtime?.major === SUPPORTED_OPA_MAJOR_VERSION) {\n return undefined;\n }\n const found = runtime ? `; found ${runtime.version}` : '; unable to parse the installed version';\n return (\n `OPA ${SUPPORTED_OPA_MAJOR_VERSION}.x is required${found}. ` +\n `Install or upgrade it using the official instructions: ${OPA_INSTALL_URL}`\n );\n}\n\n/**\n * Explain why a Regal version cannot run OPA 1 policy verification.\n *\n * @param output - Captured `regal version` output\n * @param minimumVersion - Oldest accepted Regal release\n * @param compatibilityTarget - Capability requiring the minimum version\n * @returns Requirement error, or undefined for supported Regal\n */\nexport function unsupportedRegalVersionMessage(\n output: string,\n minimumVersion: string = MINIMUM_REGAL_VERSION,\n compatibilityTarget = 'OPA 1 support',\n): string | undefined {\n const runtime = parsePolicyToolVersion(output);\n if (runtime && semver.gte(runtime.version, minimumVersion)) {\n return undefined;\n }\n const found = runtime ? `; found ${runtime.version}` : '; unable to parse the installed version';\n return (\n `Regal ${minimumVersion} or newer is required for ${compatibilityTarget}${found}. ` +\n `Install or upgrade it using the official instructions: ${REGAL_INSTALL_URL}`\n );\n}\n"],"mappings":"sBAMA,MAGa,EAAuC,SAGvC,EAAkB,sDAGlB,EAAoB,kEAGpB,EACX,iHAC0D,IAG/C,EACX,0HAC+C,IAGpC,EACX,iHAC0D,IAkB5D,SAAgB,EAAuB,EAA+C,CACpF,IAAM,EAAQ,EAAO,MACnB,mFACD,CACG,MAAC,GAAS,CAAC,EAAO,MAAM,EAAM,GAAG,EAGrC,MAAO,CACL,QAAS,EAAM,GACf,MAAO,EAAO,MAAM,EAAM,GAAG,CAC9B,CASH,SAAgB,EAA6B,EAAoC,CAC/E,IAAM,EAAU,EAAuB,EAAO,CAC1C,MAAS,QAAA,EAIb,MACE,sBAFY,EAAU,WAAW,EAAQ,UAAY,0CAEI,2DACC,IAY9D,SAAgB,EACd,EACA,EAAyB,SACzB,EAAsB,gBACF,CACpB,IAAM,EAAU,EAAuB,EAAO,CAC1C,QAAW,EAAO,IAAI,EAAQ,QAAS,EAAe,EAI1D,MACE,SAAS,EAAe,4BAA4B,IAFxC,EAAU,WAAW,EAAQ,UAAY,0CAE2B,2DACtB"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
let e=!1;function t(t){e=t}function n(){return e}var r=class extends Error{constructor(e,t){super(e,{cause:t?.cause}),this.name=`PolicyEngineCliError`}};function i(e){if(!n())return e.message;let t=[e.message,``,`Debug details:`],r=e.cause;return r instanceof Error?t.push(r.stack??r.message):r===void 0?t.push(`No underlying cause was recorded.`):t.push(String(r)),t.join(`
|
|
2
2
|
`)}function a(e){if(e instanceof r)return i(e)}function o(e){return a(e)||(e instanceof Error?n()?e.stack??String(e):e.message:String(e))}export{o as n,t as r,r as t};
|
|
3
|
-
//# sourceMappingURL=policyEngineCliError-
|
|
3
|
+
//# sourceMappingURL=policyEngineCliError-DY8V-qkK.mjs.map
|
package/dist/{policyEngineCliError-BnBghLd1.mjs.map → policyEngineCliError-DY8V-qkK.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policyEngineCliError-
|
|
1
|
+
{"version":3,"file":"policyEngineCliError-DY8V-qkK.mjs","names":[],"sources":["../src/commands/policy/helpers/policyEngineCliError.ts"],"sourcesContent":["/** Whether policy commands should include technical error details in output. */\nlet policyEngineCliDebugEnabled = false;\n\n/**\n * Enables or disables technical Policy Engine CLI error output for the current command run.\n *\n * @param enabled - When true, API causes and stack traces are included in failures\n */\nexport function setPolicyEngineCliDebug(enabled: boolean): void {\n policyEngineCliDebugEnabled = enabled;\n}\n\n/**\n * Returns true when `--debug` was passed to a policy command.\n *\n * @returns Whether debug output is enabled\n */\nexport function isPolicyEngineCliDebugEnabled(): boolean {\n return policyEngineCliDebugEnabled;\n}\n\n/**\n * User-facing Policy Engine CLI error without a stack trace by default.\n */\nexport class PolicyEngineCliError extends Error {\n /**\n * Creates a policy CLI error suitable for end-user output.\n *\n * @param message - User-readable error text\n * @param options - Optional underlying failure\n */\n constructor(\n message: string,\n options?: {\n /** Original failure, typically a got HTTPError */\n cause?: unknown;\n },\n ) {\n super(message, { cause: options?.cause });\n this.name = 'PolicyEngineCliError';\n }\n}\n\n/**\n * Formats a Policy Engine CLI error for terminal output.\n *\n * @param error - Thrown policy CLI error\n * @returns Message only by default; technical details when debug mode is enabled\n */\nexport function formatPolicyEngineCliErrorForTerminal(error: PolicyEngineCliError): string {\n if (!isPolicyEngineCliDebugEnabled()) {\n return error.message;\n }\n\n const parts = [error.message, '', 'Debug details:'];\n const cause = error.cause;\n\n if (cause instanceof Error) {\n parts.push(cause.stack ?? cause.message);\n } else if (cause !== undefined) {\n parts.push(String(cause));\n } else {\n parts.push('No underlying cause was recorded.');\n }\n\n return parts.join('\\n');\n}\n\n/**\n * Formats thrown values for Stricli, suppressing stacks for policy CLI errors unless debug is enabled.\n *\n * @param exc - Thrown value from a command\n * @returns Terminal-safe error text\n */\nexport function formatPolicyEngineCliException(exc: unknown): string | undefined {\n if (exc instanceof PolicyEngineCliError) {\n return formatPolicyEngineCliErrorForTerminal(exc);\n }\n\n return undefined;\n}\n\n/**\n * Formats any thrown command value for terminal output.\n *\n * `PolicyEngineCliError` values are formatted by `formatPolicyEngineCliException`.\n * Other errors (e.g. bundle-not-found, missing OPA binary, local OPA failures)\n * are plain `Error`s -- return only their message by default so operators don't\n * see a minified stack trace, and surface the stack only when a policy command\n * opted in via `--debug`.\n *\n * @param exc - Thrown value from a command\n * @returns Terminal-safe error text\n */\nexport function formatCliException(exc: unknown): string {\n const policyMessage = formatPolicyEngineCliException(exc);\n if (policyMessage) {\n return policyMessage;\n }\n\n if (exc instanceof Error) {\n return isPolicyEngineCliDebugEnabled() ? (exc.stack ?? String(exc)) : exc.message;\n }\n\n return String(exc);\n}\n"],"mappings":"AACA,IAAI,EAA8B,GAOlC,SAAgB,EAAwB,EAAwB,CAC9D,EAA8B,EAQhC,SAAgB,GAAyC,CACvD,OAAO,EAMT,IAAa,EAAb,cAA0C,KAAM,CAO9C,YACE,EACA,EAIA,CACA,MAAM,EAAS,CAAE,MAAO,GAAS,MAAO,CAAC,CACzC,KAAK,KAAO,yBAUhB,SAAgB,EAAsC,EAAqC,CACzF,GAAI,CAAC,GAA+B,CAClC,OAAO,EAAM,QAGf,IAAM,EAAQ,CAAC,EAAM,QAAS,GAAI,iBAAiB,CAC7C,EAAQ,EAAM,MAUpB,OARI,aAAiB,MACnB,EAAM,KAAK,EAAM,OAAS,EAAM,QAAQ,CAC/B,IAAU,IAAA,GAGnB,EAAM,KAAK,oCAAoC,CAF/C,EAAM,KAAK,OAAO,EAAM,CAAC,CAKpB,EAAM,KAAK;EAAK,CASzB,SAAgB,EAA+B,EAAkC,CAC/E,GAAI,aAAe,EACjB,OAAO,EAAsC,EAAI,CAkBrD,SAAgB,EAAmB,EAAsB,CAUvD,OATsB,EAA+B,EACjD,GAIA,aAAe,MACV,GAA+B,CAAI,EAAI,OAAS,OAAO,EAAI,CAAI,EAAI,QAGrE,OAAO,EAAI"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{t as e}from"./policyEngineCliError-
|
|
1
|
+
import{t as e}from"./policyEngineCliError-DY8V-qkK.mjs";import t from"got";const n=5120,r=51200;function i(e,n){let r=e.replace(/\/$/,``);if(/(^|\/)v1$/i.test(r))throw Error(`--transcend-url must not include a trailing "/v1" (the CLI appends it automatically). Got "${e}"; use "${r.replace(/\/v1$/i,``)}" instead.`);return t.extend({prefixUrl:r,headers:{Authorization:`Bearer ${n}`,accept:`application/json`}})}function a(e){if(typeof e==`string`)try{return JSON.parse(e).message}catch{return e.length>0?e:void 0}if(e&&typeof e==`object`&&`message`in e){let t=e.message;if(typeof t==`string`&&t.length>0)return t}}function o(e,t){if(!e)return;let n=e[t]??e[t.toLowerCase()];return Array.isArray(n)?n[0]:n}function s(e,t){if(e)return e;let n=o(t,`retry-after`),r=o(t,`x-ratelimit-reset`),i=`Rate limit exceeded (429 Too Many Requests).
|
|
2
2
|
|
|
3
3
|
Fix:
|
|
4
|
-
- Wait and retry the command`;return n?
|
|
4
|
+
- Wait and retry the command`;return n?i+=`\n- Retry after ${n} second(s)`:r&&(i+=`\n- Retry after ${r}`),i}function c(e,t,n){switch(e){case 401:return`Authentication failed (401 Unauthorized).
|
|
5
5
|
|
|
6
6
|
Your Transcend API key is missing, invalid, or does not have permission for this command.
|
|
7
7
|
|
|
@@ -22,12 +22,12 @@ Uploaded bundles must be at most 5 KiB compressed and 50 KiB decompressed gzip t
|
|
|
22
22
|
|
|
23
23
|
Fix:
|
|
24
24
|
- Remove unnecessary files from the bundle directory before publishing
|
|
25
|
-
- Ensure the compiled .tar.gz stays within the upload limits`;case 429:return
|
|
25
|
+
- Ensure the compiled .tar.gz stays within the upload limits`;case 429:return s(t,n);default:return e>=500?`Transcend server error (${e}). Try again in a few moments. If the problem persists, contact Transcend support.`:t??`Request failed with status code ${e}.`}}function l(e){if(!(e instanceof Error))return!1;let t=e.code;if(t===`ECONNREFUSED`||t===`ENOTFOUND`||t===`ETIMEDOUT`||t===`ECONNRESET`)return!0;let n=e.message.toLowerCase();return n.includes(`network`)||n.includes(`timeout`)||n.includes(`econnrefused`)||n.includes(`enotfound`)||n.includes(`etimedout`)}function u(e){if(l(e))return`Connection to Transcend failed.
|
|
26
26
|
|
|
27
27
|
The Policy Engine API could not be reached.
|
|
28
28
|
|
|
29
29
|
Fix:
|
|
30
30
|
- Check your network connection
|
|
31
31
|
- Confirm --transcend-url points at the correct environment
|
|
32
|
-
- Retry the command in a few moments`;if(e&&typeof e==`object`&&`response`in e){let t=e.response,n=t?.statusCode,
|
|
33
|
-
//# sourceMappingURL=printResult-
|
|
32
|
+
- Retry the command in a few moments`;if(e&&typeof e==`object`&&`response`in e){let t=e.response,n=t?.statusCode,r=a(t?.body);if(n)return c(n,r,t?.headers);if(r)return r}return e instanceof Error?e.message:String(e)}function d(t){throw new e(u(t),{cause:t})}async function f(e){try{return await e}catch(e){d(e)}}function p(e,t){if(t.json){e.write(`${JSON.stringify(t.data,null,2)}\n`);return}t.renderTable&&e.write(`${t.renderTable()}\n`)}export{n as a,i,f as n,r as o,d as r,p as t};
|
|
33
|
+
//# sourceMappingURL=printResult-CHe3nRN4.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printResult-CHe3nRN4.mjs","names":[],"sources":["../src/commands/policy/constants.ts","../src/commands/policy/helpers/buildPolicyEngineClient.ts","../src/commands/policy/helpers/formatPolicyEngineRequestError.ts","../src/commands/policy/helpers/printResult.ts"],"sourcesContent":["/** Maximum compressed policy bundle upload size in bytes (5 KiB). */\nexport const MAX_BUNDLE_COMPRESSED_BYTES = 5120;\n\n/** Maximum decompressed policy bundle size enforced by the server (50 KiB). */\nexport const MAX_BUNDLE_DECOMPRESSED_BYTES = 51200;\n\n/** Placeholder for nullable API fields in table output. */\nexport const EMPTY_CELL = '-';\n","import got, { type Got } from 'got';\n\n/**\n * Creates a got client for Policy Engine REST endpoints on the monolith.\n *\n * The CLI appends `v1/...` paths to this base URL, so callers must NOT include\n * a trailing `/v1` (that would produce `/v1/v1/...` and an opaque `400`). We\n * detect and reject that mistake with a clear hint.\n *\n * @param transcendUrl - Transcend API base URL (without `/v1`)\n * @param auth - Transcend API key\n * @returns Configured got instance\n */\nexport function buildPolicyEngineClient(transcendUrl: string, auth: string): Got {\n const normalized = transcendUrl.replace(/\\/$/, '');\n if (/(^|\\/)v1$/i.test(normalized)) {\n throw new Error(\n `--transcend-url must not include a trailing \"/v1\" (the CLI appends it automatically). ` +\n `Got \"${transcendUrl}\"; use \"${normalized.replace(/\\/v1$/i, '')}\" instead.`,\n );\n }\n return got.extend({\n prefixUrl: normalized,\n headers: {\n Authorization: `Bearer ${auth}`,\n accept: 'application/json',\n },\n });\n}\n","import { PolicyEngineCliError } from './policyEngineCliError.js';\n\n/** Parsed JSON error body from a Policy Engine API response. */\ninterface PolicyEngineErrorBody {\n /** Human-readable error message */\n message?: string;\n}\n\n/** HTTP response metadata on a got HTTPError. */\ninterface PolicyEngineHttpResponse {\n /** HTTP status code */\n statusCode?: number;\n /** Response body (JSON or raw text) */\n body?: unknown;\n /** Response headers */\n headers?: Record<string, string | string[] | undefined>;\n}\n\n/** Shape of a got HTTPError with response metadata. */\ninterface PolicyEngineHttpError {\n /** HTTP response metadata */\n response?: PolicyEngineHttpResponse;\n}\n\nconst AUTH_ERROR_MESSAGE = `Authentication failed (401 Unauthorized).\n\nYour Transcend API key is missing, invalid, or does not have permission for this command.\n\nFix:\n- Set a valid API key: export TRANSCEND_API_KEY=<your-key>\n or pass --auth=<your-key>\n- Ensure the key has the required Policy Engine scopes (e.g. View/Manage/Activate Policy)\n- Confirm you are pointing at the correct environment (--transcend-url)`;\n\nconst NOT_FOUND_MESSAGE = `Resource not found (404 Not Found).\n\nThe requested policy bundle or version does not exist.\n\nFix:\n- Check the --bundle-name value\n- Run \\`transcend policy bundles\\` to see available bundles\n- Run \\`transcend policy versions --bundle-name=<name>\\` to see available versions`;\n\nconst PAYLOAD_TOO_LARGE_MESSAGE = `Policy bundle upload is too large (413 Payload Too Large).\n\nUploaded bundles must be at most 5 KiB compressed and 50 KiB decompressed gzip tarballs containing only manifest.json and .rego files.\n\nFix:\n- Remove unnecessary files from the bundle directory before publishing\n- Ensure the compiled .tar.gz stays within the upload limits`;\n\nconst NETWORK_ERROR_MESSAGE = `Connection to Transcend failed.\n\nThe Policy Engine API could not be reached.\n\nFix:\n- Check your network connection\n- Confirm --transcend-url points at the correct environment\n- Retry the command in a few moments`;\n\n/**\n * Extracts a human-readable message from a Policy Engine API error body.\n *\n * @param body - Raw or parsed response body\n * @returns API message when present\n */\nfunction extractApiMessage(body: unknown): string | undefined {\n if (typeof body === 'string') {\n try {\n const parsed = JSON.parse(body) as PolicyEngineErrorBody;\n return parsed.message;\n } catch {\n return body.length > 0 ? body : undefined;\n }\n }\n\n if (body && typeof body === 'object' && 'message' in body) {\n const message = (body as PolicyEngineErrorBody).message;\n if (typeof message === 'string' && message.length > 0) {\n return message;\n }\n }\n\n return undefined;\n}\n\n/**\n * Reads a single response header value.\n *\n * @param headers - Response headers\n * @param name - Header name\n * @returns Header value when present\n */\nfunction readResponseHeader(\n headers: Record<string, string | string[] | undefined> | undefined,\n name: string,\n): string | undefined {\n if (!headers) {\n return undefined;\n }\n\n const value = headers[name] ?? headers[name.toLowerCase()];\n if (Array.isArray(value)) {\n return value[0];\n }\n\n return value;\n}\n\n/**\n * Builds a rate-limit error message using response headers when available.\n *\n * @param apiMessage - Message from the response body, when present\n * @param headers - Response headers\n * @returns User-readable rate-limit text\n */\nfunction formatRateLimitMessage(\n apiMessage: string | undefined,\n headers: Record<string, string | string[] | undefined> | undefined,\n): string {\n if (apiMessage) {\n return apiMessage;\n }\n\n const retryAfter = readResponseHeader(headers, 'retry-after');\n const resetAt = readResponseHeader(headers, 'x-ratelimit-reset');\n\n let message = `Rate limit exceeded (429 Too Many Requests).\n\nFix:\n- Wait and retry the command`;\n\n if (retryAfter) {\n message += `\\n- Retry after ${retryAfter} second(s)`;\n } else if (resetAt) {\n message += `\\n- Retry after ${resetAt}`;\n }\n\n return message;\n}\n\n/**\n * Maps common HTTP status codes to actionable CLI messages.\n *\n * @param statusCode - HTTP status code\n * @param apiMessage - Message from the API response body, when present\n * @param headers - Response headers\n * @returns User-readable error text\n */\nfunction formatHttpStatusError(\n statusCode: number,\n apiMessage?: string,\n headers?: Record<string, string | string[] | undefined>,\n): string {\n switch (statusCode) {\n case 401:\n return AUTH_ERROR_MESSAGE;\n case 403:\n return (\n apiMessage ??\n 'Access was denied (403 Forbidden). If this persists, contact your Transcend admin.'\n );\n case 404:\n return NOT_FOUND_MESSAGE;\n case 400:\n return apiMessage ?? 'The request was invalid. Check your command flags and try again.';\n case 409:\n return apiMessage ?? 'The request conflicted with the current policy bundle state.';\n case 413:\n return apiMessage ?? PAYLOAD_TOO_LARGE_MESSAGE;\n case 429:\n return formatRateLimitMessage(apiMessage, headers);\n default:\n if (statusCode >= 500) {\n return `Transcend server error (${statusCode}). Try again in a few moments. If the problem persists, contact Transcend support.`;\n }\n return apiMessage ?? `Request failed with status code ${statusCode}.`;\n }\n}\n\n/**\n * Returns true when the error looks like a network or timeout failure.\n *\n * @param error - Thrown error\n * @returns Whether the error is likely a connectivity issue\n */\nfunction isNetworkError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n const code = (error as NodeJS.ErrnoException).code;\n if (\n code === 'ECONNREFUSED' ||\n code === 'ENOTFOUND' ||\n code === 'ETIMEDOUT' ||\n code === 'ECONNRESET'\n ) {\n return true;\n }\n\n const message = error.message.toLowerCase();\n return (\n message.includes('network') ||\n message.includes('timeout') ||\n message.includes('econnrefused') ||\n message.includes('enotfound') ||\n message.includes('etimedout')\n );\n}\n\n/**\n * Extracts a useful error message from a failed Policy Engine HTTP request.\n *\n * @param error - The thrown error, typically a got `HTTPError`\n * @returns A message suitable for CLI output\n */\nexport function formatPolicyEngineRequestError(error: unknown): string {\n if (isNetworkError(error)) {\n return NETWORK_ERROR_MESSAGE;\n }\n\n if (error && typeof error === 'object' && 'response' in error) {\n const response = (error as PolicyEngineHttpError).response;\n const statusCode = response?.statusCode;\n const apiMessage = extractApiMessage(response?.body);\n\n if (statusCode) {\n return formatHttpStatusError(statusCode, apiMessage, response?.headers);\n }\n\n if (apiMessage) {\n return apiMessage;\n }\n }\n\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Rethrows a Policy Engine request failure with a user-readable message.\n *\n * @param error - The thrown error, typically a got `HTTPError`\n */\nexport function throwPolicyEngineRequestError(error: unknown): never {\n throw new PolicyEngineCliError(formatPolicyEngineRequestError(error), { cause: error });\n}\n\n/**\n * Awaits a Policy Engine HTTP request and maps failures to user-readable errors.\n *\n * @param request - Promise returned by a got client call (e.g. `.json()`)\n * @returns Parsed response body\n */\nexport async function policyEngineRequest<T>(request: Promise<T>): Promise<T> {\n try {\n return await request;\n } catch (error) {\n throwPolicyEngineRequestError(error);\n }\n}\n","/** Options for printing CLI command output. */\nexport interface PrintResultOptions {\n /** When true, print raw JSON */\n json: boolean;\n /** JSON-serializable payload */\n data: unknown;\n /** Table renderer used when json is false */\n renderTable?: () => string;\n}\n\n/**\n * Prints JSON or a human-readable table to stdout.\n *\n * @param stdout - Process stdout stream\n * @param options - Output options\n */\nexport function printResult(stdout: NodeJS.WriteStream, options: PrintResultOptions): void {\n if (options.json) {\n stdout.write(`${JSON.stringify(options.data, null, 2)}\\n`);\n return;\n }\n\n if (options.renderTable) {\n stdout.write(`${options.renderTable()}\\n`);\n }\n}\n"],"mappings":"2EACA,MAAa,EAA8B,KAG9B,EAAgC,MCS7C,SAAgB,EAAwB,EAAsB,EAAmB,CAC/E,IAAM,EAAa,EAAa,QAAQ,MAAO,GAAG,CAClD,GAAI,aAAa,KAAK,EAAW,CAC/B,MAAU,MACR,8FACU,EAAa,UAAU,EAAW,QAAQ,SAAU,GAAG,CAAC,YACnE,CAEH,OAAO,EAAI,OAAO,CAChB,UAAW,EACX,QAAS,CACP,cAAe,UAAU,IACzB,OAAQ,mBACT,CACF,CAAC,CCuCJ,SAAS,EAAkB,EAAmC,CAC5D,GAAI,OAAO,GAAS,SAClB,GAAI,CAEF,OADe,KAAK,MAAM,EACb,CAAC,aACR,CACN,OAAO,EAAK,OAAS,EAAI,EAAO,IAAA,GAIpC,GAAI,GAAQ,OAAO,GAAS,UAAY,YAAa,EAAM,CACzD,IAAM,EAAW,EAA+B,QAChD,GAAI,OAAO,GAAY,UAAY,EAAQ,OAAS,EAClD,OAAO,GAcb,SAAS,EACP,EACA,EACoB,CACpB,GAAI,CAAC,EACH,OAGF,IAAM,EAAQ,EAAQ,IAAS,EAAQ,EAAK,aAAa,EAKzD,OAJI,MAAM,QAAQ,EAAM,CACf,EAAM,GAGR,EAUT,SAAS,EACP,EACA,EACQ,CACR,GAAI,EACF,OAAO,EAGT,IAAM,EAAa,EAAmB,EAAS,cAAc,CACvD,EAAU,EAAmB,EAAS,oBAAoB,CAE5D,EAAU;;;8BAWd,OANI,EACF,GAAW,mBAAmB,EAAW,YAChC,IACT,GAAW,mBAAmB,KAGzB,EAWT,SAAS,EACP,EACA,EACA,EACQ,CACR,OAAQ,EAAR,CACE,IAAK,KACH,MAAO;;;;;;;;yEACT,IAAK,KACH,OACE,GACA,qFAEJ,IAAK,KACH,MAAO;;;;;;;oFACT,IAAK,KACH,OAAO,GAAc,mEACvB,IAAK,KACH,OAAO,GAAc,+DACvB,IAAK,KACH,OAAO,GAAc;;;;;;8DACvB,IAAK,KACH,OAAO,EAAuB,EAAY,EAAQ,CACpD,QAIE,OAHI,GAAc,IACT,2BAA2B,EAAW,oFAExC,GAAc,mCAAmC,EAAW,IAUzE,SAAS,EAAe,EAAyB,CAC/C,GAAI,EAAE,aAAiB,OACrB,MAAO,GAGT,IAAM,EAAQ,EAAgC,KAC9C,GACE,IAAS,gBACT,IAAS,aACT,IAAS,aACT,IAAS,aAET,MAAO,GAGT,IAAM,EAAU,EAAM,QAAQ,aAAa,CAC3C,OACE,EAAQ,SAAS,UAAU,EAC3B,EAAQ,SAAS,UAAU,EAC3B,EAAQ,SAAS,eAAe,EAChC,EAAQ,SAAS,YAAY,EAC7B,EAAQ,SAAS,YAAY,CAUjC,SAAgB,EAA+B,EAAwB,CACrE,GAAI,EAAe,EAAM,CACvB,MAAO;;;;;;;sCAGT,GAAI,GAAS,OAAO,GAAU,UAAY,aAAc,EAAO,CAC7D,IAAM,EAAY,EAAgC,SAC5C,EAAa,GAAU,WACvB,EAAa,EAAkB,GAAU,KAAK,CAEpD,GAAI,EACF,OAAO,EAAsB,EAAY,EAAY,GAAU,QAAQ,CAGzE,GAAI,EACF,OAAO,EAIX,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAQ/D,SAAgB,EAA8B,EAAuB,CACnE,MAAM,IAAI,EAAqB,EAA+B,EAAM,CAAE,CAAE,MAAO,EAAO,CAAC,CASzF,eAAsB,EAAuB,EAAiC,CAC5E,GAAI,CACF,OAAO,MAAM,QACN,EAAO,CACd,EAA8B,EAAM,EClPxC,SAAgB,EAAY,EAA4B,EAAmC,CACzF,GAAI,EAAQ,KAAM,CAChB,EAAO,MAAM,GAAG,KAAK,UAAU,EAAQ,KAAM,KAAM,EAAE,CAAC,IAAI,CAC1D,OAGE,EAAQ,aACV,EAAO,MAAM,GAAG,EAAQ,aAAa,CAAC,IAAI"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{i as e}from"./prompts-ClBXdELk.mjs";import{t}from"./path-safety-D5Qwl40b.mjs";import{basename as n,dirname as r,join as i,relative as a,resolve as o,sep as s}from"node:path";function c(e,t){try{return e.fs.lstatSync(t),!0}catch(e){if(e.code===`ENOENT`)return!1;throw e}}function l(e,t){if(!c(e,t))return{kind:`absent`,path:t};let n=e.fs.lstatSync(t);if(n.isSymbolicLink())return{kind:`link`,path:t,target:e.fs.readlinkSync(t)};if(!n.isFile())throw Error(`Cannot transactionally replace non-file path: ${t}`);return{kind:`file`,path:t,contents:e.fs.readFileSync(t,`utf8`),mode:n.mode}}function u(e,t,a,o){e.fs.mkdirSync(r(t),{recursive:!0});let s=i(r(t),`.${n(t)}.${e.process.pid}.${Date.now()}.tmp`);try{e.fs.writeFileSync(s,a,o===void 0?void 0:{mode:o&511}),e.fs.renameSync(s,t)}finally{c(e,s)&&e.fs.rmSync(s,{force:!0})}}function d(e,t,a,o){e.fs.mkdirSync(r(t),{recursive:!0});let s=i(r(t),`.${n(t)}.${e.process.pid}.${Date.now()}.tmp`);try{e.fs.writeFileSync(s,a,o===void 0?void 0:{mode:o&511}),e.fs.linkSync(s,t)}finally{c(e,s)&&e.fs.rmSync(s,{force:!0})}}function f(e,t){if(t.kind===`absent`){c(e,t.path)&&e.fs.rmSync(t.path,{recursive:!0,force:!0});return}if(e.fs.mkdirSync(r(t.path),{recursive:!0}),t.kind===`link`){c(e,t.path)&&e.fs.rmSync(t.path,{recursive:!0,force:!0}),e.fs.symlinkSync(t.target,t.path,`dir`);return}c(e,t.path)&&!e.fs.lstatSync(t.path).isFile()&&e.fs.rmSync(t.path,{recursive:!0,force:!0}),u(e,t.path,t.contents,t.mode)}function p(e,t){let n=c(e,t.path);if(t.before===null){if(n)throw Error(`File appeared after preview: ${t.path}`);return}if(!n)throw Error(`File changed after preview: ${t.path}`);let r=e.fs.lstatSync(t.path);if(!r.isFile()||t.mode!==void 0&&r.mode!==t.mode||e.fs.readFileSync(t.path,`utf8`)!==t.before)throw Error(`File changed after preview: ${t.path}`);if(t.createOnly)throw Error(`Refusing to overwrite existing file: ${t.path}`)}function m(e,t){if(t.kind===`file`){p(e,t);return}if(c(e,t.path))throw Error(`Skill target appeared after preview: ${t.path}`)}function h(t,n){let r=e(t,n.path);if(r.length!==n.relativePaths.length||r.some((e,t)=>e!==n.relativePaths[t]))throw Error(`Directory changed after preview: ${n.path}`)}function g(e,t){let n=o(t.rootDirectory),i=new Set;for(let l of t.changes){let t=r(o(l.path));for(;;){let o=a(n,t);if(o===`..`||o.startsWith(`..${s}`)||(c(e,t)||i.add(t),t===n))break;t=r(t)}}return[...i].sort((e,t)=>t.split(s).length-e.split(s).length)}function _(e,t){let n=[];for(let r of t)if(c(e,r))try{e.fs.rmdirSync(r)}catch(e){e.code!==`ENOENT`&&n.push(`${r}: ${e.message}`)}return n}function v(e,n,a){try{e.fs.symlinkSync(n.target,n.path,`dir`)}catch(o){let s=o.code;if(![`EPERM`,`EACCES`,`ENOTSUP`,`UNKNOWN`].includes(s??``))throw o;n.fallbackFiles.forEach(o=>{let s=i(n.path,o.path);t(e,a,s),e.fs.mkdirSync(r(s),{recursive:!0}),e.fs.writeFileSync(s,o.contents)})}}async function y(e,n){for(let r of n.changes)t(e,n.rootDirectory,r.path),m(e,r);for(let r of n.directoryPreconditions??[])t(e,n.rootDirectory,r.path),h(e,r);let r=g(e,n),i=[];try{for(let r of n.changes)if(t(e,n.rootDirectory,r.path),m(e,r),r.kind===`file`){let t=l(e,r.path);r.before===null?d(e,r.path,r.after,r.mode):u(e,r.path,r.after,r.mode),i.push(t)}else i.push({kind:`absent`,path:r.path}),v(e,r,n.rootDirectory)}catch(t){let n=[];for(let t of i.reverse())try{f(e,t)}catch(e){n.push(`${t.path}: ${e.message}`)}throw n.push(..._(e,r)),n.length>0?Error(`${t.message}\nRollback also failed:\n${n.join(`
|
|
2
|
+
`)}`):t}}export{y as t};
|
|
3
|
+
//# sourceMappingURL=project-plan-apply-Dvndx455.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-plan-apply-Dvndx455.mjs","names":[],"sources":["../src/lib/scaffolding/project-plan-apply.ts"],"sourcesContent":["import { basename, dirname, join, relative, resolve, sep } from 'node:path';\n\nimport type { LocalContext } from '../../context.js';\nimport { assertPathPhysicallyContained } from './path-safety.js';\nimport { collectProjectRelativePaths } from './project-discovery.js';\nimport type {\n PlannedDirectoryPrecondition,\n PlannedChange,\n PlannedFileChange,\n PlannedLinkChange,\n ProjectPlan,\n} from './project-plan.js';\n\n/** Original state retained for rollback. */\ntype RollbackSnapshot =\n | {\n /** Snapshot kind. */\n kind: 'absent';\n /** Absolute path. */\n path: string;\n }\n | {\n /** Snapshot kind. */\n kind: 'file';\n /** Absolute path. */\n path: string;\n /** Original UTF-8 contents. */\n contents: string;\n /** Original mode. */\n mode: number;\n }\n | {\n /** Snapshot kind. */\n kind: 'link';\n /** Absolute path. */\n path: string;\n /** Original link target. */\n target: string;\n };\n\n/**\n * Check a path without following its final symbolic link.\n *\n * @param context - CLI context\n * @param path - Candidate path\n * @returns Whether any filesystem entry exists\n */\nfunction pathExists(context: LocalContext, path: string): boolean {\n try {\n context.fs.lstatSync(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return false;\n }\n throw error;\n }\n}\n\n/**\n * Read one path for rollback.\n *\n * @param context - CLI context\n * @param path - Absolute path\n * @returns Original state\n */\nfunction snapshotPath(context: LocalContext, path: string): RollbackSnapshot {\n if (!pathExists(context, path)) {\n return { kind: 'absent', path };\n }\n const stat = context.fs.lstatSync(path);\n if (stat.isSymbolicLink()) {\n return { kind: 'link', path, target: context.fs.readlinkSync(path) };\n }\n if (!stat.isFile()) {\n throw new Error(`Cannot transactionally replace non-file path: ${path}`);\n }\n return {\n kind: 'file',\n path,\n contents: context.fs.readFileSync(path, 'utf8'),\n mode: stat.mode,\n };\n}\n\n/**\n * Write a regular file through a temporary sibling and rename.\n *\n * @param context - CLI context\n * @param path - Destination\n * @param contents - Desired contents\n * @param mode - Optional mode to preserve\n */\nfunction writeAtomic(context: LocalContext, path: string, contents: string, mode?: number): void {\n context.fs.mkdirSync(dirname(path), { recursive: true });\n const temporaryPath = join(\n dirname(path),\n `.${basename(path)}.${context.process.pid}.${Date.now()}.tmp`,\n );\n try {\n context.fs.writeFileSync(\n temporaryPath,\n contents,\n mode === undefined ? undefined : { mode: mode & 0o777 },\n );\n context.fs.renameSync(temporaryPath, path);\n } finally {\n if (pathExists(context, temporaryPath)) {\n context.fs.rmSync(temporaryPath, { force: true });\n }\n }\n}\n\n/**\n * Create a file atomically without replacing a destination that appeared.\n *\n * @param context - CLI context\n * @param path - Destination path\n * @param contents - UTF-8 contents\n * @param mode - Optional file mode\n */\nfunction writeAtomicCreateOnly(\n context: LocalContext,\n path: string,\n contents: string,\n mode?: number,\n): void {\n context.fs.mkdirSync(dirname(path), { recursive: true });\n const temporaryPath = join(\n dirname(path),\n `.${basename(path)}.${context.process.pid}.${Date.now()}.tmp`,\n );\n try {\n context.fs.writeFileSync(\n temporaryPath,\n contents,\n mode === undefined ? undefined : { mode: mode & 0o777 },\n );\n context.fs.linkSync(temporaryPath, path);\n } finally {\n if (pathExists(context, temporaryPath)) {\n context.fs.rmSync(temporaryPath, { force: true });\n }\n }\n}\n\n/**\n * Restore one path.\n *\n * @param context - CLI context\n * @param snapshot - Original state\n */\nfunction restoreSnapshot(context: LocalContext, snapshot: RollbackSnapshot): void {\n if (snapshot.kind === 'absent') {\n if (pathExists(context, snapshot.path)) {\n context.fs.rmSync(snapshot.path, { recursive: true, force: true });\n }\n return;\n }\n context.fs.mkdirSync(dirname(snapshot.path), { recursive: true });\n if (snapshot.kind === 'link') {\n if (pathExists(context, snapshot.path)) {\n context.fs.rmSync(snapshot.path, { recursive: true, force: true });\n }\n context.fs.symlinkSync(snapshot.target, snapshot.path, 'dir');\n return;\n }\n if (pathExists(context, snapshot.path) && !context.fs.lstatSync(snapshot.path).isFile()) {\n context.fs.rmSync(snapshot.path, { recursive: true, force: true });\n }\n writeAtomic(context, snapshot.path, snapshot.contents, snapshot.mode);\n}\n\n/**\n * Verify a planned regular-file precondition.\n *\n * @param context - CLI context\n * @param change - Planned file\n */\nfunction preflightFile(context: LocalContext, change: PlannedFileChange): void {\n const exists = pathExists(context, change.path);\n if (change.before === null) {\n if (exists) {\n throw new Error(`File appeared after preview: ${change.path}`);\n }\n return;\n }\n if (!exists) {\n throw new Error(`File changed after preview: ${change.path}`);\n }\n const stat = context.fs.lstatSync(change.path);\n if (\n !stat.isFile() ||\n (change.mode !== undefined && stat.mode !== change.mode) ||\n context.fs.readFileSync(change.path, 'utf8') !== change.before\n ) {\n throw new Error(`File changed after preview: ${change.path}`);\n }\n if (change.createOnly) {\n throw new Error(`Refusing to overwrite existing file: ${change.path}`);\n }\n}\n\n/**\n * Verify one planned mutation still matches preview assumptions.\n *\n * @param context - CLI context\n * @param change - Planned mutation\n */\nfunction preflightChange(context: LocalContext, change: PlannedChange): void {\n if (change.kind === 'file') {\n preflightFile(context, change);\n return;\n }\n if (pathExists(context, change.path)) {\n throw new Error(`Skill target appeared after preview: ${change.path}`);\n }\n}\n\n/**\n * Verify directory-wide contents observed during planning.\n *\n * @param context - CLI context\n * @param precondition - Expected directory snapshot\n */\nfunction preflightDirectory(\n context: LocalContext,\n precondition: PlannedDirectoryPrecondition,\n): void {\n const currentPaths = collectProjectRelativePaths(context, precondition.path);\n if (\n currentPaths.length !== precondition.relativePaths.length ||\n currentPaths.some((path, index) => path !== precondition.relativePaths[index])\n ) {\n throw new Error(`Directory changed after preview: ${precondition.path}`);\n }\n}\n\n/**\n * Record missing parent directories that this plan may create.\n *\n * @param context - CLI context\n * @param plan - Approved project plan\n * @returns Missing directories ordered deepest first\n */\nfunction collectCreatedDirectoryCandidates(context: LocalContext, plan: ProjectPlan): string[] {\n const rootDirectory = resolve(plan.rootDirectory);\n const directories = new Set<string>();\n for (const change of plan.changes) {\n let current = dirname(resolve(change.path));\n while (true) {\n const child = relative(rootDirectory, current);\n if (child === '..' || child.startsWith(`..${sep}`)) {\n break;\n }\n if (!pathExists(context, current)) {\n directories.add(current);\n }\n if (current === rootDirectory) {\n break;\n }\n current = dirname(current);\n }\n }\n return [...directories].sort((left, right) => right.split(sep).length - left.split(sep).length);\n}\n\n/**\n * Remove empty parent directories created while applying a failed plan.\n *\n * @param context - CLI context\n * @param directories - Previously absent directories\n * @returns Rollback failures\n */\nfunction removeCreatedDirectories(context: LocalContext, directories: readonly string[]): string[] {\n const errors: string[] = [];\n for (const directory of directories) {\n if (!pathExists(context, directory)) {\n continue;\n }\n try {\n context.fs.rmdirSync(directory);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n errors.push(`${directory}: ${(error as Error).message}`);\n }\n }\n }\n return errors;\n}\n\n/**\n * Install a project-local skill link, copying on platforms where links fail.\n *\n * @param context - CLI context\n * @param change - Planned link\n * @param rootDirectory - Approved mutation root\n */\nfunction applyLink(context: LocalContext, change: PlannedLinkChange, rootDirectory: string): void {\n try {\n context.fs.symlinkSync(change.target, change.path, 'dir');\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (!['EPERM', 'EACCES', 'ENOTSUP', 'UNKNOWN'].includes(code ?? '')) {\n throw error;\n }\n change.fallbackFiles.forEach((file) => {\n const path = join(change.path, file.path);\n assertPathPhysicallyContained(context, rootDirectory, path);\n context.fs.mkdirSync(dirname(path), { recursive: true });\n context.fs.writeFileSync(path, file.contents);\n });\n }\n}\n\n/**\n * Apply an approved project plan and restore source-controlled files on error.\n *\n * @param context - CLI context\n * @param plan - Approved plan\n */\nexport async function applyProjectPlan(context: LocalContext, plan: ProjectPlan): Promise<void> {\n for (const change of plan.changes) {\n assertPathPhysicallyContained(context, plan.rootDirectory, change.path);\n preflightChange(context, change);\n }\n for (const precondition of plan.directoryPreconditions ?? []) {\n assertPathPhysicallyContained(context, plan.rootDirectory, precondition.path);\n preflightDirectory(context, precondition);\n }\n\n const createdDirectoryCandidates = collectCreatedDirectoryCandidates(context, plan);\n const applied: RollbackSnapshot[] = [];\n try {\n for (const change of plan.changes) {\n assertPathPhysicallyContained(context, plan.rootDirectory, change.path);\n preflightChange(context, change);\n if (change.kind === 'file') {\n const snapshot = snapshotPath(context, change.path);\n if (change.before === null) {\n writeAtomicCreateOnly(context, change.path, change.after, change.mode);\n } else {\n writeAtomic(context, change.path, change.after, change.mode);\n }\n applied.push(snapshot);\n } else {\n applied.push({ kind: 'absent', path: change.path });\n applyLink(context, change, plan.rootDirectory);\n }\n }\n } catch (error) {\n const rollbackErrors: string[] = [];\n for (const snapshot of applied.reverse()) {\n try {\n restoreSnapshot(context, snapshot);\n } catch (rollbackError) {\n rollbackErrors.push(`${snapshot.path}: ${(rollbackError as Error).message}`);\n }\n }\n rollbackErrors.push(...removeCreatedDirectories(context, createdDirectoryCandidates));\n if (rollbackErrors.length > 0) {\n throw new Error(\n `${(error as Error).message}\\nRollback also failed:\\n${rollbackErrors.join('\\n')}`,\n );\n }\n throw error;\n }\n}\n"],"mappings":"qLA+CA,SAAS,EAAW,EAAuB,EAAuB,CAChE,GAAI,CAEF,OADA,EAAQ,GAAG,UAAU,EAAK,CACnB,SACA,EAAO,CACd,GAAK,EAAgC,OAAS,SAC5C,MAAO,GAET,MAAM,GAWV,SAAS,EAAa,EAAuB,EAAgC,CAC3E,GAAI,CAAC,EAAW,EAAS,EAAK,CAC5B,MAAO,CAAE,KAAM,SAAU,OAAM,CAEjC,IAAM,EAAO,EAAQ,GAAG,UAAU,EAAK,CACvC,GAAI,EAAK,gBAAgB,CACvB,MAAO,CAAE,KAAM,OAAQ,OAAM,OAAQ,EAAQ,GAAG,aAAa,EAAK,CAAE,CAEtE,GAAI,CAAC,EAAK,QAAQ,CAChB,MAAU,MAAM,iDAAiD,IAAO,CAE1E,MAAO,CACL,KAAM,OACN,OACA,SAAU,EAAQ,GAAG,aAAa,EAAM,OAAO,CAC/C,KAAM,EAAK,KACZ,CAWH,SAAS,EAAY,EAAuB,EAAc,EAAkB,EAAqB,CAC/F,EAAQ,GAAG,UAAU,EAAQ,EAAK,CAAE,CAAE,UAAW,GAAM,CAAC,CACxD,IAAM,EAAgB,EACpB,EAAQ,EAAK,CACb,IAAI,EAAS,EAAK,CAAC,GAAG,EAAQ,QAAQ,IAAI,GAAG,KAAK,KAAK,CAAC,MACzD,CACD,GAAI,CACF,EAAQ,GAAG,cACT,EACA,EACA,IAAS,IAAA,GAAY,IAAA,GAAY,CAAE,KAAM,EAAO,IAAO,CACxD,CACD,EAAQ,GAAG,WAAW,EAAe,EAAK,QAClC,CACJ,EAAW,EAAS,EAAc,EACpC,EAAQ,GAAG,OAAO,EAAe,CAAE,MAAO,GAAM,CAAC,EAavD,SAAS,EACP,EACA,EACA,EACA,EACM,CACN,EAAQ,GAAG,UAAU,EAAQ,EAAK,CAAE,CAAE,UAAW,GAAM,CAAC,CACxD,IAAM,EAAgB,EACpB,EAAQ,EAAK,CACb,IAAI,EAAS,EAAK,CAAC,GAAG,EAAQ,QAAQ,IAAI,GAAG,KAAK,KAAK,CAAC,MACzD,CACD,GAAI,CACF,EAAQ,GAAG,cACT,EACA,EACA,IAAS,IAAA,GAAY,IAAA,GAAY,CAAE,KAAM,EAAO,IAAO,CACxD,CACD,EAAQ,GAAG,SAAS,EAAe,EAAK,QAChC,CACJ,EAAW,EAAS,EAAc,EACpC,EAAQ,GAAG,OAAO,EAAe,CAAE,MAAO,GAAM,CAAC,EAWvD,SAAS,EAAgB,EAAuB,EAAkC,CAChF,GAAI,EAAS,OAAS,SAAU,CAC1B,EAAW,EAAS,EAAS,KAAK,EACpC,EAAQ,GAAG,OAAO,EAAS,KAAM,CAAE,UAAW,GAAM,MAAO,GAAM,CAAC,CAEpE,OAGF,GADA,EAAQ,GAAG,UAAU,EAAQ,EAAS,KAAK,CAAE,CAAE,UAAW,GAAM,CAAC,CAC7D,EAAS,OAAS,OAAQ,CACxB,EAAW,EAAS,EAAS,KAAK,EACpC,EAAQ,GAAG,OAAO,EAAS,KAAM,CAAE,UAAW,GAAM,MAAO,GAAM,CAAC,CAEpE,EAAQ,GAAG,YAAY,EAAS,OAAQ,EAAS,KAAM,MAAM,CAC7D,OAEE,EAAW,EAAS,EAAS,KAAK,EAAI,CAAC,EAAQ,GAAG,UAAU,EAAS,KAAK,CAAC,QAAQ,EACrF,EAAQ,GAAG,OAAO,EAAS,KAAM,CAAE,UAAW,GAAM,MAAO,GAAM,CAAC,CAEpE,EAAY,EAAS,EAAS,KAAM,EAAS,SAAU,EAAS,KAAK,CASvE,SAAS,EAAc,EAAuB,EAAiC,CAC7E,IAAM,EAAS,EAAW,EAAS,EAAO,KAAK,CAC/C,GAAI,EAAO,SAAW,KAAM,CAC1B,GAAI,EACF,MAAU,MAAM,gCAAgC,EAAO,OAAO,CAEhE,OAEF,GAAI,CAAC,EACH,MAAU,MAAM,+BAA+B,EAAO,OAAO,CAE/D,IAAM,EAAO,EAAQ,GAAG,UAAU,EAAO,KAAK,CAC9C,GACE,CAAC,EAAK,QAAQ,EACb,EAAO,OAAS,IAAA,IAAa,EAAK,OAAS,EAAO,MACnD,EAAQ,GAAG,aAAa,EAAO,KAAM,OAAO,GAAK,EAAO,OAExD,MAAU,MAAM,+BAA+B,EAAO,OAAO,CAE/D,GAAI,EAAO,WACT,MAAU,MAAM,wCAAwC,EAAO,OAAO,CAU1E,SAAS,EAAgB,EAAuB,EAA6B,CAC3E,GAAI,EAAO,OAAS,OAAQ,CAC1B,EAAc,EAAS,EAAO,CAC9B,OAEF,GAAI,EAAW,EAAS,EAAO,KAAK,CAClC,MAAU,MAAM,wCAAwC,EAAO,OAAO,CAU1E,SAAS,EACP,EACA,EACM,CACN,IAAM,EAAe,EAA4B,EAAS,EAAa,KAAK,CAC5E,GACE,EAAa,SAAW,EAAa,cAAc,QACnD,EAAa,MAAM,EAAM,IAAU,IAAS,EAAa,cAAc,GAAO,CAE9E,MAAU,MAAM,oCAAoC,EAAa,OAAO,CAW5E,SAAS,EAAkC,EAAuB,EAA6B,CAC7F,IAAM,EAAgB,EAAQ,EAAK,cAAc,CAC3C,EAAc,IAAI,IACxB,IAAK,IAAM,KAAU,EAAK,QAAS,CACjC,IAAI,EAAU,EAAQ,EAAQ,EAAO,KAAK,CAAC,CAC3C,OAAa,CACX,IAAM,EAAQ,EAAS,EAAe,EAAQ,CAO9C,GANI,IAAU,MAAQ,EAAM,WAAW,KAAK,IAAM,GAG7C,EAAW,EAAS,EAAQ,EAC/B,EAAY,IAAI,EAAQ,CAEtB,IAAY,GACd,MAEF,EAAU,EAAQ,EAAQ,EAG9B,MAAO,CAAC,GAAG,EAAY,CAAC,MAAM,EAAM,IAAU,EAAM,MAAM,EAAI,CAAC,OAAS,EAAK,MAAM,EAAI,CAAC,OAAO,CAUjG,SAAS,EAAyB,EAAuB,EAA0C,CACjG,IAAM,EAAmB,EAAE,CAC3B,IAAK,IAAM,KAAa,EACjB,KAAW,EAAS,EAAU,CAGnC,GAAI,CACF,EAAQ,GAAG,UAAU,EAAU,OACxB,EAAO,CACT,EAAgC,OAAS,UAC5C,EAAO,KAAK,GAAG,EAAU,IAAK,EAAgB,UAAU,CAI9D,OAAO,EAUT,SAAS,EAAU,EAAuB,EAA2B,EAA6B,CAChG,GAAI,CACF,EAAQ,GAAG,YAAY,EAAO,OAAQ,EAAO,KAAM,MAAM,OAClD,EAAO,CACd,IAAM,EAAQ,EAAgC,KAC9C,GAAI,CAAC,CAAC,QAAS,SAAU,UAAW,UAAU,CAAC,SAAS,GAAQ,GAAG,CACjE,MAAM,EAER,EAAO,cAAc,QAAS,GAAS,CACrC,IAAM,EAAO,EAAK,EAAO,KAAM,EAAK,KAAK,CACzC,EAA8B,EAAS,EAAe,EAAK,CAC3D,EAAQ,GAAG,UAAU,EAAQ,EAAK,CAAE,CAAE,UAAW,GAAM,CAAC,CACxD,EAAQ,GAAG,cAAc,EAAM,EAAK,SAAS,EAC7C,EAUN,eAAsB,EAAiB,EAAuB,EAAkC,CAC9F,IAAK,IAAM,KAAU,EAAK,QACxB,EAA8B,EAAS,EAAK,cAAe,EAAO,KAAK,CACvE,EAAgB,EAAS,EAAO,CAElC,IAAK,IAAM,KAAgB,EAAK,wBAA0B,EAAE,CAC1D,EAA8B,EAAS,EAAK,cAAe,EAAa,KAAK,CAC7E,EAAmB,EAAS,EAAa,CAG3C,IAAM,EAA6B,EAAkC,EAAS,EAAK,CAC7E,EAA8B,EAAE,CACtC,GAAI,CACF,IAAK,IAAM,KAAU,EAAK,QAGxB,GAFA,EAA8B,EAAS,EAAK,cAAe,EAAO,KAAK,CACvE,EAAgB,EAAS,EAAO,CAC5B,EAAO,OAAS,OAAQ,CAC1B,IAAM,EAAW,EAAa,EAAS,EAAO,KAAK,CAC/C,EAAO,SAAW,KACpB,EAAsB,EAAS,EAAO,KAAM,EAAO,MAAO,EAAO,KAAK,CAEtE,EAAY,EAAS,EAAO,KAAM,EAAO,MAAO,EAAO,KAAK,CAE9D,EAAQ,KAAK,EAAS,MAEtB,EAAQ,KAAK,CAAE,KAAM,SAAU,KAAM,EAAO,KAAM,CAAC,CACnD,EAAU,EAAS,EAAQ,EAAK,cAAc,OAG3C,EAAO,CACd,IAAM,EAA2B,EAAE,CACnC,IAAK,IAAM,KAAY,EAAQ,SAAS,CACtC,GAAI,CACF,EAAgB,EAAS,EAAS,OAC3B,EAAe,CACtB,EAAe,KAAK,GAAG,EAAS,KAAK,IAAK,EAAwB,UAAU,CAShF,MANA,EAAe,KAAK,GAAG,EAAyB,EAAS,EAA2B,CAAC,CACjF,EAAe,OAAS,EAChB,MACR,GAAI,EAAgB,QAAQ,2BAA2B,EAAe,KAAK;EAAK,GACjF,CAEG"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{t as e}from"./path-safety-D5Qwl40b.mjs";import{dirname as t,isAbsolute as n,join as r,relative as i,resolve as a,sep as o}from"node:path";import s from"colors";import c from"inquirer";import{createTwoFilesPatch as l}from"diff";import{createHash as u}from"node:crypto";function d(e,t){let r=i(e,t).split(o).join(`/`);return r.length===0?`.`:r===`..`||r.startsWith(`../`)||n(r)?t.split(o).join(`/`):r}function f(e){return`'${e.replace(/'/gu,`'\\''`)}'`}function p(e,t){return t.kind===`link`?{kind:`link`,target:`${d(e,t.path)} -> ${t.target}`,description:t.description}:{kind:t.before===null?`create`:`merge`,target:d(e,t.path),description:t.description}}function m(e,t){let n=Math.max(...t.details.map(({label:e})=>e.length+1),0),r=[s.bold(t.title),...t.details.map(({label:e,path:r})=>{let i=`${e}:`.padEnd(n);return` ${s.dim(i)} ${s.cyan(d(t.cwd,r))}`}),``];return e.changes.length===0?r.push(s.dim(`No changes needed.`)):(r.push(s.bold(`Changes`)),e.changes.forEach(e=>{let n=p(t.cwd,e),i={create:s.green(n.kind.padEnd(7)),merge:s.cyan(n.kind.padEnd(7)),link:s.magenta(n.kind.padEnd(7))}[n.kind];if(r.push(` ${i} ${n.target}`),e.kind===`file`&&e.before!==null){let n=d(t.cwd,e.path),i=l(n,n,e.before,e.after,``,``,{context:3});r.push(...i.trimEnd().split(`
|
|
2
|
+
`).map(e=>` ${e}`))}})),e.unchanged.length>0&&(r.push(``,s.bold(`Left unchanged`)),e.unchanged.forEach(e=>r.push(` ${s.dim(d(t.cwd,e))}`))),e.warnings.length>0&&(r.push(``,s.bold(s.yellow(`Warnings`))),e.warnings.forEach(e=>r.push(` ${s.yellow(e)}`))),`${r.join(`
|
|
3
|
+
`)}\n`}function h(e,t){let n=e[t];if(!n)throw Error(`Missing preflight snapshot for ${t}`);return n}function g(e,t){let n=h(e,t);if(n.kind===`directory`||n.kind===`link`)throw Error(`Expected a regular file or absent path: ${t}`);return n.kind===`file`?{path:t,contents:n.contents,mode:n.mode}:{path:t,contents:null}}function _(e){let{snapshot:t,after:n,description:r,createOnly:i}=e;if(i&&t.contents!==null)throw Error(`Refusing to overwrite existing file: ${t.path}`);if(t.contents!==n)return{kind:`file`,path:t.path,before:t.contents,after:n,description:r,...t.mode===void 0?{}:{mode:t.mode},...i===void 0?{}:{createOnly:i}}}const v=`.agents/skills`,y=[`.aider-desk/skills`,v,`.autohand/skills`,`.augment/skills`,`.bob/skills`,`.claude/skills`,`.codeartsdoer/skills`,`.codebuddy/skills`,`.codemaker/skills`,`.codestudio/skills`,`.commandcode/skills`,`.continue/skills`,`.cortex/skills`,`.crush/skills`,`.devin/skills`,`.factory/skills`,`agent/skills`,`.forge/skills`,`.goose/skills`,`.grok/skills`,`.hermes/skills`,`.inferencesh/skills`,`.jazz/skills`,`.junie/skills`,`.iflow/skills`,`.kilocode/skills`,`.kimchi/skills`,`.kiro/skills`,`.kode/skills`,`.lingma/skills`,`.mcpjam/skills`,`.minimax/skills`,`.vibe/skills`,`.moxby/skills`,`.mux/skills`,`.openhands/skills`,`.ona/skills`,`.pi/skills`,`.posit/assistant/skills`,`.qoder/skills`,`.qwen/skills`,`.reasonix/skills`,`.rovodev/skills`,`.roo/skills`,`.tabnine/agent/skills`,`.terramind/skills`,`.tinycloud/skills`,`.trae/skills`,`.windsurf/skills`,`.zcode/skills`,`.zencoder/skills`,`.neovate/skills`,`.pochi/skills`,`.adal/skills`],b=[v,`.cursor/skills`,`.codex/skills`,`.github/skills`,`.gemini/skills`,`.opencode/skills`,`.cline/skills`,`.warp/skills`,`.zed/skills`,`.replit/skills`];function x(e){return e.length===1?{canonical:e[0].path,aliases:[]}:{canonical:v,aliases:e.length>1?e.filter(({path:e,supportsAgentsSkills:t})=>e!==`.agents/skills`&&!t).map(({path:e})=>e):[]}}function S(e,t){let n=e.trimEnd();return`${n}\n\n<!-- managed-by: ${t}; content-sha256: ${u(`sha256`).update(n).digest(`hex`)} -->\n`}function C(e,t){let n=t.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`),r=e.match(RegExp(`<!-- managed-by: ${n}; content-sha256: ([a-f0-9]{64}) -->\\s*$`,`u`));if(!r||r.index===void 0)return!1;let i=e.slice(0,r.index).trimEnd();return u(`sha256`).update(i).digest(`hex`)===r[1]}function w(e,t,n){let i=x(t),a=new Set,o=r(e,i.canonical,n.name);return n.files.forEach(({path:e})=>a.add(r(o,e))),i.aliases.forEach(t=>{let i=r(e,t,n.name);a.add(i),n.files.forEach(({path:e})=>a.add(r(i,e)))}),t.forEach(({path:t})=>{n.files.forEach(({path:i})=>{a.add(r(e,t,n.name,i))})}),[...a].sort((e,t)=>e.localeCompare(t))}function T(e){let{rootDirectory:n,existingDirectories:a,snapshots:o,skill:s,preserveModified:c=!1}=e,l={changes:[],unchanged:[],warnings:[]},u=x(a),d=r(n,u.canonical,s.name),f=s.files.map(e=>({path:e.path,contents:S(e.contents,s.owner)})),p=(e,t)=>{f.forEach(n=>{let i=r(e,n.path),a=g(o,i);if(a.contents!==null&&a.contents!==n.contents&&!C(a.contents,s.owner)){if(c){l.unchanged.push(i),l.warnings.push(`Customized managed skill file was left unchanged: ${i}. Merge the updated guidance manually.`);return}throw Error(`Refusing to replace user-managed skill: ${i}. Apply the skill update manually.`)}let u=_({snapshot:a,after:n.contents,description:`${t}: ${n.path}`});u?l.changes.push(u):l.unchanged.push(i)})};return p(d,`Install ${s.displayName} skill file`),u.aliases.forEach(e=>{let a=r(n,e,s.name),u=h(o,a),m=i(t(a),d);if(u.kind===`link`&&u.target===m){l.unchanged.push(a);return}if(u.kind===`directory`){p(a,`Update ${s.displayName} skill copy in ${e}`);return}if(u.kind!==`absent`){if(c){l.unchanged.push(a),l.warnings.push(`Customized skill target was left unchanged: ${a}. Expose the canonical skill manually if needed.`);return}throw Error(`Refusing to replace unexpected skill target: ${a}`)}let g={kind:`link`,path:a,target:m,fallbackFiles:f,description:`Expose the canonical skill in ${e}`};l.changes.push(g)}),a.map(({path:e})=>e).filter(e=>e!==u.canonical&&!u.aliases.includes(e)).forEach(e=>{let t=r(n,e,s.name),i=r(t,`SKILL.md`),a=g(o,i);a.contents!==null&&C(a.contents,s.owner)?p(t,`Update existing managed skill in ${e}`):a.contents?.includes(`managed-by: ${s.owner}`)&&(l.unchanged.push(i),l.warnings.push(`Existing customized managed skill was left unchanged: ${t}`))}),l}function E(t,n,r){return Object.fromEntries(r.map(r=>{e(t,n,r);try{let e=t.fs.lstatSync(r);if(e.isSymbolicLink())return[r,{kind:`link`,path:r,target:t.fs.readlinkSync(r)}];if(e.isDirectory())return[r,{kind:`directory`,path:r}];if(!e.isFile())throw Error(`Unsupported filesystem entry: ${r}`);return[r,{kind:`file`,path:r,contents:t.fs.readFileSync(r,`utf8`),mode:e.mode}]}catch(e){if(e.code===`ENOENT`)return[r,{kind:`absent`,path:r}];throw e}}))}function D(e,n){let i=n;for(;;){if(e.fs.existsSync(r(i,`.git`)))return i;let n=t(i);if(n===i)return;i=n}}function O(e,n){let r=n;for(;!e.fs.existsSync(r);){let e=t(r);if(e===r)return r;r=e}return e.fs.statSync(r).isDirectory()?r:t(r)}function k(e,t){let r=i(e,t);return r!==`..`&&!r.startsWith(`..${o}`)&&!n(r)}function A(e,t,n={}){if(!e.fs.existsSync(t))return[];let a=[],s=c=>{e.fs.readdirSync(c,{withFileTypes:!0}).forEach(e=>{if(e.name===`.git`||e.name===`node_modules`)return;let l=r(c,e.name),u=e.isDirectory()&&!e.isSymbolicLink();(n.includeDirectories!==!1||!u)&&a.push(i(t,l).split(o).join(`/`)),u&&s(l)})};return s(t),a.sort((e,t)=>e.localeCompare(t))}function j(e,t,n){return n===0?!1:e.fs.readdirSync(t,{withFileTypes:!0}).some(i=>{if(!i.isDirectory()||i.isSymbolicLink())return!1;let a=r(t,i.name);return e.fs.existsSync(r(a,`SKILL.md`))||j(e,a,n-1)})}function M(e,t){if(!e.fs.existsSync(t)||!e.fs.statSync(t).isDirectory())return[];let n=new Set(b),i=new Set([...y,...b]);return e.fs.readdirSync(t,{withFileTypes:!0}).forEach(n=>{if(!n.isDirectory()||n.isSymbolicLink())return;let a=r(t,n.name,`skills`);e.fs.existsSync(a)&&e.fs.statSync(a).isDirectory()&&j(e,a,3)&&i.add(`${n.name}/skills`)}),[...i].filter(n=>{let i=r(t,n);return e.fs.existsSync(i)&&e.fs.statSync(i).isDirectory()}).sort((e,t)=>e.localeCompare(t)).map(e=>({path:e,supportsAgentsSkills:n.has(e)}))}function N(e,t){if(!t)return!1;if(e.fs.existsSync(r(t,`.github`)))return!0;let n=r(t,`.git`),i=n;if(e.fs.existsSync(n)&&e.fs.statSync(n).isFile()){let r=e.fs.readFileSync(n,`utf8`).match(/^gitdir:\s*(.+)$/mu)?.[1];r&&(i=a(t,r))}let o=r(i,`commondir`);e.fs.existsSync(o)&&e.fs.statSync(o).isFile()&&(i=a(i,e.fs.readFileSync(o,`utf8`).trim()));let s=r(i,`config`);return e.fs.existsSync(s)&&e.fs.readFileSync(s,`utf8`).includes(`github.com`)}function P(t,n){let r=D(t,O(t,n.invocationDirectory)),i=r&&k(r,n.targetDirectory)?r:D(t,O(t,n.targetDirectory)),a=n.standaloneProjectRoot!==n.targetDirectory&&k(n.standaloneProjectRoot,n.targetDirectory),o=i,s=a?r??n.standaloneProjectRoot:o??n.standaloneProjectRoot;return e(t,s,n.targetDirectory),{projectRoot:s,...o?{repositoryRoot:o}:{},existingSkillDirectories:M(t,s),usesGithub:N(t,o)}}var F=class extends Error{constructor(){super(`Prompt cancelled.`),this.name=`PromptCancelledError`}};function I(e){let t=e instanceof Error?e.message:String(e);return e instanceof F||/force closed|prompt.*cancel|user.*close|SIGINT/iu.test(t)?new F:e instanceof Error?e:Error(t)}var L=class{prompt;constructor(e){this.prompt=c.createPromptModule({input:e.process.stdin,output:e.process.stderr})}async text(e,t,n){try{return(await this.prompt([{type:`input`,name:`value`,message:e,...t===void 0?{}:{default:t},validate:e=>{let t=e.trim();return t.length>0?n?.(t)??!0:`Enter a value.`}}])).value.trim()}catch(e){throw I(e)}}async select(e,t,n){try{return(await this.prompt([{type:`list`,name:`value`,message:e,choices:[...t],...n===void 0?{}:{default:n}}])).value}catch(e){throw I(e)}}async checkbox(e,t){try{return(await this.prompt([{type:`checkbox`,name:`value`,message:e,choices:[...t]}])).value}catch(e){throw I(e)}}async confirm(e,t=!0){try{return(await this.prompt([{type:`confirm`,name:`value`,message:e,default:t}])).value}catch(e){throw I(e)}}};export{P as a,w as c,h as d,_ as f,p as g,m as h,A as i,T as l,f as m,L as n,O as o,d as p,E as r,D as s,F as t,g as u};
|
|
4
|
+
//# sourceMappingURL=prompts-ClBXdELk.mjs.map
|