@vercel/cli-support 0.0.0 → 65.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +100 -3
- package/dist/chunks/add-5YZQTIQM.js +8 -0
- package/dist/chunks/add-A524QQ2H.js +8 -0
- package/dist/chunks/add-V4JMUHKO.js +8 -0
- package/dist/chunks/build-K2PVDJZ4.js +7 -0
- package/dist/chunks/chunk-22FDWPWY.js +7 -0
- package/dist/chunks/chunk-25565AGS.js +7 -0
- package/dist/chunks/chunk-2ACMWVTB.js +12 -0
- package/dist/chunks/chunk-2EYYB6YN.js +7 -0
- package/dist/chunks/chunk-2GHZGOWT.js +7 -0
- package/dist/chunks/chunk-2H3SB5RP.js +9 -0
- package/dist/chunks/chunk-2NABMKFV.js +29 -0
- package/dist/chunks/chunk-2PKEEQ5W.js +25 -0
- package/dist/chunks/chunk-2S6PE6GB.js +7 -0
- package/dist/chunks/chunk-2U7DJZSQ.js +21 -0
- package/dist/chunks/chunk-2WYYGGEO.js +7 -0
- package/dist/chunks/chunk-3ADDGPEN.js +7 -0
- package/dist/chunks/chunk-3AYYFYZG.js +7 -0
- package/dist/chunks/chunk-3G3FQYMW.js +7 -0
- package/dist/chunks/chunk-3JGBBS6V.js +7 -0
- package/dist/chunks/chunk-3KKFLKQG.js +7 -0
- package/dist/chunks/chunk-3LIKVGFT.js +8 -0
- package/dist/chunks/chunk-3XW7N4W3.js +9 -0
- package/dist/chunks/chunk-43GBAKL2.js +86 -0
- package/dist/chunks/chunk-4CACOKMS.js +7 -0
- package/dist/chunks/chunk-4NTBYNFR.js +17 -0
- package/dist/chunks/chunk-4SAVH3H7.js +7 -0
- package/dist/chunks/chunk-4UGHFESV.js +8 -0
- package/dist/chunks/chunk-4VFYJU37.js +7 -0
- package/dist/chunks/chunk-5IASAERQ.js +7 -0
- package/dist/chunks/chunk-5RMIM4S2.js +7 -0
- package/dist/chunks/chunk-67GZ5REA.js +7 -0
- package/dist/chunks/chunk-6IDNVZZR.js +7 -0
- package/dist/chunks/chunk-6ISAISGD.js +16 -0
- package/dist/chunks/chunk-6KVHNQW4.js +17 -0
- package/dist/chunks/chunk-6OVX3PWM.js +7 -0
- package/dist/chunks/chunk-6QKS6QK7.js +7 -0
- package/dist/chunks/chunk-6VH56CX2.js +19 -0
- package/dist/chunks/chunk-6Y2ZL5XJ.js +98 -0
- package/dist/chunks/chunk-76KGQU2G.js +7 -0
- package/dist/chunks/chunk-76SVVWPH.js +7 -0
- package/dist/chunks/chunk-773GOZIR.js +13 -0
- package/dist/chunks/chunk-7BGKE3JW.js +10 -0
- package/dist/chunks/chunk-7EJQLVWX.js +7 -0
- package/dist/chunks/chunk-7HV7O6DM.js +7 -0
- package/dist/chunks/chunk-7L2K4OKM.js +63 -0
- package/dist/chunks/chunk-7Y46LB43.js +14 -0
- package/dist/chunks/chunk-7YKFF6CE.js +7 -0
- package/dist/chunks/chunk-7Z3WUAO5.js +10 -0
- package/dist/chunks/chunk-A2RZZQEP.js +7 -0
- package/dist/chunks/chunk-ABZEMNDR.js +7 -0
- package/dist/chunks/chunk-ADLBLGT3.js +8 -0
- package/dist/chunks/chunk-AM46JVVN.js +7 -0
- package/dist/chunks/chunk-ANMDN3EG.js +9 -0
- package/dist/chunks/chunk-APZULWJC.js +8 -0
- package/dist/chunks/chunk-AWMQGOS2.js +7 -0
- package/dist/chunks/chunk-B4UE4LVE.js +7 -0
- package/dist/chunks/chunk-B4YYOSPY.js +7 -0
- package/dist/chunks/chunk-BBKEP7RO.js +7 -0
- package/dist/chunks/chunk-BL3HBRF6.js +12 -0
- package/dist/chunks/chunk-BLUPZPAS.js +7 -0
- package/dist/chunks/chunk-BPUANOGW.js +7 -0
- package/dist/chunks/chunk-BRQUZ5NC.js +7 -0
- package/dist/chunks/chunk-BS32OUOC.js +7 -0
- package/dist/chunks/chunk-BTI5TG6Q.js +7 -0
- package/dist/chunks/chunk-BUJITHGZ.js +8 -0
- package/dist/chunks/chunk-BVH2AEFE.js +7 -0
- package/dist/chunks/chunk-BZENIQ7N.js +7 -0
- package/dist/chunks/chunk-C6GY2G73.js +7 -0
- package/dist/chunks/chunk-CEMPU323.js +7 -0
- package/dist/chunks/chunk-COD3WAUI.js +7 -0
- package/dist/chunks/chunk-COM5YCHF.js +9 -0
- package/dist/chunks/chunk-CZSOZKHX.js +7 -0
- package/dist/chunks/chunk-D2BZMGHP.js +7 -0
- package/dist/chunks/chunk-D3AHZ5LI.js +7 -0
- package/dist/chunks/chunk-D6REP5QQ.js +15 -0
- package/dist/chunks/chunk-DFVNL5ML.js +7 -0
- package/dist/chunks/chunk-DGYHWXD2.js +10 -0
- package/dist/chunks/chunk-DUT4U5YY.js +7 -0
- package/dist/chunks/chunk-DWZBL4NK.js +7 -0
- package/dist/chunks/chunk-E2SADN6I.js +7 -0
- package/dist/chunks/chunk-E6CO6TUM.js +7 -0
- package/dist/chunks/chunk-EAUDC24V.js +9 -0
- package/dist/chunks/chunk-ECQIO5K3.js +7 -0
- package/dist/chunks/chunk-ETV3C2CV.js +7 -0
- package/dist/chunks/chunk-F2SWJEYV.js +8 -0
- package/dist/chunks/chunk-F4KY2TOK.js +7 -0
- package/dist/chunks/chunk-F53OKXYI.js +7 -0
- package/dist/chunks/chunk-F7AVGV4Y.js +7 -0
- package/dist/chunks/chunk-FBYA6LLM.js +7 -0
- package/dist/chunks/chunk-FDNYYENK.js +11 -0
- package/dist/chunks/chunk-FGFLTLEA.js +7 -0
- package/dist/chunks/chunk-FUX6LKNP.js +7 -0
- package/dist/chunks/chunk-G4T7VBGN.js +9 -0
- package/dist/chunks/chunk-GA277JFB.js +20 -0
- package/dist/chunks/chunk-GD7AV7BO.js +9 -0
- package/dist/chunks/chunk-GG5RME4X.js +7 -0
- package/dist/chunks/chunk-GHAY4PSD.js +7 -0
- package/dist/chunks/chunk-GVTXA6HG.js +7 -0
- package/dist/chunks/chunk-GYVJIIYL.js +7 -0
- package/dist/chunks/chunk-GZNDA6SV.js +8 -0
- package/dist/chunks/chunk-HCRD3JFL.js +7 -0
- package/dist/chunks/chunk-HEGJZJO7.js +7 -0
- package/dist/chunks/chunk-HRR57QNP.js +7 -0
- package/dist/chunks/chunk-IA3MXJRC.js +8 -0
- package/dist/chunks/chunk-ID663OJ7.js +7 -0
- package/dist/chunks/chunk-IEPW2YRH.js +7 -0
- package/dist/chunks/chunk-IGDG5CWT.js +7 -0
- package/dist/chunks/chunk-IKQTP764.js +7 -0
- package/dist/chunks/chunk-IQ7FPAI4.js +7 -0
- package/dist/chunks/chunk-IQKGQ2Y2.js +15 -0
- package/dist/chunks/chunk-ISWW3DKF.js +7 -0
- package/dist/chunks/chunk-IUXSJWL3.js +7 -0
- package/dist/chunks/chunk-IVSC7ZFJ.js +7 -0
- package/dist/chunks/chunk-IVSSTHB6.js +7 -0
- package/dist/chunks/chunk-J24BABG4.js +21 -0
- package/dist/chunks/chunk-JALVF3C2.js +7 -0
- package/dist/chunks/chunk-JELLVPCM.js +8 -0
- package/dist/chunks/chunk-JESNVRVR.js +7 -0
- package/dist/chunks/chunk-JLEJB6KM.js +7 -0
- package/dist/chunks/chunk-KH6565YH.js +8 -0
- package/dist/chunks/chunk-KNLGWGUE.js +57 -0
- package/dist/chunks/chunk-KRPY5FHJ.js +7 -0
- package/dist/chunks/chunk-KW6GSQXV.js +7 -0
- package/dist/chunks/chunk-L4NSF346.js +22 -0
- package/dist/chunks/chunk-LCHECISY.js +7 -0
- package/dist/chunks/chunk-LJBUJ23M.js +7 -0
- package/dist/chunks/chunk-LKLH6DZP.js +9 -0
- package/dist/chunks/chunk-LRYGNQ6C.js +8 -0
- package/dist/chunks/chunk-LSF7FY6X.js +7 -0
- package/dist/chunks/chunk-LSQREJXO.js +11 -0
- package/dist/chunks/chunk-LT3UK4K6.js +10 -0
- package/dist/chunks/chunk-LUBUI5GF.js +7 -0
- package/dist/chunks/chunk-MCRKBVZA.js +7 -0
- package/dist/chunks/chunk-MVGTMPMI.js +23 -0
- package/dist/chunks/chunk-MXTC4ZAQ.js +7 -0
- package/dist/chunks/chunk-NB2WLB3J.js +12 -0
- package/dist/chunks/chunk-NEFDNROD.js +7 -0
- package/dist/chunks/chunk-NQWGRKF4.js +7 -0
- package/dist/chunks/chunk-NTZ5WWYV.js +7 -0
- package/dist/chunks/chunk-NWGBDBZI.js +7 -0
- package/dist/chunks/chunk-NZ2TFADV.js +7 -0
- package/dist/chunks/chunk-OAM5NJCU.js +9 -0
- package/dist/chunks/chunk-OCQPXOTX.js +11 -0
- package/dist/chunks/chunk-OCR5CRTH.js +10 -0
- package/dist/chunks/chunk-OFDTADPQ.js +7 -0
- package/dist/chunks/chunk-OGPENBY2.js +7 -0
- package/dist/chunks/chunk-OKEBIUKZ.js +7 -0
- package/dist/chunks/chunk-OMCGXRSA.js +21 -0
- package/dist/chunks/chunk-OO572JUC.js +7 -0
- package/dist/chunks/chunk-OPORM35X.js +7 -0
- package/dist/chunks/chunk-OQCMRU3J.js +10 -0
- package/dist/chunks/chunk-OQPXJCMK.js +32 -0
- package/dist/chunks/chunk-OWOWPOIE.js +23 -0
- package/dist/chunks/chunk-PADL3C6Z.js +7 -0
- package/dist/chunks/chunk-PFD7LETF.js +7 -0
- package/dist/chunks/chunk-PFNYWWLI.js +7 -0
- package/dist/chunks/chunk-PFPJLIFF.js +33 -0
- package/dist/chunks/chunk-PSOVLGHP.js +7 -0
- package/dist/chunks/chunk-PUKYAALC.js +7 -0
- package/dist/chunks/chunk-PVASGBEF.js +7 -0
- package/dist/chunks/chunk-Q5ODLDCU.js +7 -0
- package/dist/chunks/chunk-Q7D7RGXM.js +7 -0
- package/dist/chunks/chunk-QB7F3UAP.js +7 -0
- package/dist/chunks/chunk-QHJLRTVY.js +7 -0
- package/dist/chunks/chunk-QMCHGGDX.js +10 -0
- package/dist/chunks/chunk-QZX7VG2V.js +9 -0
- package/dist/chunks/chunk-R6BEOVTU.js +7 -0
- package/dist/chunks/chunk-RLKS5G6C.js +12 -0
- package/dist/chunks/chunk-RM3ZDRYE.js +7 -0
- package/dist/chunks/chunk-RRDNKB2X.js +7 -0
- package/dist/chunks/chunk-RRREFECI.js +7 -0
- package/dist/chunks/chunk-RUXO73ON.js +7 -0
- package/dist/chunks/chunk-RW3X523R.js +8 -0
- package/dist/chunks/chunk-S3L2OHPO.js +7 -0
- package/dist/chunks/chunk-S4SJ7GIZ.js +7 -0
- package/dist/chunks/chunk-S5IWVPYT.js +32 -0
- package/dist/chunks/chunk-SACGQMVQ.js +13 -0
- package/dist/chunks/chunk-SCV7XEEO.js +7 -0
- package/dist/chunks/chunk-SF4E3AQ3.js +7 -0
- package/dist/chunks/chunk-SKYDLHEZ.js +7 -0
- package/dist/chunks/chunk-SLI2O5X7.js +63 -0
- package/dist/chunks/chunk-SXOSF4O6.js +39 -0
- package/dist/chunks/chunk-TAAWMNNL.js +7 -0
- package/dist/chunks/chunk-TG2RCYTH.js +7 -0
- package/dist/chunks/chunk-TKBORMUF.js +7 -0
- package/dist/chunks/chunk-TO5PJDEN.js +7 -0
- package/dist/chunks/chunk-TPNOSQZ3.js +15 -0
- package/dist/chunks/chunk-TZFDVQ72.js +27 -0
- package/dist/chunks/chunk-U4Z2MMOF.js +301 -0
- package/dist/chunks/chunk-U56NHYAH.js +7 -0
- package/dist/chunks/chunk-UJSW56GS.js +9 -0
- package/dist/chunks/chunk-UKQMYTWW.js +9 -0
- package/dist/chunks/chunk-ULHNMQ7C.js +7 -0
- package/dist/chunks/chunk-UNEGQPD3.js +7 -0
- package/dist/chunks/chunk-URPEIX6M.js +7 -0
- package/dist/chunks/chunk-UVHKXCR5.js +11 -0
- package/dist/chunks/chunk-V6Y6UK6B.js +43 -0
- package/dist/chunks/chunk-V7BEC3E4.js +10 -0
- package/dist/chunks/chunk-VMMMBWD3.js +7 -0
- package/dist/chunks/chunk-VOCZ34ON.js +7 -0
- package/dist/chunks/chunk-VQSLPYAF.js +7 -0
- package/dist/chunks/chunk-VT6RIZJH.js +7 -0
- package/dist/chunks/chunk-WBF36MYT.js +16 -0
- package/dist/chunks/chunk-WCWP4GBR.js +7 -0
- package/dist/chunks/chunk-WGXKX24Q.js +7 -0
- package/dist/chunks/chunk-X4762EE4.js +7 -0
- package/dist/chunks/chunk-XB4SKARZ.js +29 -0
- package/dist/chunks/chunk-XGTKHQTT.js +7 -0
- package/dist/chunks/chunk-XOETL6DB.js +96 -0
- package/dist/chunks/chunk-XP3FT56R.js +27 -0
- package/dist/chunks/chunk-XR6QY7RR.js +7 -0
- package/dist/chunks/chunk-XXXRTHTP.js +8 -0
- package/dist/chunks/chunk-XZV4BFM5.js +7 -0
- package/dist/chunks/chunk-Y6AGOERS.js +8 -0
- package/dist/chunks/chunk-YHPPP3SF.js +7 -0
- package/dist/chunks/chunk-YHQ7PPXP.js +7 -0
- package/dist/chunks/chunk-YK7XLFU2.js +24 -0
- package/dist/chunks/chunk-YN3C5BL5.js +7 -0
- package/dist/chunks/chunk-ZF27J6FQ.js +7 -0
- package/dist/chunks/chunk-ZFRNVIHI.js +7 -0
- package/dist/chunks/chunk-ZH6KHD55.js +20 -0
- package/dist/chunks/cjs-2SMN43VH.js +54 -0
- package/dist/chunks/clear-ZS4KQ7OT.js +8 -0
- package/dist/chunks/compile-vercel-config-3IYM2CHC.js +7 -0
- package/dist/chunks/config-N2SBVW4T.js +8 -0
- package/dist/chunks/config-ZFIC7N4D.js +7 -0
- package/dist/chunks/config-validator.mjs +1 -0
- package/dist/chunks/connect-git-provider-FS5Q2HO4.js +7 -0
- package/dist/chunks/constants-ICJL2EO5.js +7 -0
- package/dist/chunks/create-project-IKCB6MB2.js +7 -0
- package/dist/chunks/delete-2ZE2NVHI.js +10 -0
- package/dist/chunks/delete-AL57HZDQ.js +9 -0
- package/dist/chunks/detect-projects-OD4JEAW2.js +7 -0
- package/dist/chunks/detect-services-MOXTX5XG.js +7 -0
- package/dist/chunks/disable-MKI3BKNH.js +7 -0
- package/dist/chunks/discard-SI4H7ST3.js +14 -0
- package/dist/chunks/dist-33WTJLVQ.js +7 -0
- package/dist/chunks/dist-RXYNZPEA.js +7 -0
- package/dist/chunks/edit-DNWH6SPE.js +8 -0
- package/dist/chunks/edit-WYNWDFUJ.js +9 -0
- package/dist/chunks/enable-J6MMYPYF.js +7 -0
- package/dist/chunks/esm-33752ISR.js +7 -0
- package/dist/chunks/esm-4JKEE7PC.js +7 -0
- package/dist/chunks/esm-BYG5BWYH.js +9 -0
- package/dist/chunks/esm-DFFBNKNU.js +20 -0
- package/dist/chunks/esm-IF453UWS.js +7 -0
- package/dist/chunks/esm-LABWDJ72.js +7 -0
- package/dist/chunks/esm-TG37FXTU.js +9 -0
- package/dist/chunks/exec-OZSY46V6.js +16372 -0
- package/dist/chunks/export-MHSH7QCX.js +19 -0
- package/dist/chunks/fetch-proxy-45DGILKR.js +67 -0
- package/dist/chunks/future-FFOGTKMF.js +7 -0
- package/dist/chunks/generate-cert-for-deploy-YZKNGAEQ.js +7 -0
- package/dist/chunks/image-7METSS6F.js +7 -0
- package/dist/chunks/import-builders-GM2SERWV.js +7 -0
- package/dist/chunks/inspect-A7WJQQZO.js +15 -0
- package/dist/chunks/inspect-DI434TAM.js +19 -0
- package/dist/chunks/inspect-H2Q7XOWN.js +13 -0
- package/dist/chunks/inspect-H5JC2XKI.js +9 -0
- package/dist/chunks/inspect-IAWVHJXQ.js +20 -0
- package/dist/chunks/list-ELEUTZWJ.js +12 -0
- package/dist/chunks/list-INRPH25K.js +10 -0
- package/dist/chunks/list-WWU734RK.js +16 -0
- package/dist/chunks/login-R5NQRPQC.js +7 -0
- package/dist/chunks/login-ZF2TLCQB.js +9 -0
- package/dist/chunks/logs-UD7FEXZ7.js +7 -0
- package/dist/chunks/ls-5ZEAKKPQ.js +8 -0
- package/dist/chunks/ls-IXRLAJ4L.js +11 -0
- package/dist/chunks/ls-LIGIBVAT.js +12 -0
- package/dist/chunks/ls-MCQ2NS65.js +8 -0
- package/dist/chunks/ls-S5E2NQMI.js +12 -0
- package/dist/chunks/ls-V2ZSIVO3.js +12 -0
- package/dist/chunks/ls-VXH4QYF5.js +12 -0
- package/dist/chunks/mutate-OQWOKLIW.js +9 -0
- package/dist/chunks/notifications-KFZ333V5.js +7 -0
- package/dist/chunks/open-HH6K7ZRC.js +7 -0
- package/dist/chunks/openapi-JGYEFJJV.js +7 -0
- package/dist/chunks/permissions-ZSHKMXBZ.js +7 -0
- package/dist/chunks/pkg-EDJQLCNP.js +7 -0
- package/dist/chunks/plugin-offer-Z6FCPQFD.js +9 -0
- package/dist/chunks/prompt-missing-credentials-KOA7C4QC.js +7 -0
- package/dist/chunks/publish-FPNQ2US4.js +15 -0
- package/dist/chunks/pull-7OGOIKB3.js +7 -0
- package/dist/chunks/purchase-domain-if-available-F4LKHVBD.js +7 -0
- package/dist/chunks/push-NY3SIK2C.js +7 -0
- package/dist/chunks/query-JGPO7TNY.js +12 -0
- package/dist/chunks/reauthenticate-OZRQFR66.js +7 -0
- package/dist/chunks/reorder-4J2STFUS.js +10 -0
- package/dist/chunks/reply-EO4NTTPW.js +9 -0
- package/dist/chunks/repo-info-to-url-XQSULSEO.js +7 -0
- package/dist/chunks/resolve-RPHHRPNM.js +12 -0
- package/dist/chunks/resolve-agent-team-KX77HEAF.js +7 -0
- package/dist/chunks/resolve-deployment-framework-preset-AXXYBFCL.js +7 -0
- package/dist/chunks/restore-TEA6TSVK.js +16 -0
- package/dist/chunks/rm-BPILSPUI.js +8 -0
- package/dist/chunks/rm-F6XVUDBM.js +8 -0
- package/dist/chunks/rm-JCPXV2FN.js +8 -0
- package/dist/chunks/rm-LPQRGX7N.js +8 -0
- package/dist/chunks/rm-WHUGT6TE.js +8 -0
- package/dist/chunks/routes-P6LKQCWH.js +7 -0
- package/dist/chunks/rule-inspect-BOETGPFO.js +8 -0
- package/dist/chunks/schema-BEUO7G52.js +44 -0
- package/dist/chunks/schema-YOEAK4VX.js +14 -0
- package/dist/chunks/select-org-OMLGQEKK.js +7 -0
- package/dist/chunks/set-5XY27S7R.js +7 -0
- package/dist/chunks/setup-and-link-A7M3QT52.js +7 -0
- package/dist/chunks/skills-4J2NC2QI.js +590 -0
- package/dist/chunks/slugify-NMMUASYK.js +7 -0
- package/dist/chunks/stamp-TKONNIJ5.js +7 -0
- package/dist/chunks/tags-ZXZQEXOV.js +7 -0
- package/dist/chunks/token-W6P2KNI5.js +7 -0
- package/dist/chunks/token-util-JDQI37VN.js +7 -0
- package/dist/chunks/types-SK6J2HFE.js +14 -0
- package/dist/chunks/update-25CKNOY5.js +8 -0
- package/dist/chunks/update-route-version-KWK5S4UW.js +7 -0
- package/dist/chunks/utils-IQZEE4DT.js +86 -0
- package/dist/chunks/vlt-builder-graph-XL2XRO4V.js +7 -0
- package/dist/chunks/vlt-builder-importer-RBUPAB6J.js +11 -0
- package/dist/chunks/zod-2C2SXNIK.js +7 -0
- package/dist/commands/build/builder-worker.cjs +281 -0
- package/dist/commands/build/index.js +34 -0
- package/dist/commands/deploy/index.js +72 -0
- package/dist/commands/dev/builder-worker.cjs +110 -0
- package/dist/commands/dev/index.js +157 -0
- package/dist/commands/env/index.js +40 -0
- package/dist/commands/link/index.js +10 -0
- package/dist/commands/list/index.js +14 -0
- package/dist/commands/project/index.js +113 -0
- package/dist/commands-account.js +209 -0
- package/dist/commands-ai.js +200 -0
- package/dist/commands-blob.js +107 -0
- package/dist/commands-core.js +222 -0
- package/dist/commands-deployments.js +84 -0
- package/dist/commands-flags.js +377 -0
- package/dist/commands-integrations.js +143 -0
- package/dist/commands-observability.js +122 -0
- package/dist/commands-routing.js +273 -0
- package/dist/fetch-dist-tags.cjs +60 -0
- package/dist/get-latest-worker.cjs +222 -0
- package/dist/help.js +7 -0
- package/dist/index.js +25 -0
- package/dist/internal-build-worker.js +10 -0
- package/dist/internal-build.js +11 -0
- package/dist/package.json +265 -0
- package/dist/root-help-commands.mjs +1 -0
- package/dist/runtime-assets/dev-tunnel/api/tunnel.ts +443 -0
- package/dist/runtime-assets/dev-tunnel/lib/env.ts +25 -0
- package/dist/runtime-assets/dev-tunnel/lib/tunnel_pb.ts +505 -0
- package/dist/runtime-assets/node-preloads/next-dev-websocket.cjs +220 -0
- package/dist/vc.js +393 -0
- package/dist/version.mjs +2 -0
- package/package.json +224 -14
- package/index.js +0 -1
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module';
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname as __dirname_ } from 'node:path';
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __dirname_(__filename);
|
|
7
|
+
import{FILTER_DEPRECATION_WARNING,alignTimeRangeToGranularity,canonicalResponseToMetricsResponse,createCanonicalMetricsRequest,usesODataSyntax}from"./chunks/chunk-LCHECISY.js";import{init_dist,prepareFlagsDefinitions}from"./chunks/chunk-OAM5NJCU.js";import{EncryptJWT,base64url_exports,jwtDecrypt}from"./chunks/chunk-S3L2OHPO.js";import{require_fast_deep_equal}from"./chunks/chunk-MCRKBVZA.js";import{sanitizeForTerminal}from"./chunks/chunk-5RMIM4S2.js";import{getLinkedFlagsProject,getProjectNameFromFlags}from"./chunks/chunk-ULHNMQ7C.js";import{parseSubcommandArguments,requireProjectContext}from"./chunks/chunk-NEFDNROD.js";import{computeGranularity,formatText,generateSparkline}from"./chunks/chunk-WBF36MYT.js";import{OBSERVABILITY_METRICS_PATH,getRollupColumnName,handleApiError}from"./chunks/chunk-FDNYYENK.js";import"./chunks/chunk-IVSSTHB6.js";import{require_dist}from"./chunks/chunk-JELLVPCM.js";import{readStdinText}from"./chunks/chunk-PSOVLGHP.js";import{require_raw_body}from"./chunks/chunk-XOETL6DB.js";import{normalizeRepeatableStringFilters,outputError,resolveTimeRange,validateIntegerRangeWithDefault,validateTimeBound,validateTimeOrder}from"./chunks/chunk-RW3X523R.js";import{ellipsizeMiddle,truncateEnd}from"./chunks/chunk-ID663OJ7.js";import{formatDate}from"./chunks/chunk-HRR57QNP.js";import{formatTable}from"./chunks/chunk-LSQREJXO.js";import{stamp_default}from"./chunks/chunk-A2RZZQEP.js";import"./chunks/chunk-Q7D7RGXM.js";import"./chunks/chunk-GZNDA6SV.js";import{resolveProjectContext}from"./chunks/chunk-3JGBBS6V.js";import{STANDARD_ENVIRONMENTS}from"./chunks/chunk-7YKFF6CE.js";import{formatProject}from"./chunks/chunk-6OVX3PWM.js";import{require_open}from"./chunks/chunk-PVASGBEF.js";import"./chunks/chunk-BL3HBRF6.js";import"./chunks/chunk-7EJQLVWX.js";import{readOnOffOption}from"./chunks/chunk-IKQTP764.js";import{canPrompt}from"./chunks/chunk-IQ7FPAI4.js";import{getCommandFlags}from"./chunks/chunk-XGTKHQTT.js";import{printNextPageCommand}from"./chunks/chunk-QMCHGGDX.js";import"./chunks/chunk-PFD7LETF.js";import{getInvalidSubcommand}from"./chunks/chunk-TG2RCYTH.js";import{getSubcommand}from"./chunks/chunk-ETV3C2CV.js";import{FLAG_ATTRIBUTE_TYPES,FLAG_CONDITION_LIST_COMPARATORS,FLAG_CONDITION_RHS_OPTIONAL_COMPARATORS,FLAG_EVALUATIONS_DIMENSIONS,FLAG_EVALUATIONS_DIMENSION_NAMES,FLAG_EVALUATIONS_GRANULARITIES,alertsInspectSubcommand,alertsListSubcommand,alertsSubcommand,archiveSubcommand,attackModeDisableSubcommand,attackModeEnableSubcommand,attackModeSubcommand,botManagementSubcommand,connectionsAddSubcommand,connectionsListSubcommand,connectionsRemoveSubcommand,connectionsSubcommand,createSubcommand6 as createSubcommand,datafileSubcommand,diffSubcommand,disableSubcommand,discardSubcommand,enableSubcommand2 as enableSubcommand,entitiesCreateSubcommand,entitiesListSubcommand,entitiesRemoveSubcommand,entitiesSubcommand,entitiesUpdateSubcommand,evaluationsSubcommand,feedbackCommand,firewallCommand,flagsCommand,formatFlagAttributeTypeList,formatFlagConditionComparator,formatFlagConditionComparatorList,getCommandAliases,getFlagAttributeType,inspectSubcommand9 as inspectSubcommand,ipBlocksBlockSubcommand,ipBlocksListSubcommand,ipBlocksSubcommand,ipBlocksUnblockSubcommand,isBucketingAttribute,isFlagAttributeType,isFlagEvaluationsDimension,isFlagEvaluationsGranularity,isTimestampAttributeType,labelsListSubcommand,labelsSubcommand,listSubcommand14 as listSubcommand,openSubcommand3 as openSubcommand,overrideSubcommand,overviewSubcommand,persistentActionsInspectSubcommand,persistentActionsListSubcommand,persistentActionsSubcommand,prepareSubcommand,publishSubcommand,removeSubcommand8 as removeSubcommand,rolloutSubcommand,rulesAddSubcommand2 as rulesAddSubcommand,rulesAddSubcommand3 as rulesAddSubcommand2,rulesDisableSubcommand,rulesEditSubcommand2 as rulesEditSubcommand,rulesEnableSubcommand,rulesInspectSubcommand,rulesListSubcommand2 as rulesListSubcommand,rulesListSubcommand3 as rulesListSubcommand2,rulesMoveSubcommand,rulesRemoveSubcommand2 as rulesRemoveSubcommand,rulesRemoveSubcommand3 as rulesRemoveSubcommand2,rulesReorderSubcommand,rulesSubcommand2 as rulesSubcommand,rulesSubcommand3 as rulesSubcommand2,rulesUpdateSubcommand,sdkKeysAddSubcommand,sdkKeysListSubcommand,sdkKeysRemoveSubcommand,sdkKeysSubcommand,segmentsCreateSubcommand,segmentsInspectSubcommand,segmentsListSubcommand,segmentsRemoveSubcommand,segmentsSubcommand,segmentsUpdateSubcommand,setSubcommand2 as setSubcommand,splitSubcommand,staleSubcommand,statusSubcommand,systemBypassAddSubcommand,systemBypassListSubcommand,systemBypassRemoveSubcommand,systemBypassSubcommand,systemMitigationsPauseSubcommand,systemMitigationsResumeSubcommand,systemMitigationsSubcommand,targetingEnableSubcommand,targetingSubcommand,targetsAddSubcommand,targetsListSubcommand,targetsRemoveSubcommand,targetsSubcommand,trafficInspectSubcommand,trafficListSubcommand,trafficSubcommand,unarchiveSubcommand,updateSubcommand5 as updateSubcommand,useTargetingSubcommand,versionsDiffSubcommand,versionsListSubcommand,versionsSubcommand}from"./chunks/chunk-TPNOSQZ3.js";import"./chunks/chunk-LUBUI5GF.js";import"./chunks/chunk-GVTXA6HG.js";import"./chunks/chunk-5IASAERQ.js";import"./chunks/chunk-WGXKX24Q.js";import"./chunks/chunk-E2SADN6I.js";import"./chunks/chunk-ABZEMNDR.js";import"./chunks/chunk-3AYYFYZG.js";import"./chunks/chunk-76KGQU2G.js";import"./chunks/chunk-UNEGQPD3.js";import"./chunks/chunk-YHQ7PPXP.js";import"./chunks/chunk-NQWGRKF4.js";import"./chunks/chunk-IGDG5CWT.js";import"./chunks/chunk-QZX7VG2V.js";import"./chunks/chunk-3ADDGPEN.js";import"./chunks/chunk-B4YYOSPY.js";import"./chunks/chunk-PFNYWWLI.js";import"./chunks/chunk-NTZ5WWYV.js";import"./chunks/chunk-JALVF3C2.js";import"./chunks/chunk-LJBUJ23M.js";import"./chunks/chunk-OKEBIUKZ.js";import{help}from"./chunks/chunk-KH6565YH.js";import{table}from"./chunks/chunk-773GOZIR.js";import{printError}from"./chunks/chunk-G4T7VBGN.js";import"./chunks/chunk-67GZ5REA.js";import"./chunks/chunk-BS32OUOC.js";import{TelemetryClient}from"./chunks/chunk-2PKEEQ5W.js";import"./chunks/chunk-PUKYAALC.js";import{getScope}from"./chunks/chunk-B4UE4LVE.js";import{require_ms}from"./chunks/chunk-MXTC4ZAQ.js";import"./chunks/chunk-NWGBDBZI.js";import"./chunks/chunk-FGFLTLEA.js";import{AGENT_REASON,AGENT_STATUS,buildCommandWithGlobalFlags,buildCommandWithYes,clientObservabilityPlanRecovery,getExitCodeForReason,outputAgentError,shouldEmitNonInteractiveCommandError,writeActionRequired,writeAgentError}from"./chunks/chunk-DGYHWXD2.js";import"./chunks/chunk-IUXSJWL3.js";import{getProjectByNameOrId,require_pluralize,ua_default}from"./chunks/chunk-KNLGWGUE.js";import{formatAlignedLabel,printAlignedLabel}from"./chunks/chunk-ADLBLGT3.js";import"./chunks/chunk-BBKEP7RO.js";import"./chunks/chunk-4NTBYNFR.js";import{parseArguments}from"./chunks/chunk-VOCZ34ON.js";import{quoteArg,teamCache}from"./chunks/chunk-F53OKXYI.js";import{SDK_KEY_PATTERN,getFlagsSpecification,getGlobalFlagsFromArgs,getProjectOptionFromArgs,warnDeprecatedInput,warnDeprecatedOption,warnDeprecatedSubcommand}from"./chunks/chunk-AWMQGOS2.js";import{fetch,toNodeReadable}from"./chunks/chunk-FUX6LKNP.js";import"./chunks/chunk-OPORM35X.js";import"./chunks/chunk-4SAVH3H7.js";import{ProjectNotFound,isAPIError}from"./chunks/chunk-6VH56CX2.js";import{cmd,getCommandName,getCommandNamePlain,packageName}from"./chunks/chunk-JESNVRVR.js";import{output_manager_default,recordCliError}from"./chunks/chunk-XP3FT56R.js";import"./chunks/chunk-BLUPZPAS.js";import"./chunks/chunk-RM3ZDRYE.js";import{pkg_default}from"./chunks/chunk-OO572JUC.js";import"./chunks/chunk-D3AHZ5LI.js";import"./chunks/chunk-2GHZGOWT.js";import"./chunks/chunk-YHPPP3SF.js";import{require_source}from"./chunks/chunk-NB2WLB3J.js";import"./chunks/chunk-ISWW3DKF.js";import"./chunks/chunk-BRQUZ5NC.js";import{__toESM}from"./chunks/chunk-BZENIQ7N.js";var import_raw_body=__toESM(require_raw_body(),1);var FeedbackTelemetryClient=class extends TelemetryClient{trackCliArgumentNote(note){note!==void 0&&this.trackCliArgument({arg:"note",value:this.redactedValue})}trackCliOptionField(fields){fields?.length&&this.trackCliOption({option:"field",value:this.redactedValue})}};var FEEDBACK_URL="https://vercel.com/api/feedback/cli",MAX_FEEDBACK_BYTES=1024*1024,FETCH_TIMEOUT_MS=1e4;async function feedback(client){let fail=(reason,message,code)=>(recordCliError({code:reason}),output_manager_default.error(message),code),parsed;try{parsed=parseArguments(client.argv.slice(2),getFlagsSpecification(feedbackCommand.options))}catch{return fail(AGENT_REASON.INVALID_ARGUMENTS,"Invalid feedback arguments. Run vercel feedback --help for usage.",2)}let notes=parsed.args.slice(1),fields=parsed.flags["--field"]??[];if(notes.length===0&&fields.length===0)return client.stdout.write(help(feedbackCommand,{columns:client.stderr.columns})),0;if(notes.length>1)return fail(AGENT_REASON.INVALID_ARGUMENTS,"Pass one note. Quote notes containing spaces, or use vercel feedback - to read stdin.",2);let telemetry=new FeedbackTelemetryClient({opts:{store:client.telemetryEventStore}});telemetry.trackCliArgumentNote(notes[0]),telemetry.trackCliOptionField(fields);let data=Object.create(null);for(let field of fields){let separator=field.indexOf("="),key=field.slice(0,separator).trim();if(separator<1||key==="")return fail(AGENT_REASON.INVALID_ARGUMENTS,"Each --field needs a non-empty key followed by =value. Example: vercel feedback --field topic=deploy.",2);data[key]=field.slice(separator+1)}if(notes.length&&Object.hasOwn(data,"note"))return fail(AGENT_REASON.INVALID_ARGUMENTS,"Provide the note once: use a positional note or --field note=..., rather than both.",2);if(notes[0]==="-"){if(client.stdin.isTTY)return fail(AGENT_REASON.INVALID_ARGUMENTS,"No input was piped to stdin. Pipe a note with: cat notes.md | vercel feedback -",2);try{data.note=await readStdinText(client.stdin,MAX_FEEDBACK_BYTES)}catch(error){return error.type==="entity.too.large"?fail(AGENT_REASON.INVALID_ARGUMENTS,"Feedback is too large. Keep the complete submission below 1 MiB.",2):fail(AGENT_REASON.STDIN_ERROR,"Could not read the feedback note from stdin. Check the input pipe and try again.",1)}}else notes[0]!==void 0&&(data.note=notes[0]);for(let key of Object.keys(data))data[key].trim()||delete data[key];if(!Object.keys(data).length)return fail(AGENT_REASON.INVALID_ARGUMENTS,"Provide a note or at least one named field. Run vercel feedback --help for examples.",2);let canSendTelemetry=client.telemetryEventStore?.enabled??!1,body=JSON.stringify({metadata:canSendTelemetry?{agent:client.isAgent,agent_name:client.isAgent?client.agentName:void 0,cli_version:pkg_default.version,operating_system:process.platform,team_id:client.config.currentTeam??null,user_id:client.authConfig.userId??null,invocation_id:client.telemetryEventStore?.currentInvocationId??null,session_id:client.telemetryEventStore?.currentSessionId??null}:null,data});if(Buffer.byteLength(body)>MAX_FEEDBACK_BYTES)return fail(AGENT_REASON.INVALID_ARGUMENTS,"Feedback is too large. Keep the complete submission below 1 MiB.",2);let controller=new AbortController,timeout=setTimeout(()=>controller.abort(),FETCH_TIMEOUT_MS);timeout.unref?.();try{let response=await fetch(FEEDBACK_URL,{method:"POST",headers:{"content-type":"application/json","user-agent":ua_default},body,redirect:"manual",signal:controller.signal});if(!response.ok)return await response.body?.cancel(),fail(response.status===429?AGENT_REASON.RATE_LIMITED:AGENT_REASON.API_ERROR,`Feedback could not be submitted (HTTP ${response.status}). Try again later.`,1);let responseBody=toNodeReadable(response.body);return JSON.parse(await(0,import_raw_body.default)(responseBody,{limit:64*1024,encoding:"utf8"}).finally(()=>responseBody.destroy()))?.success!==!0?fail(AGENT_REASON.UNKNOWN_OUTCOME,"Could not confirm that Vercel accepted the feedback. It may have been submitted; no automatic retry was made.",1):(client.stdout.write(`Feedback sent
|
|
8
|
+
`),0)}catch{return fail(AGENT_REASON.UNKNOWN_OUTCOME,"Could not confirm that Vercel accepted the feedback. Check your connection. It may have been submitted; no automatic retry was made.",1)}finally{clearTimeout(timeout)}}var import_chalk6=__toESM(require_source(),1);var import_chalk2=__toESM(require_source(),1);var import_chalk=__toESM(require_source(),1);var ACTION_COLORS={allow:import_chalk.default.blue,deny:import_chalk.default.red,challenge:import_chalk.default.yellow,log:import_chalk.default.magenta,rate_limit:import_chalk.default.cyan,"rate-limit":import_chalk.default.cyan,bypass:import_chalk.default.green};function labelForAction(action){return action==="rate_limit"||action==="rate-limit"?"Rate Limited":action.split(/[-_]/).filter(Boolean).map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join(" ")}var MONTHS=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function formatCount(n){return n>=1e6?`${(n/1e6).toFixed(1)}M`:n>=1e3?`${(n/1e3).toFixed(1)}k`:String(Math.round(n))}function pad2(n){return String(n).padStart(2,"0")}function formatUtcTime(ms8,withDate){let d=new Date(ms8),hm=`${pad2(d.getUTCHours())}:${pad2(d.getUTCMinutes())}`;return withDate?`${MONTHS[d.getUTCMonth()]} ${d.getUTCDate()} ${hm}`:hm}function relativeTime(ts){let diff2=Date.now()-ts;return diff2<6e4?"just now":diff2<36e5?`${Math.floor(diff2/6e4)}m ago`:diff2<864e5?`${Math.floor(diff2/36e5)}h ago`:`${Math.floor(diff2/864e5)}d ago`}function formatUtcDateTime(ms8){return`${formatUtcTime(ms8,!0)} UTC (${relativeTime(ms8)})`}function colorizeDetail(detail){return detail.split(" \xB7 ").map(part=>{let color=ACTION_COLORS[part.toLowerCase().replace(/ /g,"_")];return color?color(part):part}).join(" \xB7 ")}function windowNeedsDate(startMs,endMs){return endMs-startMs>25*36e5}function granularityLabel(granularity){return"minutes"in granularity?`${granularity.minutes}m`:"hours"in granularity?`${granularity.hours}h`:`${granularity.days}d`}function formatActionTrendTable(series){let allTs=new Set;for(let s of series)for(let p of s.timeseries)allTs.add(p.timestamp);let axis=[...allTs].sort(),hasAnyTraffic=series.some(s=>s.total>0||s.timeseries.some(p=>p.value>0));if(series.length===0||axis.length===0||!hasAnyTraffic)return import_chalk.default.dim(" No request data for this period.");let startMs=new Date(axis[0]).getTime(),endMs=new Date(axis[axis.length-1]).getTime(),needsDate=windowNeedsDate(startMs,endMs),rows=[["Action","Trend","Total","Peak","Peak at"].map(h=>import_chalk.default.bold(import_chalk.default.cyan(h)))];for(let s of series){let byTs=new Map(s.timeseries.map(p=>[p.timestamp,p.value])),values=axis.map(t=>byTs.get(t)??0),peak=0,peakTs="";for(let i=0;i<axis.length;i++)values[i]>peak&&(peak=values[i],peakTs=axis[i]);let plain=x=>x,color=s.total>0?ACTION_COLORS[s.action]??plain:import_chalk.default.dim,trend=s.total>0?plain:import_chalk.default.dim;rows.push([color(labelForAction(s.action)),trend(generateSparkline(values)),formatCount(s.total),peak>0?formatCount(peak):"--",peak>0?formatUtcTime(new Date(peakTs).getTime(),needsDate):"--"])}return table(rows,{align:["l","l","r","r","r"],hsep:3}).split(`
|
|
9
|
+
`).map(line2=>` ${line2}`.trimEnd()).join(`
|
|
10
|
+
`)}var NO_SERVER_MESSAGE="Response Error";function apiServerMessage(error){let message=isAPIError(error)?error.serverMessage:void 0;return message&&message!==NO_SERVER_MESSAGE?message:void 0}var FIREWALL_O11Y_ALERT_TYPES=["botId_anomaly","firewallSystemRule_anomaly","firewallCustomRule_anomaly"],FIREWALL_ANOMALY_TYPE="firewall_anomaly",SYS_DOS_MITIGATION_RULE_ID="sys_dos_mitigation",SYSTEM_RULE_ANOMALY_TYPE="firewallSystemRule_anomaly",FIREWALL_ACTIVITY_PLAN_MESSAGE="Traffic and alerts need Observability Plus.",FIREWALL_ALERTS_PARTIAL_ERROR_MESSAGE="Couldn't load every alert source.";function reduceAttackAnomaly(anomaly){return Object.keys(anomaly.affectedHostMap).reduce((acc,host)=>{acc.hosts.push(host);let challenged=anomaly.affectedHostMap[host].ddosAlerts?.["sys_dos_mitigation:challenge"]?.totalReqs||0,denied=anomaly.affectedHostMap[host].ddosAlerts?.["sys_dos_mitigation:deny"]?.totalReqs||0;return acc.challenged+=challenged,acc.denied+=denied,acc.count+=challenged+denied,acc},{hosts:[],challenged:0,denied:0,count:0})}function hostsFromAnomaly(anomaly){return Object.entries(anomaly.affectedHostMap).map(([host,data])=>{let challenged=data.ddosAlerts?.["sys_dos_mitigation:challenge"]?.totalReqs||0,denied=data.ddosAlerts?.["sys_dos_mitigation:deny"]?.totalReqs||0;return{name:host,count:challenged+denied}}).filter(row=>row.count>0).sort((a,b)=>b.count-a.count)}function mapAttackAnomaly(anomaly){let reduced=reduceAttackAnomaly(anomaly),parts=["System rule"];return reduced.denied>0&&parts.push(labelForAction("deny")),reduced.challenged>0&&parts.push(labelForAction("challenge")),{id:`${anomaly.ownerId}-${anomaly.projectId}-${anomaly.startTime}`,title:"DDoS Mitigation",type:FIREWALL_ANOMALY_TYPE,startedAt:anomaly.startTime,resolvedAt:anomaly.endTime||void 0,count:reduced.count,detail:parts.join(" \xB7 "),action:reduced.denied>=reduced.challenged?"deny":"challenge",ruleId:SYS_DOS_MITIGATION_RULE_ID,host:reduced.hosts[0]}}function mapO11yAlert(alert){if(!alert.startedAt)return null;let action=alert.data?.action,ruleId=alert.data?.ruleId,detailParts=[alert.type,action?labelForAction(action):void 0,ruleId].filter(Boolean);return{id:alert.id||`${alert.type}-${alert.startedAt}`,title:alert.title||alert.type||"Firewall alert",type:alert.type||"unknown",startedAt:alert.startedAt,resolvedAt:alert.resolvedAt,count:alert.data?.count,detail:detailParts.filter(p=>p!==alert.title).join(" \xB7 ")||void 0,action,ruleId,path:alert.data?.path}}var ATTACK_STATUS_MAX_DAYS=7;async function getAttackStatus(client,opts){let query=new URLSearchParams;if(query.set("projectId",opts.projectId),query.set("teamId",opts.teamId),opts.sinceDays!==void 0){let sinceDays=Math.min(ATTACK_STATUS_MAX_DAYS,Math.max(1,Math.ceil(opts.sinceDays)));query.set("since",String(sinceDays))}return client.fetch(`/v1/security/firewall/attack-status?${query.toString()}`,{accountId:opts.teamId,signal:opts.signal})}var O11Y_ALERTS_LIMIT=200;async function getFirewallO11yAlerts(client,opts){let query=new URLSearchParams;query.set("teamId",opts.teamId),query.set("projectId",opts.projectId),query.set("from",opts.from.toISOString()),query.set("to",opts.to.toISOString()),query.set("limit",String(O11Y_ALERTS_LIMIT));for(let type of FIREWALL_O11Y_ALERT_TYPES)query.append("types",type);return(await client.fetch(`/alerts/v3/groups?${query.toString()}`,{accountId:opts.teamId,signal:opts.signal})).flatMap(g=>g.alerts??[]).map(mapO11yAlert).filter(a=>a!==null)}var ALERTS_TIMEOUT_MS=2e4;function sourceFailureReason(err){return isAPIError(err)&&err.status===408||err instanceof Error&&(err.name==="TimeoutError"||err.name==="AbortError")?"timed out":isAPIError(err)&&err.status===402?"needs Observability Plus":isAPIError(err)&&typeof err.status=="number"?`HTTP ${err.status}`:err instanceof Error&&err.message?err.message:"unknown error"}function resolveAlertsWindow(opts){let now=Date.now(),to=opts.to??new Date(now),from=opts.from??new Date(to.getTime()-864e5*(opts.sinceDays??1)),sinceDays=opts.sinceDays??Math.max(1,Math.ceil((now-from.getTime())/864e5));return{from,to,sinceDays}}function classifyAlertSourceError(err){if(isAPIError(err)&&(err.status===401||err.status===403))throw err;return isAPIError(err)&&err.status===402?{reason:"plan",message:FIREWALL_ACTIVITY_PLAN_MESSAGE}:{reason:"error",message:apiServerMessage(err)||!isAPIError(err)&&err instanceof Error&&err.message||FIREWALL_ALERTS_PARTIAL_ERROR_MESSAGE}}async function getFirewallAlertsDetailed(client,opts){let{from,to,sinceDays}=resolveAlertsWindow(opts),timeoutMs=opts.timeoutMs??ALERTS_TIMEOUT_MS,signal=AbortSignal.timeout(timeoutMs),[o11yResult,attackResult]=await Promise.allSettled([getFirewallO11yAlerts(client,{...opts,from,to,signal}),getAttackStatus(client,{...opts,sinceDays,signal})]),errors=[],o11yAlerts=[],o11y;o11yResult.status==="fulfilled"?o11yAlerts=o11yResult.value:(o11y=classifyAlertSourceError(o11yResult.reason),errors.push({source:"alerts",message:sourceFailureReason(o11yResult.reason)}));let mappedAttacks=[],attackStatus;attackResult.status==="fulfilled"?mappedAttacks=(attackResult.value.anomalies||[]).map(mapAttackAnomaly):(attackStatus=classifyAlertSourceError(attackResult.reason),errors.push({source:"attackStatus",message:sourceFailureReason(attackResult.reason)}));let resolvedCutoff=from.getTime();return{alerts:mappedAttacks.concat(o11yAlerts.filter(a=>!a.resolvedAt||a.resolvedAt>resolvedCutoff)).sort((a,b)=>!a.resolvedAt&&b.resolvedAt?-1:a.resolvedAt&&!b.resolvedAt?1:b.startedAt-a.startedAt),o11y,attackStatus,errors}}function alertsIncompleteMessage(errors){return`Attack count and alerts may be incomplete: ${errors.map(e=>`${e.source==="alerts"?"alerts":"attack history"} ${e.message}`).join("; ")}.`}function countAttacksMitigated(alerts,windowStartMs,windowEndMs){return alerts.filter(alert=>isAttackAlert(alert)&&alertOverlapsWindow(alert,windowStartMs,windowEndMs)).length}function alertOverlapsWindow(alert,windowStartMs,windowEndMs){return alert.startedAt<=windowEndMs&&(alert.resolvedAt??Number.POSITIVE_INFINITY)>=windowStartMs}function isAttackAlert(alert){return alert.type===FIREWALL_ANOMALY_TYPE?!0:alert.type===SYSTEM_RULE_ANOMALY_TYPE&&alert.ruleId===SYS_DOS_MITIGATION_RULE_ID}var O11Y_ALERT_ID_PREFIX="al_",INSPECT_FALLBACK_DAYS=7;function isO11yAlertId(id){return id.startsWith(O11Y_ALERT_ID_PREFIX)}function parseLegacyAlertStartTime(id){let match=id.match(/-(\d{13})$/);return match?Number(match[1]):void 0}function daysCovering(startMs,endMs){return Math.max(1,Math.ceil((endMs-startMs)/864e5))}function mapGroupAsAlert(group,alertId){let nested=(group.alerts??[]).map(mapO11yAlert).filter(a=>a!==null),hit=nested.find(a=>a.id===alertId)??nested[0];if(hit)return hit;let startedAt=group.recordedStartedAt;return startedAt?mapO11yAlert({id:alertId,title:group.title,type:group.type,startedAt,resolvedAt:group.recordedResolvedAt,data:group.alerts?.[0]?.data}):null}async function getO11yAlertById(client,opts){let query=new URLSearchParams;query.set("teamId",opts.teamId),query.set("projectId",opts.projectId);try{let group=await client.fetch(`/alerts/v3/groups/${encodeURIComponent(opts.alertId)}?${query.toString()}`,{accountId:opts.teamId,signal:opts.signal});return mapGroupAsAlert(group,opts.alertId)}catch(err){if(isAPIError(err)&&err.status===404)return null;throw err}}async function findFirewallAlert(client,opts){let timeoutMs=opts.timeoutMs??ALERTS_TIMEOUT_MS,budget=()=>AbortSignal.timeout(timeoutMs),now=Date.now();if(isO11yAlertId(opts.alertId)){let fromGroup2=await getO11yAlertById(client,{...opts,signal:budget()});if(fromGroup2)return{alert:fromGroup2};let from=new Date(now-864e5*INSPECT_FALLBACK_DAYS),hit=(await getFirewallO11yAlerts(client,{projectId:opts.projectId,teamId:opts.teamId,from,to:new Date(now),signal:budget()})).find(a=>a.id===opts.alertId);return hit?{alert:hit}:null}let startTime=parseLegacyAlertStartTime(opts.alertId),sinceDays=startTime?daysCovering(startTime,now)+1:INSPECT_FALLBACK_DAYS,anomaly=((await getAttackStatus(client,{projectId:opts.projectId,teamId:opts.teamId,sinceDays,signal:budget()}).catch(err=>{if(isAPIError(err)&&(err.status===401||err.status===403))throw err;return{anomalies:[]}})).anomalies||[]).find(a=>`${a.ownerId}-${a.projectId}-${a.startTime}`===opts.alertId);if(anomaly)return{alert:mapAttackAnomaly(anomaly),hosts:hostsFromAnomaly(anomaly)};let fromGroup=await getO11yAlertById(client,{...opts,signal:budget()}).catch(err=>{if(isAPIError(err)&&(err.status===401||err.status===403))throw err;return null});return fromGroup?{alert:fromGroup}:null}var MANAGED_BOT_RULE_IDS=["bot-protection","ai-bots","bot-id"],ALIASES={"bot-protection":"bot-protection","bot protection":"bot-protection",bot_protection:"bot-protection",bot_filter:"bot-protection",managed_bot_protection:"bot-protection",managed_bot_filter:"bot-protection","ai-bots":"ai-bots","ai bots":"ai-bots",ai_bots:"ai-bots",managed_ai_bots:"ai-bots","bot-id":"bot-id",botid:"bot-id",bot_id:"bot-id"},ACTIONS={"bot-protection":["off","log","challenge"],"ai-bots":["allow","log","challenge","deny"],"bot-id":["basic","deep-analysis"]},NAMES={"bot-protection":"Bot Protection","ai-bots":"AI Bots","bot-id":"BotID"},WAF_RULE_IDS={"bot-protection":"managed_bot_protection","ai-bots":"managed_ai_bots"};function resolveManagedBotRuleId(identifier){if(identifier)return ALIASES[identifier.trim().toLowerCase()]}function managedBotActions(id){return ACTIONS[id]}function formatManagedBotAction(action){return action==="deep-analysis"?"Deep Analysis":action.charAt(0).toUpperCase()+action.slice(1)}function botProtectionConfig(managedRules){return managedRules?.bot_filter??managedRules?.bot_protection}function currentBotProtectionAction(config){let ruleset=botProtectionConfig(config?.managedRules);return ruleset?.active?ruleset.action==="log"?"log":"challenge":"off"}function currentAiBotsAction(config){let ruleset=config?.managedRules?.ai_bots;return ruleset?.active?ruleset.action==="challenge"?"challenge":ruleset.action==="deny"?"deny":"log":"allow"}function currentBotIdAction(config){return config?.botIdEnabled?"deep-analysis":"basic"}function getManagedBotRule(config,id){let action=id==="bot-protection"?currentBotProtectionAction(config):id==="ai-bots"?currentAiBotsAction(config):currentBotIdAction(config);return{id,name:NAMES[id],action,wafRuleId:WAF_RULE_IDS[id]}}function getManagedBotRules(config){return MANAGED_BOT_RULE_IDS.map(id=>getManagedBotRule(config,id))}function parseManagedBotAction(id,raw){let action=raw.trim().toLowerCase().replace(/\s+/g,"-"),valid=ACTIONS[id];return valid.includes(action)?{action}:{error:`Invalid action "${raw}" for ${NAMES[id]}. Use ${valid.join(", ")}.`}}function buildManagedBotPatch(id,action){if(id==="bot-id")return{action:"botId.toggle",value:action==="deep-analysis"};let patchId=id==="bot-protection"?"bot_protection":"ai_bots";return action==="off"||action==="allow"?{action:"managedRules.update",id:patchId,value:{active:!1}}:{action:"managedRules.update",id:patchId,value:{active:!0,action}}}function suggestedManagedBotAction(rule){return rule.id==="bot-protection"?rule.action==="challenge"?"log":"challenge":rule.id==="ai-bots"?rule.action==="deny"?"allow":"deny":rule.action==="deep-analysis"?"basic":"deep-analysis"}function managedBotTrafficWarning(id,from,to){if(id==="ai-bots"&&to==="deny")return"AI Bots deny blocks known AI crawlers from this project.";if(id==="bot-protection"&&from==="off"&&to==="challenge")return"Bot Protection challenge will present a verification page to non-browser traffic."}function managedBotJson(rule){return{id:rule.id,name:rule.name,action:rule.action,wafRuleId:rule.wafRuleId??null}}function projectScope(project,teamId,teamSlug){return{type:"project",projectId:project.id,teamId,...teamSlug?{teamSlug}:{},displayName:project.name}}function firewallConfigUrl(scope,path=""){let query=new URLSearchParams;return scope.type==="project"?(query.set("projectId",scope.projectId),scope.teamId&&query.set("teamId",scope.teamId),`/v1/security/firewall/config${path}?${query.toString()}`):(query.set("teamId",scope.teamId),`/v1/security/firewall/team-config${path}?${query.toString()}`)}async function listFirewallConfigs(client,scope){return client.fetch(firewallConfigUrl(scope))}async function activateFirewallConfig(client,scope,configVersion){return client.fetch(firewallConfigUrl(scope,`/${configVersion}/activate`),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({})})}var PRIORITY_PROJECT_ENABLE_COMMAND="project priority enable",BUY_PRO_COMMAND="buy pro";function withGlobalFlags(client,commandTemplate,scope,options={}){let template=scope?.type==="team"?`${commandTemplate} --team-level`:commandTemplate;return buildCommandWithGlobalFlags(client.argv,template,void 0,{globalFlags:"all",preserveProject:options.preserveProject??!0,excludeFlags:options.excludeFlags})}async function resolveFirewallScope(client,flags){if(flags["--team-level"]&&flags["--project"]){let message="Cannot specify both --team-level and --project. Use one or the other.";return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.INVALID_ARGUMENTS,message},2),2):(output_manager_default.error(message),2)}if(flags["--team-level"]){let{team}=await getScope(client);if(!team){let message="Team-level firewall requires a team scope. Personal accounts are not supported. Run `vercel switch` to select a team or pass --scope <team>.";return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_SCOPE,message},1),1):(output_manager_default.error(message),1)}return{type:"team",teamId:team.id,displayName:team.slug}}let link=await requireProjectContext(client,"firewall",flags["--project"]);if(typeof link=="number")return link;let{project,org}=link;return{type:"project",projectId:project.id,teamId:org.type==="team"?org.id:void 0,teamSlug:org.type==="team"?org.slug:void 0,displayName:project.name}}function mentionsPriorityProject(message){return/priority\s+project/i.test(message)||/priority\s+tier/i.test(message)}function teamPlan(scope){return scope.teamId?teamCache.get(scope.teamId)?.billing?.plan:void 0}function priorityTeam(scope){let cached=scope.teamId?teamCache.get(scope.teamId):void 0;if(scope.type==="team")return{id:scope.teamId,slug:scope.displayName,name:cached?.name??null,scopeArg:scope.displayName};if(!scope.teamId)return null;let slug=scope.teamSlug??cached?.slug??null;return{id:scope.teamId,slug,name:cached?.name??null,scopeArg:slug??scope.teamId}}function teamLabel(team){return team.name&&team.name!==team.slug?`${team.slug} (${team.name})`:team.slug}function styledCommand(command,plain){return plain?getCommandNamePlain(command):getCommandName(command)}function priorityProjectFix(scope){let excludeFlags=["--non-interactive","--project","--yes","--scope","--team"],project=scope.type==="project"?{id:scope.projectId,name:scope.displayName}:null,team=priorityTeam(scope),plan=teamPlan(scope)??null,data={project,team:team&&{id:team.id,slug:team.slug,name:team.name},plan},projectToken=project?quoteArg(project.name):"<project>",scopeFlag=team?` --scope ${quoteArg(team.scopeArg)}`:"",enable4=`${PRIORITY_PROJECT_ENABLE_COMMAND} ${projectToken}${scopeFlag}`;if(!team){let hint="Priority projects are only available on team accounts. Use --scope to specify one.";return{command:"",hint,plainHint:hint,when:hint,excludeFlags,preserveProject:!1,reason:AGENT_REASON.MISSING_SCOPE,data}}if(plan==="hobby"||plan==="oss"){let upgrade=`${BUY_PRO_COMMAND}${scopeFlag}`,hint=plain2=>`Priority Projects are only available on Pro or Enterprise team plans. Upgrade with ${styledCommand(upgrade,plain2)}, then run ${styledCommand(enable4,plain2)}.`;return{command:upgrade,hint:hint(!1),plainHint:hint(!0),when:"a person has approved upgrading the plan",excludeFlags,preserveProject:!1,reason:AGENT_REASON.PLAN_UPGRADE_REQUIRED,scope:team.scopeArg,data}}let shown=styledCommand(enable4,!1),plain=styledCommand(enable4,!0),placeholder="Replace <project> with a project on this team.";return{command:enable4,hint:project?shown:`${shown} ${placeholder}`,plainHint:project?plain:`${plain} ${placeholder}`,when:project?"user runs this command in an interactive terminal":"Replace <project> with a project on this team.",excludeFlags,preserveProject:!1,reason:AGENT_REASON.PLAN_UPGRADE_REQUIRED,scope:team.scopeArg,data}}function mapFirewallApiError(e,scope,fallback){let err=e;return scope.type==="team"&&err.status===403?err.code==="plan_not_supported"?`Team-level firewall requires an Enterprise plan (current team: "${scope.displayName}"). Pass --scope <team> or run \`vercel switch\` to target a different team.`:`You need to be a team owner to manage the team-level firewall for "${scope.displayName}".${err.message?` (${err.message})`:""}`:err.message||fallback}function priorityProjectMessage(scope,fix){let team=fix.data.team,label=team?.slug!=null?teamLabel({slug:team.slug,name:team.name}):void 0;return scope.type==="project"?label?`This rule requires a Priority project for ${scope.displayName} on team ${label}.`:`This rule requires a Priority project. ${fix.hint}`:label?`This rule requires a Priority project on team ${label}.`:"This rule requires a Priority project."}function failPriorityProjectGate(client,error,scope,opts){let serverMessage=apiServerMessage(error);if(!serverMessage||!mentionsPriorityProject(serverMessage))return null;let fix=priorityProjectFix(scope),message=priorityProjectMessage(scope,fix),payload={status:AGENT_STATUS.ERROR,reason:fix.reason,message,userActionRequired:!0,hint:fix.plainHint,retryable:!1,...fix.scope?{scope:fix.scope}:{},data:fix.data,...fix.command?{next:[{command:buildCommandWithGlobalFlags(client.argv,fix.command,packageName,{globalFlags:"all",preserveProject:!1,excludeFlags:fix.excludeFlags}),when:fix.when}]}:{}};return shouldEmitNonInteractiveCommandError(client)&&outputAgentError(client,payload,1),opts?.json?(output_manager_default.stopSpinner(),writeAgentError(client,payload),1):(output_manager_default.error(message),fix.command&&output_manager_default.log(fix.hint),1)}function getRulePayload(flags){let legacy=flags["--json"];return legacy!==void 0&&flags["--data"]!==void 0?(output_manager_default.error("Can't use --data with --json."),2):(legacy!==void 0&&output_manager_default.warning("--json is deprecated for rule payloads. Use --data."),flags["--data"]??legacy)}async function parseSubcommandArgs(argv,command,client,commandPath){let parsedArgs,fullPath=commandPath||command.name;try{parsedArgs=parseSubcommandArguments(argv,command)}catch(err){if(client?.nonInteractive){let rawMessage=err instanceof Error?err.message:String(err),flags=getGlobalFlagsFromArgs(client.argv.slice(2),{preserveProject:!0});return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.INVALID_ARGUMENTS,message:rawMessage,next:[{command:getCommandNamePlain(`firewall ${fullPath} ${flags.join(" ")}`.trim()),when:"fix flags and retry"}]},2),2}return printError(err),2}return parsedArgs}async function confirmAction(client,skipConfirmation,message,details){return skipConfirmation?!0:client.nonInteractive||!client.stdin.isTTY?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.CONFIRMATION_REQUIRED,message:`${message} Re-run with --yes to confirm.`,next:[{command:buildCommandWithYes(client.argv),when:"re-run with --yes to confirm"}]}),process.exit(1),!1):(details&&output_manager_default.print(` ${details}
|
|
11
|
+
`),await client.input.confirm(message,!1))}function firewallPermissionMessage(action,projectName){return`You don't have permission to ${action} for ${projectName}. Ask a team owner to grant access.`}function failFirewall(client,opts){let reason=opts.reason??AGENT_REASON.INVALID_ARGUMENTS,exitCode=getExitCodeForReason(reason);return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason,message:opts.message,...opts.fix?.hint?{hint:opts.fix.hint}:{},next:[...opts.fix?.command?[{command:withGlobalFlags(client,opts.fix.command,void 0,{excludeFlags:opts.fix.excludeFlags,preserveProject:opts.fix.preserveProject}),...opts.fix.when?{when:opts.fix.when}:{}}]:[],...opts.nextCommand?[{command:withGlobalFlags(client,opts.nextCommand)}]:[]]},exitCode),exitCode):(output_manager_default.error(opts.message),opts.fix&&output_manager_default.log(opts.fix.hint),exitCode)}function failFirewallObservabilityPlan(client,error,projectName){let message=apiServerMessage(error)??FIREWALL_ACTIVITY_PLAN_MESSAGE,fix=clientObservabilityPlanRecovery(client,error,message,projectName);return failFirewall(client,{message,fix,reason:AGENT_REASON.API_ERROR})}function refuseManagedBotMutation(client,scope,identifier,verb){if(scope.type!=="project")return null;let id=resolveManagedBotRuleId(identifier);if(!id)return null;let command=`firewall rules update ${id} --action <action>`;return failFirewall(client,{message:`Can't ${verb} "${identifier}". That's a managed bot rule.`,reason:AGENT_REASON.INVALID_ARGUMENTS,fix:{command,hint:`Use ${import_chalk2.default.cyan(withGlobalFlags(client,command,scope))} to change it.`,when:"change the managed bot rule instead"}})}function isRetryableApiError(error){return isAPIError(error)&&(error.status>=500||error.status===429)}function failFirewallApi(client,e,opts){if(isAPIError(e)&&(e.status===401||e.status===403))return failFirewall(client,{message:firewallPermissionMessage(opts.permissionAction,opts.projectName),reason:AGENT_REASON.PERMISSION_DENIED});if(e instanceof Error&&(e.name==="TimeoutError"||e.name==="AbortError")){let job=opts.timeoutJob??"firewall data";return failFirewall(client,{message:`Timed out waiting for ${job}. Re-run the command \u2014 the next try is usually faster.`,nextCommand:opts.nextCommand,reason:AGENT_REASON.API_ERROR})}let msg=e instanceof Error&&e.message?e.message:opts.fallback;return failFirewall(client,{message:msg,nextCommand:isRetryableApiError(e)?opts.nextCommand:void 0,reason:AGENT_REASON.API_ERROR})}function outputJson(client,data){output_manager_default.stopSpinner(),client.stdout.write(JSON.stringify(data,null,2)+`
|
|
12
|
+
`)}async function detectExistingDraft(client,scope){let{draft}=await listFirewallConfigs(client,scope);return draft!==null&&draft.changes.length>0}async function offerAutoPublish(client,scope,hadExistingDraft,opts){if(output_manager_default.print(`
|
|
13
|
+
${import_chalk2.default.gray(`This change is staged. Run ${import_chalk2.default.cyan(withGlobalFlags(client,"firewall publish",scope))} to make it live, or ${import_chalk2.default.cyan(withGlobalFlags(client,"firewall discard",scope))} to undo.`)}
|
|
14
|
+
`),!hadExistingDraft&&!opts.skipPrompts&&client.stdin.isTTY&&!client.nonInteractive){if(output_manager_default.print(`
|
|
15
|
+
`),await client.input.confirm("This is the only draft change. Publish to production now?",!1)){let publishStamp=stamp_default();output_manager_default.spinner("Publishing to production");try{await activateFirewallConfig(client,scope,"draft"),output_manager_default.log(`${import_chalk2.default.cyan("Published")} to production ${import_chalk2.default.gray(publishStamp())}`)}catch(e){output_manager_default.error(`Failed to publish to production: ${mapFirewallApiError(e,scope,"Unknown error")}`)}}}else hadExistingDraft&&output_manager_default.warn(`There are other draft changes. Review with ${import_chalk2.default.cyan(withGlobalFlags(client,"firewall diff",scope))} before publishing.`)}function resolveIpRule(ips,identifier){if(!identifier)return[];let byId=ips.find(r=>r.id===identifier);if(byId)return[byId];let query=identifier.toLowerCase(),byIp=ips.filter(r=>r.ip.toLowerCase()===query);return byIp.length>0?byIp:ips.filter(r=>r.id.toLowerCase().includes(query))}function resolveRule(rules2,identifier){if(!identifier)return[];let byId=rules2.find(r=>r.id===identifier);if(byId)return[byId];let query=identifier.toLowerCase(),byName=rules2.filter(r=>r.name.toLowerCase()===query);if(byName.length>0)return byName;let byPartialName=rules2.filter(r=>r.name.toLowerCase().includes(query));return byPartialName.length>0?byPartialName:rules2.filter(r=>r.id.toLowerCase().includes(query))}function printActionImpactWarning(action){let actionType=action.mitigate?.action;if(actionType)switch(actionType){case"deny":output_manager_default.warn("This rule will deny matching requests. Legitimate traffic may be blocked if conditions are too broad.");break;case"challenge":output_manager_default.warn("This rule will challenge matching requests with a verification page. Some legitimate users or automated clients may be unable to complete the challenge.");break;case"rate_limit":output_manager_default.warn("This rule will rate limit matching requests. Legitimate traffic may be throttled if the limit is too low or keys are too broad.");break;default:break}}async function getBypass(client,projectId,options={}){let{teamId}=options,query=new URLSearchParams;query.set("projectId",projectId),teamId&&query.set("teamId",teamId);let url=`/v1/security/firewall/bypass?${query.toString()}`;return client.fetch(url)}import{isIP}from"node:net";var STRING_OPS=["eq","inc"],STRING_MATCH_OPS=["sub","pre","suf","re"],KEY_EXISTS_OPS=["ex"],STRING_ONLY=[...STRING_OPS],STRING_AND_MATCH=[...STRING_OPS,...STRING_MATCH_OPS],STRING_MATCH_AND_EXISTS=[...STRING_OPS,...STRING_MATCH_OPS,...KEY_EXISTS_OPS],CONDITION_TYPES=[{type:"path",displayName:"Request Path",description:"URL path of the request",category:"request",requiresKey:!1,operators:STRING_AND_MATCH},{type:"route",displayName:"Route",description:"Route pattern (e.g., /blog/[slug])",category:"request",requiresKey:!1,operators:STRING_AND_MATCH},{type:"raw_path",displayName:"Raw Path",description:"Pre-rewrite URL path",category:"request",requiresKey:!1,operators:STRING_AND_MATCH},{type:"server_action",displayName:"Server Action Name",description:"Next.js Server Action name",category:"request",requiresKey:!1,operators:STRING_AND_MATCH},{type:"method",displayName:"Method",description:"HTTP method (GET, POST, DELETE, etc.)",category:"request",requiresKey:!1,operators:STRING_ONLY,presetValues:[{label:"GET",value:"GET"},{label:"HEAD",value:"HEAD"},{label:"POST",value:"POST"},{label:"DELETE",value:"DELETE"},{label:"PATCH",value:"PATCH"},{label:"PUT",value:"PUT"},{label:"CONNECT",value:"CONNECT"},{label:"OPTIONS",value:"OPTIONS"},{label:"TRACE",value:"TRACE"},{label:"DEBUG",value:"DEBUG"},{label:"QUERY",value:"QUERY"}]},{type:"host",displayName:"Hostname",description:"Request hostname",category:"request",requiresKey:!1,operators:STRING_AND_MATCH},{type:"protocol",displayName:"Protocol",description:"HTTP protocol version (HTTP/1.1, HTTP/2.0)",category:"request",requiresKey:!1,operators:STRING_ONLY,presetValues:[{label:"HTTP/1.1",value:"HTTP/1.1"},{label:"HTTP/2.0",value:"HTTP/2.0"}]},{type:"environment",displayName:"Environment",description:"Deployment environment (preview, production)",category:"request",requiresKey:!1,operators:STRING_ONLY,presetValues:[{label:"Preview",value:"preview"},{label:"Production",value:"production"}]},{type:"region",displayName:"Vercel Region",description:"Edge region serving the request",category:"request",requiresKey:!1,operators:STRING_ONLY},{type:"target_path",displayName:"Target Path",description:"Post-rewrite destination path",category:"request",requiresKey:!1,operators:STRING_AND_MATCH,valueValidation:"path"},{type:"scheme",displayName:"Scheme",description:"Request scheme (http, https)",category:"request",requiresKey:!1,operators:STRING_ONLY,presetValues:[{label:"http",value:"http"},{label:"https",value:"https"}]},{type:"rate_limit_api_id",displayName:"Rate Limit API ID",description:"Identifier for rate-limit API grouping",category:"request",requiresKey:!1,operators:STRING_ONLY},{type:"ip_address",displayName:"IP Address",description:"Client IP address or CIDR range",category:"client",requiresKey:!1,operators:STRING_ONLY},{type:"user_agent",displayName:"User Agent",description:"Client User-Agent string",category:"client",requiresKey:!1,operators:STRING_AND_MATCH},{type:"geo_country",displayName:"Country",description:"Country code (ISO 3166-1 alpha-2)",category:"geo",requiresKey:!1,operators:STRING_ONLY},{type:"geo_continent",displayName:"Continent",description:"Continent code (AF, AN, AS, EU, NA, OC, SA)",category:"geo",requiresKey:!1,operators:STRING_ONLY,presetValues:[{label:"Africa (AF)",value:"AF"},{label:"Antarctica (AN)",value:"AN"},{label:"Asia (AS)",value:"AS"},{label:"Europe (EU)",value:"EU"},{label:"North America (NA)",value:"NA"},{label:"Oceania (OC)",value:"OC"},{label:"South America (SA)",value:"SA"}]},{type:"geo_city",displayName:"City",description:"City name",category:"geo",requiresKey:!1,operators:STRING_AND_MATCH},{type:"geo_country_region",displayName:"State / Region",description:"State or region code",category:"geo",requiresKey:!1,operators:STRING_AND_MATCH},{type:"geo_as_number",displayName:"AS Number",description:"Autonomous System Number",category:"geo",requiresKey:!1,operators:STRING_AND_MATCH,valueValidation:"digits"},{type:"header",displayName:"Request Header",description:"HTTP request header (requires key)",category:"key-value",requiresKey:!0,operators:STRING_MATCH_AND_EXISTS},{type:"query",displayName:"Query Parameter",description:"URL query parameter (requires key)",category:"key-value",requiresKey:!0,operators:STRING_MATCH_AND_EXISTS},{type:"cookie",displayName:"Cookie",description:"HTTP cookie (requires key)",category:"key-value",requiresKey:!0,operators:STRING_MATCH_AND_EXISTS},{type:"ja4_digest",displayName:"JA4 Digest",description:"JA4 TLS fingerprint",category:"security",requiresKey:!1,operators:STRING_AND_MATCH},{type:"ja3_digest",displayName:"JA3 Digest",description:"JA3 TLS fingerprint",category:"security",requiresKey:!1,operators:STRING_AND_MATCH,planRequirement:"enterprise"},{type:"bot_name",displayName:"Bot Name",description:"Verified bot name",category:"bot",requiresKey:!1,operators:STRING_AND_MATCH,planRequirement:"security-plus"},{type:"bot_category",displayName:"Bot Category",description:"Verified bot category",category:"bot",requiresKey:!1,operators:STRING_AND_MATCH,planRequirement:"security-plus"}],CONDITION_TYPE_MAP=Object.fromEntries(CONDITION_TYPES.map(ct=>[ct.type,ct])),ALL_OPERATORS=["eq","neq","inc","ninc","sub","pre","suf","re","ex","nex","gt","gte","lt","lte"],CATEGORY_LABELS={request:"Request",client:"Client",geo:"Geo / Location","key-value":"Key-Value (Header / Query / Cookie)",security:"Security / TLS",bot:"Bot Detection"},VALID_ACTIONS=["deny","challenge","log","bypass","rate_limit","redirect"],VALID_DURATIONS=["1m","5m","15m","30m","1h"],VALID_ALGORITHMS=["fixed_window","token_bucket"];async function fetchPlanInfo(client){try{let{team}=await getScope(client);if(team)return{isEnterprise:team.billing.plan==="enterprise",hasSecurityPlus:team.securityPlus?.enabled===!0,known:!0}}catch{}return{isEnterprise:!1,hasSecurityPlus:!1,known:!1}}function getAvailableConditionTypes(planInfo){return CONDITION_TYPES.filter(ct=>!(ct.deprecated||ct.planRequirement==="enterprise"&&!planInfo?.isEnterprise||ct.planRequirement==="security-plus"&&!planInfo?.hasSecurityPlus))}function getActionLabel(action){return{deny:"Deny \u2014 Block traffic (403)",challenge:"Challenge \u2014 Verify at security checkpoint",log:"Log \u2014 Monitor without blocking",bypass:"Bypass \u2014 Skip other custom rules",rate_limit:"Rate Limit \u2014 Enforce request limits",redirect:"Redirect \u2014 Send to a different URL"}[action]||action}function getOperatorDisplayName(op,neg){let pair={eq:["equals","does not equal"],inc:["is any of","is not any of"],sub:["contains","does not contain"],pre:["starts with","does not start with"],suf:["ends with","does not end with"],re:["matches regex","does not match regex"],ex:["exists","does not exist"]}[op];return pair?neg?pair[1]:pair[0]:neg?`NOT ${op}`:op}function validateConditionValue(val,meta){if(!meta?.valueValidation)return!0;switch(meta.valueValidation){case"path":return val.startsWith("/")?!0:"Path must start with /";case"ip":{if(isIP(val))return!0;let slashIdx=val.lastIndexOf("/");if(slashIdx!==-1){let ip=val.slice(0,slashIdx),prefix=Number.parseInt(val.slice(slashIdx+1),10);if(isIP(ip)&&!Number.isNaN(prefix)&&prefix>=0)return!0}return"Please enter a valid IP address or CIDR range."}case"hostname":return/^[A-Za-z0-9-]{1,63}(?:\.[A-Za-z0-9-]{1,63})*$/.test(val)?!0:"Please enter a valid hostname.";case"digits":return/^\d+$/.test(val)?!0:"Please enter digits only.";default:return!0}}var FIREWALL_ACTION_METRIC="vercel.firewall_action.count";var VALUE_ALIAS="value",DEFAULT_TIMEOUT_MS=45e3,ActivityTimeoutError=class extends Error{constructor(message){super(message),this.name="ActivityTimeoutError"}};function isRateLimited(error){return isAPIError(error)&&error.status===429}function rateLimitRetrySeconds(error){if(!isRateLimited(error))return;let ms8=error.retryAfterMs;if(!(typeof ms8!="number"||ms8<=0))return Math.ceil(ms8/1e3)}function isActivityTimeout(error){return isAPIError(error)&&error.status===408||error instanceof Error&&error.name==="ActivityTimeoutError"}function toBucketSeconds(granularity){return"minutes"in granularity?granularity.minutes*60:"hours"in granularity?granularity.hours*60*60:granularity.days*24*60*60}function alignQueryWindow(startTime,endTime,granularity){let stepMs=granularity?toBucketSeconds(granularity)*1e3:1e3;return{startTime:new Date(Math.floor(startTime.getTime()/stepMs)*stepMs),endTime:new Date(Math.ceil(endTime.getTime()/stepMs)*stepMs)}}async function queryFirewallObservability(client,opts){let groupBy=opts.groupBy??[],window=alignQueryWindow(opts.startTime,opts.endTime,opts.granularity),bucketed=opts.granularity!==void 0,ranked=groupBy.length>0&&opts.limit!==void 0,body={scope:{ownerId:opts.ownerId,projectIds:[opts.projectId]},timeRange:{start:window.startTime.toISOString(),end:window.endTime.toISOString()},metrics:{[VALUE_ALIAS]:{metric:opts.metric??FIREWALL_ACTION_METRIC,aggregation:"count"}},outputs:[VALUE_ALIAS],...opts.granularity?{bucketSeconds:toBucketSeconds(opts.granularity)}:{},...groupBy.length>0?{groupBy}:{},...opts.filter?{filter:opts.filter}:{},...ranked&&bucketed?{seriesSelection:{limit:opts.limit,mode:opts.approximateSelection?"approximate":"exact",rankBy:[{metric:VALUE_ALIAS,direction:"desc"}]}}:{},...ranked&&!bucketed?{rowLimit:opts.limit,orderBy:[{metric:VALUE_ALIAS,direction:"desc"}]}:{}},timeoutMs=opts.timeoutMs??DEFAULT_TIMEOUT_MS,response;try{response=await client.fetch(OBSERVABILITY_METRICS_PATH,{method:"POST",body:JSON.stringify(body),headers:{"Content-Type":"application/json"},accountId:opts.ownerId,signal:AbortSignal.timeout(timeoutMs),bailOn429:!0})}catch(err){throw err instanceof Error&&(err.name==="TimeoutError"||err.name==="AbortError")?new ActivityTimeoutError(`Timed out after ${Math.round(timeoutMs/1e3)}s waiting for ${opts.timeoutSubject??"firewall traffic data"}.`):err}return{summary:response.summary??[],series:response.series??[],startTime:window.startTime,endTime:window.endTime}}function rowValue(row){let raw=row.values?.[VALUE_ALIAS],n=typeof raw=="number"?raw:Number(raw);return Number.isFinite(n)?n:0}function rowDimension(row,field){return String(row.dimensions?.[field]??"")}function isUnsupportedDimension(error){if(!isAPIError(error)||error.status!==400)return!1;let pattern=/does not support|is not supported|not publicly queryable/i,issues=error.issues;return Array.isArray(issues)?issues.some(issue=>typeof issue?.message=="string"&&pattern.test(issue.message)):pattern.test(error.serverMessage||error.message||"")}var ACTION_DIMENSION="wafAction";function actionFromRow(row){return rowDimension(row,ACTION_DIMENSION)||"unknown"}async function getFirewallMetrics(client,opts){let granularity=opts.granularity??{hours:1},result=await queryFirewallObservability(client,{ownerId:opts.ownerId,projectId:opts.projectId,startTime:opts.startTime,endTime:opts.endTime,granularity,groupBy:[ACTION_DIMENSION],filter:opts.filter,limit:100,timeoutMs:opts.timeoutMs,timeoutSubject:"firewall metrics"}),byAction=new Map,totalFromSummary=new Set;for(let row of result.summary){let action=actionFromRow(row);totalFromSummary.add(action),byAction.set(action,{action,total:rowValue(row),timeseries:[]})}for(let row of result.series){let action=actionFromRow(row),value=rowValue(row),series2=byAction.get(action);series2||(series2={action,total:0,timeseries:[]},byAction.set(action,series2)),series2.timeseries.push({timestamp:row.timestamp,value}),totalFromSummary.has(action)||(series2.total+=value)}let order=["allow","deny","challenge","log","rate_limit","bypass"],series=[...byAction.values()].sort((a,b)=>{let ai=order.indexOf(a.action),bi=order.indexOf(b.action);return ai===-1&&bi===-1?a.action.localeCompare(b.action):ai===-1?1:bi===-1?-1:ai-bi});for(let s of series)s.timeseries.sort((a,b)=>a.timestamp.localeCompare(b.timestamp));let totals={};for(let s of series)totals[s.action]=s.total;return{startTime:result.startTime.toISOString(),endTime:result.endTime.toISOString(),granularity,series,totals}}function quoteKqlValue(value){return`"${value.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function eqFilter(field,value){return`${field}:${quoteKqlValue(value)}`}function neFilter(field,value){return`${field}!=${quoteKqlValue(value)}`}function nonEmptyFilter(field){return neFilter(field,"")}var TRAFFIC_DIMENSIONS=[{alias:"ip",field:"clientIp",label:"IP Address",widgetTitle:"Top IPs",excludeFilter:neFilter("clientIp","127.0.0.1"),headerDetailFields:["asnName","asnId","clientIpCountry"],defaultGroupBy:"path"},{alias:"ja4",field:"clientJa4Digest",label:"JA4 Digest",widgetTitle:"Top JA4 Digests",excludeFilter:nonEmptyFilter("clientJa4Digest"),headerDetailFields:["clientUserAgent"],defaultGroupBy:"path"},{alias:"asn",field:"asnName",label:"AS Name",widgetTitle:"Top AS Names",excludeFilter:`(${nonEmptyFilter("asnId")}) AND (${nonEmptyFilter("asnName")})`,groupBy:["asnName","asnId"],labelFields:["asnId"],headerDetailFields:["asnId"],defaultGroupBy:"ip"},{alias:"user-agent",field:"clientUserAgent",label:"User Agent",widgetTitle:"Top User Agents",excludeFilter:nonEmptyFilter("clientUserAgent"),defaultGroupBy:"path"},{alias:"path",field:"requestPath",label:"Request Path",widgetTitle:"Top Request Paths",excludeFilter:nonEmptyFilter("requestPath"),defaultGroupBy:"ip"},{alias:"rule",field:"wafRuleId",label:"Firewall Rule",widgetTitle:"Rules",excludeFilter:`(${nonEmptyFilter("wafRuleId")}) AND (${nonEmptyFilter("wafAction")})`,defaultGroupBy:"ip"},{alias:"host",field:"requestHostname",label:"Hostname",widgetTitle:"Top Hosts",defaultGroupBy:"path"},{alias:"bot",field:"botName",label:"Bot",widgetTitle:"Verified Bots",excludeFilter:nonEmptyFilter("botName"),defaultGroupBy:"path"},{alias:"unknown-bot",field:"botCategory",label:"Unknown Bot Category",widgetTitle:"Unknown Bot Traffic",excludeFilter:nonEmptyFilter("botCategory"),metric:"vercel.request.count",extraFilter:neFilter("botVerified","pass"),defaultGroupBy:"path"},{alias:"country",field:"clientIpCountry",label:"Country",widgetTitle:"Top Countries",excludeFilter:nonEmptyFilter("clientIpCountry"),defaultGroupBy:"ip"},{alias:"action",field:"wafAction",label:"Firewall Action",widgetTitle:"Actions",excludeFilter:nonEmptyFilter("wafAction"),defaultGroupBy:"rule"}];function getDimension(alias){return TRAFFIC_DIMENSIONS.find(d=>d.alias===alias)}function dimensionAliases(){return TRAFFIC_DIMENSIONS.map(d=>d.alias)}function andFilters(...parts){let nonEmpty=parts.filter(p=>!!(p&&p.length>0));if(nonEmpty.length!==0)return nonEmpty.length===1?nonEmpty[0]:nonEmpty.map(p=>`(${p})`).join(" AND ")}var RULE_ID_DIMENSION="wafRuleId",RULE_TRAFFIC_FILTER=`(${nonEmptyFilter(RULE_ID_DIMENSION)}) AND (${nonEmptyFilter("wafAction")})`,GRANULARITY_LADDER=[[6e4,{minutes:1}],[5*6e4,{minutes:5}],[15*6e4,{minutes:15}],[30*6e4,{minutes:30}],[36e5,{hours:1}],[2*36e5,{hours:2}],[4*36e5,{hours:4}],[12*36e5,{hours:12}],[24*36e5,{hours:24}]],DEFAULT_MAX_BUCKETS=24;function pickGranularity(spanMs,maxBuckets=DEFAULT_MAX_BUCKETS){for(let[stepMs,granularity]of GRANULARITY_LADDER)if(spanMs/stepMs<=maxBuckets)return granularity;return{hours:24}}async function getTopList(client,opts){let{summary}=await queryFirewallObservability(client,{...opts,granularity:void 0,limit:Math.min(opts.top,500)}),rows=summary.map(row=>({values:Object.fromEntries(opts.groupBy.map(field=>[field,rowDimension(row,field)])),total:rowValue(row)}));return rows.sort((a,b)=>b.total-a.total),rows.slice(0,opts.top)}async function getGroupedTimeseries(client,opts){let spanMs=opts.endTime.getTime()-opts.startTime.getTime(),granularity=opts.granularity??pickGranularity(spanMs),groupBy=opts.groupBy??[],result=await queryFirewallObservability(client,{...opts,granularity,groupBy}),keyOf=row=>groupBy.map(f=>rowDimension(row,f)).join(" \xB7 "),groups=new Map,pointsByGroup=new Map,axisSet=new Set,hasSummary=result.summary.length>0,getOrCreate=row=>{let key=keyOf(row),group=groups.get(key);return group||(group={values:Object.fromEntries(groupBy.map(field=>[field,rowDimension(row,field)])),key,total:0,series:[]},groups.set(key,group)),group};for(let row of result.summary)getOrCreate(row).total=rowValue(row);for(let row of result.series){let timestamp=row.timestamp;if(!timestamp)continue;axisSet.add(timestamp);let group=getOrCreate(row),points=pointsByGroup.get(group.key);points||(points=new Map,pointsByGroup.set(group.key,points));let value=rowValue(row);points.set(timestamp,(points.get(timestamp)??0)+value),hasSummary||(group.total+=value)}let axis=[...axisSet].sort();for(let group of groups.values()){let points=pointsByGroup.get(group.key);group.series=axis.map(t=>points?.get(t)??0)}return{startTime:result.startTime.toISOString(),endTime:result.endTime.toISOString(),granularity,axis,groups:[...groups.values()].sort((a,b)=>b.total-a.total)}}var WELL_KNOWN_RULE_NAMES={sys_dos_mitigation:"DDoS Mitigation",ip_blocking:"IP Blocking",challenge_mode:"Attack Mode",default_web_traffic:"Allowed Requests",managed_bot_protection:"Bot Protection",managed_bot_filter:"Bot Protection",owasp_anomaly_detection:"OWASP Anomaly Detection",owasp_xss_detection:"OWASP XSS Detection",owasp_sqli_detection:"OWASP SQL Injection Detection",owasp_rfi_detection:"OWASP RFI Detection",owasp_lfi_detection:"OWASP LFI Detection",owasp_rce_detection:"OWASP RCE Detection",owasp_php_detection:"OWASP PHP Injection Detection",owasp_session_fixation_detection:"OWASP Session Fixation Detection",deployment_rules:"Deployment Rules",deployment_defined_rules:"Deployment Defined Rules"};function titleCaseManagedSuffix(ruleId){return ruleId.slice(8).split("_").filter(Boolean).map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join(" ")}function ipBlockName(ip){return!ip.hostname||ip.hostname==="*"?`IP Block ${ip.ip}`:`IP Block ${ip.hostname} ${ip.ip}`}function resolveRuleDisplayName(ruleId,config){if(!ruleId)return ruleId;let custom=config?.rules.find(r=>r.id===ruleId);if(custom?.name)return custom.name;let ip=config?.ips.find(r=>r.id===ruleId);if(ip)return ipBlockName(ip);let known=WELL_KNOWN_RULE_NAMES[ruleId];return known||(ruleId.startsWith("managed_")?titleCaseManagedSuffix(ruleId):ruleId)}var import_chalk3=__toESM(require_source(),1);var MAX_VALUE_WIDTH=60,MAX_TREND_LABEL_WIDTH=40,NOT_SET="(not set)",FIELD_LABELS={asnId:"AS Number",asnName:"AS Name",clientIp:"IP Address",clientIpCountry:"Country",clientJa4Digest:"JA4 Digest",clientUserAgent:"User Agent",requestHostname:"Hostname",requestPath:"Request Path",wafAction:"Action",wafRuleId:"Rule"};function fieldLabel(field){return FIELD_LABELS[field]??field}function windowLabel(opts){let range=`${formatUtcTime(opts.startMs,!0)} \u2013 ${formatUtcTime(opts.endMs,!0)} UTC`;if(opts.points===0)return range;let unit=opts.points===1?"point":"points";return`${range} \xB7 ${opts.points} ${unit} (${granularityLabel(opts.granularity)} each)`}function axisOf(series){let timestamps=new Set;for(let s of series)for(let point of s.timeseries)timestamps.add(point.timestamp);return[...timestamps].sort()}function peakOf(values,axis){let peak=0,peakTs="";for(let i=0;i<axis.length;i++)values[i]>peak&&(peak=values[i],peakTs=axis[i]);return{peak,peakTs}}function indent(rendered){return rendered.split(`
|
|
16
|
+
`).map(line2=>` ${line2}`.trimEnd())}function emptyLine(filtered){return import_chalk3.default.dim(filtered?" No requests match the current filters.":" No requests in this period.")}function retryLabel(seconds){if(seconds<90)return`${seconds}s`;let minutes=Math.round(seconds/60);if(minutes<90)return`${minutes} ${minutes===1?"minute":"minutes"}`;let hours=Math.round(seconds/3600);return`${hours} ${hours===1?"hour":"hours"}`}function unavailableLine(reason,retrySeconds){switch(reason){case"filter":return"Not reported alongside the filters in use.";case"plan":return"Needs Observability Plus.";case"rate-limit":return retrySeconds?`Rate limited by the Observability API. Retry in ${retryLabel(retrySeconds)}.`:"Rate limited by the Observability API.";case"timeout":return"Timed out. Narrow the window with `--since` and try again.";default:return"Couldn't load this table."}}function toTopListRows(rows,field,labelFields){return rows.filter(row=>row.values[field]).map(row=>{let extras=(labelFields??[]).map(f=>row.values[f]).filter(v=>!!v&&v!==row.values[field]);return{value:row.values[field],total:row.total,...extras.length>0?{label:`${row.values[field]} (${extras.join(", ")})`}:{}}})}function topListFetchCount(top,groupBy=[]){let extraFields=Math.max(0,groupBy.length-1);return top+1+extraFields*16}function formatTopList(list7,filtered){let lines=[` ${import_chalk3.default.bold(list7.title)}`];return list7.unavailable?(lines.push(import_chalk3.default.dim(` ${list7.message??unavailableLine(list7.unavailable,list7.retrySeconds)}`)),lines):list7.rows.length===0?(lines.push(emptyLine(filtered)),lines):(lines.push(...indent(table(list7.rows.map(row=>[ellipsizeMiddle(row.label??row.value,MAX_VALUE_WIDTH),formatCount(row.total)]),{align:["l","r"],hsep:3}))),lines)}function formatTrafficTopList(list7,filtered=!1){return formatTopList(list7,filtered).join(`
|
|
17
|
+
`)}function formatGroupedTrendTable(opts){let{axis}=opts.result,needsDate=windowNeedsDate(new Date(opts.result.startTime).getTime(),new Date(opts.result.endTime).getTime()),rows=[[opts.labelHeader,"Trend","Total","Peak","Peak at"].map(h=>import_chalk3.default.bold(import_chalk3.default.cyan(h)))];for(let group of opts.result.groups){let{peak,peakTs}=peakOf(group.series,axis);rows.push([ellipsizeMiddle(group.values[opts.field]||NOT_SET,MAX_TREND_LABEL_WIDTH),generateSparkline(group.series),formatCount(group.total),peak>0?formatCount(peak):"--",peak>0?formatUtcTime(new Date(peakTs).getTime(),needsDate):"--"])}return indent(table(rows,{align:["l","l","r","r","r"],hsep:3}))}function formatTrafficList(opts){let startMs=new Date(opts.startTime).getTime(),endMs=new Date(opts.endTime).getTime(),axis=axisOf(opts.series),lines=[` ${import_chalk3.default.bold("Firewall traffic")} ${import_chalk3.default.dim(windowLabel({startMs,endMs,points:axis.length,granularity:opts.granularity}))}`,"",` ${import_chalk3.default.bold("Requests by Action")}`,formatActionTrendTable(opts.series)],shared=sharedUnavailable(opts.topLists);if(shared)return lines.push(""),lines.push(` ${import_chalk3.default.dim(shared.message??unavailableLine(shared.reason,shared.retrySeconds))}`),lines.push(import_chalk3.default.dim(` No top lists: ${opts.topLists.map(l=>l.title).join(", ")}.`)),lines.push(""),lines.join(`
|
|
18
|
+
`);for(let list7 of opts.topLists)lines.push(""),lines.push(...formatTopList(list7,opts.filtered));return lines.push(""),lines.join(`
|
|
19
|
+
`)}function allTopListsUnavailable(lists){return lists.length>0&&lists.every(list7=>!!list7.unavailable)}function sharedUnavailable(lists){if(lists.length<2)return;let first=lists[0].unavailable;if(first&&lists.every(l=>l.unavailable===first))return{reason:first,message:lists.find(l=>l.message)?.message,retrySeconds:lists.map(l=>l.retrySeconds).filter(s=>typeof s=="number").sort((a,b)=>a-b)[0]}}function formatTrafficInspect(opts){let lines=[` ${import_chalk3.default.bold(opts.value)} ${import_chalk3.default.dim(opts.dimensionLabel)}`];for(let row of opts.detail)row.value&&lines.push(formatAlignedLabel(fieldLabel(row.field),ellipsizeMiddle(row.value,MAX_VALUE_WIDTH)));return lines.push(formatAlignedLabel("Requests",formatCount(opts.total))),lines.push(""),lines.push(` ${import_chalk3.default.bold("Requests by Action")} ${import_chalk3.default.dim(windowLabel({startMs:new Date(opts.startTime).getTime(),endMs:new Date(opts.endTime).getTime(),points:axisOf(opts.series).length,granularity:opts.granularity}))}`),lines.push(formatActionTrendTable(opts.series)),lines.push(""),lines.push(` ${import_chalk3.default.bold(`Breakdown by ${opts.breakdownLabel}`)} ${import_chalk3.default.dim(`(top ${opts.top})`)}`),opts.breakdown.groups.length===0?lines.push(emptyLine(opts.filtered)):lines.push(...formatGroupedTrendTable({labelHeader:opts.breakdownLabel,field:opts.breakdownField,result:opts.breakdown})),lines.push(""),lines.join(`
|
|
20
|
+
`)}var import_chalk4=__toESM(require_source(),1);var OVERVIEW_TOP_RULES=8,MAX_RULE_VALUE_WIDTH=40;function formatOverviewOutput(opts){let lines=[],windowStartMs=new Date(opts.startTime).getTime(),windowEndMs=new Date(opts.endTime).getTime(),needsDate=windowNeedsDate(windowStartMs,windowEndMs),attacksSuffix=opts.attacksMitigatedIncomplete?` ${import_chalk4.default.dim("\xB7 at least, some alerts unread")}`:"";lines.push(` ${import_chalk4.default.bold("Attacks mitigated")} (this window) ${formatCount(opts.attacksMitigated)}${attacksSuffix}`),lines.push("");let allTs=new Set;for(let s of opts.series)for(let p of s.timeseries)allTs.add(p.timestamp);let axis=[...allTs].sort(),bucket=opts.granularity?granularityLabel(opts.granularity):void 0,rangeLabel=`${formatUtcTime(windowStartMs,!0)} \u2013 ${formatUtcTime(windowEndMs,!0)} UTC`,pointsLabel=axis.length>0?` \xB7 ${axis.length} point${axis.length===1?"":"s"}${bucket?` (${bucket} each)`:""}`:"";lines.push(` ${import_chalk4.default.bold("Requests by Action")} ${rangeLabel+pointsLabel}`);let hasAnyTraffic=opts.series.some(s=>s.total>0||s.timeseries.some(p=>p.value>0));if(opts.series.length===0||axis.length===0||!hasAnyTraffic)lines.push(import_chalk4.default.dim(" No request data for this period."));else{let rows=[["Action","Trend","Total","Peak","Peak at"].map(h=>import_chalk4.default.bold(import_chalk4.default.cyan(h)))];for(let s of opts.series){let byTs=new Map(s.timeseries.map(p=>[p.timestamp,p.value])),values=axis.map(t=>byTs.get(t)??0),peak=0,peakTs="";for(let i=0;i<axis.length;i++)values[i]>peak&&(peak=values[i],peakTs=axis[i]);let plain=x=>x,color=s.total>0?ACTION_COLORS[s.action]??plain:import_chalk4.default.dim,trend=s.total>0?plain:import_chalk4.default.dim;rows.push([color(labelForAction(s.action)),trend(generateSparkline(values)),formatCount(s.total),peak>0?formatCount(peak):"--",peak>0?formatUtcTime(new Date(peakTs).getTime(),needsDate):"--"])}let rendered=table(rows,{align:["l","l","r","r","r"],hsep:3});for(let line2 of rendered.split(`
|
|
21
|
+
`))lines.push(` ${line2}`.trimEnd())}if(lines.push(""),lines.push(` ${import_chalk4.default.bold("Rules")} (top ${OVERVIEW_TOP_RULES})`),opts.rules.length===0)lines.push(import_chalk4.default.dim(" No rule traffic for this period."));else{let rows=[["Rule","Requests","Id"].map(h=>import_chalk4.default.bold(import_chalk4.default.cyan(h)))];for(let r of opts.rules)rows.push([ellipsizeMiddle(r.name,MAX_RULE_VALUE_WIDTH),formatCount(r.total),ellipsizeMiddle(r.id,MAX_RULE_VALUE_WIDTH)]);let rendered=table(rows,{align:["l","r","l"],hsep:3});for(let line2 of rendered.split(`
|
|
22
|
+
`))lines.push(` ${line2}`.trimEnd())}if(opts.annotations.length>0){lines.push(""),lines.push(import_chalk4.default.bold(" Alerts in this window"));for(let a of opts.annotations.slice(0,8)){let when=formatUtcTime(a.startedAt,needsDate),ago=`(${relativeTime(a.startedAt)})`,count=a.count!==void 0?` \xB7 ${formatCount(a.count)}`:"",detail=a.detail?` \xB7 ${colorizeDetail(a.detail)}`:"";lines.push(` ${import_chalk4.default.yellow("!")} ${when} UTC ${ago} ${a.title}${detail}${count}`)}}return lines.push(""),lines.join(`
|
|
23
|
+
`)}var import_chalk5=__toESM(require_source(),1);var PLAN_UNAVAILABLE="Requires Pro or Enterprise",MS_PER_SECOND=1e3,MS_PER_MINUTE=60*MS_PER_SECOND,MS_PER_HOUR=60*MS_PER_MINUTE;function formatDuration(ms8){let hours=Math.floor(ms8/MS_PER_HOUR),minutes=Math.floor(ms8%MS_PER_HOUR/MS_PER_MINUTE);return`${hours}h ${minutes}m`}function isAllSourcesBypass(ip){return ip==="0.0.0.0/0"||ip==="::/0"}var MAX_EXPIRY_SECONDS=4102444800;function parseExpirySeconds(expiry){if(!expiry||!/^\d+$/.test(expiry))return null;let seconds=Number(expiry);return Number.isSafeInteger(seconds)&&seconds<=MAX_EXPIRY_SECONDS?seconds:null}function allSourcesBypassExpiries(firewallBypassIps=[],bypass=[]){let expiries=[];for(let entry of firewallBypassIps){let[ip,expiry]=entry.split("#");isAllSourcesBypass(ip)&&expiries.push(parseExpirySeconds(expiry))}for(let rule of bypass??[])!isAllSourcesBypass(rule.Ip)||rule.Domain!=="*"||expiries.push(rule.ExpiresAt??null);return expiries}function getMitigationsStatus(firewallBypassIps,bypass){let expiries=allSourcesBypassExpiries(firewallBypassIps,bypass);if(expiries.includes(null))return{paused:!0};let nowSeconds=Date.now()/MS_PER_SECOND,unexpired=expiries.filter(expiry=>expiry!==null&&expiry>nowSeconds);return unexpired.length?{paused:!0,resumesAt:Math.max(...unexpired)}:{paused:!1}}function formatAttackModeStatus(status2){if(!status2.enabled)return import_chalk5.default.dim("Off");if(status2.activeUntil){let remainingMs=status2.activeUntil-Date.now();return remainingMs<=0?import_chalk5.default.dim("Off (expired)"):import_chalk5.default.red(`On (expires in ${formatDuration(remainingMs)})`)}return import_chalk5.default.red("On")}function formatMitigationsStatus(status2){if(!status2.paused)return import_chalk5.default.green("Active");if(status2.resumesAt!==void 0){let remainingMs=status2.resumesAt*MS_PER_SECOND-Date.now();if(remainingMs>0)return import_chalk5.default.yellow(`Paused (auto-resumes in ${formatDuration(remainingMs)})`)}return import_chalk5.default.yellow("Paused")}function formatStatusOutput(opts){let{active,draft,bypass,attackMode,firewallBypassIps}=opts,lines=[];if(lines.push(formatAlignedLabel("Firewall",active?active.firewallEnabled?import_chalk5.default.green("Enabled"):import_chalk5.default.red("Disabled"):import_chalk5.default.dim("Not configured"))),bypass===null)lines.push(formatAlignedLabel("Bypass",import_chalk5.default.dim(PLAN_UNAVAILABLE)));else{let regularBypasses=bypass.filter(b=>!isAllSourcesBypass(b.Ip));lines.push(formatAlignedLabel("Bypass",`${regularBypasses.length} IP${regularBypasses.length!==1?"s":""}`))}if(lines.push(formatAlignedLabel("Mitigations",formatMitigationsStatus(getMitigationsStatus(firewallBypassIps,bypass)))),attackMode&&lines.push(formatAlignedLabel("Attack Mode",formatAttackModeStatus(attackMode))),active){lines.push(formatAlignedLabel("IP Blocks",String(active.ips.length)));let activeRules=active.rules.filter(r=>r.active).length,inactiveRules=active.rules.filter(r=>!r.active).length;lines.push(formatAlignedLabel("Rules",`${activeRules} active, ${inactiveRules} inactive (${active.rules.length} total)`))}if(lines.push(formatAlignedLabel("Bot Protection",formatBotProtectionStatus(getBotProtectionConfig(active?.managedRules)))),lines.push(formatAlignedLabel("AI Bots",formatAiBotsStatus(active?.managedRules?.ai_bots))),lines.push(formatAlignedLabel("OWASP",formatOwaspStatus(active?.managedRules?.owasp))),draft&&draft.changes.length>0){lines.push(""),lines.push(formatAlignedLabel("Draft",import_chalk5.default.yellow(`${draft.changes.length} unpublished change${draft.changes.length!==1?"s":""}`)));let activeRulesMap=new Map((active?.rules||[]).map(r=>[r.id,r]));lines.push(formatDiffOutput(draft.changes,activeRulesMap))}return lines.join(`
|
|
24
|
+
`)}function formatBypassTable(bypasses){let lines=[],domains=bypasses.map(b=>b.Domain==="*"?"All domains":b.Domain),ipWidth=Math.max(7,...bypasses.map(b=>b.Ip.length)),domainWidth=Math.max(6,...domains.map(d=>d.length)),gap=3;lines.push(` ${import_chalk5.default.dim("IP/CIDR".padEnd(ipWidth+gap))}${import_chalk5.default.dim("Domain".padEnd(domainWidth+gap))}${import_chalk5.default.dim("Note")}`);for(let i=0;i<bypasses.length;i++){let bypass=bypasses[i],ip=bypass.Ip.padEnd(ipWidth+gap),domain=domains[i].padEnd(domainWidth+gap),note=bypass.Note||"";lines.push(` ${ip}${domain}${note}`)}return lines.join(`
|
|
25
|
+
`)}function annotateIpRules(activeIps,draftIps,changes){if(!draftIps)return activeIps.map(rule=>({rule,status:"live"}));let addedIds=new Set(changes.filter(c=>c.action==="ip.insert").map(c=>c.id).filter(id=>id!=null)),removedIds=new Set(changes.filter(c=>c.action==="ip.remove").map(c=>c.id).filter(id=>id!=null)),modifiedIds=new Set(changes.filter(c=>c.action==="ip.update").map(c=>c.id).filter(id=>id!=null)),result=[];for(let rule of draftIps)addedIds.has(rule.id)?result.push({rule,status:"added"}):modifiedIds.has(rule.id)?result.push({rule,status:"modified"}):result.push({rule,status:"live"});for(let rule of activeIps)removedIds.has(rule.id)&&result.push({rule,status:"removed"});return result}function formatIpBlocksTable(annotated){let lines=[],hostnames=annotated.map(a=>a.rule.hostname==="*"||a.rule.hostname===""?"All hosts":a.rule.hostname),gap=3,prefixWidth=2,ipWidth=Math.max(7,...annotated.map(a=>a.rule.ip.length)),hostnameWidth=Math.max(8,...hostnames.map(h=>h.length));lines.push(` ${" ".repeat(prefixWidth)}${import_chalk5.default.dim("IP/CIDR".padEnd(ipWidth+gap))}${import_chalk5.default.dim("Hostname".padEnd(hostnameWidth+gap))}${import_chalk5.default.dim("Notes")}`);for(let i=0;i<annotated.length;i++){let{rule,status:status2}=annotated[i],ip=rule.ip.padEnd(ipWidth+gap),hostname=hostnames[i].padEnd(hostnameWidth+gap),notes=rule.notes||"",prefix=" ",colorFn=s=>s;status2==="added"?(prefix="+ ",colorFn=import_chalk5.default.green):status2==="removed"?(prefix="- ",colorFn=import_chalk5.default.red):status2==="modified"&&(prefix="~ ",colorFn=import_chalk5.default.yellow),lines.push(colorFn(` ${prefix}${ip}${hostname}${notes}`))}return lines.join(`
|
|
26
|
+
`)}function getDiffSymbol(action){return action.endsWith(".insert")?{symbol:"+",color:import_chalk5.default.green}:action.endsWith(".remove")?{symbol:"-",color:import_chalk5.default.red}:{symbol:"~",color:import_chalk5.default.yellow}}function formatChangeDescription(change,activeRules){let{action,id,value}=change;switch(action){case"rules.insert":return`Added rule "${value?.name||id||"unknown"}"`;case"rules.update":{let draft=value,ruleName=draft?.name||id||"unknown";if(activeRules&&id&&draft&&typeof draft.active=="boolean"){let activeRule=activeRules.get(id);if(activeRule&&activeRule.active!==draft.active){let nameUnchanged=activeRule.name===draft.name,conditionsUnchanged=JSON.stringify(activeRule.conditionGroup)===JSON.stringify(draft.conditionGroup),actionUnchanged=JSON.stringify(activeRule.action)===JSON.stringify(draft.action),descriptionUnchanged=(activeRule.description||"")===(draft.description||"");if(nameUnchanged&&conditionsUnchanged&&actionUnchanged&&descriptionUnchanged)return draft.active?`Enabled rule "${ruleName}"`:`Disabled rule "${ruleName}"`}}return`Modified rule "${ruleName}"`}case"rules.remove":return`Removed rule "${id||"unknown"}"`;case"rules.priority":return`Reordered rule "${value?.name||id||"unknown"}"`;case"ip.insert":return`Added IP block ${value?.ip||"unknown"}`;case"ip.remove":return`Removed IP block ${id||"unknown"}`;case"ip.update":return`Modified IP block ${value?.ip||id||"unknown"}`;case"firewallEnabled":return`${value?"Enabled":"Disabled"} firewall`;case"crs.update":return"Updated OWASP CRS configuration";case"crs.disable":return"Disabled OWASP CRS";case"managedRules.update":return"Updated managed ruleset configuration";case"managedRuleGroup.update":return"Updated managed rule group";case"botId.toggle":return`${value?"Enabled":"Disabled"} Bot ID detection`;case"ja3Enabled":return`${value?"Enabled":"Disabled"} JA3 fingerprinting`;case"ja4Enabled":return`${value?"Enabled":"Disabled"} JA4 fingerprinting`;case"logHeaders.update":return"Updated log headers configuration";default:return`${action}${id?` (${id})`:""}`}}function formatRuleFieldDiff(activeRule,draftValue){let lines=[];if(draftValue.name&&activeRule.name!==draftValue.name&&lines.push(import_chalk5.default.yellow(` ~ Name: "${activeRule.name}" \u2192 "${draftValue.name}"`)),draftValue.action&&JSON.stringify(activeRule.action)!==JSON.stringify(draftValue.action)){let oldAction=formatActionDisplay(activeRule.action),newAction=formatActionDisplay(draftValue.action);lines.push(import_chalk5.default.yellow(` ~ Action: ${oldAction} \u2192 ${newAction}`))}if(draftValue.conditionGroup&&JSON.stringify(activeRule.conditionGroup)!==JSON.stringify(draftValue.conditionGroup)){let oldConditions=new Set(activeRule.conditionGroup.flatMap(g=>g.conditions.map(c=>formatConditionCompact(c)))),newConditions=new Set(draftValue.conditionGroup.flatMap(g=>g.conditions.map(c=>formatConditionCompact(c)))),added=[...newConditions].filter(c=>!oldConditions.has(c)),removed=[...oldConditions].filter(c=>!newConditions.has(c));for(let c of added)lines.push(import_chalk5.default.green(` + Condition: ${c}`));for(let c of removed)lines.push(import_chalk5.default.red(` - Condition: ${c}`));added.length===0&&removed.length===0&&lines.push(import_chalk5.default.yellow(" ~ Condition groups restructured"))}return lines}var CHANGE_ACTION_ORDER={firewallEnabled:0,"rules.insert":1,"rules.update":2,"rules.remove":3,"rules.priority":4,"ip.insert":5,"ip.update":6,"ip.remove":7,"crs.update":8,"crs.disable":9,"managedRules.update":10,"managedRuleGroup.update":11,"botId.toggle":12,ja3Enabled:13,ja4Enabled:14,"logHeaders.update":15};function formatDiffOutput(changes,activeRules){let lines=[],sorted=[...changes].sort((a,b)=>(CHANGE_ACTION_ORDER[a.action]??99)-(CHANGE_ACTION_ORDER[b.action]??99));for(let change of sorted){let{symbol,color}=getDiffSymbol(change.action),description=formatChangeDescription(change,activeRules);if(lines.push(color(` ${symbol} ${description}`)),change.action==="rules.update"&&activeRules&&change.id){let activeRule=activeRules.get(change.id);if(activeRule&&change.value){let subLines=formatRuleFieldDiff(activeRule,change.value);lines.push(...subLines)}}}return lines.join(`
|
|
27
|
+
`)}var OPERATOR_LABELS={eq:"equals",neq:"does not equal",re:"matches regex",ex:"exists",nex:"does not exist",inc:"is any of",ninc:"is not any of",pre:"starts with",suf:"ends with",sub:"contains",gt:">",gte:">=",lt:"<",lte:"<="},NEGATED_OPERATOR_LABELS={eq:"does not equal",neq:"equals",re:"does not match regex",ex:"does not exist",nex:"exists",inc:"is not any of",ninc:"is any of",pre:"does not start with",suf:"does not end with",sub:"does not contain",gt:"NOT >",gte:"NOT >=",lt:"NOT <",lte:"NOT <="},CONDITION_TYPE_LABELS={path:"path",raw_path:"raw path",target_path:"target path",route:"route",server_action:"server action",method:"method",host:"host",protocol:"protocol",scheme:"scheme",environment:"environment",region:"region",ip_address:"IP address",user_agent:"user agent",geo_country:"geo country",geo_continent:"geo continent",geo_country_region:"state/region",geo_city:"geo city",geo_as_number:"geo AS number",header:"header",cookie:"cookie",query:"query string",ja3_digest:"JA3 digest",ja4_digest:"JA4 digest",request_body:"request body",rate_limit_api_id:"rate limit API ID",bot_name:"bot name",bot_category:"bot category"};function getConditionTypeLabel(type,key){let label=CONDITION_TYPE_LABELS[type]||type;return key?`${label}[${key}]`:label}function getOperatorLabel(op,neg){return neg?NEGATED_OPERATOR_LABELS[op]||`NOT ${OPERATOR_LABELS[op]||op}`:OPERATOR_LABELS[op]||op}function formatConditionValue(condition){return condition.op==="ex"||condition.op==="nex"?"":Array.isArray(condition.value)?condition.value.join(", "):String(condition.value??"")}function formatConditionCompact(condition){let type=getConditionTypeLabel(condition.type,condition.key),op=getOperatorLabel(condition.op,condition.neg),value=formatConditionValue(condition);return value?`${type} ${op} ${value}`:`${type} ${op}`}function formatActionDisplay(action){let mitigate=action.mitigate;if(!mitigate)return import_chalk5.default.dim("None");let actionType=mitigate.action,duration=mitigate.actionDuration;switch(actionType){case"deny":return duration?`Deny (${duration})`:"Deny";case"challenge":return duration?`Challenge (${duration})`:"Challenge";case"log":return"Log";case"bypass":return"Bypass";case"rate_limit":{let rl=mitigate.rateLimit;return rl?`Rate Limit (${rl.limit}/${rl.window}s)`:"Rate Limit"}case"redirect":{let rd=mitigate.redirect;if(rd){let code=rd.permanent?"301":"307";return`Redirect \u2192 ${rd.location} (${code})`}return"Redirect"}default:return actionType}}function formatActionType(action){let type=action.mitigate?.action;return type?type==="rate_limit"?"Rate Limit":type.charAt(0).toUpperCase()+type.slice(1):"None"}function annotateRules(activeRules,draftRules,changes){if(!draftRules)return activeRules.map(rule=>({rule,status:"live"}));let addedIds=new Set(changes.filter(c=>c.action==="rules.insert").map(c=>c.id).filter(id=>id!=null)),removedIds=new Set(changes.filter(c=>c.action==="rules.remove").map(c=>c.id).filter(id=>id!=null)),modifiedIds=new Set(changes.filter(c=>c.action==="rules.update"||c.action==="rules.priority").map(c=>c.id).filter(id=>id!=null)),result=[];for(let rule of draftRules)addedIds.has(rule.id)?result.push({rule,status:"added"}):modifiedIds.has(rule.id)?result.push({rule,status:"modified"}):result.push({rule,status:"live"});for(let rule of activeRules)removedIds.has(rule.id)&&result.push({rule,status:"removed"});return result}function formatActionCompact(action){let mitigate=action.mitigate;if(!mitigate)return"None";let actionType=mitigate.action,duration=mitigate.actionDuration;switch(actionType){case"deny":return duration?`Deny (${duration})`:"Deny";case"challenge":return duration?`Challenge (${duration})`:"Challenge";case"log":return"Log";case"bypass":return"Bypass";case"rate_limit":{let rl=mitigate.rateLimit;return rl?`Rate Limit (${rl.limit}/${rl.window}s)`:"Rate Limit"}case"redirect":return`Redirect (${mitigate.redirect?.permanent?"301":"307"})`;default:return actionType}}function formatRulesTable(annotated,columns=80){let lines=[],numWidth=Math.max(1,String(annotated.length).length),actionTexts=annotated.map(a=>formatActionCompact(a.rule.action)),nameWidth=Math.max(4,...annotated.map(a=>a.rule.name.length)),actionWidth=Math.max(6,...actionTexts.map(t=>t.length)),width=columns>0?columns:80,overflow=2+2+numWidth+3+nameWidth+3+actionWidth+3+8-width;if(overflow>0){let nameShrink=Math.min(overflow,Math.max(0,nameWidth-4));nameWidth-=nameShrink,overflow-=nameShrink}if(overflow>0){let actionShrink=Math.min(overflow,Math.max(0,actionWidth-6));actionWidth-=actionShrink}lines.push(` ${" ".repeat(2)}${import_chalk5.default.dim("#".padEnd(numWidth+3))}${import_chalk5.default.dim("Name".padEnd(nameWidth+3))}${import_chalk5.default.dim("Action".padEnd(actionWidth+3))}${import_chalk5.default.dim("Status")}`);for(let i=0;i<annotated.length;i++){let{rule,status:status2}=annotated[i],num=String(i+1).padEnd(numWidth+3),name=truncateEnd(rule.name,nameWidth,{omission:"\u2026"}).padEnd(nameWidth+3),actionText=truncateEnd(actionTexts[i],actionWidth,{omission:"\u2026"}).padEnd(actionWidth+3),prefix=" ",colorFn=s=>s;status2==="added"?(prefix="+ ",colorFn=import_chalk5.default.green):status2==="removed"?(prefix="- ",colorFn=import_chalk5.default.red):status2==="modified"&&(prefix="~ ",colorFn=import_chalk5.default.yellow);let activeStatusText=rule.active?"Enabled":"Disabled",activeStatus=status2==="removed"?import_chalk5.default.dim(activeStatusText):rule.active?import_chalk5.default.green(activeStatusText):import_chalk5.default.red(activeStatusText);lines.push(colorFn(` ${prefix}${num}${name}${actionText}${activeStatus}`));let idIndent=" ".repeat(2+numWidth+3);lines.push(colorFn(` ${idIndent}${import_chalk5.default.dim(rule.id)}`))}return lines.join(`
|
|
28
|
+
`)}function colorManagedBotAction(action){let label=formatManagedBotAction(action);if(action==="off"||action==="allow"||action==="basic")return import_chalk5.default.dim(label);if(action==="deep-analysis")return import_chalk5.default.green(label);let color=ACTION_COLORS[action];return color?color(label):label}function formatManagedBotRulesTable(rules2){let lines=[],nameWidth=Math.max(4,...rules2.map(r=>r.name.length)),actionWidth=Math.max(6,...rules2.map(r=>formatManagedBotAction(r.action).length));lines.push(` ${import_chalk5.default.bold("Managed")}`),lines.push(""),lines.push(` ${import_chalk5.default.dim("Name".padEnd(nameWidth+3))}${import_chalk5.default.dim("Action".padEnd(actionWidth+3))}${import_chalk5.default.dim("ID")}`);for(let rule of rules2){let name=rule.name.padEnd(nameWidth+3),actionLabel=formatManagedBotAction(rule.action),actionPad=" ".repeat(Math.max(0,actionWidth+3-actionLabel.length));lines.push(` ${name}${colorManagedBotAction(rule.action)}${actionPad}${import_chalk5.default.dim(rule.id)}`)}return lines.join(`
|
|
29
|
+
`)}function formatManagedBotRuleDetail(rule){let lines=[];return lines.push(formatAlignedLabel("Rule",rule.name)),lines.push(formatAlignedLabel("ID",import_chalk5.default.dim(rule.id))),rule.wafRuleId&&lines.push(formatAlignedLabel("WAF ID",import_chalk5.default.dim(rule.wafRuleId))),lines.push(formatAlignedLabel("Action",colorManagedBotAction(rule.action))),lines.join(`
|
|
30
|
+
`)}function formatConditionGroup(group,groupIndex,totalGroups){let lines=[],label=totalGroups>1?`Group ${groupIndex+1} (AND):`:"Conditions:";lines.push(` ${import_chalk5.default.dim(label)}`);for(let condition of group.conditions)lines.push(` ${formatConditionCompact(condition)}`);return lines.join(`
|
|
31
|
+
`)}function formatRuleExpanded(rule,index){let lines=[],prefix=index!==void 0?`${index+1}. `:"",status2=rule.active?import_chalk5.default.green("Enabled"):import_chalk5.default.red("Disabled");if(lines.push(` ${prefix}${import_chalk5.default.bold(rule.name)} [${status2}]`),rule.description&&lines.push(` ${import_chalk5.default.dim(rule.description)}`),lines.push(""),rule.conditionGroup.length===0)lines.push(` ${import_chalk5.default.dim("No conditions")}`);else for(let i=0;i<rule.conditionGroup.length;i++)lines.push(formatConditionGroup(rule.conditionGroup[i],i,rule.conditionGroup.length)),i<rule.conditionGroup.length-1&&lines.push(` ${import_chalk5.default.dim("OR")}`);lines.push(""),lines.push(` ${import_chalk5.default.dim("Action:")} ${formatActionType(rule.action)}`);let duration=rule.action.mitigate?.actionDuration;duration&&rule.action.mitigate?.action!=="rate_limit"&&lines.push(` ${import_chalk5.default.dim("Duration:")} ${duration}`);let rl=rule.action.mitigate?.rateLimit;if(rl&&(lines.push(` ${import_chalk5.default.dim("Rate Limit:")} ${rl.limit} req / ${rl.window}s (${rl.algo})`),lines.push(` ${import_chalk5.default.dim("Keys:")} ${rl.keys.join(", ")}`),rl.action)){let exceeded=duration?`${rl.action} (${duration})`:rl.action;lines.push(` ${import_chalk5.default.dim("If exceeded:")} ${exceeded}`)}let rd=rule.action.mitigate?.redirect;return rd&&lines.push(` ${import_chalk5.default.dim("Redirect:")} ${rd.location} (${rd.permanent?"301 permanent":"307 temporary"})`),lines.join(`
|
|
32
|
+
`)}function formatRuleDetail(rule){let lines=[];if(lines.push(` ${import_chalk5.default.bold("Rule:")} ${rule.name}`),lines.push(` ${import_chalk5.default.bold("ID:")} ${import_chalk5.default.dim(rule.id)}`),lines.push(` ${import_chalk5.default.bold("Status:")} ${rule.active?import_chalk5.default.green("Enabled"):import_chalk5.default.red("Disabled")}`),rule.description&&lines.push(` ${import_chalk5.default.bold("Description:")} ${rule.description}`),lines.push(""),rule.conditionGroup.length===0)lines.push(` ${import_chalk5.default.bold("Conditions:")} ${import_chalk5.default.dim("No conditions")}`);else{lines.push(` ${import_chalk5.default.bold("Conditions:")}`);for(let i=0;i<rule.conditionGroup.length;i++){rule.conditionGroup.length>1&&lines.push(` ${import_chalk5.default.dim(`Group ${i+1} (AND):`)}`);for(let condition of rule.conditionGroup[i].conditions)lines.push(` ${formatConditionCompact(condition)}`);i<rule.conditionGroup.length-1&&lines.push(` ${import_chalk5.default.dim("OR")}`)}}lines.push(""),lines.push(` ${import_chalk5.default.bold("Action:")} ${formatActionType(rule.action)}`);let duration=rule.action.mitigate?.actionDuration;duration&&rule.action.mitigate?.action!=="rate_limit"&&lines.push(` ${import_chalk5.default.bold("Duration:")} ${duration}`);let rl=rule.action.mitigate?.rateLimit;if(rl&&(lines.push(` ${import_chalk5.default.bold("Rate Limit:")}`),lines.push(` Algorithm: ${rl.algo}`),lines.push(` Window: ${rl.window}s`),lines.push(` Limit: ${rl.limit} requests`),lines.push(` Keys: ${rl.keys.join(", ")}`),rl.action)){let exceeded=duration?`${rl.action} (${duration})`:rl.action;lines.push(` If exceeded: ${exceeded}`)}let rd=rule.action.mitigate?.redirect;return rd&&(lines.push(` ${import_chalk5.default.bold("Redirect:")}`),lines.push(` Location: ${rd.location}`),lines.push(` Type: ${rd.permanent?"301 (permanent)":"307 (temporary)"}`)),lines.join(`
|
|
33
|
+
`)}function hasOwaspEntitlement(planInfo){return!!(planInfo?.hasSecurityPlus||planInfo?.isEnterprise)}function getBotProtectionConfig(managedRules){return managedRules?.bot_filter??managedRules?.bot_protection}function formatBotProtectionStatus(ruleset){return ruleset?.active?ruleset.action==="log"?ACTION_COLORS.log("Log"):ruleset.action==="deny"?ACTION_COLORS.deny("Deny"):ACTION_COLORS.challenge("Challenge"):import_chalk5.default.dim("Off")}function formatAiBotsStatus(ruleset){return ruleset?.active?ruleset.action==="log"?ACTION_COLORS.log("Log"):ruleset.action==="challenge"?ACTION_COLORS.challenge("Challenge"):ACTION_COLORS.deny("Deny"):import_chalk5.default.dim("Allow")}function formatOwaspStatus(ruleset){if(!ruleset?.active)return import_chalk5.default.dim("Off");let groups=ruleset.ruleGroups?Object.values(ruleset.ruleGroups):void 0;if(groups&&groups.length>0){let activeGroups=groups.filter(g=>g.active).length;return import_chalk5.default.green(`On (${activeGroups} of ${groups.length} groups)`)}return import_chalk5.default.green("On")}function owaspJsonStatus(ruleset,planInfo){let enabled=!!ruleset?.active,action=enabled?ruleset?.action??null:null;return enabled||hasOwaspEntitlement(planInfo)?{enabled,action}:{enabled:!1,action:null,requiresUpgrade:!0,upgrade:"security-plus"}}var PIPELINE_TOPOLOGY=[{id:"system-rules",order:1,group:"system-rules",label:"System Rules",description:"Vercel-managed protections covering multiple threat categories",configurable:!1,skippableBy:["system"]},{id:"attack-mode",order:2,group:null,label:"Attack Challenge Mode",description:"Challenges all visitors with a verification page when enabled",configurable:!0,skippableBy:[]},{id:"ip-blocking",order:3,group:"custom-rules",label:"IP Blocking",description:"User-configured IP and CIDR block rules",configurable:!0,skippableBy:[]},{id:"custom-rules",order:4,group:"custom-rules",label:"Custom Firewall Rules",description:"User-configured firewall rules",configurable:!0,skippableBy:[]},{id:"bot-management",order:5,group:"managed-rulesets",label:"Bot Management",description:"Automated bot detection and verification",configurable:!0,skippableBy:["system","custom"]},{id:"managed-rulesets",order:6,group:"managed-rulesets",label:"Managed Rulesets",description:"OWASP Top 10 and other curated security rulesets",configurable:!0,skippableBy:["custom"]},{id:"deployment-routing",order:7,group:"routing",label:"Deployment Routing",description:"The request is routed to the deployment and the response is generated",configurable:!1,skippableBy:[]},{id:"response-returned",order:8,group:"routing",label:"Response Returned",description:"If no rules blocked the request, the response is returned",configurable:!1,skippableBy:[]}],BOT_PROTECTION_KEYS=new Set(["bot_filter","bot_protection"]),RULESET_LABELS={owasp:"OWASP",ai_bots:"AI Bots",traffic_sources:"Traffic Sources",vercel_ruleset:"Vercel Ruleset"},ALWAYS_REPORTED_RULESETS=["owasp","ai_bots"];function rulesetId(key){return key.replace(/_/g,"-")}function rulesetLabel(key){return RULESET_LABELS[key]??key.split("_").map(part=>part.charAt(0).toUpperCase()+part.slice(1)).join(" ")}function countCustomBypassRules(active){return active?.rules.filter(r=>r.active&&r.action.mitigate?.action==="bypass").length??0}function getManagedRulesetStates(managedRules,planInfo){return[...ALWAYS_REPORTED_RULESETS,...Object.keys(managedRules??{}).filter(key=>!BOT_PROTECTION_KEYS.has(key)&&!ALWAYS_REPORTED_RULESETS.includes(key))].map(key=>[key,managedRules?.[key]]).map(([key,value])=>{let id=rulesetId(key),label=rulesetLabel(key);if(key==="owasp"){let owasp=owaspJsonStatus(value,planInfo);return owasp.requiresUpgrade?{id,label,state:"unavailable",unavailable:{reason:"plan",upgrade:owasp.upgrade}}:{id,label,state:owasp.enabled?"active":"inactive",action:owasp.action}}return{id,label,state:value?.active?"active":"inactive",action:value?.active?value.action??null:null}})}function getManagedRulesetsState(rulesets){let configurable=rulesets.filter(r=>r.state!=="unavailable"),active=configurable.filter(r=>r.state==="active").length;return active===0?"inactive":active===configurable.length?"active":"partial"}function getFirewallPipeline(opts){let{active,bypass,attackMode,planInfo,firewallBypassIps}=opts,systemBypassIps=bypass?.filter(b=>!isAllSourcesBypass(b.Ip))??[],customBypassRules=countCustomBypassRules(active),bypasses={system:bypass===null?{state:"unknown",skips:[]}:{state:systemBypassIps.length>0?"active":"inactive",count:systemBypassIps.length,skips:[]},custom:{state:customBypassRules>0?"active":"inactive",count:customBypassRules,skips:[]}};for(let kind of["system","custom"])bypasses[kind].skips=PIPELINE_TOPOLOGY.filter(s=>s.skippableBy.includes(kind)).map(s=>s.id);let mitigationsPaused=getMitigationsStatus(firewallBypassIps,bypass).paused,botProtection=getBotProtectionConfig(active?.managedRules),managedRulesets=getManagedRulesetStates(active?.managedRules,planInfo),activeRules=active?.rules.filter(r=>r.active).length??0,ipBlocks=active?.ips.length??0,requestFlow=PIPELINE_TOPOLOGY.map(topology=>{let skippedBy=topology.skippableBy.filter(kind=>bypasses[kind].state==="active"),base={...topology,skippedBy};switch(topology.id){case"system-rules":return{...base,state:mitigationsPaused?"inactive":"active"};case"attack-mode":return{...base,state:attackMode?.enabled?"active":"inactive"};case"ip-blocking":return{...base,state:ipBlocks>0?"active":"inactive",count:ipBlocks};case"custom-rules":return{...base,state:active?.firewallEnabled&&activeRules>0?"active":"inactive",count:activeRules};case"bot-management":return{...base,state:botProtection?.active?"active":"inactive",action:botProtection?.action??null};case"managed-rulesets":return{...base,state:getManagedRulesetsState(managedRulesets),count:managedRulesets.filter(r=>r.state==="active").length,rulesets:managedRulesets};default:return{...base,state:"terminal"}}});return{bypasses,requestFlow}}function isPlanGatedError(error){return isAPIError(error)&&error.status===402}function planGateMessage(error){return apiServerMessage(error)??"IP Bypass requires a Pro or Enterprise plan."}function readBypassResult(result){if(result.status==="fulfilled")return{bypass:result.value.result};if(!isPlanGatedError(result.reason))throw result.reason;return{bypass:null,unavailable:{reason:"plan",message:planGateMessage(result.reason)}}}function resolveFirewallEntitlements(planInfo,project){return{isEnterprise:planInfo?.isEnterprise,hasSecurityPlus:!!(planInfo?.hasSecurityPlus||project.security?.securityPlus)}}function isActivityUnavailable(error){return isAPIError(error)&&error.status===402}function activityIssue(error){if(isActivityUnavailable(error))return{reason:"plan",message:FIREWALL_ACTIVITY_PLAN_MESSAGE};if(isActivityTimeout(error))return{reason:"timeout",message:"Traffic and alerts timed out."}}function unwrap(result){if(result.status==="rejected")throw result.reason;return result.value}var ACTIVITY_WINDOW_MS=24*60*60*1e3;async function fetchActivity(client,projectId,teamId,active){let granularity={hours:1},now=new Date,{startTime,endTime}=alignQueryWindow(new Date(now.getTime()-ACTIVITY_WINDOW_MS),now,granularity);output_manager_default.spinner("Fetching firewall activity");let[metrics,alertsResult,topRules]=await Promise.all([getFirewallMetrics(client,{projectId,ownerId:teamId,startTime,endTime,granularity}),getFirewallAlertsDetailed(client,{projectId,teamId,sinceDays:1}),getTopList(client,{ownerId:teamId,projectId,groupBy:[RULE_ID_DIMENSION],filter:RULE_TRAFFIC_FILTER,startTime,endTime,top:topListFetchCount(OVERVIEW_TOP_RULES)})]),rules2=topRules.filter(row=>row.values[RULE_ID_DIMENSION]).slice(0,OVERVIEW_TOP_RULES).map(row=>{let id=row.values[RULE_ID_DIMENSION];return{id,name:resolveRuleDisplayName(id,active),total:row.total}}),windowStart=startTime.getTime(),windowEnd=endTime.getTime(),annotations=alertsResult.alerts.filter(a=>alertOverlapsWindow(a,windowStart,windowEnd));return{metrics,rules:rules2,annotations,attacksMitigated:countAttacksMitigated(alertsResult.alerts,windowStart,windowEnd),alertsUnavailable:alertsResult.errors.length>0?{sources:alertsResult.errors.map(e=>e.source),message:alertsIncompleteMessage(alertsResult.errors)}:void 0}}async function overview(client,argv){let parsed=await parseSubcommandArgs(argv,overviewSubcommand,client);if(typeof parsed=="number")return parsed;let asJson=!!parsed.flags["--json"],suggestedCommand=`firewall overview${asJson?" --json":""}`,link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;output_manager_default.spinner(`Fetching firewall overview for ${import_chalk6.default.bold(project.name)}`);try{let[configResult,bypassResult,projectResult,planResult]=await Promise.allSettled([listFirewallConfigs(client,projectScope(project,teamId)),getBypass(client,project.id,{teamId}),client.fetch(`/v9/projects/${encodeURIComponent(project.id)}`,{accountId:teamId}),fetchPlanInfo(client)]),{active,draft}=unwrap(configResult),freshProject=unwrap(projectResult),{bypass,unavailable:bypassUnavailable}=readBypassResult(bypassResult),planInfo=resolveFirewallEntitlements(planResult.status==="fulfilled"?planResult.value:void 0,freshProject),attackMode={enabled:freshProject.security?.attackModeEnabled??!1,activeUntil:freshProject.security?.attackModeActiveUntil},activity=null,activityIssueFound;if(teamId)try{activity=await fetchActivity(client,project.id,teamId,active)}catch(e){let issue=activityIssue(e);if(!issue)throw e;activityIssueFound=issue}return asJson?(outputJson(client,{active,draft,bypass,...bypassUnavailable?{bypassUnavailable}:{},attackMode,period:activity?{start:activity.metrics.startTime,end:activity.metrics.endTime,granularity:activity.metrics.granularity}:null,stats:activity?{attacksMitigated:activity.attacksMitigated,...activity.metrics.totals}:null,series:activity?.metrics.series.map(({action,timeseries})=>({action,timeseries}))??null,topRules:activity?.rules??null,annotations:activity?.annotations??null,...activityIssueFound?{activityUnavailable:activityIssueFound}:{},...activity?.alertsUnavailable?{alertsUnavailable:activity.alertsUnavailable}:{}}),0):(output_manager_default.print(`
|
|
34
|
+
`),output_manager_default.print(formatStatusOutput({active,draft,bypass,attackMode,planInfo,firewallBypassIps:freshProject.security?.firewallBypassIps})),output_manager_default.print(`
|
|
35
|
+
|
|
36
|
+
`),activityIssueFound&&output_manager_default.print(` ${import_chalk6.default.dim(activityIssueFound.message)}
|
|
37
|
+
`),activity&&output_manager_default.print(formatOverviewOutput({series:activity.metrics.series,attacksMitigated:activity.attacksMitigated,attacksMitigatedIncomplete:!!activity.alertsUnavailable,annotations:activity.annotations,rules:activity.rules,startTime:activity.metrics.startTime,endTime:activity.metrics.endTime,granularity:activity.metrics.granularity})),activity?.alertsUnavailable&&output_manager_default.print(` ${import_chalk6.default.dim(activity.alertsUnavailable.message)}
|
|
38
|
+
`),0)}catch(e){return failFirewallApi(client,e,{fallback:"Failed to fetch firewall overview",nextCommand:suggestedCommand,permissionAction:"read firewall configuration",projectName:project.name,timeoutJob:"firewall overview"})}}var import_chalk7=__toESM(require_source(),1);function unwrap2(result){if(result.status==="rejected")throw result.reason;return result.value}async function status(client,argv){let parsed=await parseSubcommandArgs(argv,statusSubcommand,client);if(typeof parsed=="number")return parsed;let asJson=!!parsed.flags["--json"],suggestedCommand=`firewall status${asJson?" --json":""}`,link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;output_manager_default.spinner(`Fetching firewall status for ${import_chalk7.default.bold(project.name)}`);try{let[configResult,bypassResult,projectResult,planResult]=await Promise.allSettled([listFirewallConfigs(client,projectScope(project,teamId)),getBypass(client,project.id,{teamId}),client.fetch(`/v9/projects/${encodeURIComponent(project.id)}`,{accountId:teamId}),fetchPlanInfo(client)]),{active,draft}=unwrap2(configResult),freshProject=unwrap2(projectResult),{bypass,unavailable:bypassUnavailable}=readBypassResult(bypassResult),planInfo=resolveFirewallEntitlements(planResult.status==="fulfilled"?planResult.value:void 0,freshProject),attackMode={enabled:freshProject.security?.attackModeEnabled??!1,activeUntil:freshProject.security?.attackModeActiveUntil};if(asJson){let botProtection=getBotProtectionConfig(active?.managedRules),aiBots=active?.managedRules?.ai_bots;return outputJson(client,{firewallEnabled:active?.firewallEnabled??!1,attackMode,bypass,...bypassUnavailable?{bypassUnavailable}:{},botProtection:{enabled:botProtection?.active??!1,action:botProtection?.action??null},aiBots:{enabled:aiBots?.active??!1,action:aiBots?.action??null},owasp:owaspJsonStatus(active?.managedRules?.owasp,planInfo),...getFirewallPipeline({active,bypass,attackMode,planInfo,firewallBypassIps:freshProject.security?.firewallBypassIps}),rules:{active:active?.rules.filter(r=>r.active).length??0,inactive:active?.rules.filter(r=>!r.active).length??0,total:active?.rules.length??0},ipBlocks:active?.ips.length??0,draftChanges:draft?.changes.length??0}),0}return output_manager_default.print(`
|
|
39
|
+
`),output_manager_default.print(formatStatusOutput({active,draft,bypass,attackMode,planInfo,firewallBypassIps:freshProject.security?.firewallBypassIps})),output_manager_default.print(`
|
|
40
|
+
|
|
41
|
+
`),0}catch(e){return failFirewallApi(client,e,{fallback:"Failed to fetch firewall status",nextCommand:suggestedCommand,permissionAction:"read firewall status",projectName:project.name,timeoutJob:"firewall status"})}finally{output_manager_default.stopSpinner()}}var import_chalk8=__toESM(require_source(),1);async function diff(client,argv){let parsed=await parseSubcommandArgs(argv,diffSubcommand,client);if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;output_manager_default.spinner(`Fetching draft changes for ${import_chalk8.default.bold(scope.displayName)}`);try{let{active,draft}=await listFirewallConfigs(client,scope);if(!draft||draft.changes.length===0)return parsed.flags["--json"]?(outputJson(client,{changes:[]}),0):(output_manager_default.log("No pending changes."),0);if(parsed.flags["--json"])return outputJson(client,{changes:draft.changes}),0;let activeRulesMap=new Map((active?.rules||[]).map(r=>[r.id,r]));return output_manager_default.print(`
|
|
42
|
+
${import_chalk8.default.bold(`Pending changes (${draft.changes.length}):`)}
|
|
43
|
+
|
|
44
|
+
`),output_manager_default.print(formatDiffOutput(draft.changes,activeRulesMap)),output_manager_default.print(`
|
|
45
|
+
|
|
46
|
+
`),output_manager_default.print(` Run ${import_chalk8.default.cyan(withGlobalFlags(client,"firewall publish",scope))} to publish, or ${import_chalk8.default.cyan(withGlobalFlags(client,"firewall discard",scope))} to discard.
|
|
47
|
+
|
|
48
|
+
`),0}catch(e){let msg=mapFirewallApiError(e,scope,"Failed to fetch draft changes");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,"firewall diff",scope)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk9=__toESM(require_source(),1);async function publish(client,argv){let parsed=await parseSubcommandArgs(argv,publishSubcommand,client);if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;output_manager_default.spinner(`Fetching draft changes for ${import_chalk9.default.bold(scope.displayName)}`);try{let{active,draft}=await listFirewallConfigs(client,scope);if(!draft||draft.changes.length===0)return output_manager_default.warn("No draft changes to publish."),0;let activeRulesMap=new Map((active?.rules||[]).map(r=>[r.id,r]));if(output_manager_default.print(`
|
|
49
|
+
${import_chalk9.default.bold(`Changes to be published (${draft.changes.length}):`)}
|
|
50
|
+
|
|
51
|
+
`),output_manager_default.print(formatDiffOutput(draft.changes,activeRulesMap)),output_manager_default.print(`
|
|
52
|
+
|
|
53
|
+
`),!await confirmAction(client,parsed.flags["--yes"],"Publish these changes to production?",scope.type==="team"?`This will make them live team-wide for ${import_chalk9.default.bold(scope.displayName)}.`:`This will make them live for ${import_chalk9.default.bold(scope.displayName)}.`))return output_manager_default.log("Canceled"),0;let updateStamp=stamp_default();return output_manager_default.spinner("Publishing to production"),await activateFirewallConfig(client,scope,"draft"),output_manager_default.log(`${import_chalk9.default.cyan("Success!")} Firewall config published to production ${import_chalk9.default.gray(updateStamp())}`),0}catch(e){let msg=mapFirewallApiError(e,scope,"Failed to publish firewall config");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,"firewall publish --yes",scope)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk10=__toESM(require_source(),1);async function deleteFirewallDraft(client,scope){await client.fetch(firewallConfigUrl(scope,"/draft"),{method:"DELETE"})}async function discard(client,argv){let parsed=await parseSubcommandArgs(argv,discardSubcommand,client);if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;output_manager_default.spinner(`Fetching draft changes for ${import_chalk10.default.bold(scope.displayName)}`);try{let{active,draft}=await listFirewallConfigs(client,scope);if(!draft||draft.changes.length===0)return output_manager_default.warn("No draft changes to discard."),0;let activeRulesMap=new Map((active?.rules||[]).map(r=>[r.id,r]));if(output_manager_default.print(`
|
|
54
|
+
${import_chalk10.default.bold(`Changes to be discarded (${draft.changes.length}):`)}
|
|
55
|
+
|
|
56
|
+
`),output_manager_default.print(formatDiffOutput(draft.changes,activeRulesMap)),output_manager_default.print(`
|
|
57
|
+
|
|
58
|
+
`),!await confirmAction(client,parsed.flags["--yes"],"Discard all draft changes?","This action cannot be undone."))return output_manager_default.log("Canceled"),0;let updateStamp=stamp_default();return output_manager_default.spinner("Discarding draft changes"),await deleteFirewallDraft(client,scope),output_manager_default.log(`${import_chalk10.default.cyan("Success!")} Draft changes discarded ${import_chalk10.default.gray(updateStamp())}`),0}catch(e){let msg=mapFirewallApiError(e,scope,"Failed to discard draft changes");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,"firewall discard --yes",scope)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk11=__toESM(require_source(),1);async function list(client,argv){let parsed=await parseSubcommandArgs(argv,systemBypassListSubcommand,client,"system-bypass list");if(typeof parsed=="number")return parsed;let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;output_manager_default.spinner(`Fetching system bypass rules for ${import_chalk11.default.bold(project.name)}`);try{let{result:allBypasses}=await getBypass(client,project.id,{teamId}),bypasses=allBypasses.filter(b=>!isAllSourcesBypass(b.Ip));return parsed.flags["--json"]?(outputJson(client,bypasses),0):bypasses.length===0?(output_manager_default.log("No system bypass rules configured."),0):(output_manager_default.print(`
|
|
59
|
+
${formatBypassTable(bypasses)}
|
|
60
|
+
|
|
61
|
+
`),0)}catch(e){let msg=e.message||"Failed to fetch bypass rules";return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,"firewall system-bypass list")}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk12=__toESM(require_source(),1);async function addBypass(client,projectId,body,options={}){let{teamId}=options,query=new URLSearchParams;query.set("projectId",projectId),teamId&&query.set("teamId",teamId);let url=`/v1/security/firewall/bypass?${query.toString()}`;return client.fetch(url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)})}import{isIP as isIP2}from"node:net";function parseCidr(input){let slashIndex=input.lastIndexOf("/");if(slashIndex===-1)return null;let ip=input.slice(0,slashIndex),prefixStr=input.slice(slashIndex+1),prefix=Number.parseInt(prefixStr,10);return Number.isNaN(prefix)||prefix<0||String(prefix)!==prefixStr?null:{ip,prefix}}function ipVersion(ip){return isIP2(ip)}function validateBypassIp(input){let version=ipVersion(input);if(version===4||version===6)return null;let cidr=parseCidr(input);if(!cidr)return"Please enter a valid IP address or CIDR.";let cidrVersion=ipVersion(cidr.ip);if(cidrVersion===0)return"Please enter a valid IP address or CIDR.";if(cidrVersion===4){if(cidr.prefix>32)return"Please enter a valid IP address or CIDR.";if(input==="0.0.0.0/0")return null;if(cidr.prefix<16)return"IPv4 CIDR cannot have a net mask less than /16."}if(cidrVersion===6){if(cidr.prefix>128)return"Please enter a valid IP address or CIDR.";if(input==="::/0")return null;if(cidr.prefix<16)return"IPv6 CIDR cannot have a net mask less than /16."}return null}function validateBlockingIp(input){let version=ipVersion(input);if(version===4||version===6)return null;let cidr=parseCidr(input);if(!cidr)return"Please enter a valid IP address or CIDR.";let cidrVersion=ipVersion(cidr.ip);if(cidrVersion===0)return"Please enter a valid IP address or CIDR.";if(cidrVersion===4){if(cidr.prefix>32)return"Please enter a valid IP address or CIDR.";if(cidr.prefix<16)return"IPv4 CIDR cannot have a net mask less than /16."}if(cidrVersion===6){if(cidr.prefix>128)return"Please enter a valid IP address or CIDR.";if(cidr.prefix<48)return"IPv6 CIDR cannot have a net mask less than /48."}return null}function validateHostname(input){return/^\*{1}$|^(?!-)(?:\*\.)?[A-Za-z0-9-]{1,63}(?<!-)(?:\.(?!-)[A-Za-z0-9-]{1,63}(?<!-))*$/.test(input)?null:"Please enter a valid domain (e.g. example.com, *.example.com, or * for all domains)."}function validateNote(input){return input.length>500?`Note must be 500 characters or less (currently ${input.length}).`:null}async function add(client,argv){let parsed=await parseSubcommandArgs(argv,systemBypassAddSubcommand,client,"system-bypass add");if(typeof parsed=="number")return parsed;let ip=parsed.args[0];if(!ip)return output_manager_default.error("Missing required argument: <ip>"),2;let ipError=validateBypassIp(ip);if(ipError)return output_manager_default.error(ipError),1;let domain=parsed.flags["--domain"],notes=parsed.flags["--notes"];if(domain){let domainError=validateHostname(domain);if(domainError)return output_manager_default.error(domainError),1}if(notes){let noteError=validateNote(notes);if(noteError)return output_manager_default.error(noteError),1}let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0,scopeLabel=domain||"all domains";if(!await confirmAction(client,parsed.flags["--yes"],`Add system bypass for ${import_chalk12.default.bold(ip)} on ${import_chalk12.default.bold(scopeLabel)}?`))return output_manager_default.log("Canceled"),0;let addStamp=stamp_default();output_manager_default.spinner("Adding system bypass rule");try{return await addBypass(client,project.id,{sourceIp:ip,...domain?{domain}:{projectScope:!0},...notes?{note:notes}:{}},{teamId}),output_manager_default.log(`${import_chalk12.default.cyan("Success!")} Added system bypass for ${import_chalk12.default.bold(ip)} on ${import_chalk12.default.bold(scopeLabel)} ${import_chalk12.default.gray(addStamp())}`),0}catch(e){let msg=e.message||"Failed to add bypass rule";return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,`firewall system-bypass add ${ip}${domain?` --domain ${domain}`:""}${notes?` --notes "${notes}"`:""} --yes`)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk13=__toESM(require_source(),1);async function removeBypass(client,projectId,body,options={}){let{teamId}=options,query=new URLSearchParams;query.set("projectId",projectId),teamId&&query.set("teamId",teamId);let url=`/v1/security/firewall/bypass?${query.toString()}`;return client.fetch(url,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)})}async function remove(client,argv){let parsed=await parseSubcommandArgs(argv,systemBypassRemoveSubcommand,client,"system-bypass remove");if(typeof parsed=="number")return parsed;let ip=parsed.args[0];if(!ip)return output_manager_default.error("Missing required argument: <ip>"),2;let ipError=validateBypassIp(ip);if(ipError)return output_manager_default.error(ipError),1;let domain=parsed.flags["--domain"];if(domain){let domainError=validateHostname(domain);if(domainError)return output_manager_default.error(domainError),1}let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0,scopeLabel=domain||"all domains";if(!await confirmAction(client,parsed.flags["--yes"],`Remove system bypass for ${import_chalk13.default.bold(ip)} on ${import_chalk13.default.bold(scopeLabel)}?`))return output_manager_default.log("Canceled"),0;let removeStamp=stamp_default();output_manager_default.spinner("Removing system bypass rule");try{return await removeBypass(client,project.id,{sourceIp:ip,...domain?{domain}:{projectScope:!0}},{teamId}),output_manager_default.log(`${import_chalk13.default.cyan("Success!")} Removed system bypass for ${import_chalk13.default.bold(ip)} ${import_chalk13.default.gray(removeStamp())}`),0}catch(e){let error=e;if(error.status===404)return output_manager_default.error(`No bypass rule found for ${import_chalk13.default.bold(ip)}. Run ${import_chalk13.default.cyan(withGlobalFlags(client,"firewall system-bypass list"))} to view all rules.`),1;let msg=error.message||"Failed to remove bypass rule";return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,`firewall system-bypass remove ${ip}${domain?` --domain ${domain}`:""} --yes`)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var COMMAND_CONFIG={list:getCommandAliases(systemBypassListSubcommand),add:getCommandAliases(systemBypassAddSubcommand),remove:getCommandAliases(systemBypassRemoveSubcommand)};async function main(client,args,telemetry){let flagsSpecification=getFlagsSpecification(systemBypassSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(args,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall","system-bypass"),output_manager_default.print(help(systemBypassSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand){case"list":return needHelp?(telemetry.trackCliFlagHelp("firewall",`system-bypass:${subcommandOriginal}`),printHelp(systemBypassListSubcommand),0):(telemetry.trackCliSubcommandSystemBypassList(subcommandOriginal),list(client,subArgs));case"add":return needHelp?(telemetry.trackCliFlagHelp("firewall",`system-bypass:${subcommandOriginal}`),printHelp(systemBypassAddSubcommand),0):(telemetry.trackCliSubcommandSystemBypassAdd(subcommandOriginal),add(client,subArgs));case"remove":return needHelp?(telemetry.trackCliFlagHelp("firewall",`system-bypass:${subcommandOriginal}`),printHelp(systemBypassRemoveSubcommand),0):(telemetry.trackCliSubcommandSystemBypassRemove(subcommandOriginal),remove(client,subArgs));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG)),output_manager_default.print(help(systemBypassSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),2}}var import_chalk14=__toESM(require_source(),1);async function updateAttackMode(client,body){return client.fetch("/security/attack-mode",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)})}var DURATION_MAP={"1h":60*60*1e3,"6h":6*60*60*1e3,"24h":24*60*60*1e3},VALID_DURATIONS2=Object.keys(DURATION_MAP);async function enable(client,argv){let parsed=await parseSubcommandArgs(argv,attackModeEnableSubcommand,client,"attack-mode enable");if(typeof parsed=="number")return parsed;if(client.nonInteractive)return outputAgentError(client,{status:"error",reason:"dangerous_operation_requires_user",message:"Enabling attack mode challenges all visitors and cannot be performed non-interactively. Agents must not make this change on behalf of a user. The user must run this command interactively in a terminal to review the impact and confirm.",next:[{command:withGlobalFlags(client,"firewall attack-mode enable"),when:"user runs this command interactively"}]},1),1;if(!client.stdin.isTTY)return output_manager_default.error("Enabling attack mode requires interactive confirmation. Please run this command in an interactive terminal."),1;let duration=parsed.flags["--duration"]||"1h";if(!DURATION_MAP[duration])return output_manager_default.error(`Invalid duration "${duration}". Valid options: ${VALID_DURATIONS2.join(", ")}`),1;let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project}=link;if(!await confirmAction(client,parsed.flags["--yes"],`Enable attack mode for ${import_chalk14.default.bold(project.name)} (${import_chalk14.default.bold(duration)})?`,`${import_chalk14.default.yellow("Warning:")} Every visitor will be shown a verification challenge before accessing your site. This may impact legitimate traffic and SEO. Attack mode automatically expires after ${duration}.`))return output_manager_default.log("Canceled"),0;let updateStamp=stamp_default();output_manager_default.spinner("Enabling attack mode");try{return await updateAttackMode(client,{projectId:project.id,attackModeEnabled:!0,attackModeActiveUntil:Date.now()+DURATION_MAP[duration]}),output_manager_default.log(`${import_chalk14.default.cyan("Success!")} Attack mode enabled for ${import_chalk14.default.bold(duration)} ${import_chalk14.default.gray(updateStamp())}`),0}catch(e){let msg=e.message||"Failed to enable attack mode";return output_manager_default.error(msg),1}}var import_chalk15=__toESM(require_source(),1);async function disable(client,argv){let parsed=await parseSubcommandArgs(argv,attackModeDisableSubcommand,client,"attack-mode disable");if(typeof parsed=="number")return parsed;if(client.nonInteractive)return outputAgentError(client,{status:"error",reason:"dangerous_operation_requires_user",message:"Disabling attack mode affects traffic handling and cannot be performed non-interactively. Agents must not make this change on behalf of a user. The user must run this command interactively in a terminal.",next:[{command:withGlobalFlags(client,"firewall attack-mode disable"),when:"user runs this command interactively"}]},1),1;if(!client.stdin.isTTY)return output_manager_default.error("Disabling attack mode requires interactive confirmation. Please run this command in an interactive terminal."),1;let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project}=link;if(!await confirmAction(client,parsed.flags["--yes"],`Disable attack mode for ${import_chalk15.default.bold(project.name)}?`,"Visitors will no longer be shown a verification challenge."))return output_manager_default.log("Canceled"),0;let updateStamp=stamp_default();output_manager_default.spinner("Disabling attack mode");try{return await updateAttackMode(client,{projectId:project.id,attackModeEnabled:!1}),output_manager_default.log(`${import_chalk15.default.cyan("Success!")} Attack mode disabled ${import_chalk15.default.gray(updateStamp())}`),0}catch(e){let msg=e.message||"Failed to disable attack mode";return output_manager_default.error(msg),1}}var COMMAND_CONFIG2={enable:getCommandAliases(attackModeEnableSubcommand),disable:getCommandAliases(attackModeDisableSubcommand)};async function main2(client,args,telemetry){let flagsSpecification=getFlagsSpecification(attackModeSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(args,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG2),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall","attack-mode"),output_manager_default.print(help(attackModeSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand){case"enable":return needHelp?(telemetry.trackCliFlagHelp("firewall",`attack-mode:${subcommandOriginal}`),printHelp(attackModeEnableSubcommand),0):(telemetry.trackCliSubcommandAttackModeEnable(subcommandOriginal),enable(client,subArgs));case"disable":return needHelp?(telemetry.trackCliFlagHelp("firewall",`attack-mode:${subcommandOriginal}`),printHelp(attackModeDisableSubcommand),0):(telemetry.trackCliSubcommandAttackModeDisable(subcommandOriginal),disable(client,subArgs));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG2)),output_manager_default.print(help(attackModeSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),2}}var import_chalk16=__toESM(require_source(),1);async function pause(client,argv){let parsed=await parseSubcommandArgs(argv,systemMitigationsPauseSubcommand,client,"system-mitigations pause");if(typeof parsed=="number")return parsed;if(client.nonInteractive)return outputAgentError(client,{status:"error",reason:"dangerous_operation_requires_user",message:"Pausing system mitigations disables DDoS protection and cannot be performed non-interactively. Agents must not make this change on behalf of a user. The user must run this command interactively in a terminal to review the impact and confirm.",next:[{command:withGlobalFlags(client,"firewall system-mitigations pause"),when:"user runs this command interactively"}]},1),1;if(!client.stdin.isTTY)return output_manager_default.error("Pausing system mitigations requires interactive confirmation. Please run this command in an interactive terminal."),1;let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;if(!await confirmAction(client,parsed.flags["--yes"],`Pause system mitigations for ${import_chalk16.default.bold(project.name)}?`,`${import_chalk16.default.yellow("Warning:")} This disables automatic DDoS protection, bot mitigation, and system-level traffic filtering for 24 hours. Your project will be unprotected from automated attacks during this period. Auto-resumes after 24 hours.`))return output_manager_default.log("Canceled"),0;let pauseStamp=stamp_default();output_manager_default.spinner("Pausing system mitigations");try{return await addBypass(client,project.id,{allSources:!0,projectScope:!0},{teamId}),output_manager_default.log(`${import_chalk16.default.cyan("Success!")} System mitigations paused for ${import_chalk16.default.bold(project.name)}. Auto-resumes in 24 hours. ${import_chalk16.default.gray(pauseStamp())}`),0}catch(e){let msg=e.message||"Failed to pause system mitigations";return output_manager_default.error(msg),1}}var import_chalk17=__toESM(require_source(),1);async function resume(client,argv){let parsed=await parseSubcommandArgs(argv,systemMitigationsResumeSubcommand,client,"system-mitigations resume");if(typeof parsed=="number")return parsed;if(client.nonInteractive)return outputAgentError(client,{status:"error",reason:"dangerous_operation_requires_user",message:"Resuming system mitigations affects traffic protection and cannot be performed non-interactively. Agents must not make this change on behalf of a user. The user must run this command interactively in a terminal.",next:[{command:withGlobalFlags(client,"firewall system-mitigations resume"),when:"user runs this command interactively"}]},1),1;if(!client.stdin.isTTY)return output_manager_default.error("Resuming system mitigations requires interactive confirmation. Please run this command in an interactive terminal."),1;let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;if(!await confirmAction(client,parsed.flags["--yes"],`Resume system mitigations for ${import_chalk17.default.bold(project.name)}?`,"Automatic DDoS protection and system-level traffic filtering will be re-enabled immediately."))return output_manager_default.log("Canceled"),0;let resumeStamp=stamp_default();output_manager_default.spinner("Resuming system mitigations");try{return await removeBypass(client,project.id,{allSources:!0,projectScope:!0},{teamId}),output_manager_default.log(`${import_chalk17.default.cyan("Success!")} System mitigations resumed for ${import_chalk17.default.bold(project.name)} ${import_chalk17.default.gray(resumeStamp())}`),0}catch(e){let msg=e.message||"Failed to resume system mitigations";return output_manager_default.error(msg),1}}var COMMAND_CONFIG3={pause:getCommandAliases(systemMitigationsPauseSubcommand),resume:getCommandAliases(systemMitigationsResumeSubcommand)};async function main3(client,args,telemetry){let flagsSpecification=getFlagsSpecification(systemMitigationsSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(args,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG3),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall","system-mitigations"),output_manager_default.print(help(systemMitigationsSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand){case"pause":return needHelp?(telemetry.trackCliFlagHelp("firewall",`system-mitigations:${subcommandOriginal}`),printHelp(systemMitigationsPauseSubcommand),0):(telemetry.trackCliSubcommandSystemMitigationsPause(subcommandOriginal),pause(client,subArgs));case"resume":return needHelp?(telemetry.trackCliFlagHelp("firewall",`system-mitigations:${subcommandOriginal}`),printHelp(systemMitigationsResumeSubcommand),0):(telemetry.trackCliSubcommandSystemMitigationsResume(subcommandOriginal),resume(client,subArgs));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG3)),output_manager_default.print(help(systemMitigationsSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),2}}var import_chalk18=__toESM(require_source(),1);async function list2(client,argv){let parsed=await parseSubcommandArgs(argv,ipBlocksListSubcommand,client,"ip-blocks list");if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;output_manager_default.spinner(`Fetching IP blocking rules for ${import_chalk18.default.bold(scope.displayName)}`);try{let{active,draft}=await listFirewallConfigs(client,scope),activeIps=active?.ips||[],draftIps=draft?.ips||null,changes=draft?.changes||[],hasDraftChanges=changes.length>0,annotated=annotateIpRules(activeIps,draftIps,changes);if(parsed.flags["--json"])return outputJson(client,{rules:annotated.map(a=>({...a.rule,_status:a.status})),hasDraft:hasDraftChanges,pendingChanges:changes.length}),0;if(annotated.length===0)return output_manager_default.log("No IP blocking rules configured."),0;output_manager_default.print(`
|
|
62
|
+
${formatIpBlocksTable(annotated)}
|
|
63
|
+
`);let ipChanges=changes.filter(c=>c.action.startsWith("ip.")).length;return ipChanges>0?output_manager_default.print(`
|
|
64
|
+
${import_chalk18.default.yellow(`${ipChanges} unpublished IP block change${ipChanges!==1?"s":""}.`)} Run ${import_chalk18.default.cyan(withGlobalFlags(client,"firewall publish",scope))} to publish.
|
|
65
|
+
`):output_manager_default.print(`
|
|
66
|
+
${import_chalk18.default.dim("Showing live configuration.")}
|
|
67
|
+
`),output_manager_default.print(`
|
|
68
|
+
`),0}catch(e){let msg=mapFirewallApiError(e,scope,"Failed to fetch IP blocking rules");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,"firewall ip-blocks list",scope)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk19=__toESM(require_source(),1);async function patchFirewallDraft(client,scope,patch){return client.fetch(firewallConfigUrl(scope,"/draft"),{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(patch)})}async function block(client,argv){let parsed=await parseSubcommandArgs(argv,ipBlocksBlockSubcommand,client,"ip-blocks block");if(typeof parsed=="number")return parsed;let ip=parsed.args[0];if(!ip)return output_manager_default.error("Missing required argument: <ip>"),2;let ipError=validateBlockingIp(ip);if(ipError)return output_manager_default.error(ipError),1;let hostnameFlag=parsed.flags["--hostname"],hostname=hostnameFlag&&hostnameFlag!==""?hostnameFlag:"*",notes=parsed.flags["--notes"];if(hostname!=="*"){let hostnameError=validateHostname(hostname);if(hostnameError)return output_manager_default.error(hostnameError),1}if(notes){let noteError=validateNote(notes);if(noteError)return output_manager_default.error(noteError),1}let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;let hostnameLabel=hostname==="*"||hostname===""?"all hosts":hostname;if(!await confirmAction(client,parsed.flags["--yes"],`Block ${import_chalk19.default.bold(ip)} on ${import_chalk19.default.bold(hostnameLabel)}?`))return output_manager_default.log("Canceled"),0;let blockStamp=stamp_default();output_manager_default.spinner("Staging IP block rule");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"ip.insert",id:null,value:{ip,hostname,action:"deny",...notes?{notes}:{}}}),output_manager_default.log(`${import_chalk19.default.cyan("Success!")} IP block for ${import_chalk19.default.bold(ip)} on ${import_chalk19.default.bold(hostnameLabel)} staged ${import_chalk19.default.gray(blockStamp())}`),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:parsed.flags["--yes"]}),0}catch(e){let msg=mapFirewallApiError(e,scope,"Failed to stage IP block rule");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,`firewall ip-blocks block ${ip}${hostname!=="*"?` --hostname ${hostname}`:""} --yes`,scope)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk20=__toESM(require_source(),1);async function unblock(client,argv){let parsed=await parseSubcommandArgs(argv,ipBlocksUnblockSubcommand,client,"ip-blocks unblock");if(typeof parsed=="number")return parsed;let identifier=parsed.args[0];if(!identifier)return output_manager_default.error("Missing required argument: <id-or-ip>"),2;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;output_manager_default.spinner(`Fetching IP blocking rules for ${import_chalk20.default.bold(scope.displayName)}`);try{let{active,draft}=await listFirewallConfigs(client,scope),currentIps=draft?.ips||active?.ips||[],hostnameFlag=parsed.flags["--hostname"],matches=resolveIpRule(currentIps,identifier);if(hostnameFlag&&matches.length>1){let filtered=matches.filter(r=>r.hostname.toLowerCase()===hostnameFlag.toLowerCase());filtered.length>0&&(matches=filtered)}if(matches.length===0)return output_manager_default.error(`No IP block found for "${identifier}". Run ${import_chalk20.default.cyan(withGlobalFlags(client,"firewall ip-blocks list",scope))} to view all rules.`),1;let rule=matches[0];if(matches.length>1){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ambiguous_match",message:`Multiple IP blocks match "${identifier}". Use --hostname to narrow the match or specify the full rule ID.`,next:matches.map(r=>({command:withGlobalFlags(client,`firewall ip-blocks unblock "${identifier}" --hostname "${r.hostname}" --yes`,scope),when:`unblock on ${r.hostname==="*"?"all hosts":r.hostname}`}))},1),output_manager_default.error(`Multiple IP blocks match "${identifier}". Use --hostname to narrow the match or specify the full rule ID.`),1;let selectedId=await client.input.select({message:`Multiple IP blocks match "${identifier}". Select one:`,choices:matches.map(r=>({value:r.id,name:`${r.ip} on ${r.hostname==="*"?"all hosts":r.hostname} (${r.action})${r.notes?` \u2014 ${r.notes}`:""}`}))}),selected=matches.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;rule=selected}let hostnameLabel=rule.hostname==="*"||rule.hostname===""?"all hosts":rule.hostname;if(output_manager_default.stopSpinner(),!await confirmAction(client,parsed.flags["--yes"],`Remove IP block for ${import_chalk20.default.bold(rule.ip)} on ${import_chalk20.default.bold(hostnameLabel)}?`))return output_manager_default.log("Canceled"),0;let unblockStamp=stamp_default();output_manager_default.spinner("Staging IP block removal");let hadExistingDraft=draft!==null&&draft.changes.length>0;return await patchFirewallDraft(client,scope,{action:"ip.remove",id:rule.id,value:null}),output_manager_default.log(`${import_chalk20.default.cyan("Success!")} IP block removal for ${import_chalk20.default.bold(rule.ip)} staged ${import_chalk20.default.gray(unblockStamp())}`),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:parsed.flags["--yes"]}),0}catch(e){let msg=mapFirewallApiError(e,scope,"Failed to stage IP block removal");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,`firewall ip-blocks unblock ${identifier} --yes`,scope)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var COMMAND_CONFIG4={list:getCommandAliases(ipBlocksListSubcommand),block:getCommandAliases(ipBlocksBlockSubcommand),unblock:getCommandAliases(ipBlocksUnblockSubcommand)};async function main4(client,args,telemetry){let flagsSpecification=getFlagsSpecification(ipBlocksSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(args,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG4),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall","ip-blocks"),output_manager_default.print(help(ipBlocksSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand){case"list":return needHelp?(telemetry.trackCliFlagHelp("firewall",`ip-blocks:${subcommandOriginal}`),printHelp(ipBlocksListSubcommand),0):(telemetry.trackCliSubcommandIpBlocksList(subcommandOriginal),list2(client,subArgs));case"block":return needHelp?(telemetry.trackCliFlagHelp("firewall",`ip-blocks:${subcommandOriginal}`),printHelp(ipBlocksBlockSubcommand),0):(telemetry.trackCliSubcommandIpBlocksBlock(subcommandOriginal),block(client,subArgs));case"unblock":return needHelp?(telemetry.trackCliFlagHelp("firewall",`ip-blocks:${subcommandOriginal}`),printHelp(ipBlocksUnblockSubcommand),0):(telemetry.trackCliSubcommandIpBlocksUnblock(subcommandOriginal),subcommandOriginal==="rm"&&warnDeprecatedSubcommand(client,"firewall ip-blocks rm","firewall ip-blocks unblock"),unblock(client,subArgs));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG4)),output_manager_default.print(help(ipBlocksSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),2}}var import_chalk21=__toESM(require_source(),1);function unpublishedRuleChangeCount(changes){return changes.filter(c=>c.action.startsWith("rules.")||c.action==="managedRules.update"||c.action==="botId.toggle").length}async function list3(client,argv){let parsed=await parseSubcommandArgs(argv,rulesListSubcommand,client,"rules list");if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;output_manager_default.spinner(`Fetching rules for ${import_chalk21.default.bold(scope.displayName)}`);try{let{active,draft}=await listFirewallConfigs(client,scope),config=draft??active,managed=scope.type==="project"?getManagedBotRules(config):[],activeRules=active?.rules||[],draftRules=draft?.rules||null,changes=draft?.changes||[],annotated=annotateRules(activeRules,draftRules,changes);if(parsed.flags["--json"])return outputJson(client,{...scope.type==="project"?{managed:managed.map(managedBotJson)}:{},rules:annotated.map(a=>({...a.rule,_status:a.status})),hasDraft:changes.length>0,pendingChanges:changes.length}),0;if(scope.type==="project"&&output_manager_default.print(`
|
|
69
|
+
${formatManagedBotRulesTable(managed)}
|
|
70
|
+
`),annotated.length===0)if(scope.type==="project")output_manager_default.print(`
|
|
71
|
+
${import_chalk21.default.bold("Custom")}
|
|
72
|
+
`),output_manager_default.print(`
|
|
73
|
+
${import_chalk21.default.dim("No custom rules configured.")}
|
|
74
|
+
`);else return output_manager_default.log("No custom rules configured."),0;else if(parsed.flags["--expand"]){scope.type==="project"?output_manager_default.print(`
|
|
75
|
+
${import_chalk21.default.bold("Custom")}
|
|
76
|
+
|
|
77
|
+
`):output_manager_default.print(`
|
|
78
|
+
`);for(let i=0;i<annotated.length;i++){let{rule,status:status2}=annotated[i],colorFn=s=>s,prefix="";status2==="added"?(colorFn=import_chalk21.default.green,prefix="+ "):status2==="removed"?(colorFn=import_chalk21.default.red,prefix="- "):status2==="modified"&&(colorFn=import_chalk21.default.yellow,prefix="~ ");let expanded=formatRuleExpanded(rule,i);if(prefix){let expandedLines=expanded.split(`
|
|
79
|
+
`);expandedLines[0]=colorFn(expandedLines[0].replace(/^ {2}/,` ${prefix}`)),output_manager_default.print(expandedLines.join(`
|
|
80
|
+
`))}else output_manager_default.print(expanded);i<annotated.length-1&&output_manager_default.print(`
|
|
81
|
+
|
|
82
|
+
`)}output_manager_default.print(`
|
|
83
|
+
`)}else scope.type==="project"?output_manager_default.print(`
|
|
84
|
+
${import_chalk21.default.bold("Custom")}
|
|
85
|
+
|
|
86
|
+
`):output_manager_default.print(`
|
|
87
|
+
`),output_manager_default.print(`${formatRulesTable(annotated,client.stderr.columns)}
|
|
88
|
+
`);let ruleChanges=unpublishedRuleChangeCount(changes);return ruleChanges>0?output_manager_default.print(`
|
|
89
|
+
${import_chalk21.default.yellow(`${ruleChanges} unpublished rule change${ruleChanges!==1?"s":""}.`)} Run ${import_chalk21.default.cyan(withGlobalFlags(client,"firewall publish",scope))} to publish.
|
|
90
|
+
`):output_manager_default.print(`
|
|
91
|
+
${import_chalk21.default.dim("Showing live configuration.")}
|
|
92
|
+
`),output_manager_default.print(`
|
|
93
|
+
`),0}catch(e){let priority=failPriorityProjectGate(client,e,scope,{json:parsed.flags["--json"]===!0});if(priority!==null)return priority;let msg=mapFirewallApiError(e,scope,"Failed to fetch custom rules");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,"firewall rules list",scope)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk22=__toESM(require_source(),1);async function inspect(client,argv){let parsed=await parseSubcommandArgs(argv,rulesInspectSubcommand,client,"rules inspect");if(typeof parsed=="number")return parsed;let identifier=parsed.args[0];if(!identifier)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"missing_arguments",message:"Rule name or ID is required.",next:[{command:withGlobalFlags(client,"firewall rules inspect <name-or-id>"),when:"replace <name-or-id>"},{command:withGlobalFlags(client,"firewall rules list"),when:"list rules"}]},2),output_manager_default.error(`Rule name or ID is required. Usage: ${withGlobalFlags(client,"firewall rules inspect <name-or-id>")}`),2;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;output_manager_default.spinner(`Fetching rules for ${import_chalk22.default.bold(scope.displayName)}`);try{let{active,draft}=await listFirewallConfigs(client,scope),config=draft??active,managedId=scope.type==="project"?resolveManagedBotRuleId(identifier):void 0;if(managedId){let managed=getManagedBotRule(config,managedId);return parsed.flags["--json"]?(outputJson(client,managedBotJson(managed)),0):(output_manager_default.print(`
|
|
94
|
+
${formatManagedBotRuleDetail(managed)}
|
|
95
|
+
`),output_manager_default.print(`
|
|
96
|
+
${import_chalk22.default.dim(" Change this rule:")}
|
|
97
|
+
${withGlobalFlags(client,`firewall rules update ${managed.id} --action ${suggestedManagedBotAction(managed)}`,scope)}
|
|
98
|
+
|
|
99
|
+
`),0)}let currentRules=draft?.rules||active?.rules||[],matches=resolveRule(currentRules,identifier);if(matches.length===0)return output_manager_default.stopSpinner(),client.nonInteractive&&outputAgentError(client,{status:"error",reason:"not_found",message:`No rule found for "${identifier}".`,next:[{command:withGlobalFlags(client,"firewall rules list",scope),when:"list rules"}]},1),output_manager_default.error(`No rule found for "${identifier}". Run ${import_chalk22.default.cyan(withGlobalFlags(client,"firewall rules list",scope))} to view all rules.`),1;let rule=matches[0];if(matches.length>1){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ambiguous_match",message:`Multiple rules match "${identifier}". Specify the full rule ID.`,next:matches.map(r=>({command:withGlobalFlags(client,`firewall rules inspect "${r.id}"`,scope),when:`inspect "${r.name}"`}))},1),output_manager_default.error(`Multiple rules match "${identifier}". Specify the full rule ID to disambiguate.`),1;let selectedId=await client.input.select({message:`Multiple rules match "${identifier}". Select one:`,choices:matches.map(r=>({value:r.id,name:`${r.name} [${r.active?"Enabled":"Disabled"}] (${r.id})`}))}),selected=matches.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;rule=selected}return parsed.flags["--json"]?(outputJson(client,rule),0):(output_manager_default.print(`
|
|
100
|
+
${formatRuleDetail(rule)}
|
|
101
|
+
|
|
102
|
+
`),0)}catch(e){let msg=mapFirewallApiError(e,scope,"Failed to fetch rules");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,`firewall rules inspect ${identifier}`,scope)}]}),process.exit(1),1):(output_manager_default.error(msg),1)}}var import_chalk26=__toESM(require_source(),1);function parseConditionFlags(conditionFlags){if(conditionFlags.length===0)return"At least one --condition is required.";let groups=[{conditions:[]}];for(let flag of conditionFlags){if(flag==="--or"){if(groups[groups.length-1].conditions.length===0)return"--or cannot be placed before any conditions or consecutively.";groups.push({conditions:[]});continue}let result=parseConditionFlag(flag);if(typeof result=="string")return result;groups[groups.length-1].conditions.push(result)}return groups[groups.length-1].conditions.length===0?"--or cannot be the last flag \u2014 add conditions after it.":{groups}}function parseConditionFlag(flag){let parsed;try{parsed=JSON.parse(flag)}catch{return`Invalid condition JSON: "${flag}". Expected a JSON object like {"type":"path","op":"pre","value":"/api"}.`}if(typeof parsed!="object"||parsed===null||Array.isArray(parsed))return`Invalid condition: expected a JSON object, got ${typeof parsed}.`;let type=parsed.type;if(!type||typeof type!="string")return'Condition must have a "type" field (string).';let meta=CONDITION_TYPE_MAP[type],op=parsed.op;if(!op||typeof op!="string")return`Condition must have an "op" field (string). Valid operators: ${ALL_OPERATORS.join(", ")}`;if(!ALL_OPERATORS.includes(op)){let validOps=meta?meta.operators.join(", "):ALL_OPERATORS.join(", ");return`Invalid operator "${op}" for condition type "${type}". Valid operators: ${validOps}`}let requiresKey=meta?.requiresKey??!1,key=parsed.key;if(requiresKey&&!key)return`Condition type "${type}" requires a "key" field. Example: {"type":"${type}","key":"name","op":"${op}","value":"..."}`;let neg=parsed.neg===!0,condition={type,op};neg&&(condition.neg=!0),key&&(condition.key=key);let value=parsed.value;if(!(op==="ex"||op==="nex"))if(op==="inc"||op==="ninc"){if(!value)return`Operator "inc" requires a "value" field. Example: {"type":"${type}","op":"inc","value":"val1,val2"}`;Array.isArray(value)?condition.value=value.map(String):condition.value=String(value).split(",").map(v=>v.trim())}else if(op==="gt"||op==="gte"||op==="lt"||op==="lte"){if(value==null)return`Operator "${op}" requires a numeric "value" field.`;let num=Number(value);if(Number.isNaN(num))return`Operator "${op}" requires a numeric value, got "${value}".`;condition.value=num}else if(op==="re"){if(!value)return'Operator "re" requires a "value" field with a regex pattern.';try{new RegExp(String(value))}catch{return`Invalid regex pattern: "${value}".`}condition.value=String(value)}else{if(value==null)return`Operator "${op}" requires a "value" field.`;condition.value=String(value)}return condition}function buildActionFromFlags(flags,actionType){let duration=flags["--duration"];if(duration&&!VALID_DURATIONS.includes(duration))return`Invalid duration "${duration}". Valid durations: ${VALID_DURATIONS.join(", ")}`;let action={mitigate:{action:actionType,rateLimit:null,redirect:null,actionDuration:duration||null}};if(actionType==="rate_limit"){let algo=flags["--rate-limit-algo"]||"fixed_window",window=flags["--rate-limit-window"],requests=flags["--rate-limit-requests"],keys=flags["--rate-limit-keys"]||["ip"];if(!VALID_ALGORITHMS.includes(algo))return`Invalid rate limit algorithm "${algo}". Valid: ${VALID_ALGORITHMS.join(", ")}`;if(!window||window<10)return"Rate limit --rate-limit-window is required (minimum 10 seconds).";if(window>3600)return"Rate limit --rate-limit-window maximum is 3600 seconds (1 hour).";if(!requests||requests<1)return"Rate limit --rate-limit-requests is required (minimum 1).";if(requests>1e7)return"Rate limit --rate-limit-requests maximum is 10,000,000.";let rlAction=flags["--rate-limit-action"]||"rate_limit",validRlActions=["log","deny","challenge","rate_limit"];if(!validRlActions.includes(rlAction))return`Invalid rate limit action "${rlAction}". Valid: ${validRlActions.join(", ")}`;action.mitigate.rateLimit={algo,window,limit:requests,keys,action:rlAction}}if(actionType==="redirect"){let redirectUrl=flags["--redirect-url"],permanent=!!flags["--redirect-permanent"];if(!redirectUrl)return"Redirect action requires --redirect-url.";if(!redirectUrl.startsWith("/")&&!redirectUrl.startsWith("http://")&&!redirectUrl.startsWith("https://"))return"Redirect URL must start with /, http://, or https://";action.mitigate.redirect={location:redirectUrl,permanent}}return action}var import_chalk25=__toESM(require_source(),1);async function generateFirewallRule(client,projectId,body,options={}){let{teamId}=options,query=new URLSearchParams;query.set("projectId",projectId),teamId&&query.set("teamId",teamId);let url=`/v1/security/firewall/config/generate-rule?${query.toString()}`;return client.fetch(url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)})}var import_chalk24=__toESM(require_source(),1);var import_chalk23=__toESM(require_source(),1);async function addInteractive(client,scope,opts={}){let pre=opts.prePopulated,planInfo=await fetchPlanInfo(client),name=await client.input.text({message:"Rule name:",default:pre?.name,validate:val=>val.trim()?val.length>160?"Name must be 160 characters or less.":!0:"Name is required."}),description=await client.input.text({message:"Description (optional, press Enter to skip):",default:pre?.description||""}),conditionGroups=await buildConditionGroupLoop(client,planInfo,pre?.conditionGroup),action=await buildActionInteractive(client,pre?.action),active=pre?.active!==void 0?pre.active:!0,previewRule={id:"(new)",name,description:description||void 0,active,conditionGroup:conditionGroups,action};if(output_manager_default.print(`
|
|
103
|
+
${formatRuleExpanded(previewRule)}
|
|
104
|
+
|
|
105
|
+
`),!await confirmAction(client,opts.skipPrompts??!1,"Create this rule?"))return output_manager_default.log("Canceled"),0;let createStamp=stamp_default();output_manager_default.spinner("Staging rule");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"rules.insert",id:null,value:{name,description:description||void 0,active,conditionGroup:conditionGroups,action}}),output_manager_default.log(`${import_chalk23.default.cyan("Success!")} Rule "${import_chalk23.default.bold(name)}" staged ${import_chalk23.default.gray(createStamp())}`),printActionImpactWarning(action),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:opts.skipPrompts}),0}catch(e){output_manager_default.stopSpinner();let priority=failPriorityProjectGate(client,e,scope);return priority!==null?priority:(output_manager_default.error(mapFirewallApiError(e,scope,"Failed to stage rule")),1)}}async function buildConditionGroupLoop(client,planInfo,prePopulated){let groups=prePopulated?JSON.parse(JSON.stringify(prePopulated)):[];if(groups.length===0){let condition=await buildConditionInteractive(client,planInfo);groups.push({conditions:[condition]})}for(;;){output_manager_default.print(`
|
|
106
|
+
${import_chalk23.default.bold("Current conditions:")}
|
|
107
|
+
`);for(let g=0;g<groups.length;g++){groups.length>1&&output_manager_default.print(` ${import_chalk23.default.dim(`Group ${g+1} (AND):`)}
|
|
108
|
+
`);for(let cond of groups[g].conditions)output_manager_default.print(` ${formatConditionCompact(cond)}
|
|
109
|
+
`);g<groups.length-1&&output_manager_default.print(` ${import_chalk23.default.dim("OR")}
|
|
110
|
+
`)}output_manager_default.print(`
|
|
111
|
+
`);let choice=await client.input.select({message:"What next?",choices:[{value:"and",name:"Add another condition (AND with current group)"},{value:"or",name:"Start new group (OR \u2014 matches if this group OR previous groups match)"},{value:"done",name:"Done with conditions"}]});if(choice==="done")break;let condition=await buildConditionInteractive(client,planInfo);choice==="and"?groups[groups.length-1].conditions.push(condition):groups.push({conditions:[condition]})}return groups}async function buildConditionInteractive(client,planInfo){let availableTypes=getAvailableConditionTypes(planInfo),categories=new Map;for(let ct of availableTypes){let existing=categories.get(ct.category)||[];existing.push(ct),categories.set(ct.category,existing)}let choices=[];for(let[category,types]of categories){let label=CATEGORY_LABELS[category]||category;choices.push({value:`__sep_${category}`,name:import_chalk23.default.dim(`\u2500\u2500 ${label} \u2500\u2500`)});for(let ct of types)choices.push({value:ct.type,name:` ${ct.displayName} ${import_chalk23.default.dim(ct.description)}`})}let type;for(;type=await client.input.select({message:"Condition type:",choices}),!!type.startsWith("__sep_"););let meta=CONDITION_TYPES.find(ct=>ct.type===type),key;meta?.requiresKey&&(key=await client.input.text({message:`${meta.displayName} key:`,validate:val=>val.trim()?!0:"Key is required."}));let operatorChoices=(meta?.operators||["eq"]).flatMap(op2=>[{value:op2,name:getOperatorDisplayName(op2,!1)},{value:`!${op2}`,name:getOperatorDisplayName(op2,!0)}]),opChoice=await client.input.select({message:"Operator:",choices:operatorChoices}),neg=opChoice.startsWith("!"),op=neg?opChoice.slice(1):opChoice,value,baseOp=op,hasPresets=meta?.presetValues&&meta.presetValues.length>0;if(baseOp!=="ex")if(baseOp==="inc"&&hasPresets)for(;;){let selected=await client.input.checkbox({message:"Select values (space to toggle, enter to confirm):",choices:meta.presetValues.map(p=>({name:p.label,value:p.value})),pageSize:meta.presetValues.length});if(selected.length===0){output_manager_default.warn("Please select at least one value.");continue}value=selected;break}else baseOp==="inc"?value=(await client.input.text({message:"Values (comma-separated):",validate:val=>val.trim()?!0:"At least one value is required."})).split(",").map(v=>v.trim()):baseOp==="eq"&&hasPresets?value=await client.input.select({message:"Value:",choices:meta.presetValues.map(p=>({name:p.label,value:p.value})),pageSize:meta.presetValues.length}):baseOp==="re"?value=await client.input.text({message:"Regex pattern (max 512 chars):",validate:val=>{if(!val.trim())return"Regex pattern is required.";if(val.length>512)return"Regex pattern must be 512 characters or less.";try{return new RegExp(val),!0}catch{return"Invalid regex pattern. Please enter a valid regular expression."}}}):value=await client.input.text({message:"Value:",validate:val=>val.trim()?validateConditionValue(val,meta):"Value is required."});let condition={type,op};return neg&&(condition.neg=!0),key&&(condition.key=key),value!==void 0&&(condition.value=value),condition}async function buildActionInteractive(client,prePopulated){let preAction=prePopulated?.mitigate?.action,actionType=await client.input.select({message:"Action:",choices:VALID_ACTIONS.map(a=>({value:a,name:getActionLabel(a)})),default:preAction}),action={mitigate:{action:actionType,rateLimit:null,redirect:null,actionDuration:null}};if(actionType==="rate_limit"){let rl=await buildRateLimitInteractive(client);action.mitigate.rateLimit=rl}if(actionType==="redirect"){let location=await client.input.text({message:"Redirect URL or path:",validate:val=>val.trim()?!val.startsWith("/")&&!val.startsWith("http://")&&!val.startsWith("https://")?"URL must start with /, http://, or https://":!0:"URL is required."}),permanent=await client.input.confirm("Permanent redirect (301)?",!1);action.mitigate.redirect={location,permanent}}if(["deny","challenge","rate_limit"].includes(actionType)){let durationChoice=await client.input.select({message:"Action duration (optional \u2014 block matching clients for a period):",choices:[{value:"none",name:"None (no persistent block)"},...VALID_DURATIONS.map(d=>({value:d,name:d}))]});durationChoice!=="none"&&(action.mitigate.actionDuration=durationChoice)}return action}async function buildRateLimitInteractive(client){let algo="fixed_window";output_manager_default.print(` ${import_chalk23.default.dim("Algorithm:")} Fixed Window ${import_chalk23.default.dim("(Token Bucket available on Enterprise via --rate-limit-algo flag)")}
|
|
112
|
+
`);let windowStr=await client.input.text({message:"Window in seconds (10-3600):",default:"60",validate:val=>{let n=Number(val);return Number.isNaN(n)||!Number.isInteger(n)?"Please enter a whole number.":n<10?"Minimum 10 seconds.":n>3600?"Maximum 3600 seconds (1 hour).":!0}}),limitStr=await client.input.text({message:"Max requests per window (1-10,000,000):",default:"100",validate:val=>{let n=Number(val);return Number.isNaN(n)||!Number.isInteger(n)?"Please enter a whole number.":n<1?"Minimum 1 request.":n>1e7?"Maximum 10,000,000 requests.":!0}}),keys=[...await client.input.checkbox({message:"Rate limit keys (space to toggle, enter to confirm):",choices:[{name:"IP Address (ip)",value:"ip",checked:!0},{name:"JA4 Digest (ja4)",value:"ja4"},{name:"User Agent (header:user-agent)",value:"header:user-agent"}],pageSize:3})];if(await client.input.confirm("Add a custom header key?",!1)){let customKey=await client.input.text({message:"Header name (e.g. x-api-key):",validate:val=>val.trim()?!0:"Header name is required."});keys.push(`header:${customKey}`)}keys.length===0&&(keys=["ip"]);let subAction=await client.input.select({message:"Action when limit is exceeded:",choices:[{value:"deny",name:"Deny (403)"},{value:"challenge",name:"Challenge"},{value:"log",name:"Log only"},{value:"rate_limit",name:"Rate limit (429)"}]});return{algo,window:Number(windowStr),limit:Number(limitStr),keys,action:subAction}}async function runInteractiveEditLoop(client,rule){let edited=JSON.parse(JSON.stringify(rule)),planInfo=await fetchPlanInfo(client);for(;;){let condCount=edited.conditionGroup.reduce((sum,g)=>sum+g.conditions.length,0),groupCount=edited.conditionGroup.length,actionLabel=formatActionDisplay(edited.action);switch(await client.input.select({message:"What would you like to edit?",choices:[{value:"name",name:`Name (${import_chalk24.default.cyan(edited.name)})`},{value:"description",name:`Description (${import_chalk24.default.cyan(edited.description||import_chalk24.default.dim("none"))})`},{value:"conditions",name:`Conditions (${import_chalk24.default.cyan(`${condCount} condition${condCount!==1?"s":""} in ${groupCount} group${groupCount!==1?"s":""}`)})`},{value:"action",name:`Action (${import_chalk24.default.cyan(actionLabel)})`},{value:"active",name:`Status (${edited.active?import_chalk24.default.green("Enabled"):import_chalk24.default.dim("Disabled")})`},{value:"done",name:import_chalk24.default.bold("Done \u2014 save changes")}]})){case"name":{edited.name=await client.input.text({message:"Rule name:",default:edited.name,validate:val=>val.trim()?val.length>160?"Name must be 160 characters or less.":!0:"Name is required."});break}case"description":{edited.description=await client.input.text({message:"Description (press Enter to keep, empty to clear):",default:edited.description||"",validate:val=>val.length>256?"Description must be 256 characters or less.":!0}),edited.description===""&&(edited.description=void 0);break}case"conditions":{let result=await editConditions(client,edited.conditionGroup,planInfo);result&&(edited.conditionGroup=result);break}case"action":{edited.action=await editAction(client,edited.action);break}case"active":{let toggle=await client.input.select({message:"Rule status:",choices:[{value:"active",name:"Enabled"},{value:"inactive",name:"Disabled"}],default:edited.active?"active":"inactive"});edited.active=toggle==="active";break}case"done":{if(edited.conditionGroup.length===0){output_manager_default.warn("Rule has no conditions. Please add at least one condition.");continue}return edited}}}}async function editConditions(client,groups,planInfo){let edited=JSON.parse(JSON.stringify(groups));for(;;){output_manager_default.print(`
|
|
113
|
+
${import_chalk24.default.bold(" Current conditions:")}
|
|
114
|
+
`);let condIndex=1;for(let g=0;g<edited.length;g++){edited.length>1&&output_manager_default.print(` ${import_chalk24.default.dim(`Group ${g+1} (AND):`)}
|
|
115
|
+
`);for(let cond of edited[g].conditions)output_manager_default.print(` ${condIndex}. ${formatConditionCompact(cond)}
|
|
116
|
+
`),condIndex++;g<edited.length-1&&output_manager_default.print(` ${import_chalk24.default.dim("OR")}
|
|
117
|
+
`)}output_manager_default.print(`
|
|
118
|
+
`);let choices=[];choices.push({value:"done",name:import_chalk24.default.bold("Done with conditions")}),edited.length>0&&choices.push({value:"add-and",name:`Add condition to ${edited.length>1?"a group":"current group"} (AND)`}),choices.push({value:"add-or",name:"Add new group (OR)"}),condIndex>1&&choices.push({value:"remove",name:"Remove a condition"});let idx=1;for(let g=0;g<edited.length;g++)for(let c=0;c<edited[g].conditions.length;c++)choices.push({value:`edit:${g}:${c}`,name:`Edit condition ${idx} (${formatConditionCompact(edited[g].conditions[c])})`}),idx++;let action=await client.input.select({message:"What would you like to do?",choices});if(action==="done")return edited;if(action.startsWith("edit:")){let[,gStr,cStr]=action.split(":"),g=Number.parseInt(gStr,10),c=Number.parseInt(cStr,10),newCond=await editSingleCondition(client,edited[g].conditions[c],planInfo);edited[g].conditions[c]=newCond;continue}if(action==="remove"){let removeChoices=[],removeIdx=1;for(let g2=0;g2<edited.length;g2++)for(let c2=0;c2<edited[g2].conditions.length;c2++)removeChoices.push({value:`${g2}:${c2}`,name:`${removeIdx}. ${formatConditionCompact(edited[g2].conditions[c2])}`}),removeIdx++;let removeTarget=await client.input.select({message:"Which condition to remove?",choices:removeChoices}),[gStr,cStr]=removeTarget.split(":"),g=Number.parseInt(gStr,10),c=Number.parseInt(cStr,10);edited[g].conditions.splice(c,1),edited[g].conditions.length===0&&(edited.splice(g,1),output_manager_default.log("Empty group removed."));continue}if(action==="add-and"){let targetGroup=0;if(edited.length>1){let groupChoice=await client.input.select({message:"Add to which group?",choices:edited.map((_,i)=>({value:String(i),name:`Group ${i+1} (${edited[i].conditions.length} conditions)`}))});targetGroup=Number.parseInt(groupChoice,10)}let newCond=await buildCondition(client,planInfo);edited[targetGroup].conditions.push(newCond);continue}if(action==="add-or"){let newCond=await buildCondition(client,planInfo);edited.push({conditions:[newCond]})}}}async function editSingleCondition(client,current,planInfo){output_manager_default.print(`
|
|
119
|
+
${import_chalk24.default.dim("Current:")} ${formatConditionCompact(current)}
|
|
120
|
+
|
|
121
|
+
`);let availableTypes=getAvailableConditionTypes(planInfo),type=await client.input.select({message:"Condition type:",choices:availableTypes.map(ct=>({value:ct.type,name:`${ct.displayName} ${import_chalk24.default.dim(ct.description)}`})),default:current.type}),meta=CONDITION_TYPES.find(ct=>ct.type===type),key;meta?.requiresKey&&(key=await client.input.text({message:`${meta.displayName} key:`,default:current.type===type?current.key:void 0,validate:val=>val.trim()?!0:"Key is required."}));let operatorChoices=(meta?.operators||["eq"]).flatMap(op2=>[{value:op2,name:getOperatorDisplayName(op2,!1)},{value:`!${op2}`,name:getOperatorDisplayName(op2,!0)}]),currentOpValue=current.type===type?current.neg?`!${current.op}`:current.op:void 0,opChoice=await client.input.select({message:"Operator:",choices:operatorChoices,default:currentOpValue}),neg=opChoice.startsWith("!"),op=neg?opChoice.slice(1):opChoice,value;if(op!=="ex"){let currentValue=current.type===type&¤t.op===op?current.value:void 0;if(op==="inc"&&meta?.presetValues){let currentArr=Array.isArray(currentValue)?currentValue:[];for(;;){let selected=await client.input.checkbox({message:"Select values:",choices:meta.presetValues.map(p=>({name:p.label,value:p.value,checked:currentArr.includes(p.value)})),pageSize:meta.presetValues.length});if(selected.length===0){output_manager_default.warn("Please select at least one value.");continue}value=selected;break}}else if(op==="inc"){let defaultVal=Array.isArray(currentValue)?currentValue.join(", "):"";value=(await client.input.text({message:"Values (comma-separated):",default:defaultVal,validate:val=>val.trim()?!0:"At least one value is required."})).split(",").map(v=>v.trim())}else if(op==="eq"&&meta?.presetValues)value=await client.input.select({message:"Value:",choices:meta.presetValues.map(p=>({name:p.label,value:p.value})),default:typeof currentValue=="string"?currentValue:void 0,pageSize:meta.presetValues.length});else{let defaultVal=typeof currentValue=="string"?currentValue:"";value=await client.input.text({message:"Value:",default:defaultVal,validate:val=>val.trim()?validateConditionValue(val,meta):"Value is required."})}}let condition={type,op};return neg&&(condition.neg=!0),key&&(condition.key=key),value!==void 0&&(condition.value=value),condition}async function buildCondition(client,planInfo){return buildConditionInteractive(client,planInfo)}async function editAction(client,current){let currentActionType=current.mitigate?.action,actionType=await client.input.select({message:"Action:",choices:VALID_ACTIONS.map(a=>({value:a,name:getActionLabel(a)})),default:currentActionType}),action={mitigate:{action:actionType,rateLimit:null,redirect:null,actionDuration:null}};if(actionType==="rate_limit"){let currentRL=current.mitigate?.rateLimit;output_manager_default.print(` ${import_chalk24.default.dim("Algorithm:")} Fixed Window ${import_chalk24.default.dim("(Token Bucket available on Enterprise via flags)")}
|
|
122
|
+
`);let windowStr=await client.input.text({message:"Window in seconds (10-3600):",default:String(currentRL?.window||60),validate:val=>{let n=Number(val);return Number.isNaN(n)||!Number.isInteger(n)?"Please enter a whole number.":n<10?"Minimum 10 seconds.":n>3600?"Maximum 3600 seconds (1 hour).":!0}}),limitStr=await client.input.text({message:"Max requests per window (1-10,000,000):",default:String(currentRL?.limit||100),validate:val=>{let n=Number(val);return Number.isNaN(n)||!Number.isInteger(n)?"Please enter a whole number.":n<1?"Minimum 1 request.":n>1e7?"Maximum 10,000,000 requests.":!0}}),currentKeys=currentRL?.keys||["ip"],keys=[...await client.input.checkbox({message:"Rate limit keys:",choices:[{name:"IP Address (ip)",value:"ip",checked:currentKeys.includes("ip")},{name:"JA4 Digest (ja4)",value:"ja4",checked:currentKeys.includes("ja4")},{name:"User Agent (header:user-agent)",value:"header:user-agent",checked:currentKeys.includes("header:user-agent")}],pageSize:3})],customKeys=currentKeys.filter(k=>!["ip","ja4","header:user-agent"].includes(k));customKeys.length>0&&(output_manager_default.print(` ${import_chalk24.default.dim("Custom keys preserved:")} ${customKeys.join(", ")}
|
|
123
|
+
`),keys=[...keys,...customKeys]),keys.length===0&&(keys=["ip"]);let subAction=await client.input.select({message:"Action when limit is exceeded:",choices:[{value:"deny",name:"Deny (403)"},{value:"challenge",name:"Challenge"},{value:"log",name:"Log only"},{value:"rate_limit",name:"Rate limit (429)"}],default:currentRL?.action||"deny"});action.mitigate.rateLimit={algo:currentRL?.algo||"fixed_window",window:Number(windowStr),limit:Number(limitStr),keys,action:subAction}}if(actionType==="redirect"){let currentRD=current.mitigate?.redirect,location=await client.input.text({message:"Redirect URL or path:",default:currentRD?.location||"",validate:val=>val.trim()?!val.startsWith("/")&&!val.startsWith("http://")&&!val.startsWith("https://")?"URL must start with /, http://, or https://":!0:"URL is required."}),permanent=await client.input.confirm("Permanent redirect (301)?",currentRD?.permanent??!1);action.mitigate.redirect={location,permanent}}if(["deny","challenge","rate_limit"].includes(actionType)){let currentDuration=current.mitigate?.actionDuration,durationChoice=await client.input.select({message:"Action duration:",choices:[{value:"none",name:"None (no persistent block)"},...VALID_DURATIONS.map(d=>({value:d,name:d}))],default:currentDuration||"none"});durationChoice!=="none"&&(action.mitigate.actionDuration=durationChoice)}return action}async function handleAIAdd(client,project,teamId,opts){let prompt=opts.prompt;if(!prompt){if(!client.stdin.isTTY||client.nonInteractive)return output_manager_default.error('--ai requires a description. Example: firewall rules add --ai "Rate limit /api to 100 requests per minute by IP"'),1;prompt=await client.input.text({message:"Describe the rule you want to create:",validate:val=>val.trim()?!0:"Please provide a description."})}let scope=projectScope(project,teamId,opts.teamSlug),currentRule,retryCount=0,maxRetries=client.nonInteractive?1:0;for(;;){output_manager_default.spinner("Generating rule with AI...");try{let response=await generateFirewallRule(client,project.id,{prompt,...currentRule?{currentRule}:{}},{teamId});if(response.error){if(output_manager_default.stopSpinner(),client.nonInteractive&&retryCount<maxRetries){retryCount++,output_manager_default.warn(`AI generation failed: ${response.error}. Retrying...`);continue}if(client.stdin.isTTY&&!client.nonInteractive&&!opts.skipPrompts){if(await client.input.select({message:`AI could not generate a rule: ${response.error}`,choices:[{value:"retry",name:"Try again with a different description"},{value:"cancel",name:"Cancel"}]})==="cancel")return output_manager_default.log("Canceled"),0;prompt=await client.input.text({message:"Describe the rule you want to create:",validate:val=>val.trim()?!0:"Please provide a description."});continue}return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ai_generation_failed",message:`AI could not generate a rule: ${response.error}`,next:[{command:withGlobalFlags(client,'firewall rules add --ai "more specific prompt" --yes'),when:"try with a more specific description"},{command:withGlobalFlags(client,`firewall rules add "Name" --condition '{"type":"path","op":"pre","value":"/api"}' --action deny --yes`),when:"create with flags instead"}]},1),output_manager_default.error(`AI could not generate a rule: ${response.error}`),1}if(!response.rule){if(output_manager_default.stopSpinner(),client.stdin.isTTY&&!client.nonInteractive&&!opts.skipPrompts){if(await client.input.select({message:"AI did not return a rule.",choices:[{value:"retry",name:"Try again with a different description"},{value:"cancel",name:"Cancel"}]})==="cancel")return output_manager_default.log("Canceled"),0;prompt=await client.input.text({message:"Describe the rule you want to create:",validate:val=>val.trim()?!0:"Please provide a description."});continue}return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ai_no_result",message:"AI did not return a rule. Try a more specific description.",next:[{command:withGlobalFlags(client,'firewall rules add --ai "more specific prompt" --yes'),when:"try with a more specific description"}]},1),output_manager_default.error("AI did not return a rule. Try a more specific description."),1}currentRule=response.rule,opts.name&&(currentRule.name=opts.name),output_manager_default.stopSpinner();break}catch(e){output_manager_default.stopSpinner();let priority=failPriorityProjectGate(client,e,scope);if(priority!==null)return priority;let msg=e.message||"Failed to generate rule";if(client.nonInteractive&&retryCount<maxRetries){retryCount++,output_manager_default.warn(`Generation failed: ${msg}. Retrying...`);continue}if(!client.stdin.isTTY||client.nonInteractive||opts.skipPrompts)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ai_generation_failed",message:msg,next:[{command:withGlobalFlags(client,'firewall rules add --ai "more specific prompt" --yes'),when:"try again"}]},1),output_manager_default.error(msg),1;if(await client.input.select({message:`Generation failed: ${msg}`,choices:[{value:"retry",name:"Try again"},{value:"cancel",name:"Cancel"}]})==="cancel")return output_manager_default.log("Canceled"),0}}let previewRule={...currentRule,id:"(AI-generated)"};if(output_manager_default.print(`
|
|
124
|
+
${formatRuleExpanded(previewRule)}
|
|
125
|
+
|
|
126
|
+
`),opts.skipPrompts)return createFromGenerated(client,scope,currentRule,opts);for(;;){let choice=await client.input.select({message:"What would you like to do?",choices:[{value:"create",name:"Create this rule"},{value:"edit-ai",name:"Edit with AI (describe changes)"},{value:"edit-manual",name:"Edit manually (step by step)"},{value:"discard",name:"Discard"}]});if(choice==="create")return createFromGenerated(client,scope,currentRule,opts);if(choice==="edit-ai"){let editPrompt=await client.input.text({message:"Describe the changes you want:",validate:val=>val.trim()?!0:"Please describe the changes."});output_manager_default.spinner("Regenerating rule...");try{let response=await generateFirewallRule(client,project.id,{prompt:editPrompt,currentRule},{teamId});if(output_manager_default.stopSpinner(),response.error||!response.rule){output_manager_default.error(`AI could not update the rule: ${response.error||"No rule returned"}`);continue}currentRule=response.rule;let updatedPreview={...currentRule,id:"(AI-generated)"};output_manager_default.print(`
|
|
127
|
+
${formatRuleExpanded(updatedPreview)}
|
|
128
|
+
|
|
129
|
+
`);continue}catch(e){output_manager_default.stopSpinner();let priority=failPriorityProjectGate(client,e,scope);if(priority!==null)return priority;let error=e;output_manager_default.error(`Failed to regenerate: ${error.message||"Unknown error"}`);continue}}if(choice==="edit-manual"){let prePopulated={...currentRule,id:"(new)"},modified=await runInteractiveEditLoop(client,prePopulated);if(!modified)continue;return createFromGenerated(client,scope,modified,opts)}if(choice==="discard")return output_manager_default.log("Discarded"),0}}async function createFromGenerated(client,scope,rule,opts){let createStamp=stamp_default();output_manager_default.spinner("Staging rule");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"rules.insert",id:null,value:{name:rule.name,description:rule.description,active:rule.active!==!1,conditionGroup:rule.conditionGroup,action:rule.action}}),output_manager_default.log(`${import_chalk25.default.cyan("Success!")} Rule "${import_chalk25.default.bold(rule.name)}" staged ${import_chalk25.default.gray(createStamp())}`),printActionImpactWarning(rule.action),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:opts.skipPrompts}),0}catch(e){output_manager_default.stopSpinner();let priority=failPriorityProjectGate(client,e,scope);if(priority!==null)return priority;let msg=e.message||"Failed to stage rule";return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"staging_failed",message:msg,next:[{command:withGlobalFlags(client,"firewall rules add --yes"),when:"try again"}]},1),output_manager_default.error(msg),1}}async function add2(client,argv){let parsed=await parseSubcommandArgs(argv,rulesAddSubcommand,client,"rules add");if(typeof parsed=="number")return parsed;let aiPrompt=parsed.flags["--ai"],jsonInput=getRulePayload(parsed.flags);if(typeof jsonInput=="number")return jsonInput;let conditionFlags=parsed.flags["--condition"];if([aiPrompt,jsonInput,conditionFlags].filter(Boolean).length>1)return output_manager_default.error("Cannot use --ai, --data, and --condition together. Use only one mode."),1;if(aiPrompt){if(parsed.flags["--team-level"])return output_manager_default.error("AI mode is not available with --team-level. Use --data or --condition flags instead."),1;if(client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ai_not_available",message:"AI mode is not available in non-interactive mode. AI-generated rules require human review before staging. Use --data or --condition flags instead.",next:[{command:withGlobalFlags(client,`firewall rules add "Name" --condition '{"type":"path","op":"pre","value":"/api"}' --action deny --yes`),when:"create with flags"},{command:withGlobalFlags(client,`firewall rules add --data '{"name":"...","conditionGroup":[...],"action":{...}}' --yes`),when:"create with JSON"}]}),output_manager_default.error("AI mode is not available in non-interactive mode. Use --data or --condition flags instead."),1;let scope=await resolveFirewallScope(client,parsed.flags);return typeof scope=="number"?scope:scope.type==="team"?(output_manager_default.error("AI mode is not available with --team-level. Use --data or --condition flags instead."),1):handleAIAdd(client,{id:scope.projectId,name:scope.displayName},scope.teamId,{prompt:aiPrompt,name:parsed.args[0],skipPrompts:!!parsed.flags["--yes"],teamSlug:scope.teamSlug})}if(jsonInput)return handleJsonAdd(client,parsed,jsonInput);if(conditionFlags)return handleFlagAdd(client,parsed,conditionFlags);if(client.stdin.isTTY&&!client.nonInteractive){let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;let mode=await client.input.select({message:"How would you like to create the rule?",choices:[...scope.type==="project"?[{value:"ai",name:"Describe what you want (AI-powered)"}]:[],{value:"manual",name:"Build manually (step by step)"},{value:"json",name:"Paste JSON"}]});if(mode==="ai"&&scope.type==="project")return handleAIAdd(client,{id:scope.projectId,name:scope.displayName},scope.teamId,{skipPrompts:!1,teamSlug:scope.teamSlug});if(mode==="json"){let jsonStr=await client.input.text({message:"Paste the JSON rule definition:"});return handleJsonAdd(client,parsed,jsonStr)}return addInteractive(client,scope,{skipPrompts:!!parsed.flags["--yes"]})}return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"missing_flags",message:"No rule definition provided. Use --data or --condition flags.",next:[{command:withGlobalFlags(client,`firewall rules add "Name" --condition '{"type":"path","op":"pre","value":"/api"}' --action deny --yes`),when:"create with flags"},{command:withGlobalFlags(client,`firewall rules add --data '{"name":"Name","conditionGroup":[...],"action":{"mitigate":{"action":"deny"}}}' --yes`),when:"create with JSON"}]}),output_manager_default.error("Interactive mode is not available. Use --ai, --data, or --condition flags to create a rule."),2}async function handleJsonAdd(client,parsed,jsonStr){let ruleData;try{ruleData=JSON.parse(jsonStr)}catch{return output_manager_default.error("Invalid JSON. Please provide a valid JSON object."),2}if(!ruleData.name||typeof ruleData.name!="string")return output_manager_default.error('JSON must include a "name" field (string).'),1;if(!ruleData.conditionGroup||!Array.isArray(ruleData.conditionGroup))return output_manager_default.error('JSON must include a "conditionGroup" field (array).'),1;for(let i=0;i<ruleData.conditionGroup.length;i++){let group=ruleData.conditionGroup[i];if(!group.conditions||!Array.isArray(group.conditions))return output_manager_default.error(`conditionGroup[${i}] must have a "conditions" array.`),1;for(let j=0;j<group.conditions.length;j++){let cond=group.conditions[j];if(!cond.type||typeof cond.type!="string")return output_manager_default.error(`conditionGroup[${i}].conditions[${j}] must have a "type" field.`),1;if(!cond.op||typeof cond.op!="string")return output_manager_default.error(`conditionGroup[${i}].conditions[${j}] must have an "op" field.`),1}}if(!ruleData.action||typeof ruleData.action!="object")return output_manager_default.error('JSON must include an "action" field (object).'),1;let actionObj=ruleData.action;if(!actionObj.mitigate||typeof actionObj.mitigate!="object")return output_manager_default.error('action must have a "mitigate" field. Example: { "mitigate": { "action": "deny" } }'),1;let mitigateObj=actionObj.mitigate;if(!mitigateObj.action||typeof mitigateObj.action!="string")return output_manager_default.error('action.mitigate must have an "action" field (string). Valid: deny, challenge, rate_limit, log, redirect.'),1;if(ruleData.name.length>160)return output_manager_default.error("Rule name must be 160 characters or less."),1;if(ruleData.description&&ruleData.description.length>256)return output_manager_default.error("Rule description must be 256 characters or less."),1;if(ruleData.conditionGroup.length>25)return output_manager_default.error("Maximum 25 condition groups allowed."),1;let rule={name:ruleData.name,description:ruleData.description,active:ruleData.active!==!1,conditionGroup:ruleData.conditionGroup,action:ruleData.action};return createRule(client,parsed,rule)}async function handleFlagAdd(client,parsed,conditionFlags){let name=parsed.args[0];if(!name)return output_manager_default.error(`Missing rule name. Provide as the first argument: ${import_chalk26.default.cyan(withGlobalFlags(client,'firewall rules add "Rule name" --condition ...'))}`),1;if(name.length>160)return output_manager_default.error("Rule name must be 160 characters or less."),1;let rawArgs=parsed.flags["--condition"];if(!rawArgs||rawArgs.length===0)return output_manager_default.error("At least one --condition is required."),2;let hasOr=parsed.flags["--or"],conditionGroups;if(hasOr){let interleaved=[],condValues=[...rawArgs],condIdx=0;for(let arg of client.argv)arg==="--or"?interleaved.push("--or"):(arg==="--condition"||arg.startsWith("--condition="))&&condIdx<condValues.length&&(interleaved.push(condValues[condIdx]),condIdx++);let result=parseConditionFlags(interleaved);if(typeof result=="string")return output_manager_default.error(result),1;conditionGroups=result.groups}else{let result=parseConditionFlags(rawArgs);if(typeof result=="string")return output_manager_default.error(result),1;conditionGroups=result.groups}let actionType=parsed.flags["--action"];if(!actionType)return output_manager_default.error(`Missing --action. Valid actions: ${VALID_ACTIONS.join(", ")}`),1;if(!VALID_ACTIONS.includes(actionType))return output_manager_default.error(`Invalid action "${actionType}". Valid actions: ${VALID_ACTIONS.join(", ")}`),1;let action=buildActionFromFlags(parsed.flags,actionType);if(typeof action=="string")return output_manager_default.error(action),1;let description=parsed.flags["--description"];if(description&&description.length>256)return output_manager_default.error("Rule description must be 256 characters or less."),1;parsed.flags["--disabled"]&&warnDeprecatedInput(client,"--disabled","--no-enable");let active=!(parsed.flags["--no-enable"]||parsed.flags["--disabled"]);return createRule(client,parsed,{name,description,active,conditionGroup:conditionGroups,action})}async function createRule(client,parsed,rule){let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;let reserved=refuseManagedBotMutation(client,scope,rule.name,"add a custom rule named");if(reserved!==null)return reserved;let previewRule={...rule,id:"(new)"};if(output_manager_default.print(`
|
|
130
|
+
${formatRuleExpanded(previewRule)}
|
|
131
|
+
|
|
132
|
+
`),!await confirmAction(client,parsed.flags["--yes"],"Create this rule?"))return output_manager_default.log("Canceled"),0;let createStamp=stamp_default();output_manager_default.spinner("Staging rule");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"rules.insert",id:null,value:rule}),output_manager_default.log(`${import_chalk26.default.cyan("Success!")} Rule "${import_chalk26.default.bold(rule.name)}" staged ${import_chalk26.default.gray(createStamp())}`),printActionImpactWarning(rule.action),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:parsed.flags["--yes"]}),0}catch(e){let priority=failPriorityProjectGate(client,e,scope);if(priority!==null)return priority;let msg=mapFirewallApiError(e,scope,"Failed to stage rule");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,"firewall rules add --yes",scope)}]}),1):(output_manager_default.error(msg),1)}}var import_chalk28=__toESM(require_source(),1);var import_chalk27=__toESM(require_source(),1);var UNSUPPORTED_FLAGS=["--ai","--data","--json","--condition","--name","--description","--duration","--enable","--no-enable","--enabled","--disabled","--rate-limit-algo","--rate-limit-window","--rate-limit-requests","--rate-limit-keys","--rate-limit-action","--redirect-url","--redirect-permanent","--or"];async function editManagedBotRule(client,opts){let used=UNSUPPORTED_FLAGS.filter(flag=>{let value=opts.flags[flag];return Array.isArray(value)?value.length>0:!!value});if(used.length>0){let command=`firewall rules update ${opts.id} --action <action>`;return failFirewall(client,{message:`Can't use ${used.join(", ")} on managed bot rules. Use --action.`,reason:AGENT_REASON.INVALID_ARGUMENTS,fix:{command,hint:`Use ${import_chalk27.default.cyan(withGlobalFlags(client,command,opts.scope))} to change it.`,when:"edit with --action"}})}let current=getManagedBotRule(opts.config,opts.id),rawAction=opts.flags["--action"],hasActionFlag=!!rawAction;if(!rawAction){if(client.nonInteractive||!client.stdin.isTTY){let command=`firewall rules update ${opts.id} --action <action>`;return failFirewall(client,{message:`Specify --action for ${current.name}. Run ${import_chalk27.default.cyan(withGlobalFlags(client,`firewall rules inspect ${opts.id}`,opts.scope))} to see the current value.`,reason:AGENT_REASON.MISSING_ARGUMENTS,fix:{command,hint:`Use ${import_chalk27.default.cyan(withGlobalFlags(client,command,opts.scope))}.`,when:"set --action"}})}output_manager_default.print(`
|
|
133
|
+
${formatManagedBotRuleDetail(current)}
|
|
134
|
+
|
|
135
|
+
`),rawAction=await client.input.select({message:"Action?",choices:managedBotActions(opts.id).map(action=>({value:action,name:formatManagedBotAction(action)}))})}let parsedAction=parseManagedBotAction(opts.id,rawAction);if("error"in parsedAction){let command=`firewall rules update ${opts.id} --action <action>`;return failFirewall(client,{message:parsedAction.error,reason:AGENT_REASON.INVALID_ARGUMENTS,fix:{command,hint:`Use ${import_chalk27.default.cyan(withGlobalFlags(client,command,opts.scope))}.`,when:"set a valid --action"}})}if(parsedAction.action===current.action)return output_manager_default.log(`No changes detected. ${current.name} is already ${formatManagedBotAction(current.action)}.`),0;if(opts.id==="bot-id"&&parsedAction.action==="deep-analysis")try{let{team}=await getScope(client);if(team?.billing?.plan==="hobby")return failFirewall(client,{message:"BotID Deep Analysis is not available on the Hobby plan.",reason:AGENT_REASON.PLAN_UPGRADE_REQUIRED})}catch{}let warning=managedBotTrafficWarning(opts.id,current.action,parsedAction.action);if(hasActionFlag&&output_manager_default.print(`
|
|
136
|
+
${formatManagedBotRuleDetail({...current,action:parsedAction.action})}
|
|
137
|
+
|
|
138
|
+
`),!await confirmAction(client,opts.flags["--yes"],`Save ${current.name} \u2192 ${formatManagedBotAction(parsedAction.action)}?`,warning))return output_manager_default.log("Canceled"),0;let editStamp=stamp_default();output_manager_default.spinner("Staging changes");try{let hadExistingDraft=await detectExistingDraft(client,opts.scope);return await patchFirewallDraft(client,opts.scope,buildManagedBotPatch(opts.id,parsedAction.action)),output_manager_default.log(`${import_chalk27.default.cyan("Success!")} ${current.name} updated to ${import_chalk27.default.bold(formatManagedBotAction(parsedAction.action))} and staged ${import_chalk27.default.gray(editStamp())}`),opts.id==="bot-id"&&parsedAction.action==="deep-analysis"&&output_manager_default.print(`
|
|
139
|
+
${import_chalk27.default.dim("Install the BotID SDK in your app:")} ${import_chalk27.default.cyan("npm i botid")}
|
|
140
|
+
`),await offerAutoPublish(client,opts.scope,hadExistingDraft,{skipPrompts:opts.flags["--yes"]}),0}catch(e){output_manager_default.stopSpinner();let priority=failPriorityProjectGate(client,e,opts.scope);if(priority!==null)return priority;let command=`firewall rules update ${opts.id} --action ${parsedAction.action}`;return failFirewall(client,{message:mapFirewallApiError(e,opts.scope,"Failed to stage bot rule changes"),nextCommand:command,reason:AGENT_REASON.API_ERROR})}}async function edit(client,argv){let parsed=await parseSubcommandArgs(argv,rulesEditSubcommand,client,"rules update");if(typeof parsed=="number")return parsed;let identifier=parsed.args[0],scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;output_manager_default.spinner(`Fetching rules for ${import_chalk28.default.bold(scope.displayName)}`);let{active,draft}=await listFirewallConfigs(client,scope),config=draft??active,currentRules=draft?.rules||active?.rules||[],managedRules=scope.type==="project"?getManagedBotRules(config):[];if(!identifier){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return output_manager_default.error(`Missing required argument: <name-or-id>. Run ${import_chalk28.default.cyan(withGlobalFlags(client,"firewall rules list",scope))} to see all rules.`),2;if(currentRules.length===0&&managedRules.length===0)return output_manager_default.error("No custom rules configured. Create one first with `vercel firewall rules add`."),1;let selectedId=await client.input.select({message:"Select a rule to update:",choices:[...managedRules.map(r=>({value:r.id,name:`${r.name} \u2014 ${formatManagedBotAction(r.action)} (${r.id})`})),...currentRules.map(r=>({value:r.id,name:`${r.name} [${r.active?"Enabled":"Disabled"}] \u2014 ${formatActionDisplay(r.action)}`}))]}),selectedManaged=resolveManagedBotRuleId(selectedId);if(selectedManaged)return editManagedBotRule(client,{id:selectedManaged,flags:parsed.flags,scope,config});let selected=currentRules.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;identifier=selected.id}let managedId=scope.type==="project"?resolveManagedBotRuleId(identifier):void 0;if(managedId)return output_manager_default.stopSpinner(),editManagedBotRule(client,{id:managedId,flags:parsed.flags,scope,config});let matches=resolveRule(currentRules,identifier);if(matches.length===0)return output_manager_default.error(`No rule found for "${identifier}". Run ${import_chalk28.default.cyan(withGlobalFlags(client,"firewall rules list",scope))} to view all rules.`),1;let originalRule=matches[0];if(matches.length>1){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return output_manager_default.error(`Multiple rules match "${identifier}". Specify the full rule ID to disambiguate.`),1;let selectedId=await client.input.select({message:`Multiple rules match "${identifier}". Select one:`,choices:matches.map(r=>({value:r.id,name:`${r.name} [${r.active?"Enabled":"Disabled"}] (${r.id})`}))}),selected=matches.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;originalRule=selected}output_manager_default.stopSpinner();let aiPrompt=parsed.flags["--ai"],jsonInput=getRulePayload(parsed.flags);if(typeof jsonInput=="number")return jsonInput;let conditionFlags=parsed.flags["--condition"];if([aiPrompt,jsonInput,conditionFlags].filter(Boolean).length>1)return output_manager_default.error("Cannot use --ai, --data, and --condition together. Use only one mode."),1;if(aiPrompt)return scope.type==="team"?(output_manager_default.error("AI mode is not available with --team-level. Use --data or flag-based editing instead."),1):client.nonInteractive||!client.stdin.isTTY?(client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ai_not_available",message:"AI mode is not available in non-interactive mode. AI-generated changes require human review. Use --data or flag-based editing instead.",next:[{command:withGlobalFlags(client,`firewall rules update "${identifier}" --action challenge --yes`),when:"edit with flags"},{command:withGlobalFlags(client,`firewall rules update "${identifier}" --data '{"name":"...","conditionGroup":[...],"action":{...}}' --yes`),when:"edit with JSON"}]}),output_manager_default.error("AI mode is not available in non-interactive mode. Use --data or flag-based editing instead."),1):handleAIEdit(client,{id:scope.projectId,name:scope.displayName},scope.teamId,originalRule,{prompt:aiPrompt,skipPrompts:!!parsed.flags["--yes"]});if(jsonInput)return handleJsonEdit(client,parsed,originalRule,jsonInput,scope);if(conditionFlags||parsed.flags["--action"]||parsed.flags["--name"]||parsed.flags["--description"]!==void 0||parsed.flags["--duration"]||parsed.flags["--enable"]||parsed.flags["--no-enable"]||parsed.flags["--enabled"]||parsed.flags["--disabled"]||parsed.flags["--rate-limit-algo"]||parsed.flags["--rate-limit-window"]||parsed.flags["--rate-limit-requests"]||parsed.flags["--rate-limit-keys"]||parsed.flags["--rate-limit-action"]||parsed.flags["--redirect-url"]||parsed.flags["--redirect-permanent"])return handleFlagEdit(client,parsed,originalRule,argv,scope);if(client.stdin.isTTY&&!client.nonInteractive){if(output_manager_default.print(`
|
|
141
|
+
${import_chalk28.default.bold("Current rule:")}
|
|
142
|
+
`),output_manager_default.print(`${formatRuleExpanded(originalRule)}
|
|
143
|
+
|
|
144
|
+
`),await client.input.select({message:"How would you like to update this rule?",choices:[...scope.type==="project"?[{value:"ai",name:"Describe changes (AI-powered)"}]:[],{value:"manual",name:"Edit manually (field by field)"}]})==="ai"&&scope.type==="project")return handleAIEdit(client,{id:scope.projectId,name:scope.displayName},scope.teamId,originalRule,{skipPrompts:!1});let modified=await runInteractiveEditLoop(client,originalRule);return modified?JSON.stringify(modified)===JSON.stringify(originalRule)?(output_manager_default.log("No changes detected."),0):saveEdit(client,scope,originalRule,modified,parsed,{skipConfirm:!0}):(output_manager_default.log("Canceled"),0)}return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"missing_flags",message:"No edit flags provided. Use --data, --condition, --action, --name, etc.",next:[{command:withGlobalFlags(client,`firewall rules update "${identifier}" --action challenge --yes`),when:"edit with flags"},{command:withGlobalFlags(client,`firewall rules update "${identifier}" --data '{"name":"...","conditionGroup":[...],"action":{"mitigate":{"action":"deny"}}}' --yes`),when:"edit with JSON"}]}),output_manager_default.error("Interactive mode is not available. Use --data or flag-based editing."),2}async function handleAIEdit(client,project,teamId,originalRule,opts){let prompt=opts.prompt;if(!prompt){if(!client.stdin.isTTY||client.nonInteractive)return output_manager_default.error("--ai requires a description."),1;prompt=await client.input.text({message:"Describe the changes you want:",validate:val=>val.trim()?!0:"Please describe the changes."})}let currentRule=JSON.parse(JSON.stringify(originalRule));for(;;){output_manager_default.spinner("Generating changes with AI...");try{let response=await generateFirewallRule(client,project.id,{prompt,currentRule},{teamId});if(output_manager_default.stopSpinner(),response.error){if(client.stdin.isTTY&&!client.nonInteractive&&!opts.skipPrompts){if(await client.input.select({message:`AI could not update the rule: ${response.error}`,choices:[{value:"retry",name:"Try again with a different description"},{value:"cancel",name:"Cancel"}]})==="cancel")return output_manager_default.log("Canceled"),0;prompt=await client.input.text({message:"Describe the changes you want:",validate:val=>val.trim()?!0:"Please describe the changes."});continue}return output_manager_default.error(`AI could not update the rule: ${response.error}`),1}if(!response.rule){if(client.stdin.isTTY&&!client.nonInteractive&&!opts.skipPrompts){if(await client.input.select({message:"AI did not return a rule.",choices:[{value:"retry",name:"Try again with a different description"},{value:"cancel",name:"Cancel"}]})==="cancel")return output_manager_default.log("Canceled"),0;prompt=await client.input.text({message:"Describe the changes you want:",validate:val=>val.trim()?!0:"Please describe the changes."});continue}return output_manager_default.error("AI did not return a rule."),1}currentRule={...response.rule,id:originalRule.id};break}catch(e){output_manager_default.stopSpinner();let error=e;if(!client.stdin.isTTY||client.nonInteractive)return output_manager_default.error(error.message||"Failed to generate changes"),1;if(await client.input.select({message:`Generation failed: ${error.message||"Unknown error"}`,choices:[{value:"retry",name:"Try again"},{value:"cancel",name:"Cancel"}]})==="cancel")return output_manager_default.log("Canceled"),0}}if(output_manager_default.print(`
|
|
145
|
+
${formatRuleExpanded(currentRule)}
|
|
146
|
+
|
|
147
|
+
`),opts.skipPrompts)return saveEdit(client,projectScope(project,teamId),originalRule,currentRule,{flags:{"--yes":!0}});for(;;){let choice;try{choice=await client.input.select({message:"What would you like to do?",choices:[{value:"save",name:"Save changes"},{value:"edit-ai",name:"Edit with AI (describe more changes)"},{value:"edit-manual",name:"Edit manually (field by field)"},{value:"discard",name:"Discard"}]})}catch{return 1}if(choice==="save")return saveEdit(client,projectScope(project,teamId),originalRule,currentRule,{flags:{}},{skipConfirm:!0});if(choice==="edit-ai"){prompt=await client.input.text({message:"Describe the changes you want:",validate:val=>val.trim()?!0:"Please describe the changes."}),output_manager_default.spinner("Regenerating...");try{let response=await generateFirewallRule(client,project.id,{prompt,currentRule},{teamId});if(output_manager_default.stopSpinner(),response.error||!response.rule){output_manager_default.error(`AI could not update the rule: ${response.error||"No rule returned"}`);continue}currentRule={...response.rule,id:originalRule.id},output_manager_default.print(`
|
|
148
|
+
${formatRuleExpanded(currentRule)}
|
|
149
|
+
|
|
150
|
+
`);continue}catch(e){output_manager_default.stopSpinner();let error=e;output_manager_default.error(error.message||"Failed to regenerate");continue}}if(choice==="edit-manual"){let modified=await runInteractiveEditLoop(client,currentRule);if(!modified)continue;currentRule=modified,output_manager_default.print(`
|
|
151
|
+
${formatRuleExpanded(currentRule)}
|
|
152
|
+
|
|
153
|
+
`);continue}if(choice==="discard")return output_manager_default.log("Discarded"),0}}async function handleJsonEdit(client,parsed,originalRule,jsonStr,scope){let ruleData;try{ruleData=JSON.parse(jsonStr)}catch{return output_manager_default.error("Invalid JSON. Please provide a valid JSON object."),2}if(!ruleData.name||typeof ruleData.name!="string")return output_manager_default.error('JSON must include a "name" field (string).'),1;if(!ruleData.conditionGroup||!Array.isArray(ruleData.conditionGroup))return output_manager_default.error('JSON must include a "conditionGroup" field (array).'),1;if(!ruleData.action||typeof ruleData.action!="object")return output_manager_default.error('JSON must include an "action" field (object).'),1;if(ruleData.name.length>160)return output_manager_default.error("Rule name must be 160 characters or less."),1;if(ruleData.description!==void 0&&ruleData.description!==null){if(typeof ruleData.description!="string")return output_manager_default.error('JSON "description" field must be a string.'),2;if(ruleData.description.length>256)return output_manager_default.error("Rule description must be 256 characters or less."),1}let actionObj=ruleData.action;if(!actionObj.mitigate||typeof actionObj.mitigate!="object")return output_manager_default.error('action must have a "mitigate" field. Example: { "mitigate": { "action": "deny" } }'),1;let mitigateObj=actionObj.mitigate;if(!mitigateObj.action||typeof mitigateObj.action!="string")return output_manager_default.error('action.mitigate must have an "action" field (string). Valid: deny, challenge, rate_limit, log, redirect.'),1;let modified={id:originalRule.id,name:ruleData.name,description:ruleData.description,active:ruleData.active!==void 0?ruleData.active!==!1:originalRule.active!==!1,conditionGroup:ruleData.conditionGroup,action:ruleData.action};return saveEdit(client,scope,originalRule,modified,parsed)}function extractConditionFlags(argv){let result=[],i=0;for(;i<argv.length;)argv[i]==="--or"?(result.push("--or"),i++):argv[i]==="--condition"&&i+1<argv.length?(result.push(argv[i+1]),i+=2):(argv[i].startsWith("--condition=")&&result.push(argv[i].slice(12)),i++);return result}async function handleFlagEdit(client,parsed,originalRule,rawArgv,scope){let modified=JSON.parse(JSON.stringify(originalRule)),newName=parsed.flags["--name"];if(newName){if(newName.length>160)return output_manager_default.error("Rule name must be 160 characters or less."),1;modified.name=newName}if(parsed.flags["--description"]!==void 0){let desc=parsed.flags["--description"];if(desc.length>256)return output_manager_default.error("Description must be 256 characters or less."),1;modified.description=desc===""?void 0:desc}let enable4=readOnOffOption(client,parsed.flags,{on:"--enable",off:"--no-enable",oldOn:"--enabled",oldOff:"--disabled"});if("error"in enable4)return output_manager_default.error(enable4.error),2;if(enable4.value!==void 0&&(modified.active=enable4.value),parsed.flags["--condition"]){let interleaved=extractConditionFlags(rawArgv);if(interleaved.length===0)return output_manager_default.error("At least one --condition is required."),2;let condResult=parseConditionFlags(interleaved);if(typeof condResult=="string")return output_manager_default.error(condResult),1;modified.conditionGroup=condResult.groups}let actionType=parsed.flags["--action"];if(actionType){if(!VALID_ACTIONS.includes(actionType))return output_manager_default.error(`Invalid action "${actionType}". Valid actions: ${VALID_ACTIONS.join(", ")}`),1;let actionResult=buildActionFromFlags(parsed.flags,actionType);if(typeof actionResult=="string")return output_manager_default.error(actionResult),1;modified.action=actionResult}else{let duration=parsed.flags["--duration"];if(duration){if(!VALID_DURATIONS.includes(duration))return output_manager_default.error(`Invalid duration "${duration}". Valid durations: ${VALID_DURATIONS.join(", ")}`),1;modified.action.mitigate&&(modified.action.mitigate.actionDuration=duration)}}return JSON.stringify(modified)===JSON.stringify(originalRule)?(output_manager_default.log("No changes detected."),0):saveEdit(client,scope,originalRule,modified,parsed)}async function saveEdit(client,scope,originalRule,modified,parsed,opts){if(!opts?.skipConfirm&&(output_manager_default.print(`
|
|
154
|
+
${formatRuleExpanded(modified)}
|
|
155
|
+
|
|
156
|
+
`),!await confirmAction(client,parsed.flags["--yes"],`Save changes to "${modified.name}"?`)))return output_manager_default.log("Canceled"),0;let editStamp=stamp_default();output_manager_default.spinner("Staging changes");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"rules.update",id:originalRule.id,value:{name:modified.name,description:modified.description,active:modified.active,conditionGroup:modified.conditionGroup,action:modified.action}}),output_manager_default.log(`${import_chalk28.default.cyan("Success!")} Rule "${import_chalk28.default.bold(modified.name)}" updated and staged ${import_chalk28.default.gray(editStamp())}`),printActionImpactWarning(modified.action),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:parsed.flags["--yes"]}),0}catch(e){output_manager_default.stopSpinner();let priority=failPriorityProjectGate(client,e,scope);if(priority!==null)return priority;let msg=mapFirewallApiError(e,scope,"Failed to stage rule changes");return client.nonInteractive?(outputAgentError(client,{status:"error",reason:"api_error",message:msg,next:[{command:withGlobalFlags(client,`firewall rules update "${originalRule.name}" --yes`,scope)}]}),1):(output_manager_default.error(msg),1)}}var import_chalk29=__toESM(require_source(),1);async function enable2(client,argv){let parsed=await parseSubcommandArgs(argv,rulesEnableSubcommand,client,"rules enable");if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;let identifier=parsed.args[0],reserved=refuseManagedBotMutation(client,scope,identifier,"enable");if(reserved!==null)return reserved;output_manager_default.spinner(`Fetching rules for ${import_chalk29.default.bold(scope.displayName)}`);let{active,draft}=await listFirewallConfigs(client,scope),currentRules=draft?.rules||active?.rules||[];if(currentRules.length===0)return output_manager_default.stopSpinner(),output_manager_default.error("No custom rules configured. Create one first with `vercel firewall rules add`."),1;if(!identifier){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"missing_arguments",message:"Rule name or ID is required.",next:[{command:withGlobalFlags(client,"firewall rules enable <name-or-id>"),when:"replace <name-or-id>"},{command:withGlobalFlags(client,"firewall rules list",scope),when:"list rules"}]},2),output_manager_default.error(`Rule name or ID is required. Usage: ${withGlobalFlags(client,"firewall rules enable <name-or-id>",scope)}`),2;let disabledRules=currentRules.filter(r=>r.active===!1);if(disabledRules.length===0)return output_manager_default.log("All rules are already enabled."),0;let selectedId=await client.input.select({message:"Select a rule to enable:",choices:disabledRules.map(r=>({value:r.id,name:`${r.name} \u2014 ${formatActionDisplay(r.action)}`}))}),selected=currentRules.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;identifier=selected.name}let allMatches=resolveRule(currentRules,identifier);if(allMatches.length===0)return output_manager_default.stopSpinner(),output_manager_default.error(`No rule found for "${identifier}". Run ${import_chalk29.default.cyan(withGlobalFlags(client,"firewall rules list",scope))} to view all rules.`),1;let matches=allMatches.filter(r=>r.active===!1);if(matches.length===0)return output_manager_default.stopSpinner(),allMatches.length===1?output_manager_default.log(`Rule "${allMatches[0].name}" is already enabled.`):output_manager_default.log("All matching rules are already enabled."),0;let rule=matches[0];if(matches.length>1){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ambiguous_match",message:`Multiple rules match "${identifier}". Specify the full rule ID.`,next:matches.map(r=>({command:withGlobalFlags(client,`firewall rules enable "${r.id}" --yes`,scope),when:`enable "${r.name}"`}))}),output_manager_default.error(`Multiple rules match "${identifier}". Specify the full rule ID to disambiguate.`),1;let selectedId=await client.input.select({message:`Multiple rules match "${identifier}". Select one:`,choices:matches.map(r=>({value:r.id,name:`${r.name} \u2014 ${formatActionDisplay(r.action)}`}))}),selected=matches.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;rule=selected}output_manager_default.stopSpinner();let enableStamp=stamp_default();output_manager_default.spinner("Staging changes");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"rules.update",id:rule.id,value:{name:rule.name,description:rule.description,active:!0,conditionGroup:rule.conditionGroup,action:rule.action}}),output_manager_default.log(`${import_chalk29.default.cyan("Enabled")} rule "${import_chalk29.default.bold(rule.name)}" ${import_chalk29.default.gray(enableStamp())}`),printActionImpactWarning(rule.action),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:parsed.flags["--yes"]}),0}catch(e){output_manager_default.stopSpinner();let priority=failPriorityProjectGate(client,e,scope);return priority!==null?priority:(output_manager_default.error(mapFirewallApiError(e,scope,"Failed to enable rule")),1)}}var import_chalk30=__toESM(require_source(),1);async function disable2(client,argv){let parsed=await parseSubcommandArgs(argv,rulesDisableSubcommand,client,"rules disable");if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;let identifier=parsed.args[0],reserved=refuseManagedBotMutation(client,scope,identifier,"disable");if(reserved!==null)return reserved;output_manager_default.spinner(`Fetching rules for ${import_chalk30.default.bold(scope.displayName)}`);let{active,draft}=await listFirewallConfigs(client,scope),currentRules=draft?.rules||active?.rules||[];if(currentRules.length===0)return output_manager_default.stopSpinner(),output_manager_default.error("No custom rules configured. Create one first with `vercel firewall rules add`."),1;if(!identifier){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"missing_arguments",message:"Rule name or ID is required.",next:[{command:withGlobalFlags(client,"firewall rules disable <name-or-id>"),when:"replace <name-or-id>"},{command:withGlobalFlags(client,"firewall rules list",scope),when:"list rules"}]},2),output_manager_default.error(`Rule name or ID is required. Usage: ${withGlobalFlags(client,"firewall rules disable <name-or-id>",scope)}`),2;let enabledRules=currentRules.filter(r=>r.active!==!1);if(enabledRules.length===0)return output_manager_default.log("All rules are already disabled."),0;let selectedId=await client.input.select({message:"Select a rule to disable:",choices:enabledRules.map(r=>({value:r.id,name:`${r.name} \u2014 ${formatActionDisplay(r.action)}`}))}),selected=currentRules.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;identifier=selected.name}let allMatches=resolveRule(currentRules,identifier);if(allMatches.length===0)return output_manager_default.stopSpinner(),output_manager_default.error(`No rule found for "${identifier}". Run ${import_chalk30.default.cyan(withGlobalFlags(client,"firewall rules list",scope))} to view all rules.`),1;let matches=allMatches.filter(r=>r.active!==!1);if(matches.length===0)return output_manager_default.stopSpinner(),allMatches.length===1?output_manager_default.log(`Rule "${allMatches[0].name}" is already disabled.`):output_manager_default.log("All matching rules are already disabled."),0;let rule=matches[0];if(matches.length>1){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ambiguous_match",message:`Multiple rules match "${identifier}". Specify the full rule ID.`,next:matches.map(r=>({command:withGlobalFlags(client,`firewall rules disable "${r.id}" --yes`,scope),when:`disable "${r.name}"`}))}),output_manager_default.error(`Multiple rules match "${identifier}". Specify the full rule ID to disambiguate.`),1;let selectedId=await client.input.select({message:`Multiple rules match "${identifier}". Select one:`,choices:matches.map(r=>({value:r.id,name:`${r.name} \u2014 ${formatActionDisplay(r.action)}`}))}),selected=matches.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;rule=selected}output_manager_default.stopSpinner();let disableStamp=stamp_default();output_manager_default.spinner("Staging changes");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"rules.update",id:rule.id,value:{name:rule.name,description:rule.description,active:!1,conditionGroup:rule.conditionGroup,action:rule.action}}),output_manager_default.log(`${import_chalk30.default.cyan("Disabled")} rule "${import_chalk30.default.bold(rule.name)}" ${import_chalk30.default.gray(disableStamp())}`),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:parsed.flags["--yes"]}),0}catch(e){output_manager_default.stopSpinner();let priority=failPriorityDisable(client,e,scope,rule);return priority!==null?priority:(output_manager_default.error(mapFirewallApiError(e,scope,"Failed to disable rule")),1)}}function failPriorityDisable(client,error,scope,rule){let serverMessage=apiServerMessage(error);if(!serverMessage||!mentionsPriorityProject(serverMessage))return null;let cached=scope.teamId?teamCache.get(scope.teamId):void 0,scopeArg=scope.type==="team"?scope.displayName:scope.teamSlug??cached?.slug??scope.teamId,scopeFlag=scopeArg?` --scope ${quoteArg(scopeArg)}`:"",command=`firewall rules remove ${quoteArg(rule.name)}${scopeFlag}`,message=`This rule cannot be disabled while ${scope.displayName} is not a Priority project. Remove it instead.`,nextCommand=withGlobalFlags(client,command,scope,{preserveProject:!0,excludeFlags:["--non-interactive","--yes","--scope","--team"]}),payload={status:AGENT_STATUS.ERROR,reason:AGENT_REASON.INVALID_ARGUMENTS,message,userActionRequired:!0,hint:nextCommand,retryable:!1,...scopeArg?{scope:scopeArg}:{},next:[{command:nextCommand,when:"remove the rule instead of disabling it"}]};return shouldEmitNonInteractiveCommandError(client)&&outputAgentError(client,payload,1),output_manager_default.error(message),output_manager_default.log(nextCommand),1}var import_chalk31=__toESM(require_source(),1);async function remove2(client,argv){let parsed=await parseSubcommandArgs(argv,rulesRemoveSubcommand,client,"rules remove");if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;let identifier=parsed.args[0],reserved=refuseManagedBotMutation(client,scope,identifier,"remove");if(reserved!==null)return reserved;output_manager_default.spinner(`Fetching rules for ${import_chalk31.default.bold(scope.displayName)}`);let{active,draft}=await listFirewallConfigs(client,scope),currentRules=draft?.rules||active?.rules||[];if(currentRules.length===0)return output_manager_default.stopSpinner(),output_manager_default.error("No custom rules configured. Create one first with `vercel firewall rules add`."),1;if(!identifier){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"missing_arguments",message:"Rule name or ID is required.",next:[{command:withGlobalFlags(client,"firewall rules remove <name-or-id> --yes"),when:"replace <name-or-id>"},{command:withGlobalFlags(client,"firewall rules list",scope),when:"list rules"}]},2),output_manager_default.error(`Rule name or ID is required. Usage: ${withGlobalFlags(client,"firewall rules remove <name-or-id> --yes",scope)}`),2;let selectedId=await client.input.select({message:"Select a rule to remove:",choices:currentRules.map(r=>({value:r.id,name:`${r.name} [${r.active?"Enabled":"Disabled"}] \u2014 ${formatActionDisplay(r.action)}`}))}),selected=currentRules.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;identifier=selected.name}let matches=resolveRule(currentRules,identifier);if(matches.length===0)return output_manager_default.stopSpinner(),output_manager_default.error(`No rule found for "${identifier}". Run ${import_chalk31.default.cyan(withGlobalFlags(client,"firewall rules list",scope))} to view all rules.`),1;let rule=matches[0];if(matches.length>1){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ambiguous_match",message:`Multiple rules match "${identifier}". Specify the full rule ID.`,next:matches.map(r=>({command:withGlobalFlags(client,`firewall rules remove "${r.id}" --yes`,scope),when:`remove "${r.name}"`}))}),output_manager_default.error(`Multiple rules match "${identifier}". Specify the full rule ID to disambiguate.`),1;let selectedId=await client.input.select({message:`Multiple rules match "${identifier}". Select one:`,choices:matches.map(r=>({value:r.id,name:`${r.name} [${r.active?"Enabled":"Disabled"}] \u2014 ${formatActionDisplay(r.action)}`}))}),selected=matches.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;rule=selected}output_manager_default.stopSpinner();let action=formatActionDisplay(rule.action),conditionCount=rule.conditionGroup.reduce((sum,g)=>sum+g.conditions.length,0);if(output_manager_default.log(`Rule: ${import_chalk31.default.bold(rule.name)} [${rule.active?"Enabled":"Disabled"}] \u2014 ${action} (${conditionCount} condition${conditionCount!==1?"s":""})`),!await confirmAction(client,parsed.flags["--yes"],`Remove rule "${rule.name}"?`))return output_manager_default.log("Canceled"),0;let removeStamp=stamp_default();output_manager_default.spinner("Staging removal");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"rules.remove",id:rule.id,value:null}),output_manager_default.log(`${import_chalk31.default.cyan("Removed")} rule "${import_chalk31.default.bold(rule.name)}" ${import_chalk31.default.gray(removeStamp())}`),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:parsed.flags["--yes"]}),0}catch(e){return output_manager_default.error(mapFirewallApiError(e,scope,"Failed to remove rule")),1}}var import_chalk32=__toESM(require_source(),1);async function reorder(client,argv){let parsed=await parseSubcommandArgs(argv,rulesReorderSubcommand,client,"rules move");if(typeof parsed=="number")return parsed;let scope=await resolveFirewallScope(client,parsed.flags);if(typeof scope=="number")return scope;let identifier=parsed.args[0],reserved=refuseManagedBotMutation(client,scope,identifier,"move");if(reserved!==null)return reserved;output_manager_default.spinner(`Fetching rules for ${import_chalk32.default.bold(scope.displayName)}`);let{active,draft}=await listFirewallConfigs(client,scope),currentRules=draft?.rules||active?.rules||[];if(currentRules.length<2)return output_manager_default.stopSpinner(),output_manager_default.error("Need at least 2 rules to move one."),1;if(!identifier){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"missing_arguments",message:"Rule name or ID is required.",next:[{command:withGlobalFlags(client,"firewall rules move <name-or-id> --first --yes"),when:"replace <name-or-id>"},{command:withGlobalFlags(client,"firewall rules list",scope),when:"list rules"}]},2),output_manager_default.error(`Rule name or ID is required. Usage: ${withGlobalFlags(client,"firewall rules move <name-or-id> --position N --yes",scope)}`),2;let selectedId=await client.input.select({message:"Select a rule to move:",choices:currentRules.map((r,i)=>({value:r.id,name:`${i+1}. ${r.name} [${r.active?"Enabled":"Disabled"}] \u2014 ${formatActionDisplay(r.action)}`}))}),selected=currentRules.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;identifier=selected.name}let matches=resolveRule(currentRules,identifier);if(matches.length===0)return output_manager_default.stopSpinner(),output_manager_default.error(`No rule found for "${identifier}". Run ${import_chalk32.default.cyan(withGlobalFlags(client,"firewall rules list",scope))} to view all rules.`),1;let rule=matches[0];if(matches.length>1){if(output_manager_default.stopSpinner(),client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"ambiguous_match",message:`Multiple rules match "${identifier}". Specify the full rule ID.`,next:matches.map(r=>({command:withGlobalFlags(client,`firewall rules move "${r.id}" --first --yes`,scope),when:`move "${r.name}"`}))}),output_manager_default.error(`Multiple rules match "${identifier}". Specify the full rule ID to disambiguate.`),1;let selectedId=await client.input.select({message:`Multiple rules match "${identifier}". Select one:`,choices:matches.map(r=>({value:r.id,name:`${r.name} [${r.active?"Enabled":"Disabled"}] \u2014 ${formatActionDisplay(r.action)}`}))}),selected=matches.find(r=>r.id===selectedId);if(!selected)return output_manager_default.error("No rule selected"),1;rule=selected}output_manager_default.stopSpinner();let currentIndex=currentRules.findIndex(r=>r.id===rule.id),flagFirst=parsed.flags["--first"],flagLast=parsed.flags["--last"],flagPosition=parsed.flags["--position"];if([flagFirst,flagLast,flagPosition].filter(Boolean).length>1)return output_manager_default.error("Cannot use --first, --last, and --position together. Use only one."),1;let targetIndex;if(flagFirst)targetIndex=0;else if(flagLast)targetIndex=currentRules.length-1;else if(flagPosition!==void 0){if(flagPosition<1)return output_manager_default.error("Position must be at least 1."),2;if(flagPosition>currentRules.length)return output_manager_default.error(`Position ${flagPosition} exceeds the number of rules (${currentRules.length}).`),1;targetIndex=flagPosition-1}else{if(client.nonInteractive||!client.stdin.isTTY)return client.nonInteractive&&outputAgentError(client,{status:"error",reason:"missing_arguments",message:"A position flag is required. Use --position N, --first, or --last.",next:[{command:withGlobalFlags(client,`firewall rules move "${rule.name}" --first --yes`,scope),when:"move to first position"},{command:withGlobalFlags(client,`firewall rules move "${rule.name}" --last --yes`,scope),when:"move to last position"}]},2),output_manager_default.error("A position flag is required. Use --position N, --first, or --last."),2;output_manager_default.print(`
|
|
157
|
+
Current rule order:
|
|
158
|
+
`);for(let i=0;i<currentRules.length;i++){let r=currentRules[i],marker=r.id===rule.id?"\u2192":" ";output_manager_default.print(` ${marker} ${i+1}. ${r.name} [${r.active?"Enabled":"Disabled"}]
|
|
159
|
+
`)}output_manager_default.print(`
|
|
160
|
+
`);let positionStr=await client.input.text({message:`Move "${rule.name}" to position (1-${currentRules.length}):`,validate:val=>{let num=Number(val);return Number.isNaN(num)||!Number.isInteger(num)?"Enter a number.":num<1||num>currentRules.length?`Position must be between 1 and ${currentRules.length}.`:!0}});targetIndex=Number(positionStr)-1}if(currentIndex===targetIndex)return output_manager_default.log(`Rule "${rule.name}" is already at position ${targetIndex+1}.`),0;if(!await confirmAction(client,parsed.flags["--yes"],`Move "${rule.name}" from position ${currentIndex+1} to position ${targetIndex+1}?`))return output_manager_default.log("Canceled"),0;let reorderStamp=stamp_default();output_manager_default.spinner("Staging move");try{let hadExistingDraft=await detectExistingDraft(client,scope);return await patchFirewallDraft(client,scope,{action:"rules.priority",id:rule.id,value:targetIndex}),output_manager_default.log(`${import_chalk32.default.cyan("Moved")} rule "${import_chalk32.default.bold(rule.name)}" to position ${targetIndex+1} ${import_chalk32.default.gray(reorderStamp())}`),await offerAutoPublish(client,scope,hadExistingDraft,{skipPrompts:parsed.flags["--yes"]}),0}catch(e){return output_manager_default.error(mapFirewallApiError(e,scope,"Failed to move rule")),1}}var COMMAND_CONFIG5={list:getCommandAliases(rulesListSubcommand),inspect:getCommandAliases(rulesInspectSubcommand),add:getCommandAliases(rulesAddSubcommand),update:getCommandAliases(rulesEditSubcommand),enable:getCommandAliases(rulesEnableSubcommand),disable:getCommandAliases(rulesDisableSubcommand),remove:getCommandAliases(rulesRemoveSubcommand),move:getCommandAliases(rulesReorderSubcommand)};async function main5(client,args,telemetry){let flagsSpecification=getFlagsSpecification(rulesSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(args,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG5),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall","rules"),output_manager_default.print(help(rulesSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand){case"list":return needHelp?(telemetry.trackCliFlagHelp("firewall",`rules:${subcommandOriginal}`),printHelp(rulesListSubcommand),0):(telemetry.trackCliSubcommandRulesList(subcommandOriginal),list3(client,subArgs));case"inspect":return needHelp?(telemetry.trackCliFlagHelp("firewall",`rules:${subcommandOriginal}`),printHelp(rulesInspectSubcommand),0):(telemetry.trackCliSubcommandRulesInspect(subcommandOriginal),inspect(client,subArgs));case"add":return needHelp?(telemetry.trackCliFlagHelp("firewall",`rules:${subcommandOriginal}`),printHelp(rulesAddSubcommand),0):(telemetry.trackCliSubcommandRulesAdd(subcommandOriginal),add2(client,subArgs));case"update":return needHelp?(telemetry.trackCliFlagHelp("firewall",`rules:${subcommandOriginal}`),printHelp(rulesEditSubcommand),0):(telemetry.trackCliSubcommandRulesUpdate(subcommandOriginal),subcommandOriginal==="edit"&&warnDeprecatedSubcommand(client,"firewall rules edit","firewall rules update"),edit(client,subArgs));case"enable":return needHelp?(telemetry.trackCliFlagHelp("firewall",`rules:${subcommandOriginal}`),printHelp(rulesEnableSubcommand),0):(telemetry.trackCliSubcommandRulesEnable(subcommandOriginal),enable2(client,subArgs));case"disable":return needHelp?(telemetry.trackCliFlagHelp("firewall",`rules:${subcommandOriginal}`),printHelp(rulesDisableSubcommand),0):(telemetry.trackCliSubcommandRulesDisable(subcommandOriginal),disable2(client,subArgs));case"remove":return needHelp?(telemetry.trackCliFlagHelp("firewall",`rules:${subcommandOriginal}`),printHelp(rulesRemoveSubcommand),0):(telemetry.trackCliSubcommandRulesRemove(subcommandOriginal),subcommandOriginal==="delete"&&warnDeprecatedSubcommand(client,"firewall rules delete","firewall rules remove"),remove2(client,subArgs));case"move":return needHelp?(telemetry.trackCliFlagHelp("firewall",`rules:${subcommandOriginal}`),printHelp(rulesReorderSubcommand),0):(telemetry.trackCliSubcommandRulesMove(subcommandOriginal),subcommandOriginal==="reorder"&&warnDeprecatedSubcommand(client,"firewall rules reorder","firewall rules move"),reorder(client,subArgs));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG5)),output_manager_default.print(help(rulesSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),2}}var import_chalk34=__toESM(require_source(),1);var import_chalk33=__toESM(require_source(),1);function splitAlertSections(alerts){let active=[],resolved=[];for(let alert of alerts)alert.resolvedAt?resolved.push(alert):active.push(alert);return{active,resolved}}function alertRow(alert){return[alert.resolvedAt?import_chalk33.default.dim("Resolved"):import_chalk33.default.yellow("Active"),alert.title,alert.detail?colorizeDetail(alert.detail):"",alert.count!==void 0?formatCount(alert.count):"\u2014",`${formatUtcTime(alert.startedAt,!0)} UTC`,relativeTime(alert.startedAt),alert.id]}function formatAlertsList(opts){let lines=[],window=`${formatUtcTime(opts.from.getTime(),!0)} \u2013 ${formatUtcTime(opts.to.getTime(),!0)} UTC`;lines.push(` ${import_chalk33.default.bold("Firewall alerts")} ${import_chalk33.default.dim(`(${window})`)}`),lines.push("");let alerts=[...opts.active,...opts.resolved];if(alerts.length===0)return lines.push(import_chalk33.default.dim(" No alerts in this window.")),lines.push(""),lines.join(`
|
|
161
|
+
`);let header=["Status","Alert","Detail","Requests","Started","Age","Id"].map(h=>import_chalk33.default.bold(import_chalk33.default.cyan(h))),rendered=table([header,...alerts.map(alertRow)],{align:["l","l","l","r","l","r","l"],hsep:3});for(let line2 of rendered.split(`
|
|
162
|
+
`))lines.push(` ${line2}`.trimEnd());return lines.push(""),lines.join(`
|
|
163
|
+
`)}function formatNamedCounts(rows){let nameWidth=Math.max(...rows.map(r=>r.name.length),0),countWidth=Math.max(...rows.map(r=>formatCount(r.count).length),0);return rows.map(row=>` ${row.name.padEnd(nameWidth)} ${formatCount(row.count).padStart(countWidth)}`).join(`
|
|
164
|
+
`)}function formatRate(n){return`${formatCount(n)} req/min`}function formatAlertInspect(view){let{alert}=view,status2=alert.resolvedAt?"Resolved":import_chalk33.default.yellow("Active"),lines=[` ${import_chalk33.default.bold(alert.title)} ${status2}`,formatAlignedLabel("Started",formatUtcDateTime(alert.startedAt))];if(alert.resolvedAt&&lines.push(formatAlignedLabel("Resolved",formatUtcDateTime(alert.resolvedAt))),alert.ruleId&&lines.push(formatAlignedLabel("Rule",alert.ruleId)),alert.action){let color=ACTION_COLORS[alert.action]??(s=>s);lines.push(formatAlignedLabel("Action",color(labelForAction(alert.action))))}if(alert.count!==void 0&&lines.push(formatAlignedLabel("Requests",formatCount(alert.count))),view.rates){lines.push(""),lines.push(formatAlignedLabel("Previous 24h",formatRate(view.rates.previousReqPerMin)));let anomaly=formatRate(view.rates.anomalyReqPerMin),multiplier=view.rates.multiplier!==null&&view.rates.multiplier>0?` ${Math.round(view.rates.multiplier)}x`:"";lines.push(formatAlignedLabel("Anomaly",`${anomaly}${multiplier}`))}if(view.timeseries&&view.timeseries.values.length>0){let{timeseries}=view,range=`${formatUtcTime(timeseries.startMs,!0)} \u2013 ${formatUtcTime(timeseries.endMs,!0)} UTC`,points=`${timeseries.pointCount} point${timeseries.pointCount===1?"":"s"} (${timeseries.granularityMinutes}m each)`,actionLabel=timeseries.action?` (${timeseries.action})`:"";if(lines.push(""),lines.push(` ${import_chalk33.default.bold(`Requests${actionLabel}`)} ${range} \xB7 ${points}`),lines.push(` ${generateSparkline(timeseries.values)}`),alert.resolvedAt||alert.startedAt){let endMs=alert.resolvedAt??timeseries.endMs;lines.push(` Anomaly window: ${formatUtcTime(alert.startedAt,!0)} \u2013 ${formatUtcTime(endMs,!0)} UTC`)}}if(view.ips&&view.ips.length>0){let ipTitle=alert.action==="challenge"?"Challenged IPs (during anomaly)":"Denied IPs (during anomaly)";lines.push(""),lines.push(import_chalk33.default.bold(` ${ipTitle}`)),lines.push(formatNamedCounts(view.ips))}return view.hosts&&view.hosts.length>0&&(lines.push(""),lines.push(import_chalk33.default.bold(" Top Hosts (during anomaly)")),lines.push(formatNamedCounts(view.hosts))),lines.push(""),lines.join(`
|
|
165
|
+
`)}async function list4(client,argv){let parsed=await parseSubcommandArgs(argv,alertsListSubcommand,client,"alerts list");if(typeof parsed=="number")return parsed;let sinceResult=validateTimeBound(parsed.flags["--since"]);if(!sinceResult.valid)return failFirewall(client,{message:sinceResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let untilResult=validateTimeBound(parsed.flags["--until"]);if(!untilResult.valid)return failFirewall(client,{message:untilResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let order=validateTimeOrder(sinceResult.value,untilResult.value);if(!order.valid)return failFirewall(client,{message:order.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let to=untilResult.value??new Date,from=sinceResult.value??new Date(to.getTime()-24*60*60*1e3),link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;if(!teamId)return failFirewall(client,{message:"Firewall alerts need a team. Run `vercel switch` to select a team or pass --scope <team>.",reason:AGENT_REASON.MISSING_SCOPE});let asJson=!!parsed.flags["--json"],suggestedCommand=`firewall alerts list${asJson?" --json":""}`;output_manager_default.spinner(`Fetching firewall alerts for ${import_chalk34.default.bold(project.name)}`);try{let fetched=await getFirewallAlertsDetailed(client,{projectId:project.id,teamId,from,to}),bothFailed=!!(fetched.o11y&&fetched.attackStatus),planIssue=[fetched.o11y,fetched.attackStatus].find(issue=>issue?.reason==="plan"),sourceError=[fetched.o11y,fetched.attackStatus].find(issue=>issue?.reason==="error");if(bothFailed&&sourceError)return failFirewall(client,{message:planIssue?`${sourceError.message.replace(/\.$/,"")}. ${planIssue.message}`:sourceError.message,nextCommand:suggestedCommand,reason:AGENT_REASON.API_ERROR});let inWindow=fetched.alerts.filter(alert=>alertOverlapsWindow(alert,from.getTime(),to.getTime())),sections=splitAlertSections(inWindow);return asJson?(outputJson(client,{...sections,...planIssue?{activityUnavailable:{reason:"plan",message:FIREWALL_ACTIVITY_PLAN_MESSAGE}}:{},...sourceError?{alertsUnavailable:{reason:"error",message:sourceError.message}}:{}}),0):(output_manager_default.print(`
|
|
166
|
+
${formatAlertsList({...sections,from,to})}`),planIssue?output_manager_default.print(` ${FIREWALL_ACTIVITY_PLAN_MESSAGE}
|
|
167
|
+
`):sourceError&&output_manager_default.print(` ${FIREWALL_ALERTS_PARTIAL_ERROR_MESSAGE}
|
|
168
|
+
`),output_manager_default.print(`
|
|
169
|
+
`),0)}catch(e){return failFirewallApi(client,e,{fallback:"Failed to fetch firewall alerts",nextCommand:suggestedCommand,permissionAction:"read firewall alerts",projectName:project.name,timeoutJob:"firewall alerts"})}}var import_chalk35=__toESM(require_source(),1);var EVENTS_TIMEOUT_MS=2e4,TOP_N=5;function apiTimestampMs(apiTimestamp){let pinned=new Date(`${apiTimestamp.replace(" ","T")}Z`).getTime();return Number.isNaN(pinned)?new Date(apiTimestamp).getTime():pinned}function toIso(apiTimestamp){let ms8=apiTimestampMs(apiTimestamp);return Number.isNaN(ms8)?apiTimestamp:new Date(ms8).toISOString()}function toPersistentAction(row){let redacted=isRedacted(row.action_type)||isRedacted(row.public_ip)||isRedacted(row.host);return{startTime:toIso(row.startTime),endTime:toIso(row.endTime),active:row.isActive,action:row.action,actionType:row.action_type,ruleType:isRedacted(row.action_type)?"hidden":row.action_type===SYSTEM_ACTION_TYPE?"system":"custom",...redacted?{redacted:!0}:{},host:row.host,ip:row.public_ip,requests:row.count,...row.ruleId?{ruleId:row.ruleId}:{},...row.ruleName?{ruleName:row.ruleName}:{}}}var SYSTEM_ACTION_TYPE="system-action",REDACTED_VALUE="***";function isRedacted(value){return value===REDACTED_VALUE}function ruleTypeLabel(actionType){return isRedacted(actionType)?"Hidden":actionType===SYSTEM_ACTION_TYPE?"System Rule":"Custom Rule"}var CLIENT_IP_DIMENSION="clientIp",HOST_DIMENSION="requestHostname",PATH_DIMENSION="requestPath";function persistentActionFilter(opts){return andFilters(isRedacted(opts.ip)?void 0:eqFilter(CLIENT_IP_DIMENSION,opts.ip),opts.host&&!isRedacted(opts.host)?eqFilter(HOST_DIMENSION,opts.host):void 0,opts.withPath?nonEmptyFilter(PATH_DIMENSION):void 0)}function aggregateTop(actions,key,top,mitigation){let totals=new Map;for(let action of actions){if(mitigation&&action.action!==mitigation)continue;let name=action[key];!name||isRedacted(name)||totals.set(name,(totals.get(name)??0)+action.count)}return[...totals.entries()].map(([name,count])=>({name,count})).sort((a,b)=>b.count-a.count).slice(0,top)}var PERSISTENT_ACTION_RETENTION_MS={enterprise:7*24*60*60*1e3,other:24*60*60*1e3};function clampPersistentActionWindow(opts){if(opts.planKnown===!1)return{from:opts.from,to:opts.to,empty:!1};let now=opts.now??Date.now(),retentionMs=opts.isEnterprise?PERSISTENT_ACTION_RETENTION_MS.enterprise:PERSISTENT_ACTION_RETENTION_MS.other,earliest=now-retentionMs;if(opts.from.getTime()>=earliest)return{from:opts.from,to:opts.to,empty:!1};let from=new Date(earliest);return{from,to:opts.to,requestedFrom:opts.from,empty:from.getTime()>=opts.to.getTime()}}function retentionLabel(isEnterprise){return isEnterprise?"7 days":"24 hours"}function startedAtMs(row){let ms8=apiTimestampMs(row.startTime);return Number.isNaN(ms8)?0:ms8}async function fetchFirewallPersistentActions(client,opts){let query=new URLSearchParams;query.set("projectId",opts.projectId),query.set("teamId",opts.teamId),query.set("startTimestamp",String(opts.startTime.getTime())),query.set("endTimestamp",String(opts.endTime.getTime())),opts.host&&query.set("hosts",opts.host);let timeoutMs=opts.timeoutMs??EVENTS_TIMEOUT_MS;try{return[...(await client.fetch(`/v1/security/firewall/events?${query.toString()}`,{accountId:opts.teamId,signal:AbortSignal.timeout(timeoutMs)})).actions??[]].sort((a,b)=>{let start=startedAtMs(b)-startedAtMs(a);return start!==0?start:b.count-a.count})}catch(err){throw err instanceof Error&&(err.name==="TimeoutError"||err.name==="AbortError")?new Error(`Timed out after ${Math.round(timeoutMs/1e3)}s waiting for firewall events. Re-run the command \u2014 the next try is usually faster.`):err}}async function getFirewallEvents(client,opts){let actions=await fetchFirewallPersistentActions(client,opts),top=opts.top??TOP_N;return{ips:aggregateTop(actions,"public_ip",top,opts.action),hosts:aggregateTop(actions,"host",top)}}function summarizePersistentActions(actions){let challenging=new Set,blocking=new Set,otherActions=0,withheldActions=0,activeTotal=0;for(let action of actions)if(action.isActive){if(activeTotal+=1,isRedacted(action.public_ip)){action.action==="challenge"||action.action==="deny"?withheldActions+=1:otherActions+=1;continue}action.action==="challenge"?challenging.add(action.public_ip):action.action==="deny"?blocking.add(action.public_ip):otherActions+=1}return activeTotal===0?null:{challengingIps:challenging.size,blockingIps:blocking.size,otherActions,withheldActions,activeTotal}}var PREVIOUS_WINDOW_MS=24*60*60*1e3,GRANULARITY_MINUTES=15,GRANULARITY_MS=GRANULARITY_MINUTES*60*1e3;function isActivityUnavailable2(error){return isAPIError(error)&&error.status===402}function floorToBucket(ms8){return Math.floor(ms8/GRANULARITY_MS)*GRANULARITY_MS}function sumInWindow(series,action,startMs,endMs){let total=0;for(let s of series)if(s.action===action)for(let point of s.timeseries){let ts=new Date(point.timestamp).getTime();ts>=startMs&&ts<endMs&&(total+=point.value)}return total}function reqPerMin(total,windowMs){let minutes=windowMs/6e4;return minutes>0?total/minutes:0}function axisBetween(startMs,endMs,stepMs){let axis=[];for(let t=startMs;t<endMs;t+=stepMs)axis.push(t);return axis}function valuesOnAxis(series,axis){let byTs=new Map;for(let point of series?.timeseries??[])byTs.set(new Date(point.timestamp).getTime(),point.value);return axis.map(t=>byTs.get(t)??0)}async function inspect2(client,argv){let parsed=await parseSubcommandArgs(argv,alertsInspectSubcommand,client,"alerts inspect");if(typeof parsed=="number")return parsed;let alertId=parsed.args[0];if(!alertId)return failFirewall(client,{message:`Alert id is required. Usage: ${withGlobalFlags(client,"firewall alerts inspect <alertid>")}`,nextCommand:"firewall alerts inspect <alertid>",reason:AGENT_REASON.MISSING_ARGUMENTS});let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;if(!teamId)return failFirewall(client,{message:"Firewall alerts need a team. Run `vercel switch` to select a team or pass --scope <team>.",reason:AGENT_REASON.MISSING_SCOPE});let asJson=!!parsed.flags["--json"],suggestedCommand=`firewall alerts inspect ${alertId}${asJson?" --json":""}`;output_manager_default.spinner(`Fetching alert ${import_chalk35.default.bold(alertId)}`);try{let resolved=await findFirewallAlert(client,{projectId:project.id,teamId,alertId});if(!resolved)return failFirewall(client,{message:`No firewall alert found for "${alertId}". Run ${withGlobalFlags(client,"firewall alerts list")} to view recent alerts.`,nextCommand:"firewall alerts list",reason:AGENT_REASON.NOT_FOUND});let{alert}=resolved,action=alert.action??"deny",anomalyStart=floorToBucket(alert.startedAt),anomalyEnd=Math.max(alert.resolvedAt??Date.now(),anomalyStart+GRANULARITY_MS),chartStart=floorToBucket(anomalyStart-PREVIOUS_WINDOW_MS),chartEnd=anomalyEnd;output_manager_default.spinner(`Fetching traffic for ${import_chalk35.default.bold(alert.title)}`);let eventsIssue,[metrics,events]=await Promise.all([getFirewallMetrics(client,{projectId:project.id,ownerId:teamId,startTime:new Date(chartStart),endTime:new Date(chartEnd),granularity:{minutes:GRANULARITY_MINUTES}}).catch(err=>{if(isActivityUnavailable2(err))return null;throw err}),getFirewallEvents(client,{projectId:project.id,teamId,startTime:new Date(anomalyStart),endTime:new Date(anomalyEnd),action}).catch(err=>{if(isAPIError(err)&&(err.status===401||err.status===403))throw err;return isActivityUnavailable2(err)?(eventsIssue={reason:"plan",message:FIREWALL_ACTIVITY_PLAN_MESSAGE},null):(eventsIssue={reason:"error",message:apiServerMessage(err)||!isAPIError(err)&&err instanceof Error&&err.message||"Couldn't load denied IPs."},null)})]),rates,timeseries;if(metrics){let previousMs=anomalyStart-chartStart,anomalyMs=anomalyEnd-anomalyStart,previousTotal=sumInWindow(metrics.series,action,chartStart,anomalyStart),anomalyTotal=sumInWindow(metrics.series,action,anomalyStart,anomalyEnd),previousReqPerMin=reqPerMin(previousTotal,previousMs),anomalyReqPerMin=reqPerMin(anomalyTotal,anomalyMs);rates={previousReqPerMin,anomalyReqPerMin,multiplier:previousReqPerMin>0?anomalyReqPerMin/previousReqPerMin:null};let axis=axisBetween(chartStart,chartEnd,GRANULARITY_MS),series=metrics.series.find(s=>s.action===action);timeseries={action,startMs:chartStart,endMs:chartEnd,pointCount:axis.length,granularityMinutes:GRANULARITY_MINUTES,values:valuesOnAxis(series,axis)}}let hosts=events?.hosts&&events.hosts.length>0?events.hosts:resolved.hosts,ips=events?.ips;if(asJson)return outputJson(client,{alert,status:alert.resolvedAt?"resolved":"active",previous24h:rates?{reqPerMin:rates.previousReqPerMin}:null,anomaly:rates?{reqPerMin:rates.anomalyReqPerMin,multiplier:rates.multiplier}:null,timeseries:timeseries?{action:timeseries.action,startTime:new Date(timeseries.startMs).toISOString(),endTime:new Date(timeseries.endMs).toISOString(),granularity:{minutes:timeseries.granularityMinutes},points:timeseries.values.map((value,i)=>({timestamp:new Date(timeseries.startMs+i*GRANULARITY_MS).toISOString(),value}))}:null,deniedIps:ips?.map(row=>({ip:row.name,count:row.count}))??null,topHosts:hosts?.map(row=>({host:row.name,count:row.count}))??null,...metrics?{}:{activityUnavailable:{reason:"plan",message:FIREWALL_ACTIVITY_PLAN_MESSAGE}},...eventsIssue?{eventsUnavailable:eventsIssue}:{}}),0;if(output_manager_default.print(`
|
|
170
|
+
${formatAlertInspect({alert,rates,timeseries,ips,hosts})}`),!metrics)output_manager_default.print(` ${FIREWALL_ACTIVITY_PLAN_MESSAGE}
|
|
171
|
+
`);else if(eventsIssue?.reason==="plan")output_manager_default.print(` ${FIREWALL_ACTIVITY_PLAN_MESSAGE}
|
|
172
|
+
`);else if(eventsIssue){let haveHosts=!!(hosts&&hosts.length>0);output_manager_default.print(` Couldn't load denied IPs${haveHosts?"":" and hosts"}.
|
|
173
|
+
`)}return output_manager_default.print(`
|
|
174
|
+
`),0}catch(e){return isActivityUnavailable2(e)?failFirewallObservabilityPlan(client,e,project.name):failFirewallApi(client,e,{fallback:"Failed to fetch firewall alert",nextCommand:suggestedCommand,permissionAction:"read firewall alerts",projectName:project.name,timeoutJob:"firewall alert"})}}var COMMAND_CONFIG6={list:getCommandAliases(alertsListSubcommand),inspect:getCommandAliases(alertsInspectSubcommand)};async function main6(client,args,telemetry){let flagsSpecification=getFlagsSpecification(alertsSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(args,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG6),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall","alerts"),output_manager_default.print(help(alertsSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand){case"list":return needHelp?(telemetry.trackCliFlagHelp("firewall",`alerts:${subcommandOriginal}`),printHelp(alertsListSubcommand),0):(telemetry.trackCliSubcommandAlertsList(subcommandOriginal),list4(client,subArgs));case"inspect":return needHelp?(telemetry.trackCliFlagHelp("firewall",`alerts:${subcommandOriginal}`),printHelp(alertsInspectSubcommand),0):(telemetry.trackCliSubcommandAlertsInspect(subcommandOriginal),inspect2(client,subArgs));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG6)),output_manager_default.print(help(alertsSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),2}}var import_chalk37=__toESM(require_source(),1);var import_chalk36=__toESM(require_source(),1);var DEFAULT_PERSISTENT_ACTION_LIMIT=10,DEFAULT_PERSISTENT_ACTION_WINDOW_MS=60*60*1e3;function persistentActionWindow(since,until){let to=until??new Date;return{from:since??new Date(to.getTime()-DEFAULT_PERSISTENT_ACTION_WINDOW_MS),to}}function formatPersistentActionWindowLabel(from,to){let hours=(to.getTime()-from.getTime())/36e5,untilIsNow=Date.now()-to.getTime()<6e4;return untilIsNow&&hours>.9&&hours<1.1?"past 1h, UTC":untilIsNow&&Number.isInteger(hours)&&hours>=1&&hours<=48?`past ${hours}h, UTC`:`${formatUtcTime(from.getTime(),!0)} \u2013 ${formatUtcTime(to.getTime(),!0)} UTC`}function actionMs(value){return apiTimestampMs(value)}function formatEnd(action){return action.isActive?import_chalk36.default.blue("Ongoing"):`${formatUtcTime(actionMs(action.endTime),!0)} UTC`}function colorAction(action){return(ACTION_COLORS[action]??(s=>s))(labelForAction(action))}function pluralize(count,singular){return count===1?singular:`${singular}s`}function formatNamedCounts2(rows){let nameWidth=Math.max(...rows.map(r=>r.name.length),0),countWidth=Math.max(...rows.map(r=>formatCount(r.count).length),0);return rows.map(row=>` ${row.name.padEnd(nameWidth)} ${formatCount(row.count).padStart(countWidth)}`).join(`
|
|
175
|
+
`)}function formatPersistentActionsList(opts){let lines=[` ${import_chalk36.default.bold("Persistent actions")} (${formatPersistentActionWindowLabel(opts.from,opts.to)})`],summary=opts.summary;if(summary){let parts=[summary.challengingIps>0?`Challenging ${summary.challengingIps} ${pluralize(summary.challengingIps,"IP")}`:null,summary.blockingIps>0?`Blocking ${summary.blockingIps} ${pluralize(summary.blockingIps,"IP")}`:null,summary.otherActions>0?`${summary.otherActions} other ${pluralize(summary.otherActions,"action")}`:null,summary.withheldActions>0?`${summary.withheldActions} on hidden ${pluralize(summary.withheldActions,"IP")}`:null].filter(part=>!!part);lines.push(` ${parts.join(" \xB7 ")} ${import_chalk36.default.dim(`\xB7 ${summary.activeTotal} currently applied`)}`)}if(lines.push(""),opts.actions.length===0)return lines.push(import_chalk36.default.dim(" No persistent actions in this window.")),lines.push(""),lines.join(`
|
|
176
|
+
`);let rows=[["Type","Action","Hostname","IP Address","Start","End","Requests"].map(h=>import_chalk36.default.bold(import_chalk36.default.cyan(h)))];for(let action of opts.actions)rows.push([ruleTypeLabel(action.action_type),colorAction(action.action),action.host,action.public_ip,`${formatUtcTime(actionMs(action.startTime),!0)} UTC`,formatEnd(action),formatCount(action.count)]);let rendered=table(rows,{align:["l","l","l","l","l","l","r"],hsep:3});for(let line2 of rendered.split(`
|
|
177
|
+
`))lines.push(` ${line2}`.trimEnd());return opts.actions.some(action=>isRedacted(action.public_ip)||isRedacted(action.host)||isRedacted(action.action_type))&&(lines.push(""),lines.push(import_chalk36.default.dim(" *** marks detail this plan withholds for actions older than an hour."))),opts.actions.length<opts.total&&(lines.push(""),lines.push(` Showing ${opts.actions.length} of ${opts.total}. Raise --limit, or narrow with --since and --until.`)),lines.push(""),lines.join(`
|
|
178
|
+
`)}function formatPersistentActionInspect(opts){let{action}=opts,lines=[` ${import_chalk36.default.bold("Persistent action")}`,"",formatAlignedLabel("Start",`${formatUtcTime(actionMs(action.startTime),!0)} UTC`),formatAlignedLabel("End",formatEnd(action)),formatAlignedLabel("Action",colorAction(action.action)),formatAlignedLabel("Type",ruleTypeLabel(action.action_type)),formatAlignedLabel("Hostname",action.host),formatAlignedLabel("IP",action.public_ip),formatAlignedLabel("Requests",formatCount(action.count))];return opts.matchCount>1&&(lines.push(""),lines.push(` Showing the most recent of ${opts.matchCount} matching persistent actions. Pass --host, --action, --since, and --until to pick one.`)),opts.series&&(lines.push(""),lines.push(` ${import_chalk36.default.bold("Requests by Action")}`),lines.push(formatActionTrendTable(opts.series))),opts.pathsAvailable&&(lines.push(""),lines.push(import_chalk36.default.dim(" Pass --paths for the paths this client requested."))),opts.paths&&opts.paths.length>0&&(lines.push(""),lines.push(` ${import_chalk36.default.bold("Top Request Paths")}`),lines.push(formatNamedCounts2(opts.paths))),lines.push(""),lines.join(`
|
|
179
|
+
`)}async function list5(client,argv){let startedAt=Date.now(),parsed=await parseSubcommandArgs(argv,persistentActionsListSubcommand,client,"persistent-actions list");if(typeof parsed=="number")return parsed;let sinceResult=validateTimeBound(parsed.flags["--since"]);if(!sinceResult.valid)return failFirewall(client,{message:sinceResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let untilResult=validateTimeBound(parsed.flags["--until"]);if(!untilResult.valid)return failFirewall(client,{message:untilResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let order=validateTimeOrder(sinceResult.value,untilResult.value);if(!order.valid)return failFirewall(client,{message:order.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let limitResult=validateIntegerRangeWithDefault(parsed.flags["--limit"],{flag:"--limit",min:1,max:1e4,defaultValue:DEFAULT_PERSISTENT_ACTION_LIMIT});if(!limitResult.valid)return failFirewall(client,{message:limitResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let requested=persistentActionWindow(sinceResult.value,untilResult.value),link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;if(!teamId)return failFirewall(client,{message:"Firewall persistent actions need a team. Run `vercel switch` to select a team or pass --scope <team>.",reason:AGENT_REASON.MISSING_SCOPE});let asJson=!!parsed.flags["--json"],suggestedCommand=`firewall persistent-actions list${asJson?" --json":""}`,{isEnterprise,known}=await fetchPlanInfo(client),window=clampPersistentActionWindow({...requested,isEnterprise,planKnown:known,now:startedAt}),{from,to}=window;if(window.empty)return failFirewall(client,{message:`This plan keeps ${retentionLabel(isEnterprise)} of persistent-action history, and the requested window is entirely older than that. Narrow it with --since and --until.`,reason:AGENT_REASON.INVALID_ARGUMENTS});window.requestedFrom&&!asJson&&output_manager_default.warn(`This plan keeps ${retentionLabel(isEnterprise)} of persistent-action history. Showing from ${from.toISOString()} rather than ${window.requestedFrom.toISOString()}.`),output_manager_default.spinner(`Fetching persistent actions for ${import_chalk37.default.bold(project.name)}`);try{let actions=await fetchFirewallPersistentActions(client,{projectId:project.id,teamId,startTime:from,endTime:to}),shown=actions.slice(0,limitResult.value),summary=summarizePersistentActions(actions);return asJson?(outputJson(client,{window:{startTime:from.toISOString(),endTime:to.toISOString(),...window.requestedFrom?{requestedStartTime:window.requestedFrom.toISOString(),trimmedToPlanRetention:!0}:{}},actions:shown.map(toPersistentAction),shown:shown.length,total:actions.length,summary}),0):(output_manager_default.print(`
|
|
180
|
+
${formatPersistentActionsList({actions:shown,total:actions.length,summary,from,to})}
|
|
181
|
+
`),0)}catch(e){return isAPIError(e)&&e.status===402?failFirewallObservabilityPlan(client,e,project.name):failFirewallApi(client,e,{fallback:"Failed to fetch persistent firewall actions",nextCommand:suggestedCommand,permissionAction:"read firewall persistent actions",projectName:project.name,timeoutJob:"firewall persistent actions"})}}var import_chalk38=__toESM(require_source(),1);import{isIP as isIP3}from"node:net";var TOP_PATHS=8,MIN_TRAFFIC_WINDOW_MS=6e4;function isActivityUnavailable3(error){return isAPIError(error)&&error.status===402}function inspectGranularity(from,to){let hours=(to.getTime()-from.getTime())/36e5;return hours<=3?{minutes:1}:hours<=24?{minutes:5}:{hours:1}}function matchesInspectFilters(action,opts){return!(action.public_ip!==opts.ip||opts.host&&action.host!==opts.host||opts.action&&action.action!==opts.action)}async function inspect3(client,argv){let startedAt=Date.now(),parsed=await parseSubcommandArgs(argv,persistentActionsInspectSubcommand,client,"persistent-actions inspect");if(typeof parsed=="number")return parsed;let ip=parsed.args[0];if(!ip)return failFirewall(client,{message:`IP is required. Usage: ${withGlobalFlags(client,"firewall persistent-actions inspect <ip>")}`,nextCommand:"firewall persistent-actions inspect <ip>",reason:AGENT_REASON.MISSING_ARGUMENTS});if(!isIP3(ip))return failFirewall(client,{message:"Please enter a valid IP address.",reason:AGENT_REASON.INVALID_ARGUMENTS});let sinceResult=validateTimeBound(parsed.flags["--since"]);if(!sinceResult.valid)return failFirewall(client,{message:sinceResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let untilResult=validateTimeBound(parsed.flags["--until"]);if(!untilResult.valid)return failFirewall(client,{message:untilResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let order=validateTimeOrder(sinceResult.value,untilResult.value);if(!order.valid)return failFirewall(client,{message:order.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let requested=persistentActionWindow(sinceResult.value,untilResult.value),host=parsed.flags["--host"],actionFilter=parsed.flags["--action"],link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;if(!teamId)return failFirewall(client,{message:"Firewall persistent actions need a team. Run `vercel switch` to select a team or pass --scope <team>.",reason:AGENT_REASON.MISSING_SCOPE});let asJson=!!parsed.flags["--json"],suggestedCommand=`firewall persistent-actions inspect ${ip}${asJson?" --json":""}`,{isEnterprise,known}=await fetchPlanInfo(client),window=clampPersistentActionWindow({...requested,isEnterprise,planKnown:known,now:startedAt}),{from,to}=window;if(window.empty)return failFirewall(client,{message:`This plan keeps ${retentionLabel(isEnterprise)} of persistent-action history, and the requested window is entirely older than that. Narrow it with --since and --until.`,reason:AGENT_REASON.INVALID_ARGUMENTS});output_manager_default.spinner(`Fetching persistent action ${import_chalk38.default.bold(ip)}`);try{let matches=(await fetchFirewallPersistentActions(client,{projectId:project.id,teamId,startTime:from,endTime:to,host})).filter(action=>matchesInspectFilters(action,{ip,host,action:actionFilter})),selected=matches[0];if(!selected)return failFirewall(client,{message:`No persistent action found for "${ip}". Run ${withGlobalFlags(client,"firewall persistent-actions list")} to view recent actions.`,nextCommand:"firewall persistent-actions list",reason:AGENT_REASON.NOT_FOUND});output_manager_default.spinner(`Fetching traffic for ${import_chalk38.default.bold(ip)}`);let requestedStart=new Date(apiTimestampMs(selected.startTime)),requestedEnd=new Date(Math.max(Math.min(apiTimestampMs(selected.endTime),Date.now()),requestedStart.getTime()+MIN_TRAFFIC_WINDOW_MS)),wantPaths=!!parsed.flags["--paths"],filter=persistentActionFilter({ip:selected.public_ip,host:selected.host}),pathsFilter=persistentActionFilter({ip:selected.public_ip,host:selected.host,withPath:!0}),scopable=!isRedacted(selected.public_ip),granularity=inspectGranularity(requestedStart,requestedEnd),{startTime:actionStart,endTime:actionEnd}=alignQueryWindow(requestedStart,requestedEnd,granularity),[metrics,paths]=await Promise.all([scopable?getFirewallMetrics(client,{projectId:project.id,ownerId:teamId,startTime:actionStart,endTime:actionEnd,granularity,filter}).catch(err=>{if(isActivityUnavailable3(err))return null;throw err}):Promise.resolve(null),wantPaths&&scopable?getTopList(client,{projectId:project.id,ownerId:teamId,startTime:actionStart,endTime:actionEnd,groupBy:[PATH_DIMENSION],filter:pathsFilter,top:TOP_PATHS}).catch(err=>{if(isActivityUnavailable3(err))return null;throw err}):Promise.resolve(null)]),pathRows=paths?.map(row=>({name:row.values[PATH_DIMENSION]||"/",count:row.total}));return asJson?(outputJson(client,{action:toPersistentAction(selected),matchCount:matches.length,series:metrics?.series??null,...wantPaths?{paths:pathRows??null}:{},...metrics?{}:{activityUnavailable:{reason:"plan",message:FIREWALL_ACTIVITY_PLAN_MESSAGE}}}),0):(output_manager_default.print(`
|
|
182
|
+
${formatPersistentActionInspect({action:selected,matchCount:matches.length,series:metrics?.series,paths:pathRows,pathsAvailable:!wantPaths})}`),metrics||output_manager_default.print(` ${FIREWALL_ACTIVITY_PLAN_MESSAGE}
|
|
183
|
+
`),output_manager_default.print(`
|
|
184
|
+
`),0)}catch(e){return isActivityUnavailable3(e)?failFirewallObservabilityPlan(client,e,project.name):failFirewallApi(client,e,{fallback:"Failed to fetch persistent firewall action",nextCommand:suggestedCommand,permissionAction:"read firewall persistent actions",projectName:project.name,timeoutJob:"firewall persistent action"})}}var COMMAND_CONFIG7={list:getCommandAliases(persistentActionsListSubcommand),inspect:getCommandAliases(persistentActionsInspectSubcommand)};async function main7(client,args,telemetry){let flagsSpecification=getFlagsSpecification(persistentActionsSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(args,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG7),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall","persistent-actions"),output_manager_default.print(help(persistentActionsSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand){case"list":return needHelp?(telemetry.trackCliFlagHelp("firewall",`persistent-actions:${subcommandOriginal}`),printHelp(persistentActionsListSubcommand),0):(telemetry.trackCliSubcommandPersistentActionsList(subcommandOriginal),list5(client,subArgs));case"inspect":return needHelp?(telemetry.trackCliFlagHelp("firewall",`persistent-actions:${subcommandOriginal}`),printHelp(persistentActionsInspectSubcommand),0):(telemetry.trackCliSubcommandPersistentActionsInspect(subcommandOriginal),inspect3(client,subArgs));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG7)),output_manager_default.print(help(persistentActionsSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),2}}var import_chalk39=__toESM(require_source(),1);var DEFAULT_TRAFFIC_WINDOW_MS=24*60*60*1e3;function requireTrafficTeam(client,org,what){return org.type==="team"?org.id:failFirewall(client,{message:`${what} needs a team. Run \`vercel switch\` to select a team or pass --scope <team>.`,reason:AGENT_REASON.MISSING_SCOPE})}function resolveTrafficWindow(since,until,scope){let sinceResult=validateTimeBound(since);if(!sinceResult.valid)return{valid:!1,message:sinceResult.message};let untilResult=validateTimeBound(until);if(!untilResult.valid)return{valid:!1,message:untilResult.message};let order=validateTimeOrder(sinceResult.value,untilResult.value);if(!order.valid)return{valid:!1,message:order.message};if(!sinceResult.value&&!untilResult.value&&scope)return{valid:!0,startTime:scope.startTime,endTime:scope.endTime};let endTime=untilResult.value??new Date,startTime=sinceResult.value??scope?.startTime??new Date(endTime.getTime()-DEFAULT_TRAFFIC_WINDOW_MS);return startTime.getTime()>endTime.getTime()?{valid:!1,message:sinceResult.value?"`--since` is in the future. Pass a past time, such as `24h` or an earlier date.":"The alert began after `--until`. Widen the window with `--since`, or drop `--until`."}:{valid:!0,startTime,endTime}}function buildTrafficFilter(flags){let parts=[];for(let dimension of TRAFFIC_DIMENSIONS){let value=flags[`--${dimension.alias}`];typeof value=="string"&&value.length>0&&parts.push(eqFilter(dimension.field,value))}let raw=flags["--filter"],rawExpressions=[];if(Array.isArray(raw))for(let expression of raw)typeof expression=="string"&&expression.length>0&&(rawExpressions.push(expression),parts.push(expression));return usesODataSyntax(rawExpressions)&&output_manager_default.warn(FILTER_DEPRECATION_WARNING),andFilters(...parts)}function unknownDimensionMessage(flag,value){return`Unknown ${flag} "${value}". Dimensions: ${dimensionAliases().join(", ")}.`}var WAF_ONLY_ALIASES=new Set(["action","rule"]);function hasStringFlag(flags,flag){let value=flags[flag];return typeof value=="string"&&value.length>0}function requestCountFilterFlags(flags){return TRAFFIC_DIMENSIONS.filter(d=>d.metric&&hasStringFlag(flags,`--${d.alias}`)).map(d=>`--${d.alias}`)}function mixedTrafficMetricError(opts){let requestFilters=requestCountFilterFlags(opts.flags),queryingRequestCount=!!opts.dimension?.metric;if(!queryingRequestCount&&requestFilters.length>0)return`Can't combine ${requestFilters.join(", ")} with firewall-action data. Inspect unknown-bot <category> instead.`;if(!queryingRequestCount||!opts.dimension)return;let unsupported=[];if(hasStringFlag(opts.flags,"--action")&&unsupported.push("--action"),hasStringFlag(opts.flags,"--rule")&&unsupported.push("--rule"),opts.groupBy&&WAF_ONLY_ALIASES.has(opts.groupBy.alias)&&unsupported.push(`--group-by ${opts.groupBy.alias}`),unsupported.length!==0)return`${opts.dimension.label} uses request-count data and cannot be combined with ${unsupported.join(", ")}. Use a request dimension such as path, ip, host, country, asn, ja4, or user-agent instead.`}var TOP_LIMITS={min:1,max:100};function trendBuckets(client){let columns=client.stderr.columns||80;return Math.max(12,Math.min(96,columns-56))}async function runWithConcurrency(tasks,limit){let results=new Array(tasks.length),next=0,workers=Array.from({length:Math.min(limit,tasks.length)},async()=>{for(;next<tasks.length;){let index=next++;results[index]=await tasks[index]()}});return await Promise.all(workers),results}var AlertNotFoundError=class extends Error{constructor(alertId){super(`No firewall alert found for "${alertId}". Run \`vercel firewall alerts list\` to view recent alerts.`),this.name="AlertNotFoundError"}};async function resolveAlertScope(client,opts){let resolved=await findFirewallAlert(client,opts);if(!resolved)throw new AlertNotFoundError(opts.alertId);let{alert}=resolved;return{alert,startTime:new Date(alert.startedAt),endTime:new Date(alert.resolvedAt??Date.now()),filter:alert.ruleId?eqFilter(RULE_ID_DIMENSION,alert.ruleId):void 0}}var DEFAULT_TOP=5,DEFAULT_DIMENSIONS=["ip","ja4","asn","user-agent","path","rule","host","bot"],LIST_CONCURRENCY=8;function isActivityUnavailable4(error){return isAPIError(error)&&error.status===402}async function list6(client,argv){let parsed=await parseSubcommandArgs(argv,trafficListSubcommand,client,"traffic list");if(typeof parsed=="number")return parsed;let topResult=validateIntegerRangeWithDefault(parsed.flags["--top"],{flag:"--top",...TOP_LIMITS,defaultValue:DEFAULT_TOP});if(!topResult.valid)return failFirewall(client,{message:topResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let top=topResult.value,requested=normalizeRepeatableStringFilters(parsed.flags["--dimension"]),dimensions=[];for(let alias of requested.length>0?requested:DEFAULT_DIMENSIONS){let dimension=getDimension(alias);if(!dimension)return failFirewall(client,{message:unknownDimensionMessage("--dimension",alias),reason:AGENT_REASON.INVALID_ARGUMENTS});dimensions.includes(dimension)||dimensions.push(dimension)}let mixedMetricError=mixedTrafficMetricError({flags:parsed.flags});if(mixedMetricError)return failFirewall(client,{message:mixedMetricError,nextCommand:"firewall traffic inspect unknown-bot <category>",reason:AGENT_REASON.INVALID_ARGUMENTS});let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=requireTrafficTeam(client,org,"Firewall traffic");if(typeof teamId=="number")return teamId;let asJson=!!parsed.flags["--json"],suggestedCommand=`firewall traffic list${asJson?" --json":""}`,alertScope,alertId=parsed.flags["--alert"];if(alertId){output_manager_default.spinner(`Fetching alert ${import_chalk39.default.bold(alertId)}`);try{alertScope=await resolveAlertScope(client,{alertId,projectId:project.id,teamId})}catch(e){return e instanceof AlertNotFoundError?failFirewall(client,{message:e.message,nextCommand:"firewall alerts list",reason:AGENT_REASON.NOT_FOUND}):failFirewallApi(client,e,{fallback:"Failed to fetch firewall alert",nextCommand:suggestedCommand,permissionAction:"read firewall alerts",projectName:project.name,timeoutJob:"firewall alert"})}}let window=resolveTrafficWindow(parsed.flags["--since"],parsed.flags["--until"],alertScope);if(!window.valid)return failFirewall(client,{message:window.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let filter=andFilters(alertScope?.filter,buildTrafficFilter(parsed.flags)),filtered=!!filter;output_manager_default.spinner(`Fetching firewall traffic for ${import_chalk39.default.bold(project.name)}`);let granularity=pickGranularity(window.endTime.getTime()-window.startTime.getTime(),asJson?DEFAULT_MAX_BUCKETS:trendBuckets(client)),{startTime,endTime}=alignQueryWindow(window.startTime,window.endTime,granularity),activeConfig=dimensions.some(d=>d.alias==="rule")?listFirewallConfigs(client,projectScope(project,teamId)).then(configs=>configs.active).catch(()=>null):Promise.resolve(null);try{let[metrics,topLists,config]=await Promise.all([getFirewallMetrics(client,{projectId:project.id,ownerId:teamId,startTime,endTime,granularity,filter}),runWithConcurrency(dimensions.map(dimension=>async()=>{let title=dimension.widgetTitle;try{let groupBy=dimension.groupBy??[dimension.field],rows=await getTopList(client,{projectId:project.id,ownerId:teamId,startTime,endTime,metric:dimension.metric,groupBy,filter:andFilters(filter,dimension.excludeFilter,dimension.extraFilter),top:topListFetchCount(top,groupBy)});return{dimension:dimension.alias,title,rows:toTopListRows(rows,dimension.field,dimension.labelFields).slice(0,top)}}catch(e){return{dimension:dimension.alias,title,rows:[],unavailable:isActivityUnavailable4(e)?"plan":isUnsupportedDimension(e)?"filter":isRateLimited(e)?"rate-limit":isActivityTimeout(e)?"timeout":"error",retrySeconds:rateLimitRetrySeconds(e),message:isRateLimited(e)?apiServerMessage(e):void 0}}}),LIST_CONCURRENCY),activeConfig]);for(let list7 of topLists)list7.dimension==="rule"&&(list7.rows=list7.rows.map(row=>({...row,label:resolveRuleDisplayName(row.value,config)})));let allFailed=allTopListsUnavailable(topLists);return asJson?(outputJson(client,{period:{start:metrics.startTime,end:metrics.endTime,granularity:metrics.granularity},filter:filter??null,...alertScope?{alert:{id:alertScope.alert.id,title:alertScope.alert.title,startedAt:alertScope.alert.startedAt,resolvedAt:alertScope.alert.resolvedAt??null}}:{},stats:metrics.totals,series:metrics.series.map(({action,timeseries})=>({action,timeseries})),topLists:topLists.map(list7=>({dimension:list7.dimension,rows:list7.rows,...list7.unavailable?{unavailable:list7.unavailable}:{},...list7.retrySeconds?{retrySeconds:list7.retrySeconds}:{}}))}),allFailed?1:0):(output_manager_default.print(`
|
|
185
|
+
`),output_manager_default.print(formatTrafficList({series:metrics.series,topLists,startTime:metrics.startTime,endTime:metrics.endTime,granularity:metrics.granularity,filtered})),allFailed||output_manager_default.print(`
|
|
186
|
+
${import_chalk39.default.dim(" Break any of these values down further:")}
|
|
187
|
+
${withGlobalFlags(client,"firewall traffic inspect <dimension> <value>")}
|
|
188
|
+
|
|
189
|
+
`),allFailed?1:0)}catch(e){return isActivityUnavailable4(e)?failFirewallObservabilityPlan(client,e,project.name):failFirewallApi(client,e,{fallback:"Failed to fetch firewall traffic",nextCommand:suggestedCommand,permissionAction:"query firewall traffic",projectName:project.name,timeoutJob:"firewall traffic"})}}var import_chalk40=__toESM(require_source(),1);var DEFAULT_TOP2=10;function isActivityUnavailable5(error){return isAPIError(error)&&error.status===402}async function inspect4(client,argv){let parsed=await parseSubcommandArgs(argv,trafficInspectSubcommand,client,"traffic inspect");if(typeof parsed=="number")return parsed;let usage="firewall traffic inspect <dimension> <value>",[dimensionArg,value]=parsed.args;if(!dimensionArg||!value)return failFirewall(client,{message:`Dimension and value are required. Usage: ${withGlobalFlags(client,usage)}. Dimensions: ${dimensionAliases().join(", ")}.`,nextCommand:usage,reason:AGENT_REASON.MISSING_ARGUMENTS});let dimension=getDimension(dimensionArg);if(!dimension)return failFirewall(client,{message:unknownDimensionMessage("dimension",dimensionArg),reason:AGENT_REASON.INVALID_ARGUMENTS});let groupByArg=parsed.flags["--group-by"]??dimension.defaultGroupBy,groupBy=getDimension(groupByArg);if(!groupBy)return failFirewall(client,{message:unknownDimensionMessage("--group-by",groupByArg),reason:AGENT_REASON.INVALID_ARGUMENTS});if(groupBy.alias===dimension.alias)return failFirewall(client,{message:`\`--group-by\` must name a different dimension from "${dimension.alias}".`,reason:AGENT_REASON.INVALID_ARGUMENTS});let requestMetricError=mixedTrafficMetricError({dimension,groupBy,flags:parsed.flags});if(requestMetricError)return failFirewall(client,{message:requestMetricError,reason:AGENT_REASON.INVALID_ARGUMENTS});let topResult=validateIntegerRangeWithDefault(parsed.flags["--top"],{flag:"--top",...TOP_LIMITS,defaultValue:DEFAULT_TOP2});if(!topResult.valid)return failFirewall(client,{message:topResult.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let top=topResult.value,link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=requireTrafficTeam(client,org,"Firewall traffic");if(typeof teamId=="number")return teamId;let asJson=!!parsed.flags["--json"],suggestedCommand=`firewall traffic inspect ${dimension.alias} ${value}${asJson?" --json":""}`,alertScope,alertId=parsed.flags["--alert"];if(alertId){output_manager_default.spinner(`Fetching alert ${import_chalk40.default.bold(alertId)}`);try{alertScope=await resolveAlertScope(client,{alertId,projectId:project.id,teamId})}catch(e){return e instanceof AlertNotFoundError?failFirewall(client,{message:e.message,nextCommand:"firewall alerts list",reason:AGENT_REASON.NOT_FOUND}):failFirewallApi(client,e,{fallback:"Failed to fetch firewall alert",nextCommand:suggestedCommand,permissionAction:"read firewall alerts",projectName:project.name,timeoutJob:"firewall alert"})}if(dimension.metric&&alertScope.filter)return failFirewall(client,{message:`${dimension.label} uses request-count data and cannot be scoped to a firewall alert with an attributed rule. Drop --alert, or inspect a firewall-action dimension instead.`,reason:AGENT_REASON.INVALID_ARGUMENTS})}let window=resolveTrafficWindow(parsed.flags["--since"],parsed.flags["--until"],alertScope);if(!window.valid)return failFirewall(client,{message:window.message,reason:AGENT_REASON.INVALID_ARGUMENTS});let filter=andFilters(alertScope?.filter,eqFilter(dimension.field,value),buildTrafficFilter(parsed.flags),dimension.extraFilter),granularity=pickGranularity(window.endTime.getTime()-window.startTime.getTime(),asJson?DEFAULT_MAX_BUCKETS:trendBuckets(client)),{startTime,endTime}=alignQueryWindow(window.startTime,window.endTime,granularity);output_manager_default.spinner(`Fetching traffic for ${import_chalk40.default.bold(value)}`);try{let[detailRows,metrics,breakdown]=await Promise.all([dimension.headerDetailFields?.length?getTopList(client,{projectId:project.id,ownerId:teamId,startTime,endTime,metric:dimension.metric,groupBy:dimension.headerDetailFields,filter,top:1}).catch(()=>[]):Promise.resolve([]),dimension.metric?requestCountMetrics(client,{projectId:project.id,ownerId:teamId,startTime,endTime,granularity,filter,metric:dimension.metric}):getFirewallMetrics(client,{projectId:project.id,ownerId:teamId,startTime,endTime,granularity,filter}),getGroupedTimeseries(client,{projectId:project.id,ownerId:teamId,startTime,endTime,granularity,metric:dimension.metric,groupBy:[groupBy.field],filter,limit:top,approximateSelection:!0})]),detail=(dimension.headerDetailFields??[]).map(field=>({field,value:detailRows[0]?.values[field]??""})),total=Object.values(metrics.totals).reduce((sum,count)=>sum+count,0);return total===0?failFirewall(client,{message:`No firewall traffic for ${dimension.label} "${value}" in this window. Run ${withGlobalFlags(client,"firewall traffic list")} to see which values have traffic, or widen the window with \`--since\`.`,nextCommand:"firewall traffic list",reason:AGENT_REASON.NOT_FOUND}):asJson?(outputJson(client,{dimension:dimension.alias,value,period:{start:metrics.startTime,end:metrics.endTime,granularity:metrics.granularity},filter:filter??null,...alertScope?{alert:{id:alertScope.alert.id,title:alertScope.alert.title,startedAt:alertScope.alert.startedAt,resolvedAt:alertScope.alert.resolvedAt??null}}:{},detail:Object.fromEntries(detail.map(row=>[row.field,row.value])),total,stats:metrics.totals,series:metrics.series.map(({action,timeseries})=>({action,timeseries})),breakdown:{groupBy:groupBy.alias,axis:breakdown.axis,groups:breakdown.groups.map(group=>({value:group.values[groupBy.field],total:group.total,series:group.series}))}}),0):(output_manager_default.print(`
|
|
190
|
+
`),output_manager_default.print(formatTrafficInspect({value,dimensionLabel:dimension.label,detail,total,series:metrics.series,startTime:metrics.startTime,endTime:metrics.endTime,granularity:metrics.granularity,breakdown,breakdownField:groupBy.field,breakdownLabel:groupBy.label,top,filtered:!0})),output_manager_default.print(`
|
|
191
|
+
${nextSteps(client,dimension.alias)}
|
|
192
|
+
`),0)}catch(e){return isActivityUnavailable5(e)?failFirewallObservabilityPlan(client,e,project.name):failFirewallApi(client,e,{fallback:"Failed to fetch firewall traffic",nextCommand:suggestedCommand,permissionAction:"query firewall traffic",projectName:project.name,timeoutJob:"firewall traffic"})}}async function requestCountMetrics(client,opts){let result=await getGroupedTimeseries(client,opts),group=result.groups[0],total=group?.total??0,timeseries=result.axis.map((timestamp,i)=>({timestamp,value:group?.series[i]??0}));return{startTime:result.startTime,endTime:result.endTime,granularity:result.granularity,series:total>0?[{action:"requests",total,timeseries}]:[],totals:total>0?{requests:total}:{}}}function nextSteps(client,alias){let steps=[];if(alias==="ip"?steps.push(["Block this client on every host","firewall ip-blocks block <ip>"]):alias==="rule"&&steps.push(["Change what this rule does","firewall rules update <rule>"]),steps.push(["Break the same traffic down another way",`firewall traffic inspect ${alias} <value> --group-by <dimension>`]),steps.length===1){let[why,command]=steps[0];return`${import_chalk40.default.dim(` ${why}:`)}
|
|
193
|
+
${withGlobalFlags(client,command)}
|
|
194
|
+
`}return[` ${import_chalk40.default.bold("Next steps:")}`,...steps.flatMap(([why,command])=>[import_chalk40.default.dim(` ${why}`),` ${withGlobalFlags(client,command)}`]),""].join(`
|
|
195
|
+
`)}var COMMAND_CONFIG8={list:getCommandAliases(trafficListSubcommand),inspect:getCommandAliases(trafficInspectSubcommand)};async function main8(client,args,telemetry){let flagsSpecification=getFlagsSpecification(trafficSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(args,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG8),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall","traffic"),output_manager_default.print(help(trafficSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand){case"list":return needHelp?(telemetry.trackCliFlagHelp("firewall",`traffic:${subcommandOriginal}`),printHelp(trafficListSubcommand),0):(telemetry.trackCliSubcommandTrafficList(subcommandOriginal),list6(client,subArgs));case"inspect":return needHelp?(telemetry.trackCliFlagHelp("firewall",`traffic:${subcommandOriginal}`),printHelp(trafficInspectSubcommand),0):(telemetry.trackCliSubcommandTrafficInspect(subcommandOriginal),inspect4(client,subArgs));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG8)),output_manager_default.print(help(trafficSubcommand,{parent:firewallCommand,columns:client.stderr.columns})),2}}var import_chalk41=__toESM(require_source(),1);var UNKNOWN_BOT_TOP=5;function isActivityUnavailable6(error){return isAPIError(error)&&error.status===402}async function botManagement(client,argv){let parsed=await parseSubcommandArgs(argv,botManagementSubcommand,client,"bot-management");if(typeof parsed=="number")return parsed;let link=await requireProjectContext(client,"firewall",parsed.flags["--project"]);if(typeof link=="number")return link;let{project,org}=link,teamId=org.type==="team"?org.id:void 0;output_manager_default.spinner(`Fetching bot management for ${import_chalk41.default.bold(project.name)}`);try{let[{active,draft},unknownBotTraffic]=await Promise.all([listFirewallConfigs(client,projectScope(project,teamId)),teamId?loadUnknownBotTraffic(client,project.id,teamId):Promise.resolve(void 0)]),managed=getManagedBotRules(draft??active);if(parsed.flags["--json"])return outputJson(client,{managed:managed.map(managedBotJson),...unknownBotTraffic?{unknownBotTraffic:{rows:unknownBotTraffic.rows,...unknownBotTraffic.unavailable?{unavailable:unknownBotTraffic.unavailable}:{},...unknownBotTraffic.retrySeconds?{retrySeconds:unknownBotTraffic.retrySeconds}:{}}}:{}}),0;output_manager_default.print(`
|
|
196
|
+
${formatManagedBotRulesTable(managed)}
|
|
197
|
+
`),unknownBotTraffic&&output_manager_default.print(`
|
|
198
|
+
${formatTrafficTopList(unknownBotTraffic)}
|
|
199
|
+
`);let steps=managed.map(rule=>{let action=suggestedManagedBotAction(rule);return[`Change ${rule.name}`,`firewall rules update ${rule.id} --action ${action}`]});return unknownBotTraffic&&!unknownBotTraffic.unavailable&&steps.push(["Break unknown bot traffic down further","firewall traffic inspect unknown-bot <category>"]),output_manager_default.print(`
|
|
200
|
+
${import_chalk41.default.bold("Next steps:")}
|
|
201
|
+
${steps.flatMap(([why,command])=>[import_chalk41.default.dim(` ${why}`),` ${withGlobalFlags(client,command)}`]).join(`
|
|
202
|
+
`)}
|
|
203
|
+
|
|
204
|
+
`),0}catch(e){return failFirewallApi(client,e,{fallback:"Failed to fetch bot management",nextCommand:"firewall bot-management",permissionAction:"read firewall config",projectName:project.name,timeoutJob:"bot management"})}finally{output_manager_default.stopSpinner()}}async function loadUnknownBotTraffic(client,projectId,teamId){let dimension=getDimension("unknown-bot"),title=dimension?.widgetTitle??"Unknown Bot Traffic",unavailable=error=>({dimension:"unknown-bot",title,rows:[],unavailable:isActivityUnavailable6(error)?"plan":isUnsupportedDimension(error)?"filter":isRateLimited(error)?"rate-limit":isActivityTimeout(error)?"timeout":"error",retrySeconds:rateLimitRetrySeconds(error),message:isRateLimited(error)?apiServerMessage(error):void 0});if(!dimension)return unavailable(new Error("unknown-bot dimension missing"));let endTime=new Date,startTime=new Date(endTime.getTime()-DEFAULT_TRAFFIC_WINDOW_MS);try{let rows=await getTopList(client,{projectId,ownerId:teamId,startTime,endTime,metric:dimension.metric,groupBy:[dimension.field],filter:andFilters(dimension.excludeFilter,dimension.extraFilter),top:topListFetchCount(UNKNOWN_BOT_TOP)});return{dimension:dimension.alias,title,rows:toTopListRows(rows,dimension.field).slice(0,UNKNOWN_BOT_TOP)}}catch(e){return output_manager_default.debug(isAPIError(e)?`Unknown bot traffic query failed: status=${e.status} code=${e.code??"(none)"} message=${e.serverMessage}`:`Unknown bot traffic query failed: ${e instanceof Error?e.message:String(e)}`),unavailable(e)}}var FirewallTelemetryClient=class extends TelemetryClient{trackCliFlagTeamLevel(value){value&&this.trackCliFlag("team-level")}trackCliSubcommandStatus(actual){this.trackCliSubcommand({subcommand:"status",value:actual})}trackCliSubcommandOverview(actual){this.trackCliSubcommand({subcommand:"overview",value:actual})}trackCliSubcommandDiff(actual){this.trackCliSubcommand({subcommand:"diff",value:actual})}trackCliSubcommandPublish(actual){this.trackCliSubcommand({subcommand:"publish",value:actual})}trackCliSubcommandDiscard(actual){this.trackCliSubcommand({subcommand:"discard",value:actual})}trackCliSubcommandRules(actual){this.trackCliSubcommand({subcommand:"rules",value:actual})}trackCliSubcommandRulesList(actual){this.trackCliSubcommand({subcommand:"rules:list",value:actual})}trackCliSubcommandRulesInspect(actual){this.trackCliSubcommand({subcommand:"rules:inspect",value:actual})}trackCliSubcommandRulesAdd(actual){this.trackCliSubcommand({subcommand:"rules:add",value:actual})}trackCliSubcommandRulesUpdate(actual){this.trackCliSubcommand({subcommand:"rules:update",value:actual})}trackCliSubcommandRulesEnable(actual){this.trackCliSubcommand({subcommand:"rules:enable",value:actual})}trackCliSubcommandRulesDisable(actual){this.trackCliSubcommand({subcommand:"rules:disable",value:actual})}trackCliSubcommandRulesRemove(actual){this.trackCliSubcommand({subcommand:"rules:remove",value:actual})}trackCliSubcommandRulesReorder(actual){this.trackCliSubcommand({subcommand:"rules:reorder",value:actual})}trackCliSubcommandRulesMove(actual){this.trackCliSubcommand({subcommand:"rules:move",value:actual})}trackCliSubcommandIpBlocks(actual){this.trackCliSubcommand({subcommand:"ip-blocks",value:actual})}trackCliSubcommandIpBlocksList(actual){this.trackCliSubcommand({subcommand:"ip-blocks:list",value:actual})}trackCliSubcommandIpBlocksBlock(actual){this.trackCliSubcommand({subcommand:"ip-blocks:block",value:actual})}trackCliSubcommandIpBlocksUnblock(actual){this.trackCliSubcommand({subcommand:"ip-blocks:unblock",value:actual})}trackCliSubcommandSystemBypass(actual){this.trackCliSubcommand({subcommand:"system-bypass",value:actual})}trackCliSubcommandSystemBypassList(actual){this.trackCliSubcommand({subcommand:"system-bypass:list",value:actual})}trackCliSubcommandSystemBypassAdd(actual){this.trackCliSubcommand({subcommand:"system-bypass:add",value:actual})}trackCliSubcommandSystemBypassRemove(actual){this.trackCliSubcommand({subcommand:"system-bypass:remove",value:actual})}trackCliSubcommandAttackMode(actual){this.trackCliSubcommand({subcommand:"attack-mode",value:actual})}trackCliSubcommandAttackModeEnable(actual){this.trackCliSubcommand({subcommand:"attack-mode:enable",value:actual})}trackCliSubcommandAttackModeDisable(actual){this.trackCliSubcommand({subcommand:"attack-mode:disable",value:actual})}trackCliSubcommandSystemMitigations(actual){this.trackCliSubcommand({subcommand:"system-mitigations",value:actual})}trackCliSubcommandSystemMitigationsPause(actual){this.trackCliSubcommand({subcommand:"system-mitigations:pause",value:actual})}trackCliSubcommandSystemMitigationsResume(actual){this.trackCliSubcommand({subcommand:"system-mitigations:resume",value:actual})}trackCliSubcommandAlerts(actual){this.trackCliSubcommand({subcommand:"alerts",value:actual})}trackCliSubcommandAlertsList(actual){this.trackCliSubcommand({subcommand:"alerts:list",value:actual})}trackCliSubcommandAlertsInspect(actual){this.trackCliSubcommand({subcommand:"alerts:inspect",value:actual})}trackCliSubcommandPersistentActions(actual){this.trackCliSubcommand({subcommand:"persistent-actions",value:actual})}trackCliSubcommandPersistentActionsList(actual){this.trackCliSubcommand({subcommand:"persistent-actions:list",value:actual})}trackCliSubcommandPersistentActionsInspect(actual){this.trackCliSubcommand({subcommand:"persistent-actions:inspect",value:actual})}trackCliSubcommandTraffic(actual){this.trackCliSubcommand({subcommand:"traffic",value:actual})}trackCliSubcommandTrafficList(actual){this.trackCliSubcommand({subcommand:"traffic:list",value:actual})}trackCliSubcommandTrafficInspect(actual){this.trackCliSubcommand({subcommand:"traffic:inspect",value:actual})}trackCliSubcommandBotManagement(actual){this.trackCliSubcommand({subcommand:"bot-management",value:actual})}};var COMMAND_CONFIG9={overview:getCommandAliases(overviewSubcommand),status:getCommandAliases(statusSubcommand),rules:getCommandAliases(rulesSubcommand),diff:getCommandAliases(diffSubcommand),publish:getCommandAliases(publishSubcommand),discard:getCommandAliases(discardSubcommand),"ip-blocks":getCommandAliases(ipBlocksSubcommand),"system-bypass":getCommandAliases(systemBypassSubcommand),"attack-mode":getCommandAliases(attackModeSubcommand),"system-mitigations":getCommandAliases(systemMitigationsSubcommand),alerts:getCommandAliases(alertsSubcommand),"persistent-actions":getCommandAliases(persistentActionsSubcommand),traffic:getCommandAliases(trafficSubcommand),"bot-management":getCommandAliases(botManagementSubcommand)};async function main9(client){let telemetry=new FirewallTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(firewallCommand.options);try{parsedArgs=parseArguments(client.argv.slice(2),flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let subArgs=parsedArgs.args.slice(1),{subcommand,args,subcommandOriginal}=getSubcommand(subArgs,COMMAND_CONFIG9),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("firewall"),output_manager_default.print(help(firewallCommand,{columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:firewallCommand,columns:client.stderr.columns}))}switch(subcommand&&!needHelp&&(telemetry.trackCliOptionProject(getProjectOptionFromArgs(args)),telemetry.trackCliFlagTeamLevel(args.includes("--team-level"))),subcommand){case"status":return needHelp?(telemetry.trackCliFlagHelp("firewall",subcommandOriginal),printHelp(statusSubcommand),0):(telemetry.trackCliSubcommandStatus(subcommandOriginal),status(client,args));case"overview":return needHelp?(telemetry.trackCliFlagHelp("firewall",subcommandOriginal),printHelp(overviewSubcommand),0):(telemetry.trackCliSubcommandOverview(subcommandOriginal),overview(client,args));case"diff":return needHelp?(telemetry.trackCliFlagHelp("firewall",subcommandOriginal),printHelp(diffSubcommand),0):(telemetry.trackCliSubcommandDiff(subcommandOriginal),diff(client,args));case"publish":return needHelp?(telemetry.trackCliFlagHelp("firewall",subcommandOriginal),printHelp(publishSubcommand),0):(telemetry.trackCliSubcommandPublish(subcommandOriginal),publish(client,args));case"discard":return needHelp?(telemetry.trackCliFlagHelp("firewall",subcommandOriginal),printHelp(discardSubcommand),0):(telemetry.trackCliSubcommandDiscard(subcommandOriginal),discard(client,args));case"rules":{telemetry.trackCliSubcommandRules(subcommandOriginal);let nestedArgs=needHelp?[...args,"--help"]:args;return main5(client,nestedArgs,telemetry)}case"ip-blocks":{telemetry.trackCliSubcommandIpBlocks(subcommandOriginal);let nestedArgs=needHelp?[...args,"--help"]:args;return main4(client,nestedArgs,telemetry)}case"system-bypass":{telemetry.trackCliSubcommandSystemBypass(subcommandOriginal);let nestedArgs=needHelp?[...args,"--help"]:args;return main(client,nestedArgs,telemetry)}case"attack-mode":{telemetry.trackCliSubcommandAttackMode(subcommandOriginal);let nestedArgs=needHelp?[...args,"--help"]:args;return main2(client,nestedArgs,telemetry)}case"system-mitigations":{telemetry.trackCliSubcommandSystemMitigations(subcommandOriginal);let nestedArgs=needHelp?[...args,"--help"]:args;return main3(client,nestedArgs,telemetry)}case"alerts":{telemetry.trackCliSubcommandAlerts(subcommandOriginal);let nestedArgs=needHelp?[...args,"--help"]:args;return main6(client,nestedArgs,telemetry)}case"persistent-actions":{telemetry.trackCliSubcommandPersistentActions(subcommandOriginal);let nestedArgs=needHelp?[...args,"--help"]:args;return main7(client,nestedArgs,telemetry)}case"traffic":{telemetry.trackCliSubcommandTraffic(subcommandOriginal);let nestedArgs=needHelp?[...args,"--help"]:args;return main8(client,nestedArgs,telemetry)}case"bot-management":return needHelp?(telemetry.trackCliFlagHelp("firewall",subcommandOriginal),printHelp(botManagementSubcommand),0):(telemetry.trackCliSubcommandBotManagement(subcommandOriginal),botManagement(client,args));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG9)),output_manager_default.print(help(firewallCommand,{columns:client.stderr.columns})),2}}var FlagsTelemetryClient=class extends TelemetryClient{trackCliSubcommandList(actual){this.trackCliSubcommand({subcommand:"ls",value:actual})}trackCliSubcommandInspect(actual){this.trackCliSubcommand({subcommand:"inspect",value:actual})}trackCliSubcommandVersions(actual){this.trackCliSubcommand({subcommand:"versions",value:actual})}trackCliSubcommandEvaluations(actual){this.trackCliSubcommand({subcommand:"evaluations",value:actual})}trackCliSubcommandStale(actual){this.trackCliSubcommand({subcommand:"stale",value:actual})}trackCliSubcommandOpen(actual){this.trackCliSubcommand({subcommand:"open",value:actual})}trackCliSubcommandCreate(actual){this.trackCliSubcommand({subcommand:"create",value:actual})}trackCliSubcommandUpdate(actual){this.trackCliSubcommand({subcommand:"update",value:actual})}trackCliSubcommandSet(actual){this.trackCliSubcommand({subcommand:"set",value:actual})}trackCliSubcommandTargeting(actual){this.trackCliSubcommand({subcommand:"targeting",value:actual})}trackCliSubcommandUseTargeting(actual){this.trackCliSubcommand({subcommand:"use-targeting",value:actual})}trackCliSubcommandSplit(actual){this.trackCliSubcommand({subcommand:"split",value:actual})}trackCliSubcommandRollout(actual){this.trackCliSubcommand({subcommand:"rollout",value:actual})}trackCliSubcommandDelete(actual){this.trackCliSubcommand({subcommand:"delete",value:actual})}trackCliSubcommandArchive(actual){this.trackCliSubcommand({subcommand:"archive",value:actual})}trackCliSubcommandUnarchive(actual){this.trackCliSubcommand({subcommand:"unarchive",value:actual})}trackCliSubcommandDisable(actual){this.trackCliSubcommand({subcommand:"disable",value:actual})}trackCliSubcommandEnable(actual){this.trackCliSubcommand({subcommand:"enable",value:actual})}trackCliSubcommandSdkKeys(actual){this.trackCliSubcommand({subcommand:"sdk-keys",value:actual})}trackCliSubcommandConnections(actual){this.trackCliSubcommand({subcommand:"connections",value:actual})}trackCliSubcommandSegments(actual){this.trackCliSubcommand({subcommand:"segments",value:actual})}trackCliSubcommandEntities(actual){this.trackCliSubcommand({subcommand:"entities",value:actual})}trackCliSubcommandLabels(actual){this.trackCliSubcommand({subcommand:"labels",value:actual})}trackCliSubcommandRules(actual){this.trackCliSubcommand({subcommand:"rules",value:actual})}trackCliSubcommandTargets(actual){this.trackCliSubcommand({subcommand:"targets",value:actual})}trackCliSubcommandPrepare(actual){this.trackCliSubcommand({subcommand:"prepare",value:actual})}trackCliSubcommandDatafile(actual){this.trackCliSubcommand({subcommand:"datafile",value:actual})}trackCliSubcommandOverride(actual){this.trackCliSubcommand({subcommand:"override",value:actual})}};var import_chalk42=__toESM(require_source(),1),import_ms=__toESM(require_ms(),1),import_pluralize=__toESM(require_pluralize(),1);function flagUrl(projectId,flagIdOrSlug){return`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/flags/${encodeURIComponent(flagIdOrSlug)}`}async function fetchFlagForUpdate(client,projectId,flagIdOrSlug){output_manager_default.debug(`Fetching feature flag ${flagIdOrSlug} for project ${projectId} with ETag`);let response=await client.fetch(flagUrl(projectId,flagIdOrSlug),{json:!1}),etag=response.headers.get("etag");if(!etag)throw new Error("Unable to update flag safely because the flag ETag is missing.");return{flag:await response.json(),etag}}async function updateFlag(client,projectId,flagIdOrSlug,request,options){output_manager_default.debug(`Updating feature flag ${flagIdOrSlug} for project ${projectId}`);let url=flagUrl(projectId,flagIdOrSlug);return await client.fetch(url,{method:"PATCH",headers:options?.ifMatch?{"If-Match":options.ifMatch}:void 0,body:request})}var MAX_FLAGS_PAGE_LIMIT=100,MAX_FLAG_VERSIONS_PAGE_LIMIT=100;async function getFlags(client,projectId,options={}){let{state="active",tags,createdBy,maintainerIds,limit,cursor}=options;output_manager_default.debug(`Fetching feature flags for project ${projectId}`);let basePath=`/v2/projects/${encodeURIComponent(projectId)}/feature-flags/flags`,buildQuery=(pageLimit,pageCursor2)=>{let query=new URLSearchParams;query.set("state",state),query.set("limit",String(pageLimit)),pageCursor2&&query.set("cursor",pageCursor2),createdBy&&query.set("createdBy",createdBy);for(let tag of tags??[])query.append("tags",tag);for(let maintainerId of maintainerIds??[])query.append("maintainerIds",maintainerId);return query.toString()};if(limit!==void 0||cursor!==void 0){let pageLimit=Math.min(limit??MAX_FLAGS_PAGE_LIMIT,MAX_FLAGS_PAGE_LIMIT),response=await client.fetch(`${basePath}?${buildQuery(pageLimit,cursor)}`);return{flags:response.data,next:response.pagination?.next??null}}let flags=[],pageCursor;do{let response=await client.fetch(`${basePath}?${buildQuery(MAX_FLAGS_PAGE_LIMIT,pageCursor)}`);flags.push(...response.data),pageCursor=response.pagination?.next??void 0}while(pageCursor);return{flags,next:null}}async function getFlag(client,projectId,flagIdOrSlug){output_manager_default.debug(`Fetching feature flag ${flagIdOrSlug} for project ${projectId}`);let url=flagUrl(projectId,flagIdOrSlug);return await client.fetch(url)}async function getFlagSettings(client,projectId){return output_manager_default.debug(`Fetching feature flag settings for project ${projectId}`),await client.fetch(flagSettingsUrl(projectId))}async function updateFlagSettings(client,projectId,request){return output_manager_default.debug(`Updating feature flag settings for project ${projectId}`),client.fetch(flagSettingsUrl(projectId),{method:"PATCH",body:request})}function flagSettingsUrl(projectId){return`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/settings`}async function getFlagVersions(client,projectId,flagIdOrSlug,options={}){output_manager_default.debug(`Fetching feature flag versions for ${flagIdOrSlug} in project ${projectId}`);let query=new URLSearchParams;query.set("withMetadata","true"),options.environment&&query.set("environment",options.environment),options.limit!==void 0&&query.set("limit",String(options.limit)),options.cursor&&query.set("cursor",options.cursor);let url=`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/flags/${encodeURIComponent(flagIdOrSlug)}/versions?${query.toString()}`,response=await client.fetch(url),next=response.pagination?.next??(response.pagination?.hasNext?response.pagination.cursor:null)??null;return{versions:response.versions,next}}var FlagsLsTelemetryClient=class extends TelemetryClient{trackCliOptionState(state){state&&this.trackCliOption({option:"state",value:state})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}trackCliOptionTag(tags){tags&&tags.length>0&&this.trackCliOption({option:"tag",value:this.redactedValue})}trackCliOptionCreatedBy(createdBy){createdBy&&this.trackCliOption({option:"created-by",value:this.redactedValue})}trackCliOptionMaintainerId(maintainerIds){maintainerIds&&maintainerIds.length>0&&this.trackCliOption({option:"maintainer-id",value:this.redactedValue})}trackCliOptionLimit(limit){limit!==void 0&&this.trackCliOption({option:"limit",value:String(limit)})}trackCliOptionNext(next){next&&this.trackCliOption({option:"next",value:this.redactedValue})}};async function ls(client,argv){let telemetryClient=new FlagsLsTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(listSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{flags}=parsedArgs,state=flags["--state"]||"active",tags=flags["--tag"],createdBy=flags["--created-by"],maintainerIds=flags["--maintainer-id"],limit=flags["--limit"],next=flags["--next"],json=flags["--json"],projectName=getProjectNameFromFlags(flags);if(telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionState(state),telemetryClient.trackCliOptionTag(tags),telemetryClient.trackCliOptionCreatedBy(createdBy),telemetryClient.trackCliOptionMaintainerId(maintainerIds),telemetryClient.trackCliOptionLimit(limit),telemetryClient.trackCliOptionNext(next),telemetryClient.trackCliFlagJson(json),limit!==void 0&&(!Number.isInteger(limit)||limit<1||limit>MAX_FLAGS_PAGE_LIMIT))return output_manager_default.error(`The --limit option must be an integer between 1 and ${MAX_FLAGS_PAGE_LIMIT}.`),2;let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name),lsStamp=stamp_default();output_manager_default.spinner(`Fetching ${state} feature flags for ${projectSlugLink}`);try{let{flags:flagsList,next:nextCursor}=await getFlags(client,project.id,{state,tags,createdBy,maintainerIds,limit,cursor:next});if(output_manager_default.stopSpinner(),json)outputJson2(client,flagsList,nextCursor);else if(flagsList.length===0)output_manager_default.log(`No ${state} feature flags found for ${projectSlugLink} ${import_chalk42.default.gray(lsStamp())}`);else if(output_manager_default.log(`${(0,import_pluralize.default)("feature flag",flagsList.length,!0)} found for ${projectSlugLink} ${import_chalk42.default.gray(lsStamp())}`),printFlagsTable(flagsList),nextCursor){let nextCmd=buildNextPageCommand(flags,tags,maintainerIds,nextCursor);output_manager_default.print(`
|
|
205
|
+
`),printNextPageCommand(getCommandNamePlain(nextCmd))}}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function buildNextPageCommand(flags,tags,maintainerIds,nextCursor){let baseFlags=getCommandFlags(flags,["_","--tag","--maintainer-id","--next","--json"]),repeatable=[...(tags??[]).map(tag=>`--tag ${quoteArg(tag)}`),...(maintainerIds??[]).map(id=>`--maintainer-id ${quoteArg(id)}`)],suffix=repeatable.length>0?` ${repeatable.join(" ")}`:"";return`flags ls${baseFlags}${suffix} --next ${nextCursor}`}function outputJson2(client,flags,next){let jsonOutput={flags:flags.map(flag=>({id:flag.id,slug:flag.slug,description:flag.description??null,kind:flag.kind,state:flag.state,variants:flag.variants,createdAt:flag.createdAt,updatedAt:flag.updatedAt})),pagination:{next}};client.stdout.write(`${JSON.stringify(jsonOutput,null,2)}
|
|
206
|
+
`)}function printFlagsTable(flags){let headers=["Name","Kind","State","Variants","Updated"],now=Date.now(),rows=flags.map(flag=>[import_chalk42.default.bold(flag.slug),flag.kind,flag.state==="active"?import_chalk42.default.green(flag.state):import_chalk42.default.gray(flag.state),String(flag.variants.length),(0,import_ms.default)(now-flag.updatedAt)+" ago"]),table2=formatTable(headers,["l","l","l","r","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
207
|
+
${table2}
|
|
208
|
+
`)}var import_chalk43=__toESM(require_source(),1),import_pluralize2=__toESM(require_pluralize(),1);var DEFAULT_STALE_FLAGS_LIMIT=50,MAX_STALE_FLAGS_LIMIT=100,DEFAULT_STALE_AFTER="30d",MAX_STALE_AFTER_DAYS=90;async function getStaleFlags(client,projectId,options={}){let{staleAfter=DEFAULT_STALE_AFTER,limit=DEFAULT_STALE_FLAGS_LIMIT,cursor}=options;output_manager_default.debug(`Fetching stale feature flags for project ${projectId}`);let query=new URLSearchParams;query.set("staleAfter",staleAfter),query.set("limit",String(limit)),cursor&&query.set("cursor",cursor);let response=await client.fetch(`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/stale-flags?${query}`);return{flags:response.data,next:response.pagination.next}}var FlagsStaleTelemetryClient=class extends TelemetryClient{trackCliOptionStaleAfter(staleAfter){staleAfter&&this.trackCliOption({option:"stale-after",value:staleAfter})}trackCliOptionLimit(limit){limit!==void 0&&this.trackCliOption({option:"limit",value:String(limit)})}trackCliOptionNext(next){next&&this.trackCliOption({option:"next",value:this.redactedValue})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}};async function stale(client,argv){let telemetryClient=new FlagsStaleTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(staleSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{flags}=parsedArgs,staleAfter=flags["--stale-after"]??DEFAULT_STALE_AFTER,limit=flags["--limit"]??DEFAULT_STALE_FLAGS_LIMIT,next=flags["--next"],json=flags["--json"],projectName=getProjectNameFromFlags(flags);if(telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionStaleAfter(staleAfter),telemetryClient.trackCliOptionLimit(limit),telemetryClient.trackCliOptionNext(next),telemetryClient.trackCliFlagJson(json),!Number.isInteger(limit)||limit<1||limit>MAX_STALE_FLAGS_LIMIT)return output_manager_default.error(`The --limit option must be an integer between 1 and ${MAX_STALE_FLAGS_LIMIT}.`),2;let staleAfterValidationError=getStaleAfterValidationError(staleAfter);if(staleAfterValidationError)return output_manager_default.error(staleAfterValidationError),1;let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name),staleStamp=stamp_default();output_manager_default.spinner(`Fetching stale feature flags for ${projectSlugLink}`);try{let{flags:staleFlags,next:nextCursor}=await getStaleFlags(client,project.id,{staleAfter,limit,cursor:next});output_manager_default.stopSpinner();let stalePeriod=`(past ${formatStaleAfter(staleAfter)})`;if(json)outputJson3(client,staleFlags,nextCursor,staleAfter);else if(staleFlags.length===0)output_manager_default.log(`No stale feature flags found for ${projectSlugLink} ${stalePeriod} ${import_chalk43.default.gray(staleStamp())}`);else if(output_manager_default.log(`${(0,import_pluralize2.default)("stale feature flag",staleFlags.length,!0)} found for ${projectSlugLink} ${stalePeriod} ${import_chalk43.default.gray(staleStamp())}`),printStaleFlagsTable(staleFlags),nextCursor){let nextCmd=buildNextPageCommand2(flags,nextCursor);output_manager_default.print(`
|
|
209
|
+
`),printNextPageCommand(getCommandNamePlain(nextCmd))}}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function getStaleAfterValidationError(value){let match=/^([1-9][0-9]*)d$/.exec(value);return match?Number(match[1])>MAX_STALE_AFTER_DAYS?`The --stale-after option cannot exceed ${MAX_STALE_AFTER_DAYS}d.`:null:"The --stale-after option must be a relative day duration like 14d."}function buildNextPageCommand2(flags,nextCursor){return`flags stale${getCommandFlags(flags,["_","--next","--json"])} --next ${quoteArg(nextCursor)}`}function outputJson3(client,flags,next,staleAfter){let jsonOutput={staleAfter,flags:flags.map(flag=>({slug:flag.slug,reason:flag.reason})),pagination:{next}};client.stdout.write(`${JSON.stringify(jsonOutput,null,2)}
|
|
210
|
+
`)}function printStaleFlagsTable(flags){let headers=["Flag","Reason"],rows=flags.map(flag=>[import_chalk43.default.bold(flag.slug),formatStaleReason(flag.reason)]),table2=formatTable(headers,["l","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
211
|
+
${table2}
|
|
212
|
+
${formatStaleReasonTypesTable()}
|
|
213
|
+
`)}function formatStaleReasonTypesTable(){return formatTable(["Type","Description"],["l","l"],[{name:"Types",rows:[["Unused","No production deployment references it, and it has no evaluations in the selected period."],["Redundant","All configured and evaluated variants return the production default value."]]}])}function formatStaleAfter(value){let match=/^([1-9][0-9]*)d$/.exec(value);return match?(0,import_pluralize2.default)("day",Number(match[1]),!0):value}function formatStaleReason(reason){switch(reason){case"unused":return"Unused";case"redundant":return"Redundant";default:return reason}}var FlagsInspectTelemetryClient=class extends TelemetryClient{trackCliFlagJson(json){json&&this.trackCliFlag("json")}trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}};var import_chalk47=__toESM(require_source(),1);function getFlagDashboardUrl(orgSlug,projectName,flagSlug){return`https://vercel.com/${orgSlug}/${projectName}/flag/${flagSlug}`}function getFlagsDashboardUrl(orgSlug,projectName){return`https://vercel.com/${orgSlug}/${projectName}/flags`}var import_chalk44=__toESM(require_source(),1);var EPOCH_MS_PATTERN=/^\d+$/,ISO_TIMESTAMP_PATTERN=/^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minute>\d{2})(?::(?<second>\d{2})(?:\.(?<fraction>\d{1,3}))?)?(?:Z|[+-]\d{2}:\d{2})?$/,MIN_EPOCH_MS=1e12,MAX_EPOCH_MS=864e13,TIMESTAMP_FORMAT_HELP="Use an ISO 8601 date and time (for example 2026-04-16T09:00:00Z) or epoch milliseconds.",TIMESTAMP_COMPARATOR_HELP="Use gt (after), gte (at-or-after), lt (before), or lte (at-or-before). gt and lt are exclusive; use gte or lte for inclusive boundaries.",SUPPORTED_TIMESTAMP_COMPARATORS=new Set(["gt","gte","lt","lte"]);function parseTimestampInput(value){let trimmed=value.trim();if(EPOCH_MS_PATTERN.test(trimmed))return validateTimestampEpochMs(Number(trimmed));let isoMatch=ISO_TIMESTAMP_PATTERN.exec(trimmed);if(isoMatch?.groups){assertValidIsoTimestampParts(trimmed,isoMatch.groups);let parsed=Date.parse(trimmed);if(Number.isFinite(parsed))return acceptTimestampEpochMs(parsed)}throw new Error(`Invalid timestamp "${value}". ${TIMESTAMP_FORMAT_HELP}`)}function assertValidIsoTimestampParts(value,parts){let year=Number(parts.year),month=Number(parts.month),day=Number(parts.day),hour=Number(parts.hour),minute=Number(parts.minute),second=parts.second===void 0?0:Number(parts.second),utcProbe=new Date(Date.UTC(year,month-1,day,hour,minute,second));if(utcProbe.getUTCFullYear()!==year||utcProbe.getUTCMonth()!==month-1||utcProbe.getUTCDate()!==day||utcProbe.getUTCHours()!==hour||utcProbe.getUTCMinutes()!==minute||utcProbe.getUTCSeconds()!==second)throw new Error(`Invalid timestamp "${value}". ${TIMESTAMP_FORMAT_HELP}`)}function validateTimestampEpochMs(value){if(Number.isSafeInteger(value)&&value>=MIN_EPOCH_MS&&value<=MAX_EPOCH_MS)return value;throw new Error(`Invalid timestamp "${value}". Epoch values must be milliseconds, not seconds or years. ${TIMESTAMP_FORMAT_HELP}`)}function acceptTimestampEpochMs(value){if(Number.isSafeInteger(value)&&value>=-MAX_EPOCH_MS&&value<=MAX_EPOCH_MS&&!Number.isNaN(new Date(value).getTime()))return value;throw new Error(`Invalid timestamp "${value}". ${TIMESTAMP_FORMAT_HELP}`)}function formatTimestampValue(value){let date=new Date(value);return Number.isNaN(date.getTime())?String(value):date.toISOString()}function coerceTimestampSegmentData(data,settings,source="stored"){return{...data,rules:data.rules?.map(rule=>coerceTimestampRule(rule,settings,source))}}function coerceTimestampOperations(operations,settings,source="input"){return operations.map(operation=>operation.field!=="rule"||!operation.rule?operation:{...operation,rule:coerceTimestampRule(operation.rule,settings,source)})}function coerceTimestampRule(rule,settings,source){return{...rule,conditions:rule.conditions.map(condition=>coerceTimestampCondition(condition,settings,source))}}function coerceTimestampCondition(condition,settings,source="stored"){if(condition.lhs.type!=="entity")return condition;let attributeType=getFlagAttributeType(settings,condition.lhs.kind,condition.lhs.attribute);if(!isTimestampAttributeType(attributeType))return condition;if(!SUPPORTED_TIMESTAMP_COMPARATORS.has(condition.cmp))throw new Error(`Operator "${condition.cmp}" is not valid for Timestamp attribute ${condition.lhs.kind}.${condition.lhs.attribute}. ${TIMESTAMP_COMPARATOR_HELP}`);return typeof condition.rhs=="string"?{...condition,rhs:parseTimestampInput(condition.rhs)}:typeof condition.rhs=="number"?{...condition,rhs:coerceTimestampEpochNumber(condition.rhs,source)}:condition}function coerceTimestampEpochNumber(value,source){return source==="input"?validateTimestampEpochMs(value):acceptTimestampEpochMs(value)}function formatTimestampRhs(value,attributeType){if(!(typeof value!="number"||!isTimestampAttributeType(attributeType)))return formatTimestampValue(value)}function resolveTargetingLabel(settings,entityKind,attribute,value){if(!settings)return;let entity=settings.entities.find(e=>e.kind===entityKind);if(!entity)return;let attr=entity.attributes.find(a=>a.key===attribute);return attr?.labels?attr.labels.find(l=>l.value===value)?.label:void 0}function formatFlagCondition(condition,settings){let lhs;condition.lhs.type==="segment"?lhs="segment":lhs=`${condition.lhs.kind}.${condition.lhs.attribute}`;let attributeType=condition.lhs.type==="entity"?getFlagAttributeType(settings,condition.lhs.kind,condition.lhs.attribute):void 0,cmp=import_chalk44.default.dim(formatFlagConditionComparator(condition.cmp,{...condition.cmpOptions,attributeType}));if(condition.rhs===void 0||condition.rhs===null)return{text:`${lhs} ${cmp}`};if(typeof condition.rhs=="object"){if((condition.rhs.type==="list"||condition.rhs.type==="list/inline")&&Array.isArray(condition.rhs.items)){let items=condition.rhs.items.map(item=>{let itemValue=typeof item=="object"&&item!==null&&"value"in item?String(item.value):String(item);if(condition.lhs.type==="entity"){let label=resolveTargetingLabel(settings,condition.lhs.kind,condition.lhs.attribute,itemValue);return label?`${itemValue} ${import_chalk44.default.gray(label)}`:itemValue}return itemValue});return{text:`${lhs} ${cmp}`,listItems:items}}return{text:`${lhs} ${cmp} ${JSON.stringify(condition.rhs)}`}}let rhs;if(condition.lhs.type==="entity"){let timestampRhs=formatTimestampRhs(condition.rhs,attributeType),label=resolveTargetingLabel(settings,condition.lhs.kind,condition.lhs.attribute,String(condition.rhs)),displayValue=timestampRhs??String(condition.rhs);rhs=label?`${displayValue} ${import_chalk44.default.gray(label)}`:displayValue}else rhs=String(condition.rhs);return{text:`${lhs} ${cmp} ${rhs}`}}var import_chalk46=__toESM(require_source(),1),import_ms2=__toESM(require_ms(),1);var import_chalk45=__toESM(require_source(),1),import_fast_deep_equal=__toESM(require_fast_deep_equal(),1);function formatVariantValue(value){return JSON.stringify(value)}function formatVariantForDisplay(variant){let value=formatVariantValue(variant.value);return variant.label?`${variant.label} (${import_chalk45.default.dim(value)})`:value}function formatVariantListSummary(variant){let value=formatVariantValue(variant.value);return variant.label?`${value}: ${import_chalk45.default.gray(variant.label)}`:value}function formatAvailableVariants(variants){return variants.map(v=>` - ${formatAvailableVariant(v)}`).join(`
|
|
214
|
+
`)}function resolveVariant(input,variants){let byId=variants.find(v=>v.id===input);if(byId)return{variant:byId,error:null};let parsedInput=parseVariantValue(input),byValue=variants.find(v=>valuesMatch(v.value,parsedInput));if(byValue)return{variant:byValue,error:null};let byExactStringValue=variants.find(v=>v.value===input);if(byExactStringValue)return{variant:byExactStringValue,error:null};let availableList=formatAvailableVariants(variants);return{variant:null,error:`Variant "${input}" not found.
|
|
215
|
+
|
|
216
|
+
Available variants:
|
|
217
|
+
${availableList}
|
|
218
|
+
|
|
219
|
+
You can specify a variant by its ID or value.`}}function resolveVariantOrThrow(input,variants,optionName,displayInput=input){let result=resolveVariant(input,variants);if(result.error||!result.variant)throw new Error(`${optionName} ${import_chalk45.default.bold(displayInput)} is invalid. ${result.error||"Variant not found."}`);return result.variant}function resolveVariantByIdOrThrow(variantId,variants,optionName){let variant=variants.find(candidate=>candidate.id===variantId);if(!variant)throw new Error(`${optionName} references an unknown variant ${import_chalk45.default.bold(variantId)}.`);return variant}function parseVariantValue(input){let trimmed=input.trim();if(!trimmed)return input;try{return JSON.parse(trimmed)}catch{let lowerInput=trimmed.toLowerCase();if(lowerInput==="true")return!0;if(lowerInput==="false")return!1;let parsedNumber=Number(trimmed);return Number.isNaN(parsedNumber)?input:parsedNumber}}function valuesMatch(variantValue,inputValue){return(0,import_fast_deep_equal.default)(variantValue,inputValue)}function formatAvailableVariant(variant){let value=formatStyledVariantValue(variant.value);return variant.label?`${value} ${import_chalk45.default.dim(variant.label)}`:value}function formatStyledVariantValue(value){let formattedValue=formatVariantValue(value);return typeof value!="string"?import_chalk45.default.bold(formattedValue):`"${import_chalk45.default.bold(formattedValue.slice(1,-1))}"`}function formatFlagOutcome(outcome,variants,includeVariantId=!1){if(outcome.type==="variant"){let variant=variants.find(v=>v.id===outcome.variantId);return formatFlagVariantSummary(variant,outcome.variantId,includeVariantId)}return outcome.type==="split"?`split (${formatFlagSplitWeights(outcome.weights,variants,includeVariantId)})`:outcome.type==="experiment"?"experiment assignment":formatRolloutOutcome(outcome,variants,includeVariantId)}function formatFlagVariantSummary(variant,fallback,includeVariantId=!1){if(!variant)return import_chalk46.default.bold(fallback);let summary=variant.label?import_chalk46.default.bold(variant.label):import_chalk46.default.bold(formatVariantValue(variant.value));return includeVariantId?`${summary} ${import_chalk46.default.dim(`(${variant.id})`)}`:summary}function formatFlagSplitWeights(weights,variants,includeVariantId=!1){let total=Object.values(weights).reduce((sum,weight)=>sum+weight,0);return Object.entries(weights).map(([id,weight])=>{let variant=variants.find(v=>v.id===id),summary=formatFlagVariantSummary(variant,id,includeVariantId),percentage=total>0?weight/total*100:0,formattedPercentage=Number.isInteger(percentage)?String(percentage):String(Number(percentage.toFixed(2)));return`${summary}: ${formattedPercentage}%`}).join(", ")}function formatRolloutOutcome(outcome,variants,includeVariantId=!1){let fromVariant=variants.find(v=>v.id===outcome.rollFromVariantId),toVariant=variants.find(v=>v.id===outcome.rollToVariantId),defaultVariant=variants.find(v=>v.id===outcome.defaultVariantId),stages=outcome.slots.map(slot=>{let percentage=slot.promille/1e3;return`${Number.isInteger(percentage)?String(percentage):String(Number(percentage.toFixed(3)))}% for ${(0,import_ms2.default)(slot.durationMs,{long:!0})}`}).join(", ");return`${formatFlagVariantSummary(fromVariant,outcome.rollFromVariantId,includeVariantId)} -> ${formatFlagVariantSummary(toVariant,outcome.rollToVariantId,includeVariantId)}; ${stages}; then ${(outcome.finalPromille??1e5)/1e3}%; Fallback: ${formatFlagVariantSummary(defaultVariant,outcome.defaultVariantId,includeVariantId)}`}function printFlagDetails({flag,settings,projectSlugLink,orgSlug,projectName,showTimestamps=!0}){let dashboardUrl=getFlagDashboardUrl(orgSlug,projectName,flag.slug);output_manager_default.log(`
|
|
220
|
+
Feature flag ${import_chalk47.default.bold(flag.slug)} for ${projectSlugLink}
|
|
221
|
+
`),output_manager_default.print(` ${import_chalk47.default.cyan(dashboardUrl)}
|
|
222
|
+
|
|
223
|
+
`),output_manager_default.print(` ${import_chalk47.default.dim("ID:")} ${flag.id}
|
|
224
|
+
`),output_manager_default.print(` ${import_chalk47.default.dim("Kind:")} ${flag.kind}
|
|
225
|
+
`),output_manager_default.print(` ${import_chalk47.default.dim("State:")} ${flag.state==="active"?import_chalk47.default.green(flag.state):import_chalk47.default.gray(flag.state)}
|
|
226
|
+
`),flag.description&&output_manager_default.print(` ${import_chalk47.default.dim("Description:")} ${flag.description}
|
|
227
|
+
`),flag.experiment&&output_manager_default.print(` ${import_chalk47.default.dim("Experiment:")} managed by ${flag.experiment.id??"an experiment"}
|
|
228
|
+
`),showTimestamps&&(output_manager_default.print(` ${import_chalk47.default.dim("Created:")} ${formatDate(flag.createdAt)}
|
|
229
|
+
`),output_manager_default.print(` ${import_chalk47.default.dim("Updated:")} ${formatDate(flag.updatedAt)}
|
|
230
|
+
`)),output_manager_default.print(`
|
|
231
|
+
${import_chalk47.default.dim("Variants:")}
|
|
232
|
+
`);for(let[index,variant]of flag.variants.entries())output_manager_default.print(` ${formatVariantListSummary(variant)}
|
|
233
|
+
`),output_manager_default.print(` ${import_chalk47.default.dim(`id: ${variant.id}`)}
|
|
234
|
+
`),index<flag.variants.length-1&&output_manager_default.print(`
|
|
235
|
+
`);printFlagEnvironmentDetails(flag,settings)}function printFlagEnvironmentDetails(flag,settings,environments){let sortedEnvs=getSortedEnvironmentEntries(flag,environments);output_manager_default.print(`
|
|
236
|
+
${import_chalk47.default.dim("Environments:")}
|
|
237
|
+
`);for(let[envName,envConfig]of sortedEnvs){if(envConfig.reuse?.active){output_manager_default.print(` ${import_chalk47.default.bold(envName)}: reuses ${import_chalk47.default.cyan(envConfig.reuse.environment)} environment
|
|
238
|
+
`);continue}if(envConfig.active){let hasCustomConfiguration=hasCustomConfigurationEnabled(envConfig),envSummary=hasCustomConfiguration?"custom":formatFlagOutcome(envConfig.fallthrough,flag.variants);if(output_manager_default.print(` ${import_chalk47.default.bold(envName)}: ${envSummary}
|
|
239
|
+
`),envConfig.targets&&Object.keys(envConfig.targets).length>0){output_manager_default.print(` ${import_chalk47.default.dim("Targeting:")}
|
|
240
|
+
`);for(let[variantId,entityKinds]of Object.entries(envConfig.targets)){let variant=flag.variants.find(v=>v.id===variantId),variantSummary=formatFlagVariantSummary(variant,variantId);for(let[entityKind,attributes]of Object.entries(entityKinds))for(let[attribute,values]of Object.entries(attributes)){let valueList=values.map(v=>{let label=resolveTargetingLabel(settings,entityKind,attribute,v.value);return label?`${v.value} ${import_chalk47.default.gray(label)}`:v.value}).join(", ");output_manager_default.print(` ${import_chalk47.default.dim(`${entityKind}.${attribute}:`)} ${valueList} ${import_chalk47.default.dim("\u2192")} ${variantSummary}
|
|
241
|
+
`)}}}if(envConfig.rules&&envConfig.rules.length>0){output_manager_default.print(` ${import_chalk47.default.dim("Rules:")}
|
|
242
|
+
`);for(let rule of envConfig.rules){let outcome=formatFlagOutcome(rule.outcome,flag.variants);output_manager_default.print(` ${import_chalk47.default.dim("\u2192")} ${outcome}
|
|
243
|
+
`);for(let condition of rule.conditions){let{text,listItems}=formatFlagCondition(condition,settings);if(output_manager_default.print(` ${import_chalk47.default.dim("if")} ${text}
|
|
244
|
+
`),listItems&&listItems.length>0)for(let item of listItems)output_manager_default.print(` ${import_chalk47.default.dim("-")} ${item}
|
|
245
|
+
`)}}}if(hasCustomConfiguration&&envConfig.fallthrough){let fallthrough=envConfig.fallthrough;if(fallthrough.type==="variant"){let defaultVariant=flag.variants.find(v=>v.id===fallthrough.variantId),defaultSummary=formatFlagVariantSummary(defaultVariant,fallthrough.variantId);output_manager_default.print(` ${import_chalk47.default.dim("Default:")} ${defaultSummary}
|
|
246
|
+
`)}else if(fallthrough.type==="split"){let weights=formatFlagSplitWeights(fallthrough.weights,flag.variants);output_manager_default.print(` ${import_chalk47.default.dim("Default split:")} ${weights}
|
|
247
|
+
`)}else fallthrough.type==="rollout"?output_manager_default.print(` ${import_chalk47.default.dim("Rollout:")} ${formatFlagOutcome(fallthrough,flag.variants)}
|
|
248
|
+
`):fallthrough.type==="experiment"&&output_manager_default.print(` ${import_chalk47.default.dim("Default:")} ${formatFlagOutcome(fallthrough,flag.variants)}
|
|
249
|
+
`)}}else{let pausedVariant=flag.variants.find(v=>v.id===envConfig.pausedOutcome?.variantId),pausedSummary=formatFlagVariantSummary(pausedVariant,envConfig.pausedOutcome?.variantId||"paused");output_manager_default.print(` ${import_chalk47.default.bold(envName)}: ${pausedSummary}
|
|
250
|
+
`)}}output_manager_default.print(`
|
|
251
|
+
`)}function getSortedEnvironmentEntries(flag,environments){let envOrder=["production","preview","development"],selectedEnvironments=environments?new Set(environments):void 0;return Object.entries(flag.environments).filter(([envName])=>selectedEnvironments?selectedEnvironments.has(envName):!0).sort(([a],[b])=>{let aIndex=envOrder.indexOf(a),bIndex=envOrder.indexOf(b);return aIndex===-1&&bIndex===-1?a.localeCompare(b):aIndex===-1?1:bIndex===-1?-1:aIndex-bIndex})}function hasCustomConfigurationEnabled(envConfig){return!!(envConfig.targets&&Object.keys(envConfig.targets).length>0)||envConfig.rules.length>0||envConfig.fallthrough.type==="split"||envConfig.fallthrough.type==="rollout"||envConfig.fallthrough.type==="experiment"}async function inspect5(client,argv){let telemetryClient=new FlagsInspectTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(inspectSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,json=flags["--json"],projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error(`Missing required argument: flag. Usage: ${getCommandName("flags inspect <flag>")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagJson(json);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name);try{if(json){let flag2=await getFlag(client,project.id,flagArg);return client.stdout.write(`${JSON.stringify({flag:flag2},null,2)}
|
|
252
|
+
`),0}let[flag,settings]=await Promise.all([getFlag(client,project.id,flagArg),getFlagSettings(client,project.id)]);printFlagDetails({flag,settings,projectSlugLink,orgSlug:org.slug,projectName:project.name})}catch(err){return printError(err),1}return 0}var import_chalk49=__toESM(require_source(),1),import_pluralize3=__toESM(require_pluralize(),1);var FlagsVersionsTelemetryClient=class extends TelemetryClient{trackCliSubcommandList(actual){this.trackCliSubcommand({subcommand:"list",value:actual})}trackCliSubcommandDiff(actual){this.trackCliSubcommand({subcommand:"diff",value:actual})}trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:STANDARD_ENVIRONMENTS.includes(environment)?environment:this.redactedValue})}trackCliOptionLimit(limit){limit!==void 0&&this.trackCliOption({option:"limit",value:String(limit)})}trackCliOptionNext(next){next&&this.trackCliOption({option:"next",value:this.redactedValue})}trackCliOptionCursor(cursor){cursor&&this.trackCliOption({option:"cursor",value:this.redactedValue})}trackCliOptionRevision(revision){revision!==void 0&&this.trackCliOption({option:"revision",value:String(revision)})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}};var import_chalk48=__toESM(require_source(),1),import_fast_deep_equal2=__toESM(require_fast_deep_equal(),1);var ENVIRONMENT_ORDER=["production","preview","development"];function normalizeVersionDataForDiff(data){return{...data,permanent:data.permanent??!1,environments:Object.fromEntries(Object.entries(data.environments).map(([environment,config])=>{let diffConfig={...config};return delete diffConfig.revision,[environment,diffConfig]}))}}function diffVersionData(before,after){return diffValues(normalizeVersionDataForDiff(before),normalizeVersionDataForDiff(after))}function formatVersionDataDiff(before,after){let beforeData=normalizeVersionDataForDiff(before),afterData=normalizeVersionDataForDiff(after),lines=[];return appendGeneralChanges(lines,beforeData,afterData),appendEnvironmentChanges(lines,beforeData,afterData),appendUnknownChanges(lines,beforeData,afterData),lines.join(`
|
|
253
|
+
`)}function appendGeneralChanges(lines,before,after){let section=[];appendScalarChange(section,"Description",before.description,after.description),appendScalarChange(section,"State",before.state,after.state),appendScalarChange(section,"Permanent",before.permanent,after.permanent),appendListChange(section,"Tags",before.tags??[],after.tags??[]),appendListChange(section,"Maintainers",before.maintainerIds??[],after.maintainerIds??[]),appendScalarChange(section,"Seed",before.seed,after.seed),appendVariantChanges(section,before.variants,after.variants),appendSection(lines,"General",section)}function appendEnvironmentChanges(lines,before,after){let environments=new Set([...Object.keys(before.environments),...Object.keys(after.environments)]);for(let environment of Array.from(environments).sort(sortEnvironments)){let beforeEnvironment=before.environments[environment],afterEnvironment=after.environments[environment],section=[];if(!beforeEnvironment&&afterEnvironment){section.push(diffLine("+","Environment added",4)),appendEnvironmentSummary(section,afterEnvironment,after.variants,6),appendSection(lines,formatEnvironmentName(environment),section);continue}if(beforeEnvironment&&!afterEnvironment){section.push(diffLine("-","Environment removed",4)),appendEnvironmentSummary(section,beforeEnvironment,before.variants,6),appendSection(lines,formatEnvironmentName(environment),section);continue}!beforeEnvironment||!afterEnvironment||(0,import_fast_deep_equal2.default)(beforeEnvironment,afterEnvironment)||(appendScalarChange(section,"Status",formatEnvironmentStatus(beforeEnvironment,before.variants),formatEnvironmentStatus(afterEnvironment,after.variants)),appendReuseChange(section,beforeEnvironment,afterEnvironment),appendOutcomeChange(section,"Paused outcome",beforeEnvironment.pausedOutcome,afterEnvironment.pausedOutcome,before.variants,after.variants),appendOutcomeChange(section,"Fallthrough",beforeEnvironment.fallthrough,afterEnvironment.fallthrough,before.variants,after.variants),appendRuleChanges(section,beforeEnvironment.rules??[],afterEnvironment.rules??[],before.variants,after.variants),appendTargetChanges(section,beforeEnvironment.targets,afterEnvironment.targets,before.variants,after.variants),appendUnknownEnvironmentChanges(section,beforeEnvironment,afterEnvironment),appendSection(lines,formatEnvironmentName(environment),section))}}function appendUnknownChanges(lines,before,after){let beforeUnknown=omitKeys(before,["description","environments","maintainerIds","permanent","seed","state","tags","variants"]),afterUnknown=omitKeys(after,["description","environments","maintainerIds","permanent","seed","state","tags","variants"]),changes=diffValues(beforeUnknown,afterUnknown);changes.length>0&&appendFallbackChanges(lines,"Other",changes)}function appendUnknownEnvironmentChanges(section,before,after){let beforeUnknown=omitKeys(before,["active","fallthrough","pausedOutcome","reuse","rules","targets"]),afterUnknown=omitKeys(after,["active","fallthrough","pausedOutcome","reuse","rules","targets"]),changes=diffValues(beforeUnknown,afterUnknown);changes.length>0&&(section.push(line(import_chalk48.default.bold("Other"),4)),appendFallbackChangeLines(section,changes,6))}function appendVariantChanges(section,beforeVariants,afterVariants){if((0,import_fast_deep_equal2.default)(beforeVariants,afterVariants))return;let beforeById=new Map(beforeVariants.map(variant=>[variant.id,variant])),afterById=new Map(afterVariants.map(variant=>[variant.id,variant])),variantLines=[],beforeOrder=beforeVariants.map(variant=>variant.id),afterOrder=afterVariants.map(variant=>variant.id),commonBeforeOrder=beforeOrder.filter(id=>afterById.has(id)),commonAfterOrder=afterOrder.filter(id=>beforeById.has(id));commonBeforeOrder.length>1&&!(0,import_fast_deep_equal2.default)(commonBeforeOrder,commonAfterOrder)&&(variantLines.push(line(import_chalk48.default.bold("Order"),6)),variantLines.push(diffLine("-",formatItemOrder(beforeOrder),8)),variantLines.push(diffLine("+",formatItemOrder(afterOrder),8)));for(let id of Array.from(new Set([...beforeById.keys(),...afterById.keys()])).sort()){let before=beforeById.get(id),after=afterById.get(id);if(!before&&after){variantLines.push(diffLine("+",formatVariantSummary(after),6));continue}if(before&&!after){variantLines.push(diffLine("-",formatVariantSummary(before),6));continue}!before||!after||(0,import_fast_deep_equal2.default)(before,after)||(variantLines.push(diffLine("~",formatVariantChangeTitle(before,after),6)),appendScalarChange(variantLines,"Value",before.value,after.value,8),appendScalarChange(variantLines,"Label",before.label,after.label,8),appendScalarChange(variantLines,"Description",before.description,after.description,8))}variantLines.length>0&&(section.push(line(import_chalk48.default.bold("Variants"),4)),section.push(...variantLines))}function appendRuleChanges(section,beforeRules,afterRules,beforeVariants,afterVariants){if((0,import_fast_deep_equal2.default)(beforeRules,afterRules))return;let beforeById=new Map(beforeRules.map(rule=>[rule.id,rule])),afterById=new Map(afterRules.map(rule=>[rule.id,rule])),ruleLines=[],beforeOrder=beforeRules.map(rule=>rule.id),afterOrder=afterRules.map(rule=>rule.id),commonBeforeOrder=beforeOrder.filter(id=>afterById.has(id)),commonAfterOrder=afterOrder.filter(id=>beforeById.has(id));commonBeforeOrder.length>1&&!(0,import_fast_deep_equal2.default)(commonBeforeOrder,commonAfterOrder)&&(ruleLines.push(line(import_chalk48.default.bold("Order"),6)),ruleLines.push(diffLine("-",formatItemOrder(beforeOrder),8)),ruleLines.push(diffLine("+",formatItemOrder(afterOrder),8)));for(let id of Array.from(new Set([...beforeById.keys(),...afterById.keys()])).sort()){let before=beforeById.get(id),after=afterById.get(id);if(!before&&after){ruleLines.push(diffLine("+",formatRuleTitle(after.id,afterOrder.indexOf(after.id),afterOrder),6)),ruleLines.push(...formatRuleDetails(after,afterVariants,8));continue}if(before&&!after){ruleLines.push(diffLine("-",formatRuleTitle(before.id,beforeOrder.indexOf(before.id),beforeOrder),6)),ruleLines.push(...formatRuleDetails(before,beforeVariants,8));continue}!before||!after||(0,import_fast_deep_equal2.default)(before,after)||(ruleLines.push(diffLine("~",after.id,6)),appendConditionChanges(ruleLines,before.conditions,after.conditions,8),appendOutcomeChange(ruleLines,"Serve",before.outcome,after.outcome,beforeVariants,afterVariants,8,!1))}ruleLines.length>0&&(section.push(line(import_chalk48.default.bold("Rules"),4)),section.push(...ruleLines))}function appendConditionChanges(lines,beforeConditions,afterConditions,indent2){let before=beforeConditions.map(condition=>({condition,key:JSON.stringify(condition)})),after=afterConditions.map(condition=>({condition,key:JSON.stringify(condition)})),removed=before.filter(beforeCondition=>!after.some(afterCondition=>afterCondition.key===beforeCondition.key)),added=after.filter(afterCondition=>!before.some(beforeCondition=>beforeCondition.key===afterCondition.key));if(!(removed.length===0&&added.length===0)){lines.push(line(import_chalk48.default.bold("Conditions"),indent2));for(let{condition}of removed)appendConditionDiff(lines,"-",condition,indent2+2);for(let{condition}of added)appendConditionDiff(lines,"+",condition,indent2+2)}}function appendTargetChanges(section,beforeTargets,afterTargets,beforeVariants,afterVariants){if((0,import_fast_deep_equal2.default)(beforeTargets,afterTargets))return;let before=formatTargets(beforeTargets,beforeVariants),after=formatTargets(afterTargets,afterVariants);(0,import_fast_deep_equal2.default)(before,after)&&(before=formatTargets(beforeTargets,beforeVariants,!0),after=formatTargets(afterTargets,afterVariants,!0)),appendStringSetChange(section,"Targeting",before,after)}function appendOutcomeChange(lines,label,before,after,beforeVariants,afterVariants,indent2=4,includeServe=!0){if((0,import_fast_deep_equal2.default)(before,after))return;let beforeSummary=before?formatOutcome(before,beforeVariants,includeServe):void 0,afterSummary=after?formatOutcome(after,afterVariants,includeServe):void 0;(0,import_fast_deep_equal2.default)(beforeSummary,afterSummary)&&(beforeSummary=before?formatOutcome(before,beforeVariants,includeServe,!0):void 0,afterSummary=after?formatOutcome(after,afterVariants,includeServe,!0):void 0),appendScalarChange(lines,label,beforeSummary,afterSummary,indent2)}function appendReuseChange(section,before,after){appendScalarChange(section,"Reuse",formatReuse(before.reuse),formatReuse(after.reuse))}function appendEnvironmentSummary(lines,environment,variants,indent2){if(lines.push(line(`${import_chalk48.default.dim("Status:")} ${formatEnvironmentStatus(environment,variants)}`,indent2)),environment.reuse?.active){lines.push(line(`${import_chalk48.default.dim("Reuse:")} ${formatReuse(environment.reuse)}`,indent2));return}if(!environment.active&&environment.pausedOutcome){lines.push(line(`${import_chalk48.default.dim("Paused outcome:")} ${formatOutcome(environment.pausedOutcome,variants)}`,indent2));return}lines.push(line(`${import_chalk48.default.dim("Fallthrough:")} ${formatOutcome(environment.fallthrough,variants)}`,indent2));let ruleCount=environment.rules?.length??0;ruleCount>0&&lines.push(line(`${import_chalk48.default.dim("Rules:")} ${import_chalk48.default.bold(String(ruleCount))}`,indent2));let targets2=formatTargets(environment.targets,variants);targets2.length>0&&lines.push(line(`${import_chalk48.default.dim("Targets:")} ${import_chalk48.default.bold(String(targets2.length))}`,indent2))}function appendScalarChange(lines,label,before,after,indent2=4){(0,import_fast_deep_equal2.default)(before,after)||(lines.push(line(import_chalk48.default.bold(label),indent2)),lines.push(diffLine("-",formatScalarValue(before),indent2+2)),lines.push(diffLine("+",formatScalarValue(after),indent2+2)))}function appendListChange(lines,label,before,after,indent2=4){appendStringSetChange(lines,label,before,after,indent2)}function appendStringSetChange(lines,label,before,after,indent2=4){let removed=before.filter(item=>!after.includes(item)).sort(),added=after.filter(item=>!before.includes(item)).sort();if(!(removed.length===0&&added.length===0)){lines.push(line(import_chalk48.default.bold(label),indent2));for(let item of removed)lines.push(diffLine("-",item,indent2+2));for(let item of added)lines.push(diffLine("+",item,indent2+2))}}function appendSection(lines,title,section){section.length!==0&&(lines.length>0&&lines.push(""),lines.push(line(import_chalk48.default.bold(title),2)),lines.push(...section))}function appendFallbackChanges(lines,title,changes){let section=[];appendFallbackChangeLines(section,changes,4),appendSection(lines,title,section)}function appendFallbackChangeLines(lines,changes,indent2){for(let change of changes)lines.push(line(import_chalk48.default.bold(change.path||"value"),indent2)),change.action!=="added"&&lines.push(diffLine("-",formatScalarValue(change.before),indent2+2)),change.action!=="removed"&&lines.push(diffLine("+",formatScalarValue(change.after),indent2+2))}function formatRuleDetails(rule,variants,indent2){let lines=[];lines.push(line(`${import_chalk48.default.dim("\u2192")} ${formatOutcome(rule.outcome,variants,!1)}`,indent2));for(let condition of rule.conditions)appendConditionDetails(lines,condition,indent2+2);return lines}function appendConditionDetails(lines,condition,indent2){let{text,listItems}=formatFlagCondition(condition,void 0);lines.push(line(`${import_chalk48.default.dim("if")} ${text}`,indent2));for(let item of listItems??[])lines.push(line(`${import_chalk48.default.dim("-")} ${item}`,indent2+3))}function appendConditionDiff(lines,marker,condition,indent2){let{text,listItems}=formatFlagCondition(condition,void 0);lines.push(diffLine(marker,`${import_chalk48.default.dim("if")} ${text}`,indent2));for(let item of listItems??[])lines.push(line(`${import_chalk48.default.dim("-")} ${item}`,indent2+3))}function formatTargets(targets2,variants,includeVariantId=!1){let lines=[];for(let[variantId,entityKinds]of Object.entries(targets2??{}))for(let[entityKind,attributes]of Object.entries(entityKinds))for(let[attribute,values]of Object.entries(attributes))for(let target of values){let variant=variants.find(candidate=>candidate.id===variantId);lines.push(`${import_chalk48.default.dim(`${entityKind}.${attribute}:`)} ${formatTargetValue(target)} ${import_chalk48.default.dim("\u2192")} ${formatFlagVariantSummary(variant,variantId,includeVariantId)}`)}return lines.sort()}function formatTargetValue(target){return target.note?`${target.value} ${import_chalk48.default.gray(`(${target.note})`)}`:target.value}function formatEnvironmentStatus(environment,variants){return environment.active?import_chalk48.default.green("active"):environment.pausedOutcome?`${import_chalk48.default.gray("paused")}, ${import_chalk48.default.dim("serving")} ${formatOutcome(environment.pausedOutcome,variants,!1)}`:import_chalk48.default.gray("paused")}function formatReuse(reuse){return reuse?.active?`${import_chalk48.default.dim("reusing")} ${import_chalk48.default.cyan(formatEnvironmentName(reuse.environment))}`:import_chalk48.default.gray("none")}function formatOutcome(outcome,variants,includeServe=!0,includeVariantId=!1){let prefix=includeServe?`${import_chalk48.default.dim("Serve")} `:"",summary=formatFlagOutcome(outcome,variants,includeVariantId);if(outcome.type==="split"){let defaultVariant=variants.find(variant=>variant.id===outcome.defaultVariantId);return`${prefix}${summary}; ${import_chalk48.default.dim("by")} ${formatBucketingBase(outcome.base)}; ${import_chalk48.default.dim("Fallback:")} ${formatFlagVariantSummary(defaultVariant,outcome.defaultVariantId,includeVariantId)}`}return outcome.type==="rollout"?`${prefix}${summary}; ${import_chalk48.default.dim("by")} ${formatBucketingBase(outcome.base)}; ${import_chalk48.default.dim("Starts:")} ${formatTimestamp(outcome.startTimestamp)}`:`${prefix}${summary}`}function formatBucketingBase(base){return`${base.kind}.${base.attribute}`}function formatTimestamp(timestamp){let date=new Date(timestamp);return Number.isNaN(date.getTime())?String(timestamp):date.toISOString()}function formatItemOrder(ids){return ids.join(` ${import_chalk48.default.dim("\u2192")} `)}function formatRuleTitle(ruleId,index,ruleOrder){return ruleOrder.length===1?ruleId:`${ruleId} ${import_chalk48.default.dim(`(position ${index+1})`)}`}function formatVariantChangeTitle(before,after){let label=after.label??before.label;return label?`${import_chalk48.default.bold(label)} (${import_chalk48.default.dim(after.id)})`:after.id}function formatVariantSummary(variant){let details=[`${import_chalk48.default.dim("id:")} ${variant.id}`,`${import_chalk48.default.dim("value:")} ${import_chalk48.default.bold(formatVariantValue(variant.value))}`];return variant.label&&details.unshift(import_chalk48.default.bold(variant.label)),details.join(", ")}function formatScalarValue(value){return value==null||value===""?"-":typeof value=="string"?value:typeof value=="boolean"?value?"true":"false":JSON.stringify(sortObjectKeys(value),null,2)}function formatEnvironmentName(environment){return environment.charAt(0).toUpperCase()+environment.slice(1)}function line(text,indent2){return`${" ".repeat(indent2)}${text}`}function diffLine(marker,text,indent2){let color=marker==="+"?import_chalk48.default.green:marker==="-"?import_chalk48.default.red:import_chalk48.default.yellow;return line(color(`${marker} ${text}`),indent2)}function sortEnvironments(a,b){let aIndex=ENVIRONMENT_ORDER.indexOf(a),bIndex=ENVIRONMENT_ORDER.indexOf(b);return aIndex===-1&&bIndex===-1?a.localeCompare(b):aIndex===-1?1:bIndex===-1?-1:aIndex-bIndex}function omitKeys(value,keys){let omitted={...value};for(let key of keys)delete omitted[key];return omitted}function diffValues(before,after,path=""){return(0,import_fast_deep_equal2.default)(before,after)?[]:isPlainObject(before)&&isPlainObject(after)?Array.from(new Set([...Object.keys(before),...Object.keys(after)])).sort().flatMap(key=>diffValues(before[key],after[key],joinPath(path,key))):[{path,action:before===void 0?"added":after===void 0?"removed":"changed",before,after}]}function isPlainObject(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function joinPath(path,key){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)?path?`${path}.${key}`:key:`${path}[${JSON.stringify(key)}]`}function sortObjectKeys(value){return Array.isArray(value)?value.map(sortObjectKeys):isPlainObject(value)?Object.fromEntries(Object.keys(value).sort().map(key=>[key,sortObjectKeys(value[key])])):value}var COMMAND_CONFIG10={list:getCommandAliases(versionsListSubcommand),diff:getCommandAliases(versionsDiffSubcommand)};async function versions(client,argv){let telemetryClient=new FlagsVersionsTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(versionsSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG10),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetryClient.trackCliFlagHelp("flags versions",subcommandOriginal),output_manager_default.print(help(parsedArgs.args.length>0?versionsListSubcommand:versionsSubcommand,{parent:parsedArgs.args.length>0?getVersionsHelpParent():flagsCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:getVersionsHelpParent(),columns:client.stderr.columns}))}switch(subcommand){case"diff":return needHelp?(telemetryClient.trackCliFlagHelp("flags versions",subcommandOriginal),printHelp(versionsDiffSubcommand),0):(telemetryClient.trackCliSubcommandDiff(subcommandOriginal),diffVersions(client,args,telemetryClient));case"list":return needHelp?(telemetryClient.trackCliFlagHelp("flags versions",subcommandOriginal),printHelp(versionsListSubcommand),0):(telemetryClient.trackCliSubcommandList(subcommandOriginal),listVersions(client,args,telemetryClient));default:return telemetryClient.trackCliSubcommandList("default"),listVersions(client,argv,telemetryClient)}}async function listVersions(client,argv,telemetryClient){let parsedArgs,flagsSpecification=getFlagsSpecification(versionsListSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],limit=flags["--limit"],cursor=flags["--next"]??flags["--cursor"],json=flags["--json"],projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error(`Missing required argument: flag. Usage: ${getCommandName("flags versions <flag>")}`),2;if(telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionLimit(limit),telemetryClient.trackCliOptionNext(flags["--next"]),telemetryClient.trackCliOptionCursor(flags["--cursor"]),flags["--cursor"]!==void 0&&warnDeprecatedOption(client.argv,"--cursor","--next"),telemetryClient.trackCliFlagJson(json),limit!==void 0&&(!Number.isInteger(limit)||limit<1||limit>MAX_FLAG_VERSIONS_PAGE_LIMIT))return output_manager_default.error(`The --limit option must be an integer between 1 and ${MAX_FLAG_VERSIONS_PAGE_LIMIT}.`),2;let link=await resolveLinkedProject(client,projectName);if(typeof link=="number")return link;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name),versionsStamp=stamp_default(),environmentLabel=environment?` in ${environment}`:"";output_manager_default.spinner(`Fetching version history for ${import_chalk49.default.bold(flagArg)}${environmentLabel} in ${projectSlugLink}`);try{let{versions:versionList,next}=await getFlagVersions(client,project.id,flagArg,{environment,limit,cursor});if(output_manager_default.stopSpinner(),json)outputJson4(client,versionList,next);else if(versionList.length===0)output_manager_default.log(`No versions found for ${import_chalk49.default.bold(flagArg)}${environmentLabel} in ${projectSlugLink} ${import_chalk49.default.gray(versionsStamp())}`);else if(output_manager_default.log(`${(0,import_pluralize3.default)("version",versionList.length,!0)} found for ${import_chalk49.default.bold(flagArg)}${environmentLabel} in ${projectSlugLink} ${import_chalk49.default.gray(versionsStamp())}`),printVersionsTable(versionList),next){let nextCmd=buildNextPageCommand3(flagArg,flags,next);output_manager_default.print(`
|
|
254
|
+
`),printNextPageCommand(getCommandNamePlain(nextCmd))}}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}async function diffVersions(client,argv,telemetryClient){let parsedArgs,flagsSpecification=getFlagsSpecification(versionsDiffSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,revision=flags["--revision"],json=flags["--json"],projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error(`Missing required argument: flag. Usage: ${getCommandName("flags versions diff <flag> --revision <number>")}`),2;if(telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionRevision(revision),telemetryClient.trackCliFlagJson(json),revision===void 0||!Number.isInteger(revision)||revision<0)return output_manager_default.error("The --revision option must be a non-negative integer."),2;if(revision===0)return output_manager_default.error("Revision 0 has no previous revision to compare."),1;let link=await resolveLinkedProject(client,projectName);if(typeof link=="number")return link;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name),diffStamp=stamp_default();output_manager_default.spinner(`Fetching version diff for ${import_chalk49.default.bold(flagArg)} revision ${revision} in ${projectSlugLink}`);try{let{version,previousVersion,availableRevisionCount}=await getVersionPair(client,project.id,flagArg,revision);if(output_manager_default.stopSpinner(),!version)return output_manager_default.error(`${formatAvailableRevisionCount(availableRevisionCount)} Revision ${revision} was not found for ${import_chalk49.default.bold(flagArg)} in ${projectSlugLink}.`),1;if(!previousVersion)return output_manager_default.error(`${formatAvailableRevisionCount(availableRevisionCount)} Previous revision ${revision-1} was not found for ${import_chalk49.default.bold(flagArg)} in ${projectSlugLink}.`),1;json?outputDiffJson(client,flagArg,version,previousVersion,diffVersionData(previousVersion.data,version.data)):printVersionDiff({flagArg,projectSlugLink,version,previousVersion,diffStamp})}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}async function resolveLinkedProject(client,projectName){let link=await getLinkedFlagsProject(client,projectName);return link.status==="error"?link.exitCode:link.status==="not_linked"?(output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1):(client.config.currentTeam=link.org.type==="team"?link.org.id:void 0,link)}async function getVersionPair(client,projectId,flagArg,revision){let cursor,version,previousVersion,availableRevisions=new Set;do{let result=await getFlagVersions(client,projectId,flagArg,{limit:MAX_FLAG_VERSIONS_PAGE_LIMIT,cursor});for(let candidate of result.versions)availableRevisions.add(candidate.revision);if(version??=result.versions.find(candidate=>candidate.revision===revision),previousVersion??=result.versions.find(candidate=>candidate.revision===revision-1),version&&previousVersion)break;cursor=result.next??void 0}while(cursor);return{version,previousVersion,availableRevisionCount:availableRevisions.size}}function formatAvailableRevisionCount(count){return`Only ${(0,import_pluralize3.default)("revision",count,!0)} ${count===1?"is":"are"} available.`}function outputJson4(client,versions2,next){let jsonOutput={versions:versions2.map(version=>({...formatVersionSummary(version),data:version.data})),pagination:{next}};client.stdout.write(`${JSON.stringify(jsonOutput,null,2)}
|
|
255
|
+
`)}function outputDiffJson(client,flagArg,version,previousVersion,changes){let jsonOutput={flag:flagArg,revision:version.revision,previousRevision:previousVersion.revision,version:formatVersionSummary(version),previousVersion:formatVersionSummary(previousVersion),changes};client.stdout.write(`${JSON.stringify(jsonOutput,null,2)}
|
|
256
|
+
`)}function formatVersionSummary(version){return{id:version.id,flagId:version.flagId,revision:version.revision,author:getVersionAuthor(version),createdBy:version.createdBy??null,message:getVersionMessage(version),createdAt:version.createdAt,changedEnvironments:version.changedEnvironments}}function printVersionsTable(versions2){let headers=["Revision","Author","Message","Timestamp","Changed Environments"],rows=versions2.map(version=>[String(version.revision),getVersionAuthor(version)??import_chalk49.default.gray("-"),getVersionMessage(version)??import_chalk49.default.gray("-"),formatDate(version.createdAt),formatChangedEnvironments(version.changedEnvironments)]),table2=formatTable(headers,["r","l","l","l","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
257
|
+
${table2}
|
|
258
|
+
`)}function printVersionDiff({flagArg,projectSlugLink,version,previousVersion,diffStamp}){output_manager_default.log(`Changes in revision ${import_chalk49.default.bold(String(version.revision))} for ${import_chalk49.default.bold(flagArg)} compared with revision ${import_chalk49.default.bold(String(previousVersion.revision))} in ${projectSlugLink} ${import_chalk49.default.gray(diffStamp())}`),output_manager_default.print(`
|
|
259
|
+
${import_chalk49.default.dim("Author:")} ${getVersionAuthor(version)??import_chalk49.default.gray("-")}
|
|
260
|
+
`),output_manager_default.print(` ${import_chalk49.default.dim("Message:")} ${getVersionMessage(version)??import_chalk49.default.gray("-")}
|
|
261
|
+
`),output_manager_default.print(` ${import_chalk49.default.dim("Changed environments:")} ${formatChangedEnvironments(version.changedEnvironments)}
|
|
262
|
+
`);let formattedDiff=formatVersionDataDiff(previousVersion.data,version.data);if(formattedDiff.length===0){output_manager_default.print(`
|
|
263
|
+
${import_chalk49.default.gray("No changes detected.")}
|
|
264
|
+
|
|
265
|
+
`);return}output_manager_default.print(`
|
|
266
|
+
${formattedDiff}
|
|
267
|
+
|
|
268
|
+
`)}function formatChangedEnvironments(environments){return environments.length===0?import_chalk49.default.gray("-"):environments.join(", ")}function getVersionAuthor(version){return version.metadata?.creator?.name??version.createdBy??null}function getVersionMessage(version){return version.message?version.message:version.revision===0?"Flag created":null}function getVersionsHelpParent(){return{...versionsSubcommand,name:"flags versions"}}function buildNextPageCommand3(flagArg,flags,nextCursor){let environment=flags["--environment"],baseFlags=getCommandFlags(flags,["_","--next","--cursor","--environment","--json"]),environmentFlag=environment?` --environment ${quoteArg(environment)}`:"";return`flags versions ${quoteArg(flagArg)}${baseFlags}${environmentFlag} --next ${quoteArg(nextCursor)}`}async function getSdkKeys(client,projectId){output_manager_default.debug(`Fetching SDK keys for project ${projectId}`);let url=`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/sdk-keys`;return(await client.fetch(url)).data}async function createSdkKey(client,projectId,request){output_manager_default.debug(`Creating SDK key for project ${projectId}`);let url=`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/sdk-keys`;return await client.fetch(url,{method:"PUT",body:request})}async function deleteSdkKey(client,projectId,hashKey){output_manager_default.debug(`Deleting SDK key ${hashKey} for project ${projectId}`);let url=`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/sdk-keys/${encodeURIComponent(hashKey)}`;await client.fetch(url,{method:"DELETE",json:!1})}var FLAG_EVALUATIONS_METRIC="vercel.flags.evaluation",FLAG_EVALUATIONS_AGGREGATION="sum",EVALUATIONS_TIMEOUT_MS=5e3;async function countFlagEvaluations(client,options){let{ownerId,projectId,flagSlug,startTime,endTime}=options;try{let body={scope:{ownerId,projectIds:[projectId]},timeRange:{start:startTime.toISOString(),end:endTime.toISOString()},metrics:{value:{metric:FLAG_EVALUATIONS_METRIC,aggregation:FLAG_EVALUATIONS_AGGREGATION}},outputs:["value"],filter:`flagKey:${JSON.stringify(flagSlug)}`},response=await client.fetch(OBSERVABILITY_METRICS_PATH,{method:"POST",body:JSON.stringify(body),headers:{"Content-Type":"application/json"},accountId:ownerId,signal:AbortSignal.timeout(EVALUATIONS_TIMEOUT_MS),retry:{retries:0},bailOn429:!0}),total=0;for(let row of response.summary??[]){let value=Number(row.values.value);Number.isFinite(value)&&(total+=value)}return total}catch(err){return output_manager_default.debug(`Could not count evaluations for flag ${flagSlug}: ${err instanceof Error?err.message:String(err)}`),null}}var FlagsEvaluationsTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionSince(since){since&&this.trackCliOption({option:"since",value:this.redactedValue})}trackCliOptionUntil(until){until&&this.trackCliOption({option:"until",value:this.redactedValue})}trackCliOptionGranularity(granularity){granularity&&this.trackCliOption({option:"granularity",value:isFlagEvaluationsGranularity(granularity)?granularity:this.redactedValue})}trackCliOptionGroupBy(groupBy){groupBy&&groupBy.length>0&&this.trackCliOption({option:"group-by",value:groupBy.map(dimension=>isFlagEvaluationsDimension(dimension)?dimension:this.redactedValue).join(",")})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}};var FLAG_EVALUATIONS_ROLLUP=getRollupColumnName(FLAG_EVALUATIONS_METRIC,FLAG_EVALUATIONS_AGGREGATION),MAX_GROUPS=100,DEFAULT_IN_CODE_VARIANT="Default in Code",PERSONAL_ACCOUNT_MESSAGE="Flag evaluations are available for team-owned projects only. Select a team with --scope <team>.",FORBIDDEN_MESSAGE="You do not have permission to read feature flags for this project, which flag evaluations require.";function getCellValue(cell){return cell==null?"":String(cell)}function sanitizeGroupValue(value){return sanitizeForTerminal(value).replace(/\p{Cc}/gu,"")}function getEvaluationVariantValue(flag,variantId){return variantId?flag.variants.find(variant=>variant.id===variantId)?.value??null:DEFAULT_IN_CODE_VARIANT}function getVariantDisplayName(flag,variantId){if(!variantId||variantId==="(not set)"||variantId===DEFAULT_IN_CODE_VARIANT)return DEFAULT_IN_CODE_VARIANT;let variant=flag.variants.find(item=>item.id===variantId);return variant?formatVariantListSummary(variant):variantId}function getSdkKeyLabel(sdkKey){return sdkKey.label?`${sdkKey.label} (${sdkKey.environment})`:`${sdkKey.environment} ${sdkKey.type} key`}function getSdkKeyDisplayName(sdkKeys2,hashKey){if(!hashKey)return"(not set)";let sdkKey=sdkKeys2.get(hashKey);return sdkKey?getSdkKeyLabel(sdkKey):`${hashKey} (unknown or deleted key)`}function handleCommandError(client,error,jsonOutput){if(!jsonOutput)return printError(error),1;if(isAPIError(error))return outputError(client,!0,error.code||"API_ERROR",error.serverMessage||`API error (${error.status}).`);let message=error instanceof Error?error.message:String(error);return outputError(client,!0,"UNEXPECTED_ERROR",message)}function handleMetricsQueryError(client,error,jsonOutput){if(!isAPIError(error))return handleCommandError(client,error,jsonOutput);let genericForbidden=error.status===403&&(!error.serverMessage||error.serverMessage==="Forbidden"||error.serverMessage==="Response Error");return handleApiError(error,jsonOutput,client,genericForbidden?{403:{code:"FORBIDDEN",message:FORBIDDEN_MESSAGE}}:{})}function getGroupKey(row,fields){return JSON.stringify(fields.map(field=>getCellValue(row[field])))}function limitEvaluationGroups(response,fields){if(response.summary.length<=MAX_GROUPS)return{response,truncated:!1};let summary=response.summary.slice(0,MAX_GROUPS),visibleGroups=new Set(summary.map(row=>getGroupKey(row,fields)));return{response:{...response,summary,data:response.data?.filter(row=>visibleGroups.has(getGroupKey(row,fields)))},truncated:!0}}function formatEvaluationsJson(flag,dimensions,sdkKeys2,response,startTime,endTime,granularity,truncated){return`${JSON.stringify({flag:flag?.slug??null,...flag?{variants:Object.fromEntries(flag.variants.map(({id,value})=>[id,value]))}:{},groupBy:dimensions,startTime:startTime.toISOString(),endTime:endTime.toISOString(),granularity,truncated,buckets:(response.data??[]).map(row=>{let bucket={timestamp:row.timestamp};for(let dimension of dimensions){let value=getCellValue(row[FLAG_EVALUATIONS_DIMENSIONS[dimension].field]);switch(dimension){case"variant":bucket.variantId=value,bucket.variantValue=flag?getEvaluationVariantValue(flag,value):null;break;case"flag":bucket.flagKey=value;break;case"sdk-key":{let sdkKey=sdkKeys2.get(value);bucket.sdkKeyId=value,bucket.sdkKeyLabel=sdkKey?.label??null,bucket.sdkKeyEnvironment=sdkKey?.environment??null;break}case"client":bucket.clientName=value;break;case"environment":bucket.environment=value;break;case"reason":bucket.reason=value;break}}return bucket.evaluations=row[FLAG_EVALUATIONS_ROLLUP]??null,bucket})},null,2)}
|
|
269
|
+
`}async function evaluations(client,argv){let telemetry=new FlagsEvaluationsTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(evaluationsSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(error){return printError(error),2}let{args,flags}=parsedArgs,[flagArgument]=args,projectName=getProjectNameFromFlags(flags),since=flags["--since"],until=flags["--until"],granularity=flags["--granularity"],groupByArguments=flags["--group-by"]??[];telemetry.trackCliArgumentFlag(flagArgument),telemetry.trackCliOptionProject(projectName),telemetry.trackCliOptionSince(since),telemetry.trackCliOptionUntil(until),telemetry.trackCliOptionGranularity(granularity),telemetry.trackCliOptionGroupBy(groupByArguments.length>0?groupByArguments:void 0),telemetry.trackCliFlagJson(flags["--json"]);let jsonOutput=flags["--json"]??!1;if(granularity&&!isFlagEvaluationsGranularity(granularity))return outputError(client,jsonOutput,"INVALID_GRANULARITY",`Invalid granularity "${granularity}". Use one of: ${FLAG_EVALUATIONS_GRANULARITIES.join(", ")}.`);let invalidDimension=groupByArguments.find(dimension=>!isFlagEvaluationsDimension(dimension));if(invalidDimension!==void 0)return outputError(client,jsonOutput,"INVALID_GROUP_BY",`Invalid group-by dimension "${invalidDimension}". Use one of: ${FLAG_EVALUATIONS_DIMENSION_NAMES.join(", ")}.`);let dimensions=Array.from(new Set(groupByArguments.filter(isFlagEvaluationsDimension)));if(dimensions.length===0&&dimensions.push(flagArgument?"variant":"flag"),!flagArgument&&dimensions.includes("variant"))return outputError(client,jsonOutput,"MISSING_FLAG",`Grouping by variant needs a flag, because variants belong to one flag. Pass a flag: ${getCommandName("flags evaluations <flag> --group-by variant")}, or group the whole project by another dimension.`);let startTime,endTime,resolvedGranularity;try{if({startTime,endTime}=resolveTimeRange(since,until),startTime.getTime()>=endTime.getTime())throw new Error("The start time must be before the end time.");resolvedGranularity=computeGranularity(endTime.getTime()-startTime.getTime(),granularity),{startTime,endTime}=alignTimeRangeToGranularity(startTime,endTime,resolvedGranularity.duration)}catch(error){let message=error instanceof Error?error.message:String(error);return outputError(client,jsonOutput,"INVALID_TIME",message)}!jsonOutput&&resolvedGranularity.adjusted&&resolvedGranularity.notice&&output_manager_default.log(`Notice: ${resolvedGranularity.notice}`);let link;try{link=await getLinkedFlagsProject(client,projectName,{projectNotFoundHandling:jsonOutput?"return":"report"})}catch(error){return handleCommandError(client,error,jsonOutput)}if(link.status==="error")return jsonOutput?outputError(client,!0,"PROJECT_RESOLUTION_FAILED","Unable to resolve the requested Vercel project."):link.exitCode;if(link.status==="not_linked"){let code=projectName?"PROJECT_NOT_FOUND":"NOT_LINKED",message=projectName?`Project "${projectName}" was not found in the current scope.`:`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`;return outputError(client,jsonOutput,code,message)}if(link.org.type!=="team")return outputError(client,jsonOutput,"MISSING_SCOPE",PERSONAL_ACCOUNT_MESSAGE);client.config.currentTeam=link.org.id;let{project,org}=link,flag,sdkKeys2=new Map;try{let[resolvedFlag,resolvedSdkKeys]=await Promise.all([flagArgument?getFlag(client,project.id,flagArgument):void 0,dimensions.includes("sdk-key")?getSdkKeys(client,project.id).catch(error=>(output_manager_default.debug(`Could not load SDK keys: ${String(error)}`),jsonOutput||output_manager_default.warn("Could not load SDK key labels; SDK keys are shown as hashes."),[])):[]]);flag=resolvedFlag;for(let sdkKey of resolvedSdkKeys)sdkKeys2.set(sdkKey.hashKey,sdkKey)}catch(error){return handleCommandError(client,error,jsonOutput)}jsonOutput||output_manager_default.spinner("Querying flag evaluations...");let scope={type:"project",ownerId:org.id,projectIds:[project.id]},groupByFields=dimensions.map(dimension=>FLAG_EVALUATIONS_DIMENSIONS[dimension].field),response;try{let body=createCanonicalMetricsRequest({scope,metric:FLAG_EVALUATIONS_METRIC,selection:{metric:FLAG_EVALUATIONS_METRIC,aggregation:FLAG_EVALUATIONS_AGGREGATION},startTime,endTime,granularity:resolvedGranularity.duration,groupBy:groupByFields,filter:flag?`flagKey:${JSON.stringify(flag.slug)}`:void 0,limit:MAX_GROUPS+1,orderBy:"value",orderDirection:"desc"}),canonicalResponse=await client.fetch(OBSERVABILITY_METRICS_PATH,{method:"POST",body:JSON.stringify(body),headers:{"Content-Type":"application/json"},accountId:org.id,bailOn429:!0});response=canonicalResponseToMetricsResponse(canonicalResponse,FLAG_EVALUATIONS_ROLLUP,"value","desc")}catch(error){return handleMetricsQueryError(client,error,jsonOutput)}finally{jsonOutput||output_manager_default.stopSpinner()}let limited=limitEvaluationGroups(response,groupByFields);if(jsonOutput)return client.stdout.write(formatEvaluationsJson(flag,dimensions,sdkKeys2,limited.response,startTime,endTime,resolvedGranularity.duration,limited.truncated)),0;let headings=dimensions.map(dimension=>FLAG_EVALUATIONS_DIMENSIONS[dimension].heading);if(limited.truncated){let subject=headings.length===1?headings[0].toLowerCase():"groups";output_manager_default.warn(`Results are limited to the ${MAX_GROUPS} most evaluated ${subject}.`)}let headingToDimension=new Map(dimensions.map((dimension,index)=>[headings[index],dimension]));return client.stdout.write(formatText({...limited.response,data:limited.response.data?.map(row=>({...row,...Object.fromEntries(dimensions.map((dimension,index)=>[headings[index],getCellValue(row[FLAG_EVALUATIONS_DIMENSIONS[dimension].field])]))}))},{metric:FLAG_EVALUATIONS_METRIC,metricUnit:"count",aggregation:FLAG_EVALUATIONS_AGGREGATION,groupBy:headings,scope,projectName:project.name,teamName:org.slug,periodStart:startTime.toISOString(),periodEnd:endTime.toISOString(),granularity:resolvedGranularity.duration,presentation:{compact:!0,formatGroupValue:(field,value)=>{switch(headingToDimension.get(field)){case"variant":return sanitizeGroupValue(flag?getVariantDisplayName(flag,value):value);case"sdk-key":return sanitizeGroupValue(getSdkKeyDisplayName(sdkKeys2,value));default:return sanitizeGroupValue(value)||"(not set)"}}}})),0}var import_chalk50=__toESM(require_source(),1);async function createFlag(client,projectId,request){let url=`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/flags`;output_manager_default.debug(`Creating feature flag ${request.slug} for project ${projectId}`),output_manager_default.debug(`API endpoint: PUT ${url}`),output_manager_default.debug(`Request body: ${JSON.stringify(request,null,2)}`);try{let response=await client.fetch(url,{method:"PUT",body:request});return output_manager_default.debug(`Response: ${JSON.stringify(response,null,2)}`),response}catch(err){if(output_manager_default.debug("API error occurred"),err instanceof Error){output_manager_default.debug(`Error message: ${err.message}`),output_manager_default.debug(`Error name: ${err.name}`),output_manager_default.debug(`Error stack: ${err.stack}`);let errWithBody=err;errWithBody.status&&output_manager_default.debug(`Error status: ${errWithBody.status}`),errWithBody.body&&output_manager_default.debug(`Error body: ${JSON.stringify(errWithBody.body,null,2)}`)}throw err}}var FlagsCreateTelemetryClient=class extends TelemetryClient{trackCliArgumentSlug(slug){slug&&this.trackCliArgument({arg:"slug",value:this.redactedValue})}trackCliOptionKind(kind){kind&&this.trackCliOption({option:"kind",value:kind})}trackCliOptionDescription(description){description&&this.trackCliOption({option:"description",value:this.redactedValue})}trackCliOptionVariant(variants){variants?.length&&this.trackCliOption({option:"variant",value:this.redactedValue})}trackCliOptionDefaultVariant(defaultVariant){defaultVariant&&this.trackCliOption({option:"default-variant",value:this.redactedValue})}trackCliOptionEnvironmentVariant(environmentVariants){if(environmentVariants?.length){let environments=environmentVariants.map(input=>input.split("=")[0].trim()),allStandard=environments.every(environment=>STANDARD_ENVIRONMENTS.includes(environment));this.trackCliOption({option:"environment-variant",value:allStandard?STANDARD_ENVIRONMENTS.filter(environment=>environments.includes(environment)).join(","):this.redactedValue})}}};import{randomBytes}from"node:crypto";var VARIANT_ID_ALPHABET="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";function generateVariantId(size=21){let bytes=randomBytes(size),id="";for(let index=0;index<size;index++)id+=VARIANT_ID_ALPHABET[bytes[index]%VARIANT_ID_ALPHABET.length];return id}function parseVariantInput(input,kind,index){let{rawValue,rawLabel}=splitVariantInput(input,kind),validationError=validateVariantValue(rawValue,kind);if(validationError)throw new Error(`Invalid variant "${input}": ${validationError}`);return{id:generateVariantId(),value:parseVariantValue2(rawValue,kind),label:getVariantLabel(rawLabel,kind,index),description:""}}function validateVariantValue(value,kind){if(!value.trim())return"Variant value cannot be empty";if(kind==="boolean"){let loweredValue=value.toLowerCase();if(loweredValue!=="true"&&loweredValue!=="false")return"Boolean variant values must be true or false"}if(kind==="number"){let parsed=Number(value);if(!Number.isFinite(parsed))return"Number variants must be valid numeric values"}return kind==="json"&&!isValidJsonVariantValue(value)?"JSON variant values must be valid JSON":null}function splitVariantInput(input,kind){if(kind!=="json"){let separatorIndex=input.indexOf("=");return{rawValue:separatorIndex===-1?input.trim():input.slice(0,separatorIndex).trim(),rawLabel:separatorIndex===-1?void 0:input.slice(separatorIndex+1).trim()||void 0}}let trimmed=input.trim();if(isValidJsonVariantValue(trimmed))return{rawValue:trimmed};for(let index=trimmed.length-1;index>=0;index--){if(trimmed[index]!=="=")continue;let rawValue=trimmed.slice(0,index).trim(),rawLabel=trimmed.slice(index+1).trim();if(!(!rawValue||!isValidJsonVariantValue(rawValue)))return{rawValue,rawLabel:rawLabel||void 0}}return{rawValue:trimmed}}function getVariantLabel(rawLabel,kind,index){if(rawLabel)return rawLabel;if(kind==="json")return`Variant ${index+1}`}function parseVariantValue2(value,kind){return kind==="number"?Number(value):kind==="json"?JSON.parse(value):value}function isValidJsonVariantValue(value){try{return JSON.parse(value),!0}catch{return!1}}function normalizeOptionalInput(input){let value=input?.trim();return value||void 0}async function resolveOptionalInput(client,input,defaultValue,promptMessage){let value=normalizeOptionalInput(input);if(value!==void 0)return value;if(!client.stdin.isTTY)return defaultValue;let response=await client.input.text({message:promptMessage,default:defaultValue});return normalizeOptionalInput(response)||defaultValue}async function create(client,argv){let telemetryClient=new FlagsCreateTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(createSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[slug]=args;if(!slug)return output_manager_default.error("Please provide a slug for the feature flag"),output_manager_default.log(`Example: ${getCommandName("flags create my-feature")}`),2;let kind=flags["--kind"]||"boolean",description=flags["--description"],variantInputs=flags["--variant"]||[],defaultVariantSelector=normalizeOptionalInput(flags["--default-variant"]),environmentVariantInputs=flags["--environment-variant"]||[],projectName=getProjectNameFromFlags(flags);if(telemetryClient.trackCliArgumentSlug(slug),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionKind(kind),telemetryClient.trackCliOptionDescription(description),telemetryClient.trackCliOptionVariant(variantInputs),telemetryClient.trackCliOptionDefaultVariant(defaultVariantSelector),telemetryClient.trackCliOptionEnvironmentVariant(environmentVariantInputs),kind!=="boolean"&&kind!=="string"&&kind!=="number"&&kind!=="json")return output_manager_default.error(`Invalid kind: ${kind}. Must be one of: boolean, string, number, json`),2;let environmentVariantSelectors;try{environmentVariantSelectors=parseEnvironmentVariantInputs(environmentVariantInputs)}catch(err){return output_manager_default.error(err.message),2}let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link,projectSlugLink=formatProject(link.org.slug,project.name),variants;try{variants=await getVariants(client,kind,variantInputs)}catch(err){return output_manager_default.error(err.message),1}let environments;try{environments=resolveEnvironments(kind,variants,defaultVariantSelector,environmentVariantSelectors)}catch(err){return output_manager_default.error(err.message),2}let request={slug,kind,description:description||"",variants,environments};try{output_manager_default.spinner("Creating feature flag...");let flag=await createFlag(client,project.id,request);output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk50.default.bold(flag.slug)} created successfully`),printFlagDetails({flag,projectSlugLink,orgSlug:link.org.slug,projectName:project.name,showTimestamps:!1})}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}async function getVariants(client,kind,variantInputs){if(kind==="boolean"){if(variantInputs.length>0)throw new Error("Boolean flags always use true/false variants. Omit --variant when creating a boolean flag.");return getDefaultVariants(kind)}if(variantInputs.length>0)return variantInputs.map((input,index)=>parseVariantInput(input,kind,index));if(!client.stdin.isTTY)throw new Error("Missing required flag --variant. Use --variant <value>[=label] (repeat as needed), or run interactively in a terminal.");return collectVariantsInteractively(client,kind)}async function collectVariantsInteractively(client,kind){let variants=[],addAnother=!0;for(;addAnother||variants.length===0;){let variantNumber=variants.length+1,valueInput=await client.input.text({message:kind==="json"?`Enter JSON value for variant ${variantNumber}:`:`Enter value for variant ${variantNumber}:`,validate:value=>{let result=validateVariantValue(value,kind);return result===null?!0:result}}),label=await client.input.text({message:`Enter an optional label for variant ${variantNumber}:`});variants.push(parseVariantInput(formatVariantInput(valueInput,label),kind,variants.length)),addAnother=await client.input.confirm("Add another variant?",!1)}return variants}function parseEnvironmentVariantInputs(inputs){let selectors={};for(let input of inputs){let separatorIndex=input.indexOf("="),environment=separatorIndex===-1?input.trim():input.slice(0,separatorIndex).trim(),variant=separatorIndex===-1?"":input.slice(separatorIndex+1).trim();if(!environment||!variant)throw new Error(`Invalid --environment-variant ${import_chalk50.default.bold(input)}. Use ENVIRONMENT=VARIANT, for example development=true.`);if(!STANDARD_ENVIRONMENTS.includes(environment))throw new Error(`Invalid environment in --environment-variant ${import_chalk50.default.bold(input)}. Must be one of: ${STANDARD_ENVIRONMENTS.join(", ")}`);let standardEnvironment=environment;if(selectors[standardEnvironment]!==void 0)throw new Error(`--environment-variant was passed more than once for ${import_chalk50.default.bold(environment)}. Pass each environment once.`);selectors[standardEnvironment]=variant}return selectors}function resolveEnvironments(kind,variants,defaultVariantSelector,environmentVariantSelectors){let defaultVariant=defaultVariantSelector?resolveVariantOrThrow(defaultVariantSelector,variants,"--default-variant"):void 0,environments={};for(let environment of STANDARD_ENVIRONMENTS){let selector=environmentVariantSelectors[environment],variant=selector?resolveVariantOrThrow(selector,variants,"--environment-variant",`${environment}=${selector}`):defaultVariant??getDefaultEnvironmentVariant(kind,variants,environment);environments[environment]=createEnvironmentConfig(variant.id,variant.id,!1)}return environments}function getDefaultEnvironmentVariant(kind,variants,environment){return kind==="boolean"&&environment==="development"?variants[1]:variants[0]}function createEnvironmentConfig(pausedVariantId,fallthroughVariantId,active){return{revision:0,active,pausedOutcome:{type:"variant",variantId:pausedVariantId},fallthrough:{type:"variant",variantId:fallthroughVariantId},rules:[],reuse:{active:!1,environment:""}}}function formatVariantInput(valueInput,label){let trimmedLabel=label.trim();return trimmedLabel?`${valueInput}=${trimmedLabel}`:valueInput}function getDefaultVariants(kind){switch(kind){case"boolean":return[{id:generateVariantId(),value:!1,label:"Off",description:"not enabled"},{id:generateVariantId(),value:!0,label:"On",description:"enabled"}];case"string":case"number":case"json":throw new Error(`Default variants are not supported for kind: ${kind}`)}}var import_open=__toESM(require_open(),1);var FlagsOpenTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}};async function openFlag(client,argv){let telemetryClient=new FlagsOpenTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(openSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg,extraArg]=args,projectName=getProjectNameFromFlags(flags);if(extraArg)return output_manager_default.error(`Too many arguments. Usage: ${getCommandName("flags open [flag]")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link;try{let url=getFlagsDashboardUrl(org.slug,project.name),label="feature flags dashboard";if(flagArg){output_manager_default.spinner("Fetching flag...");let flag=await getFlag(client,project.id,flagArg);output_manager_default.stopSpinner(),url=getFlagDashboardUrl(org.slug,project.name,flag.slug),label=`feature flag ${flag.slug}`}client.stdout.isTTY?(output_manager_default.log(`Opening ${label} in your browser...`),output_manager_default.log(`Visit this URL if the browser does not open: ${url}`),(0,import_open.default)(url).catch(()=>{})):client.stdout.write(`${url}
|
|
270
|
+
`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function logArchivedFlagNotice(flag){flag.state==="archived"&&output_manager_default.log("This flag remains archived. Changes will not affect flag evaluation until it is unarchived.")}var import_chalk51=__toESM(require_source(),1),import_fast_deep_equal3=__toESM(require_fast_deep_equal(),1);function findVariantReferencePaths(flag,variantIds){let trackedVariantIds=new Set(variantIds),references=new Map;for(let[environmentName,environmentConfig]of Object.entries(flag.environments))collectEnvironmentReferencePaths(environmentName,environmentConfig,trackedVariantIds,references);return new Map(Array.from(references.entries(),([variantId,paths])=>[variantId,Array.from(paths).sort()]))}function collectEnvironmentReferencePaths(environmentName,environmentConfig,trackedVariantIds,references){collectOutcomeReferencePaths(environmentConfig.pausedOutcome,`${environmentName}.pausedOutcome`,trackedVariantIds,references),collectOutcomeReferencePaths(environmentConfig.fallthrough,`${environmentName}.fallthrough`,trackedVariantIds,references);for(let[ruleIndex,rule]of environmentConfig.rules.entries())collectOutcomeReferencePaths(rule.outcome,`${environmentName}.rules[${ruleIndex}].outcome`,trackedVariantIds,references);if(environmentConfig.targets){for(let[variantId,entityKinds]of Object.entries(environmentConfig.targets))if(trackedVariantIds.has(variantId))for(let[entityKind,attributes]of Object.entries(entityKinds))for(let[attribute,values]of Object.entries(attributes))values.length!==0&&addReferencePath(references,variantId,`${environmentName}.targets.${entityKind}.${attribute}`)}}function collectOutcomeReferencePaths(outcome,basePath,trackedVariantIds,references){if(outcome)switch(outcome.type){case"variant":trackedVariantIds.has(outcome.variantId)&&addReferencePath(references,outcome.variantId,basePath);return;case"split":collectSplitOutcomeReferencePaths(outcome,basePath,trackedVariantIds,references);return;case"rollout":collectRolloutOutcomeReferencePaths(outcome,basePath,trackedVariantIds,references);return;default:return}}function collectSplitOutcomeReferencePaths(outcome,basePath,trackedVariantIds,references){trackedVariantIds.has(outcome.defaultVariantId)&&addReferencePath(references,outcome.defaultVariantId,`${basePath}.default`);for(let variantId of Object.keys(outcome.weights))trackedVariantIds.has(variantId)&&addReferencePath(references,variantId,`${basePath}.weights.${variantId}`)}function collectRolloutOutcomeReferencePaths(outcome,basePath,trackedVariantIds,references){trackedVariantIds.has(outcome.rollFromVariantId)&&addReferencePath(references,outcome.rollFromVariantId,`${basePath}.from`),trackedVariantIds.has(outcome.rollToVariantId)&&addReferencePath(references,outcome.rollToVariantId,`${basePath}.to`),trackedVariantIds.has(outcome.defaultVariantId)&&addReferencePath(references,outcome.defaultVariantId,`${basePath}.default`)}function addReferencePath(references,variantId,path){let paths=references.get(variantId);paths||(paths=new Set,references.set(variantId,paths)),paths.add(path)}var FlagsUpdateTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionVariant(variant){variant&&this.trackCliOption({option:"variant",value:this.redactedValue})}trackCliOptionValue(value){value&&this.trackCliOption({option:"value",value:this.redactedValue})}trackCliOptionLabel(label){label&&this.trackCliOption({option:"label",value:this.redactedValue})}trackCliOptionAddVariant(addVariant){addVariant?.length&&this.trackCliOption({option:"add-variant",value:this.redactedValue})}trackCliOptionRemoveVariant(removeVariant){removeVariant?.length&&this.trackCliOption({option:"remove-variant",value:this.redactedValue})}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}trackCliFlagYes(yes){yes&&this.trackCliFlag("yes")}};var DEFAULT_UPDATE_MESSAGE="Updated via CLI";async function update(client,argv){let telemetryClient=new FlagsUpdateTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(updateSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,variantSelector=normalizeOptionalInput(flags["--variant"]),valueInput=normalizeOptionalInput(flags["--value"]),label=normalizeOptionalInput(flags["--label"]),addVariantInputs=flags["--add-variant"]||[],removeVariantSelectors=flags["--remove-variant"]||[],skipConfirmation=flags["--yes"],message=normalizeOptionalInput(flags["--message"]),projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to update"),output_manager_default.log(`Example: ${getCommandName('flags update my-feature --variant control --value welcome-back --label "Welcome back"')}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionVariant(variantSelector),telemetryClient.trackCliOptionValue(valueInput),telemetryClient.trackCliOptionLabel(label),telemetryClient.trackCliOptionAddVariant(addVariantInputs),telemetryClient.trackCliOptionRemoveVariant(removeVariantSelectors),telemetryClient.trackCliOptionMessage(message),telemetryClient.trackCliFlagYes(skipConfirmation);let hasVariantMutations=addVariantInputs.length>0||removeVariantSelectors.length>0;if(hasVariantMutations&&hasLegacyVariantEditOptions(variantSelector,valueInput,label))return output_manager_default.error("Cannot mix --variant, --value, or --label with --add-variant or --remove-variant."),1;let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{return hasVariantMutations?await updateFlagVariants(client,project.id,flagArg,{addVariantInputs,removeVariantSelectors,skipConfirmation:skipConfirmation||!1,message}):await updateExistingVariant(client,project.id,flagArg,{selector:variantSelector,valueInput,label,message})}catch(err){return output_manager_default.stopSpinner(),isAPIError(err)&&err.status===412?(output_manager_default.error("Flag changed while updating; re-run the command."),1):(printError(err),1)}}async function updateExistingVariant(client,projectId,flagArg,input){output_manager_default.spinner("Fetching flag...");let{flag,etag}=await fetchFlagForUpdate(client,projectId,flagArg);if(output_manager_default.stopSpinner(),logArchivedFlagNotice(flag),rejectExperimentOwnedVariantUpdate(flag))return 1;let variantUpdate=await collectVariantUpdate(client,flag,input),{variants,changedVariants}=applyVariantUpdates(flag,[variantUpdate]);if(changedVariants.length===0)return output_manager_default.warn(`Flag ${import_chalk51.default.bold(flag.slug)} is already up to date`),0;let updateMessage=await resolveOptionalInput(client,input.message,DEFAULT_UPDATE_MESSAGE,"Enter a message for this update:");output_manager_default.spinner("Updating flag..."),await updateFlag(client,projectId,flagArg,{variants,message:updateMessage},{ifMatch:etag}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk51.default.bold(flag.slug)} has been updated`);for(let variant of changedVariants)output_manager_default.log(` ${import_chalk51.default.dim("Variant:")} ${formatVariantForDisplay(variant)}`);return 0}async function updateFlagVariants(client,projectId,flagArg,input){output_manager_default.spinner("Fetching flag...");let{flag,etag}=await fetchFlagForUpdate(client,projectId,flagArg);if(output_manager_default.stopSpinner(),logArchivedFlagNotice(flag),rejectExperimentOwnedVariantUpdate(flag))return 1;if(flag.kind==="boolean")return output_manager_default.error("Boolean flags do not support --add-variant or --remove-variant."),1;let plan=buildVariantMutationPlan(flag,input.addVariantInputs,input.removeVariantSelectors);if(plan.removedVariants.length>0&&!await confirmVariantRemoval(client,flag,plan.removedVariants,input.skipConfirmation))return output_manager_default.log("Aborted"),0;let updateMessage=await resolveOptionalInput(client,input.message,DEFAULT_UPDATE_MESSAGE,"Enter a message for this update:");output_manager_default.spinner("Updating flag..."),await updateFlag(client,projectId,flagArg,{variants:plan.variants,message:updateMessage},{ifMatch:etag}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk51.default.bold(flag.slug)} has been updated`);for(let variant of plan.addedVariants)output_manager_default.log(` ${import_chalk51.default.dim("Added:")} ${formatVariantForLog(variant)}`);for(let variant of plan.removedVariants)output_manager_default.log(` ${import_chalk51.default.dim("Removed:")} ${formatVariantForLog(variant)}`);return 0}function rejectExperimentOwnedVariantUpdate(flag){if(!flag.experiment)return!1;let experiment=flag.experiment.id?`experiment ${import_chalk51.default.bold(flag.experiment.id)}`:"an experiment";return output_manager_default.error(`Flag ${import_chalk51.default.bold(flag.slug)} is managed by ${experiment}. Update its variants with ${getCommandName("experiments update <experiment> --file <file>")}.`),!0}function hasLegacyVariantEditOptions(variantSelector,valueInput,label){return variantSelector!==void 0||valueInput!==void 0||label!==void 0}function buildVariantMutationPlan(flag,addVariantInputs,removeVariantSelectors){let removedVariants=resolveRemovedVariants(flag.variants,removeVariantSelectors);assertVariantRemovalsAreAllowed(flag,removedVariants);let baseIndex=flag.variants.length-removedVariants.length,addedVariants=parseAddedVariants(flag,addVariantInputs,baseIndex),removedVariantIds=new Set(removedVariants.map(variant=>variant.id)),variants=flag.variants.filter(variant=>!removedVariantIds.has(variant.id)).map(variant=>({...variant}));return variants.push(...addedVariants),assertUniqueVariantValues(variants),{variants,addedVariants,removedVariants}}function parseAddedVariants(flag,addVariantInputs,baseIndex){let kind=flag.kind;if(kind==="boolean")throw new Error("Boolean flags do not support adding variants.");return addVariantInputs.map((input,index)=>parseVariantInput(input,kind,baseIndex+index))}function resolveRemovedVariants(variants,removeVariantSelectors){let removedVariantIds=new Set;return removeVariantSelectors.map(selector=>{let result=resolveVariant(selector,variants);if(result.error||!result.variant)throw new Error(result.error||`Variant "${selector}" not found`);if(removedVariantIds.has(result.variant.id))throw new Error(`Duplicate --remove-variant selector ${import_chalk51.default.bold(selector)} resolves to ${formatVariantForLog(result.variant)}.`);return removedVariantIds.add(result.variant.id),result.variant})}function assertVariantRemovalsAreAllowed(flag,removedVariants){let referencePaths=findVariantReferencePaths(flag,removedVariants.map(variant=>variant.id));if(referencePaths.size===0)return;let referencedVariants=removedVariants.filter(variant=>referencePaths.has(variant.id)),detailLines=referencedVariants.map(variant=>{let paths=referencePaths.get(variant.id)??[];return` - ${formatVariantForLog(variant)} referenced by ${paths.join(", ")}`});throw new Error(`Cannot remove variant${referencedVariants.length===1?"":"s"} because ${referencedVariants.length===1?"it is":"they are"} still referenced:
|
|
271
|
+
${detailLines.join(`
|
|
272
|
+
`)}`)}function assertUniqueVariantValues(variants){for(let index=0;index<variants.length;index++){let variant=variants[index],duplicateVariant=variants.slice(0,index).find(candidate=>(0,import_fast_deep_equal3.default)(candidate.value,variant.value));if(duplicateVariant)throw new Error(`Variant value ${formatVariantValue(variant.value)} would be duplicated by ${formatVariantForLog(duplicateVariant)} and ${formatVariantForLog(variant)}.`)}}async function confirmVariantRemoval(client,flag,removedVariants,skipConfirmation){if(skipConfirmation)return!0;if(!client.stdin.isTTY)throw new Error("Missing required flag --yes. Use --yes to skip the removal confirmation prompt in non-interactive mode.");let promptLines=removedVariants.map(variant=>` - ${formatVariantForLog(variant)}`).join(`
|
|
273
|
+
`);return client.input.confirm(`Remove ${removedVariants.length} variant${removedVariants.length===1?"":"s"} from ${import_chalk51.default.bold(flag.slug)}?
|
|
274
|
+
${promptLines}`,!1)}function formatVariantForLog(variant){return`${formatVariantForDisplay(variant)} ${import_chalk51.default.dim(`[id: ${variant.id}]`)}`}async function collectVariantUpdate(client,flag,input){let selectedVariant=await resolveSelectedVariant(client,flag,input.selector),nextValueInput=input.valueInput,nextLabel=input.label;return flag.kind!=="boolean"&&nextValueInput===void 0&&client.stdin.isTTY&&(nextValueInput=await promptForVariantValueUpdate(client,flag,selectedVariant)),nextLabel===void 0&&client.stdin.isTTY&&(nextLabel=await promptForVariantLabelUpdate(client,selectedVariant)),client.stdin.isTTY||ensureVariantUpdateInput(nextValueInput,nextLabel),{selector:selectedVariant.id,valueInput:nextValueInput,label:nextLabel}}function ensureVariantUpdateInput(valueInput,label){if(!valueInput&&!label)throw new Error("At least one of --value or --label must be provided. Use --value <VALUE>, --label <LABEL>, or run interactively in a terminal.")}async function resolveSelectedVariant(client,flag,selector){if(selector){let result=resolveVariant(selector,flag.variants);if(result.error||!result.variant)throw new Error(result.error||`Variant "${selector}" not found`);return result.variant}if(!client.stdin.isTTY)throw new Error("Missing required flag --variant. Use --variant <VARIANT>, or run interactively in a terminal.");let selectedVariantId=await client.input.select({message:"Select a variant to update:",choices:flag.variants.map(variant=>({name:formatVariantForLog(variant),value:variant.id}))}),selectedVariant=flag.variants.find(v=>v.id===selectedVariantId);if(!selectedVariant)throw new Error("No variant selected");return selectedVariant}async function promptForVariantValueUpdate(client,flag,selectedVariant){let valueResponse=await client.input.text({message:`Enter a new value for ${formatVariantForDisplay(selectedVariant)} (press Enter to keep ${formatVariantValue(selectedVariant.value)}):`,validate:value=>{if(!value.trim())return!0;let result=validateVariantValue(value,flag.kind);return result===null?!0:result}});return normalizeOptionalInput(valueResponse)}async function promptForVariantLabelUpdate(client,selectedVariant){let currentLabel=selectedVariant.label,labelResponse=await client.input.text({message:currentLabel?`Enter a new label for ${formatVariantForDisplay(selectedVariant)} (press Enter to keep ${JSON.stringify(currentLabel)}):`:`Enter an optional label for ${formatVariantForDisplay(selectedVariant)} (press Enter to skip):`});return normalizeOptionalInput(labelResponse)}function applyVariantUpdates(flag,updates){let variants=flag.variants.map(variant=>({...variant})),changedVariantIds=new Set;for(let update2 of updates){let result=resolveVariant(update2.selector,variants);if(result.error||!result.variant)throw new Error(result.error||`Variant "${update2.selector}" not found`);let nextValue=update2.valueInput!==void 0?parseUpdatedVariantValue(update2.valueInput,flag.kind,result.variant):result.variant.value,nextLabel=update2.label??result.variant.label,variantIndex=variants.findIndex(v=>v.id===result.variant.id),existingVariant=variants[variantIndex],hasChanged=!(0,import_fast_deep_equal3.default)(existingVariant.value,nextValue)||existingVariant.label!==nextLabel;variants[variantIndex]={...existingVariant,value:nextValue,label:nextLabel},hasChanged&&changedVariantIds.add(existingVariant.id)}return{variants,changedVariants:variants.filter(variant=>changedVariantIds.has(variant.id))}}function parseUpdatedVariantValue(valueInput,kind,existingVariant){let validationError=validateVariantValue(valueInput,kind);if(validationError)throw new Error(validationError);if(kind==="boolean"){let nextValue=valueInput.toLowerCase()==="true";if(nextValue!==existingVariant.value)throw new Error("Boolean variant values cannot be changed. You can update the label only.");return nextValue}return kind==="number"?Number(valueInput):kind==="json"?JSON.parse(valueInput):valueInput}var import_chalk53=__toESM(require_source(),1);var import_chalk52=__toESM(require_source(),1);async function resolveFlagEnvironment(client,flag,environment,promptMessage,options={}){let nextEnvironment=environment;if(!nextEnvironment){if(!canPrompt(client))throw new Error("Missing required flag --environment. Use --environment <ENV>, or run interactively in a terminal.");let availableEnvironments=STANDARD_ENVIRONMENTS.filter(env=>Object.prototype.hasOwnProperty.call(flag.environments,env));if(availableEnvironments.length===0)throw new Error("No valid environments found for this flag");options.showEnvironmentDetails&&printFlagEnvironmentDetails(flag,void 0,availableEnvironments),nextEnvironment=await client.input.select({message:promptMessage,choices:availableEnvironments.map(env=>({name:options.decorateChoices===!1?env:formatEnvironmentChoiceLabel(env,flag.environments[env]),value:env}))})}if(!STANDARD_ENVIRONMENTS.includes(nextEnvironment))throw new Error(`Invalid environment: ${nextEnvironment}. Must be one of: ${STANDARD_ENVIRONMENTS.join(", ")}`);if(!flag.environments[nextEnvironment])throw new Error(`Environment ${nextEnvironment} not found for this flag`);return nextEnvironment}function formatEnvironmentChoiceLabel(envName,envConfig){let status2=envConfig?.active?import_chalk52.default.green("active"):import_chalk52.default.yellow("paused");return`${envName} (${status2})`}function isPausingEnvironmentToVariant(envConfig,variantId){return!envConfig.active&&envConfig.pausedOutcome?.variantId===variantId}function buildTargetingVariantEnvironmentConfig(envConfig,variantId){return buildOutcomeEnvConfig(envConfig,{outcome:{type:"variant",variantId},defaultVariantId:variantId})}function buildResumeTargetingEnvironmentConfig(flag,environment){let envConfig=flag.environments[environment],fallthrough=resolveEffectiveFallthrough(flag,environment),defaultVariantId=getFallthroughDefaultVariantId(fallthrough);return buildOutcomeEnvConfig(envConfig,{outcome:fallthrough,defaultVariantId})}function resolveEffectiveFallthrough(flag,environment){let envConfig=flag.environments[environment],inheritedFrom=envConfig.reuse?.active?envConfig.reuse.environment:void 0;if(inheritedFrom){let inheritedConfig=flag.environments[inheritedFrom];if(inheritedConfig)return structuredClone(inheritedConfig.fallthrough)}return structuredClone(envConfig.fallthrough)}function isUsableFallthrough(fallthrough,variants){let variantIds=new Set(variants.map(variant=>variant.id));return fallthrough.type==="variant"?variantIds.has(fallthrough.variantId):fallthrough.type==="split"?variantIds.has(fallthrough.defaultVariantId):fallthrough.type==="experiment"?!1:variantIds.has(fallthrough.defaultVariantId)&&variantIds.has(fallthrough.rollFromVariantId)&&variantIds.has(fallthrough.rollToVariantId)}function getFallthroughDefaultVariantId(fallthrough){if(fallthrough.type==="variant")return fallthrough.variantId;if(fallthrough.type==="experiment")throw new Error("Experiment outcomes do not have a default variant");return fallthrough.defaultVariantId}function buildPausedEnvironmentConfig(envConfig,variantId){return{...envConfig,active:!1,pausedOutcome:{type:"variant",variantId}}}function buildOutcomeEnvConfig(envConfig,options){let{reuse,...restConfig}=envConfig,nextConfig={...restConfig,active:!0,pausedOutcome:envConfig.pausedOutcome??{type:"variant",variantId:options.defaultVariantId},fallthrough:options.outcome};return reuse&&(nextConfig.reuse={...reuse,active:!1}),nextConfig}function getBooleanVariant(flag,value){let variant=flag.variants.find(candidate=>candidate.value===value);if(!variant)throw new Error(`Flag ${import_chalk52.default.bold(flag.slug)} is missing the standard boolean variants`);return variant}async function resolveFlagUpdateMessage(client,message,defaultMessage){if(message!==void 0)return message;if(!canPrompt(client))return defaultMessage;let response=await client.input.text({message:"Enter a message for this update:",default:defaultMessage});return normalizeOptionalInput(response)||defaultMessage}var FlagsSetTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:STANDARD_ENVIRONMENTS.includes(environment)?environment:this.redactedValue})}trackCliOptionVariant(variant){variant&&this.trackCliOption({option:"variant",value:this.redactedValue})}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}};async function set(client,argv){let telemetryClient=new FlagsSetTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(setSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],variantSelector=normalizeOptionalInput(flags["--variant"]),message=normalizeOptionalInput(flags["--message"]),projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to set"),output_manager_default.log(`Example: ${getCommandName("flags set my-feature --environment production --variant true")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionVariant(variantSelector),telemetryClient.trackCliOptionMessage(message);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{output_manager_default.spinner("Fetching flag...");let flag=await getFlag(client,project.id,flagArg);output_manager_default.stopSpinner(),logArchivedFlagNotice(flag);let selectedEnvironment=await resolveFlagEnvironment(client,flag,environment,"Select an environment to set the variant in:",{showEnvironmentDetails:!0,decorateChoices:!1}),selectedVariant=await resolveVariantToSet(client,flag,variantSelector),envConfig=flag.environments[selectedEnvironment];if(isPausingEnvironmentToVariant(envConfig,selectedVariant.id))return output_manager_default.warning(`Flag ${import_chalk53.default.bold(flag.slug)} is already ${flag.state==="archived"?"configured with":"serving"} ${formatVariantForDisplay(selectedVariant)} in ${selectedEnvironment}`),0;let presentation=getSetPresentation(flag,selectedVariant),updateMessage=await resolveFlagUpdateMessage(client,message,presentation.defaultMessage(selectedEnvironment));output_manager_default.spinner(presentation.spinner(selectedEnvironment)),await updateFlag(client,project.id,flagArg,{environments:{[selectedEnvironment]:buildPausedEnvironmentConfig(envConfig,selectedVariant.id)},message:updateMessage}),output_manager_default.stopSpinner(),output_manager_default.success(flag.state==="archived"?`Archived flag ${import_chalk53.default.bold(flag.slug)} configuration has been updated in ${import_chalk53.default.bold(selectedEnvironment)}`:presentation.success(flag.slug,selectedEnvironment)),output_manager_default.log(` ${import_chalk53.default.dim(flag.state==="archived"?"Configured variant:":"Serving variant:")} ${formatVariantForDisplay(selectedVariant)}`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}async function resolveVariantToSet(client,flag,selector){if(selector){let result=resolveVariant(selector,flag.variants);if(result.error||!result.variant)throw new Error(result.error||`Variant "${selector}" not found`);return result.variant}if(!client.stdin.isTTY)throw new Error("Missing required flag --variant. Use --variant <VARIANT>, or run interactively in a terminal.");let selectedVariantId=await client.input.select({message:"Select a variant to serve:",choices:flag.variants.map(variant=>({name:formatVariantForDisplay(variant),value:variant.id}))}),selectedVariant=flag.variants.find(variant=>variant.id===selectedVariantId);if(!selectedVariant)throw new Error("No variant selected");return selectedVariant}function getSetPresentation(flag,variant){return flag.kind==="boolean"&&variant.value===!0?{spinner:environment=>`Enabling flag in ${environment}...`,success:(slug,environment)=>`Feature flag ${import_chalk53.default.bold(slug)} has been enabled in ${import_chalk53.default.bold(environment)}`,defaultMessage:environment=>`Enabled for ${environment} via CLI`}:flag.kind==="boolean"&&variant.value===!1?{spinner:environment=>`Disabling flag in ${environment}...`,success:(slug,environment)=>`Feature flag ${import_chalk53.default.bold(slug)} has been disabled in ${import_chalk53.default.bold(environment)}`,defaultMessage:environment=>`Disabled for ${environment} via CLI`}:{spinner:environment=>`Setting variant in ${environment}...`,success:(slug,environment)=>`Feature flag ${import_chalk53.default.bold(slug)} has been set in ${import_chalk53.default.bold(environment)}`,defaultMessage:environment=>`Set variant for ${environment} via CLI`}}var import_chalk54=__toESM(require_source(),1),import_fast_deep_equal4=__toESM(require_fast_deep_equal(),1);var FlagsUseTargetingTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:STANDARD_ENVIRONMENTS.includes(environment)?environment:this.redactedValue})}trackCliOptionDefaultVariant(variant){variant&&this.trackCliOption({option:"default-variant",value:this.redactedValue})}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}trackCliOptionProject(project){project&&this.trackCliOption({option:"project",value:this.redactedValue})}};async function useTargeting(client,argv){let telemetryClient=new FlagsUseTargetingTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(useTargetingSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],defaultVariantSelector=normalizeOptionalInput(flags["--default-variant"]),message=normalizeOptionalInput(flags["--message"]),projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to use targeting for"),output_manager_default.log(`Example: ${getCommandName("flags targeting enable my-feature --environment production")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionDefaultVariant(defaultVariantSelector),telemetryClient.trackCliOptionMessage(message);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{output_manager_default.spinner("Fetching flag...");let flag=await getFlag(client,project.id,flagArg);output_manager_default.stopSpinner(),logArchivedFlagNotice(flag);let selectedEnvironment=await resolveFlagEnvironment(client,flag,environment,"Select an environment to use targeting in:",{showEnvironmentDetails:!0,decorateChoices:!1}),envConfig=flag.environments[selectedEnvironment],nextEnvConfig=await resolveNextTargetingEnvironmentConfig(client,flag,selectedEnvironment,defaultVariantSelector);if((0,import_fast_deep_equal4.default)(envConfig,nextEnvConfig))return output_manager_default.warn(flag.state==="archived"?`Archived flag ${import_chalk54.default.bold(flag.slug)} is already configured to use targeting in ${import_chalk54.default.bold(selectedEnvironment)}`:formatAlreadyUsingTargetingWarning(flag,selectedEnvironment,nextEnvConfig)),0;let updateMessage=await resolveFlagUpdateMessage(client,message,`Activated targeting for ${selectedEnvironment} via CLI`);output_manager_default.spinner(`Activating targeting in ${selectedEnvironment}...`),await updateFlag(client,project.id,flagArg,{environments:{[selectedEnvironment]:nextEnvConfig},message:updateMessage}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk54.default.bold(flag.slug)} ${flag.state==="archived"?"is configured to use targeting":"now uses targeting"} in ${import_chalk54.default.bold(selectedEnvironment)}`),output_manager_default.log(` ${import_chalk54.default.dim("Fallthrough:")} ${formatFlagOutcome(nextEnvConfig.fallthrough,flag.variants)}`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}async function resolveNextTargetingEnvironmentConfig(client,flag,environment,defaultVariantSelector){if(defaultVariantSelector){let variant=resolveDefaultVariantOrThrow(flag,defaultVariantSelector);return buildTargetingVariantEnvironmentConfig(flag.environments[environment],variant.id)}let fallthrough=resolveEffectiveFallthrough(flag,environment);if(isUsableFallthrough(fallthrough,flag.variants))return buildResumeTargetingEnvironmentConfig(flag,environment);let selectedVariant=await resolveReplacementDefaultVariant(client,flag,fallthrough);return buildTargetingVariantEnvironmentConfig(flag.environments[environment],selectedVariant.id)}function resolveDefaultVariantOrThrow(flag,selector){let result=resolveVariant(selector,flag.variants);if(result.error||!result.variant)throw new Error(result.error||`Variant "${selector}" not found`);return result.variant}async function resolveReplacementDefaultVariant(client,flag,fallthrough){if(!canPrompt(client))throw new Error(`Couldn't resume targeting because the current fallthrough references a missing variant. Pass --default-variant <VARIANT>${describeUnusableFallthrough(fallthrough)}.`);output_manager_default.warn(`Current fallthrough references a missing variant${describeUnusableFallthrough(fallthrough)}. Choose a new default variant.`);let selectedVariantId=await client.input.select({message:"Select a default variant when no rules match:",choices:flag.variants.map(variant=>({name:formatVariantForDisplay(variant),value:variant.id}))}),selectedVariant=flag.variants.find(variant=>variant.id===selectedVariantId);if(!selectedVariant)throw new Error("No variant selected");return selectedVariant}function describeUnusableFallthrough(fallthrough){return fallthrough.type==="variant"?` (${fallthrough.variantId})`:fallthrough.type==="experiment"?" (experiment assignment)":` (${fallthrough.type} default ${fallthrough.defaultVariantId})`}function formatAlreadyUsingTargetingWarning(flag,environment,envConfig){let{fallthrough}=envConfig;if(fallthrough.type==="variant"){let variant=flag.variants.find(candidate=>candidate.id===fallthrough.variantId),label=variant?formatVariantForDisplay(variant):fallthrough.variantId;return`Flag ${import_chalk54.default.bold(flag.slug)} already uses targeting with default ${label} in ${environment}`}return`Flag ${import_chalk54.default.bold(flag.slug)} already uses targeting in ${environment}`}var import_chalk57=__toESM(require_source(),1),import_fast_deep_equal5=__toESM(require_fast_deep_equal(),1);var import_chalk56=__toESM(require_source(),1);var import_chalk55=__toESM(require_source(),1);function resolveFlagBucketingBase(settings,selector){let separatorIndex=selector.indexOf(".");if(separatorIndex<=0||separatorIndex===selector.length-1)throw new Error("Invalid value for --by. Use the format <entity.attribute>, for example --by user.userId.");let kind=selector.slice(0,separatorIndex),attribute=selector.slice(separatorIndex+1),entity=settings.entities.find(candidate=>candidate.kind===kind);if(!entity){let availableKinds=settings.entities.map(candidate=>candidate.kind);throw new Error(`Unknown entity ${import_chalk55.default.bold(kind)}. Available entities: ${availableKinds.join(", ")}`)}let matchingAttribute=entity.attributes.find(candidate=>candidate.key===attribute);if(!matchingAttribute){let availableAttributes=entity.attributes.map(candidate=>candidate.key);throw new Error(`Unknown attribute ${import_chalk55.default.bold(selector)}. Available attributes for ${kind}: ${availableAttributes.join(", ")}`)}if(!isBucketingAttribute(matchingAttribute))throw new Error(`Attribute ${import_chalk55.default.bold(selector)} is a Timestamp and cannot be used for bucketing. Choose a string or number attribute.`);return{type:"entity",kind,attribute}}function formatFlagBucketingBaseSelector(base){if(base)return`${base.kind}.${base.attribute}`}function resolveFlagSplit(flag,settings,options){let currentSplit=options.currentOutcome?.type==="split"?options.currentOutcome:void 0,baseSelector=options.baseSelector||formatFlagBucketingBaseSelector(currentSplit?.base);if(!baseSelector)throw new Error("Missing required flag --by. Use --by <entity.attribute> to choose how users are bucketed.");let base=resolveFlagBucketingBase(settings,baseSelector),weights=resolveSplitWeights(flag,options.weightInputs,currentSplit),defaultVariant=resolveDefaultVariant(flag,options.defaultVariantSelector,currentSplit);return{outcome:{type:"split",base,weights,defaultVariantId:defaultVariant.id},defaultVariant,baseLabel:`${base.kind}.${base.attribute}`,summary:formatSplitSummary(flag.variants,weights)}}function resolveSplitWeights(flag,weightInputs,currentSplit){if(weightInputs.length===0&¤tSplit)return validateAndNormalizeWeights(flag,currentSplit.weights);if(weightInputs.length===0)throw new Error("At least one --weight is required. Use --weight <VARIANT=WEIGHT> for each variant, or run interactively in a terminal.");let weights={},seen=new Set;for(let input of weightInputs){let{variantSelector,weight}=parseWeightInput(input),variant=resolveVariantOrThrow(variantSelector,flag.variants,"--weight");if(seen.has(variant.id))throw new Error(`Duplicate weight for variant ${import_chalk56.default.bold(formatVariantForDisplay(variant))}.`);seen.add(variant.id),weights[variant.id]=weight}let missingVariants=flag.variants.filter(variant=>!seen.has(variant.id));if(missingVariants.length>0)throw new Error(`Missing weights for variants: ${missingVariants.map(variant=>formatVariantForDisplay(variant)).join(", ")}. Use --weight <VARIANT=WEIGHT> for each variant, including 0 for variants that should receive no traffic.`);return validateAndNormalizeWeights(flag,weights)}function parseWeightInput(input){let separatorIndex=input.lastIndexOf("=");if(separatorIndex<=0||separatorIndex===input.length-1)throw new Error(`Invalid weight ${import_chalk56.default.bold(input)}. Use --weight <VARIANT=WEIGHT>, for example --weight true=5.`);let variantSelector=input.slice(0,separatorIndex).trim(),rawWeight=input.slice(separatorIndex+1).trim();if(!variantSelector)throw new Error(`Invalid weight ${import_chalk56.default.bold(input)}. Variant cannot be empty.`);if(!rawWeight)throw new Error(`Invalid weight ${import_chalk56.default.bold(input)}. Weight cannot be empty.`);let weight=Number(rawWeight);if(!Number.isFinite(weight)||weight<0)throw new Error(`Invalid weight "${rawWeight}". Use a number greater than or equal to 0.`);return{variantSelector,weight}}function validateAndNormalizeWeights(flag,weights){let normalizedWeights=Object.fromEntries(flag.variants.map(variant=>[variant.id,weights[variant.id]??0]));if(Object.values(normalizedWeights).reduce((sum,weight)=>sum+weight,0)<=0)throw new Error("At least one weight must be greater than 0.");return normalizedWeights}function resolveDefaultVariant(flag,selector,currentSplit){if(selector)return resolveVariantOrThrow(selector,flag.variants,"--default-variant");if(currentSplit)return resolveVariantByIdOrThrow(currentSplit.defaultVariantId,flag.variants,"--default-variant");if(flag.kind==="boolean")return getBooleanVariant(flag,!1);throw new Error("Missing required flag --default-variant. Use --default-variant <VARIANT> for non-boolean splits.")}function formatSplitSummary(variants,weights){let total=Object.values(weights).reduce((sum,weight)=>sum+weight,0);return variants.map(variant=>{let weight=weights[variant.id]??0,percentage=total>0?weight/total*100:0;return`${formatPlainVariant(variant)}: ${formatPercentage(percentage)}`}).join(", ")}function formatPlainVariant(variant){let value=formatVariantValue(variant.value);return variant.label?`${variant.label} (${value})`:value}function formatPercentage(percentage){return Number.isInteger(percentage)?`${percentage}%`:`${Number(percentage.toFixed(2))}%`}var FlagsSplitTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:STANDARD_ENVIRONMENTS.includes(environment)?environment:this.redactedValue})}trackCliOptionBy(base){base&&this.trackCliOption({option:"by",value:this.redactedValue})}trackCliOptionWeight(weights){weights?.length&&this.trackCliOption({option:"weight",value:this.redactedValue})}trackCliOptionDefaultVariant(variant){variant&&this.trackCliOption({option:"default-variant",value:this.redactedValue})}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}};async function split(client,argv){let telemetryClient=new FlagsSplitTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(splitSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],baseSelector=normalizeOptionalInput(flags["--by"]),defaultVariantSelector=normalizeOptionalInput(flags["--default-variant"]),weightInputs=flags["--weight"]||[],message=normalizeOptionalInput(flags["--message"]),projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to split"),output_manager_default.log(`Example: ${getCommandName("flags split my-feature --environment production --by user.userId --weight false=95 --weight true=5")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionBy(baseSelector),telemetryClient.trackCliOptionWeight(weightInputs.length>0?[weightInputs[0]]:void 0),telemetryClient.trackCliOptionDefaultVariant(defaultVariantSelector),telemetryClient.trackCliOptionMessage(message);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{output_manager_default.spinner("Fetching flag...");let[flag,settings]=await Promise.all([getFlag(client,project.id,flagArg),getFlagSettings(client,project.id)]);output_manager_default.stopSpinner(),logArchivedFlagNotice(flag);let selectedEnvironment=await resolveFlagEnvironment(client,flag,environment,"Select an environment to split traffic in:",{showEnvironmentDetails:!0,decorateChoices:!1}),envConfig=flag.environments[selectedEnvironment],currentSplit=envConfig.fallthrough.type==="split"?envConfig.fallthrough:void 0,shouldPromptCurrentSplit=canPrompt(client)&¤tSplit!==void 0&&!baseSelector&&weightInputs.length===0&&!defaultVariantSelector&&!message,resolvedBaseSelector=await resolveBaseSelector(client,settings,baseSelector,currentSplit,shouldPromptCurrentSplit),resolvedWeightInputs=await resolveWeightInputs(client,flag,weightInputs,currentSplit,shouldPromptCurrentSplit),resolvedDefaultVariantSelector=await resolveDefaultVariantSelector(client,flag,defaultVariantSelector,currentSplit,shouldPromptCurrentSplit),splitConfig=resolveFlagSplit(flag,settings,{baseSelector:resolvedBaseSelector,weightInputs:resolvedWeightInputs,defaultVariantSelector:resolvedDefaultVariantSelector,currentOutcome:envConfig.fallthrough.type==="experiment"?void 0:envConfig.fallthrough}),nextEnvironmentConfig=buildOutcomeEnvConfig(envConfig,{outcome:splitConfig.outcome,defaultVariantId:splitConfig.defaultVariant.id});if(!message&&envConfig.active&&(0,import_fast_deep_equal5.default)(envConfig.fallthrough,splitConfig.outcome)&&(0,import_fast_deep_equal5.default)(envConfig,nextEnvironmentConfig))return output_manager_default.warn(`Flag ${import_chalk57.default.bold(flag.slug)} is already configured with this split in ${selectedEnvironment}`),0;let updateMessage=await resolveFlagUpdateMessage(client,message,getDefaultSplitMessage(selectedEnvironment,splitConfig));output_manager_default.spinner(`Updating split in ${selectedEnvironment}...`),await updateFlag(client,project.id,flagArg,{environments:{[selectedEnvironment]:nextEnvironmentConfig},message:updateMessage}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk57.default.bold(flag.slug)} split has been updated in ${import_chalk57.default.bold(selectedEnvironment)}`),output_manager_default.log(` ${import_chalk57.default.dim("Based on:")} ${splitConfig.baseLabel}`),output_manager_default.log(` ${import_chalk57.default.dim("Fallback:")} ${formatVariantForDisplay(splitConfig.defaultVariant)}`),output_manager_default.log(` ${import_chalk57.default.dim("Weights:")} ${splitConfig.summary}`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function getDefaultSplitMessage(environment,splitConfig){return`Configure split for ${environment}: ${splitConfig.summary}`}async function resolveBaseSelector(client,settings,baseSelector,currentSplit,shouldPromptCurrentSplit){if(baseSelector||currentSplit&&!shouldPromptCurrentSplit)return baseSelector;if(!canPrompt(client))return;let choices=settings.entities.flatMap(entity=>entity.attributes.filter(isBucketingAttribute).map(attribute=>({name:`${entity.label} \u203A ${attribute.key}`,value:`${entity.kind}.${attribute.key}`}))),currentBaseSelector=formatFlagBucketingBaseSelector(currentSplit?.base),defaultChoice=choices.find(choice=>choice.value===currentBaseSelector)?.value;if(choices.length===0)throw new Error("No entities are configured for weighted splits.");return client.input.select({message:"Select an attribute to split by:",choices,default:defaultChoice})}async function resolveWeightInputs(client,flag,weightInputs,currentSplit,shouldPromptCurrentSplit){if(weightInputs.length>0||currentSplit&&!shouldPromptCurrentSplit||!canPrompt(client))return weightInputs;output_manager_default.log("Enter weights for each variant. Weights are ratios; use 0 for variants that should receive no traffic.");let promptedWeights=[];for(let variant of flag.variants){let defaultWeight=currentSplit?.weights[variant.id]!==void 0?String(currentSplit.weights[variant.id]):currentSplit?"0":"1",weight=await client.input.text({message:`Weight for ${formatVariantForDisplay(variant)}:`,default:defaultWeight,validate:value=>{let trimmed=value.trim();if(!trimmed)return"Enter a weight";let parsed=Number(trimmed);return!Number.isFinite(parsed)||parsed<0?"Enter a number greater than or equal to 0":!0}});promptedWeights.push(`${variant.id}=${weight.trim()}`)}return promptedWeights}async function resolveDefaultVariantSelector(client,flag,defaultVariantSelector,currentSplit,shouldPromptCurrentSplit){if(defaultVariantSelector||currentSplit&&!shouldPromptCurrentSplit||flag.kind==="boolean"&&!canPrompt(client))return defaultVariantSelector;if(canPrompt(client))return client.input.select({message:"Select a fallback variant:",choices:flag.variants.map(variant=>({name:formatVariantForDisplay(variant),value:variant.id})),default:flag.variants.find(variant=>variant.id===currentSplit?.defaultVariantId)?.id||getBooleanFallbackVariantId(flag)})}function getBooleanFallbackVariantId(flag){if(flag.kind==="boolean")return flag.variants.find(variant=>variant.value===!1)?.id}var import_chalk59=__toESM(require_source(),1),import_fast_deep_equal6=__toESM(require_fast_deep_equal(),1);var import_chalk58=__toESM(require_source(),1),import_ms3=__toESM(require_ms(),1);function resolveFlagRollout(flag,settings,options){let currentRollout=options.currentOutcome?.type==="rollout"?options.currentOutcome:void 0,baseSelector=options.baseSelector||formatFlagBucketingBaseSelector(currentRollout?.base);if(!baseSelector)throw new Error("Missing required flag --by. Use --by <entity.attribute> to choose how users are bucketed.");let base=resolveFlagBucketingBase(settings,baseSelector),rollFromVariant=resolveRollFromVariant(flag,options.rollFromVariantSelector,currentRollout),rollToVariant=resolveRollToVariant(flag,options.rollToVariantSelector,currentRollout);if(rollFromVariant.id===rollToVariant.id)throw new Error("`--from-variant` and `--to-variant` must resolve to different variants.");let defaultVariant=resolveDefaultVariant2(flag,options.defaultVariantSelector,currentRollout,rollFromVariant),slots=options.stageInputs.length>0?parseStageInputs(options.stageInputs):currentRollout?.slots;if(!slots||slots.length===0)throw new Error("At least one --stage is required. Use --stage <PERCENTAGE,DURATION>, for example --stage 5,6h.");let finalPromille=options.finalPercentage===void 0?currentRollout?.finalPromille:parseFinalPercentage(options.finalPercentage),startTimestamp=resolveRolloutStartTimestamp(options.start,currentRollout?.startTimestamp);return{outcome:{type:"rollout",base,startTimestamp,rollFromVariantId:rollFromVariant.id,rollToVariantId:rollToVariant.id,defaultVariantId:defaultVariant.id,slots,...finalPromille!==void 0&&{finalPromille}},defaultVariant,rollFromVariant,rollToVariant,baseLabel:`${base.kind}.${base.attribute}`,summary:formatRolloutStages(slots,finalPromille),startLabel:formatStartLabel(options.start,currentRollout?.startTimestamp)}}function resolveRollFromVariant(flag,selector,currentRollout){return selector?resolveVariantOrThrow(selector,flag.variants,"--from-variant"):currentRollout?resolveVariantByIdOrThrow(currentRollout.rollFromVariantId,flag.variants,"--from-variant"):inferBooleanVariant(flag,!1,"--from-variant")}function resolveRollToVariant(flag,selector,currentRollout){return selector?resolveVariantOrThrow(selector,flag.variants,"--to-variant"):currentRollout?resolveVariantByIdOrThrow(currentRollout.rollToVariantId,flag.variants,"--to-variant"):inferBooleanVariant(flag,!0,"--to-variant")}function resolveDefaultVariant2(flag,selector,currentRollout,rollFromVariant){return selector?resolveVariantOrThrow(selector,flag.variants,"--default-variant"):currentRollout?resolveVariantByIdOrThrow(currentRollout.defaultVariantId,flag.variants,"--default-variant"):rollFromVariant}function inferBooleanVariant(flag,value,optionName){if(flag.kind!=="boolean")throw new Error(`Missing required flag ${optionName}. Use ${optionName} <VARIANT> for non-boolean rollouts.`);let variant=flag.variants.find(candidate=>candidate.value===value);if(!variant)throw new Error(`Flag ${import_chalk58.default.bold(flag.slug)} is missing the standard boolean variants`);return variant}function parseStageInputs(stageInputs){let slots=stageInputs.map(parseStageInput);for(let index=1;index<slots.length;index++)if(slots[index].promille<=slots[index-1].promille)throw new Error("Stage percentages must be in ascending order.");return slots}function parseStageInput(input){let parts=input.split(",").map(part=>part.trim());if(parts.length!==2)throw new Error(`Invalid stage ${import_chalk58.default.bold(input)}. Use --stage <PERCENTAGE,DURATION>, for example --stage 5,6h.`);let percentage=Number(parts[0]);if(!Number.isFinite(percentage)||percentage<=0||percentage>=100||!Number.isInteger(percentage*1e3))throw new Error(`Invalid stage percentage "${parts[0]}". Use a number greater than 0 and less than 100 with up to 3 decimal places.`);let durationMs=parseStageDuration(parts[1]);if(durationMs===void 0)throw new Error(`Invalid duration "${parts[1]}". Use minutes (e.g. "30m"), hours (e.g. "6h"), or days (e.g. "1d"). Seconds are not supported.`);return{durationMs,promille:Math.round(percentage*1e3)}}function parseStageDuration(value){if(!value||/^\d+(s|ms)$/i.test(value))return;let durationMs=(0,import_ms3.default)(/^\d+$/.test(value)?`${value}m`:value);if(durationMs===void 0||durationMs<=0)return;let roundedMinutes=Math.round(durationMs/6e4);if(!(roundedMinutes<=0))return roundedMinutes*6e4}function resolveRolloutStartTimestamp(start,currentStartTimestamp){if(start===void 0)return currentStartTimestamp??Date.now();if(start==="now")return Date.now();let relativeDurationMs=(0,import_ms3.default)(start);if(relativeDurationMs!==void 0){if(relativeDurationMs<=0)throw new Error(`Invalid start time "${start}". Use "now", a future relative duration such as "1h", or an ISO 8601 datetime.`);return Date.now()+relativeDurationMs}let absoluteTime=new Date(start).getTime();if(Number.isNaN(absoluteTime))throw new Error(`Invalid start time "${start}". Use "now", a future relative duration such as "1h", or an ISO 8601 datetime.`);return absoluteTime}function parseFinalPercentage(input){let percentage=Number(input);if(input.trim()===""||!Number.isFinite(percentage)||percentage<0||percentage>100||Math.round(percentage*1e3)/1e3!==percentage)throw new Error(`Invalid final percentage "${input}". Use --final-percentage with a number between 0 and 100 with up to 3 decimal places.`);return Math.round(percentage*1e3)}function formatRolloutStages(slots,finalPromille=1e5){return`${slots.map(slot=>`${formatPromille(slot.promille)} for ${(0,import_ms3.default)(slot.durationMs,{long:!0})}`).join(", ")}, then ${formatPromille(finalPromille)} indefinitely`}function formatPromille(promille){let percentage=promille/1e3;return Number.isInteger(percentage)?`${percentage}%`:`${Number(percentage.toFixed(3))}%`}function formatStartLabel(start,currentStartTimestamp){return start===void 0?currentStartTimestamp?"preserve current start time":"immediately":start==="now"?"immediately":`start at ${start}`}var FlagsRolloutTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:STANDARD_ENVIRONMENTS.includes(environment)?environment:this.redactedValue})}trackCliOptionFromVariant(variant){variant&&this.trackCliOption({option:"from-variant",value:this.redactedValue})}trackCliOptionToVariant(variant){variant&&this.trackCliOption({option:"to-variant",value:this.redactedValue})}trackCliOptionDefaultVariant(variant){variant&&this.trackCliOption({option:"default-variant",value:this.redactedValue})}trackCliOptionBy(base){base&&this.trackCliOption({option:"by",value:this.redactedValue})}trackCliOptionStage(stages){stages?.length&&this.trackCliOption({option:"stage",value:this.redactedValue})}trackCliOptionFinalPercentage(percentage){percentage!==void 0&&this.trackCliOption({option:"final-percentage",value:this.redactedValue})}trackCliOptionStart(start){start&&this.trackCliOption({option:"start",value:this.redactedValue})}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}};async function rollout(client,argv){let telemetryClient=new FlagsRolloutTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(rolloutSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],rollFromVariantSelector=normalizeOptionalInput(flags["--from-variant"]),rollToVariantSelector=normalizeOptionalInput(flags["--to-variant"]),defaultVariantSelector=normalizeOptionalInput(flags["--default-variant"]),baseSelector=normalizeOptionalInput(flags["--by"]),stageInputs=(flags["--stage"]||[]).map(input=>input.trim()),finalPercentage=flags["--final-percentage"],start=normalizeOptionalInput(flags["--start"]),message=normalizeOptionalInput(flags["--message"]),projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to roll out"),output_manager_default.log(`Example: ${getCommandName("flags rollout my-feature --environment production --by user.userId --stage 5,6h --stage 25,1d")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionFromVariant(rollFromVariantSelector),telemetryClient.trackCliOptionToVariant(rollToVariantSelector),telemetryClient.trackCliOptionDefaultVariant(defaultVariantSelector),telemetryClient.trackCliOptionBy(baseSelector),telemetryClient.trackCliOptionStage(stageInputs.length>0?[stageInputs[0]]:void 0),telemetryClient.trackCliOptionFinalPercentage(finalPercentage),telemetryClient.trackCliOptionStart(start),telemetryClient.trackCliOptionMessage(message);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{output_manager_default.spinner("Fetching flag...");let[flag,settings]=await Promise.all([getFlag(client,project.id,flagArg),getFlagSettings(client,project.id)]);output_manager_default.stopSpinner(),logArchivedFlagNotice(flag);let selectedEnvironment=await resolveFlagEnvironment(client,flag,environment,"Select an environment to roll out in:",{showEnvironmentDetails:!0,decorateChoices:!1}),currentOutcome=flag.environments[selectedEnvironment].fallthrough,rolloutConfig=resolveFlagRollout(flag,settings,{stageInputs,finalPercentage,baseSelector,rollFromVariantSelector,rollToVariantSelector,defaultVariantSelector,start,currentOutcome:currentOutcome.type==="experiment"?void 0:currentOutcome}),nextEnvironmentConfig=buildOutcomeEnvConfig(flag.environments[selectedEnvironment],{outcome:rolloutConfig.outcome,defaultVariantId:rolloutConfig.defaultVariant.id});if(flag.environments[selectedEnvironment].active&&(0,import_fast_deep_equal6.default)(flag.environments[selectedEnvironment].fallthrough,rolloutConfig.outcome)&&(0,import_fast_deep_equal6.default)(flag.environments[selectedEnvironment],nextEnvironmentConfig))return output_manager_default.warn(`Flag ${import_chalk59.default.bold(flag.slug)} is already configured with this rollout in ${selectedEnvironment}`),0;let updateMessage=await resolveFlagUpdateMessage(client,message,getDefaultRolloutMessage(selectedEnvironment,rolloutConfig));output_manager_default.spinner(`Updating rollout in ${selectedEnvironment}...`),await updateFlag(client,project.id,flagArg,{environments:{[selectedEnvironment]:nextEnvironmentConfig},message:updateMessage}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk59.default.bold(flag.slug)} rollout has been updated in ${import_chalk59.default.bold(selectedEnvironment)}`),output_manager_default.log(` ${import_chalk59.default.dim("Based on:")} ${rolloutConfig.baseLabel}`),output_manager_default.log(` ${import_chalk59.default.dim("Roll from:")} ${formatVariantLabel(rolloutConfig.rollFromVariant)}`),output_manager_default.log(` ${import_chalk59.default.dim("Roll to:")} ${formatVariantLabel(rolloutConfig.rollToVariant)}`),output_manager_default.log(` ${import_chalk59.default.dim("Fallback:")} ${formatVariantLabel(rolloutConfig.defaultVariant)}`),output_manager_default.log(` ${import_chalk59.default.dim("Start:")} ${rolloutConfig.startLabel}`),output_manager_default.log(` ${import_chalk59.default.dim("Stages:")} ${rolloutConfig.summary}`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function getDefaultRolloutMessage(environment,rolloutConfig){return`Configure rollout for ${environment}: ${rolloutConfig.summary}`}function formatVariantLabel(variant){return variant.label||variant.id}var import_chalk60=__toESM(require_source(),1);async function deleteFlag(client,projectId,flagIdOrSlug){output_manager_default.debug(`Deleting feature flag ${flagIdOrSlug} for project ${projectId}`);let url=`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/flags/${encodeURIComponent(flagIdOrSlug)}`;await client.fetch(url,{method:"DELETE"})}var FlagsRmTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliFlagYes(yes){yes&&this.trackCliFlag("yes")}};async function rm(client,argv){let telemetryClient=new FlagsRmTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(removeSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,skipConfirmation=flags["--yes"],projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to delete"),output_manager_default.log(`Example: ${getCommandName("flags delete my-feature")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagYes(skipConfirmation);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{output_manager_default.spinner("Fetching flag...");let flag=await getFlag(client,project.id,flagArg);if(output_manager_default.stopSpinner(),flag.state!=="archived")return output_manager_default.error(`Flag ${import_chalk60.default.bold(flag.slug)} must be archived before it can be deleted. Run ${getCommandName(`flags archive ${flag.slug}`)} first.`),1;if(!skipConfirmation){if(!client.stdin.isTTY)return output_manager_default.error("Missing required flag --yes. Use --yes to skip the confirmation prompt in non-interactive mode."),2;if(!await client.input.confirm(`Are you sure you want to delete ${import_chalk60.default.bold(flag.slug)}? This action cannot be undone.`,!1))return output_manager_default.log("Aborted"),0}output_manager_default.spinner("Deleting flag..."),await deleteFlag(client,project.id,flagArg),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk60.default.bold(flag.slug)} has been deleted`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var import_chalk61=__toESM(require_source(),1);var FlagsArchiveTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliFlagYes(yes){yes&&this.trackCliFlag("yes")}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}};var EVALUATION_WINDOW_DAYS=3;async function archive(client,argv){let telemetryClient=new FlagsArchiveTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(archiveSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,skipConfirmation=flags["--yes"],message=normalizeOptionalInput(flags["--message"]),projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to archive"),output_manager_default.log(`Example: ${getCommandName("flags archive my-feature")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagYes(skipConfirmation),telemetryClient.trackCliOptionMessage(message);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link;try{output_manager_default.spinner("Fetching flag...");let flag=await getFlag(client,project.id,flagArg);if(output_manager_default.stopSpinner(),flag.state==="archived")return output_manager_default.warn(`Flag ${import_chalk61.default.bold(flag.slug)} is already archived`),0;if(!skipConfirmation&&!client.stdin.isTTY)return output_manager_default.error("Missing required flag --yes. Use --yes to skip the confirmation prompt in non-interactive mode."),2;output_manager_default.spinner("Checking recent evaluations...");let endTime=new Date,startTime=new Date(endTime.getTime()-EVALUATION_WINDOW_DAYS*24*60*60*1e3),evaluations2=await countFlagEvaluations(client,{ownerId:org.id,projectId:project.id,flagSlug:flag.slug,startTime,endTime});output_manager_default.stopSpinner();let window=`the last ${EVALUATION_WINDOW_DAYS} days`;if(evaluations2===null){let evaluationsCommand=["flags","evaluations",flag.slug,"--since",`${EVALUATION_WINDOW_DAYS}d`,...getGlobalFlagsFromArgs(client.argv.slice(2),{preserveProject:!0})].map(quoteArg).join(" ");output_manager_default.log(`Could not check recent evaluations for ${import_chalk61.default.bold(flag.slug)}. Run ${getCommandName(evaluationsCommand)} to verify the flag is no longer evaluated.`)}else evaluations2>0?output_manager_default.warn(`${import_chalk61.default.bold(flag.slug)} reported ${evaluations2.toLocaleString()} ${evaluations2===1?"evaluation":"evaluations"} in ${window}. Archived flags evaluate to the default value in code. Remove the flag from your code and deploy before archiving.`):output_manager_default.log(`No evaluations reported for ${import_chalk61.default.bold(flag.slug)} in ${window}.`);if(!skipConfirmation&&!await client.input.confirm(evaluations2!==null&&evaluations2>0?`Archive ${import_chalk61.default.bold(flag.slug)} anyway?`:`Are you sure you want to archive ${import_chalk61.default.bold(flag.slug)}?`,!1))return output_manager_default.log("Aborted"),0;output_manager_default.spinner("Archiving flag..."),await updateFlag(client,project.id,flagArg,{state:"archived",message:message??"Archived via CLI"}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk61.default.bold(flag.slug)} has been archived`),output_manager_default.log(`
|
|
275
|
+
To unarchive this flag, run ${getCommandName(`flags unarchive ${flag.slug}`)}`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var import_chalk62=__toESM(require_source(),1);var FlagsUnarchiveTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliFlagYes(yes){yes&&this.trackCliFlag("yes")}};async function unarchive(client,argv){let telemetryClient=new FlagsUnarchiveTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(unarchiveSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,skipConfirmation=flags["--yes"],projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to unarchive"),output_manager_default.log(`Example: ${getCommandName("flags unarchive my-feature")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagYes(skipConfirmation);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{output_manager_default.spinner("Fetching flag...");let flag=await getFlag(client,project.id,flagArg);if(output_manager_default.stopSpinner(),flag.state==="active")return output_manager_default.warn(`Flag ${import_chalk62.default.bold(flag.slug)} is already active`),0;if(!skipConfirmation){if(!client.stdin.isTTY)return output_manager_default.error("Missing required flag --yes. Use --yes to skip the confirmation prompt in non-interactive mode."),2;if(!await client.input.confirm(`Are you sure you want to unarchive ${import_chalk62.default.bold(flag.slug)}?`,!1))return output_manager_default.log("Aborted"),0}output_manager_default.spinner("Unarchiving flag..."),await updateFlag(client,project.id,flagArg,{state:"active",message:"Unarchive"}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk62.default.bold(flag.slug)} has been unarchived`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var import_chalk64=__toESM(require_source(),1);var import_chalk63=__toESM(require_source(),1);function logNonBooleanFlagGuidance(flag,{attemptedSubcommand,environment,isInteractive,teamSlug,projectName}){let dashboardUrl=getFlagDashboardUrl(teamSlug,projectName,flag.slug),suggestedEnvironment=environment&&environment in flag.environments?environment:void 0;if(output_manager_default.warn(`The ${getCommandName(`flags ${attemptedSubcommand}`)} command only works with boolean flags.`),output_manager_default.log(`Flag ${import_chalk63.default.bold(flag.slug)} is a ${import_chalk63.default.cyan(flag.kind)} flag. Set a specific variant instead:`),output_manager_default.log(` ${getCommandName(getSuggestedSetCommand(flag.slug,suggestedEnvironment,isInteractive))}`),flag.variants.length>0){output_manager_default.log("Available variants:");for(let variant of flag.variants)output_manager_default.log(` - ${formatVariantForDisplay(variant)}`)}output_manager_default.log(`See full flag details with ${getCommandName(`flags inspect ${flag.slug}`)}`),output_manager_default.log(`Open in the dashboard: ${import_chalk63.default.cyan(dashboardUrl)}`)}function getSuggestedSetCommand(slug,environment,isInteractive){let parts=[`flags set ${slug}`];return environment?parts.push(`--environment ${environment}`):isInteractive||parts.push("--environment <ENV>"),isInteractive||parts.push("--variant <VARIANT>"),parts.join(" ")}var FlagsDisableTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:STANDARD_ENVIRONMENTS.includes(environment)?environment:this.redactedValue})}trackCliOptionVariant(variant){variant&&this.trackCliOption({option:"variant",value:this.redactedValue})}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}};async function disable3(client,argv){let telemetryClient=new FlagsDisableTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(disableSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],variantId=flags["--variant"],message=normalizeOptionalInput(flags["--message"]),projectName=getProjectNameFromFlags(flags);if(!flagArg){if(client.nonInteractive){let envPart=environment?`--environment ${environment}`:"--environment <production|preview|development>";return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide a flag slug or ID to disable.",next:[{command:buildCommandWithGlobalFlags(client.argv,`flags disable <flag> ${envPart}`),when:"disable a feature flag by slug or ID"}]},2),2}return output_manager_default.error("Please provide a flag slug or ID to disable"),output_manager_default.log(`Example: ${getCommandName("flags disable my-feature --environment production")}`),2}telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionVariant(variantId),telemetryClient.trackCliOptionMessage(message);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.NOT_LINKED,message:"Your codebase is not linked to a project. Run link first.",next:[{command:buildCommandWithGlobalFlags(client.argv,"link"),when:"link the project"}]},1),1):(output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1);client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{output_manager_default.spinner("Fetching flag...");let flag=await getFlag(client,project.id,flagArg);if(output_manager_default.stopSpinner(),logArchivedFlagNotice(flag),flag.kind!=="boolean")return logNonBooleanFlagGuidance(flag,{attemptedSubcommand:"disable",environment,isInteractive:!!client.stdin.isTTY,teamSlug:link.org.slug,projectName:project.name}),0;if(!environment&&client.nonInteractive)return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide --environment (production, preview, or development) to disable the flag in.",next:[{command:buildCommandWithGlobalFlags(client.argv,`flags disable ${flagArg} --environment <production|preview|development>`),when:"disable the flag in a specific environment"}]},2),2;environment=await resolveFlagEnvironment(client,flag,environment,"Select an environment to disable the flag in:");let envConfig=flag.environments[environment],selectedVariant=getBooleanVariant(flag,!1);if(variantId){let result=resolveVariant(variantId,flag.variants);if(result.error)return output_manager_default.error(result.error),1;selectedVariant=result.variant}if(isPausingEnvironmentToVariant(envConfig,selectedVariant.id))return output_manager_default.warn(`Flag ${import_chalk64.default.bold(flag.slug)} is already disabled in ${environment}`),0;let updateMessage=await resolveFlagUpdateMessage(client,message,getDefaultDisableMessage(environment));output_manager_default.spinner(`Disabling flag in ${environment}...`),await updateFlag(client,project.id,flagArg,{environments:{[environment]:buildPausedEnvironmentConfig(envConfig,selectedVariant.id)},message:updateMessage}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk64.default.bold(flag.slug)} ${flag.state==="archived"?"configuration has been updated":"has been disabled"} in ${import_chalk64.default.bold(environment)}`),output_manager_default.log(` ${import_chalk64.default.dim(flag.state==="archived"?"Configured variant:":"Serving variant:")} ${formatVariantForDisplay(selectedVariant)}`)}catch(err){output_manager_default.stopSpinner();let message2=err instanceof Error?err.message:String(err);return client.nonInteractive&&message2.startsWith("Invalid environment:")?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.INVALID_ARGUMENTS,message:message2,next:[{command:buildCommandWithGlobalFlags(client.argv,`flags disable ${flagArg} --environment <production|preview|development>`),when:"use a valid environment (production, preview, or development)"}]},2),2):(printError(err),2)}return 0}function getDefaultDisableMessage(environment){return`Disabled for ${environment} via CLI`}var import_chalk65=__toESM(require_source(),1);var FlagsEnableTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:STANDARD_ENVIRONMENTS.includes(environment)?environment:this.redactedValue})}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}};async function enable3(client,argv){let telemetryClient=new FlagsEnableTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(enableSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],message=normalizeOptionalInput(flags["--message"]),projectName=getProjectNameFromFlags(flags);if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to enable"),output_manager_default.log(`Example: ${getCommandName("flags enable my-feature --environment production")}`),2;telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionMessage(message);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{output_manager_default.spinner("Fetching flag...");let flag=await getFlag(client,project.id,flagArg);if(output_manager_default.stopSpinner(),logArchivedFlagNotice(flag),flag.kind!=="boolean")return logNonBooleanFlagGuidance(flag,{attemptedSubcommand:"enable",environment,isInteractive:!!client.stdin.isTTY,teamSlug:link.org.slug,projectName:project.name}),0;if(!environment&&client.nonInteractive)return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide --environment (production, preview, or development) to enable the flag in.",next:[{command:buildCommandWithGlobalFlags(client.argv,`flags enable ${flagArg} --environment <production|preview|development>`),when:"enable the flag in a specific environment"}]},2),2;environment=await resolveFlagEnvironment(client,flag,environment,"Select an environment to enable the flag in:");let envConfig=flag.environments[environment],onVariant=getBooleanVariant(flag,!0);if(isPausingEnvironmentToVariant(envConfig,onVariant.id))return output_manager_default.warn(`Flag ${import_chalk65.default.bold(flag.slug)} is already enabled in ${environment}`),0;let updateMessage=await resolveFlagUpdateMessage(client,message,getDefaultEnableMessage(environment));output_manager_default.spinner(`Enabling flag in ${environment}...`),await updateFlag(client,project.id,flagArg,{environments:{[environment]:buildPausedEnvironmentConfig(envConfig,onVariant.id)},message:updateMessage}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag ${import_chalk65.default.bold(flag.slug)} ${flag.state==="archived"?"configuration has been updated":"has been enabled"} in ${import_chalk65.default.bold(environment)}`),output_manager_default.log(` ${import_chalk65.default.dim(flag.state==="archived"?"Configured variant:":"Serving variant:")} ${formatVariantForDisplay(onVariant)}`)}catch(err){output_manager_default.stopSpinner();let message2=err instanceof Error?err.message:String(err);return client.nonInteractive&&message2.startsWith("Invalid environment:")?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.INVALID_ARGUMENTS,message:message2,next:[{command:buildCommandWithGlobalFlags(client.argv,`flags enable ${flagArg} --environment <production|preview|development>`),when:"use a valid environment (production, preview, or development)"}]},2),2):(printError(err),2)}return 0}function getDefaultEnableMessage(environment){return`Enabled for ${environment} via CLI`}var FlagsSdkKeysTelemetryClient=class extends TelemetryClient{trackCliSubcommandList(actual){this.trackCliSubcommand({subcommand:"ls",value:actual})}trackCliSubcommandCreate(actual){this.trackCliSubcommand({subcommand:"create",value:actual})}trackCliSubcommandRevoke(actual){this.trackCliSubcommand({subcommand:"revoke",value:actual})}},FlagsSdkKeysLsTelemetryClient=class extends TelemetryClient{trackCliFlagJson(json){json&&this.trackCliFlag("json")}},FlagsSdkKeysAddTelemetryClient=class extends TelemetryClient{trackCliOptionType(type){type&&this.trackCliOption({option:"type",value:type})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:environment})}trackCliOptionLabel(label){label&&this.trackCliOption({option:"label",value:this.redactedValue})}},FlagsSdkKeysRmTelemetryClient=class extends TelemetryClient{trackCliArgumentKey(key){key&&this.trackCliArgument({arg:"key",value:this.redactedValue})}trackCliFlagYes(yes){yes&&this.trackCliFlag("yes")}};var import_chalk66=__toESM(require_source(),1),import_ms4=__toESM(require_ms(),1);async function sdkKeysLs(client,argv){let telemetryClient=new FlagsSdkKeysLsTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(sdkKeysListSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{flags}=parsedArgs,json=flags["--json"],projectName=getProjectNameFromFlags(flags);telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagJson(json);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name);try{output_manager_default.spinner("Fetching SDK keys...");let keys=await getSdkKeys(client,project.id);output_manager_default.stopSpinner();let sortedKeys=keys.sort((a,b)=>b.createdAt-a.createdAt);json?outputSdkKeysJson(client,sortedKeys):keys.length===0?(output_manager_default.log(`No SDK keys found for ${projectSlugLink}`),output_manager_default.log(`
|
|
276
|
+
Create one with: ${getCommandName("flags sdk-keys create --type server --environment production")}`)):(output_manager_default.log(`${import_chalk66.default.bold(keys.length)} SDK key${keys.length===1?"":"s"} found for ${projectSlugLink}`),printSdkKeysTable(sortedKeys))}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function outputSdkKeysJson(client,keys){let jsonOutput={sdkKeys:keys.map(key=>({hashKey:key.hashKey,type:key.type,environment:key.environment,label:key.label??null,partialKeyValue:key.partialKeyValue??null,createdAt:key.createdAt,updatedAt:key.updatedAt}))};client.stdout.write(`${JSON.stringify(jsonOutput,null,2)}
|
|
277
|
+
`)}function printSdkKeysTable(keys){let headers=["Hash Key","Type","Environment","Label","Partial Key Value","Created"],now=Date.now(),rows=keys.map(key=>[import_chalk66.default.dim(key.hashKey.slice(0,12)+"..."),getTypeLabel(key.type),key.environment,key.label||import_chalk66.default.dim("-"),key.partialKeyValue||import_chalk66.default.dim("-"),(0,import_ms4.default)(now-key.createdAt)+" ago"]),table2=formatTable(headers,["l","l","l","l","l","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
278
|
+
${table2}
|
|
279
|
+
`)}function getTypeLabel(type){switch(type){case"server":return import_chalk66.default.blue("server");case"client":return import_chalk66.default.green("client");case"mobile":return import_chalk66.default.yellow("mobile");default:return type}}var import_chalk67=__toESM(require_source(),1);var VALID_TYPES=["server","client","mobile"],VALID_ENVIRONMENTS=["production","preview","development"];async function sdkKeysAdd(client,argv){let telemetryClient=new FlagsSdkKeysAddTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(sdkKeysAddSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{flags}=parsedArgs,sdkKeyType=flags["--type"],environment=flags["--environment"],label=flags["--label"],projectName=getProjectNameFromFlags(flags);telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionType(sdkKeyType),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionLabel(label);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.NOT_LINKED,message:"Your codebase is not linked to a project. Run link first.",next:[{command:buildCommandWithGlobalFlags(client.argv,"link"),when:"link the project"}]},1),1):(output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1);client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;if(!sdkKeyType){if(client.nonInteractive){let envPart=environment?`--environment ${environment}`:"--environment <production|preview|development>";return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide --type (server, client, or mobile) for the SDK key.",next:[{command:buildCommandWithGlobalFlags(client.argv,`flags sdk-keys create --type <server|client|mobile> ${envPart}`),when:"create an SDK key with a specific type"}]},2),2}sdkKeyType=await client.input.select({message:"Select the SDK key type:",choices:[{name:"Server (for backend/server-side usage)",value:"server"},{name:"Client (for browser/frontend usage)",value:"client"},{name:"Mobile (for mobile app usage)",value:"mobile"}]})}if(!VALID_TYPES.includes(sdkKeyType)){if(client.nonInteractive){let envPart=environment?`--environment ${environment}`:"--environment <production|preview|development>";return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.INVALID_ARGUMENTS,message:`Invalid type: ${sdkKeyType}. Must be one of: ${VALID_TYPES.join(", ")}`,next:[{command:buildCommandWithGlobalFlags(client.argv,`flags sdk-keys create --type <server|client|mobile> ${envPart}`),when:"use a valid type (server, client, or mobile)"}]},2),2}return output_manager_default.error(`Invalid type: ${sdkKeyType}. Must be one of: ${VALID_TYPES.join(", ")}`),2}if(!environment){if(client.nonInteractive)return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide --environment (production, preview, or development) for the SDK key.",next:[{command:buildCommandWithGlobalFlags(client.argv,`flags sdk-keys create --type ${sdkKeyType} --environment <production|preview|development>`),when:"create an SDK key for a specific environment"}]},2),2;environment=await client.input.select({message:"Select the environment:",choices:VALID_ENVIRONMENTS.map(env=>({name:env,value:env}))})}if(!VALID_ENVIRONMENTS.includes(environment))return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.INVALID_ARGUMENTS,message:`Invalid environment: ${environment}. Must be one of: ${VALID_ENVIRONMENTS.join(", ")}`,next:[{command:buildCommandWithGlobalFlags(client.argv,`flags sdk-keys create --type ${sdkKeyType} --environment <production|preview|development>`),when:"use a valid environment (production, preview, or development)"}]},2),2):(output_manager_default.error(`Invalid environment: ${environment}. Must be one of: ${VALID_ENVIRONMENTS.join(", ")}`),2);let finalLabel=label;!finalLabel&&client.stdin.isTTY&&!client.nonInteractive&&(finalLabel=await client.input.text({message:"Enter an optional label for this SDK key (press Enter to skip):"}),finalLabel===""&&(finalLabel=void 0));let request={sdkKeyType,environment,label:finalLabel};try{output_manager_default.spinner("Creating SDK key...");let key=await createSdkKey(client,project.id,request);output_manager_default.stopSpinner(),output_manager_default.success("SDK key created successfully"),output_manager_default.print(`
|
|
280
|
+
`),output_manager_default.print(` ${import_chalk67.default.dim("Hash Key:")} ${key.hashKey}
|
|
281
|
+
`),output_manager_default.print(` ${import_chalk67.default.dim("Type:")} ${key.type}
|
|
282
|
+
`),output_manager_default.print(` ${import_chalk67.default.dim("Environment:")} ${key.environment}
|
|
283
|
+
`),key.label&&output_manager_default.print(` ${import_chalk67.default.dim("Label:")} ${key.label}
|
|
284
|
+
`),key.keyValue&&(output_manager_default.print(`
|
|
285
|
+
`),output_manager_default.warn("Save this key - it will not be shown again:"),output_manager_default.print(`
|
|
286
|
+
${import_chalk67.default.cyan(key.keyValue)}
|
|
287
|
+
`)),key.connectionString&&(output_manager_default.print(`
|
|
288
|
+
`),output_manager_default.log(`${import_chalk67.default.dim("Connection string:")}`),output_manager_default.print(` ${import_chalk67.default.cyan(key.connectionString)}
|
|
289
|
+
`))}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var import_chalk68=__toESM(require_source(),1);async function sdkKeysRm(client,argv){let telemetryClient=new FlagsSdkKeysRmTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(sdkKeysRemoveSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[hashKey]=args,skipConfirmation=flags["--yes"],projectName=getProjectNameFromFlags(flags);telemetryClient.trackCliArgumentKey(hashKey),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagYes(skipConfirmation);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.NOT_LINKED,message:"Your codebase is not linked to a project. A user must run `vercel link` in a terminal to continue (this will prompt for login if needed).",next:[{command:buildCommandWithGlobalFlags(client.argv,"link"),when:"run in a terminal to log in if needed and link this codebase to a Vercel project, then retry this command"}]},1),1):(output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1);client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{if(!hashKey){if(client.nonInteractive)return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide the SDK key hash to delete. Run `vercel flags sdk-keys ls` to list keys.",next:[{command:buildCommandWithGlobalFlags(client.argv,"flags sdk-keys revoke <hashKey>"),when:"delete an SDK key by hash"},{command:buildCommandWithGlobalFlags(client.argv,"flags sdk-keys ls"),when:"list SDK keys to find the hash"}]},2),2;output_manager_default.spinner("Fetching SDK keys...");let keys=await getSdkKeys(client,project.id);if(output_manager_default.stopSpinner(),keys.length===0)return output_manager_default.log("No SDK keys found"),0;hashKey=await client.input.select({message:"Select an SDK key to delete:",choices:keys.map(key=>({name:`${key.hashKey.slice(0,12)}... (${key.type}, ${key.environment}${key.label?`, ${key.label}`:""})`,value:key.hashKey}))})}if(!skipConfirmation){if(client.nonInteractive)return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.CONFIRMATION_REQUIRED,message:`Confirm revoking SDK key ${hashKey.slice(0,12)}... by adding --yes.`,next:[{command:buildCommandWithGlobalFlags(client.argv,`flags sdk-keys revoke ${hashKey} --yes`),when:"confirm and revoke the SDK key"}]},1),1;if(!await client.input.confirm(`Are you sure you want to revoke SDK key ${import_chalk68.default.bold(hashKey.slice(0,12)+"...")}?`,!1))return output_manager_default.log("Aborted"),0}output_manager_default.spinner("Revoking SDK key..."),await deleteSdkKey(client,project.id,hashKey),output_manager_default.stopSpinner(),output_manager_default.success(`SDK key ${import_chalk68.default.bold(hashKey.slice(0,12)+"...")} has been revoked`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var COMMAND_CONFIG11={ls:getCommandAliases(sdkKeysListSubcommand),add:getCommandAliases(sdkKeysAddSubcommand),revoke:getCommandAliases(sdkKeysRemoveSubcommand)};async function sdkKeys(client){let telemetry=new FlagsSdkKeysTelemetryClient({opts:{store:client.telemetryEventStore}}),flagsSpecification=getFlagsSpecification(sdkKeysSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(client.argv.slice(4),flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let subArgs=parsedArgs.args.slice(0),{subcommand,args,subcommandOriginal}=getSubcommand(subArgs,COMMAND_CONFIG11),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("flags sdk-keys",subcommand),output_manager_default.print(help(sdkKeysSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:sdkKeysSubcommand,columns:client.stderr.columns}))}switch(subcommand){case"ls":return needHelp?(telemetry.trackCliFlagHelp("flags sdk-keys",subcommandOriginal),printHelp(sdkKeysListSubcommand),0):(telemetry.trackCliSubcommandList(subcommandOriginal),sdkKeysLs(client,args));case"add":return needHelp?(telemetry.trackCliFlagHelp("flags sdk-keys",subcommandOriginal),printHelp(sdkKeysAddSubcommand),0):(telemetry.trackCliSubcommandCreate(subcommandOriginal),subcommandOriginal==="add"&&warnDeprecatedSubcommand(client,"flags sdk-keys add","flags sdk-keys create"),sdkKeysAdd(client,args));case"revoke":return needHelp?(telemetry.trackCliFlagHelp("flags sdk-keys",subcommandOriginal),printHelp(sdkKeysRemoveSubcommand),0):(telemetry.trackCliSubcommandRevoke(subcommandOriginal),subcommandOriginal!=="revoke"&&warnDeprecatedSubcommand(client,`flags sdk-keys ${subcommandOriginal}`,"flags sdk-keys revoke"),sdkKeysRm(client,args));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG11)),output_manager_default.print(help(sdkKeysSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),2}}var FlagsConnectionsTelemetryClient=class extends TelemetryClient{trackCliSubcommandList(actual){this.trackCliSubcommand({subcommand:"ls",value:actual})}trackCliSubcommandAdd(actual){this.trackCliSubcommand({subcommand:"add",value:actual})}trackCliSubcommandRemove(actual){this.trackCliSubcommand({subcommand:"rm",value:actual})}},FlagsConnectionsLsTelemetryClient=class extends TelemetryClient{trackCliOptionRole(role){role&&this.trackCliOption({option:"role",value:role})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}},FlagsConnectionsAddTelemetryClient=class extends TelemetryClient{trackCliArgumentConsumerProject(project){project&&this.trackCliArgument({arg:"consumer-project",value:this.redactedValue})}},FlagsConnectionsRmTelemetryClient=class extends TelemetryClient{trackCliArgumentConsumerProject(project){project&&this.trackCliArgument({arg:"consumer-project",value:this.redactedValue})}trackCliFlagYes(yes){yes&&this.trackCliFlag("yes")}};var import_chalk69=__toESM(require_source(),1),import_ms5=__toESM(require_ms(),1);function connectionsUrl(projectId){return`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/connections`}async function getConnections(client,projectId,role){return output_manager_default.debug(`Fetching flags connections for project ${projectId} as ${role}`),(await client.fetch(`${connectionsUrl(projectId)}?role=${role}`)).data}async function createConnection(client,sourceProjectId,consumerProjectId){return output_manager_default.debug(`Connecting project ${consumerProjectId} to the flags of project ${sourceProjectId}`),client.fetch(connectionsUrl(sourceProjectId),{method:"PUT",body:{consumerProjectId}})}async function deleteConnection(client,sourceProjectId,consumerProjectId){output_manager_default.debug(`Disconnecting project ${consumerProjectId} from the flags of project ${sourceProjectId}`),await client.fetch(`${connectionsUrl(sourceProjectId)}/${encodeURIComponent(consumerProjectId)}`,{method:"DELETE",json:!1})}function connectionsCommand(client,template){return buildCommandWithGlobalFlags(client.argv,template,void 0,{preserveProject:!0,excludeFlags:["--yes"]})}function connectionsError(client,payload,exitCode=1){return outputAgentError(client,{...payload,status:AGENT_STATUS.ERROR,next:payload.next?.map(next=>({...next,command:connectionsCommand(client,next.command)}))},exitCode),client.nonInteractive||output_manager_default.fatal(payload.message),exitCode}async function resolveSourceProject(client,projectName){let link=await getLinkedFlagsProject(client,projectName);return link.status==="error"?link.exitCode:link.status==="not_linked"?connectionsError(client,{reason:AGENT_REASON.NOT_LINKED,message:`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`,next:[{command:"link",when:"link the project"}]}):(client.config.currentTeam=link.org.type==="team"?link.org.id:void 0,link)}async function resolveConsumerProject(client,link,consumerNameOrId,usage){if(!consumerNameOrId)return connectionsError(client,{reason:AGENT_REASON.MISSING_ARGUMENTS,message:`Please provide the name or ID of the consumer project: ${getCommandName(usage)}`,next:[{command:usage,when:"name the consumer project"}]},2);let consumer;try{consumer=await getProjectByNameOrId(client,consumerNameOrId,link.org.type==="team"?link.org.id:void 0)}catch(err){return printError(err),1}return consumer instanceof ProjectNotFound?connectionsError(client,{reason:AGENT_REASON.NOT_FOUND,message:`Project "${consumerNameOrId}" was not found in team ${link.org.slug}.`}):consumer.id===link.project.id?connectionsError(client,{reason:AGENT_REASON.INVALID_ARGUMENTS,message:"A project cannot be connected to its own flags."},2):consumer}var VALID_ROLES=["source","consumer"];async function connectionsLs(client,argv){let telemetryClient=new FlagsConnectionsLsTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(connectionsListSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{flags}=parsedArgs,json=flags["--json"],role=flags["--role"]??"source",projectName=getProjectNameFromFlags(flags);if(telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionRole(flags["--role"]),telemetryClient.trackCliFlagJson(json),!isRole(role))return connectionsError(client,{reason:AGENT_REASON.INVALID_ARGUMENTS,message:`Invalid role: ${role}. Must be one of: ${VALID_ROLES.join(", ")}`,next:[{command:"flags connections ls --role <source|consumer>",when:"list connections for a valid role"}]},2);let link=await resolveSourceProject(client,projectName);if(typeof link=="number")return link;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name),accountId=org.type==="team"?org.id:void 0;try{output_manager_default.spinner("Fetching flags connections...");let sorted=(await getConnections(client,project.id,role)).sort((a,b)=>b.createdAt-a.createdAt),names=json?new Map:await resolveProjectNames(client,sorted,role,accountId);if(output_manager_default.stopSpinner(),json)client.stdout.write(`${JSON.stringify({role,connections:sorted},null,2)}
|
|
290
|
+
`);else if(sorted.length===0)role==="source"?(output_manager_default.log(`No project may read the flags of ${projectSlugLink}`),output_manager_default.log(`
|
|
291
|
+
Connect one with: ${import_chalk69.default.cyan(connectionsCommand(client,"flags connections add <consumer-project>"))}`)):(output_manager_default.log(`${projectSlugLink} may not read the flags of any project`),output_manager_default.log(`
|
|
292
|
+
Ask an owner of the source project to run: ${getCommandName(`flags connections add ${quoteArg(project.name)} --project <source-project>`)}`));else{let count=`${import_chalk69.default.bold(sorted.length)} project${sorted.length===1?"":"s"}`;output_manager_default.log(role==="source"?`${count} may read the flags of ${projectSlugLink}`:`${projectSlugLink} may read the flags of ${count}`),printConnectionsTable(sorted,role,names)}}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function isRole(value){return VALID_ROLES.includes(value)}function otherProjectId(connection,role){return role==="source"?connection.consumerProjectId:connection.sourceProjectId}async function resolveProjectNames(client,connections2,role,accountId){let ids=[...new Set(connections2.map(c=>otherProjectId(c,role)))],entries=await Promise.all(ids.map(async id=>{try{let project=await getProjectByNameOrId(client,id,accountId);return[id,project instanceof Error?id:project.name]}catch{return[id,id]}}));return new Map(entries)}function printConnectionsTable(connections2,role,names){let now=Date.now(),header=role==="source"?"Consumer Project":"Source Project",rows=connections2.map(connection=>{let id=otherProjectId(connection,role),name=names.get(id)??id;return[name===id?id:`${name} ${import_chalk69.default.dim(id)}`,import_chalk69.default.dim(connection.createdBy),(0,import_ms5.default)(now-connection.createdAt)+" ago"]}),table2=formatTable([header,"Created By","Created"],["l","l","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
293
|
+
${table2}
|
|
294
|
+
`)}var import_chalk70=__toESM(require_source(),1);async function connectionsAdd(client,argv){let telemetryClient=new FlagsConnectionsAddTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(connectionsAddSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[consumerNameOrId]=args,projectName=getProjectNameFromFlags(flags);telemetryClient.trackCliArgumentConsumerProject(consumerNameOrId),telemetryClient.trackCliOptionProject(projectName);let link=await resolveSourceProject(client,projectName);if(typeof link=="number")return link;let consumer=await resolveConsumerProject(client,link,consumerNameOrId,"flags connections add <consumer-project>");if(typeof consumer=="number")return consumer;let source=link.project;try{output_manager_default.spinner("Connecting project..."),await createConnection(client,source.id,consumer.id),output_manager_default.stopSpinner()}catch(err){return output_manager_default.stopSpinner(),isAPIError(err)&&err.code==="flags_project_connection_exists"?(output_manager_default.log(`${import_chalk70.default.bold(consumer.name)} already may read the flags of ${import_chalk70.default.bold(source.name)}`),0):(printError(err),1)}return output_manager_default.success(`${import_chalk70.default.bold(consumer.name)} may now read the flags of ${import_chalk70.default.bold(source.name)}`),output_manager_default.print(`
|
|
295
|
+
`),output_manager_default.print(` ${import_chalk70.default.dim("Source project ID:")} ${source.id}
|
|
296
|
+
`),0}var import_chalk71=__toESM(require_source(),1);async function connectionsRm(client,argv){let telemetryClient=new FlagsConnectionsRmTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(connectionsRemoveSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[consumerNameOrId]=args,skipConfirmation=flags["--yes"],projectName=getProjectNameFromFlags(flags);telemetryClient.trackCliArgumentConsumerProject(consumerNameOrId),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagYes(skipConfirmation);let link=await resolveSourceProject(client,projectName);if(typeof link=="number")return link;let consumer=await resolveConsumerProject(client,link,consumerNameOrId,"flags connections remove <consumer-project>");if(typeof consumer=="number")return consumer;let source=link.project;if(!skipConfirmation){if(client.nonInteractive)return connectionsError(client,{reason:AGENT_REASON.CONFIRMATION_REQUIRED,message:`Confirm removing the connection of ${consumer.name} to the flags of ${source.name} by adding --yes.`,next:[{command:`flags connections remove ${quoteArg(consumerNameOrId)} --yes`,when:"confirm and remove the connection"}]});if(!await client.input.confirm(`Stop ${import_chalk71.default.bold(consumer.name)} from reading the flags of ${import_chalk71.default.bold(source.name)}? Its deployments lose access right away.`,!1))return output_manager_default.log("Aborted"),0}try{output_manager_default.spinner("Removing connection..."),await deleteConnection(client,source.id,consumer.id),output_manager_default.stopSpinner(),output_manager_default.success(`${import_chalk71.default.bold(consumer.name)} may no longer read the flags of ${import_chalk71.default.bold(source.name)}`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var COMMAND_CONFIG12={ls:getCommandAliases(connectionsListSubcommand),add:getCommandAliases(connectionsAddSubcommand),rm:getCommandAliases(connectionsRemoveSubcommand)};async function connections(client){let telemetry=new FlagsConnectionsTelemetryClient({opts:{store:client.telemetryEventStore}}),flagsSpecification=getFlagsSpecification(connectionsSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(client.argv.slice(4),flagsSpecification,{permissive:!0})}catch(err){return printError(err),1}let subArgs=parsedArgs.args.slice(0),{subcommand,args,subcommandOriginal}=getSubcommand(subArgs,COMMAND_CONFIG12),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("flags connections",subcommand),output_manager_default.print(help(connectionsSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:connectionsSubcommand,columns:client.stderr.columns}))}switch(subcommand){case"ls":return needHelp?(telemetry.trackCliFlagHelp("flags connections",subcommandOriginal),printHelp(connectionsListSubcommand),0):(telemetry.trackCliSubcommandList(subcommandOriginal),connectionsLs(client,args));case"add":return needHelp?(telemetry.trackCliFlagHelp("flags connections",subcommandOriginal),printHelp(connectionsAddSubcommand),0):(telemetry.trackCliSubcommandAdd(subcommandOriginal),connectionsAdd(client,args));case"rm":return needHelp?(telemetry.trackCliFlagHelp("flags connections",subcommandOriginal),printHelp(connectionsRemoveSubcommand),0):(telemetry.trackCliSubcommandRemove(subcommandOriginal),connectionsRm(client,args));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG12)),output_manager_default.print(help(connectionsSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),2}}var FlagsSegmentsTelemetryClient=class extends TelemetryClient{trackCliSubcommandList(actual){this.trackCliSubcommand({subcommand:"ls",value:actual})}trackCliSubcommandInspect(actual){this.trackCliSubcommand({subcommand:"inspect",value:actual})}trackCliSubcommandCreate(actual){this.trackCliSubcommand({subcommand:"create",value:actual})}trackCliSubcommandUpdate(actual){this.trackCliSubcommand({subcommand:"update",value:actual})}trackCliSubcommandDelete(actual){this.trackCliSubcommand({subcommand:"delete",value:actual})}},FlagsSegmentsLsTelemetryClient=class extends TelemetryClient{trackCliFlagJson(json){json&&this.trackCliFlag("json")}},FlagsSegmentsInspectTelemetryClient=class extends TelemetryClient{trackCliArgumentSegment(segment){segment&&this.trackCliArgument({arg:"segment",value:this.redactedValue})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}},FlagsSegmentsCreateTelemetryClient=class extends TelemetryClient{trackCliArgumentSlug(slug){slug&&this.trackCliArgument({arg:"slug",value:this.redactedValue})}trackCliOptionLabel(label){label&&this.trackCliOption({option:"label",value:this.redactedValue})}trackCliOptionDescription(description){description&&this.trackCliOption({option:"description",value:this.redactedValue})}trackCliOptionHint(hint){hint&&this.trackCliOption({option:"hint",value:this.redactedValue})}trackCliOptionData(data){data&&this.trackCliOption({option:"data",value:this.redactedValue})}trackCliOptionAdd(add3){add3?.length&&this.trackCliOption({option:"add",value:this.redactedValue})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}},FlagsSegmentsUpdateTelemetryClient=class extends TelemetryClient{trackCliArgumentSegment(segment){segment&&this.trackCliArgument({arg:"segment",value:this.redactedValue})}trackCliOptionLabel(label){label&&this.trackCliOption({option:"label",value:this.redactedValue})}trackCliOptionDescription(description){description&&this.trackCliOption({option:"description",value:this.redactedValue})}trackCliOptionHint(hint){hint&&this.trackCliOption({option:"hint",value:this.redactedValue})}trackCliOptionData(data){data&&this.trackCliOption({option:"data",value:this.redactedValue})}trackCliOptionAdd(add3){add3?.length&&this.trackCliOption({option:"add",value:this.redactedValue})}trackCliOptionRemove(remove3){remove3?.length&&this.trackCliOption({option:"remove",value:this.redactedValue})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}},FlagsSegmentsRmTelemetryClient=class extends TelemetryClient{trackCliArgumentSegment(segment){segment&&this.trackCliArgument({arg:"segment",value:this.redactedValue})}trackCliFlagYes(yes){yes&&this.trackCliFlag("yes")}};var import_chalk72=__toESM(require_source(),1),import_ms6=__toESM(require_ms(),1),import_pluralize4=__toESM(require_pluralize(),1);function getSegmentsUrl(projectId,withMetadata=!1){let url=`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/segments`;return withMetadata?`${url}?withMetadata=true`:url}function getSegmentUrl(projectId,segmentIdOrSlug,withMetadata=!1){let url=`${getSegmentsUrl(projectId)}/${encodeURIComponent(segmentIdOrSlug)}`;return withMetadata?`${url}?withMetadata=true`:url}async function getSegments(client,projectId,withMetadata=!1){return output_manager_default.debug(`Fetching feature flag segments for project ${projectId}`),(await client.fetch(getSegmentsUrl(projectId,withMetadata))).data}async function getSegment(client,projectId,segmentIdOrSlug,withMetadata=!0){return output_manager_default.debug(`Fetching feature flag segment ${segmentIdOrSlug} for project ${projectId}`),client.fetch(getSegmentUrl(projectId,segmentIdOrSlug,withMetadata))}async function createSegment(client,projectId,request){let url=getSegmentsUrl(projectId);return output_manager_default.debug(`Creating feature flag segment ${request.slug} for project ${projectId}`),output_manager_default.debug(`API endpoint: PUT ${url}`),client.fetch(url,{method:"PUT",body:request})}async function updateSegment(client,projectId,segmentIdOrSlug,request){let url=getSegmentUrl(projectId,segmentIdOrSlug);return output_manager_default.debug(`Updating feature flag segment ${segmentIdOrSlug} for project ${projectId}`),client.fetch(url,{method:"PATCH",body:request})}async function deleteSegment(client,projectId,segmentIdOrSlug){let url=getSegmentUrl(projectId,segmentIdOrSlug);output_manager_default.debug(`Deleting feature flag segment ${segmentIdOrSlug} for project ${projectId}`),await client.fetch(url,{method:"DELETE"})}async function segmentsLs(client,argv){let telemetryClient=new FlagsSegmentsLsTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(segmentsListSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{flags}=parsedArgs,json=flags["--json"],projectName=getProjectNameFromFlags(flags);telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagJson(json);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name),lsStamp=stamp_default();output_manager_default.spinner(`Fetching feature flag segments for ${projectSlugLink}`);try{let segments2=await getSegments(client,project.id,!0);output_manager_default.stopSpinner();let sortedSegments=segments2.sort((a,b)=>b.updatedAt-a.updatedAt);json?outputJson5(client,sortedSegments):segments2.length===0?(output_manager_default.log(`No feature flag segments found for ${projectSlugLink} ${import_chalk72.default.gray(lsStamp())}`),output_manager_default.log(`
|
|
297
|
+
Create one with: ${getCommandName('flags segments create beta-users --label "Beta users" --add include:user.id=user_123')}`)):(output_manager_default.log(`${(0,import_pluralize4.default)("feature flag segment",segments2.length,!0)} found for ${projectSlugLink} ${import_chalk72.default.gray(lsStamp())}`),printSegmentsTable(sortedSegments))}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function outputJson5(client,segments2){let jsonOutput={segments:segments2.map(segment=>({id:segment.id,slug:segment.slug,label:segment.label,description:segment.description??null,data:segment.data,hint:segment.hint,usedByFlags:segment.usedByFlags??[],usedBySegments:segment.usedBySegments??[],createdAt:segment.createdAt,updatedAt:segment.updatedAt}))};client.stdout.write(`${JSON.stringify(jsonOutput,null,2)}
|
|
298
|
+
`)}function printSegmentsTable(segments2){let headers=["Slug","Label","Rules","Values","Used By","Updated"],now=Date.now(),rows=segments2.map(segment=>[import_chalk72.default.bold(segment.slug),segment.label,String(segment.data.rules?.length??0),String(countSegmentValues(segment)),String((segment.usedByFlags?.length??0)+(segment.usedBySegments?.length??0)),(0,import_ms6.default)(now-segment.updatedAt)+" ago"]),table2=formatTable(headers,["l","l","r","r","r","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
299
|
+
${table2}
|
|
300
|
+
`)}function countSegmentValues(segment){return countMembershipValues(segment.data.include)+countMembershipValues(segment.data.exclude)}function countMembershipValues(map){return map?Object.values(map).reduce((sum,attributes)=>sum+Object.values(attributes).reduce((attributeSum,values)=>attributeSum+values.length,0),0):0}var import_chalk73=__toESM(require_source(),1);function printSegmentDetails({segment,projectSlugLink,showTimestamps=!0,settings}){output_manager_default.log(`
|
|
301
|
+
Feature flag segment ${import_chalk73.default.bold(segment.slug)} for ${projectSlugLink}
|
|
302
|
+
`),output_manager_default.print(` ${import_chalk73.default.dim("ID:")} ${segment.id}
|
|
303
|
+
`),output_manager_default.print(` ${import_chalk73.default.dim("Label:")} ${segment.label}
|
|
304
|
+
`),segment.description&&output_manager_default.print(` ${import_chalk73.default.dim("Description:")} ${segment.description}
|
|
305
|
+
`),segment.usedByFlags&&output_manager_default.print(` ${import_chalk73.default.dim("Used by flags:")} ${segment.usedByFlags.length}
|
|
306
|
+
`),segment.usedBySegments&&output_manager_default.print(` ${import_chalk73.default.dim("Used by segments:")} ${segment.usedBySegments.length}
|
|
307
|
+
`),showTimestamps&&(output_manager_default.print(` ${import_chalk73.default.dim("Created:")} ${formatDate(segment.createdAt)}
|
|
308
|
+
`),output_manager_default.print(` ${import_chalk73.default.dim("Updated:")} ${formatDate(segment.updatedAt)}
|
|
309
|
+
`)),printSegmentData(segment,settings)}function printSegmentData(segment,settings){let{rules:rules2=[],include={},exclude={}}=segment.data;if(output_manager_default.print(`
|
|
310
|
+
${import_chalk73.default.dim("Rules:")}
|
|
311
|
+
`),rules2.length===0)output_manager_default.print(` ${import_chalk73.default.dim("-")}
|
|
312
|
+
`);else for(let rule of rules2){output_manager_default.print(` ${import_chalk73.default.dim("Rule ID:")} ${rule.id}
|
|
313
|
+
`),output_manager_default.print(` ${import_chalk73.default.dim("\u2192")} ${formatOutcome2(rule.outcome)}
|
|
314
|
+
`);for(let condition of rule.conditions)output_manager_default.print(` ${import_chalk73.default.dim("if")} ${formatCondition(condition,settings)}
|
|
315
|
+
`)}printMembership("Include",include),printMembership("Exclude",exclude),output_manager_default.print(`
|
|
316
|
+
`)}function printMembership(label,map){output_manager_default.print(`
|
|
317
|
+
${import_chalk73.default.dim(`${label}:`)}
|
|
318
|
+
`);let entries=getMembershipEntries(map);if(entries.length===0){output_manager_default.print(` ${import_chalk73.default.dim("-")}
|
|
319
|
+
`);return}for(let entry of entries){let note=entry.note?import_chalk73.default.gray(` (${entry.note})`):"";output_manager_default.print(` ${import_chalk73.default.dim(`${entry.entity}.${entry.attribute}:`)} ${entry.value}${note}
|
|
320
|
+
`)}}function getMembershipEntries(map){return Object.entries(map).flatMap(([entity,attributes])=>Object.entries(attributes).flatMap(([attribute,values])=>values.map(value=>({entity,attribute,value:value.value,note:value.note}))))}function formatOutcome2(outcome){return outcome.type==="all"?"match all conditions":`match ${outcome.passPromille/10}% by ${outcome.base.kind}.${outcome.base.attribute}`}function formatCondition(condition,settings){let lhs=condition.lhs.type==="entity"?`${condition.lhs.kind}.${condition.lhs.attribute}`:"segment",attributeType=condition.lhs.type==="entity"?getFlagAttributeType(settings,condition.lhs.kind,condition.lhs.attribute):void 0,rhs=condition.rhs===void 0?"":` ${formatValue(condition.rhs,attributeType)}`;return`${lhs} ${formatFlagConditionComparator(condition.cmp,{attributeType})}${rhs}`}function formatValue(value,attributeType){let timestampRhs=formatTimestampRhs(value,attributeType);return timestampRhs||(typeof value!="object"||value===null?JSON.stringify(value):value.type==="list"||value.type==="list/inline"?value.items.map(item=>JSON.stringify(item.value)).join(", "):value.type==="regex"?`/${value.pattern}/${value.flags}`:JSON.stringify(value))}async function segmentsInspect(client,argv){let telemetryClient=new FlagsSegmentsInspectTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(segmentsInspectSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[segmentArg]=args,json=flags["--json"],projectName=getProjectNameFromFlags(flags);if(!segmentArg)return output_manager_default.error("Please provide a segment slug or ID to inspect"),output_manager_default.log(`Example: ${getCommandName("flags segments inspect beta-users")}`),2;telemetryClient.trackCliArgumentSegment(segmentArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagJson(json);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1;client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name);try{output_manager_default.spinner("Fetching segment...");let[segment,settings]=await Promise.all([getSegment(client,project.id,segmentArg,!0),getFlagSettings(client,project.id)]);output_manager_default.stopSpinner(),json?client.stdout.write(`${JSON.stringify({segment},null,2)}
|
|
321
|
+
`):printSegmentDetails({segment,projectSlugLink,settings})}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var import_chalk74=__toESM(require_source(),1);var import_fast_deep_equal7=__toESM(require_fast_deep_equal(),1);import{randomBytes as randomBytes2}from"node:crypto";function parseEntityAttributeSelector(input){let trimmed=input.trim(),separatorIndex=trimmed.indexOf(".");if(separatorIndex<=0||separatorIndex===trimmed.length-1)throw new Error(`Invalid entity attribute "${input}". Use ENTITY.ATTRIBUTE, for example user.signupAt.`);return{kind:trimmed.slice(0,separatorIndex),attribute:trimmed.slice(separatorIndex+1)}}var OPERATOR_ALIASES={"=":"eq","==":"eq",eq:"eq",equals:"eq",equal:"eq","does-not-equal":"!eq","not-equals":"!eq","not-equal":"!eq","!=":"!eq","!eq":"!eq",in:"oneOf",oneof:"oneOf","one-of":"oneOf",oneOf:"oneOf","not-in":"!oneOf","not-one-of":"!oneOf","!oneof":"!oneOf","!oneOf":"!oneOf",containsallof:"containsAllOf","contains-all-of":"containsAllOf",containsAllOf:"containsAllOf",containsanyof:"containsAnyOf","contains-any-of":"containsAnyOf",containsAnyOf:"containsAnyOf",containsnoneof:"containsNoneOf","contains-none-of":"containsNoneOf",containsNoneOf:"containsNoneOf",startswith:"startsWith","starts-with":"startsWith",startsWith:"startsWith",endswith:"endsWith","ends-with":"endsWith",endsWith:"endsWith",contains:"contains","!contains":"!contains","does-not-contain":"!contains",notcontains:"!contains","not-contains":"!contains",notContains:"!contains",exists:"ex",ex:"ex","!exists":"!ex","not-exists":"!ex","!ex":"!ex",gt:"gt",">":"gt",after:"gt",gte:"gte",">=":"gte","at-or-after":"gte","on-or-after":"gte",lt:"lt","<":"lt",before:"lt",lte:"lte","<=":"lte","at-or-before":"lte","on-or-before":"lte"},LIST_OPERATORS=new Set(FLAG_CONDITION_LIST_COMPARATORS),RHS_OPTIONAL_OPERATORS=new Set(FLAG_CONDITION_RHS_OPTIONAL_COMPARATORS);function shortId(prefix){let alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",bytes=randomBytes2(12),id=prefix;for(let i=0;i<bytes.length;i++)id+=alphabet[bytes[i]%alphabet.length];return id}function parseSegmentDataInput(input){let value=parseJson(input,"segment data");if(!isRecord(value))throw new Error("Segment data must be a JSON object");return value}function parseSegmentRuleInput(input,outcome={type:"all"}){let trimmed=input.trim();if(!trimmed)throw new Error("Segment rule cannot be empty");if(trimmed.startsWith("{")){let value=parseJson(trimmed,"segment rule");if(!isRecord(value))throw new Error("Segment rule JSON must be an object");return value}let conditions=trimmed.split(";").map(part=>part.trim()).filter(Boolean).map(parseSegmentConditionInput);if(conditions.length===0)throw new Error("Segment rule must include at least one condition");return{id:shortId("rule_"),conditions,outcome}}function parseSegmentConditionInput(input){let[field,operator,...valueParts]=input.split(":");if(!field||!operator)throw new Error(`Invalid segment rule "${input}". Use ENTITY.ATTRIBUTE:OPERATOR:VALUE, for example user.email:ends-with:@vercel.com.`);let lhs=parseEntityAttribute(field),cmp=parseComparator(operator),rawValue=valueParts.join(":");if(!rawValue&&!RHS_OPTIONAL_OPERATORS.has(cmp))throw new Error(`Segment rule "${input}" is missing a value`);return{lhs,cmp,...rawValue?{rhs:parseConditionValue(rawValue,cmp)}:{}}}function parseSegmentValueInput(input){let separatorIndex=input.indexOf("=");if(separatorIndex===-1)throw new Error(`Invalid segment value "${input}". Use ENTITY.ATTRIBUTE=VALUE.`);let lhs=input.slice(0,separatorIndex).trim(),rawValue=input.slice(separatorIndex+1).trim();if(!rawValue)throw new Error(`Invalid segment value "${input}". Value cannot be empty.`);let{kind:entity,attribute}=parseEntityAttribute(lhs),{value,note}=splitValueNote(rawValue);return{entity,attribute,value:note?{value,note}:{value}}}function addSegmentValue(data,field,input){let{entity,attribute,value}=parseSegmentValueInput(input),map=data[field]??{},entityValues=map[entity]??{},values=entityValues[attribute]??[];entityValues[attribute]=values.concat(value),map[entity]=entityValues,data[field]=map}function buildSegmentOperations(field,action,inputs){return inputs.map(input=>{let{entity,attribute,value}=parseSegmentValueInput(input);return{action,field,entity,attribute,value}})}function buildSegmentRuleOperations(action,inputs){return inputs.map(input=>buildSegmentRuleOperation(action,input))}function buildSegmentTargetOperations(action,inputs){return inputs.map(input=>parseSegmentTargetOperation(action,input))}function applySegmentOperations(data,operations){let next=normalizeSegmentData({rules:structuredClone(data.rules??[]),include:structuredClone(data.include??{}),exclude:structuredClone(data.exclude??{})});for(let operation of operations){if(operation.field==="rule"){if(operation.action==="add")next.rules=(next.rules??[]).concat(structuredClone(operation.rule));else if(operation.ruleId){let rules2=next.rules??[];if(!rules2.some(rule=>rule.id===operation.ruleId))throw new Error(`Segment rule "${operation.ruleId}" does not exist.`);next.rules=rules2.filter(rule=>rule.id!==operation.ruleId)}else if(operation.rule){let ruleToRemove=operation.rule,rules2=next.rules??[];if(!rules2.some(rule=>segmentRulesEqual(rule,ruleToRemove)))throw new Error("Segment rule does not exist.");next.rules=rules2.filter(rule=>!segmentRulesEqual(rule,ruleToRemove))}continue}if(operation.action==="add"){let map2=next[operation.field]??{},entityValues2=map2[operation.entity]??{},values2=entityValues2[operation.attribute]??[];entityValues2[operation.attribute]=values2.concat(operation.value),map2[operation.entity]=entityValues2,next[operation.field]=map2;continue}let entityValues=next[operation.field]?.[operation.entity],values=entityValues?.[operation.attribute],valueExists=values?.some(value=>value.value===operation.value.value);if(!values||!valueExists)throw new Error(`Segment ${operation.field} value "${operation.entity}.${operation.attribute}=${operation.value.value}" does not exist.`);entityValues[operation.attribute]=values.filter(value=>value.value!==operation.value.value)}return next}function parseSegmentTargetOperation(action,input){let separatorIndex=input.indexOf(":");if(separatorIndex===-1)throw new Error(`Invalid segment operation "${input}". Use include:ENTITY.ATTRIBUTE=VALUE, exclude:ENTITY.ATTRIBUTE=VALUE, or rule:ENTITY.ATTRIBUTE:OPERATOR:VALUE.`);let field=input.slice(0,separatorIndex).trim().toLowerCase(),valueInput=input.slice(separatorIndex+1).trim();if(!valueInput)throw new Error(`Invalid segment operation "${input}". Target is empty.`);if(field==="include"||field==="exclude"){let{entity,attribute,value}=parseSegmentValueInput(valueInput);return{action,field,entity,attribute,value}}if(field==="rule"||field==="rules")return buildSegmentRuleOperation(action,valueInput);throw new Error(`Invalid segment operation target "${field}". Use include, exclude, or rule.`)}function buildSegmentRuleOperation(action,input){if(action==="remove"&&isRuleIdInput(input))return{action,field:"rule",ruleId:input.trim()};let rule=parseSegmentRuleInput(input);return action==="add"?{action,field:"rule",rule}:{action,field:"rule",rule}}function normalizeSegmentData(data){return{rules:data.rules??[],include:data.include??{},exclude:data.exclude??{}}}function segmentRulesEqual(a,b){return(0,import_fast_deep_equal7.default)(getComparableRule(a),getComparableRule(b))}function getComparableRule(rule){return{conditions:rule.conditions,outcome:rule.outcome}}function isRuleIdInput(input){let trimmed=input.trim();return!trimmed.startsWith("{")&&!trimmed.includes(":")&&!trimmed.includes(".")}function parseComparator(input,ruleLabel="segment rule"){let normalized=input.trim(),lowercase=normalized.toLowerCase(),comparator=OPERATOR_ALIASES[normalized]??OPERATOR_ALIASES[lowercase];if(!comparator)throw new Error(`Invalid ${ruleLabel} operator "${input}". Valid operators: ${formatFlagConditionComparatorList()}.`);return comparator}function parseEntityAttribute(input){let{kind,attribute}=parseEntityAttributeSelector(input);return{type:"entity",kind,attribute}}function parseConditionValue(input,comparator){let trimmed=input.trim();return LIST_OPERATORS.has(comparator)?{type:"list",items:trimmed.split(",").map(value=>value.trim()).filter(Boolean).map(value=>({value:parseListItemValue(value)}))}:parseScalarValue(trimmed)}function parseScalarValue(value){return value==="true"?!0:value==="false"?!1:value!==""&&Number.isFinite(Number(value))?Number(value):value}function parseListItemValue(value){return value!==""&&Number.isFinite(Number(value))?Number(value):value}function splitValueNote(input){let separatorIndex=input.indexOf("|");if(separatorIndex===-1)return{value:input};let value=input.slice(0,separatorIndex).trim(),note=input.slice(separatorIndex+1).trim();return note?{value,note}:{value}}function parseJson(input,label){try{return JSON.parse(input)}catch{throw new Error(`Invalid JSON for ${label}`)}}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}async function segmentsCreate(client,argv){let telemetryClient=new FlagsSegmentsCreateTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(segmentsCreateSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[slug]=args,label=flags["--label"],description=flags["--description"],hint=flags["--hint"],dataInput=flags["--data"],addInputs=flags["--add"]??[],json=flags["--json"],projectName=getProjectNameFromFlags(flags);if(telemetryClient.trackCliArgumentSlug(slug),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionLabel(label),telemetryClient.trackCliOptionDescription(description),telemetryClient.trackCliOptionHint(hint),telemetryClient.trackCliOptionData(dataInput),telemetryClient.trackCliOptionAdd(addInputs),telemetryClient.trackCliFlagJson(json),!slug)return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide a segment slug to create.",next:[{command:buildCommandWithGlobalFlags(client.argv,"flags segments create <slug> --label <label> --add include:user.id=<value>"),when:"create a segment with explicit values"}]},2),2):(output_manager_default.error("Please provide a slug for the segment"),output_manager_default.log(`Example: ${getCommandName('flags segments create beta-users --label "Beta users" --add include:user.id=user_123')}`),2);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.NOT_LINKED,message:"Your codebase is not linked to a project. Run link first.",next:[{command:buildCommandWithGlobalFlags(client.argv,"link"),when:"link the project"}]},1),1):(output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1);client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name);label=await resolveSegmentLabel(client,label,slug),hint=await resolveSegmentHint(client,hint,description,label);let data,settings;try{settings=await getFlagSettings(client,project.id),data=coerceTimestampSegmentData(await collectSegmentData(client,{dataInput,addInputs}),settings,"input")}catch(err){return output_manager_default.error(err.message),1}let request={slug,label,description,data,hint};try{output_manager_default.spinner("Creating segment...");let segment=await createSegment(client,project.id,request);if(output_manager_default.stopSpinner(),json)return client.stdout.write(`${JSON.stringify({segment},null,2)}
|
|
322
|
+
`),0;output_manager_default.success(`Feature flag segment ${import_chalk74.default.bold(segment.slug)} created`),printSegmentDetails({segment,projectSlugLink,showTimestamps:!1,settings})}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}async function resolveSegmentLabel(client,label,slug){let defaultLabel=humanizeSlug(slug);return label||client.stdin.isTTY&&!client.nonInteractive&&(await client.input.text({message:`Enter a label for this segment (press Enter for "${defaultLabel}"):`})).trim()||defaultLabel}async function resolveSegmentHint(client,hint,description,label){return hint||(client.stdin.isTTY&&!client.nonInteractive?(await client.input.text({message:`Enter a hint for who belongs in this segment (press Enter for "${description||label}"):`})).trim()||description||label:description||label)}async function collectSegmentData(client,input){let hasExplicitData=!!input.dataInput,data=hasExplicitData?parseSegmentDataInput(input.dataInput):normalizeSegmentData({}),operations=buildSegmentTargetOperations("add",input.addInputs),nextData=operations.length>0?applySegmentOperations(data,operations):data;return!hasExplicitData&&input.addInputs.length===0&&client.stdin.isTTY&&!client.nonInteractive&&await collectSegmentDataInteractively(client,nextData),normalizeSegmentData(nextData)}async function collectSegmentDataInteractively(client,data){let addAnother=await client.input.confirm("Add segment criteria now?",!0);for(;addAnother;){let kind=await client.input.select({message:"What do you want to add?",choices:[{name:"Include an exact entity value",value:"include"},{name:"Exclude an exact entity value",value:"exclude"},{name:"Add a rule",value:"rule"}]});if(kind==="rule"){let rule=await client.input.text({message:"Enter rule as ENTITY.ATTRIBUTE:OPERATOR:VALUE (for example user.email:ends-with:@vercel.com):"});data.rules=(data.rules??[]).concat(parseSegmentRuleInput(rule))}else{let value=await client.input.text({message:`Enter ${kind} value as ENTITY.ATTRIBUTE=VALUE:`});addSegmentValue(data,kind,value)}addAnother=await client.input.confirm("Add another criterion?",!1)}}function humanizeSlug(slug){return slug.split(/[-_\s]+/).filter(Boolean).map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join(" ")}var import_chalk75=__toESM(require_source(),1);async function segmentsUpdate(client,argv){let telemetryClient=new FlagsSegmentsUpdateTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(segmentsUpdateSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,segmentArg=args[0],label=flags["--label"],description=flags["--description"],hint=flags["--hint"],dataInput=flags["--data"],addInputs=flags["--add"]??[],removeInputs=flags["--remove"]??[],json=flags["--json"],projectName=getProjectNameFromFlags(flags);telemetryClient.trackCliArgumentSegment(segmentArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionLabel(label),telemetryClient.trackCliOptionDescription(description),telemetryClient.trackCliOptionHint(hint),telemetryClient.trackCliOptionData(dataInput),telemetryClient.trackCliOptionAdd(addInputs),telemetryClient.trackCliOptionRemove(removeInputs),telemetryClient.trackCliFlagJson(json);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.NOT_LINKED,message:"Your codebase is not linked to a project. Run link first.",next:[{command:buildCommandWithGlobalFlags(client.argv,"link"),when:"link the project"}]},1),1):(output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1);client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project,org}=link,projectSlugLink=formatProject(org.slug,project.name);try{if(!segmentArg&&(segmentArg=await resolveSegmentArg(client,project.id),!segmentArg))return 1;let settings=await getFlagSettings(client,project.id),operations=coerceTimestampOperations(buildOperations({addInputs,removeInputs}),settings),hasChanges=label!==void 0||description!==void 0||hint!==void 0||!!dataInput||operations.length>0,request;if(!hasChanges&&client.stdin.isTTY&&!client.nonInteractive){output_manager_default.spinner("Fetching segment...");let segment2=await getSegment(client,project.id,segmentArg,!0);output_manager_default.stopSpinner(),request=await collectUpdateInteractively(client,segment2,settings)}else request=await buildUpdateRequest(client,project.id,segmentArg,{label,description,hint,dataInput,operations,settings});if(request=coerceTimestampUpdateRequest(request,settings),!hasUpdateRequestChanges(request))return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide at least one segment update option, such as --label, --data, --add, or --remove.",next:[{command:buildCommandWithGlobalFlags(client.argv,"flags segments update <segment> --add include:user.id=<value>"),when:"add a value to a segment"},{command:buildCommandWithGlobalFlags(client.argv,"flags segments update <segment> --remove include:user.id=<value>"),when:"remove a value from a segment"},{command:buildCommandWithGlobalFlags(client.argv,"flags segments inspect <segment> --json"),when:"inspect the current segment data first"}]},2),2):(output_manager_default.warn("No segment changes were provided"),0);output_manager_default.spinner("Updating segment...");let segment=await updateSegment(client,project.id,segmentArg,request);if(output_manager_default.stopSpinner(),json)return client.stdout.write(`${JSON.stringify({segment},null,2)}
|
|
323
|
+
`),0;output_manager_default.success(`Feature flag segment ${import_chalk75.default.bold(segment.slug)} updated`),printSegmentDetails({segment,projectSlugLink,showTimestamps:!1,settings})}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}async function resolveSegmentArg(client,projectId){if(client.nonInteractive){outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide a segment slug or ID. Run `vercel flags segments ls` to list segments.",next:[{command:buildCommandWithGlobalFlags(client.argv,"flags segments update <segment> --add include:user.id=<value>"),when:"update a segment by slug or ID"},{command:buildCommandWithGlobalFlags(client.argv,"flags segments ls"),when:"list segments to find the slug or ID"}]},2);return}if(!client.stdin.isTTY){output_manager_default.error("Please provide a segment slug or ID to update"),output_manager_default.log(`Example: ${getCommandName("flags segments update beta-users --add include:user.id=user_123")}`);return}output_manager_default.spinner("Fetching segments...");let segments2=await getSegments(client,projectId,!0);if(output_manager_default.stopSpinner(),segments2.length===0){output_manager_default.error("No feature flag segments found"),output_manager_default.log(`Create one with: ${getCommandName('flags segments create beta-users --label "Beta users" --add include:user.id=user_123')}`);return}return client.input.select({message:"Select a segment to update:",choices:segments2.map(segment=>({name:`${segment.label} (${segment.slug})`,value:segment.slug}))})}async function buildUpdateRequest(client,projectId,segmentArg,input){let request={};if(input.label!==void 0&&(request.label=input.label),input.description!==void 0&&(request.description=input.description),input.hint!==void 0&&(request.hint=input.hint),input.dataInput&&(request.data=coerceTimestampSegmentData(parseSegmentDataInput(input.dataInput),input.settings,"input")),request.data)request.data=applySegmentOperations(request.data,input.operations);else if(hasRuleOperations(input.operations)){output_manager_default.spinner("Fetching segment...");let segment=await getSegment(client,projectId,segmentArg,!0);output_manager_default.stopSpinner(),request.data=applySegmentOperations(segment.data,input.operations)}else if(input.operations.length>0){if(hasRemoveOperations(input.operations)){output_manager_default.spinner("Fetching segment...");let segment=await getSegment(client,projectId,segmentArg,!0);output_manager_default.stopSpinner(),applySegmentOperations(segment.data,input.operations)}request.operations=input.operations.filter(isMembershipOperation)}return request}function buildOperations(input){return[...buildSegmentTargetOperations("add",input.addInputs),...buildSegmentTargetOperations("remove",input.removeInputs)]}function hasRuleOperations(operations){return operations.some(operation=>operation.field==="rule")}function hasRemoveOperations(operations){return operations.some(operation=>operation.action==="remove")}function isMembershipOperation(operation){return operation.field==="include"||operation.field==="exclude"}async function collectUpdateInteractively(client,segment,settings){let request={},data,replacingRules=!1,operations=[],keepEditing=!0;for(;keepEditing;){let action=await client.input.select({message:"What do you want to update?",choices:[{name:"Label",value:"label"},{name:"Description",value:"description"},{name:"Hint",value:"hint"},{name:"Add rule",value:"add-rule"},{name:"Remove rule",value:"remove-rule"},{name:"Replace all rules",value:"replace-rules"},{name:"Add include value",value:"include"},{name:"Add exclude value",value:"exclude"},{name:"Remove include value",value:"remove-include"},{name:"Remove exclude value",value:"remove-exclude"},{name:"Replace full data JSON",value:"data"},{name:"Done",value:"done"}]});switch(action){case"label":request.label=await client.input.text({message:`Enter a new label (current: ${segment.label}):`});break;case"description":request.description=await client.input.text({message:"Enter a new description:"});break;case"hint":request.hint=await client.input.text({message:`Enter a new hint (current: ${segment.hint}):`});break;case"add-rule":{let rule=await client.input.text({message:"Enter rule as ENTITY.ATTRIBUTE:OPERATOR:VALUE:"});operations.push(...buildSegmentRuleOperations("add",[rule]));break}case"remove-rule":{let rule=await client.input.text({message:"Enter rule as ENTITY.ATTRIBUTE:OPERATOR:VALUE or rule ID:"});operations.push(...buildSegmentRuleOperations("remove",[rule]));break}case"replace-rules":{let rule=await client.input.text({message:"Enter rule as ENTITY.ATTRIBUTE:OPERATOR:VALUE (repeat by choosing this again):"});replacingRules||(data=normalizeSegmentData({...segment.data,rules:[]}),replacingRules=!0),data=normalizeSegmentData(data??segment.data);let[coercedRule]=coerceTimestampSegmentData({rules:[parseSegmentRuleInput(rule)]},settings,"input").rules;data.rules=(data.rules??[]).concat(coercedRule);break}case"include":case"exclude":case"remove-include":case"remove-exclude":{let value=await client.input.text({message:"Enter value as ENTITY.ATTRIBUTE=VALUE:"});operations.push(...buildSegmentOperations(action.includes("include")?"include":"exclude",action.startsWith("remove")?"remove":"add",[value]));break}case"data":{let value=await client.input.text({message:"Enter full segment data JSON:"});data=coerceTimestampSegmentData(parseSegmentDataInput(value),settings,"input");break}case"done":keepEditing=!1;break}keepEditing&&(keepEditing=await client.input.confirm("Make another change?",!1))}let coercedOperations=coerceTimestampOperations(operations,settings,"input");return data?request.data=applySegmentOperations(data,coercedOperations):hasRuleOperations(coercedOperations)?request.data=applySegmentOperations(segment.data,coercedOperations):coercedOperations.length>0&&(request.operations=coercedOperations.filter(isMembershipOperation)),request}function hasUpdateRequestChanges(request){return request.label!==void 0||request.description!==void 0||request.hint!==void 0||request.data!==void 0||!!request.operations?.length}function coerceTimestampUpdateRequest(request,settings){return request.data?{...request,data:coerceTimestampSegmentData(request.data,settings)}:request}var import_chalk76=__toESM(require_source(),1);async function segmentsRm(client,argv){let telemetryClient=new FlagsSegmentsRmTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(segmentsRemoveSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,segmentArg=args[0],skipConfirmation=flags["--yes"],projectName=getProjectNameFromFlags(flags);telemetryClient.trackCliArgumentSegment(segmentArg),telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliFlagYes(skipConfirmation);let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return client.nonInteractive?(outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.NOT_LINKED,message:"Your codebase is not linked to a project. Run link first.",next:[{command:buildCommandWithGlobalFlags(client.argv,"link"),when:"link the project"}]},1),1):(output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),1);client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;try{if(!segmentArg&&(segmentArg=await resolveSegmentArg2(client,project.id),!segmentArg))return 1;output_manager_default.spinner("Fetching segment...");let segment=await getSegment(client,project.id,segmentArg,!1);if(output_manager_default.stopSpinner(),!skipConfirmation){if(!client.stdin.isTTY)return output_manager_default.error("Missing required flag --yes. Use --yes to skip the confirmation prompt in non-interactive mode."),2;if(client.nonInteractive)return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.CONFIRMATION_REQUIRED,message:`Confirm deletion of segment ${segment.slug} by adding --yes.`,next:[{command:buildCommandWithGlobalFlags(client.argv,`flags segments delete ${segmentArg} --yes`),when:"confirm and delete the segment"}]},1),1;if(!await client.input.confirm(`Are you sure you want to delete segment ${import_chalk76.default.bold(segment.slug)}?`,!1))return output_manager_default.log("Aborted"),0}output_manager_default.spinner("Deleting segment..."),await deleteSegment(client,project.id,segmentArg),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag segment ${import_chalk76.default.bold(segment.slug)} deleted`)}catch(err){return output_manager_default.stopSpinner(),handleSegmentInUseError(client,err,segmentArg)||printError(err),1}return 0}function handleSegmentInUseError(client,error,segmentArg){if(!isAPIError(error)||error.code!=="SEGMENT_IN_USE")return!1;let usedBy=error.usedBy,flags=usedBy?.flags??[],segments2=usedBy?.segments??[],segment=segmentArg??"<segment>",formatReferences=references=>references.map(reference=>{let primary=reference.name??reference.label??reference.slug??reference.id;return primary&&reference.slug&&reference.slug!==primary?`${primary} (${reference.slug})`:primary??"Unknown reference"}).join(", "),firstFlag=flags.find(reference=>reference.slug||reference.id),firstSegment=segments2.find(reference=>reference.slug||reference.id),inspectSubcommand2=firstFlag!==void 0?`flags inspect ${firstFlag.slug??firstFlag.id}`:firstSegment!==void 0?`flags segments inspect ${firstSegment.slug??firstSegment.id}`:void 0,lines=[`Segment ${segment} is still in use and can't be deleted.`];flags.length>0&&lines.push(`Used by feature flags: ${formatReferences(flags)}`),segments2.length>0&&lines.push(`Used by segments: ${formatReferences(segments2)}`);let message=lines.join(`
|
|
324
|
+
`);return outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.SEGMENT_IN_USE,message,next:[...inspectSubcommand2?[{command:buildCommandWithGlobalFlags(client.argv,inspectSubcommand2),when:"inspect one reference that still uses the segment"}]:[],{command:buildCommandWithGlobalFlags(client.argv,`flags segments delete ${segment} --yes`),when:"retry after removing all references"}]},1),inspectSubcommand2?lines.push("",`Run ${getCommandName(inspectSubcommand2)} to inspect one reference, remove the segment from each rule, then try deleting the segment again.`):lines.push("","Remove every flag or segment rule that references it, then try deleting the segment again."),output_manager_default.error(lines.join(`
|
|
325
|
+
`)),!0}async function resolveSegmentArg2(client,projectId){if(client.nonInteractive){outputAgentError(client,{status:AGENT_STATUS.ERROR,reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Please provide a segment slug or ID. Run `vercel flags segments ls` to list segments.",next:[{command:buildCommandWithGlobalFlags(client.argv,"flags segments delete <segment> --yes"),when:"delete a segment by slug or ID"},{command:buildCommandWithGlobalFlags(client.argv,"flags segments ls"),when:"list segments to find the slug or ID"}]},2);return}if(!client.stdin.isTTY){output_manager_default.error("Please provide a segment slug or ID to delete"),output_manager_default.log(`Example: ${getCommandName("flags segments delete beta-users")}`);return}output_manager_default.spinner("Fetching segments...");let segments2=await getSegments(client,projectId);if(output_manager_default.stopSpinner(),segments2.length===0){output_manager_default.log("No feature flag segments found");return}return client.input.select({message:"Select a segment to delete:",choices:segments2.map(segment=>({name:`${segment.label} (${segment.slug})`,value:segment.slug}))})}var COMMAND_CONFIG13={ls:getCommandAliases(segmentsListSubcommand),inspect:getCommandAliases(segmentsInspectSubcommand),create:getCommandAliases(segmentsCreateSubcommand),update:getCommandAliases(segmentsUpdateSubcommand),delete:getCommandAliases(segmentsRemoveSubcommand)};async function segments(client){let telemetry=new FlagsSegmentsTelemetryClient({opts:{store:client.telemetryEventStore}}),flagsSpecification=getFlagsSpecification(segmentsSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(client.argv.slice(4),flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG13),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("flags segments",subcommand),output_manager_default.print(help(segmentsSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:segmentsSubcommand,columns:client.stderr.columns}))}switch(subcommand){case"ls":return needHelp?(telemetry.trackCliFlagHelp("flags segments",subcommandOriginal),printHelp(segmentsListSubcommand),0):(telemetry.trackCliSubcommandList(subcommandOriginal),segmentsLs(client,args));case"inspect":return needHelp?(telemetry.trackCliFlagHelp("flags segments",subcommandOriginal),printHelp(segmentsInspectSubcommand),0):(telemetry.trackCliSubcommandInspect(subcommandOriginal),segmentsInspect(client,args));case"create":return needHelp?(telemetry.trackCliFlagHelp("flags segments",subcommandOriginal),printHelp(segmentsCreateSubcommand),0):(telemetry.trackCliSubcommandCreate(subcommandOriginal),subcommandOriginal==="add"&&warnDeprecatedSubcommand(client,"flags segments add","flags segments create"),segmentsCreate(client,args));case"update":return needHelp?(telemetry.trackCliFlagHelp("flags segments",subcommandOriginal),printHelp(segmentsUpdateSubcommand),0):(telemetry.trackCliSubcommandUpdate(subcommandOriginal),segmentsUpdate(client,args));case"delete":return needHelp?(telemetry.trackCliFlagHelp("flags segments",subcommandOriginal),printHelp(segmentsRemoveSubcommand),0):(telemetry.trackCliSubcommandDelete(subcommandOriginal),subcommandOriginal==="remove"&&warnDeprecatedSubcommand(client,"flags segments remove","flags segments delete"),segmentsRm(client,args));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG13)),output_manager_default.print(help(segmentsSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),2}}var FlagsEntitiesTelemetryClient=class extends TelemetryClient{trackSubcommand(subcommand,actual){this.trackCliSubcommand({subcommand,value:actual})}trackArguments(args,flags){args[0]&&this.trackCliArgument({arg:"kind",value:this.redactedValue}),this.trackCliOptionProject(flags["--project"]);for(let option of["label","attribute","add-attribute","remove-attribute","set-attribute-type"]){let value=flags[`--${option}`];(typeof value=="string"?value.trim():Array.isArray(value)&&value.length)&&this.trackCliOption({option,value:this.redactedValue})}for(let flag of["json","yes"])flags[`--${flag}`]&&this.trackCliFlag(flag)}};var import_chalk78=__toESM(require_source(),1),import_pluralize5=__toESM(require_pluralize(),1);var import_chalk77=__toESM(require_source(),1);async function loadEntityUsageSources(client,projectId){let[active,archived,segments2]=await Promise.all([getFlagsFromDatabase(client,projectId,"active"),getFlagsFromDatabase(client,projectId,"archived"),getSegments(client,projectId)]);return{flags:[...active,...archived],segments:segments2}}async function getFlagsFromDatabase(client,projectId,state){let flags=[],query=new URLSearchParams({state,limit:String(MAX_FLAGS_PAGE_LIMIT)}),cursor;do{let response=await client.fetch(`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/flags?${query}`);flags.push(...response.data),cursor=response.pagination?.next??null,cursor&&query.set("cursor",cursor)}while(cursor);return flags}function collectEntityUsage(sources,kind,attribute){let matches=reference=>reference.kind===kind&&(attribute===void 0||reference.attribute===attribute);return{flags:sources.flags.filter(flag=>flagReferences(flag).some(matches)).map(flag=>flag.slug),segments:sources.segments.filter(segment=>segmentReferences(segment).some(matches)).map(segment=>segment.slug)}}function hasEntityUsage(usage){return usage.flags.length>0||usage.segments.length>0}function flagReferences(flag){let references=Object.values(flag.environments).flatMap(environmentReferences);return flag.experiment&&references.push(flag.experiment.base),references}function environmentReferences(environment){let references=[];(environment.fallthrough.type==="split"||environment.fallthrough.type==="rollout")&&references.push(environment.fallthrough.base);for(let rule of environment.rules){for(let condition of rule.conditions)condition.lhs.type==="entity"&&references.push(condition.lhs);(rule.outcome.type==="split"||rule.outcome.type==="rollout")&&references.push(rule.outcome.base)}for(let targets2 of Object.values(environment.targets??{}))references.push(...membershipReferences(targets2));return references}function segmentReferences(segment){let references=[];for(let rule of segment.data.rules??[]){for(let condition of rule.conditions)condition.lhs.type==="entity"&&references.push(condition.lhs);rule.outcome.type==="split"&&references.push(rule.outcome.base)}return references.push(...membershipReferences(segment.data.include)),references.push(...membershipReferences(segment.data.exclude)),references}function membershipReferences(map){return map?Object.entries(map).flatMap(([kind,attributes])=>Object.entries(attributes).filter(([,values])=>values.length>0).map(([attribute])=>({kind,attribute}))):[]}async function resolveEntitiesProject(client,projectName){let link=await getLinkedFlagsProject(client,projectName);return link.status==="error"?{exitCode:link.exitCode}:link.status==="not_linked"?client.nonInteractive?(entityAgentError(client,{reason:AGENT_REASON.NOT_LINKED,message:"Your codebase is not linked to a project. Run link first.",next:[{command:"link",when:"link the project"}]}),{exitCode:1}):(output_manager_default.fatal(`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName("link")} to link it.`),{exitCode:1}):(client.config.currentTeam=link.org.type==="team"?link.org.id:void 0,{project:link.project,org:link.org,projectSlugLink:formatProject(link.org.slug,link.project.name)})}function isExitCodeResult(result){return"exitCode"in result}function formatAttributeList(entity){return entity.attributes.length===0?import_chalk77.default.dim("-"):entity.attributes.map(attribute=>`${attribute.key}:${import_chalk77.default.dim(attribute.type)}`).join(", ")}function printEntityDetails(entity,projectSlugLink){output_manager_default.log(`
|
|
326
|
+
Feature flag entity ${import_chalk77.default.bold(entity.kind)} for ${projectSlugLink}
|
|
327
|
+
`),output_manager_default.print(` ${import_chalk77.default.dim("Kind:")} ${entity.kind}
|
|
328
|
+
`),output_manager_default.print(` ${import_chalk77.default.dim("Label:")} ${entity.label}
|
|
329
|
+
`),output_manager_default.print(` ${import_chalk77.default.dim("Attributes:")}
|
|
330
|
+
`),entity.attributes.length===0&&output_manager_default.print(` ${import_chalk77.default.dim("-")}
|
|
331
|
+
`);for(let attribute of entity.attributes)output_manager_default.print(` ${attribute.key} ${import_chalk77.default.dim(attribute.type)}
|
|
332
|
+
`);output_manager_default.print(`
|
|
333
|
+
`)}function reportEntityNotFound(client,kind,retryCommand){entityAgentError(client,{reason:AGENT_REASON.NOT_FOUND,message:`Entity ${kind} was not found in this project.`,next:[{command:"flags entities ls",when:"list entities to find the kind"},{command:retryCommand,when:"replace <kind> with an existing entity kind and retry"}]}),output_manager_default.fatal(`Entity ${import_chalk77.default.bold(kind)} was not found. Run ${cmd(buildCommandWithGlobalFlags(client.argv,"flags entities ls",void 0,{preserveProject:!0,excludeFlags:["--yes"]}))} to list entities.`)}function reportEntityInUse(client,options){let{kind,attribute,usage,retryCommand}=options;if(!hasEntityUsage(usage))return!1;let lines=[`${attribute?`Attribute ${kind}.${attribute}`:`Entity ${kind}`} is still in use and can't be changed.`];usage.flags.length>0&&lines.push(`Used by feature flags: ${usage.flags.join(", ")}`),usage.segments.length>0&&lines.push(`Used by segments: ${usage.segments.join(", ")}`);let inspectCommand=usage.flags.length>0?`flags inspect ${quoteArg(usage.flags[0])}`:`flags segments inspect ${quoteArg(usage.segments[0])}`;return entityAgentError(client,{reason:AGENT_REASON.ENTITY_IN_USE,message:lines.join(`
|
|
334
|
+
`),next:[{command:inspectCommand,when:"inspect one reference that still uses it"},{command:retryCommand,when:"retry after removing all references"}]}),lines.push("",`Run ${cmd(buildCommandWithGlobalFlags(client.argv,inspectCommand,void 0,{preserveProject:!0,excludeFlags:["--yes"]}))} to inspect one reference, remove all references to ${attribute?"the attribute":"the entity"}, then try again.`),output_manager_default.fatal(lines.join(`
|
|
335
|
+
`)),!0}async function selectEntityKind(client,entities2,action,retryCommand){if(client.nonInteractive){entityAgentError(client,{reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Provide an entity kind. Run `vercel flags entities ls` to list entities.",next:[{command:retryCommand,when:`replace <kind> with the entity kind to ${action}`},{command:"flags entities ls",when:"list entities to find the kind"}]});return}if(!client.stdin.isTTY){output_manager_default.fatal(`Provide an entity kind to ${action}`),output_manager_default.log(`Example: ${getCommandName(action==="delete"?"flags entities delete device":"flags entities update user --add-attribute email:string")}`);return}if(entities2.length===0){output_manager_default.log("No feature flag entities found");return}return client.input.select({message:`Select an entity to ${action}:`,choices:entities2.map(entity=>({name:`${entity.label} (${entity.kind})`,value:entity.kind}))})}function parseEntityArguments(client,argv,options){let parsed=parseArguments(argv,getFlagsSpecification(options));return new FlagsEntitiesTelemetryClient({opts:{store:client.telemetryEventStore}}).trackArguments(parsed.args,parsed.flags),parsed}function entityAgentError(client,payload){outputAgentError(client,{...payload,status:AGENT_STATUS.ERROR,next:payload.next?.map(next=>({...next,command:buildCommandWithGlobalFlags(client.argv,next.command,void 0,{preserveProject:next.command.startsWith("flags "),excludeFlags:["--yes"]})}))},1)}async function entitiesLs(client,argv){let parsedArgs=parseEntityArguments(client,argv,entitiesListSubcommand.options),{flags}=parsedArgs,json=flags["--json"],projectName=getProjectNameFromFlags(flags),context=await resolveEntitiesProject(client,projectName);if(isExitCodeResult(context))return context.exitCode;let{project,projectSlugLink}=context,lsStamp=stamp_default();output_manager_default.spinner(`Fetching feature flag entities for ${projectSlugLink}`);let settings=await getFlagSettings(client,project.id).catch(err=>{if(!(isAPIError(err)&&err.status===404&&err.code==="settings_not_found"))throw err});output_manager_default.stopSpinner();let entities2=settings?.entities??[];return json?client.stdout.write(`${JSON.stringify({entities:entities2},null,2)}
|
|
336
|
+
`):settings?entities2.length===0?(output_manager_default.log(`No feature flag entities found for ${projectSlugLink} ${import_chalk78.default.gray(lsStamp())}`),output_manager_default.log(`
|
|
337
|
+
Create one with: ${getCommandName("flags entities create user --label User --attribute id:string")}`)):(output_manager_default.log(`${(0,import_pluralize5.default)("feature flag entity",entities2.length,!0)} found for ${projectSlugLink} ${import_chalk78.default.gray(lsStamp())}`),printEntitiesTable(entities2)):(output_manager_default.log(`Flags is not set up for ${projectSlugLink} yet.`),output_manager_default.log(`
|
|
338
|
+
Create your first flag to set it up: ${cmd(buildCommandWithGlobalFlags(client.argv,"flags create my-feature",void 0,{preserveProject:!0}))}`)),0}function printEntitiesTable(entities2){let headers=["Kind","Label","Attributes"],rows=entities2.map(entity=>[import_chalk78.default.bold(entity.kind),entity.label,formatAttributeList(entity)]),table2=formatTable(headers,["l","l","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
339
|
+
${table2}
|
|
340
|
+
`)}var import_chalk79=__toESM(require_source(),1);var IDENTIFIER_PATTERN=/^[a-zA-Z0-9_-]+$/,MAX_ENTITIES=32,MAX_ATTRIBUTES=32,MAX_IDENTIFIER_LENGTH=128;function validateEntityKind(kind){if(!IDENTIFIER_PATTERN.test(kind)||kind.length>MAX_IDENTIFIER_LENGTH)throw new Error(`Invalid entity kind "${kind}". Use up to ${MAX_IDENTIFIER_LENGTH} letters, numbers, dashes, and underscores, for example user.`)}function validateEntityLabel(label){if(label.trim().length===0)throw new Error("Entity label can not be empty.");if(label.length>MAX_IDENTIFIER_LENGTH)throw new Error(`Entity label can not be longer than ${MAX_IDENTIFIER_LENGTH} characters.`)}function validateAttributeKey(key){if(!IDENTIFIER_PATTERN.test(key)||key.length>MAX_IDENTIFIER_LENGTH)throw new Error(`Invalid attribute key "${key}". Use up to ${MAX_IDENTIFIER_LENGTH} letters, numbers, dashes, and underscores, for example plan.`)}function parseAttributeType(type,key){if(!isFlagAttributeType(type))throw new Error(`Invalid type "${type}" for attribute "${key}". Valid types: ${formatFlagAttributeTypeList()}.`);return type}function parseAttributeInput(input){let parts=input.trim().split(":").map(part=>part.trim());if(parts.length!==2||!parts[0]||!parts[1])throw new Error(`Invalid attribute "${input}". Use KEY:TYPE, for example plan:string. Valid types: ${formatFlagAttributeTypeList()}.`);let[key,type]=parts;return validateAttributeKey(key),{key,type:parseAttributeType(type,key)}}function parseAttributeInputs(inputs){let attributes=inputs.map(parseAttributeInput),seen=new Set;for(let attribute of attributes){if(seen.has(attribute.key))throw new Error(`Attribute "${attribute.key}" is specified twice.`);seen.add(attribute.key)}return attributes}function defaultEntityLabel(kind){return kind.split(/[-_\s]+/).filter(Boolean).map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join(" ")}function findEntity(entities2,kind){return entities2.find(entity=>entity.kind===kind)}function findAttribute(entity,key){return entity.attributes.find(attribute=>attribute.key===key)}function validateEntities(entities2){if(entities2.length>MAX_ENTITIES)throw new Error(`A project can have at most ${MAX_ENTITIES} entities. Remove one before adding another.`);let kinds=new Set,labels2=new Set;for(let entity of entities2){if(kinds.has(entity.kind))throw new Error(`Entity kind "${entity.kind}" already exists.`);if(labels2.has(entity.label.trim()))throw new Error(`Entity label "${entity.label}" is already used by another entity.`);if(kinds.add(entity.kind),labels2.add(entity.label.trim()),entity.attributes.length>MAX_ATTRIBUTES)throw new Error(`Entity "${entity.kind}" can have at most ${MAX_ATTRIBUTES} attributes.`);let keys=new Set;for(let attribute of entity.attributes){if(keys.has(attribute.key))throw new Error(`Attribute "${attribute.key}" already exists on entity "${entity.kind}".`);keys.add(attribute.key)}}}async function entitiesCreate(client,argv){let parsedArgs=parseEntityArguments(client,argv,entitiesCreateSubcommand.options),{args,flags}=parsedArgs,[kind]=args,label=flags["--label"]?.trim(),attributeInputs=flags["--attribute"]??[],json=flags["--json"],projectName=getProjectNameFromFlags(flags);if(!kind)return client.nonInteractive?(entityAgentError(client,{reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Provide an entity kind to create.",next:[{command:"flags entities create <kind> --label <label> --attribute <key>:<type>",when:"create an entity with explicit attributes"}]}),2):(output_manager_default.fatal("Provide a kind for the entity"),output_manager_default.log(`Example: ${getCommandName("flags entities create user --label User --attribute id:string")}`),2);let attributes;try{validateEntityKind(kind),label!==void 0&&validateEntityLabel(label),attributes=parseAttributeInputs(attributeInputs)}catch(err){return output_manager_default.fatal(err.message),2}let context=await resolveEntitiesProject(client,projectName);if(isExitCodeResult(context))return context.exitCode;let{project,projectSlugLink}=context;output_manager_default.spinner("Fetching feature flag settings\u2026");let settings=await getFlagSettings(client,project.id);if(output_manager_default.stopSpinner(),findEntity(settings.entities,kind))return output_manager_default.fatal(`Entity ${import_chalk79.default.bold(kind)} already exists. Run ${getCommandName(`flags entities update ${kind}`)} to change it.`),1;let willPrompt=client.stdin.isTTY&&!client.nonInteractive&&(label===void 0||attributes.length===0);willPrompt&&printAlignedLabel("Project",projectSlugLink),label=await resolveEntityLabel(client,label,kind),attributes.length===0&&client.stdin.isTTY&&!client.nonInteractive&&(attributes=await collectAttributesInteractively(client)),willPrompt&&(settings=await getFlagSettings(client,project.id));let entity={kind,label,attributes},entities2=[...settings.entities,entity];try{validateEntityLabel(label),validateEntities(entities2)}catch(err){return output_manager_default.fatal(err.message),1}output_manager_default.spinner("Creating entity\u2026");let updated=await updateFlagSettings(client,project.id,{entities:entities2});output_manager_default.stopSpinner();let created=findEntity(updated.entities,kind)??entity;return json?(client.stdout.write(`${JSON.stringify({entity:created},null,2)}
|
|
341
|
+
`),0):(output_manager_default.success(`Feature flag entity ${import_chalk79.default.bold(created.kind)} created`),printEntityDetails(created,projectSlugLink),0)}async function resolveEntityLabel(client,label,kind){if(label)return label;let defaultLabel=defaultEntityLabel(kind);return client.stdin.isTTY&&!client.nonInteractive&&(await client.input.text({message:`Enter a label for this entity (press Enter for "${defaultLabel}"):`})).trim()||defaultLabel}async function collectAttributesInteractively(client){let attributes=[],addAnother=await client.input.confirm("Add attributes now?",!0);for(;addAnother;){let key=await client.input.text({message:"Attribute key (for example plan):",validate:value=>{try{validateAttributeKey(value.trim())}catch(err){return err.message}return attributes.some(attribute=>attribute.key===value.trim())?`Attribute "${value.trim()}" is already added.`:!0}}),type=await client.input.select({message:"Attribute type:",choices:FLAG_ATTRIBUTE_TYPES.map(value=>({name:value,value}))});attributes.push({key:key.trim(),type}),addAnother=await client.input.confirm("Add another attribute?",!1)}return attributes}var import_chalk80=__toESM(require_source(),1);async function entitiesUpdate(client,argv){let parsedArgs=parseEntityArguments(client,argv,entitiesUpdateSubcommand.options),{args,flags}=parsedArgs,kind=args[0],label=flags["--label"]?.trim(),addInputs=flags["--add-attribute"]??[],removeInputs=flags["--remove-attribute"]??[],setTypeInputs=flags["--set-attribute-type"]??[],json=flags["--json"],projectName=getProjectNameFromFlags(flags),changes;try{changes=parseChanges({label,addInputs,removeInputs,setTypeInputs})}catch(err){return output_manager_default.fatal(err.message),2}if(!(changes.label!==void 0||changes.addAttributes.length>0||changes.removeAttributes.length>0||changes.setAttributeTypes.length>0))return client.nonInteractive?(entityAgentError(client,{reason:AGENT_REASON.MISSING_ARGUMENTS,message:"Provide at least one entity update option, such as --label, --add-attribute, --remove-attribute, or --set-attribute-type.",next:[{command:"flags entities update <kind> --add-attribute <key>:<type>",when:"add an attribute to an entity"},{command:"flags entities update <kind> --remove-attribute <key>",when:"remove an attribute from an entity"},{command:"flags entities ls --json",when:"inspect the current entities first"}]}),2):(output_manager_default.fatal("Provide at least one change: --label, --add-attribute, --remove-attribute, or --set-attribute-type"),output_manager_default.log(`Example: ${getCommandName("flags entities update user --add-attribute email:string")}`),2);let context=await resolveEntitiesProject(client,projectName);if(isExitCodeResult(context))return context.exitCode;let{project,projectSlugLink}=context;output_manager_default.spinner("Fetching feature flag settings\u2026");let settings=await getFlagSettings(client,project.id);if(output_manager_default.stopSpinner(),!kind){if(client.stdin.isTTY&&!client.nonInteractive&&printAlignedLabel("Project",projectSlugLink),kind=await selectEntityKind(client,settings.entities,"update",buildRetryCommand(void 0,changes)),!kind)return client.nonInteractive||!client.stdin.isTTY?2:1;settings=await getFlagSettings(client,project.id)}let entity=findEntity(settings.entities,kind);if(!entity)return reportEntityNotFound(client,kind,buildRetryCommand(void 0,changes)),1;let retryCommand=buildRetryCommand(kind,changes);for(let attribute of changes.addAttributes)if(findAttribute(entity,attribute.key))return output_manager_default.fatal(`Attribute "${attribute.key}" already exists on entity "${entity.kind}". Use --set-attribute-type to change its type.`),1;for(let key of changes.removeAttributes)if(!findAttribute(entity,key))return output_manager_default.fatal(`Attribute ${import_chalk80.default.bold(`${kind}.${key}`)} does not exist.`),1;for(let attribute of changes.setAttributeTypes)if(!findAttribute(entity,attribute.key))return output_manager_default.fatal(`Attribute ${import_chalk80.default.bold(`${kind}.${attribute.key}`)} does not exist. Use --add-attribute to add it.`),1;let updatedEntity=applyChanges(entity,changes),entities2=settings.entities.map(candidate=>candidate.kind===kind?updatedEntity:candidate);try{validateEntities(entities2)}catch(err){return output_manager_default.fatal(err.message),1}let typeChanges=changes.setAttributeTypes.filter(attribute=>findAttribute(entity,attribute.key)?.type!==attribute.type),guardedKeys=[...changes.removeAttributes,...typeChanges.map(attribute=>attribute.key)];if(guardedKeys.length>0){output_manager_default.spinner("Checking flags and segments for references\u2026");let sources=await loadEntityUsageSources(client,project.id);output_manager_default.stopSpinner();for(let key of guardedKeys){let usage=collectEntityUsage(sources,kind,key);if(reportEntityInUse(client,{kind,attribute:key,usage,retryCommand}))return 1}}output_manager_default.spinner("Updating entity\u2026");let updated=await updateFlagSettings(client,project.id,{entities:entities2});output_manager_default.stopSpinner();let result=findEntity(updated.entities,kind)??updatedEntity;return json?(client.stdout.write(`${JSON.stringify({entity:result},null,2)}
|
|
342
|
+
`),0):(output_manager_default.success(`Feature flag entity ${import_chalk80.default.bold(result.kind)} updated`),printEntityDetails(result,projectSlugLink),0)}function parseChanges(input){input.label!==void 0&&validateEntityLabel(input.label);let addAttributes=parseAttributeInputs(input.addInputs),setAttributeTypes=parseAttributeInputs(input.setTypeInputs),removeAttributes=input.removeInputs.map(value=>value.trim());for(let key of removeAttributes)validateAttributeKey(key);let removed=new Set(removeAttributes);for(let attribute of[...addAttributes,...setAttributeTypes])if(removed.has(attribute.key))throw new Error(`Attribute "${attribute.key}" can not be removed and changed in the same command.`);let added=new Set(addAttributes.map(attribute=>attribute.key));for(let attribute of setAttributeTypes)if(added.has(attribute.key))throw new Error(`Attribute "${attribute.key}" can not be added and have its type changed in the same command.`);return{label:input.label,addAttributes,removeAttributes,setAttributeTypes}}function applyChanges(entity,changes){let removed=new Set(changes.removeAttributes),typeByKey=new Map(changes.setAttributeTypes.map(attribute=>[attribute.key,attribute.type]));return{...entity,label:changes.label??entity.label,attributes:[...entity.attributes.filter(attribute=>!removed.has(attribute.key)).map(attribute=>{let type=typeByKey.get(attribute.key);return type!==void 0&&type!==attribute.type?{key:attribute.key,type}:attribute}),...changes.addAttributes]}}function buildRetryCommand(kind,changes){let parts=[`flags entities update ${kind===void 0?"<kind>":quoteArg(kind)}`];changes.label!==void 0&&parts.push(`--label ${quoteArg(changes.label)}`);for(let attribute of changes.addAttributes)parts.push(`--add-attribute ${quoteArg(`${attribute.key}:${attribute.type}`)}`);for(let key of changes.removeAttributes)parts.push(`--remove-attribute ${quoteArg(key)}`);for(let attribute of changes.setAttributeTypes)parts.push(`--set-attribute-type ${quoteArg(`${attribute.key}:${attribute.type}`)}`);return parts.join(" ")}var import_chalk81=__toESM(require_source(),1),import_pluralize6=__toESM(require_pluralize(),1);async function entitiesRm(client,argv){let parsedArgs=parseEntityArguments(client,argv,entitiesRemoveSubcommand.options),{args,flags}=parsedArgs;if(args.length>1){let message="Provide only one entity kind to delete.";return entityAgentError(client,{reason:AGENT_REASON.INVALID_ARGUMENTS,message,next:[{command:"flags entities delete <kind> --yes",when:"replace <kind> with the single entity kind to delete"}]}),client.nonInteractive||output_manager_default.fatal(message),2}let kind=args[0],skipConfirmation=flags["--yes"],projectName=getProjectNameFromFlags(flags);if(client.nonInteractive||!client.stdin.isTTY){if(!kind)return await selectEntityKind(client,[],"delete","flags entities delete <kind> --yes"),2;if(!skipConfirmation)return reportMissingConfirmation(client,kind),1}let context=await resolveEntitiesProject(client,projectName);if(isExitCodeResult(context))return context.exitCode;let{project,projectSlugLink}=context;output_manager_default.spinner("Fetching feature flag settings\u2026");let settings=await getFlagSettings(client,project.id),prompted=!1;if(output_manager_default.stopSpinner(),!kind&&(printAlignedLabel("Project",projectSlugLink),kind=await selectEntityKind(client,settings.entities,"delete","flags entities delete <kind> --yes"),prompted=!0,!kind))return 1;let entity=findEntity(settings.entities,kind);if(!entity)return reportEntityNotFound(client,kind,"flags entities delete <kind> --yes"),1;if(!skipConfirmation){prompted||printAlignedLabel("Project",projectSlugLink);let confirmed=await client.input.confirm(`Delete entity ${import_chalk81.default.bold(entity.kind)} and its ${(0,import_pluralize6.default)("attribute",entity.attributes.length,!0)}?`,!1);if(prompted=!0,!confirmed)return output_manager_default.log("Aborted"),0}if(prompted&&(settings=await getFlagSettings(client,project.id),!findEntity(settings.entities,kind)))return reportEntityNotFound(client,kind,"flags entities delete <kind> --yes"),1;output_manager_default.spinner("Checking flags and segments for references\u2026");let sources=await loadEntityUsageSources(client,project.id);return output_manager_default.stopSpinner(),reportEntityInUse(client,{kind,usage:collectEntityUsage(sources,kind),retryCommand:`flags entities delete ${quoteArg(kind)} --yes`})?1:(output_manager_default.spinner("Deleting entity\u2026"),await updateFlagSettings(client,project.id,{entities:settings.entities.filter(candidate=>candidate.kind!==kind)}),output_manager_default.stopSpinner(),output_manager_default.success(`Feature flag entity ${import_chalk81.default.bold(entity.kind)} deleted`),0)}function reportMissingConfirmation(client,kind){entityAgentError(client,{reason:AGENT_REASON.CONFIRMATION_REQUIRED,message:`Add --yes to delete entity ${kind}.`,next:[{command:`flags entities delete ${quoteArg(kind)} --yes`,when:"delete the entity"}]}),client.nonInteractive||output_manager_default.fatal("Missing required flag --yes. Add --yes to delete the entity without prompting.")}var commands={ls:{command:entitiesListSubcommand,run:entitiesLs},create:{command:entitiesCreateSubcommand,run:entitiesCreate},update:{command:entitiesUpdateSubcommand,run:entitiesUpdate},delete:{command:entitiesRemoveSubcommand,run:entitiesRm}},aliases=Object.fromEntries(Object.entries(commands).map(([name,{command}])=>[name,getCommandAliases(command)]));async function entities(client){let telemetry=new FlagsEntitiesTelemetryClient({opts:{store:client.telemetryEventStore}});try{let parsed=parseArguments(client.argv.slice(4),getFlagsSpecification(entitiesSubcommand.options),{permissive:!0}),{subcommand,args,subcommandOriginal}=getSubcommand(parsed.args,aliases),entry=typeof subcommand=="string"?commands[subcommand]:void 0;return parsed.flags["--help"]||!entry?(parsed.flags["--help"]?telemetry.trackCliFlagHelp("flags entities",entry?subcommandOriginal:void 0):output_manager_default.fatal(getInvalidSubcommand(aliases)),output_manager_default.print(help(entry?.command??entitiesSubcommand,{parent:entry?{...entitiesSubcommand,name:"flags entities"}:flagsCommand,columns:client.stderr.columns})),parsed.flags["--help"]?0:2):(telemetry.trackSubcommand(subcommand,subcommandOriginal),subcommand==="create"&&subcommandOriginal==="add"&&warnDeprecatedSubcommand(client,"flags entities add","flags entities create"),subcommand==="delete"&&subcommandOriginal==="remove"&&warnDeprecatedSubcommand(client,"flags entities remove","flags entities delete"),await entry.run(client,args))}catch(err){return output_manager_default.stopSpinner(),printError(err),1}}var import_pluralize7=__toESM(require_pluralize(),1);function parseEntityLabelOperations(input){let operations;if(input.data!==void 0){if(input.set.length||input.remove.length)throw new Error("Can't combine --data with --set or --remove.");let data;try{data=JSON.parse(input.data)}catch{throw new Error("--data must be a JSON array of label operations.")}if(!Array.isArray(data)||data.length===0)throw new Error("--data must be a non-empty JSON array of label operations.");operations=data}else operations=[...input.remove.map(value=>({operation:"delete",value})),...input.set.map(valueLabel=>{let separator=valueLabel.indexOf("=");if(separator===-1)throw new Error('Use --set VALUE=LABEL, for example --set "pro=Pro Plan".');return{operation:"upsert",value:valueLabel.slice(0,separator),label:valueLabel.slice(separator+1)}})];return validateEntityLabelOperations(operations)}var MAX_LABEL_OPERATIONS=100;function validateEntityLabelOperations(operations){if(operations.length>MAX_LABEL_OPERATIONS)throw new Error(`Cannot update more than ${MAX_LABEL_OPERATIONS} labels at once. Split the operations into smaller batches.`);let values=new Set;return operations.map(item=>{if(!item||typeof item!="object")throw new Error("Each label operation must be an object.");let record=item,{operation,value,label}=record;if(operation!=="upsert"&&operation!=="delete")throw new Error('Label operations must use "upsert" or "delete".');let keys=operation==="upsert"?["operation","value","label"]:["operation","value"];if(Object.keys(record).some(key=>!keys.includes(key)))throw new Error(`Label ${operation} operations accept only ${keys.join(", ")}.`);if(validateLabelString(value,"value"),values.has(value))throw new Error("Each value can have only one label operation per command.");return values.add(value),operation==="delete"?{operation,value}:(validateLabelString(label,"label"),{operation,value,label})})}function validateLabelString(value,field){if(typeof value!="string"||Array.from(value).length>128)throw new Error(`Label ${field} must be a string of at most 128 characters.`)}function updateEntityLabelsBulk(client,projectId,items){return client.fetch(`/v1/projects/${encodeURIComponent(projectId)}/feature-flags/labels/bulk`,{method:"PATCH",body:{items},retry:{retries:0},bailOn429:!0})}function parseLabelPagination(limit=20,next,attribute){if(!Number.isSafeInteger(limit)||limit<1)throw new Error("The --limit option must be a positive integer.");if(next===void 0)return{limit};try{if(!/^[A-Za-z0-9_-]+$/.test(next)||next.length>4096)throw new Error;let cursor=JSON.parse(Buffer.from(next,"base64url").toString("utf8"));if(!cursor||cursor.version!==1||typeof cursor.projectId!="string"||!cursor.projectId||cursor.attribute!==attribute||typeof cursor.after!="string")throw new Error;return{limit,cursor}}catch{throw new Error("Invalid or expired --next cursor for this list view. Omit --next to restart the list.")}}function paginateLabelItems(items,{limit,cursor},projectId,attribute,key){let remaining=items.filter(item=>cursor===void 0||key(item)>cursor.after).sort((a,b)=>key(a)<key(b)?-1:key(a)>key(b)?1:0),page=remaining.slice(0,limit),next=remaining.length>page.length?Buffer.from(JSON.stringify({version:1,projectId,attribute,after:key(page[page.length-1])})).toString("base64url"):null;return{items:page,pagination:{next}}}var FlagsLabelsTelemetryClient=class extends TelemetryClient{trackSubcommand(subcommand,actual){this.trackCliSubcommand({subcommand,value:actual})}trackArguments(args,flags){for(let[index,arg]of["attribute","value","label"].entries())index<args.length&&this.trackCliArgument({arg,value:this.redactedValue});this.trackCliOptionProject(flags["--project"]);for(let option of["set","remove","data","next"])flags[`--${option}`]!==void 0&&this.trackCliOption({option,value:this.redactedValue});flags["--limit"]!==void 0&&this.trackCliOption({option:"limit",value:String(flags["--limit"])}),flags["--json"]&&this.trackCliFlag("json")}};async function labels(client){let argv=client.argv.slice(4),telemetry=new FlagsLabelsTelemetryClient({opts:{store:client.telemetryEventStore}}),json=client.nonInteractive||argv.includes("--json"),inspectCommand="flags entities ls --json",reason=AGENT_REASON.INVALID_ARGUMENTS,recovery="Inspect entities and labels before retrying";function next(){return[{command:buildCommandWithGlobalFlags(client.argv,inspectCommand,void 0,{preserveProject:inspectCommand.startsWith("flags ")}),when:recovery}]}function printRecovery(){output_manager_default.print(` ${recovery}:
|
|
343
|
+
${next()[0].command}
|
|
344
|
+
`)}function fail(message){if(json){let status2=reason===AGENT_REASON.MISSING_ARGUMENTS||reason===AGENT_REASON.NOT_LINKED?AGENT_STATUS.ACTION_REQUIRED:AGENT_STATUS.ERROR;client.stdout.write(`${JSON.stringify({status:status2,reason,message,next:next()},null,2)}
|
|
345
|
+
`)}else output_manager_default.fatal(message),printRecovery();return getExitCodeForReason(reason)}try{let printNextPage2=function(cursor){if(!json&&cursor&&pageOptions){let globalArgs=getGlobalFlagsFromArgs(client.argv.slice(2));globalArgs.some(arg=>arg==="--scope"||arg==="-S"||arg.startsWith("--scope="))||globalArgs.push("--scope",org.slug);let command2=getCommandNamePlain(["flags","labels","ls",...target===void 0?[]:[target],"--project",project.name,"--limit",String(pageOptions.limit),"--next",cursor,...globalArgs].map(quoteArg).join(" "));output_manager_default.print(`
|
|
346
|
+
`),printNextPageCommand(command2)}};var printNextPage=printNextPage2;let parsed=parseArguments(argv,getFlagsSpecification(labelsListSubcommand.options),{permissive:!0}),aliases2=Object.fromEntries(labelsSubcommand.subcommands.map(command2=>[command2.name,getCommandAliases(command2)])),{subcommand,subcommandOriginal}=getSubcommand(parsed.args,aliases2),command=labelsSubcommand.subcommands.find(command2=>command2.name===subcommand);if(parsed.flags["--help"])return telemetry.trackCliFlagHelp("flags labels",command?subcommandOriginal:void 0),output_manager_default.print(help(command??labelsSubcommand,{parent:command?{...labelsSubcommand,name:"flags labels"}:flagsCommand,columns:client.stderr.columns})),0;if(!command)return reason=parsed.args.length?AGENT_REASON.INVALID_ARGUMENTS:AGENT_REASON.MISSING_ARGUMENTS,fail(getInvalidSubcommand(aliases2));telemetry.trackSubcommand(command.name,subcommandOriginal);let{args:positional,flags}=parseArguments(argv,getFlagsSpecification(command.options)),[target,...args]=positional.slice(1);if(telemetry.trackArguments(positional.slice(1),flags),json=!!flags["--json"]||client.nonInteractive,target===void 0&&command.name!=="ls")return reason=AGENT_REASON.MISSING_ARGUMENTS,fail('Provide an attribute as ENTITY.ATTRIBUTE. Example: vercel flags labels set user.plan pro "Pro Plan".');let[kind,attributeKey]=target?.split(".")??[];if(target!==void 0){if(target.split(".").length!==2)return fail("Use an attribute as ENTITY.ATTRIBUTE, for example user.plan.");validateEntityKind(kind),validateAttributeKey(attributeKey)}let pageOptions=command.name==="ls"?parseLabelPagination(flags["--limit"],flags["--next"],target??null):void 0;if(args.length!==command.arguments.length-1)return args.length<command.arguments.length-1&&(reason=AGENT_REASON.MISSING_ARGUMENTS),fail(command.name==="set"?'Provide a value and a label. Example: vercel flags labels set user.plan pro "Pro Plan".':command.name==="remove"?"Provide one value. Example: vercel flags labels remove user.plan pro.":`The ${command.name} command accepts only one attribute as ENTITY.ATTRIBUTE.`);let operations=command.name==="set"?validateEntityLabelOperations([{operation:"upsert",value:args[0],label:args[1]}]):command.name==="remove"?validateEntityLabelOperations([{operation:"delete",value:args[0]}]):parseEntityLabelOperations({set:flags["--set"]??[],remove:flags["--remove"]??[],data:flags["--data"]});if(command.name==="apply"&&operations.length===0)return reason=AGENT_REASON.MISSING_ARGUMENTS,fail("Provide --set VALUE=LABEL, --remove VALUE, or --data JSON.");reason=AGENT_REASON.API_ERROR;let projectName=getProjectNameFromFlags(flags),context=await getLinkedFlagsProject(client,projectName,{projectNotFoundHandling:"return"});if(context.status==="error")return inspectCommand="project ls",recovery="Check the project and team context before retrying",fail("Failed to resolve the project. Check the project and team settings.");if(context.status==="not_linked")return reason=projectName?AGENT_REASON.PROJECT_NOT_FOUND:AGENT_REASON.NOT_LINKED,inspectCommand=projectName?"project ls":"link",recovery=projectName?"Select an accessible project before retrying":"Link a project before retrying",fail(projectName?`Project ${JSON.stringify(projectName)} was not found or is not accessible. Check --project and your team scope.`:"Your codebase isn't linked to a project. Pass --project <name>, or run vercel link to link it.");let{project,org}=context;if(client.config.currentTeam=org.type==="team"?org.id:void 0,pageOptions?.cursor&&pageOptions.cursor.projectId!==project.id)return reason=AGENT_REASON.INVALID_ARGUMENTS,fail("The --next cursor belongs to a different project. Omit --next to restart the list.");let projectSlugLink=formatProject(org.slug,project.name);output_manager_default.spinner("Fetching attribute labels\u2026");let settings=await getFlagSettings(client,project.id);if(output_manager_default.stopSpinner(),pageOptions&&target===void 0){let available=settings.entities.flatMap(entity2=>entity2.attributes.filter(attribute2=>attribute2.labels?.length).map(attribute2=>({id:null,attributes:[{entityKind:entity2.kind,attributeKey:attribute2.key}],labelCount:attribute2.labels.length}))),{items:lists,pagination}=paginateLabelItems(available,pageOptions,project.id,null,list7=>`${list7.attributes[0].entityKind}.${list7.attributes[0].attributeKey}`);if(json)client.stdout.write(`${JSON.stringify({status:AGENT_STATUS.OK,lists,pagination},null,2)}
|
|
347
|
+
`);else if(printAlignedLabel("Project",projectSlugLink),lists.length===0)output_manager_default.log(pageOptions.cursor?"No more label lists found.":"No label lists found.");else{let rows=lists.map(list7=>[`${list7.attributes[0].entityKind}.${list7.attributes[0].attributeKey}`,String(list7.labelCount)]);output_manager_default.print(`
|
|
348
|
+
${formatTable(["Attribute","Labels"],["l","r"],[{name:"",rows}])}
|
|
349
|
+
`)}return printNextPage2(pagination.next),0}let entity=findEntity(settings.entities,kind),attribute=entity&&findAttribute(entity,attributeKey);if(!attribute)return reason=AGENT_REASON.NOT_FOUND,fail(entity?`Attribute ${kind}.${attributeKey} was not found in this project.`:`Entity ${kind} was not found in this project.`);if(inspectCommand=`flags labels ls ${quoteArg(`${kind}.${attributeKey}`)} --json`,pageOptions){let{items:labels2,pagination}=paginateLabelItems(attribute.labels??[],pageOptions,project.id,`${kind}.${attributeKey}`,label=>label.value);if(json)client.stdout.write(`${JSON.stringify({status:AGENT_STATUS.OK,entityKind:kind,attributeKey,labels:labels2,pagination},null,2)}
|
|
350
|
+
`);else if(printAlignedLabel("Project",projectSlugLink),printAlignedLabel("Attribute",`${kind}.${attributeKey}`),labels2.length===0)output_manager_default.log(pageOptions.cursor?"No more value labels found.":"No value labels found.");else{let rows=labels2.map(({value,label})=>[formatLabelCell(value),formatLabelCell(label)]);output_manager_default.print(`
|
|
351
|
+
${formatTable(["Value","Label"],["l","l"],[{name:"",rows}])}
|
|
352
|
+
`)}return printNextPage2(pagination.next),0}if(attribute.type!=="string"&&attribute.type!=="stringArray")return reason=AGENT_REASON.INVALID_ARGUMENTS,fail("Value labels are supported only for string and stringArray attributes.");json||(printAlignedLabel("Project",projectSlugLink),printAlignedLabel("Attribute",`${kind}.${attributeKey}`)),output_manager_default.spinner("Updating attribute labels\u2026");let result=await updateEntityLabelsBulk(client,project.id,operations.map(operation=>({...operation,entityKind:kind,attributeKey})));output_manager_default.stopSpinner();let failed=result.errors.length>0,message=`${(0,import_pluralize7.default)("label operation",result.labels.length,!0)} applied, ${result.errors.length} failed.`;if(json)client.stdout.write(`${JSON.stringify({status:failed?AGENT_STATUS.ERROR:AGENT_STATUS.OK,entityKind:kind,attributeKey,...result,...failed?{reason:AGENT_REASON.API_ERROR,message,next:next()}:{}},null,2)}
|
|
353
|
+
`);else if(failed){output_manager_default.fatal(message);for(let error of result.errors)output_manager_default.print(` ${JSON.stringify(error.value)}: ${error.code} \u2014 ${JSON.stringify(error.message)}
|
|
354
|
+
`);printRecovery()}else{let set2=result.labels.filter(item=>item.operation==="upsert").length,removed=result.labels.filter(item=>item.operation==="delete").length;output_manager_default.success(`Value labels updated for ${kind}.${attributeKey}: ${set2} set, ${removed} removed`)}return failed?1:0}catch(err){return output_manager_default.stopSpinner(),isAPIError(err)&&(reason=err.status===403?AGENT_REASON.PERMISSION_DENIED:AGENT_REASON.API_ERROR),fail(err instanceof Error?err.message:"Failed to manage attribute labels.")}}function formatLabelCell(value){let quoted=JSON.stringify(value);return value===""||value.trim()!==value||quoted.slice(1,-1)!==value?quoted:value}var FlagsRulesTelemetryClient=class extends TelemetryClient{trackCliSubcommandList(actual){this.trackCliSubcommand({subcommand:"ls",value:actual})}trackCliSubcommandAdd(actual){this.trackCliSubcommand({subcommand:"add",value:actual})}trackCliSubcommandUpdate(actual){this.trackCliSubcommand({subcommand:"update",value:actual})}trackCliSubcommandRemove(actual){this.trackCliSubcommand({subcommand:"rm",value:actual})}trackCliSubcommandMove(actual){this.trackCliSubcommand({subcommand:"move",value:actual})}},FlagsRulesCommandTelemetryClient=class extends TelemetryClient{trackCliArgumentFlag(flag){flag&&this.trackCliArgument({arg:"flag",value:this.redactedValue})}trackCliArgumentRule(rule){rule&&this.trackCliArgument({arg:"rule",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:STANDARD_ENVIRONMENTS.includes(environment)?environment:this.redactedValue})}trackCliOptionCondition(condition){condition?.length&&this.trackCliOption({option:"condition",value:this.redactedValue})}trackCliOptionVariant(variant){variant&&this.trackCliOption({option:"variant",value:this.redactedValue})}trackCliOptionBy(base){base&&this.trackCliOption({option:"by",value:this.redactedValue})}trackCliOptionWeight(weights){weights?.length&&this.trackCliOption({option:"weight",value:this.redactedValue})}trackCliOptionDefaultVariant(variant){variant&&this.trackCliOption({option:"default-variant",value:this.redactedValue})}trackCliOptionFromVariant(variant){variant&&this.trackCliOption({option:"from-variant",value:this.redactedValue})}trackCliOptionToVariant(variant){variant&&this.trackCliOption({option:"to-variant",value:this.redactedValue})}trackCliOptionStage(stages){stages?.length&&this.trackCliOption({option:"stage",value:this.redactedValue})}trackCliOptionFinalPercentage(percentage){percentage!==void 0&&this.trackCliOption({option:"final-percentage",value:this.redactedValue})}trackCliOptionStart(start){start&&this.trackCliOption({option:"start",value:this.redactedValue})}trackCliOptionPosition(position){position!==void 0&&this.trackCliOption({option:"position",value:String(position)})}trackCliOptionMessage(message){message&&this.trackCliOption({option:"message",value:this.redactedValue})}trackCliFlagJson(json){json&&this.trackCliFlag("json")}};var import_chalk83=__toESM(require_source(),1),import_pluralize8=__toESM(require_pluralize(),1);import{randomBytes as randomBytes3}from"node:crypto";var RHS_OPTIONAL_OPERATORS2=new Set(FLAG_CONDITION_RHS_OPTIONAL_COMPARATORS);function parseFlagRuleConditions(inputs,settings){let conditionInputs=inputs.flatMap(input=>{let trimmed=input.trim();return!trimmed||trimmed.startsWith("{")?[trimmed]:trimmed.split(";").map(part=>part.trim()).filter(Boolean)});if(conditionInputs.length===0)throw new Error("At least one --condition is required. Use --condition <ENTITY.ATTRIBUTE:OPERATOR:VALUE>.");return conditionInputs.map(input=>coerceTimestampCondition(parseFlagRuleConditionInput(input),settings,"input"))}function parseFlagRuleConditionInput(input){let trimmed=input.trim();if(!trimmed)throw new Error("Flag rule condition cannot be empty");if(trimmed.startsWith("{")){let value=parseJson2(trimmed,"flag rule condition");if(!isRecord2(value))throw new Error("Flag rule condition JSON must be an object");return value}let[field,operator,...valueParts]=trimmed.split(":");if(!field||!operator)throw new Error(`Invalid flag rule condition "${input}". Use ENTITY.ATTRIBUTE:OPERATOR:VALUE or segment:OPERATOR:SEGMENT.`);let cmp=parseComparator(operator,"flag rule"),rawValue=valueParts.join(":");if(!rawValue&&!RHS_OPTIONAL_OPERATORS2.has(cmp))throw new Error(`Flag rule condition "${input}" is missing a value`);return{lhs:parseFlagConditionLhs(field),cmp,...rawValue?{rhs:parseConditionValue(rawValue,cmp)}:{}}}function hasFlagRuleOutcomeOptions(options){return!!(options.variantSelector||options.baseSelector||options.defaultVariantSelector||options.weightInputs.length>0||options.rollFromVariantSelector||options.rollToVariantSelector||options.stageInputs.length>0||options.start||options.finalPercentage!==void 0)}function needsFlagRuleOutcomeSettings(options){return options.variantSelector?!1:!!(options.baseSelector||options.defaultVariantSelector||options.weightInputs.length>0||options.rollFromVariantSelector||options.rollToVariantSelector||options.stageInputs.length>0||options.start||options.finalPercentage!==void 0)}function resolveFlagRuleOutcome(flag,settings,options){let hasVariant=!!options.variantSelector,hasRolloutOnlyOptions=!!(options.rollFromVariantSelector||options.rollToVariantSelector||options.stageInputs.length>0||options.start||options.finalPercentage!==void 0),hasSplitOnlyOptions=options.weightInputs.length>0,hasCommonOptions=!!(options.baseSelector||options.defaultVariantSelector);if(hasVariant&&(hasRolloutOnlyOptions||hasSplitOnlyOptions||hasCommonOptions))throw new Error("Cannot combine --variant with split or rollout outcome options.");if(hasRolloutOnlyOptions&&hasSplitOnlyOptions)throw new Error("Cannot combine --weight with rollout outcome options.");if(options.variantSelector)return{type:"variant",variantId:resolveVariantOrThrow(options.variantSelector,flag.variants,"--variant").id};if(hasRolloutOnlyOptions||hasCommonOptions&&options.currentOutcome?.type==="rollout")return resolveFlagRollout(flag,requireFlagSettings(settings),{stageInputs:options.stageInputs,finalPercentage:options.finalPercentage,baseSelector:options.baseSelector,rollFromVariantSelector:options.rollFromVariantSelector,rollToVariantSelector:options.rollToVariantSelector,defaultVariantSelector:options.defaultVariantSelector,start:options.start,currentOutcome:options.currentOutcome?.type==="experiment"?void 0:options.currentOutcome}).outcome;if(hasSplitOnlyOptions||hasCommonOptions)return resolveFlagSplit(flag,requireFlagSettings(settings),{weightInputs:options.weightInputs,baseSelector:options.baseSelector,defaultVariantSelector:options.defaultVariantSelector,currentOutcome:options.currentOutcome?.type==="experiment"?void 0:options.currentOutcome}).outcome;if(options.currentOutcome&&!options.requireOutcome)return options.currentOutcome;throw new Error("Missing rule outcome. Use --variant <VARIANT>, split options such as --weight, or rollout options such as --stage.")}function createFlagRule(conditions,outcome){return{id:shortId2("rule_"),conditions,outcome}}function addFlagRule(envConfig,rule,position){let rules2=structuredClone(envConfig.rules??[]),insertionIndex=resolvePosition(position,rules2.length+1)-1;return rules2.splice(insertionIndex,0,rule),buildRulesEnvironmentConfig(envConfig,rules2)}function removeFlagRule(envConfig,ruleId){let rules2=structuredClone(envConfig.rules??[]),ruleIndex=findFlagRuleIndex(rules2,ruleId);return rules2.splice(ruleIndex,1),buildRulesEnvironmentConfig(envConfig,rules2)}function updateFlagRule(envConfig,ruleId,updates){let rules2=structuredClone(envConfig.rules??[]),ruleIndex=findFlagRuleIndex(rules2,ruleId);return rules2[ruleIndex]={...rules2[ruleIndex],...updates.conditions?{conditions:updates.conditions}:{},...updates.outcome?{outcome:updates.outcome}:{}},buildRulesEnvironmentConfig(envConfig,rules2)}function moveFlagRule(envConfig,ruleId,position){let rules2=structuredClone(envConfig.rules??[]),targetPosition=resolvePosition(position,rules2.length),ruleIndex=findFlagRuleIndex(rules2,ruleId),[rule]=rules2.splice(ruleIndex,1);return rules2.splice(targetPosition-1,0,rule),buildRulesEnvironmentConfig(envConfig,rules2)}function resolveEffectiveFlagRulesEnvironment(flag,environment){let envConfig=flag.environments[environment],inheritedFrom=envConfig.reuse?.active?envConfig.reuse.environment:void 0;if(!inheritedFrom)return{environment,envConfig};let inheritedConfig=flag.environments[inheritedFrom];return inheritedConfig?{environment,envConfig:inheritedConfig,inheritedFrom}:{environment,envConfig}}function getFlagRulesEnvironmentConfig(flag,environment){let envConfig=flag.environments[environment],effectiveEnvironment=resolveEffectiveFlagRulesEnvironment(flag,environment);return{...envConfig,rules:structuredClone(effectiveEnvironment.envConfig.rules??[])}}function findFlagRule(rules2,ruleId){let rule=rules2.find(rule2=>rule2.id===ruleId);if(!rule)throw new Error(`Rule "${ruleId}" does not exist.`);return rule}function formatFlagRuleCondition(condition,settings){let lhs=condition.lhs.type==="segment"?"segment":`${condition.lhs.kind}.${condition.lhs.attribute}`,attributeType=condition.lhs.type==="entity"?getFlagAttributeType(settings,condition.lhs.kind,condition.lhs.attribute):void 0,comparator=formatFlagConditionComparator(condition.cmp,{...condition.cmpOptions,attributeType});if(condition.rhs===void 0||condition.rhs===null)return`${lhs} ${comparator}`;if(isRecord2(condition.rhs))return Array.isArray(condition.rhs.items)&&(condition.rhs.type==="list"||condition.rhs.type==="list/inline")?`${lhs} ${comparator} ${condition.rhs.items.map(formatListItem).join(", ")}`:`${lhs} ${comparator} ${JSON.stringify(condition.rhs)}`;let timestampRhs=formatTimestampRhs(condition.rhs,attributeType);return`${lhs} ${comparator} ${timestampRhs??String(condition.rhs)}`}function formatFlagRuleOutcome(outcome,variants){return formatFlagOutcome(outcome,variants)}function buildRulesEnvironmentConfig(envConfig,rules2){let nextConfig={...envConfig,rules:rules2};return envConfig.reuse&&(nextConfig.reuse={...envConfig.reuse,active:!1}),nextConfig}function parseFlagConditionLhs(input){let trimmed=input.trim();if(trimmed==="segment")return{type:"segment"};let[kind,...attributeParts]=trimmed.split("."),attribute=attributeParts.join(".");if(!kind||!attribute)throw new Error(`Invalid condition target "${input}". Use ENTITY.ATTRIBUTE or segment.`);return{type:"entity",kind,attribute}}function resolvePosition(position,max){if(position===void 0)return max;if(!Number.isInteger(position)||position<1||position>max)throw new Error(`Position must be an integer between 1 and ${max}.`);return position}function findFlagRuleIndex(rules2,ruleId){let ruleIndex=rules2.findIndex(rule=>rule.id===ruleId);if(ruleIndex===-1)throw new Error(`Rule "${ruleId}" does not exist.`);return ruleIndex}function shortId2(prefix){let alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",bytes=randomBytes3(12),id=prefix;for(let i=0;i<bytes.length;i++)id+=alphabet[bytes[i]%alphabet.length];return id}function requireFlagSettings(settings){if(!settings)throw new Error("Flag settings are required to resolve this rule outcome.");return settings}function formatListItem(item){return isRecord2(item)&&"value"in item?String(item.value):String(item)}function parseJson2(input,label){try{return JSON.parse(input)}catch{throw new Error(`Invalid JSON for ${label}`)}}function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var import_chalk82=__toESM(require_source(),1);async function resolveRulesCommandContext(client,options){let link=await resolveProjectContext({client,projectNameOrId:options.projectName});if(link.status==="error")return{exitCode:link.exitCode};if(link.status==="not_linked")return output_manager_default.error(`Your codebase isn't linked to a project on Vercel. Run ${getCommandName("link")} to begin.`),{exitCode:1};client.config.currentTeam=link.org.type==="team"?link.org.id:void 0;let{project}=link;output_manager_default.spinner("Fetching flag...");let[flag,settings]=await Promise.all([getFlag(client,project.id,options.flagArg),options.fetchSettings?getFlagSettings(client,project.id):Promise.resolve(void 0)]);output_manager_default.stopSpinner();let environment=await resolveFlagEnvironment(client,flag,options.environment,options.promptMessage,{showEnvironmentDetails:!0,decorateChoices:!1});return{projectId:project.id,flag,settings,environment,envConfig:flag.environments[environment]}}function isExitCodeResult2(result){return"exitCode"in result}function warnIfRuleChangesAreBypassed(flag,environment,changeLabel="rule"){if(flag.state==="archived"){logArchivedFlagNotice(flag);return}let envConfig=flag.environments[environment];if(!envConfig)return;let mode=describeInactiveTargetingMode(flag,envConfig);mode&&(output_manager_default.print(`${import_chalk82.default.yellow("!")} This ${changeLabel} update was saved, but ${import_chalk82.default.bold(environment)} ${mode}. ${capitalize(changeLabel)} changes will not affect flag evaluation until targeting is active again.
|
|
355
|
+
`),output_manager_default.print(` Enable targeting (keeps the current fallthrough):
|
|
356
|
+
`),output_manager_default.print(` ${getCommandName(`flags targeting enable ${quoteArg(flag.slug)} --environment ${environment}`)}
|
|
357
|
+
`))}function describeInactiveTargetingMode(flag,envConfig){if(envConfig.reuse?.active)return`reuses ${import_chalk82.default.bold(envConfig.reuse.environment)}`;if(envConfig.active)return;let variantId=envConfig.pausedOutcome?.variantId,variant=flag.variants.find(candidate=>candidate.id===variantId);return`is serving ${variant?formatVariantForDisplay(variant):variantId?import_chalk82.default.bold(variantId):"a fixed variant"}`}function capitalize(value){return value.charAt(0).toUpperCase()+value.slice(1)}async function rulesLs(client,argv){let telemetryClient=new FlagsRulesCommandTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(rulesListSubcommand2.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],json=flags["--json"];if(telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliFlagJson(json),telemetryClient.trackCliOptionProject(flags["--project"]),!flagArg)return output_manager_default.error("Please provide a flag slug or ID to list rules for"),output_manager_default.log(`Example: ${getCommandName("flags rules ls my-feature --environment production")}`),2;try{let context=await resolveRulesCommandContext(client,{projectName:parsedArgs.flags["--project"],flagArg,environment,promptMessage:"Select an environment to list rules for:",fetchSettings:!json});if(isExitCodeResult2(context))return context.exitCode;let effectiveEnvironment=resolveEffectiveFlagRulesEnvironment(context.flag,context.environment),rules2=effectiveEnvironment.envConfig.rules??[];if(json)return outputJson6(client,{flag:context.flag.slug,environment:context.environment,inheritedFrom:effectiveEnvironment.inheritedFrom,rules:rules2}),0;let lsStamp=stamp_default(),environmentLabel=effectiveEnvironment.inheritedFrom?`${context.environment} (reuses ${effectiveEnvironment.inheritedFrom})`:context.environment;if(rules2.length===0){let projectFlag=flags["--project"]?` --project ${flags["--project"]}`:"";return output_manager_default.log(`No conditional rules found for ${import_chalk83.default.bold(context.flag.slug)} in ${environmentLabel} ${import_chalk83.default.gray(lsStamp())}`),output_manager_default.log(`
|
|
358
|
+
Add one with: ${getCommandName("flags rules add "+context.flag.slug+" --environment "+context.environment+" --condition user.plan:eq:pro --variant on"+projectFlag)}`),0}output_manager_default.log(`${(0,import_pluralize8.default)("conditional rule",rules2.length,!0)} found for ${import_chalk83.default.bold(context.flag.slug)} in ${environmentLabel} ${import_chalk83.default.gray(lsStamp())}`),printRulesTable(rules2,context.flag.variants,context.settings)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function outputJson6(client,data){client.stdout.write(`${JSON.stringify(data,null,2)}
|
|
359
|
+
`)}function printRulesTable(rules2,variants,settings){let headers=["Position","ID","Conditions","Outcome"],rows=rules2.map((rule,index)=>[String(index+1),import_chalk83.default.bold(rule.id),rule.conditions.map(condition=>formatFlagRuleCondition(condition,settings)).join("; "),formatFlagRuleOutcome(rule.outcome,variants)]),table2=formatTable(headers,["r","l","l","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
360
|
+
${table2}
|
|
361
|
+
`)}var import_chalk84=__toESM(require_source(),1);async function rulesAdd(client,argv){let telemetryClient=new FlagsRulesCommandTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(rulesAddSubcommand2.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],conditionInputs=flags["--condition"]??[],variantSelector=normalizeOptionalInput(flags["--variant"]),baseSelector=normalizeOptionalInput(flags["--by"]),defaultVariantSelector=normalizeOptionalInput(flags["--default-variant"]),weightInputs=flags["--weight"]??[],rollFromVariantSelector=normalizeOptionalInput(flags["--from-variant"]),rollToVariantSelector=normalizeOptionalInput(flags["--to-variant"]),stageInputs=(flags["--stage"]??[]).map(input=>input.trim()),finalPercentage=flags["--final-percentage"],start=normalizeOptionalInput(flags["--start"]),position=flags["--position"],message=normalizeOptionalInput(flags["--message"]);telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionCondition(conditionInputs),telemetryClient.trackCliOptionVariant(variantSelector),telemetryClient.trackCliOptionBy(baseSelector),telemetryClient.trackCliOptionWeight(weightInputs),telemetryClient.trackCliOptionDefaultVariant(defaultVariantSelector),telemetryClient.trackCliOptionFromVariant(rollFromVariantSelector),telemetryClient.trackCliOptionToVariant(rollToVariantSelector),telemetryClient.trackCliOptionStage(stageInputs),telemetryClient.trackCliOptionFinalPercentage(finalPercentage),telemetryClient.trackCliOptionStart(start),telemetryClient.trackCliOptionPosition(position),telemetryClient.trackCliOptionMessage(message),telemetryClient.trackCliOptionProject(flags["--project"]);let outcomeOptions={variantSelector,baseSelector,defaultVariantSelector,weightInputs,rollFromVariantSelector,rollToVariantSelector,stageInputs,finalPercentage,start};if(!flagArg)return output_manager_default.error("Please provide a flag slug or ID to add a rule to"),output_manager_default.log(`Example: ${getCommandName("flags rules add my-feature --environment production --condition user.plan:eq:pro --variant on")}`),2;try{let context=await resolveRulesCommandContext(client,{projectName:parsedArgs.flags["--project"],flagArg,environment,promptMessage:"Select an environment to add the rule to:",fetchSettings:needsFlagRuleOutcomeSettings(outcomeOptions)||conditionInputs.length>0});if(isExitCodeResult2(context))return context.exitCode;let conditions=parseFlagRuleConditions(conditionInputs,context.settings),outcome=resolveFlagRuleOutcome(context.flag,context.settings,{...outcomeOptions,requireOutcome:!0}),rule=createFlagRule(conditions,outcome),envConfig=getFlagRulesEnvironmentConfig(context.flag,context.environment),nextEnvConfig=addFlagRule(envConfig,rule,position),nextPosition=nextEnvConfig.rules.findIndex(candidate=>candidate.id===rule.id)+1,updateMessage=await resolveFlagUpdateMessage(client,message,`Add rule ${rule.id} to ${context.environment}`);output_manager_default.spinner(`Adding rule to ${context.environment}...`);let updatedFlag=await updateFlag(client,context.projectId,flagArg,{environments:{[context.environment]:nextEnvConfig},message:updateMessage});output_manager_default.stopSpinner(),output_manager_default.success(`Rule ${import_chalk84.default.bold(rule.id)} added to ${import_chalk84.default.bold(context.flag.slug)} in ${import_chalk84.default.bold(context.environment)}`),output_manager_default.log(` ${import_chalk84.default.dim("Position:")} ${nextPosition}`),output_manager_default.log(` ${import_chalk84.default.dim("Outcome:")} ${formatFlagRuleOutcome(rule.outcome,context.flag.variants)}`),warnIfRuleChangesAreBypassed(updatedFlag,context.environment)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var import_chalk85=__toESM(require_source(),1),import_fast_deep_equal8=__toESM(require_fast_deep_equal(),1);async function rulesUpdate(client,argv){let telemetryClient=new FlagsRulesCommandTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(rulesUpdateSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg,ruleId]=args,environment=flags["--environment"],conditionInputs=flags["--condition"]??[],variantSelector=normalizeOptionalInput(flags["--variant"]),baseSelector=normalizeOptionalInput(flags["--by"]),defaultVariantSelector=normalizeOptionalInput(flags["--default-variant"]),weightInputs=flags["--weight"]??[],rollFromVariantSelector=normalizeOptionalInput(flags["--from-variant"]),rollToVariantSelector=normalizeOptionalInput(flags["--to-variant"]),stageInputs=(flags["--stage"]??[]).map(input=>input.trim()),finalPercentage=flags["--final-percentage"],start=normalizeOptionalInput(flags["--start"]),message=normalizeOptionalInput(flags["--message"]);telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliArgumentRule(ruleId),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionCondition(conditionInputs),telemetryClient.trackCliOptionVariant(variantSelector),telemetryClient.trackCliOptionBy(baseSelector),telemetryClient.trackCliOptionWeight(weightInputs),telemetryClient.trackCliOptionDefaultVariant(defaultVariantSelector),telemetryClient.trackCliOptionFromVariant(rollFromVariantSelector),telemetryClient.trackCliOptionToVariant(rollToVariantSelector),telemetryClient.trackCliOptionStage(stageInputs),telemetryClient.trackCliOptionFinalPercentage(finalPercentage),telemetryClient.trackCliOptionStart(start),telemetryClient.trackCliOptionMessage(message),telemetryClient.trackCliOptionProject(flags["--project"]);let outcomeOptions={variantSelector,baseSelector,defaultVariantSelector,weightInputs,rollFromVariantSelector,rollToVariantSelector,stageInputs,finalPercentage,start};if(!flagArg||!ruleId)return output_manager_default.error("Please provide a flag slug or ID and rule ID to update"),output_manager_default.log(`Example: ${getCommandName("flags rules update my-feature rule_123 --environment production --variant on")}`),2;try{let context=await resolveRulesCommandContext(client,{projectName:parsedArgs.flags["--project"],flagArg,environment,promptMessage:"Select an environment containing the rule:",fetchSettings:needsFlagRuleOutcomeSettings(outcomeOptions)||conditionInputs.length>0});if(isExitCodeResult2(context))return context.exitCode;let envConfig=getFlagRulesEnvironmentConfig(context.flag,context.environment),currentRule=findFlagRule(envConfig.rules??[],ruleId),hasOutcomeOptions=hasFlagRuleOutcomeOptions(outcomeOptions),nextConditions=conditionInputs.length>0?parseFlagRuleConditions(conditionInputs,context.settings):void 0,resolvedOutcome=hasOutcomeOptions?resolveFlagRuleOutcome(context.flag,context.settings,{...outcomeOptions,currentOutcome:currentRule.outcome}):void 0;if(!nextConditions&&!resolvedOutcome)return output_manager_default.warn("No rule changes were provided"),0;let nextEnvConfig=updateFlagRule(envConfig,ruleId,{conditions:nextConditions,outcome:resolvedOutcome});if((0,import_fast_deep_equal8.default)(context.envConfig,nextEnvConfig))return output_manager_default.warn("No rule changes were provided"),0;let updateMessage=await resolveFlagUpdateMessage(client,message,`Update rule ${ruleId} in ${context.environment}`);output_manager_default.spinner(`Updating rule in ${context.environment}...`);let updatedFlag=await updateFlag(client,context.projectId,flagArg,{environments:{[context.environment]:nextEnvConfig},message:updateMessage});output_manager_default.stopSpinner();let nextRule=findFlagRule(nextEnvConfig.rules,ruleId);output_manager_default.success(`Rule ${import_chalk85.default.bold(ruleId)} updated for ${import_chalk85.default.bold(context.flag.slug)} in ${import_chalk85.default.bold(context.environment)}`),output_manager_default.log(` ${import_chalk85.default.dim("Conditions:")} ${nextRule.conditions.map(condition=>formatFlagRuleCondition(condition,context.settings)).join(", ")}`),output_manager_default.log(` ${import_chalk85.default.dim("Outcome:")} ${formatFlagRuleOutcome(nextRule.outcome,context.flag.variants)}`),warnIfRuleChangesAreBypassed(updatedFlag,context.environment)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var import_chalk86=__toESM(require_source(),1);async function rulesRemove(client,argv){let telemetryClient=new FlagsRulesCommandTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(rulesRemoveSubcommand2.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg,ruleId]=args,environment=flags["--environment"],message=normalizeOptionalInput(flags["--message"]);if(telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliArgumentRule(ruleId),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionMessage(message),telemetryClient.trackCliOptionProject(flags["--project"]),!flagArg||!ruleId)return output_manager_default.error("Please provide a flag slug or ID and rule ID to remove"),output_manager_default.log(`Example: ${getCommandName("flags rules remove my-feature rule_123 --environment production")}`),2;try{let context=await resolveRulesCommandContext(client,{projectName:parsedArgs.flags["--project"],flagArg,environment,promptMessage:"Select an environment containing the rule:"});if(isExitCodeResult2(context))return context.exitCode;let envConfig=getFlagRulesEnvironmentConfig(context.flag,context.environment),nextEnvConfig=removeFlagRule(envConfig,ruleId),updateMessage=await resolveFlagUpdateMessage(client,message,`Remove rule ${ruleId} from ${context.environment}`);output_manager_default.spinner(`Removing rule from ${context.environment}...`);let updatedFlag=await updateFlag(client,context.projectId,flagArg,{environments:{[context.environment]:nextEnvConfig},message:updateMessage});output_manager_default.stopSpinner(),output_manager_default.success(`Rule ${import_chalk86.default.bold(ruleId)} removed from ${import_chalk86.default.bold(context.flag.slug)} in ${import_chalk86.default.bold(context.environment)}`),warnIfRuleChangesAreBypassed(updatedFlag,context.environment)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var import_chalk87=__toESM(require_source(),1),import_fast_deep_equal9=__toESM(require_fast_deep_equal(),1);async function rulesMove(client,argv){let telemetryClient=new FlagsRulesCommandTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(rulesMoveSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg,ruleId]=args,environment=flags["--environment"],position=flags["--position"],message=normalizeOptionalInput(flags["--message"]);if(telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliArgumentRule(ruleId),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionPosition(position),telemetryClient.trackCliOptionMessage(message),telemetryClient.trackCliOptionProject(flags["--project"]),!flagArg||!ruleId||position===void 0)return output_manager_default.error("Please provide a flag slug or ID, rule ID, and destination position"),output_manager_default.log(`Example: ${getCommandName("flags rules move my-feature rule_123 --environment production --position 1")}`),2;try{let context=await resolveRulesCommandContext(client,{projectName:parsedArgs.flags["--project"],flagArg,environment,promptMessage:"Select an environment containing the rule:"});if(isExitCodeResult2(context))return context.exitCode;let envConfig=getFlagRulesEnvironmentConfig(context.flag,context.environment),nextEnvConfig=moveFlagRule(envConfig,ruleId,position);if((0,import_fast_deep_equal9.default)(context.envConfig,nextEnvConfig))return output_manager_default.warn(`Rule ${import_chalk87.default.bold(ruleId)} is already at position ${position} in ${context.environment}`),0;let updateMessage=await resolveFlagUpdateMessage(client,message,`Move rule ${ruleId} to position ${position} in ${context.environment}`);output_manager_default.spinner(`Moving rule in ${context.environment}...`);let updatedFlag=await updateFlag(client,context.projectId,flagArg,{environments:{[context.environment]:nextEnvConfig},message:updateMessage});output_manager_default.stopSpinner(),output_manager_default.success(`Rule ${import_chalk87.default.bold(ruleId)} moved to position ${position} for ${import_chalk87.default.bold(context.flag.slug)} in ${import_chalk87.default.bold(context.environment)}`),warnIfRuleChangesAreBypassed(updatedFlag,context.environment)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var COMMAND_CONFIG14={ls:getCommandAliases(rulesListSubcommand2),add:getCommandAliases(rulesAddSubcommand2),update:getCommandAliases(rulesUpdateSubcommand),rm:getCommandAliases(rulesRemoveSubcommand2),move:getCommandAliases(rulesMoveSubcommand)};async function rules(client){let telemetry=new FlagsRulesTelemetryClient({opts:{store:client.telemetryEventStore}}),flagsSpecification=getFlagsSpecification(rulesSubcommand2.options),parsedArgs;try{parsedArgs=parseArguments(client.argv.slice(4),flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG14),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("flags rules",subcommand),output_manager_default.print(help(rulesSubcommand2,{parent:flagsCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:rulesSubcommand2,columns:client.stderr.columns}))}switch(subcommand){case"ls":return needHelp?(telemetry.trackCliFlagHelp("flags rules",subcommandOriginal),printHelp(rulesListSubcommand2),0):(telemetry.trackCliSubcommandList(subcommandOriginal),rulesLs(client,args));case"add":return needHelp?(telemetry.trackCliFlagHelp("flags rules",subcommandOriginal),printHelp(rulesAddSubcommand2),0):(telemetry.trackCliSubcommandAdd(subcommandOriginal),rulesAdd(client,args));case"update":return needHelp?(telemetry.trackCliFlagHelp("flags rules",subcommandOriginal),printHelp(rulesUpdateSubcommand),0):(telemetry.trackCliSubcommandUpdate(subcommandOriginal),rulesUpdate(client,args));case"rm":return needHelp?(telemetry.trackCliFlagHelp("flags rules",subcommandOriginal),printHelp(rulesRemoveSubcommand2),0):(telemetry.trackCliSubcommandRemove(subcommandOriginal),rulesRemove(client,args));case"move":return needHelp?(telemetry.trackCliFlagHelp("flags rules",subcommandOriginal),printHelp(rulesMoveSubcommand),0):(telemetry.trackCliSubcommandMove(subcommandOriginal),rulesMove(client,args));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG14)),output_manager_default.print(help(rulesSubcommand2,{parent:flagsCommand,columns:client.stderr.columns})),2}}var FlagsTargetsTelemetryClient=class extends TelemetryClient{trackCliSubcommandList(actual){this.trackCliSubcommand({subcommand:"ls",value:actual})}trackCliSubcommandAdd(actual){this.trackCliSubcommand({subcommand:"add",value:actual})}trackCliSubcommandRemove(actual){this.trackCliSubcommand({subcommand:"rm",value:actual})}},FlagsTargetsCommandTelemetryClient=class extends FlagsRulesCommandTelemetryClient{trackCliArgumentTarget(targets2){targets2?.length&&this.trackCliArgument({arg:"target",value:this.redactedValue})}};var import_chalk89=__toESM(require_source(),1),import_pluralize9=__toESM(require_pluralize(),1);function formatFlagTargetSelector(target){return`${target.entity}.${target.attribute}=${target.value}`}function parseFlagTargetInput(input,options={}){let separatorIndex=input.indexOf("=");if(separatorIndex===-1)throw new Error(`Invalid target "${input}". Use ENTITY.ATTRIBUTE=VALUE, for example user.id=user_123.`);let{kind:entity,attribute}=parseEntityAttributeSelector(input.slice(0,separatorIndex)),rawValue=input.slice(separatorIndex+1);if(!options.allowLabel){if(!rawValue)throw new Error(`Invalid target "${input}". Value cannot be empty.`);return{entity,attribute,value:rawValue}}let labelIndex=rawValue.indexOf("|"),value=(labelIndex===-1?rawValue:rawValue.slice(0,labelIndex)).trim();if(!value)throw new Error(`Invalid target "${input}". Value cannot be empty.`);if(labelIndex===-1)return{entity,attribute,value};let label=rawValue.slice(labelIndex+1).trim();if(!label)throw new Error(`Invalid target "${input}". Label cannot be empty; use ENTITY.ATTRIBUTE=VALUE|LABEL or omit the "|".`);return validateLabelString(label,"label"),{entity,attribute,value,label}}function parseFlagTargetInputs(inputs,settings){let seen=new Map;for(let input of inputs){let target=parseFlagTargetInput(input,{allowLabel:!0});assertTargetableAttribute(target,settings);let key=formatFlagTargetSelector(target),existing=seen.get(key);existing?target.label&&(existing.label=target.label):seen.set(key,target)}return[...seen.values()]}function assertTargetableAttribute(target,settings){let entity=settings.entities.find(candidate=>candidate.kind===target.entity);if(!entity){let available=settings.entities.map(candidate=>candidate.kind);throw new Error(available.length>0?`Entity "${target.entity}" does not exist. Available entities: ${available.join(", ")}.`:`Entity "${target.entity}" does not exist. Define entities before adding targets.`)}let attribute=entity.attributes.find(candidate=>candidate.key===target.attribute);if(!attribute){let available=entity.attributes.map(candidate=>`${entity.kind}.${candidate.key}`);throw new Error(available.length>0?`Attribute "${target.entity}.${target.attribute}" does not exist. Available attributes: ${available.join(", ")}.`:`Attribute "${target.entity}.${target.attribute}" does not exist.`)}if(attribute.type!=="string")throw new Error(`Only string attributes can be targeted directly. ${target.entity}.${target.attribute} is a ${attribute.type} attribute.`)}function listFlagTargets(targets2){let entries=[];for(let[variantId,entities2]of Object.entries(targets2??{}))for(let[entity,attributes]of Object.entries(entities2))for(let[attribute,values]of Object.entries(attributes))for(let item of values)entries.push({variantId,entity,attribute,value:item.value,...item.note?{note:item.note}:{}});return entries}function findFlagTargetVariantId(targets2,target){for(let[variantId,entities2]of Object.entries(targets2??{}))if(entities2[target.entity]?.[target.attribute]?.some(item=>item.value===target.value))return variantId}function addFlagTargets(targets2,selectors,variantId){let next=structuredClone(targets2??{}),results=[];for(let selector of selectors){let previousVariantId=findFlagTargetVariantId(next,selector);if(previousVariantId===variantId){results.push({...selector,status:"unchanged"});continue}let previous=previousVariantId?deleteTargetValue(next,previousVariantId,selector):void 0,entities2=next[variantId]??={},attributes=entities2[selector.entity]??={};(attributes[selector.attribute]??=[]).push(previous?.note?{value:selector.value,note:previous.note}:{value:selector.value}),results.push(previousVariantId?{...selector,status:"moved",previousVariantId}:{...selector,status:"added"})}return{targets:next,results}}function removeFlagTargets(targets2,selectors){let next=structuredClone(targets2??{}),results=[],seen=new Set;for(let selector of selectors){let key=formatFlagTargetSelector(selector);if(seen.has(key))continue;seen.add(key);let variantId=findFlagTargetVariantId(next,selector);if(!variantId)throw new Error(`Target "${formatFlagTargetSelector(selector)}" does not exist.`);deleteTargetValue(next,variantId,selector),results.push({...selector,variantId})}return{targets:next,results}}function deleteTargetValue(targets2,variantId,selector){let entities2=targets2[variantId],attributes=entities2?.[selector.entity],values=attributes?.[selector.attribute];if(!entities2||!attributes||!values)return;let removed=values.find(item=>item.value===selector.value),remaining=values.filter(item=>item.value!==selector.value);return remaining.length>0?(attributes[selector.attribute]=remaining,removed):(delete attributes[selector.attribute],Object.keys(attributes).length===0&&delete entities2[selector.entity],Object.keys(entities2).length===0&&delete targets2[variantId],removed)}function buildTargetsEnvironmentConfig(flag,environment,targets2){return{...flag.environments[environment],targets:targets2}}var import_chalk88=__toESM(require_source(),1);function formatTargetValue2(target,settings){let label=target.label??resolveTargetingLabel(settings,target.entity,target.attribute,target.value),selector=formatFlagTargetSelector(target);return label?`${selector} ${import_chalk88.default.gray(label)}`:selector}function formatTargetVariant(flag,variantId){let variant=flag.variants.find(candidate=>candidate.id===variantId);return formatFlagVariantSummary(variant,variantId)}async function targetsLs(client,argv){let telemetryClient=new FlagsTargetsCommandTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(targetsListSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg]=args,environment=flags["--environment"],json=flags["--json"];if(telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliFlagJson(json),telemetryClient.trackCliOptionProject(flags["--project"]),!flagArg)return output_manager_default.error("Please provide a flag slug or ID to list targets for"),output_manager_default.log(`Example: ${getCommandName("flags targets list my-feature --environment production")}`),2;if(json&&!environment)return output_manager_default.error("Missing required option --environment when using --json"),output_manager_default.log(`Example: ${getCommandName("flags targets list my-feature --environment production --json")}`),2;try{let context=await resolveRulesCommandContext(client,{projectName:flags["--project"],flagArg,environment,promptMessage:"Select an environment to list targets for:",fetchSettings:!json});if(isExitCodeResult2(context))return context.exitCode;let{envConfig}=context,targets2=envConfig.targets??{};if(json)return client.stdout.write(`${JSON.stringify({flag:context.flag.slug,environment:context.environment,active:envConfig.active,...envConfig.reuse?{reuse:envConfig.reuse}:{},targets:targets2},null,2)}
|
|
362
|
+
`),0;let entries=listFlagTargets(targets2),lsStamp=stamp_default(),inactiveMode=describeInactiveTargetingMode(context.flag,envConfig);if(entries.length===0){let projectFlag=flags["--project"]?` --project ${flags["--project"]}`:"";return output_manager_default.log(`No targets found for ${import_chalk89.default.bold(context.flag.slug)} in ${context.environment} ${import_chalk89.default.gray(lsStamp())}`),output_manager_default.log(`
|
|
363
|
+
Add one with: ${getCommandName(`flags targets add ${context.flag.slug} --environment ${context.environment} user.id=user_123${projectFlag}`)}`),0}output_manager_default.log(`${(0,import_pluralize9.default)("target",entries.length,!0)} found for ${import_chalk89.default.bold(context.flag.slug)} in ${context.environment} ${import_chalk89.default.gray(lsStamp())}`),printTargetsTable(entries,context.flag,context.settings),inactiveMode&&output_manager_default.print(`${import_chalk89.default.yellow("!")} ${import_chalk89.default.bold(context.environment)} ${inactiveMode}; these targets are not evaluated until targeting is active again.
|
|
364
|
+
`)}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function printTargetsTable(entries,flag,settings){let headers=["Attribute","Value","Label","Variant"],rows=entries.map(entry=>[`${entry.entity}.${entry.attribute}`,import_chalk89.default.bold(entry.value),resolveTargetingLabel(settings,entry.entity,entry.attribute,entry.value)??entry.note??"",formatTargetVariant(flag,entry.variantId)]),table2=formatTable(headers,["l","l","l","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
365
|
+
${table2}
|
|
366
|
+
`)}var import_chalk90=__toESM(require_source(),1),import_pluralize10=__toESM(require_pluralize(),1);var EXAMPLE="flags targets add my-feature --environment production user.id=user_123";async function targetsAdd(client,argv){let telemetryClient=new FlagsTargetsCommandTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(targetsAddSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg,...targetInputs]=args,environment=flags["--environment"],variantSelector=normalizeOptionalInput(flags["--variant"]),message=normalizeOptionalInput(flags["--message"]),json=flags["--json"];if(telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliArgumentTarget(targetInputs),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionVariant(variantSelector),telemetryClient.trackCliOptionMessage(message),telemetryClient.trackCliFlagJson(json),telemetryClient.trackCliOptionProject(flags["--project"]),!flagArg||targetInputs.length===0)return output_manager_default.error("Please provide a flag slug or ID and at least one target as ENTITY.ATTRIBUTE=VALUE"),output_manager_default.log(`Example: ${getCommandName(EXAMPLE)}`),2;if(json&&!environment)return output_manager_default.error("Missing required option --environment when using --json"),output_manager_default.log(`Example: ${getCommandName(`${EXAMPLE} --json`)}`),2;try{let context=await resolveRulesCommandContext(client,{projectName:flags["--project"],flagArg,environment,promptMessage:"Select an environment to add targets to:",fetchSettings:!0});if(isExitCodeResult2(context))return context.exitCode;if(!context.settings)throw new Error("Flag settings are required to add targets.");let selectors=parseFlagTargetInputs(targetInputs,context.settings),variant=resolveTargetVariant(context.flag,variantSelector);if(!variant)return 2;let{targets:targets2,results}=addFlagTargets(context.envConfig.targets,selectors,variant.id),changed=results.filter(result=>result.status!=="unchanged"),variantSummary=formatTargetVariant(context.flag,variant.id),labelItems=buildLabelItems(selectors,context.settings);if(changed.length===0&&labelItems.length===0)return json?(writeJson(client,context.flag.slug,context.environment,targets2),0):(output_manager_default.warn(`${(0,import_pluralize10.default)("target",results.length,!0)} already ${results.length===1?"serves":"serve"} ${variantSummary} in ${import_chalk90.default.bold(context.environment)}; nothing to change`),0);let updatedFlag=context.flag;if(changed.length>0){let defaultMessage=`Add ${(0,import_pluralize10.default)("target",changed.length,!0)} to ${context.environment}`,updateMessage=json?message??defaultMessage:await resolveFlagUpdateMessage(client,message,defaultMessage);output_manager_default.spinner(`Adding targets to ${context.environment}...`),updatedFlag=await updateFlag(client,context.projectId,flagArg,{environments:{[context.environment]:buildTargetsEnvironmentConfig(context.flag,context.environment,targets2)},message:updateMessage}),output_manager_default.stopSpinner()}let labels2=await saveLabels(client,context.projectId,labelItems),finalTargets=updatedFlag.environments[context.environment]?.targets??targets2;if(json)return writeJson(client,updatedFlag.slug,context.environment,finalTargets,labels2),labels2&&labels2.errors.length>0?1:0;let labelSummary=labels2&&labels2.labels.length>0?` ${import_chalk90.default.dim(`(${(0,import_pluralize10.default)("label",labels2.labels.length,!0)} set)`)}`:"";changed.length>0?output_manager_default.success(`${(0,import_pluralize10.default)("target",changed.length,!0)} added to ${import_chalk90.default.bold(context.flag.slug)} in ${import_chalk90.default.bold(context.environment)}${labelSummary}`):output_manager_default.success(`Targets of ${import_chalk90.default.bold(context.flag.slug)} in ${import_chalk90.default.bold(context.environment)} unchanged${labelSummary}`);let failedLabelKeys=new Set((labels2?.errors??[]).map(error=>`${error.entityKind}.${error.attributeKey}=${error.value}`));for(let result of results){let selector=failedLabelKeys.has(formatFlagTargetSelector(result))?{...result,label:void 0}:result,value=formatTargetValue2(selector,context.settings);result.status==="moved"&&result.previousVariantId?output_manager_default.log(` ${value} ${import_chalk90.default.dim("\u2192")} ${variantSummary} ${import_chalk90.default.dim(`(moved from ${formatTargetVariant(context.flag,result.previousVariantId)})`)}`):result.status==="unchanged"?output_manager_default.log(` ${value} ${import_chalk90.default.dim("\u2192")} ${variantSummary} ${import_chalk90.default.dim("(unchanged)")}`):output_manager_default.log(` ${value} ${import_chalk90.default.dim("\u2192")} ${variantSummary}`)}if(warnIfRuleChangesAreBypassed(updatedFlag,context.environment,"target"),labels2&&labels2.errors.length>0){output_manager_default.warn(`${(0,import_pluralize10.default)("label",labels2.errors.length,!0)} ${labels2.errors.length===1?"was":"were"} not saved. The targets above are in place; set the labels again with:`);for(let error of labels2.errors){let item=labelItems.find(candidate=>candidate.entityKind===error.entityKind&&candidate.attributeKey===error.attributeKey&&candidate.value===error.value);output_manager_default.print(` ${import_chalk90.default.dim(`${error.code}: ${error.message}`)}
|
|
367
|
+
`),output_manager_default.print(` ${getCommandName(["flags labels set",quoteArg(`${error.entityKind}.${error.attributeKey}`),quoteArg(error.value),quoteArg(item&&"label"in item?item.label:"")].join(" "))}
|
|
368
|
+
`)}return 1}}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}function resolveTargetVariant(flag,variantSelector){if(variantSelector)return resolveVariantOrThrow(variantSelector,flag.variants,"--variant");if(flag.kind==="boolean")return getBooleanVariant(flag,!0);output_manager_default.error(`Missing required option --variant. Flag ${import_chalk90.default.bold(flag.slug)} is a ${flag.kind} flag, so choose which variant the targets receive.`),output_manager_default.log(`Example: ${getCommandName(`flags targets add ${flag.slug} --environment production --variant <VARIANT> user.id=user_123`)}`)}function buildLabelItems(selectors,settings){let items=selectors.filter(selector=>selector.label!==void 0&&selector.label!==resolveTargetingLabel(settings,selector.entity,selector.attribute,selector.value)).map(selector=>({operation:"upsert",entityKind:selector.entity,attributeKey:selector.attribute,value:selector.value,label:selector.label}));if(items.length>MAX_LABEL_OPERATIONS)throw new Error(`Cannot set more than ${MAX_LABEL_OPERATIONS} labels at once. Split the targets into smaller batches.`);return items}async function saveLabels(client,projectId,items){if(items.length!==0){output_manager_default.spinner("Saving labels...");try{return await updateEntityLabelsBulk(client,projectId,items)}catch(err){let message=err instanceof Error?err.message:String(err);return{labels:[],errors:items.map(item=>({entityKind:item.entityKind,attributeKey:item.attributeKey,value:item.value,code:isAPIError(err)?err.code??"api_error":"error",message}))}}finally{output_manager_default.stopSpinner()}}}function writeJson(client,flag,environment,targets2,labels2){client.stdout.write(`${JSON.stringify({flag,environment,targets:targets2,...labels2?{labels:labels2}:{}},null,2)}
|
|
369
|
+
`)}var import_chalk91=__toESM(require_source(),1),import_pluralize11=__toESM(require_pluralize(),1);var EXAMPLE2="flags targets remove my-feature --environment production user.id=user_123";async function targetsRemove(client,argv){let telemetryClient=new FlagsTargetsCommandTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(targetsRemoveSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,[flagArg,...targetInputs]=args,environment=flags["--environment"],message=normalizeOptionalInput(flags["--message"]),json=flags["--json"];if(telemetryClient.trackCliArgumentFlag(flagArg),telemetryClient.trackCliArgumentTarget(targetInputs),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliOptionMessage(message),telemetryClient.trackCliFlagJson(json),telemetryClient.trackCliOptionProject(flags["--project"]),!flagArg||targetInputs.length===0)return output_manager_default.error("Please provide a flag slug or ID and at least one target as ENTITY.ATTRIBUTE=VALUE"),output_manager_default.log(`Example: ${getCommandName(EXAMPLE2)}`),2;if(json&&!environment)return output_manager_default.error("Missing required option --environment when using --json"),output_manager_default.log(`Example: ${getCommandName(`${EXAMPLE2} --json`)}`),2;try{let selectors=targetInputs.map(input=>parseFlagTargetInput(input)),context=await resolveRulesCommandContext(client,{projectName:flags["--project"],flagArg,environment,promptMessage:"Select an environment to remove targets from:",fetchSettings:!json});if(isExitCodeResult2(context))return context.exitCode;let{targets:targets2,results}=removeFlagTargets(context.envConfig.targets,selectors),defaultMessage=`Remove ${(0,import_pluralize11.default)("target",results.length,!0)} from ${context.environment}`,updateMessage=json?message??defaultMessage:await resolveFlagUpdateMessage(client,message,defaultMessage);output_manager_default.spinner(`Removing targets from ${context.environment}...`);let updatedFlag=await updateFlag(client,context.projectId,flagArg,{environments:{[context.environment]:buildTargetsEnvironmentConfig(context.flag,context.environment,targets2)},message:updateMessage});if(output_manager_default.stopSpinner(),json)return client.stdout.write(`${JSON.stringify({flag:updatedFlag.slug,environment:context.environment,targets:updatedFlag.environments[context.environment]?.targets??targets2},null,2)}
|
|
370
|
+
`),0;output_manager_default.success(`${(0,import_pluralize11.default)("target",results.length,!0)} removed from ${import_chalk91.default.bold(context.flag.slug)} in ${import_chalk91.default.bold(context.environment)}`);for(let result of results)output_manager_default.log(` ${formatTargetValue2(result,context.settings)} ${import_chalk91.default.dim("(was")} ${formatTargetVariant(context.flag,result.variantId)}${import_chalk91.default.dim(")")}`);warnIfRuleChangesAreBypassed(updatedFlag,context.environment,"target")}catch(err){return output_manager_default.stopSpinner(),printError(err),1}return 0}var COMMAND_CONFIG15={ls:getCommandAliases(targetsListSubcommand),add:getCommandAliases(targetsAddSubcommand),rm:getCommandAliases(targetsRemoveSubcommand)};async function targets(client){let telemetry=new FlagsTargetsTelemetryClient({opts:{store:client.telemetryEventStore}}),flagsSpecification=getFlagsSpecification(targetsSubcommand.options),parsedArgs;try{parsedArgs=parseArguments(client.argv.slice(4),flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let{subcommand,args,subcommandOriginal}=getSubcommand(parsedArgs.args,COMMAND_CONFIG15),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("flags targets",subcommand),output_manager_default.print(help(targetsSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:targetsSubcommand,columns:client.stderr.columns}))}switch(subcommand){case"ls":return needHelp?(telemetry.trackCliFlagHelp("flags targets",subcommandOriginal),printHelp(targetsListSubcommand),0):(telemetry.trackCliSubcommandList(subcommandOriginal),targetsLs(client,args));case"add":return needHelp?(telemetry.trackCliFlagHelp("flags targets",subcommandOriginal),printHelp(targetsAddSubcommand),0):(telemetry.trackCliSubcommandAdd(subcommandOriginal),targetsAdd(client,args));case"rm":return needHelp?(telemetry.trackCliFlagHelp("flags targets",subcommandOriginal),printHelp(targetsRemoveSubcommand),0):(telemetry.trackCliSubcommandRemove(subcommandOriginal),targetsRemove(client,args));default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG15)),output_manager_default.print(help(targetsSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),2}}var FlagsTargetingTelemetryClient=class extends TelemetryClient{trackCliSubcommandEnable(actual){this.trackCliSubcommand({subcommand:"enable",value:actual})}};var COMMAND_CONFIG16={enable:getCommandAliases(targetingEnableSubcommand)};async function targeting(client,args){let telemetry=new FlagsTargetingTelemetryClient({opts:{store:client.telemetryEventStore}}),{subcommand,args:subArgs,subcommandOriginal}=getSubcommand(args,COMMAND_CONFIG16);switch(subcommand){case"enable":return telemetry.trackCliSubcommandEnable(subcommandOriginal),useTargeting(client,subArgs);default:return output_manager_default.error(getInvalidSubcommand(COMMAND_CONFIG16)),output_manager_default.print(help(targetingSubcommand,{parent:flagsCommand,columns:client.stderr.columns})),2}}var import_env=__toESM(require_dist(),1);init_dist();async function emitDatafiles(client){try{parseArguments(client.argv.slice(4),getFlagsSpecification(prepareSubcommand.options))}catch(err){return printError(err),2}try{let localEnv={};try{localEnv=(0,import_env.loadEnvConfig)(client.cwd,!0).combinedEnv}catch(err){output_manager_default.debug(`Failed to load local env files: ${err}`)}return await prepareFlagsDefinitions({cwd:client.cwd,env:{...localEnv,...process.env},userAgentSuffix:ua_default,output:output_manager_default}),0}catch(err){return printError(err),1}}var import_env2=__toESM(require_dist(),1);async function override(client,argv){let parsedArgs,flagsSpecification=getFlagsSpecification(overrideSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,decryptToken=flags["--decrypt"];return decryptToken?handleDecrypt(client,decryptToken):handleEncrypt(client,args,flags)}async function handleEncrypt(client,args,flags){let expiration=flags["--expiration"]??"1y";if(args.length===0)return output_manager_default.error(`Please provide at least one flag override as flag=value.
|
|
371
|
+
Example: vercel flags override my-flag=true`),2;let overrides={};for(let arg of args){let eqIndex=arg.indexOf("=");if(eqIndex===-1)return output_manager_default.error(`Invalid override format: "${arg}". Expected flag=value.`),1;let key=arg.slice(0,eqIndex),rawValue=arg.slice(eqIndex+1);overrides[key]=parseValue(rawValue)}let secret=resolveSecret(client);if(!secret)return output_manager_default.error("FLAGS_SECRET not found. Set it in the environment, .env.local, or .env file."),1;try{let encrypted=await encryptOverrides(overrides,secret,expiration);return client.stdout.write(encrypted+`
|
|
372
|
+
`),0}catch(err){return printError(err),1}}async function handleDecrypt(client,token){let secret=resolveSecret(client);if(!secret)return output_manager_default.error("FLAGS_SECRET not found. Set it in the environment, .env.local, or .env file."),1;try{let overrides=await decryptOverrides(token,secret);return overrides===void 0?(output_manager_default.error("Invalid token: not a valid flag overrides token."),2):(client.stdout.write(JSON.stringify(overrides,null,2)+`
|
|
373
|
+
`),0)}catch(err){return printError(err),1}}function parseValue(raw){if(raw==="true")return!0;if(raw==="false")return!1;let num=Number(raw);return!Number.isNaN(num)&&raw.trim()!==""?num:raw}function resolveSecret(client){let{combinedEnv}=(0,import_env2.loadEnvConfig)(client.cwd,!0);return combinedEnv.FLAGS_SECRET}async function encryptOverrides(overrides,secret,expirationTime){let encodedSecret=base64url_exports.decode(secret);if(encodedSecret.length!==32)throw new Error("Invalid FLAGS_SECRET: must be a 256-bit base64url-encoded key (32 bytes).");return new EncryptJWT({o:overrides,pur:"overrides"}).setExpirationTime(expirationTime).setProtectedHeader({alg:"dir",enc:"A256GCM"}).encrypt(encodedSecret)}async function decryptOverrides(encryptedData,secret){let encodedSecret=base64url_exports.decode(secret);if(encodedSecret.length!==32)throw new Error("Invalid FLAGS_SECRET: must be a 256-bit base64url-encoded key (32 bytes).");let{payload}=await jwtDecrypt(encryptedData,encodedSecret);if(!(payload.pur!=="overrides"||!payload.o))return payload.o}var import_chalk92=__toESM(require_source(),1),import_ms7=__toESM(require_ms(),1),import_pluralize12=__toESM(require_pluralize(),1);var MAX_LISTED_VARIANTS=3,MAX_VARIANT_LENGTH=30;function isPackedDatafile(data){return typeof data=="object"&&data!==null&&typeof data.definitions=="object"&&data.definitions!==null}function printDatafileSummary(datafile2,{projectLabel,environment,jsonCommand}){let envName=datafile2.environment??environment,slugs=Object.keys(datafile2.definitions).sort(),segmentCount=Object.keys(datafile2.segments??{}).length,source=[envName?`the ${envName} datafile`:"the datafile",projectLabel??datafile2.projectId].filter(Boolean).join(" for "),details=[datafile2.revision!==void 0?`revision ${datafile2.revision}`:null,datafile2.configUpdatedAt!==void 0?`updated ${(0,import_ms7.default)(Math.max(0,Date.now()-datafile2.configUpdatedAt))} ago`:null].filter(Boolean),detailsSuffix=details.length>0?` ${import_chalk92.default.gray(`(${details.join(", ")})`)}`:"",segmentsSuffix=segmentCount>0?` and ${(0,import_pluralize12.default)("segment",segmentCount,!0)}`:"";if(slugs.length===0)output_manager_default.log(`No feature flags in ${source}${detailsSuffix}`);else{output_manager_default.log(`${(0,import_pluralize12.default)("feature flag",slugs.length,!0)}${segmentsSuffix} in ${source}${detailsSuffix}`);let rows=slugs.map(slug=>formatFlagRow(slug,datafile2.definitions[slug],envName)),table2=formatTable(["Name","Serves","Rules","Targets","Reuses"],["l","l","r","r","l"],[{name:"",rows}]);output_manager_default.print(`
|
|
374
|
+
${table2}
|
|
375
|
+
`)}output_manager_default.log(`To see the full datafile including rules, run ${jsonCommand}`)}function formatFlagRow(slug,definition,envName){let{config,reusedEnvironment}=resolveEnvironmentConfig(definition,envName),reuses=reusedEnvironment??"";return config===void 0||typeof config=="object"&&"reuse"in config?[import_chalk92.default.bold(slug),import_chalk92.default.gray("unknown"),"","",reuses]:typeof config=="number"?[import_chalk92.default.bold(slug),formatServes(definition,new Set([config])),"","",reuses]:[import_chalk92.default.bold(slug),formatServes(definition,collectServedVariants(definition,config)),String(config.rules?.length??0),String(countTargets(config.targets)),reuses]}function resolveEnvironmentConfig(definition,envName){let environments=definition.environments??{},name=envName??Object.keys(environments)[0],config=name!==void 0?environments[name]:void 0,reusedEnvironment,visited=new Set([name]);for(;typeof config=="object"&&config!==null&&"reuse"in config;){if(reusedEnvironment??=config.reuse,visited.has(config.reuse))return{config:void 0,reusedEnvironment};visited.add(config.reuse),config=environments[config.reuse]}return{config,reusedEnvironment}}function collectServedVariants(definition,config){let served=new Set,addOutcome=outcome=>{if(typeof outcome=="number"){served.add(outcome);return}switch(outcome?.type){case"split":outcome.weights.forEach((weight,index)=>{weight>0&&served.add(index)}),served.add(outcome.defaultVariant);return;case"rollout":served.add(outcome.rollFromVariant),served.add(outcome.rollToVariant),served.add(outcome.defaultVariant);return;case"experiment":if(definition.experiment){addOutcome({type:"split",...definition.experiment});return}break}definition.variants.forEach((_,index)=>served.add(index))};addOutcome(config.fallthrough);for(let rule of config.rules??[])addOutcome(rule?.outcome);return config.targets?.forEach((targetList,index)=>{countTargets([targetList])>0&&served.add(index)}),served}function formatServes(definition,served){let values=[...served].sort((a,b)=>a-b).map(index=>definition.variants[index]);return values.length===1?values[0]===void 0?import_chalk92.default.gray("unknown"):truncateEnd(formatVariantValue(values[0]),MAX_VARIANT_LENGTH,{omission:"\u2026"}):values.length<=MAX_LISTED_VARIANTS&&values.every(value=>typeof value=="boolean"||typeof value=="number")?values.map(value=>formatVariantValue(value)).join(", "):(0,import_pluralize12.default)("variant",values.length,!0)}function countTargets(targets2){let count=0;for(let targetList of targets2??[])for(let attributes of Object.values(targetList))for(let values of Object.values(attributes))count+=Array.isArray(values)?values.length:0;return count}var FlagsDatafileTelemetryClient=class extends TelemetryClient{trackCliFlagJson(json){json&&this.trackCliFlag("json")}trackCliOptionProject(project){project&&this.trackCliOption({option:"project",value:this.redactedValue})}trackCliOptionEnvironment(environment){environment&&this.trackCliOption({option:"environment",value:environment})}trackCliFlagSdkKey(sdkKey){sdkKey&&this.trackCliFlag("sdk-key")}};var DATAFILE_URL="https://flags.vercel.com/v1/datafile",ENVIRONMENTS=["production","preview","development"],MAX_SDK_KEY_BYTES=4096,SDK_KEY_FORMAT=/^vf_(?:server|client)_[\x21-\x7E]+$/;function commandName(json,subcommands){return json?getCommandNamePlain(subcommands):getCommandName(subcommands)}function sdkKeyInputHint(json){return`Pipe it to stdin instead, for example ${commandName(json,"flags datafile --sdk-key < sdk-key.txt")}.`}async function datafile(client,argv){let telemetryClient=new FlagsDatafileTelemetryClient({opts:{store:client.telemetryEventStore}}),parsedArgs,flagsSpecification=getFlagsSpecification(datafileSubcommand.options);try{parsedArgs=parseArguments(argv,flagsSpecification)}catch(err){return printError(err),2}let{args,flags}=parsedArgs,projectName=getProjectNameFromFlags(flags),environment=flags["--environment"],useSdkKey=!!flags["--sdk-key"],json=!!flags["--json"];if(telemetryClient.trackCliOptionProject(projectName),telemetryClient.trackCliOptionEnvironment(environment),telemetryClient.trackCliFlagSdkKey(useSdkKey),telemetryClient.trackCliFlagJson(json),argv.some(arg=>arg.startsWith("--sdk-key="))||args.some(arg=>SDK_KEY_PATTERN.test(arg)))return outputError(client,json,"INVALID_ARGUMENTS",`SDK keys can't be passed as arguments. ${sdkKeyInputHint(json)}`);if(args.length>0)return outputError(client,json,"INVALID_ARGUMENTS",`${commandName(json,"flags datafile")} doesn't take arguments.`);if(environment!==void 0&&!ENVIRONMENTS.includes(environment))return outputError(client,json,"INVALID_ARGUMENTS",`Invalid environment "${environment}". Must be one of: ${ENVIRONMENTS.join(", ")}.`);if(useSdkKey){if(environment)return outputError(client,json,"MUTUAL_EXCLUSIVITY","The --environment option cannot be used with --sdk-key, as SDK keys are already bound to an environment.");if(projectName)return outputError(client,json,"MUTUAL_EXCLUSIVITY","The --project option cannot be used with --sdk-key, as SDK keys are already bound to a project.");let sdkKey=await readSdkKey(client,json);return typeof sdkKey=="number"?sdkKey:(json||output_manager_default.spinner("Fetching datafile"),fetchAndPrintDatafile(client,json,sdkKey,{},"Bearer",{jsonCommand:getJsonCommand(["--sdk-key"])}))}let link=await getLinkedFlagsProject(client,projectName);if(link.status==="error")return link.exitCode;if(link.status==="not_linked")return outputError(client,json,"NOT_LINKED",`Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${commandName(json,"link")} to link it.`);let{project,org}=link;json||output_manager_default.spinner(`Fetching ${environment?`${environment} `:""}datafile for ${formatProject(org.slug,project.name)}`);let token,authScheme="Bearer",targetEnvironment=environment??"development",headers={"x-vercel-flags-project-id":project.id};try{let oidcToken=targetEnvironment==="development"?await getDevelopmentOidcToken(client,project.id,org.id):void 0;if(oidcToken)token=oidcToken;else{if(await client.ensureAuthorized(),!client.authConfig.token)return output_manager_default.stopSpinner(),outputError(client,json,"NOT_AUTHORIZED",`No user token is available. Run ${commandName(json,"login")} and retry the datafile command.`);token=client.authConfig.token,authScheme="VercelUser",headers["x-vercel-flags-team-id"]=org.id,headers["x-vercel-env"]=targetEnvironment}}catch(err){return output_manager_default.stopSpinner(),printUnexpectedError(client,json,err)}return fetchAndPrintDatafile(client,json,token,headers,authScheme,{projectLabel:formatProject(org.slug,project.name),environment:targetEnvironment,jsonCommand:getJsonCommand([...projectName?["--project",quoteArg(projectName)]:[],...environment?["--environment",environment]:[]])})}function getJsonCommand(args){return getCommandName(["flags datafile",...args,"--json"].join(" "))}async function readSdkKey(client,json){let sdkKey;if(!client.stdin.isTTY)sdkKey=(await readStdinText(client.stdin,MAX_SDK_KEY_BYTES)).trim();else if(!client.nonInteractive&&!json)sdkKey=(await client.input.password({message:"SDK key",mask:!0,validate:value=>value.trim().length>0?!0:"Enter an SDK key."})).trim();else return missingSdkKey(client,json,"Missing SDK key.");return sdkKey?SDK_KEY_PATTERN.test(sdkKey)?SDK_KEY_FORMAT.test(sdkKey)?sdkKey:outputError(client,json,"INVALID_ARGUMENTS","The SDK key can't contain spaces, line breaks, or other control characters."):outputError(client,json,"INVALID_ARGUMENTS","The SDK key must start with vf_server_ or vf_client_."):missingSdkKey(client,json,"No SDK key was read from stdin.")}function missingSdkKey(client,json,problem){let reason=AGENT_REASON.MISSING_KEY,machine=json||shouldEmitNonInteractiveCommandError(client),message=`${problem} ${sdkKeyInputHint(machine)}`;return machine?writeActionRequired(client,{status:AGENT_STATUS.ACTION_REQUIRED,reason,message,next:[{command:`${buildCommandWithGlobalFlags(client.argv,`flags datafile --sdk-key${json?" --json":""}`)} < <SDK_KEY_FILE>`,when:"Replace <SDK_KEY_FILE> with a file that contains the SDK key"}]}):output_manager_default.error(message),getExitCodeForReason(reason)}async function getDevelopmentOidcToken(client,projectId,accountId){try{let result=await client.fetch(`/projects/${projectId}/token`,{method:"POST",accountId,retry:{retries:0},bailOn429:!0,body:JSON.stringify({source:"vercel-cli"}),headers:{"Content-Type":"application/json"}});return typeof result.token=="string"&&result.token.trim()?result.token:void 0}catch{output_manager_default.debug("Development OIDC token unavailable; using user authentication.");return}}async function fetchAndPrintDatafile(client,json,token,extraHeaders,authScheme,summary){try{let res=await fetch(DATAFILE_URL,{redirect:"error",headers:{accept:"application/json",authorization:`${authScheme} ${token}`,"user-agent":ua_default,...extraHeaders}});if(output_manager_default.stopSpinner(),!res.ok){let body=await res.text().catch(()=>"");return outputError(client,json,"DATAFILE_FETCH_FAILED",redactSecret(`Failed to fetch datafile (${res.status} ${res.statusText})${body?`: ${body}`:""}`,token))}let data=await res.json();return json?client.stdout.write(`${JSON.stringify({datafile:data},null,2)}
|
|
376
|
+
`):isPackedDatafile(data)?printDatafileSummary(data,summary):client.stdout.write(`${JSON.stringify(data,null,2)}
|
|
377
|
+
`),0}catch(err){return output_manager_default.stopSpinner(),printUnexpectedError(client,json,err,token)}}function redactSecret(text,secret){return secret?text.split(secret).join("[REDACTED]"):text}function printUnexpectedError(client,json,err,secret=""){let message=err instanceof Error?err.message:String(err),redacted=redactSecret(message,secret);return json?outputError(client,json,"UNEXPECTED_ERROR",redacted):(printError(redacted===message?err:new Error(redacted)),1)}var COMMAND_CONFIG17={ls:getCommandAliases(listSubcommand),stale:getCommandAliases(staleSubcommand),inspect:getCommandAliases(inspectSubcommand),versions:getCommandAliases(versionsSubcommand),evaluations:getCommandAliases(evaluationsSubcommand),create:getCommandAliases(createSubcommand),open:getCommandAliases(openSubcommand),update:getCommandAliases(updateSubcommand),set:getCommandAliases(setSubcommand),targeting:getCommandAliases(targetingSubcommand),"use-targeting":getCommandAliases(useTargetingSubcommand),split:getCommandAliases(splitSubcommand),rollout:getCommandAliases(rolloutSubcommand),delete:getCommandAliases(removeSubcommand),archive:getCommandAliases(archiveSubcommand),unarchive:getCommandAliases(unarchiveSubcommand),disable:getCommandAliases(disableSubcommand),enable:getCommandAliases(enableSubcommand),rules:getCommandAliases(rulesSubcommand2),targets:getCommandAliases(targetsSubcommand),segments:getCommandAliases(segmentsSubcommand),entities:getCommandAliases(entitiesSubcommand),labels:getCommandAliases(labelsSubcommand),"sdk-keys":getCommandAliases(sdkKeysSubcommand),connections:getCommandAliases(connectionsSubcommand),prepare:getCommandAliases(prepareSubcommand),datafile:getCommandAliases(datafileSubcommand),override:getCommandAliases(overrideSubcommand)};async function main10(client){let telemetry=new FlagsTelemetryClient({opts:{store:client.telemetryEventStore}}),flagsSpecification=getFlagsSpecification(flagsCommand.options),parsedArgs;try{parsedArgs=parseArguments(client.argv.slice(2),flagsSpecification,{permissive:!0})}catch(err){return printError(err),2}let subArgs=parsedArgs.args.slice(1),{subcommand,args,subcommandOriginal}=getSubcommand(subArgs,COMMAND_CONFIG17),needHelp=parsedArgs.flags["--help"];if(!subcommand&&needHelp)return telemetry.trackCliFlagHelp("flags",subcommand),output_manager_default.print(help(flagsCommand,{columns:client.stderr.columns})),0;function printHelp(command){output_manager_default.print(help(command,{parent:flagsCommand,columns:client.stderr.columns}))}switch(subcommand){case"ls":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(listSubcommand),0):(telemetry.trackCliSubcommandList(subcommandOriginal),ls(client,args));case"inspect":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(inspectSubcommand),0):(telemetry.trackCliSubcommandInspect(subcommandOriginal),inspect5(client,args));case"versions":return telemetry.trackCliSubcommandVersions(subcommandOriginal),versions(client,needHelp?[...args,"--help"]:args);case"evaluations":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(evaluationsSubcommand),0):(telemetry.trackCliSubcommandEvaluations(subcommandOriginal),evaluations(client,args));case"stale":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(staleSubcommand),0):(telemetry.trackCliSubcommandStale(subcommandOriginal),stale(client,args));case"open":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(openSubcommand),0):(telemetry.trackCliSubcommandOpen(subcommandOriginal),openFlag(client,args));case"create":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(createSubcommand),0):(telemetry.trackCliSubcommandCreate(subcommandOriginal),subcommandOriginal==="add"&&warnDeprecatedSubcommand(client,"flags add","flags create"),create(client,args));case"update":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(updateSubcommand),0):(telemetry.trackCliSubcommandUpdate(subcommandOriginal),update(client,args));case"set":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(setSubcommand),0):(telemetry.trackCliSubcommandSet(subcommandOriginal),set(client,args));case"use-targeting":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(useTargetingSubcommand),0):(telemetry.trackCliSubcommandUseTargeting(subcommandOriginal),warnDeprecatedSubcommand(client,"flags use-targeting","flags targeting enable"),useTargeting(client,args));case"targeting":return telemetry.trackCliSubcommandTargeting(subcommandOriginal),targeting(client,args);case"split":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(splitSubcommand),0):(telemetry.trackCliSubcommandSplit(subcommandOriginal),split(client,args));case"rollout":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(rolloutSubcommand),0):(telemetry.trackCliSubcommandRollout(subcommandOriginal),rollout(client,args));case"delete":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(removeSubcommand),0):(telemetry.trackCliSubcommandDelete(subcommandOriginal),subcommandOriginal==="remove"&&warnDeprecatedSubcommand(client,"flags remove","flags delete"),rm(client,args));case"archive":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(archiveSubcommand),0):(telemetry.trackCliSubcommandArchive(subcommandOriginal),archive(client,args));case"unarchive":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(unarchiveSubcommand),0):(telemetry.trackCliSubcommandUnarchive(subcommandOriginal),unarchive(client,args));case"disable":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(disableSubcommand),0):(telemetry.trackCliSubcommandDisable(subcommandOriginal),disable3(client,args));case"enable":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(enableSubcommand),0):(telemetry.trackCliSubcommandEnable(subcommandOriginal),enable3(client,args));case"rules":return telemetry.trackCliSubcommandRules(subcommandOriginal),rules(client);case"targets":return telemetry.trackCliSubcommandTargets(subcommandOriginal),targets(client);case"sdk-keys":return telemetry.trackCliSubcommandSdkKeys(subcommandOriginal),sdkKeys(client);case"connections":return telemetry.trackCliSubcommandConnections(subcommandOriginal),connections(client);case"segments":return telemetry.trackCliSubcommandSegments(subcommandOriginal),segments(client);case"entities":return telemetry.trackCliSubcommandEntities(subcommandOriginal),entities(client);case"labels":return telemetry.trackCliSubcommandLabels(subcommandOriginal),labels(client);case"prepare":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(prepareSubcommand),0):(telemetry.trackCliSubcommandPrepare(subcommandOriginal),emitDatafiles(client));case"datafile":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(datafileSubcommand),0):(telemetry.trackCliSubcommandDatafile(subcommandOriginal),datafile(client,args));case"override":return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(overrideSubcommand),0):(telemetry.trackCliSubcommandOverride(subcommandOriginal),override(client,args));default:return needHelp?(telemetry.trackCliFlagHelp("flags",subcommandOriginal),printHelp(listSubcommand),0):(telemetry.trackCliSubcommandList(subcommandOriginal),ls(client,args))}}export{feedback,main9 as firewall,main10 as flags};
|