@maycombhq/atticus 2.0.0-beta.10 → 2.0.0-beta.12
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/dist/bin.js +3 -3
- package/dist/{chunk-AY2IUF4K.js → chunk-22GLUHGE.js} +659 -73
- package/dist/{chunk-CIUHAHM6.js → chunk-2A24BNRZ.js} +8 -8
- package/dist/{chunk-2RX7PI2Y.js → chunk-2ELFEKOO.js} +4 -4
- package/dist/{chunk-QKEFZRHS.js → chunk-2P6IHSRO.js} +17 -17
- package/dist/chunk-2Q2YBAR5.js +40 -0
- package/dist/{chunk-7DUDLVFJ.js → chunk-2VQLFNBO.js} +20 -20
- package/dist/{chunk-E3Z67HRK.js → chunk-3256EDLL.js} +4 -4
- package/dist/{chunk-OIU657QQ.js → chunk-34BCKMBS.js} +4 -4
- package/dist/{chunk-UR7RMZ3R.js → chunk-34NWVIBC.js} +2 -2
- package/dist/{chunk-6VBXAGJX.js → chunk-36KD4OGC.js} +14 -14
- package/dist/{chunk-I7IWQIEB.js → chunk-3CFBU2O6.js} +4 -4
- package/dist/{chunk-OSGQW2Z6.js → chunk-3JLTN3Y7.js} +8 -8
- package/dist/{chunk-FOGG4AUR.js → chunk-3M7QBKKG.js} +25 -7
- package/dist/{chunk-UF7TAFJM.js → chunk-3RP34PYV.js} +18 -18
- package/dist/{chunk-YLAJAI2W.js → chunk-3ZKLWM5Y.js} +11 -11
- package/dist/{chunk-LTQANUDH.js → chunk-47HPZ34V.js} +25 -25
- package/dist/chunk-4BPROPGG.js +45 -0
- package/dist/{chunk-Y4BRGOJR.js → chunk-4G56W6H7.js} +13 -10
- package/dist/{chunk-YXJ4XOHF.js → chunk-4HIQ2FTI.js} +4 -4
- package/dist/{chunk-AJJK7GLO.js → chunk-4HTILEXW.js} +3 -3
- package/dist/{chunk-OJLRFGBP.js → chunk-4Q2PGM5T.js} +78 -15
- package/dist/{chunk-GR6YKM55.js → chunk-4RDW2X43.js} +108 -14
- package/dist/{chunk-23M2LUYM.js → chunk-4VOG5H2K.js} +1 -1
- package/dist/chunk-5CSZTVXH.js +34 -0
- package/dist/{chunk-65C57N7P.js → chunk-5FFMJMVH.js} +19 -19
- package/dist/{chunk-XNYNEEBR.js → chunk-5GGGAI5C.js} +18 -18
- package/dist/{chunk-IUD3ME4E.js → chunk-5H46QFSL.js} +4 -4
- package/dist/{chunk-KIHOIVST.js → chunk-5ION6STH.js} +3 -3
- package/dist/chunk-5M3CLAOV.js +39 -0
- package/dist/chunk-5OACMWWI.js +886 -0
- package/dist/{chunk-2HMWX4T6.js → chunk-6ENDKY52.js} +11 -11
- package/dist/{chunk-OS7PQ35Z.js → chunk-6FG7QKJC.js} +22 -22
- package/dist/{chunk-FEZE6NIA.js → chunk-6JV3YHRR.js} +18 -18
- package/dist/{chunk-WGZWR4RF.js → chunk-6ROZRBWH.js} +5 -5
- package/dist/{chunk-WARBF2KY.js → chunk-6S27MUQQ.js} +10 -6
- package/dist/{chunk-TZDSDDSV.js → chunk-72DY5NCN.js} +2 -2
- package/dist/chunk-76QVBNEM.js +37 -0
- package/dist/{chunk-N4QZJJVB.js → chunk-77UOXZVM.js} +5 -5
- package/dist/{chunk-LVGBKKSM.js → chunk-7AXMUE2U.js} +15 -15
- package/dist/{chunk-FJCFYKVO.js → chunk-7TEQF64E.js} +196 -76
- package/dist/{chunk-IDGSU7JF.js → chunk-7TH6I6TL.js} +9 -9
- package/dist/{chunk-ZONE6E3Z.js → chunk-7UKETVPW.js} +2 -2
- package/dist/{chunk-XKS6THI5.js → chunk-7VNEDDCC.js} +2 -2
- package/dist/{chunk-BMHGA7WD.js → chunk-A5GY2EWH.js} +12 -12
- package/dist/{chunk-E3JYO547.js → chunk-AEZ3EICK.js} +20 -20
- package/dist/{chunk-7F2RUWPU.js → chunk-ARLH2ZMD.js} +1 -1
- package/dist/{chunk-VKMTFIWS.js → chunk-AYVLEB55.js} +18 -18
- package/dist/chunk-B6X5PJSA.js +320 -0
- package/dist/{chunk-JMSEEBN4.js → chunk-BRCDEGNE.js} +1 -1
- package/dist/{chunk-67J3VZBA.js → chunk-BSVTNNUK.js} +5 -5
- package/dist/{chunk-3GTZ2OON.js → chunk-BTOGAUWX.js} +20 -11
- package/dist/{chunk-4SVJNVEE.js → chunk-BXBCMGIQ.js} +2 -0
- package/dist/chunk-BXP2Q4TD.js +48 -0
- package/dist/{chunk-XPEEICAO.js → chunk-BZRWJUB4.js} +15 -15
- package/dist/{chunk-MH5OCRUM.js → chunk-CH6LUQLD.js} +2 -2
- package/dist/{chunk-T6USVBEJ.js → chunk-CIIRPLI6.js} +5 -5
- package/dist/chunk-CJXM6SG4.js +339 -0
- package/dist/{chunk-5XDNUJ4P.js → chunk-CQD26SMZ.js} +4 -2
- package/dist/{chunk-7TGYNOXD.js → chunk-CW5SEPUT.js} +7 -7
- package/dist/{chunk-5KTOPOEP.js → chunk-CWSZP2LU.js} +25 -25
- package/dist/chunk-CXK27ZUY.js +32 -0
- package/dist/{chunk-YGKYFMSL.js → chunk-CXY4YDXS.js} +3 -3
- package/dist/{chunk-R64GLVBO.js → chunk-DDZZXVQ5.js} +10 -10
- package/dist/{chunk-7YYEKTYF.js → chunk-DGZXJO5I.js} +8 -8
- package/dist/{chunk-IV7BCWWN.js → chunk-DONCF2XC.js} +3 -3
- package/dist/{chunk-RRVT4MPS.js → chunk-DPNCAFMB.js} +18 -18
- package/dist/{chunk-UBWCUP3G.js → chunk-DQKNOHUZ.js} +2 -2
- package/dist/{chunk-NGPU2ARF.js → chunk-DW4BM73R.js} +1 -1
- package/dist/{chunk-PEF5OEMB.js → chunk-DWN7RSNQ.js} +4 -4
- package/dist/{chunk-KC5DROFC.js → chunk-DWYPYVPJ.js} +14 -14
- package/dist/{chunk-B7434AE2.js → chunk-E73QLYK7.js} +24 -3
- package/dist/{chunk-EX6ZXS5K.js → chunk-EE3UNC44.js} +4 -4
- package/dist/chunk-EJDZEK22.js +53 -0
- package/dist/{chunk-ISNZYKAS.js → chunk-ENZWVTTN.js} +21 -21
- package/dist/{chunk-ROTY5J2L.js → chunk-EREL3TQG.js} +1 -1
- package/dist/{chunk-ZZXF6OOJ.js → chunk-ESGIBN3S.js} +2 -2
- package/dist/{chunk-YGR6OCHQ.js → chunk-EU7VTBAI.js} +8 -14
- package/dist/chunk-F5GA6G3U.js +48 -0
- package/dist/{chunk-JAA53T23.js → chunk-F6FGIYPT.js} +20 -20
- package/dist/{chunk-NPCD54I7.js → chunk-FAET4BB6.js} +8 -5
- package/dist/{chunk-YPBQNJHA.js → chunk-FBFSTYAB.js} +8 -8
- package/dist/{chunk-OEI7LVRP.js → chunk-FEBYMFZA.js} +24 -24
- package/dist/chunk-FMV6IZ3P.js +54 -0
- package/dist/{chunk-F7UQR4ZX.js → chunk-FQ6IBYFC.js} +3 -3
- package/dist/{chunk-J5LHDJU4.js → chunk-FSJMFPA3.js} +7 -7
- package/dist/chunk-GFZ5MIQG.js +47 -0
- package/dist/{chunk-LK44ULGI.js → chunk-GHSVJNVL.js} +104 -11
- package/dist/{chunk-LRS573EX.js → chunk-GKPOCUQR.js} +12 -7
- package/dist/{chunk-LDKUC2QJ.js → chunk-GLSNVC67.js} +17 -17
- package/dist/{chunk-47QE246J.js → chunk-GMDOXWIS.js} +5 -5
- package/dist/{chunk-5MI2SEV5.js → chunk-GN5ZLSLD.js} +3 -3
- package/dist/{chunk-JQ7XQPQS.js → chunk-GUNBOZ75.js} +4 -4
- package/dist/{chunk-HHUFVJF7.js → chunk-GYS64N6F.js} +6 -6
- package/dist/{chunk-AKJTKMXU.js → chunk-HIQWJ6JZ.js} +5 -5
- package/dist/{chunk-6GNS32SI.js → chunk-HJ52XDST.js} +4 -4
- package/dist/{chunk-2KDSXJFJ.js → chunk-HJUEQERG.js} +34 -7
- package/dist/chunk-HKGQUOQ3.js +88 -0
- package/dist/chunk-HP32HUWR.js +41 -0
- package/dist/{chunk-R4TBNKKC.js → chunk-HY2VVVFZ.js} +1249 -610
- package/dist/{chunk-G5SFOH7P.js → chunk-I2PNEG3M.js} +38 -23
- package/dist/{chunk-Y5PZHS4K.js → chunk-INCECZ2E.js} +5 -5
- package/dist/{chunk-RK6MKKKP.js → chunk-ISXNWUG7.js} +1 -1
- package/dist/{chunk-73VPWF5R.js → chunk-ITJ7ST5E.js} +4 -4
- package/dist/{chunk-5IALSMZ2.js → chunk-J3VAFDEX.js} +14 -14
- package/dist/chunk-JGLZUQVN.js +29 -0
- package/dist/{chunk-5XN76FTF.js → chunk-JLIEAQP4.js} +5 -5
- package/dist/{chunk-MGVYVW7Q.js → chunk-JQG4VO47.js} +1 -1
- package/dist/chunk-JXXQHETS.js +130 -0
- package/dist/{chunk-APSVL2AI.js → chunk-KNGESBFW.js} +15 -15
- package/dist/{chunk-7UKVYFQ2.js → chunk-KUYA2E7M.js} +8 -8
- package/dist/{chunk-WLIIQ2A4.js → chunk-KY2ZHTBJ.js} +7 -7
- package/dist/{chunk-YPIEYQF4.js → chunk-L4UIKAWD.js} +6 -6
- package/dist/chunk-LDUJ6NIT.js +247 -0
- package/dist/{chunk-5YIBJXGB.js → chunk-LTLR4JZJ.js} +10 -10
- package/dist/{chunk-IZNSAEBX.js → chunk-MFRPLAOH.js} +2 -2
- package/dist/{chunk-6GWHKMQR.js → chunk-MH7UBG47.js} +4 -4
- package/dist/{chunk-4GZXS6S2.js → chunk-MLAACAES.js} +278 -17
- package/dist/{chunk-D3PO4DOZ.js → chunk-MMB2OHUY.js} +4 -2
- package/dist/{chunk-DDAHCPGA.js → chunk-MNCQ2GL7.js} +12 -12
- package/dist/{chunk-UYYN2IUZ.js → chunk-MNUZX67F.js} +6 -6
- package/dist/{chunk-YFSSNGLR.js → chunk-MQHYCS6A.js} +32 -29
- package/dist/{chunk-MKRBG5EF.js → chunk-MRLCNXXR.js} +1 -1
- package/dist/{chunk-BUYJL3GJ.js → chunk-NBQO75XT.js} +1 -1
- package/dist/{chunk-GXJVY6WT.js → chunk-NCONDPHH.js} +5 -5
- package/dist/{chunk-ZP4FJHR4.js → chunk-NHS55U7T.js} +18 -18
- package/dist/{chunk-CRE4BJHM.js → chunk-NL6XQZSV.js} +23 -23
- package/dist/{chunk-YVLMBAYE.js → chunk-NSJ6ZR2A.js} +3 -3
- package/dist/{chunk-XRO65C7V.js → chunk-NTNJNRHW.js} +8 -6
- package/dist/{chunk-FTV6I76U.js → chunk-NTTXTLCQ.js} +25 -25
- package/dist/chunk-NWL7XEQ4.js +37 -0
- package/dist/{chunk-CNKGYDMG.js → chunk-NWXY3B4R.js} +23 -23
- package/dist/{chunk-52R2YXP5.js → chunk-O5W4ECUY.js} +16 -16
- package/dist/{chunk-OGRWQ562.js → chunk-O6ILVBYB.js} +2 -2
- package/dist/{chunk-BJPMKJTL.js → chunk-OJAJXU65.js} +102 -2
- package/dist/{chunk-FZL2HNWP.js → chunk-OMH3I5BH.js} +3 -3
- package/dist/{chunk-MF7QH4AX.js → chunk-P6UJ22XR.js} +5 -5
- package/dist/{chunk-HE4ZQXZM.js → chunk-P76AW3PA.js} +309 -15
- package/dist/{chunk-GZ4TKR3Q.js → chunk-PCCPXWJC.js} +48 -139
- package/dist/{chunk-6TJCUYC5.js → chunk-PGFRXGHA.js} +3 -3
- package/dist/{chunk-NIXVDQVO.js → chunk-PJRMMWU4.js} +2 -2
- package/dist/{chunk-X4W4XXWP.js → chunk-PKJ3K3GM.js} +5 -5
- package/dist/{chunk-KM2FBM3T.js → chunk-PVW2N63M.js} +302 -55
- package/dist/{chunk-Y7KBQ4BD.js → chunk-Q55UP5EZ.js} +22 -22
- package/dist/{chunk-7URGP4DD.js → chunk-QAFMLBPF.js} +12 -12
- package/dist/{chunk-KIAI6PWL.js → chunk-QEZSA2O7.js} +17 -17
- package/dist/{chunk-PKCMRPPB.js → chunk-QJ3OX7OC.js} +33 -27
- package/dist/{chunk-6EDQE7GO.js → chunk-QL4VNY4U.js} +2 -2
- package/dist/{chunk-6JLPXDWN.js → chunk-QR65C3DV.js} +5 -5
- package/dist/{chunk-ILFKECGI.js → chunk-QXGOEP44.js} +4 -4
- package/dist/chunk-QY7RGTUP.js +326 -0
- package/dist/{chunk-PGKHJYOB.js → chunk-RA64IK43.js} +1 -1
- package/dist/{chunk-XB5RFZHH.js → chunk-RLJDYLID.js} +12 -12
- package/dist/{chunk-AWECWW5Y.js → chunk-RMLUZYEA.js} +13 -11
- package/dist/chunk-RSVBX6A3.js +54 -0
- package/dist/chunk-RZWZO2JQ.js +42 -0
- package/dist/chunk-S5LSDXV4.js +40 -0
- package/dist/{chunk-TM7LC37P.js → chunk-SAC6FNKR.js} +181 -117
- package/dist/{chunk-DPHCFZ7W.js → chunk-SCBU46AJ.js} +3 -3
- package/dist/{chunk-EZIUFEN6.js → chunk-SGNHNN3G.js} +12 -12
- package/dist/{chunk-XKZHAD6Y.js → chunk-SHAAGH3T.js} +15 -15
- package/dist/chunk-SK5OYWIY.js +122 -0
- package/dist/{chunk-FR7JPYBD.js → chunk-SNSFQ47W.js} +12 -12
- package/dist/{chunk-FV5YFR6I.js → chunk-SSL6JMPA.js} +9 -9
- package/dist/{chunk-XEG3FE2R.js → chunk-TA2ZNDYD.js} +1 -1
- package/dist/{chunk-JF2NSTFO.js → chunk-TEHH47TG.js} +3 -3
- package/dist/{chunk-W5OYJMBT.js → chunk-TEZSZ24W.js} +5 -5
- package/dist/{chunk-SS66Q4VE.js → chunk-TH526O6E.js} +12 -12
- package/dist/{chunk-R6B6XAKK.js → chunk-TIAPEYWI.js} +4 -4
- package/dist/chunk-TLCRIAU3.js +44 -0
- package/dist/{chunk-FMKKVWZD.js → chunk-TQYBXDVH.js} +2 -2
- package/dist/chunk-TV4CGNEY.js +43 -0
- package/dist/{chunk-QICFHVRW.js → chunk-TVSNWIAM.js} +8 -6
- package/dist/{chunk-CHC5FKTU.js → chunk-TWHZU36X.js} +1 -1
- package/dist/{chunk-BMCKL3VQ.js → chunk-TXV2AYZB.js} +24 -24
- package/dist/{chunk-577AJVRS.js → chunk-U25OX22K.js} +2039 -289
- package/dist/{chunk-7EKESFWV.js → chunk-U4NNG3ES.js} +11 -11
- package/dist/{chunk-XQ3YIV5R.js → chunk-U5T4A2QV.js} +6 -6
- package/dist/{chunk-2XM6PYQQ.js → chunk-UT5OA7KA.js} +43 -11
- package/dist/{chunk-BXIX7S7O.js → chunk-V3VCUSQ6.js} +15 -15
- package/dist/{chunk-4QUQEBFT.js → chunk-V5XV3JSP.js} +6 -6
- package/dist/{chunk-F7YL2RZ4.js → chunk-VF4VOPMB.js} +23 -23
- package/dist/{chunk-3QAKDIEU.js → chunk-VLDM4QZM.js} +23 -23
- package/dist/chunk-VP5H6DII.js +34 -0
- package/dist/{chunk-N3NBWIYQ.js → chunk-VRYQJZFL.js} +10 -9
- package/dist/{chunk-FQSRHTTC.js → chunk-VS6FS472.js} +15 -15
- package/dist/{chunk-YMOJD5BO.js → chunk-VTMIRRIZ.js} +3 -3
- package/dist/{chunk-4PJADZRR.js → chunk-VXSJKWB7.js} +16 -16
- package/dist/{chunk-MTAUZW2Z.js → chunk-WE5VMPUP.js} +216 -106
- package/dist/{chunk-ZE3P35DA.js → chunk-WEG7DY5K.js} +9 -9
- package/dist/{chunk-V2TH46ZY.js → chunk-WIF7A6JU.js} +12 -12
- package/dist/{chunk-GFXLPJWY.js → chunk-WM4N2L4T.js} +2 -2
- package/dist/{chunk-XIWYUQZQ.js → chunk-X64BFQ3R.js} +9 -9
- package/dist/{chunk-QWVBEK4P.js → chunk-XJRC3ZDI.js} +13 -13
- package/dist/{chunk-F2FOQLJ7.js → chunk-XVIVWG7B.js} +6 -6
- package/dist/{chunk-XTVDAHH2.js → chunk-Y3ZKT6IF.js} +5 -5
- package/dist/{chunk-62YMDXY6.js → chunk-YURIUFKF.js} +16 -16
- package/dist/{chunk-HKTUIMH4.js → chunk-YY2WGL6S.js} +3 -3
- package/dist/{chunk-BDEKREZH.js → chunk-Z2BA4NNR.js} +3 -3
- package/dist/{chunk-MTEBM4Y4.js → chunk-Z47YGBUY.js} +19 -12
- package/dist/chunk-Z4JSRKNR.js +41 -0
- package/dist/{chunk-G2E5MNYP.js → chunk-Z53ZB34U.js} +7 -7
- package/dist/{chunk-NNUASOAA.js → chunk-ZBOPIYOY.js} +12 -12
- package/dist/{chunk-7GB4ZRE2.js → chunk-ZBQCLKTH.js} +12 -12
- package/dist/chunk-ZGI7DNJ6.js +38 -0
- package/dist/{chunk-P3TKKBAH.js → chunk-ZPT4QX3J.js} +4 -4
- package/dist/chunk-ZS47PQ3O.js +41 -0
- package/dist/{chunk-PIVKU64W.js → chunk-ZTIMXVV5.js} +2 -2
- package/dist/{chunk-T4RTWMJD.js → chunk-ZYASEL7K.js} +5 -5
- package/dist/files.json +469 -417
- package/dist/packages/sdk/npm/index.js +2309 -1983
- package/dist/packages/ui/dist/assets/{elk-api-Mo5w5xCa.js → elk-api-D2NcYpUJ.js} +2 -2
- package/dist/packages/ui/dist/assets/{index-Bp3XhPHX.css → index-C0JEkXyN.css} +1 -1
- package/dist/packages/ui/dist/assets/index-CT7skl01.js +29 -0
- package/dist/packages/ui/dist/index.html +2 -2
- package/package.json +4 -4
- package/dist/chunk-26PLPSQW.js +0 -48
- package/dist/chunk-2G4DFUWJ.js +0 -43
- package/dist/chunk-2M6WXO73.js +0 -38
- package/dist/chunk-5F3RJCHB.js +0 -45
- package/dist/chunk-B2VSVN4P.js +0 -34
- package/dist/chunk-B3O52AUQ.js +0 -275
- package/dist/chunk-CITDNDIZ.js +0 -53
- package/dist/chunk-DAQBIK5G.js +0 -47
- package/dist/chunk-DZRQDNPT.js +0 -34
- package/dist/chunk-FLOEZA6K.js +0 -29
- package/dist/chunk-FNHSVBRA.js +0 -48
- package/dist/chunk-FPGVOSOG.js +0 -41
- package/dist/chunk-FZ2E5LGK.js +0 -54
- package/dist/chunk-HB6XSGI6.js +0 -131
- package/dist/chunk-HUZQDKQK.js +0 -48
- package/dist/chunk-L4VJ4ETL.js +0 -41
- package/dist/chunk-XPCWQXTY.js +0 -37
- package/dist/chunk-YIEOFHOL.js +0 -30
- package/dist/packages/ui/dist/assets/index-DM212ZbV.js +0 -29
|
@@ -12,18 +12,18 @@ import {
|
|
|
12
12
|
readDrawio,
|
|
13
13
|
readMermaid,
|
|
14
14
|
resolveNames
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-PJRMMWU4.js";
|
|
16
16
|
import {
|
|
17
17
|
openapiExtractor,
|
|
18
18
|
readOpenApiDocument
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-34NWVIBC.js";
|
|
20
20
|
import {
|
|
21
21
|
combine,
|
|
22
22
|
formatOf,
|
|
23
23
|
screenDiagramXml,
|
|
24
24
|
screenOfficeXml,
|
|
25
25
|
screenText
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-CQD26SMZ.js";
|
|
27
27
|
import {
|
|
28
28
|
TrafficFile,
|
|
29
29
|
endpointId,
|
|
@@ -42,10 +42,10 @@ import {
|
|
|
42
42
|
routeScore,
|
|
43
43
|
toCanonicalYaml,
|
|
44
44
|
trafficFileText
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-U25OX22K.js";
|
|
46
46
|
import {
|
|
47
47
|
writeFileAtomic
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-MMB2OHUY.js";
|
|
49
49
|
import {
|
|
50
50
|
__toESM
|
|
51
51
|
} from "./chunk-TV45EUGM.js";
|
|
@@ -127,6 +127,151 @@ function fromData(data) {
|
|
|
127
127
|
}
|
|
128
128
|
return void 0;
|
|
129
129
|
}
|
|
130
|
+
var STRICT_ALIASES = 100;
|
|
131
|
+
var LENIENT_ALIASES = 1e4;
|
|
132
|
+
var LENIENT = { uniqueKeys: false, maxAliasCount: LENIENT_ALIASES };
|
|
133
|
+
var reasonOf = (e) => e.message.split("\n")[0].replace(/\s+at line \d+, column \d+:?\s*$/, "").trim();
|
|
134
|
+
var unreadableOf = (e) => ({
|
|
135
|
+
reason: reasonOf(e),
|
|
136
|
+
...e.linePos?.[0] ? { line: e.linePos[0].line, column: e.linePos[0].col } : {}
|
|
137
|
+
});
|
|
138
|
+
function duplicateKeys(text3) {
|
|
139
|
+
const lines = text3.split(/\r?\n/);
|
|
140
|
+
return (0, import_yaml.parseDocument)(text3).errors.filter((e) => e.code === "DUPLICATE_KEY" && e.linePos?.[0]).map((e) => {
|
|
141
|
+
const { line, col } = e.linePos[0];
|
|
142
|
+
const key3 = /^\s*["']?([^"':]+)["']?\s*:/.exec((lines[line - 1] ?? "").slice(col - 1))?.[1];
|
|
143
|
+
return `duplicate key ${key3 ? `"${key3.trim()}" ` : ""}at ${line}:${col}: the last one is kept`;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function braceBalance(line) {
|
|
147
|
+
let n = 0;
|
|
148
|
+
let quote;
|
|
149
|
+
for (let i = 0; i < line.length; i++) {
|
|
150
|
+
const c = line[i];
|
|
151
|
+
if (quote) {
|
|
152
|
+
if (c === "\\" && quote === '"')
|
|
153
|
+
i++;
|
|
154
|
+
else if (c === quote)
|
|
155
|
+
quote = void 0;
|
|
156
|
+
} else if (c === '"' || c === "'")
|
|
157
|
+
quote = c;
|
|
158
|
+
else if (c === "#" && (i === 0 || /\s/.test(line[i - 1])))
|
|
159
|
+
return NaN;
|
|
160
|
+
else if (c === "{")
|
|
161
|
+
n++;
|
|
162
|
+
else if (c === "}")
|
|
163
|
+
n--;
|
|
164
|
+
}
|
|
165
|
+
return quote ? NaN : n;
|
|
166
|
+
}
|
|
167
|
+
var indentOf = (l) => /^\s*/.exec(l)[0].length;
|
|
168
|
+
var blank = (l) => !l.trim() || /^\s*#/.test(l);
|
|
169
|
+
function joinServerVariables(text3) {
|
|
170
|
+
const lines = text3.split(/\r?\n/);
|
|
171
|
+
const at = [];
|
|
172
|
+
let servers;
|
|
173
|
+
let vars;
|
|
174
|
+
for (let i = 0; i < lines.length; i++) {
|
|
175
|
+
const l = lines[i];
|
|
176
|
+
if (blank(l))
|
|
177
|
+
continue;
|
|
178
|
+
const ind = indentOf(l);
|
|
179
|
+
if (vars !== void 0 && ind <= vars)
|
|
180
|
+
vars = void 0;
|
|
181
|
+
if (servers !== void 0 && ind <= servers && !/^\s*-(\s|$)/.test(l))
|
|
182
|
+
servers = void 0;
|
|
183
|
+
if (servers !== void 0 && ind < servers)
|
|
184
|
+
servers = void 0;
|
|
185
|
+
if (/^\s*["']?servers["']?\s*:\s*$/.test(l)) {
|
|
186
|
+
servers = ind;
|
|
187
|
+
vars = void 0;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (servers === void 0)
|
|
191
|
+
continue;
|
|
192
|
+
const v = /^(\s*)(-\s+)?["']?variables["']?\s*:\s*$/.exec(l);
|
|
193
|
+
if (v) {
|
|
194
|
+
vars = v[1].length + (v[2]?.length ?? 0);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (vars === void 0)
|
|
198
|
+
continue;
|
|
199
|
+
const m = /^(\s*)(["']?[\w.-]+["']?)\s*:\s*(\{.*)$/.exec(l);
|
|
200
|
+
if (!m)
|
|
201
|
+
continue;
|
|
202
|
+
let balance = braceBalance(m[3]);
|
|
203
|
+
if (Number.isNaN(balance))
|
|
204
|
+
return void 0;
|
|
205
|
+
const parts = [m[3].trim()];
|
|
206
|
+
let j = i;
|
|
207
|
+
while (balance > 0) {
|
|
208
|
+
j++;
|
|
209
|
+
if (j >= lines.length || j - i > 200)
|
|
210
|
+
return void 0;
|
|
211
|
+
const b = braceBalance(lines[j]);
|
|
212
|
+
if (Number.isNaN(b))
|
|
213
|
+
return void 0;
|
|
214
|
+
balance += b;
|
|
215
|
+
parts.push(lines[j].trim());
|
|
216
|
+
}
|
|
217
|
+
if (balance < 0)
|
|
218
|
+
return void 0;
|
|
219
|
+
const joined = `${m[1]}${m[2]}: ${parts.filter(Boolean).join(" ")}`;
|
|
220
|
+
if (joined === l && j === i)
|
|
221
|
+
continue;
|
|
222
|
+
lines[i] = joined;
|
|
223
|
+
for (let k = i + 1; k <= j; k++)
|
|
224
|
+
lines[k] = "";
|
|
225
|
+
at.push(i + 1);
|
|
226
|
+
i = j;
|
|
227
|
+
}
|
|
228
|
+
return at.length ? { text: lines.join("\n"), at } : void 0;
|
|
229
|
+
}
|
|
230
|
+
var SPEC_KINDS = ["openapi", "swagger", "asyncapi"];
|
|
231
|
+
function readYaml(text3) {
|
|
232
|
+
let first;
|
|
233
|
+
try {
|
|
234
|
+
return { data: (0, import_yaml.parse)(text3) };
|
|
235
|
+
} catch (e) {
|
|
236
|
+
first = e;
|
|
237
|
+
}
|
|
238
|
+
const notes = [];
|
|
239
|
+
const dup = first.code === "DUPLICATE_KEY";
|
|
240
|
+
const aliases = /alias count/i.test(first.message);
|
|
241
|
+
const lenient = (t) => {
|
|
242
|
+
try {
|
|
243
|
+
return { data: (0, import_yaml.parse)(t, LENIENT) };
|
|
244
|
+
} catch (e) {
|
|
245
|
+
return { error: e };
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
const notesOf = (t) => {
|
|
249
|
+
const out = duplicateKeys(t);
|
|
250
|
+
try {
|
|
251
|
+
(0, import_yaml.parse)(t, { uniqueKeys: false });
|
|
252
|
+
} catch (e) {
|
|
253
|
+
if (/alias count/i.test(e.message))
|
|
254
|
+
out.push(`more aliases than the strict parser allows (${STRICT_ALIASES}): read with a higher limit (${LENIENT_ALIASES})`);
|
|
255
|
+
}
|
|
256
|
+
return out;
|
|
257
|
+
};
|
|
258
|
+
if (dup || aliases) {
|
|
259
|
+
const r = lenient(text3);
|
|
260
|
+
if ("data" in r)
|
|
261
|
+
return { data: r.data, notes: notesOf(text3) };
|
|
262
|
+
}
|
|
263
|
+
const fixed = joinServerVariables(text3);
|
|
264
|
+
if (fixed) {
|
|
265
|
+
const r = lenient(fixed.text);
|
|
266
|
+
if ("data" in r && SPEC_KINDS.includes(fromData(r.data)?.classification ?? "unknown")) {
|
|
267
|
+
notes.push(...notesOf(fixed.text));
|
|
268
|
+
const lines = fixed.at.length === 1 ? `line ${fixed.at[0]} is a flow mapping` : `lines ${fixed.at.slice(0, -1).join(", ")} and ${fixed.at.at(-1)} are flow mappings`;
|
|
269
|
+
notes.push(`servers[].variables at ${lines} written over several lines, not indented past ${fixed.at.length === 1 ? "its key: read as if it were" : "their key: read as if each were"} on one line`);
|
|
270
|
+
return { data: r.data, notes, text: fixed.text };
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return { error: first };
|
|
274
|
+
}
|
|
130
275
|
function classify(fileName, bytes) {
|
|
131
276
|
const name = fileName.toLowerCase();
|
|
132
277
|
const ext = name.includes(".") ? name.slice(name.lastIndexOf(".") + 1) : "";
|
|
@@ -168,19 +313,26 @@ function classify(fileName, bytes) {
|
|
|
168
313
|
return { classification: "diagram" };
|
|
169
314
|
if (/^<(!doctype html|html)\b/i.test(head))
|
|
170
315
|
return { classification: "document" };
|
|
316
|
+
if (ext === "proto" || /^(syntax\s*=\s*["']proto[23]["']|package\s+[\w.]+\s*;)/m.test(head))
|
|
317
|
+
return { classification: "protobuf" };
|
|
318
|
+
if (ext === "avsc" || /^\{/.test(head) && /"type"\s*:\s*"record"/.test(head) && /"fields"\s*:/.test(head))
|
|
319
|
+
return { classification: "avro" };
|
|
171
320
|
if (["json", "yaml", "yml"].includes(ext) || /^[[{]/.test(head)) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
321
|
+
const r = readYaml(text3);
|
|
322
|
+
const named = ["json", "yaml", "yml"].includes(ext);
|
|
323
|
+
if ("error" in r && named)
|
|
324
|
+
return { classification: "unknown", unreadable: unreadableOf(r.error) };
|
|
325
|
+
const data = "data" in r ? r.data : void 0;
|
|
326
|
+
const lenient = {
|
|
327
|
+
..."notes" in r && r.notes?.length ? { notes: r.notes } : {},
|
|
328
|
+
..."text" in r && r.text !== void 0 ? { text: r.text } : {}
|
|
329
|
+
};
|
|
178
330
|
const known = fromData(data);
|
|
179
331
|
if (known)
|
|
180
|
-
return known;
|
|
332
|
+
return { ...known, ...lenient };
|
|
181
333
|
if (ext === "json" || /^[[{]/.test(head)) {
|
|
182
334
|
if (isObj(data) || Array.isArray(data))
|
|
183
|
-
return { classification: "payload", data };
|
|
335
|
+
return { classification: "payload", data, ...lenient };
|
|
184
336
|
}
|
|
185
337
|
if (ext === "yaml" || ext === "yml")
|
|
186
338
|
return { classification: "unknown" };
|
|
@@ -200,7 +352,10 @@ import { createHash } from "node:crypto";
|
|
|
200
352
|
var READERS = {
|
|
201
353
|
openapi: `${openapiExtractor.id}@${openapiExtractor.version}`,
|
|
202
354
|
asyncapi: "asyncapi@0.1.0",
|
|
203
|
-
payload: "payload@0.1.0"
|
|
355
|
+
payload: "payload@0.1.0",
|
|
356
|
+
// ADR 0164: a topic's message spec.
|
|
357
|
+
protobuf: "protobuf@0.1.0",
|
|
358
|
+
avro: "avro@0.1.0"
|
|
204
359
|
};
|
|
205
360
|
var short = (s) => createHash("sha256").update(s).digest("hex").slice(0, 6);
|
|
206
361
|
function oneFile(path, text3) {
|
|
@@ -416,9 +571,9 @@ var opt = {
|
|
|
416
571
|
};
|
|
417
572
|
|
|
418
573
|
// packages/intake/dist/scan-inputs.js
|
|
419
|
-
import { createHash as
|
|
420
|
-
import { readdir, readFile, stat } from "node:fs/promises";
|
|
421
|
-
import { join, relative, resolve, sep } from "node:path";
|
|
574
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
575
|
+
import { readdir as readdir2, readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
576
|
+
import { join as join2, relative, resolve, sep } from "node:path";
|
|
422
577
|
|
|
423
578
|
// packages/intake/dist/screen-file.js
|
|
424
579
|
var PK = (b) => b[0] === 80 && b[1] === 75;
|
|
@@ -460,131 +615,435 @@ function screenFile(path, bytes) {
|
|
|
460
615
|
}
|
|
461
616
|
}
|
|
462
617
|
|
|
463
|
-
// packages/intake/dist/
|
|
464
|
-
var
|
|
618
|
+
// packages/intake/dist/contract-specs.js
|
|
619
|
+
var import_yaml4 = __toESM(require_dist(), 1);
|
|
620
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
621
|
+
import { join } from "node:path";
|
|
622
|
+
|
|
623
|
+
// packages/intake/dist/traffic.js
|
|
465
624
|
import { createHash as createHash3 } from "node:crypto";
|
|
466
|
-
var
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
625
|
+
var cmp = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
626
|
+
var key = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
627
|
+
var sha = (s) => createHash3("sha256").update(s, "utf8").digest("hex");
|
|
628
|
+
var IPV4 = /\b\d{1,3}(?:\.\d{1,3}){3}\b/;
|
|
629
|
+
var IPV6 = /[0-9a-f]{0,4}::[0-9a-f]{0,4}|\b[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){2,7}\b/i;
|
|
630
|
+
var EMAIL = /[^\s@/]+@[^\s@/]+/;
|
|
631
|
+
var JWT = /\beyJ[A-Za-z0-9_-]{6,}/;
|
|
632
|
+
var OPAQUE = /\b(?=[A-Za-z0-9+_-]*\d)(?=[A-Za-z0-9+_-]*[A-Za-z])[A-Za-z0-9+_-]{24,}={0,2}/;
|
|
633
|
+
var UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
|
|
634
|
+
var HEX = /\b[0-9a-f]{16,}\b/i;
|
|
635
|
+
function looksSensitive(v) {
|
|
636
|
+
return [IPV4, IPV6, EMAIL, JWT, OPAQUE, UUID, HEX].some((re) => re.test(v));
|
|
473
637
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
if (!read)
|
|
638
|
+
function rowsOf(text3) {
|
|
639
|
+
const t = text3.replace(/^\uFEFF/, "").trim();
|
|
640
|
+
if (!t)
|
|
478
641
|
return void 0;
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const m = /^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)([^?#]*)/i.exec(url);
|
|
486
|
-
const host = m?.[1]?.replace(/^[^@]*@/, "").replace(/:\d+$/, "").toLowerCase();
|
|
487
|
-
if (host && !host.includes("{") && !hosts.includes(host))
|
|
488
|
-
hosts.push(host);
|
|
489
|
-
if (i === 0) {
|
|
490
|
-
const p = m ? m[2] : url.startsWith("/") ? url.split(/[?#]/)[0] : "";
|
|
491
|
-
serverPath = p.replace(/\/+$/, "");
|
|
642
|
+
if (t.startsWith("[") || t.startsWith("{")) {
|
|
643
|
+
let v;
|
|
644
|
+
try {
|
|
645
|
+
v = JSON.parse(t);
|
|
646
|
+
} catch {
|
|
647
|
+
return void 0;
|
|
492
648
|
}
|
|
649
|
+
const list2 = Array.isArray(v) ? v : v && typeof v === "object" ? ["rows", "data", "records", "items"].map((k) => v[k]).find((x) => Array.isArray(x)) : void 0;
|
|
650
|
+
if (!Array.isArray(list2) || !list2.length)
|
|
651
|
+
return void 0;
|
|
652
|
+
const out = [];
|
|
653
|
+
for (const r of list2) {
|
|
654
|
+
if (!r || typeof r !== "object" || Array.isArray(r))
|
|
655
|
+
return void 0;
|
|
656
|
+
const row = {};
|
|
657
|
+
for (const [k, x] of Object.entries(r))
|
|
658
|
+
if (typeof x === "string" || typeof x === "number")
|
|
659
|
+
row[k] = String(x);
|
|
660
|
+
out.push(row);
|
|
661
|
+
}
|
|
662
|
+
return out;
|
|
663
|
+
}
|
|
664
|
+
const recs = parseCsv(t);
|
|
665
|
+
if (recs.length < 2)
|
|
666
|
+
return void 0;
|
|
667
|
+
const head = recs[0].cells.map((c) => c.trim());
|
|
668
|
+
if (head.length < 2)
|
|
669
|
+
return void 0;
|
|
670
|
+
return recs.slice(1).map((r) => {
|
|
671
|
+
const row = {};
|
|
672
|
+
head.forEach((h, i) => row[h] = (r.cells[i] ?? "").trim());
|
|
673
|
+
return row;
|
|
493
674
|
});
|
|
494
|
-
if (swagger2)
|
|
495
|
-
serverPath = "";
|
|
496
|
-
const info = doc.get("info");
|
|
497
|
-
const title = (0, import_yaml3.isMap)(info) ? info.get("title") : void 0;
|
|
498
|
-
const version = (0, import_yaml3.isMap)(info) ? info.get("version") : void 0;
|
|
499
|
-
const ctx = { doc, lc, path, at };
|
|
500
|
-
const ops = read.operations.map((op) => {
|
|
501
|
-
const method = op.method.toUpperCase();
|
|
502
|
-
const fullPath = `${serverPath}${op.path}` || op.path;
|
|
503
|
-
const node = (0, import_yaml3.isMap)(op.node) ? op.node : void 0;
|
|
504
|
-
const opId = node?.get("operationId");
|
|
505
|
-
return {
|
|
506
|
-
method,
|
|
507
|
-
path: op.path,
|
|
508
|
-
fullPath,
|
|
509
|
-
normalizedPath: normalizePath(op.path),
|
|
510
|
-
...typeof opId === "string" && opId ? { operationId: opId } : {},
|
|
511
|
-
...op.auth ? { auth: op.auth } : {},
|
|
512
|
-
scopes: op.scopes,
|
|
513
|
-
cite: `${path}:${op.methodLine ?? op.line ?? 1}`,
|
|
514
|
-
request: requestFields(ctx, op, swagger2),
|
|
515
|
-
response: responseFields(ctx, op, swagger2),
|
|
516
|
-
...errorsOf(ctx, op, swagger2)
|
|
517
|
-
};
|
|
518
|
-
});
|
|
519
|
-
const ids = specEndpointIds(system, ops);
|
|
520
|
-
return {
|
|
521
|
-
path,
|
|
522
|
-
system,
|
|
523
|
-
...typeof title === "string" && title ? { title } : {},
|
|
524
|
-
...version !== void 0 && version !== null && String(version) ? { version: String(version) } : {},
|
|
525
|
-
hosts,
|
|
526
|
-
serverPath,
|
|
527
|
-
basePath: swagger2 ? String(doc.get("basePath") ?? "") : "",
|
|
528
|
-
operations: ops.map((o, i) => ({ id: ids[i], ...o }))
|
|
529
|
-
};
|
|
530
675
|
}
|
|
531
|
-
function
|
|
532
|
-
const
|
|
533
|
-
if (
|
|
534
|
-
return
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
return [];
|
|
539
|
-
const cite = ctx.at((0, import_yaml3.isScalar)(p.key) ? p.key.range?.[0] : void 0);
|
|
540
|
-
if (!cite)
|
|
541
|
-
return [];
|
|
542
|
-
const fields = [];
|
|
543
|
-
schemaFields(ctx, bodySchema(ctx, p.value, swagger2), "body", "", 0, /* @__PURE__ */ new Set(), fields);
|
|
544
|
-
return [{ status, cite, ...fields.length ? { fields } : {} }];
|
|
545
|
-
});
|
|
546
|
-
return errors.length ? { errors } : {};
|
|
676
|
+
function dayOf(v) {
|
|
677
|
+
const m = /^(\d{4}-\d{2}-\d{2})/.exec(v.trim());
|
|
678
|
+
if (m)
|
|
679
|
+
return m[1];
|
|
680
|
+
if (/^\d{12,13}$/.test(v.trim()))
|
|
681
|
+
return new Date(Number(v)).toISOString().slice(0, 10);
|
|
682
|
+
return void 0;
|
|
547
683
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
684
|
+
var VERSION = /^v\d+(?:\.\d+)*$/i;
|
|
685
|
+
var PARAM = /^(?:\{[A-Za-z_][A-Za-z0-9_.-]{0,40}\}|:[A-Za-z_][A-Za-z0-9_]{0,40}|<[A-Za-z_][A-Za-z0-9_:]{0,40}>)$/;
|
|
686
|
+
var segmentOf = (s) => VERSION.test(s) || PARAM.test(s) || /^[a-z][a-z._-]*$/.test(s) && s.length <= 20 && /[aeiou]/.test(s) && !looksSensitive(s) ? s : "{id}";
|
|
687
|
+
function barePath(path) {
|
|
688
|
+
let p = path.trim().split(/[?#]/, 1)[0] ?? "";
|
|
689
|
+
p = p.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]*/i, "");
|
|
690
|
+
return p.replace(/;[^/]*/g, "");
|
|
553
691
|
}
|
|
554
|
-
function
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
692
|
+
function safePathOf(path) {
|
|
693
|
+
const p = barePath(path);
|
|
694
|
+
if (!p.startsWith("/"))
|
|
695
|
+
return void 0;
|
|
696
|
+
return `/${p.split("/").filter(Boolean).map(segmentOf).join("/")}`;
|
|
697
|
+
}
|
|
698
|
+
var MATCH = 100;
|
|
699
|
+
function pathTemplateOf(path, templates) {
|
|
700
|
+
const p = barePath(path);
|
|
701
|
+
if (!p.startsWith("/"))
|
|
702
|
+
return void 0;
|
|
703
|
+
const sorted2 = [...templates].sort();
|
|
704
|
+
let best;
|
|
705
|
+
let score = 0;
|
|
706
|
+
for (const t of sorted2) {
|
|
707
|
+
const s = routeScore(p, t);
|
|
708
|
+
if (s > MATCH && s > score) {
|
|
709
|
+
score = s;
|
|
710
|
+
best = t;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (best)
|
|
714
|
+
return best;
|
|
715
|
+
const segs = p.split("/").filter(Boolean);
|
|
716
|
+
let prefix;
|
|
717
|
+
let len = 0;
|
|
718
|
+
score = 0;
|
|
719
|
+
for (const t of sorted2) {
|
|
720
|
+
const n = t.split("/").filter(Boolean).length;
|
|
721
|
+
if (n === 0 || n >= segs.length || n < len)
|
|
562
722
|
continue;
|
|
563
|
-
const
|
|
564
|
-
if (
|
|
723
|
+
const s = routeScore(`/${segs.slice(0, n).join("/")}`, t);
|
|
724
|
+
if (s <= MATCH)
|
|
565
725
|
continue;
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
name: String(pair.key.value),
|
|
572
|
-
in: "header",
|
|
573
|
-
...type ? { type } : {},
|
|
574
|
-
...swagger2 ? {} : { required: h.get("required") === true },
|
|
575
|
-
...values ? { enum: values } : {},
|
|
576
|
-
cite: ctx.at(pair.key.range?.[0]) ?? `${ctx.path}:1`
|
|
577
|
-
});
|
|
726
|
+
if (n > len || s > score) {
|
|
727
|
+
len = n;
|
|
728
|
+
score = s;
|
|
729
|
+
prefix = t;
|
|
730
|
+
}
|
|
578
731
|
}
|
|
579
|
-
return
|
|
732
|
+
return prefix ? `${prefix.replace(/\/+$/, "")}/**` : void 0;
|
|
580
733
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
734
|
+
var appLabelOf = (name) => `app-${sha(name).slice(0, 8)}`;
|
|
735
|
+
function denyListHits(text3, hashes) {
|
|
736
|
+
const hits = [];
|
|
737
|
+
text3.toLowerCase().split("\n").forEach((line, i) => {
|
|
738
|
+
const w = line.match(/[a-z0-9]+/g) ?? [];
|
|
739
|
+
for (let k = 0; k < w.length; k++)
|
|
740
|
+
if (hashes.has(sha(w[k])) || k + 1 < w.length && hashes.has(sha(`${w[k]} ${w[k + 1]}`))) {
|
|
741
|
+
hits.push(i + 1);
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
return hits;
|
|
746
|
+
}
|
|
747
|
+
function aggregateTraffic(input) {
|
|
748
|
+
const text3 = Buffer.from(input.bytes).toString("utf8");
|
|
749
|
+
const rows = rowsOf(text3);
|
|
750
|
+
const shape = `a CSV with a header row, or a JSON list of rows, with an app, a method and a path column (${input.source}: app ${input.columns.app.join("/")}; method ${input.columns.method.join("/")}; path ${[...input.columns.path, ...input.columns.basepath].join("/")})`;
|
|
751
|
+
if (!rows)
|
|
752
|
+
return { ok: false, message: `The file doesn't read as a traffic export: give ${shape}.` };
|
|
753
|
+
const names = [...new Set(rows.flatMap((r) => Object.keys(r)))];
|
|
754
|
+
const col = (aliases) => {
|
|
755
|
+
for (const a of aliases) {
|
|
756
|
+
const hit = names.find((n) => key(n) === key(a));
|
|
757
|
+
if (hit)
|
|
758
|
+
return hit;
|
|
759
|
+
}
|
|
760
|
+
return void 0;
|
|
761
|
+
};
|
|
762
|
+
const c = {
|
|
763
|
+
app: col(input.columns.app),
|
|
764
|
+
method: col(input.columns.method),
|
|
765
|
+
basepath: col(input.columns.basepath),
|
|
766
|
+
suffix: col(input.columns.suffix),
|
|
767
|
+
proxy: col(input.columns.proxy),
|
|
768
|
+
count: col(input.columns.count),
|
|
769
|
+
time: col(input.columns.time),
|
|
770
|
+
path: void 0
|
|
771
|
+
};
|
|
772
|
+
if (!c.basepath || !c.suffix)
|
|
773
|
+
c.path = col(input.columns.path);
|
|
774
|
+
const missing = [
|
|
775
|
+
!c.app ? "app" : "",
|
|
776
|
+
!c.method ? "method" : "",
|
|
777
|
+
!c.path && !(c.basepath && c.suffix) ? "path" : ""
|
|
778
|
+
].filter(Boolean);
|
|
779
|
+
if (missing.length)
|
|
780
|
+
return {
|
|
781
|
+
ok: false,
|
|
782
|
+
message: `The file has no ${missing.join(", ")} column, so it can't be kept as aggregates: give ${shape}.`
|
|
783
|
+
};
|
|
784
|
+
const range = (v) => v && /^\d{4}-\d{2}-\d{2}$/.test(v) ? v : void 0;
|
|
785
|
+
if (input.from && !range(input.from) || input.to && !range(input.to))
|
|
786
|
+
return { ok: false, message: "--from and --to are days: YYYY-MM-DD." };
|
|
787
|
+
if ((!input.from || !input.to) && !c.time)
|
|
788
|
+
return {
|
|
789
|
+
ok: false,
|
|
790
|
+
message: "The export has no date column: give --from and --to (YYYY-MM-DD) for the range it covers."
|
|
791
|
+
};
|
|
792
|
+
const kept = new Set(Object.values(c).filter((x) => !!x));
|
|
793
|
+
const dropped = names.filter((n) => !kept.has(n)).sort();
|
|
794
|
+
const secrets = /* @__PURE__ */ new Set();
|
|
795
|
+
const keptValues = /* @__PURE__ */ new Set();
|
|
796
|
+
const agg = /* @__PURE__ */ new Map();
|
|
797
|
+
let outOfRange = 0;
|
|
798
|
+
let skipped2 = 0;
|
|
799
|
+
let unmatched = 0;
|
|
800
|
+
const known = /* @__PURE__ */ new Map();
|
|
801
|
+
for (const a of input.apps ?? [])
|
|
802
|
+
if (a.trim() && !known.has(key(a)))
|
|
803
|
+
known.set(key(a), a.trim());
|
|
804
|
+
const days = [];
|
|
805
|
+
for (const r of rows) {
|
|
806
|
+
for (const n of dropped) {
|
|
807
|
+
const v = (r[n] ?? "").trim();
|
|
808
|
+
const q = /^(?:[a-z][a-z0-9+.-]*:\/\/|\/)/i.test(v) ? v.split(/[?#]/)[1] ?? "" : v;
|
|
809
|
+
if (q.length >= 6)
|
|
810
|
+
secrets.add(q);
|
|
811
|
+
}
|
|
812
|
+
for (const n of [c.path, c.suffix, c.basepath]) {
|
|
813
|
+
const v = n ? r[n] ?? "" : "";
|
|
814
|
+
const q = v.split(/[?#]/)[1] ?? "";
|
|
815
|
+
if (q.length >= 4)
|
|
816
|
+
secrets.add(q);
|
|
817
|
+
for (const m of (v.split(/[?#]/, 1)[0] ?? "").match(/;[^/]*/g) ?? [])
|
|
818
|
+
if (m.length >= 5)
|
|
819
|
+
secrets.add(m.slice(1));
|
|
820
|
+
}
|
|
821
|
+
if (c.time) {
|
|
822
|
+
const d = dayOf(r[c.time] ?? "");
|
|
823
|
+
if (d) {
|
|
824
|
+
if (input.from && d < input.from || input.to && d > input.to) {
|
|
825
|
+
outOfRange++;
|
|
826
|
+
continue;
|
|
827
|
+
}
|
|
828
|
+
days.push(d);
|
|
829
|
+
} else if (!input.from || !input.to) {
|
|
830
|
+
skipped2++;
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
const method = (r[c.method] ?? "").trim().toUpperCase();
|
|
835
|
+
const rawPath = c.path ? r[c.path] ?? "" : `${(r[c.basepath] ?? "").replace(/\/+$/, "")}/${(r[c.suffix] ?? "").replace(/^\/+/, "")}`;
|
|
836
|
+
const countText = c.count ? (r[c.count] ?? "").trim() : "1";
|
|
837
|
+
const count = Number(countText);
|
|
838
|
+
if (!/^[A-Z]{3,10}$/.test(method) || !barePath(rawPath).startsWith("/") || !Number.isInteger(count) || count < 0) {
|
|
839
|
+
skipped2++;
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
const path = pathTemplateOf(rawPath, input.templates);
|
|
843
|
+
if (!path) {
|
|
844
|
+
unmatched++;
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
if (count === 0)
|
|
848
|
+
continue;
|
|
849
|
+
const appRaw = (r[c.app] ?? "").trim();
|
|
850
|
+
const app = !appRaw ? "(none)" : known.get(key(appRaw)) ?? appLabelOf(appRaw);
|
|
851
|
+
const proxyRaw = c.proxy ? (r[c.proxy] ?? "").trim() : "";
|
|
852
|
+
const proxy = proxyRaw && !looksSensitive(proxyRaw) ? proxyRaw : void 0;
|
|
853
|
+
const baseRaw = c.basepath ? (r[c.basepath] ?? "").trim() : "";
|
|
854
|
+
const basepath = baseRaw ? safePathOf(baseRaw) : void 0;
|
|
855
|
+
for (const v of [app, proxy, basepath, path])
|
|
856
|
+
if (v)
|
|
857
|
+
keptValues.add(v);
|
|
858
|
+
const k = [app, method, path, proxy ?? "", basepath ?? ""].join("\0");
|
|
859
|
+
const row = agg.get(k) ?? {
|
|
860
|
+
app,
|
|
861
|
+
method,
|
|
862
|
+
path,
|
|
863
|
+
...proxy ? { proxy } : {},
|
|
864
|
+
...basepath ? { basepath } : {},
|
|
865
|
+
count: 0
|
|
866
|
+
};
|
|
867
|
+
row.count += count;
|
|
868
|
+
agg.set(k, row);
|
|
869
|
+
}
|
|
870
|
+
if (!agg.size)
|
|
871
|
+
return {
|
|
872
|
+
ok: false,
|
|
873
|
+
message: `No row of the file is a request in the range to a route of the estate (${rows.length} read, ${outOfRange} outside it, ${skipped2} without a method, path or count, ${unmatched} matching no route template of the estate): nothing to keep.`
|
|
874
|
+
};
|
|
875
|
+
days.sort();
|
|
876
|
+
const from = input.from ?? days[0];
|
|
877
|
+
const to = input.to ?? days[days.length - 1];
|
|
878
|
+
if (!from || !to)
|
|
879
|
+
return { ok: false, message: "The rows carry no dates: give --from and --to (YYYY-MM-DD)." };
|
|
880
|
+
const parsed = TrafficFile.safeParse({
|
|
881
|
+
schemaVersion: 1,
|
|
882
|
+
source: input.source,
|
|
883
|
+
from,
|
|
884
|
+
to,
|
|
885
|
+
inputSha256: createHash3("sha256").update(input.bytes).digest("hex"),
|
|
886
|
+
rows: [...agg.values()].sort((a, b) => cmp(a.app, b.app) || cmp(a.proxy ?? "", b.proxy ?? "") || cmp(a.path, b.path) || cmp(a.method, b.method))
|
|
887
|
+
});
|
|
888
|
+
if (!parsed.success)
|
|
889
|
+
return { ok: false, message: `The aggregate isn't valid: ${parsed.error.issues[0]?.message}.` };
|
|
890
|
+
const out = trafficFileText(parsed.data);
|
|
891
|
+
const lower = out.toLowerCase();
|
|
892
|
+
const leaked = [...secrets].filter((s) => !keptValues.has(s) && lower.includes(s.toLowerCase()));
|
|
893
|
+
if (leaked.length)
|
|
894
|
+
return {
|
|
895
|
+
ok: false,
|
|
896
|
+
message: `Refused: ${leaked.length} value${leaked.length === 1 ? "" : "s"} of the export's dropped columns would be written. Nothing was written.`
|
|
897
|
+
};
|
|
898
|
+
const body = out.replace(/^inputSha256: .*$/m, "");
|
|
899
|
+
if ([IPV4, IPV6, EMAIL, JWT, OPAQUE, UUID, HEX].some((re) => re.test(body)))
|
|
900
|
+
return {
|
|
901
|
+
ok: false,
|
|
902
|
+
message: "Refused: the aggregate would hold an IP, an email or a token-looking value. Nothing was written."
|
|
903
|
+
};
|
|
904
|
+
const hits = input.denyHashes?.size ? denyListHits(out, input.denyHashes) : [];
|
|
905
|
+
if (hits.length)
|
|
906
|
+
return {
|
|
907
|
+
ok: false,
|
|
908
|
+
message: `Refused: the deny-list names a word on line${hits.length === 1 ? "" : "s"} ${hits.join(", ")} of the aggregate. Nothing was written.`
|
|
909
|
+
};
|
|
910
|
+
return {
|
|
911
|
+
ok: true,
|
|
912
|
+
file: parsed.data,
|
|
913
|
+
text: out,
|
|
914
|
+
read: rows.length,
|
|
915
|
+
outOfRange,
|
|
916
|
+
skipped: skipped2,
|
|
917
|
+
unmatched,
|
|
918
|
+
dropped
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// packages/intake/dist/vendor-ops.js
|
|
923
|
+
var import_yaml3 = __toESM(require_dist(), 1);
|
|
924
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
925
|
+
var short2 = (s) => createHash4("sha256").update(s).digest("hex").slice(0, 6);
|
|
926
|
+
function specEndpointIds(component, ops) {
|
|
927
|
+
const ids = ops.map((o) => endpointId(component, o.method, o.normalizedPath));
|
|
928
|
+
const count = /* @__PURE__ */ new Map();
|
|
929
|
+
for (const id of ids)
|
|
930
|
+
count.set(id, (count.get(id) ?? 0) + 1);
|
|
931
|
+
return ids.map((id, i) => (count.get(id) ?? 0) > 1 ? `${id}-${short2(ops[i].normalizedPath)}` : id);
|
|
932
|
+
}
|
|
933
|
+
var MAX_DEPTH = 6;
|
|
934
|
+
function readVendorSpec(path, text3, system) {
|
|
935
|
+
const read = readOpenApiDocument(text3);
|
|
936
|
+
if (!read)
|
|
937
|
+
return void 0;
|
|
938
|
+
const { doc, lc } = read;
|
|
939
|
+
const at = (offset) => offset === void 0 ? void 0 : `${path}:${lc.linePos(offset).line}`;
|
|
940
|
+
const swagger2 = read.version.startsWith("2");
|
|
941
|
+
const hosts = [];
|
|
942
|
+
let serverPath = "";
|
|
943
|
+
read.servers.forEach((url, i) => {
|
|
944
|
+
const m = /^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)([^?#]*)/i.exec(url);
|
|
945
|
+
const host = m?.[1]?.replace(/^[^@]*@/, "").replace(/:\d+$/, "").toLowerCase();
|
|
946
|
+
if (host && !host.includes("{") && !hosts.includes(host))
|
|
947
|
+
hosts.push(host);
|
|
948
|
+
if (i === 0) {
|
|
949
|
+
const p = m ? m[2] : url.startsWith("/") ? url.split(/[?#]/)[0] : "";
|
|
950
|
+
serverPath = p.replace(/\/+$/, "");
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
if (swagger2)
|
|
954
|
+
serverPath = "";
|
|
955
|
+
const info = doc.get("info");
|
|
956
|
+
const title = (0, import_yaml3.isMap)(info) ? info.get("title") : void 0;
|
|
957
|
+
const version = (0, import_yaml3.isMap)(info) ? info.get("version") : void 0;
|
|
958
|
+
const ctx = { doc, lc, path, at };
|
|
959
|
+
const ops = read.operations.map((op) => {
|
|
960
|
+
const method = op.method.toUpperCase();
|
|
961
|
+
const fullPath = `${serverPath}${op.path}` || op.path;
|
|
962
|
+
const node = (0, import_yaml3.isMap)(op.node) ? op.node : void 0;
|
|
963
|
+
const opId = node?.get("operationId");
|
|
964
|
+
return {
|
|
965
|
+
method,
|
|
966
|
+
path: op.path,
|
|
967
|
+
fullPath,
|
|
968
|
+
normalizedPath: normalizePath(op.path),
|
|
969
|
+
...typeof opId === "string" && opId ? { operationId: opId } : {},
|
|
970
|
+
...op.auth ? { auth: op.auth } : {},
|
|
971
|
+
scopes: op.scopes,
|
|
972
|
+
cite: `${path}:${op.methodLine ?? op.line ?? 1}`,
|
|
973
|
+
request: requestFields(ctx, op, swagger2),
|
|
974
|
+
response: responseFields(ctx, op, swagger2),
|
|
975
|
+
...errorsOf(ctx, op, swagger2)
|
|
976
|
+
};
|
|
977
|
+
});
|
|
978
|
+
const ids = specEndpointIds(system, ops);
|
|
979
|
+
return {
|
|
980
|
+
path,
|
|
981
|
+
system,
|
|
982
|
+
...typeof title === "string" && title ? { title } : {},
|
|
983
|
+
...version !== void 0 && version !== null && String(version) ? { version: String(version) } : {},
|
|
984
|
+
hosts,
|
|
985
|
+
serverPath,
|
|
986
|
+
basePath: swagger2 ? String(doc.get("basePath") ?? "") : "",
|
|
987
|
+
operations: ops.map((o, i) => ({ id: ids[i], ...o }))
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
function errorsOf(ctx, op, swagger2) {
|
|
991
|
+
const responses = (0, import_yaml3.isMap)(op.node) ? op.node.get("responses") : void 0;
|
|
992
|
+
if (!(0, import_yaml3.isMap)(responses))
|
|
993
|
+
return {};
|
|
994
|
+
const errors = responses.items.flatMap((p) => {
|
|
995
|
+
const status = (0, import_yaml3.isScalar)(p.key) ? String(p.key.value) : "";
|
|
996
|
+
if (!/^[45]\d\d$/.test(status))
|
|
997
|
+
return [];
|
|
998
|
+
const cite = ctx.at((0, import_yaml3.isScalar)(p.key) ? p.key.range?.[0] : void 0);
|
|
999
|
+
if (!cite)
|
|
1000
|
+
return [];
|
|
1001
|
+
const fields = [];
|
|
1002
|
+
schemaFields(ctx, bodySchema(ctx, p.value, swagger2), "body", "", 0, /* @__PURE__ */ new Set(), fields);
|
|
1003
|
+
return [{ status, cite, ...fields.length ? { fields } : {} }];
|
|
1004
|
+
});
|
|
1005
|
+
return errors.length ? { errors } : {};
|
|
1006
|
+
}
|
|
1007
|
+
function bodySchema(ctx, response, swagger2) {
|
|
1008
|
+
if (!swagger2)
|
|
1009
|
+
return contentSchema(ctx, response);
|
|
1010
|
+
const r = deref(ctx, response);
|
|
1011
|
+
return (0, import_yaml3.isMap)(r) ? r.get("schema", true) : void 0;
|
|
1012
|
+
}
|
|
1013
|
+
function responseHeaders(ctx, response, swagger2) {
|
|
1014
|
+
const r = deref(ctx, response);
|
|
1015
|
+
const headers = (0, import_yaml3.isMap)(r) ? r.get("headers") : void 0;
|
|
1016
|
+
if (!(0, import_yaml3.isMap)(headers))
|
|
1017
|
+
return [];
|
|
1018
|
+
const out = [];
|
|
1019
|
+
for (const pair of headers.items) {
|
|
1020
|
+
if (!(0, import_yaml3.isScalar)(pair.key))
|
|
1021
|
+
continue;
|
|
1022
|
+
const h = deref(ctx, pair.value);
|
|
1023
|
+
if (!(0, import_yaml3.isMap)(h))
|
|
1024
|
+
continue;
|
|
1025
|
+
const schema = swagger2 ? h : deref(ctx, h.get("schema", true));
|
|
1026
|
+
const sm = (0, import_yaml3.isMap)(schema) ? schema : void 0;
|
|
1027
|
+
const type = sm ? typeOf2(sm) : void 0;
|
|
1028
|
+
const values = sm ? strings(sm.get("enum")) : void 0;
|
|
1029
|
+
out.push({
|
|
1030
|
+
name: String(pair.key.value),
|
|
1031
|
+
in: "header",
|
|
1032
|
+
...type ? { type } : {},
|
|
1033
|
+
...swagger2 ? {} : { required: h.get("required") === true },
|
|
1034
|
+
...values ? { enum: values } : {},
|
|
1035
|
+
cite: ctx.at(pair.key.range?.[0]) ?? `${ctx.path}:1`
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
return out;
|
|
1039
|
+
}
|
|
1040
|
+
function deref(ctx, node, seen = /* @__PURE__ */ new Set()) {
|
|
1041
|
+
let n = node;
|
|
1042
|
+
for (let i = 0; i < 8 && (0, import_yaml3.isMap)(n); i++) {
|
|
1043
|
+
const ref = n.get("$ref");
|
|
1044
|
+
if (typeof ref !== "string")
|
|
1045
|
+
return n;
|
|
1046
|
+
if (!ref.startsWith("#/") || seen.has(ref))
|
|
588
1047
|
return void 0;
|
|
589
1048
|
seen.add(ref);
|
|
590
1049
|
const parts = ref.slice(2).split("/").map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
@@ -775,12 +1234,442 @@ function operationSchemas(spec) {
|
|
|
775
1234
|
});
|
|
776
1235
|
}
|
|
777
1236
|
|
|
1237
|
+
// packages/intake/dist/contract-specs.js
|
|
1238
|
+
var MAX_BYTES = 1024 * 1024;
|
|
1239
|
+
var SKIP = /* @__PURE__ */ new Set([
|
|
1240
|
+
".git",
|
|
1241
|
+
"node_modules",
|
|
1242
|
+
"vendor",
|
|
1243
|
+
"target",
|
|
1244
|
+
"build",
|
|
1245
|
+
"dist",
|
|
1246
|
+
"out",
|
|
1247
|
+
"bin",
|
|
1248
|
+
"obj",
|
|
1249
|
+
".gradle",
|
|
1250
|
+
".idea",
|
|
1251
|
+
".venv",
|
|
1252
|
+
"__pycache__"
|
|
1253
|
+
]);
|
|
1254
|
+
var cmp2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
1255
|
+
function readProtoSpecs(path, text3) {
|
|
1256
|
+
const proto3 = /^\s*syntax\s*=\s*["']proto3["']/m.test(text3);
|
|
1257
|
+
let pkg = "";
|
|
1258
|
+
const out = [];
|
|
1259
|
+
const stack = [];
|
|
1260
|
+
let inComment = false;
|
|
1261
|
+
text3.split(/\r?\n/).forEach((raw, i) => {
|
|
1262
|
+
let line = raw;
|
|
1263
|
+
if (inComment) {
|
|
1264
|
+
const end = line.indexOf("*/");
|
|
1265
|
+
if (end < 0)
|
|
1266
|
+
return;
|
|
1267
|
+
line = line.slice(end + 2);
|
|
1268
|
+
inComment = false;
|
|
1269
|
+
}
|
|
1270
|
+
line = line.replace(/\/\*.*?\*\//g, "").replace(/\/\/.*$/, "");
|
|
1271
|
+
const open = line.indexOf("/*");
|
|
1272
|
+
if (open >= 0) {
|
|
1273
|
+
inComment = true;
|
|
1274
|
+
line = line.slice(0, open);
|
|
1275
|
+
}
|
|
1276
|
+
const n = i + 1;
|
|
1277
|
+
const p = /^\s*package\s+([\w.]+)\s*;/.exec(line);
|
|
1278
|
+
if (p)
|
|
1279
|
+
pkg = p[1];
|
|
1280
|
+
const message = /^\s*message\s+(\w+)\s*\{/.exec(line);
|
|
1281
|
+
const oneof = /^\s*oneof\s+(\w+)\s*\{/.exec(line);
|
|
1282
|
+
const other = /^\s*(enum|service|extend|extensions)\b[^{]*\{/.exec(line);
|
|
1283
|
+
let rest = line;
|
|
1284
|
+
if (message) {
|
|
1285
|
+
const outer = stack.filter((f) => f.kind === "message").map((f) => f.name);
|
|
1286
|
+
const name = [...outer, message[1]].join(".");
|
|
1287
|
+
const spec = {
|
|
1288
|
+
kind: "message",
|
|
1289
|
+
format: "protobuf",
|
|
1290
|
+
role: "schema",
|
|
1291
|
+
file: path,
|
|
1292
|
+
line: n,
|
|
1293
|
+
name: pkg ? `${pkg}.${name}` : name,
|
|
1294
|
+
fields: []
|
|
1295
|
+
};
|
|
1296
|
+
out.push(spec);
|
|
1297
|
+
stack.push({ kind: "message", name: message[1], spec });
|
|
1298
|
+
rest = line.slice(line.indexOf("{") + 1);
|
|
1299
|
+
} else if (oneof || other) {
|
|
1300
|
+
stack.push({ kind: oneof ? "oneof" : "other", name: "" });
|
|
1301
|
+
rest = line.slice(line.indexOf("{") + 1);
|
|
1302
|
+
} else {
|
|
1303
|
+
const top = stack.at(-1);
|
|
1304
|
+
const owner = top?.kind === "message" ? top : top?.kind === "oneof" ? stack.at(-2) : void 0;
|
|
1305
|
+
const f = /^\s*(optional|required|repeated)?\s*(map\s*<[^>]+>|[\w.]+)\s+(\w+)\s*=\s*(\d+)\s*(\[[^\]]*\])?\s*;/.exec(line);
|
|
1306
|
+
if (f && owner?.kind === "message" && owner.spec && !["reserved", "option"].includes(f[2])) {
|
|
1307
|
+
const label = f[1];
|
|
1308
|
+
owner.spec.fields.push({
|
|
1309
|
+
side: "message",
|
|
1310
|
+
name: f[3],
|
|
1311
|
+
type: label === "repeated" ? `repeated ${f[2]}` : f[2].replace(/\s+/g, ""),
|
|
1312
|
+
// proto2's `required` must be there; anything else may be left out (proto3 has no required).
|
|
1313
|
+
required: label === "required" && !proto3,
|
|
1314
|
+
number: Number(f[4]),
|
|
1315
|
+
at: `${path}:${n}`
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
for (const _ of rest.matchAll(/\}/g))
|
|
1320
|
+
stack.pop();
|
|
1321
|
+
});
|
|
1322
|
+
return out;
|
|
1323
|
+
}
|
|
1324
|
+
function lineOfName(lines, from, name) {
|
|
1325
|
+
const re = new RegExp(`"name"\\s*:\\s*"${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"`);
|
|
1326
|
+
for (let i = Math.max(0, from); i < lines.length; i++)
|
|
1327
|
+
if (re.test(lines[i]))
|
|
1328
|
+
return i + 1;
|
|
1329
|
+
return from + 1;
|
|
1330
|
+
}
|
|
1331
|
+
function readAvroSpecs(path, text3) {
|
|
1332
|
+
let data;
|
|
1333
|
+
try {
|
|
1334
|
+
data = JSON.parse(text3);
|
|
1335
|
+
} catch {
|
|
1336
|
+
return [];
|
|
1337
|
+
}
|
|
1338
|
+
const lines = text3.split(/\r?\n/);
|
|
1339
|
+
const out = [];
|
|
1340
|
+
let cursor = 0;
|
|
1341
|
+
const typeName = (t) => {
|
|
1342
|
+
if (typeof t === "string")
|
|
1343
|
+
return t;
|
|
1344
|
+
if (Array.isArray(t))
|
|
1345
|
+
return t.map(typeName).join("|");
|
|
1346
|
+
if (t && typeof t === "object") {
|
|
1347
|
+
const o = t;
|
|
1348
|
+
if (o.type === "array")
|
|
1349
|
+
return `repeated ${typeName(o.items)}`;
|
|
1350
|
+
if (o.type === "map")
|
|
1351
|
+
return `map<string,${typeName(o.values)}>`;
|
|
1352
|
+
if (typeof o.logicalType === "string")
|
|
1353
|
+
return String(o.type);
|
|
1354
|
+
if (typeof o.name === "string")
|
|
1355
|
+
return o.name;
|
|
1356
|
+
return typeName(o.type);
|
|
1357
|
+
}
|
|
1358
|
+
return "";
|
|
1359
|
+
};
|
|
1360
|
+
const record = (r, ns) => {
|
|
1361
|
+
if (r.type !== "record" || typeof r.name !== "string" || !Array.isArray(r.fields))
|
|
1362
|
+
return;
|
|
1363
|
+
const space = typeof r.namespace === "string" ? r.namespace : ns;
|
|
1364
|
+
const line = lineOfName(lines, cursor, r.name);
|
|
1365
|
+
cursor = line;
|
|
1366
|
+
const spec = {
|
|
1367
|
+
kind: "message",
|
|
1368
|
+
format: "avro",
|
|
1369
|
+
role: "schema",
|
|
1370
|
+
file: path,
|
|
1371
|
+
line,
|
|
1372
|
+
name: space ? `${space}.${r.name}` : r.name,
|
|
1373
|
+
fields: []
|
|
1374
|
+
};
|
|
1375
|
+
out.push(spec);
|
|
1376
|
+
r.fields.forEach((f, i) => {
|
|
1377
|
+
if (!f || typeof f !== "object")
|
|
1378
|
+
return;
|
|
1379
|
+
const x = f;
|
|
1380
|
+
if (typeof x.name !== "string")
|
|
1381
|
+
return;
|
|
1382
|
+
const at = lineOfName(lines, cursor, x.name);
|
|
1383
|
+
cursor = at;
|
|
1384
|
+
const nullable = Array.isArray(x.type) && x.type.includes("null");
|
|
1385
|
+
const type = typeName(Array.isArray(x.type) ? x.type.filter((t) => t !== "null") : x.type);
|
|
1386
|
+
spec.fields.push({
|
|
1387
|
+
side: "message",
|
|
1388
|
+
name: x.name,
|
|
1389
|
+
...type ? { type } : {},
|
|
1390
|
+
required: !nullable && !("default" in x),
|
|
1391
|
+
number: i,
|
|
1392
|
+
at: `${path}:${at}`
|
|
1393
|
+
});
|
|
1394
|
+
const inner = Array.isArray(x.type) ? x.type : [x.type];
|
|
1395
|
+
for (const t of inner)
|
|
1396
|
+
if (t && typeof t === "object")
|
|
1397
|
+
record(t, space);
|
|
1398
|
+
});
|
|
1399
|
+
};
|
|
1400
|
+
for (const r of Array.isArray(data) ? data : [data])
|
|
1401
|
+
if (r && typeof r === "object")
|
|
1402
|
+
record(r, "");
|
|
1403
|
+
return out;
|
|
1404
|
+
}
|
|
1405
|
+
var lineAt = (d, node) => {
|
|
1406
|
+
const r = node?.range;
|
|
1407
|
+
return r ? d.lc.linePos(r[0]).line : 1;
|
|
1408
|
+
};
|
|
1409
|
+
function deref2(d, node, depth = 0) {
|
|
1410
|
+
if (!(0, import_yaml4.isMap)(node) || depth > 8)
|
|
1411
|
+
return node;
|
|
1412
|
+
const ref = node.get("$ref");
|
|
1413
|
+
if (typeof ref !== "string" || !ref.startsWith("#/"))
|
|
1414
|
+
return node;
|
|
1415
|
+
let at = d.root;
|
|
1416
|
+
for (const p of ref.slice(2).split("/"))
|
|
1417
|
+
at = (0, import_yaml4.isMap)(at) ? at.get(p.replace(/~1/g, "/").replace(/~0/g, "~"), true) : void 0;
|
|
1418
|
+
return deref2(d, at, depth + 1);
|
|
1419
|
+
}
|
|
1420
|
+
function propsOf(d, schema, prefix, depth, out) {
|
|
1421
|
+
const s = deref2(d, schema);
|
|
1422
|
+
if (!(0, import_yaml4.isMap)(s) || depth > 6)
|
|
1423
|
+
return;
|
|
1424
|
+
const props = s.get("properties", true);
|
|
1425
|
+
const req = s.get("required", true);
|
|
1426
|
+
const required = new Set((0, import_yaml4.isSeq)(req) ? req.items.map((x) => (0, import_yaml4.isScalar)(x) ? String(x.value) : "") : []);
|
|
1427
|
+
if (!(0, import_yaml4.isMap)(props))
|
|
1428
|
+
return;
|
|
1429
|
+
for (const p of props.items) {
|
|
1430
|
+
if (!(0, import_yaml4.isScalar)(p.key))
|
|
1431
|
+
continue;
|
|
1432
|
+
const name = prefix ? `${prefix}.${String(p.key.value)}` : String(p.key.value);
|
|
1433
|
+
const v = deref2(d, p.value);
|
|
1434
|
+
const type = (0, import_yaml4.isMap)(v) ? v.get("type") : void 0;
|
|
1435
|
+
out.push({
|
|
1436
|
+
side: "message",
|
|
1437
|
+
name,
|
|
1438
|
+
...typeof type === "string" ? { type } : {},
|
|
1439
|
+
required: required.has(String(p.key.value)),
|
|
1440
|
+
at: `${d.path}:${lineAt(d, p.key)}`
|
|
1441
|
+
});
|
|
1442
|
+
if ((0, import_yaml4.isMap)(v)) {
|
|
1443
|
+
if (type === "array")
|
|
1444
|
+
propsOf(d, v.get("items", true), `${name}[]`, depth + 1, out);
|
|
1445
|
+
else
|
|
1446
|
+
propsOf(d, v, name, depth + 1, out);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
function docOf(path, text3) {
|
|
1451
|
+
const lc = new import_yaml4.LineCounter();
|
|
1452
|
+
const doc = (0, import_yaml4.parseDocument)(text3, { lineCounter: lc });
|
|
1453
|
+
return (0, import_yaml4.isMap)(doc.contents) ? { path, lc, root: doc.contents } : void 0;
|
|
1454
|
+
}
|
|
1455
|
+
function readJsonSchemaSpecs(path, text3) {
|
|
1456
|
+
const d = docOf(path, text3);
|
|
1457
|
+
if (!d)
|
|
1458
|
+
return [];
|
|
1459
|
+
const title = d.root.get("title");
|
|
1460
|
+
const id = d.root.get("$id");
|
|
1461
|
+
const fields = [];
|
|
1462
|
+
propsOf(d, d.root, "", 0, fields);
|
|
1463
|
+
if (!fields.length)
|
|
1464
|
+
return [];
|
|
1465
|
+
const name = typeof title === "string" && title ? title : typeof id === "string" && id ? (id.split("/").pop() ?? id).replace(/\.json$/, "") : (path.split("/").pop() ?? path).replace(/\.(schema\.)?json$|\.ya?ml$/i, "");
|
|
1466
|
+
return [
|
|
1467
|
+
{ kind: "message", format: "json-schema", role: "schema", file: path, line: 1, name, fields }
|
|
1468
|
+
];
|
|
1469
|
+
}
|
|
1470
|
+
function readAsyncApiSpecs(path, text3) {
|
|
1471
|
+
const d = docOf(path, text3);
|
|
1472
|
+
if (!d || d.root.get("asyncapi") === void 0)
|
|
1473
|
+
return [];
|
|
1474
|
+
const out = [];
|
|
1475
|
+
const channels = d.root.get("channels", true);
|
|
1476
|
+
if (!(0, import_yaml4.isMap)(channels))
|
|
1477
|
+
return out;
|
|
1478
|
+
const add = (topic, message) => {
|
|
1479
|
+
const m = deref2(d, message);
|
|
1480
|
+
if (!(0, import_yaml4.isMap)(m))
|
|
1481
|
+
return;
|
|
1482
|
+
const oneOf = m.get("oneOf", true);
|
|
1483
|
+
if ((0, import_yaml4.isSeq)(oneOf)) {
|
|
1484
|
+
for (const x of oneOf.items)
|
|
1485
|
+
add(topic, x);
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1488
|
+
const payload = m.get("payload", true);
|
|
1489
|
+
const fields = [];
|
|
1490
|
+
propsOf(d, payload, "", 0, fields);
|
|
1491
|
+
const p = deref2(d, payload);
|
|
1492
|
+
const title = (0, import_yaml4.isMap)(p) ? p.get("title") : void 0;
|
|
1493
|
+
const name = m.get("name") ?? m.get("title") ?? title;
|
|
1494
|
+
out.push({
|
|
1495
|
+
kind: "message",
|
|
1496
|
+
format: "asyncapi",
|
|
1497
|
+
role: "schema",
|
|
1498
|
+
file: path,
|
|
1499
|
+
line: lineAt(d, m),
|
|
1500
|
+
topic,
|
|
1501
|
+
...typeof name === "string" && name ? { name } : {},
|
|
1502
|
+
fields
|
|
1503
|
+
});
|
|
1504
|
+
};
|
|
1505
|
+
for (const c of channels.items) {
|
|
1506
|
+
if (!(0, import_yaml4.isScalar)(c.key))
|
|
1507
|
+
continue;
|
|
1508
|
+
const ch = deref2(d, c.value);
|
|
1509
|
+
if (!(0, import_yaml4.isMap)(ch))
|
|
1510
|
+
continue;
|
|
1511
|
+
const address = ch.get("address");
|
|
1512
|
+
const topic = typeof address === "string" && address ? address : String(c.key.value);
|
|
1513
|
+
for (const op of ["publish", "subscribe"]) {
|
|
1514
|
+
const o = ch.get(op, true);
|
|
1515
|
+
if ((0, import_yaml4.isMap)(o))
|
|
1516
|
+
add(topic, o.get("message", true));
|
|
1517
|
+
}
|
|
1518
|
+
const msgs = ch.get("messages", true);
|
|
1519
|
+
if ((0, import_yaml4.isMap)(msgs))
|
|
1520
|
+
for (const m of msgs.items)
|
|
1521
|
+
add(topic, m.value);
|
|
1522
|
+
}
|
|
1523
|
+
return out;
|
|
1524
|
+
}
|
|
1525
|
+
function openApiContractSpecs(spec) {
|
|
1526
|
+
return spec.operations.map((o) => {
|
|
1527
|
+
const [file, line] = splitAt(o.cite, spec.path);
|
|
1528
|
+
const field2 = (side) => (f) => ({
|
|
1529
|
+
side,
|
|
1530
|
+
name: f.name,
|
|
1531
|
+
...f.type ? { type: f.type } : {},
|
|
1532
|
+
...f.required !== void 0 ? { required: f.required } : {},
|
|
1533
|
+
...f.in ? { in: f.in } : {},
|
|
1534
|
+
at: f.cite
|
|
1535
|
+
});
|
|
1536
|
+
return {
|
|
1537
|
+
kind: "operation",
|
|
1538
|
+
format: "openapi",
|
|
1539
|
+
role: "consumer",
|
|
1540
|
+
file,
|
|
1541
|
+
line,
|
|
1542
|
+
method: o.method,
|
|
1543
|
+
path: o.fullPath,
|
|
1544
|
+
id: o.id,
|
|
1545
|
+
fields: [...o.request.map(field2("request")), ...o.response.map(field2("response"))],
|
|
1546
|
+
...o.errors?.length ? { errors: o.errors.map((e) => ({ status: e.status, at: e.cite })) } : {}
|
|
1547
|
+
};
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
function splitAt(cite, path) {
|
|
1551
|
+
const m = /^(.*):(\d+)$/.exec(cite);
|
|
1552
|
+
return m ? [m[1], Number(m[2])] : [path, 1];
|
|
1553
|
+
}
|
|
1554
|
+
function specFormatOf(name, text3) {
|
|
1555
|
+
const lower = name.toLowerCase();
|
|
1556
|
+
if (lower.endsWith(".proto"))
|
|
1557
|
+
return "protobuf";
|
|
1558
|
+
if (lower.endsWith(".avsc"))
|
|
1559
|
+
return "avro";
|
|
1560
|
+
if (!/\.(ya?ml|json)$/.test(lower))
|
|
1561
|
+
return void 0;
|
|
1562
|
+
const head = text3.slice(0, 4e3);
|
|
1563
|
+
if (/^\s*["']?(openapi|swagger)["']?\s*:/m.test(head))
|
|
1564
|
+
return "openapi";
|
|
1565
|
+
if (/^\s*["']?asyncapi["']?\s*:/m.test(head))
|
|
1566
|
+
return "asyncapi";
|
|
1567
|
+
if (/"type"\s*:\s*"record"/.test(head) && /"fields"\s*:/.test(head))
|
|
1568
|
+
return "avro";
|
|
1569
|
+
if (/["']?\$schema["']?\s*:/.test(head) && /json-schema\.org/.test(head))
|
|
1570
|
+
return "json-schema";
|
|
1571
|
+
return void 0;
|
|
1572
|
+
}
|
|
1573
|
+
function readContractSpecs(path, text3) {
|
|
1574
|
+
switch (specFormatOf(path, text3)) {
|
|
1575
|
+
case "protobuf":
|
|
1576
|
+
return readProtoSpecs(path, text3);
|
|
1577
|
+
case "avro":
|
|
1578
|
+
return readAvroSpecs(path, text3);
|
|
1579
|
+
case "json-schema":
|
|
1580
|
+
return readJsonSchemaSpecs(path, text3);
|
|
1581
|
+
case "asyncapi":
|
|
1582
|
+
return readAsyncApiSpecs(path, text3);
|
|
1583
|
+
case "openapi": {
|
|
1584
|
+
const spec = readVendorSpec(path, text3, "spec");
|
|
1585
|
+
return spec ? openApiContractSpecs(spec) : [];
|
|
1586
|
+
}
|
|
1587
|
+
default:
|
|
1588
|
+
return [];
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
var sameShape = (a, b) => normalizePath(a).replace(/\{[^}]*\}/g, "{}") === normalizePath(b).replace(/\{[^}]*\}/g, "{}");
|
|
1592
|
+
var SPEC_FILE = /\.(proto|avsc|ya?ml|json)$/i;
|
|
1593
|
+
function cmpPath(a, b) {
|
|
1594
|
+
const x = a.split("/");
|
|
1595
|
+
const y = b.split("/");
|
|
1596
|
+
for (let i = 0; i < Math.min(x.length, y.length); i++) {
|
|
1597
|
+
const c = cmp2(x[i], y[i]);
|
|
1598
|
+
if (c)
|
|
1599
|
+
return c;
|
|
1600
|
+
}
|
|
1601
|
+
return x.length - y.length;
|
|
1602
|
+
}
|
|
1603
|
+
var skipped = (p) => p.split("/").slice(0, -1).some((d) => SKIP.has(d) || d.startsWith("."));
|
|
1604
|
+
function folderTree(dir) {
|
|
1605
|
+
return {
|
|
1606
|
+
async files() {
|
|
1607
|
+
const out = [];
|
|
1608
|
+
const walk2 = async (rel) => {
|
|
1609
|
+
const entries = await readdir(join(dir, ...rel.split("/").filter(Boolean)), {
|
|
1610
|
+
withFileTypes: true
|
|
1611
|
+
}).catch(() => []);
|
|
1612
|
+
for (const e of [...entries].sort((a, b) => cmp2(a.name, b.name))) {
|
|
1613
|
+
const p = rel ? `${rel}/${e.name}` : e.name;
|
|
1614
|
+
if (e.isDirectory()) {
|
|
1615
|
+
if (!SKIP.has(e.name) && !e.name.startsWith("."))
|
|
1616
|
+
await walk2(p);
|
|
1617
|
+
} else if (e.isFile() && SPEC_FILE.test(e.name)) {
|
|
1618
|
+
const size = (await stat(join(dir, ...p.split("/"))).catch(() => void 0))?.size;
|
|
1619
|
+
out.push({ path: p, size: size ?? 0 });
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
await walk2("");
|
|
1624
|
+
return out;
|
|
1625
|
+
},
|
|
1626
|
+
read: (p) => readFile(join(dir, ...p.split("/")), "utf8").catch(() => void 0)
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
async function readRepoSpecs(dir, o) {
|
|
1630
|
+
const tree = o.tree ?? folderTree(dir);
|
|
1631
|
+
const files = (await tree.files()).filter((f) => SPEC_FILE.test(f.path) && !skipped(f.path) && f.size > 0 && f.size <= MAX_BYTES).sort((a, b) => cmpPath(a.path, b.path)).map((f) => f.path);
|
|
1632
|
+
const own = o.facts.filter((f) => f.kind === "entry" && f.entryType === "rest");
|
|
1633
|
+
const specs = [];
|
|
1634
|
+
for (const p of files) {
|
|
1635
|
+
const text3 = await tree.read(p);
|
|
1636
|
+
if (text3 === void 0 || !specFormatOf(p, text3))
|
|
1637
|
+
continue;
|
|
1638
|
+
const got = readContractSpecs(p, text3);
|
|
1639
|
+
if (!got.length)
|
|
1640
|
+
continue;
|
|
1641
|
+
if (o.denyHashes?.size && denyListHits(text3, o.denyHashes).length) {
|
|
1642
|
+
o.onRefused?.(`${p}: the deny-list names a word in it, so its specs are left out.`);
|
|
1643
|
+
continue;
|
|
1644
|
+
}
|
|
1645
|
+
for (const s of got) {
|
|
1646
|
+
if (s.kind !== "operation") {
|
|
1647
|
+
specs.push(s);
|
|
1648
|
+
continue;
|
|
1649
|
+
}
|
|
1650
|
+
const vendorPath = readVendorSpec(p, text3, "spec")?.operations.find((x) => x.id === s.id);
|
|
1651
|
+
const paths = [s.path ?? "", vendorPath?.path ?? ""].filter(Boolean);
|
|
1652
|
+
const entry = own.filter((e) => (!e.method || !s.method || e.method.toUpperCase() === s.method) && paths.some((x) => sameShape(x, e.path))).sort((a, b) => cmp2(a.id, b.id))[0];
|
|
1653
|
+
const { id: _id, ...rest } = s;
|
|
1654
|
+
specs.push(entry ? { ...rest, role: "own", entry: entry.id } : rest);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
return {
|
|
1658
|
+
schemaVersion: 1,
|
|
1659
|
+
repo: o.repo,
|
|
1660
|
+
...o.commit ? { commit: o.commit } : {},
|
|
1661
|
+
specs
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
|
|
778
1665
|
// packages/intake/dist/scan-inputs.js
|
|
779
1666
|
var SPECS = ["openapi", "swagger", "asyncapi"];
|
|
780
1667
|
var EVIDENCE_SOURCE = {
|
|
781
1668
|
openapi: "spec",
|
|
782
1669
|
swagger: "spec",
|
|
783
1670
|
asyncapi: "spec",
|
|
1671
|
+
protobuf: "spec",
|
|
1672
|
+
avro: "spec",
|
|
784
1673
|
diagram: "diagram",
|
|
785
1674
|
image: "document",
|
|
786
1675
|
document: "document",
|
|
@@ -798,14 +1687,14 @@ async function walk(dir, skip) {
|
|
|
798
1687
|
return;
|
|
799
1688
|
let entries;
|
|
800
1689
|
try {
|
|
801
|
-
entries = await
|
|
1690
|
+
entries = await readdir2(d, { withFileTypes: true });
|
|
802
1691
|
} catch {
|
|
803
1692
|
return;
|
|
804
1693
|
}
|
|
805
1694
|
for (const e of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
806
1695
|
if (e.name.startsWith("."))
|
|
807
1696
|
continue;
|
|
808
|
-
const full =
|
|
1697
|
+
const full = join2(d, e.name);
|
|
809
1698
|
if (e.isDirectory())
|
|
810
1699
|
await go(full);
|
|
811
1700
|
else if (e.isFile())
|
|
@@ -816,7 +1705,7 @@ async function walk(dir, skip) {
|
|
|
816
1705
|
return out;
|
|
817
1706
|
}
|
|
818
1707
|
var DATE = /(?:^|[-_ .])((\d{4})-?(\d{2})-?(\d{2}))(?=$|[-_ .])/;
|
|
819
|
-
var
|
|
1708
|
+
var VERSION2 = /(?:^|[-_ .])v(\d+(?:[._]\d+)*)(?=$|[-_ .])/i;
|
|
820
1709
|
function nameParts(stem) {
|
|
821
1710
|
let rest = stem;
|
|
822
1711
|
let date;
|
|
@@ -829,7 +1718,7 @@ function nameParts(stem) {
|
|
|
829
1718
|
}
|
|
830
1719
|
}
|
|
831
1720
|
let version;
|
|
832
|
-
const v =
|
|
1721
|
+
const v = VERSION2.exec(rest);
|
|
833
1722
|
if (v) {
|
|
834
1723
|
version = v[1].replace(/_/g, ".");
|
|
835
1724
|
rest = rest.replace(v[0], "");
|
|
@@ -855,23 +1744,23 @@ function systemsInName(stem, systems) {
|
|
|
855
1744
|
return systems.filter((sys) => [sys.id, sys.name, ...sys.aliases].some((n) => slug(n) && s.includes(`-${slug(n)}-`))).map((sys) => sys.id).sort();
|
|
856
1745
|
}
|
|
857
1746
|
async function scanInputs(o) {
|
|
858
|
-
const orgPackDir = typeof o.orgPack === "string" ? o.orgPack :
|
|
1747
|
+
const orgPackDir = typeof o.orgPack === "string" ? o.orgPack : join2(orgPackDirOf(o.root));
|
|
859
1748
|
const op = typeof o.orgPack === "object" ? o.orgPack : await loadOrgPack(orgPackDir);
|
|
860
1749
|
const systems = op.profiles.flatMap((p) => p.profile?.systems ?? []);
|
|
861
1750
|
const legend = op.profiles.find((p) => p.profile?.legend)?.profile?.legend;
|
|
862
1751
|
const records = o.records ?? [];
|
|
863
1752
|
const ingestors = o.ingestors ?? [drawioIngestor];
|
|
864
1753
|
const scannedAt = o.scannedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
865
|
-
const inputsDir = o.inputsDir ??
|
|
1754
|
+
const inputsDir = o.inputsDir ?? join2(o.root, "inputs");
|
|
866
1755
|
const problems = [];
|
|
867
1756
|
const triage = [];
|
|
868
1757
|
const authors = /* @__PURE__ */ new Map();
|
|
869
1758
|
const wikiDirs = op.sources.wikis.flatMap((w) => /^[a-z][a-z0-9+.-]*:\/\//i.test(w.location) ? [] : [resolve(orgPackDir, w.location), resolve(o.root, w.location)]);
|
|
870
|
-
const st = await
|
|
1759
|
+
const st = await stat2(inputsDir).catch(() => void 0);
|
|
871
1760
|
const paths = st?.isDirectory() ? await walk(inputsDir, wikiDirs) : [];
|
|
872
1761
|
const files = [];
|
|
873
1762
|
for (const abs of paths) {
|
|
874
|
-
const bytes = new Uint8Array(await
|
|
1763
|
+
const bytes = new Uint8Array(await readFile2(abs));
|
|
875
1764
|
const path = `inputs/${posix(relative(inputsDir, abs))}`;
|
|
876
1765
|
const name = path.split("/").pop();
|
|
877
1766
|
const c = classify(name, bytes);
|
|
@@ -879,14 +1768,19 @@ async function scanInputs(o) {
|
|
|
879
1768
|
abs,
|
|
880
1769
|
path,
|
|
881
1770
|
bytes,
|
|
882
|
-
hash:
|
|
1771
|
+
hash: createHash5("sha256").update(bytes).digest("hex"),
|
|
883
1772
|
stem: name.includes(".") ? name.slice(0, name.lastIndexOf(".")) : name,
|
|
884
1773
|
inbox: path.startsWith("inputs/inbox/"),
|
|
885
1774
|
...c.data !== void 0 ? { data: c.data } : {},
|
|
1775
|
+
...c.text !== void 0 ? { text: c.text } : {},
|
|
886
1776
|
doc: {
|
|
887
1777
|
path,
|
|
888
1778
|
classification: c.classification,
|
|
889
|
-
status: "no-reader",
|
|
1779
|
+
status: c.unreadable ? "unreadable" : "no-reader",
|
|
1780
|
+
...c.unreadable ? {
|
|
1781
|
+
reason: `${c.unreadable.reason}${c.unreadable.line !== void 0 ? ` at ${c.unreadable.line}:${c.unreadable.column}` : ""}`
|
|
1782
|
+
} : {},
|
|
1783
|
+
...c.notes?.length ? { notes: c.notes } : {},
|
|
890
1784
|
hash: "",
|
|
891
1785
|
...c.title ? { title: c.title } : {},
|
|
892
1786
|
...c.version ? { version: c.version } : {},
|
|
@@ -949,7 +1843,7 @@ async function scanInputs(o) {
|
|
|
949
1843
|
const heads = members.filter((m) => !m.doc.supersededBy);
|
|
950
1844
|
if (heads.length < 2)
|
|
951
1845
|
continue;
|
|
952
|
-
const distinct = (vals,
|
|
1846
|
+
const distinct = (vals, cmp5) => vals.every((v) => v !== void 0) && vals.every((v, i) => vals.every((w, j) => i === j || cmp5(v, w) !== 0));
|
|
953
1847
|
const byVersion = distinct(heads.map((h) => h.doc.version), compareVersions);
|
|
954
1848
|
const byDate = !byVersion && distinct(heads.map((h) => h.doc.date), (a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
955
1849
|
if (byVersion || byDate) {
|
|
@@ -992,7 +1886,7 @@ async function scanInputs(o) {
|
|
|
992
1886
|
for (const f of kept) {
|
|
993
1887
|
const cls = f.doc.classification;
|
|
994
1888
|
const current = !f.doc.supersededBy;
|
|
995
|
-
const text3 = () => new TextDecoder().decode(f.bytes);
|
|
1889
|
+
const text3 = () => f.text ?? new TextDecoder().decode(f.bytes);
|
|
996
1890
|
const linked = /* @__PURE__ */ new Set();
|
|
997
1891
|
const unknown = /* @__PURE__ */ new Set();
|
|
998
1892
|
if (SPECS.includes(cls)) {
|
|
@@ -1106,6 +2000,43 @@ async function scanInputs(o) {
|
|
|
1106
2000
|
} catch {
|
|
1107
2001
|
}
|
|
1108
2002
|
}
|
|
2003
|
+
if (cls === "protobuf" || cls === "avro") {
|
|
2004
|
+
const specs = cls === "protobuf" ? readProtoSpecs(f.path, text3()) : readAvroSpecs(f.path, text3());
|
|
2005
|
+
const named = new Set(systemsInName(f.stem, systems));
|
|
2006
|
+
for (const s of specs) {
|
|
2007
|
+
const res = s.name ? resolveName(s.name.split(".").slice(0, -1).join(" ")) : void 0;
|
|
2008
|
+
if (res?.id && !named.size)
|
|
2009
|
+
named.add(systemOf(res.id));
|
|
2010
|
+
}
|
|
2011
|
+
for (const s of named)
|
|
2012
|
+
linked.add(s);
|
|
2013
|
+
if (current && specs.length) {
|
|
2014
|
+
for (const s of specs) {
|
|
2015
|
+
const p = parseRecord({
|
|
2016
|
+
schemaVersion: 1,
|
|
2017
|
+
kind: "Schema",
|
|
2018
|
+
id: boundedId("schema.", slug(s.name ?? f.stem)),
|
|
2019
|
+
status: "current",
|
|
2020
|
+
confidence: "verified",
|
|
2021
|
+
format: cls,
|
|
2022
|
+
ref: `${f.path}#${s.name ?? ""}`,
|
|
2023
|
+
fields: s.fields.map((x) => ({
|
|
2024
|
+
name: x.name,
|
|
2025
|
+
...x.type ? { type: x.type } : {},
|
|
2026
|
+
...x.required !== void 0 ? { required: x.required } : {}
|
|
2027
|
+
})),
|
|
2028
|
+
evidence: [{ source: "spec", path: f.path, line: s.line, side: "definition" }]
|
|
2029
|
+
});
|
|
2030
|
+
if (!p.ok)
|
|
2031
|
+
continue;
|
|
2032
|
+
const schema = p.record;
|
|
2033
|
+
out.push(schema);
|
|
2034
|
+
f.doc.records.push(schema.id);
|
|
2035
|
+
}
|
|
2036
|
+
f.doc.status = "read";
|
|
2037
|
+
f.doc.reader = cls === "protobuf" ? READERS.protobuf : READERS.avro;
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
1109
2040
|
if (current && cls === "payload" && f.data !== void 0) {
|
|
1110
2041
|
const schema = readPayload(f.path, boundedId("payload.", f.doc.id.slice(4)), f.data);
|
|
1111
2042
|
out.push(schema);
|
|
@@ -1415,11 +2346,11 @@ function imageItems(records) {
|
|
|
1415
2346
|
};
|
|
1416
2347
|
});
|
|
1417
2348
|
}
|
|
1418
|
-
var
|
|
2349
|
+
var key2 = (action, target, value) => `${action}|${target}|${JSON.stringify(value ?? null)}`;
|
|
1419
2350
|
function buildTriage(input) {
|
|
1420
2351
|
const decisions = (input.decisions ?? []).filter((d) => d.kind === "CuratedDecision" && d.status === "current");
|
|
1421
2352
|
const decidedIds = new Set(decisions.map((d) => d.id));
|
|
1422
|
-
const decidedKeys = new Set(decisions.map((d) =>
|
|
2353
|
+
const decidedKeys = new Set(decisions.map((d) => key2(d.action, d.target, d.value)));
|
|
1423
2354
|
const docs = new Map((input.inputs?.documents ?? []).map((d) => [d.path, d.id]));
|
|
1424
2355
|
const docIdOf = (path) => docs.get(path) ?? boundedId("doc.", slug(path.split("/").pop().replace(/\.[^.]+$/, "")));
|
|
1425
2356
|
const records = input.records;
|
|
@@ -1432,7 +2363,7 @@ function buildTriage(input) {
|
|
|
1432
2363
|
...imageItems([...records, ...inputRecords]),
|
|
1433
2364
|
...readingItems(input)
|
|
1434
2365
|
];
|
|
1435
|
-
const open = all.filter((i) => !i.options.some((o) => decidedIds.has(o.decision.id) || decidedKeys.has(
|
|
2366
|
+
const open = all.filter((i) => !i.options.some((o) => decidedIds.has(o.decision.id) || decidedKeys.has(key2(o.decision.action, o.decision.target, o.decision.value))));
|
|
1436
2367
|
const items = sortItems(open);
|
|
1437
2368
|
return {
|
|
1438
2369
|
items,
|
|
@@ -1473,9 +2404,9 @@ function buildTriage(input) {
|
|
|
1473
2404
|
}
|
|
1474
2405
|
|
|
1475
2406
|
// packages/intake/dist/work-items.js
|
|
1476
|
-
var
|
|
1477
|
-
import { readdir as
|
|
1478
|
-
import { join as
|
|
2407
|
+
var import_yaml5 = __toESM(require_dist(), 1);
|
|
2408
|
+
import { readdir as readdir3, readFile as readFile3 } from "node:fs/promises";
|
|
2409
|
+
import { join as join3, relative as relative2, sep as sep2 } from "node:path";
|
|
1479
2410
|
var WORK_ITEM_READER = "work-items@0.1.0";
|
|
1480
2411
|
var isObj3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1481
2412
|
var text = (v) => {
|
|
@@ -1654,7 +2585,7 @@ function readWorkItemExport(path, bytes) {
|
|
|
1654
2585
|
return void 0;
|
|
1655
2586
|
let data;
|
|
1656
2587
|
try {
|
|
1657
|
-
data = (0,
|
|
2588
|
+
data = (0, import_yaml5.parse)(content);
|
|
1658
2589
|
} catch {
|
|
1659
2590
|
return void 0;
|
|
1660
2591
|
}
|
|
@@ -1677,19 +2608,19 @@ function readWorkItemExport(path, bytes) {
|
|
|
1677
2608
|
return items;
|
|
1678
2609
|
}
|
|
1679
2610
|
async function readWorkItemExports(o) {
|
|
1680
|
-
const dir = o.inputsDir ??
|
|
2611
|
+
const dir = o.inputsDir ?? join3(o.root, "inputs");
|
|
1681
2612
|
const files = [];
|
|
1682
2613
|
async function walk2(d) {
|
|
1683
2614
|
let entries;
|
|
1684
2615
|
try {
|
|
1685
|
-
entries = await
|
|
2616
|
+
entries = await readdir3(d, { withFileTypes: true });
|
|
1686
2617
|
} catch {
|
|
1687
2618
|
return;
|
|
1688
2619
|
}
|
|
1689
2620
|
for (const e of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
1690
2621
|
if (e.name.startsWith("."))
|
|
1691
2622
|
continue;
|
|
1692
|
-
const full =
|
|
2623
|
+
const full = join3(d, e.name);
|
|
1693
2624
|
if (e.isDirectory())
|
|
1694
2625
|
await walk2(full);
|
|
1695
2626
|
else if (/\.(json|ya?ml|csv)$/i.test(e.name))
|
|
@@ -1706,7 +2637,7 @@ async function readWorkItemExports(o) {
|
|
|
1706
2637
|
const path = `inputs/${relative2(dir, full).split(sep2).join("/")}`;
|
|
1707
2638
|
let bytes;
|
|
1708
2639
|
try {
|
|
1709
|
-
bytes = new Uint8Array(await
|
|
2640
|
+
bytes = new Uint8Array(await readFile3(full));
|
|
1710
2641
|
} catch (e) {
|
|
1711
2642
|
out.problems.push({ path, message: `can't read it: ${e.message}` });
|
|
1712
2643
|
continue;
|
|
@@ -1721,9 +2652,9 @@ async function readWorkItemExports(o) {
|
|
|
1721
2652
|
}
|
|
1722
2653
|
|
|
1723
2654
|
// packages/intake/dist/service-requests.js
|
|
1724
|
-
var
|
|
1725
|
-
import { readdir as
|
|
1726
|
-
import { join as
|
|
2655
|
+
var import_yaml6 = __toESM(require_dist(), 1);
|
|
2656
|
+
import { readdir as readdir4, readFile as readFile4 } from "node:fs/promises";
|
|
2657
|
+
import { join as join4, relative as relative3, sep as sep3 } from "node:path";
|
|
1727
2658
|
var SERVICE_REQUEST_READER = "service-requests@0.1.0";
|
|
1728
2659
|
var isObj4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1729
2660
|
var text2 = (v) => {
|
|
@@ -1874,7 +2805,7 @@ function readServiceRequestExport(path, bytes) {
|
|
|
1874
2805
|
return void 0;
|
|
1875
2806
|
let data;
|
|
1876
2807
|
try {
|
|
1877
|
-
data = (0,
|
|
2808
|
+
data = (0, import_yaml6.parse)(content);
|
|
1878
2809
|
} catch {
|
|
1879
2810
|
return void 0;
|
|
1880
2811
|
}
|
|
@@ -1904,19 +2835,19 @@ function readServiceRequestExport(path, bytes) {
|
|
|
1904
2835
|
return out;
|
|
1905
2836
|
}
|
|
1906
2837
|
async function readServiceRequestExports(o) {
|
|
1907
|
-
const dir = o.inputsDir ??
|
|
2838
|
+
const dir = o.inputsDir ?? join4(o.root, "inputs");
|
|
1908
2839
|
const found = [];
|
|
1909
2840
|
async function walk2(d) {
|
|
1910
2841
|
let entries;
|
|
1911
2842
|
try {
|
|
1912
|
-
entries = await
|
|
2843
|
+
entries = await readdir4(d, { withFileTypes: true });
|
|
1913
2844
|
} catch {
|
|
1914
2845
|
return;
|
|
1915
2846
|
}
|
|
1916
2847
|
for (const e of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
1917
2848
|
if (e.name.startsWith("."))
|
|
1918
2849
|
continue;
|
|
1919
|
-
const full =
|
|
2850
|
+
const full = join4(d, e.name);
|
|
1920
2851
|
if (e.isDirectory())
|
|
1921
2852
|
await walk2(full);
|
|
1922
2853
|
else if (/\.(json|ya?ml|csv)$/i.test(e.name))
|
|
@@ -1933,7 +2864,7 @@ async function readServiceRequestExports(o) {
|
|
|
1933
2864
|
const path = `inputs/${relative3(dir, full).split(sep3).join("/")}`;
|
|
1934
2865
|
let bytes;
|
|
1935
2866
|
try {
|
|
1936
|
-
bytes = new Uint8Array(await
|
|
2867
|
+
bytes = new Uint8Array(await readFile4(full));
|
|
1937
2868
|
} catch (e) {
|
|
1938
2869
|
out.problems.push({ path, message: `can't read it: ${e.message}` });
|
|
1939
2870
|
continue;
|
|
@@ -1948,15 +2879,15 @@ async function readServiceRequestExports(o) {
|
|
|
1948
2879
|
}
|
|
1949
2880
|
|
|
1950
2881
|
// packages/intake/dist/change-inputs.js
|
|
1951
|
-
var
|
|
1952
|
-
import { createHash as
|
|
1953
|
-
import { mkdir, readdir as
|
|
1954
|
-
import { join as
|
|
2882
|
+
var import_yaml7 = __toESM(require_dist(), 1);
|
|
2883
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
2884
|
+
import { mkdir, readdir as readdir5, readFile as readFile5 } from "node:fs/promises";
|
|
2885
|
+
import { join as join5 } from "node:path";
|
|
1955
2886
|
var INPUTS_DIR = "inputs";
|
|
1956
2887
|
var INPUTS_INDEX = "inputs/index.yaml";
|
|
1957
2888
|
var INPUTS_READ_DIR = "inputs/read";
|
|
1958
2889
|
var CHANGE_INPUTS_SCHEMA_VERSION = 1;
|
|
1959
|
-
var sha256 = (b) =>
|
|
2890
|
+
var sha256 = (b) => createHash6("sha256").update(b).digest("hex");
|
|
1960
2891
|
var KEYS = [
|
|
1961
2892
|
"path",
|
|
1962
2893
|
"name",
|
|
@@ -1976,10 +2907,10 @@ var KEYS = [
|
|
|
1976
2907
|
"defences"
|
|
1977
2908
|
];
|
|
1978
2909
|
async function readChangeInputs(dir) {
|
|
1979
|
-
const text3 = await
|
|
2910
|
+
const text3 = await readFile5(join5(dir, ...INPUTS_INDEX.split("/")), "utf8").catch(() => "");
|
|
1980
2911
|
let data;
|
|
1981
2912
|
try {
|
|
1982
|
-
data = text3 ? (0,
|
|
2913
|
+
data = text3 ? (0, import_yaml7.parse)(text3) : void 0;
|
|
1983
2914
|
} catch {
|
|
1984
2915
|
data = void 0;
|
|
1985
2916
|
}
|
|
@@ -2000,7 +2931,7 @@ async function writeIndex(dir, index) {
|
|
|
2000
2931
|
o[k] = f[k];
|
|
2001
2932
|
return o;
|
|
2002
2933
|
});
|
|
2003
|
-
await writeFileAtomic(
|
|
2934
|
+
await writeFileAtomic(join5(dir, ...INPUTS_INDEX.split("/")), `# Files attached to this change (ADR 0113): atticus change attach writes this file.
|
|
2004
2935
|
${toCanonicalYaml({ schemaVersion: index.schemaVersion, files }, ["schemaVersion", "files"])}`);
|
|
2005
2936
|
}
|
|
2006
2937
|
var isText = (b) => {
|
|
@@ -2091,7 +3022,7 @@ function readText(input, bytes, older) {
|
|
|
2091
3022
|
async function attachToChange(dir, files, o) {
|
|
2092
3023
|
const index = await readChangeInputs(dir);
|
|
2093
3024
|
const out = { added: [], refused: [], notes: [] };
|
|
2094
|
-
const taken = new Set(await
|
|
3025
|
+
const taken = new Set(await readdir5(join5(dir, INPUTS_DIR)).catch(() => []));
|
|
2095
3026
|
taken.add("index.yaml").add("read");
|
|
2096
3027
|
const replaced = o.replaces ? index.files.find((x) => x.path === o.replaces.trim().replace(/\\/g, "/")) : void 0;
|
|
2097
3028
|
let changed = false;
|
|
@@ -2178,11 +3109,11 @@ async function attachToChange(dir, files, o) {
|
|
|
2178
3109
|
const where = o.elsewhere?.(hash);
|
|
2179
3110
|
if (where)
|
|
2180
3111
|
out.notes.push(`${name} is also in the metarepo's inputs as ${where}.`);
|
|
2181
|
-
await mkdir(
|
|
2182
|
-
await writeFileAtomic(
|
|
3112
|
+
await mkdir(join5(dir, INPUTS_DIR), { recursive: true });
|
|
3113
|
+
await writeFileAtomic(join5(dir, INPUTS_DIR, target), f.bytes);
|
|
2183
3114
|
const text3 = readText(input, f.bytes, older);
|
|
2184
3115
|
if (text3 !== void 0)
|
|
2185
|
-
await writeFileAtomic(
|
|
3116
|
+
await writeFileAtomic(join5(dir, ...input.readAs.split("/")), text3);
|
|
2186
3117
|
index.files.push(input);
|
|
2187
3118
|
out.added.push(input);
|
|
2188
3119
|
}
|
|
@@ -2208,7 +3139,7 @@ async function changeInputSources(dir, rel) {
|
|
|
2208
3139
|
for (const f of (await readChangeInputs(dir)).files) {
|
|
2209
3140
|
if (f.supersededBy || f.defences?.risk === "high")
|
|
2210
3141
|
continue;
|
|
2211
|
-
const read = f.readAs ? await
|
|
3142
|
+
const read = f.readAs ? await readFile5(join5(dir, ...f.readAs.split("/")), "utf8").catch(() => void 0) : void 0;
|
|
2212
3143
|
const text3 = read ?? `${f.path} (${f.name}) is ${f.kind === "image" ? "a picture; Atticus doesn't read pictures" : `a ${f.format} file no reader takes`}. Open it to see it; say what you rely on from it, citing ${f.path}.`;
|
|
2213
3144
|
out.push({
|
|
2214
3145
|
id: f.path,
|
|
@@ -2237,7 +3168,7 @@ var KIND_ORDER2 = [
|
|
|
2237
3168
|
"error-schema",
|
|
2238
3169
|
"error-removed"
|
|
2239
3170
|
];
|
|
2240
|
-
var
|
|
3171
|
+
var cmp3 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
2241
3172
|
var opKey = (o) => `${o.method} ${normalizePath(o.fullPath)}`;
|
|
2242
3173
|
var opName = (o) => `${o.method} ${o.path}`;
|
|
2243
3174
|
var list = (xs) => xs.length <= 1 ? xs[0] ?? "" : `${xs.slice(0, -1).join(", ")} and ${xs.at(-1)}`;
|
|
@@ -2302,7 +3233,7 @@ function diffVendorSpecs(older, newer) {
|
|
|
2302
3233
|
});
|
|
2303
3234
|
for (const [o, n] of pairs)
|
|
2304
3235
|
out.push(...operationChanges(o, n));
|
|
2305
|
-
return out.sort((a, b) =>
|
|
3236
|
+
return out.sort((a, b) => cmp3(a.severity === "breaking" ? "0" : "1", b.severity === "breaking" ? "0" : "1") || cmp3(a.operation.path, b.operation.path) || cmp3(a.operation.method, b.operation.method) || KIND_ORDER2.indexOf(a.kind) - KIND_ORDER2.indexOf(b.kind) || cmp3(a.side ?? "", b.side ?? "") || cmp3(a.field ?? "", b.field ?? ""));
|
|
2306
3237
|
}
|
|
2307
3238
|
var opOf = (o) => ({
|
|
2308
3239
|
method: o.method,
|
|
@@ -2493,7 +3424,7 @@ function fieldChanges(olds, news, side, at, base) {
|
|
|
2493
3424
|
|
|
2494
3425
|
// packages/intake/dist/vendor-impact.js
|
|
2495
3426
|
var MAX_UPSTREAM = 4;
|
|
2496
|
-
var
|
|
3427
|
+
var cmp4 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
2497
3428
|
var sorted = (xs) => [...new Set(xs)].sort();
|
|
2498
3429
|
var joinVendorOf = (input, spec) => ({
|
|
2499
3430
|
system: input.vendor.system,
|
|
@@ -2516,7 +3447,7 @@ var versionOf = (v) => ({
|
|
|
2516
3447
|
function vendorImpact(input) {
|
|
2517
3448
|
const diff = diffVendorSpecs(input.older.spec, input.newer.spec);
|
|
2518
3449
|
const bundle = input.bundleFolders ? { bundleFolders: input.bundleFolders } : {};
|
|
2519
|
-
const
|
|
3450
|
+
const join7 = joinFacts({
|
|
2520
3451
|
repos: input.repos,
|
|
2521
3452
|
...input.targets ? { targets: input.targets } : {},
|
|
2522
3453
|
...input.facing ? { facing: input.facing } : {},
|
|
@@ -2556,8 +3487,8 @@ function vendorImpact(input) {
|
|
|
2556
3487
|
const f = facts.get(k(call))?.fact;
|
|
2557
3488
|
return f?.kind === "call" && f.from ? endOf(call.repo, f.from) : void 0;
|
|
2558
3489
|
};
|
|
2559
|
-
const hops = new Set(
|
|
2560
|
-
const joins =
|
|
3490
|
+
const hops = new Set(join7.joins.flatMap((j) => (j.gateway ?? []).map((h) => k(h.call))));
|
|
3491
|
+
const joins = join7.joins.filter((j) => j.how !== "topic" && !hops.has(k(j.call)));
|
|
2561
3492
|
const via = (j) => j.gateway?.length ? { via: j.gateway.map((h) => h.route) } : {};
|
|
2562
3493
|
const upstreamOf = (start) => {
|
|
2563
3494
|
const out = [];
|
|
@@ -2586,422 +3517,121 @@ function vendorImpact(input) {
|
|
|
2586
3517
|
}
|
|
2587
3518
|
return out;
|
|
2588
3519
|
};
|
|
2589
|
-
const fieldUse = (call, change) => {
|
|
2590
|
-
if (!change.side || !change.field || change.status)
|
|
2591
|
-
return void 0;
|
|
2592
|
-
const side = change.side;
|
|
2593
|
-
const mine = (input.repos.find((r) => r.repo === call.repo)?.facts ?? []).filter((f) => f.kind === "field" && f.owner === call.fact && (f.side ?? "request") === side).sort((a, b) =>
|
|
2594
|
-
if (!mine.length)
|
|
2595
|
-
return void 0;
|
|
2596
|
-
const want = fieldNameKey(change.field);
|
|
2597
|
-
const hit = mine.find((f) => fieldNameKey(f.name) === want);
|
|
2598
|
-
const req = side === "request";
|
|
2599
|
-
return hit ? { uses: req ? "sends" : "reads", at: `${hit.cite.file}:${hit.cite.line}` } : { uses: req ? "does-not-send" : "does-not-read" };
|
|
2600
|
-
};
|
|
2601
|
-
const changes = diff.map((c) => {
|
|
2602
|
-
const older = c.endpoints.older;
|
|
2603
|
-
const matches = older ? today.matches.filter((m) => m.operation === older) : next.matches.filter((m) => m.operation === c.endpoints.newer);
|
|
2604
|
-
const forwards = matches.map((m) => {
|
|
2605
|
-
if (m.direct) {
|
|
2606
|
-
const f = facts.get(k(m.call))?.fact;
|
|
2607
|
-
const field2 = fieldUse(m.call, c);
|
|
2608
|
-
const self = {
|
|
2609
|
-
call: m.call,
|
|
2610
|
-
interface: interfaceId(m.call.component, factIdPart(f?.to ?? input.vendor.system), m.method, m.path),
|
|
2611
|
-
...field2 ? { field: field2 } : {},
|
|
2612
|
-
...m.route ? { under: m.route } : {},
|
|
2613
|
-
upstream: upstreamOf(m.route)
|
|
2614
|
-
};
|
|
2615
|
-
return {
|
|
2616
|
-
call: m.call,
|
|
2617
|
-
...m.route ? { route: m.route } : {},
|
|
2618
|
-
operation: m.operation,
|
|
2619
|
-
direct: true,
|
|
2620
|
-
callers: [self]
|
|
2621
|
-
};
|
|
2622
|
-
}
|
|
2623
|
-
const callers = m.route ? joins.filter((j) => k(j.entry) === k(m.route) || (j.gateway ?? []).some((h) => k(h.entry) === k(m.route))).map((j) => {
|
|
2624
|
-
const u = under(j.call);
|
|
2625
|
-
const field2 = fieldUse(j.call, c);
|
|
2626
|
-
return {
|
|
2627
|
-
call: j.call,
|
|
2628
|
-
interface: j.interface,
|
|
2629
|
-
...via(j),
|
|
2630
|
-
...field2 ? { field: field2 } : {},
|
|
2631
|
-
...u ? { under: u } : {},
|
|
2632
|
-
upstream: upstreamOf(u)
|
|
2633
|
-
};
|
|
2634
|
-
}) : [];
|
|
2635
|
-
return {
|
|
2636
|
-
call: m.call,
|
|
2637
|
-
...m.route ? { route: m.route } : {},
|
|
2638
|
-
...m.tie ? { tie: m.tie } : {},
|
|
2639
|
-
operation: m.operation,
|
|
2640
|
-
callers
|
|
2641
|
-
};
|
|
2642
|
-
});
|
|
2643
|
-
return { id: c.id, severity: c.severity, says: c.says, forwards };
|
|
2644
|
-
});
|
|
2645
|
-
const repos = /* @__PURE__ */ new Set();
|
|
2646
|
-
const interfaces = /* @__PURE__ */ new Set();
|
|
2647
|
-
const endpoints = /* @__PURE__ */ new Set();
|
|
2648
|
-
const entries = /* @__PURE__ */ new Set();
|
|
2649
|
-
for (const c of changes)
|
|
2650
|
-
for (const f of c.forwards) {
|
|
2651
|
-
repos.add(f.call.repo);
|
|
2652
|
-
endpoints.add(f.operation);
|
|
2653
|
-
for (const s of f.callers) {
|
|
2654
|
-
repos.add(s.call.repo);
|
|
2655
|
-
interfaces.add(s.interface);
|
|
2656
|
-
if (s.under)
|
|
2657
|
-
entries.add(k(s.under));
|
|
2658
|
-
for (const u of s.upstream) {
|
|
2659
|
-
repos.add(u.call.repo);
|
|
2660
|
-
interfaces.add(u.interface);
|
|
2661
|
-
entries.add(k(u.reaches));
|
|
2662
|
-
if (u.under)
|
|
2663
|
-
entries.add(k(u.under));
|
|
2664
|
-
}
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
const endpointIds = /* @__PURE__ */ new Set();
|
|
2668
|
-
for (const e of entries) {
|
|
2669
|
-
const got = facts.get(e);
|
|
2670
|
-
if (got?.fact.kind === "entry")
|
|
2671
|
-
endpointIds.add(entryEndpointId(got.fact, componentOf(got.repo, got.fact)));
|
|
2672
|
-
}
|
|
2673
|
-
const flows = (input.flows ?? []).filter((f) => f.trigger && endpointIds.has(f.trigger) || (f.refs ?? []).some((r) => endpointIds.has(r))).map((f) => ({ id: f.id, repo: f.repo })).sort((a, b) => cmp2(a.id, b.id));
|
|
2674
|
-
for (const f of flows)
|
|
2675
|
-
repos.add(f.repo);
|
|
2676
|
-
const systems = /* @__PURE__ */ new Set([input.vendor.system]);
|
|
2677
|
-
for (const r of repos) {
|
|
2678
|
-
const s = input.systemOfRepo?.[r];
|
|
2679
|
-
if (s)
|
|
2680
|
-
systems.add(s);
|
|
2681
|
-
}
|
|
2682
|
-
return {
|
|
2683
|
-
diff,
|
|
2684
|
-
impact: {
|
|
2685
|
-
vendor: input.vendor.system,
|
|
2686
|
-
older: versionOf(input.older),
|
|
2687
|
-
newer: versionOf(input.newer),
|
|
2688
|
-
changes,
|
|
2689
|
-
repos: sorted(repos),
|
|
2690
|
-
systems: sorted(systems),
|
|
2691
|
-
flows,
|
|
2692
|
-
interfaces: sorted(interfaces),
|
|
2693
|
-
endpoints: sorted(endpoints),
|
|
2694
|
-
gaps: today.gaps,
|
|
2695
|
-
asks: today.asks
|
|
2696
|
-
}
|
|
2697
|
-
};
|
|
2698
|
-
}
|
|
2699
|
-
|
|
2700
|
-
// packages/intake/dist/contract-files.js
|
|
2701
|
-
var import_yaml7 = __toESM(require_dist(), 1);
|
|
2702
|
-
import { readdir as readdir5, readFile as readFile5, stat as stat2 } from "node:fs/promises";
|
|
2703
|
-
import { join as join5 } from "node:path";
|
|
2704
|
-
|
|
2705
|
-
// packages/intake/dist/traffic.js
|
|
2706
|
-
import { createHash as createHash6 } from "node:crypto";
|
|
2707
|
-
var cmp3 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
2708
|
-
var key2 = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2709
|
-
var sha = (s) => createHash6("sha256").update(s, "utf8").digest("hex");
|
|
2710
|
-
var IPV4 = /\b\d{1,3}(?:\.\d{1,3}){3}\b/;
|
|
2711
|
-
var IPV6 = /[0-9a-f]{0,4}::[0-9a-f]{0,4}|\b[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){2,7}\b/i;
|
|
2712
|
-
var EMAIL = /[^\s@/]+@[^\s@/]+/;
|
|
2713
|
-
var JWT = /\beyJ[A-Za-z0-9_-]{6,}/;
|
|
2714
|
-
var OPAQUE = /\b(?=[A-Za-z0-9+_-]*\d)(?=[A-Za-z0-9+_-]*[A-Za-z])[A-Za-z0-9+_-]{24,}={0,2}/;
|
|
2715
|
-
var UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
|
|
2716
|
-
var HEX = /\b[0-9a-f]{16,}\b/i;
|
|
2717
|
-
function looksSensitive(v) {
|
|
2718
|
-
return [IPV4, IPV6, EMAIL, JWT, OPAQUE, UUID, HEX].some((re) => re.test(v));
|
|
2719
|
-
}
|
|
2720
|
-
function rowsOf(text3) {
|
|
2721
|
-
const t = text3.replace(/^\uFEFF/, "").trim();
|
|
2722
|
-
if (!t)
|
|
2723
|
-
return void 0;
|
|
2724
|
-
if (t.startsWith("[") || t.startsWith("{")) {
|
|
2725
|
-
let v;
|
|
2726
|
-
try {
|
|
2727
|
-
v = JSON.parse(t);
|
|
2728
|
-
} catch {
|
|
2729
|
-
return void 0;
|
|
2730
|
-
}
|
|
2731
|
-
const list2 = Array.isArray(v) ? v : v && typeof v === "object" ? ["rows", "data", "records", "items"].map((k) => v[k]).find((x) => Array.isArray(x)) : void 0;
|
|
2732
|
-
if (!Array.isArray(list2) || !list2.length)
|
|
2733
|
-
return void 0;
|
|
2734
|
-
const out = [];
|
|
2735
|
-
for (const r of list2) {
|
|
2736
|
-
if (!r || typeof r !== "object" || Array.isArray(r))
|
|
2737
|
-
return void 0;
|
|
2738
|
-
const row = {};
|
|
2739
|
-
for (const [k, x] of Object.entries(r))
|
|
2740
|
-
if (typeof x === "string" || typeof x === "number")
|
|
2741
|
-
row[k] = String(x);
|
|
2742
|
-
out.push(row);
|
|
2743
|
-
}
|
|
2744
|
-
return out;
|
|
2745
|
-
}
|
|
2746
|
-
const recs = parseCsv(t);
|
|
2747
|
-
if (recs.length < 2)
|
|
2748
|
-
return void 0;
|
|
2749
|
-
const head = recs[0].cells.map((c) => c.trim());
|
|
2750
|
-
if (head.length < 2)
|
|
2751
|
-
return void 0;
|
|
2752
|
-
return recs.slice(1).map((r) => {
|
|
2753
|
-
const row = {};
|
|
2754
|
-
head.forEach((h, i) => row[h] = (r.cells[i] ?? "").trim());
|
|
2755
|
-
return row;
|
|
2756
|
-
});
|
|
2757
|
-
}
|
|
2758
|
-
function dayOf(v) {
|
|
2759
|
-
const m = /^(\d{4}-\d{2}-\d{2})/.exec(v.trim());
|
|
2760
|
-
if (m)
|
|
2761
|
-
return m[1];
|
|
2762
|
-
if (/^\d{12,13}$/.test(v.trim()))
|
|
2763
|
-
return new Date(Number(v)).toISOString().slice(0, 10);
|
|
2764
|
-
return void 0;
|
|
2765
|
-
}
|
|
2766
|
-
var VERSION2 = /^v\d+(?:\.\d+)*$/i;
|
|
2767
|
-
var PARAM = /^(?:\{[A-Za-z_][A-Za-z0-9_.-]{0,40}\}|:[A-Za-z_][A-Za-z0-9_]{0,40}|<[A-Za-z_][A-Za-z0-9_:]{0,40}>)$/;
|
|
2768
|
-
var segmentOf = (s) => VERSION2.test(s) || PARAM.test(s) || /^[a-z][a-z._-]*$/.test(s) && s.length <= 20 && /[aeiou]/.test(s) && !looksSensitive(s) ? s : "{id}";
|
|
2769
|
-
function barePath(path) {
|
|
2770
|
-
let p = path.trim().split(/[?#]/, 1)[0] ?? "";
|
|
2771
|
-
p = p.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]*/i, "");
|
|
2772
|
-
return p.replace(/;[^/]*/g, "");
|
|
2773
|
-
}
|
|
2774
|
-
function safePathOf(path) {
|
|
2775
|
-
const p = barePath(path);
|
|
2776
|
-
if (!p.startsWith("/"))
|
|
2777
|
-
return void 0;
|
|
2778
|
-
return `/${p.split("/").filter(Boolean).map(segmentOf).join("/")}`;
|
|
2779
|
-
}
|
|
2780
|
-
var MATCH = 100;
|
|
2781
|
-
function pathTemplateOf(path, templates) {
|
|
2782
|
-
const p = barePath(path);
|
|
2783
|
-
if (!p.startsWith("/"))
|
|
2784
|
-
return void 0;
|
|
2785
|
-
const sorted2 = [...templates].sort();
|
|
2786
|
-
let best;
|
|
2787
|
-
let score = 0;
|
|
2788
|
-
for (const t of sorted2) {
|
|
2789
|
-
const s = routeScore(p, t);
|
|
2790
|
-
if (s > MATCH && s > score) {
|
|
2791
|
-
score = s;
|
|
2792
|
-
best = t;
|
|
2793
|
-
}
|
|
2794
|
-
}
|
|
2795
|
-
if (best)
|
|
2796
|
-
return best;
|
|
2797
|
-
const segs = p.split("/").filter(Boolean);
|
|
2798
|
-
let prefix;
|
|
2799
|
-
let len = 0;
|
|
2800
|
-
score = 0;
|
|
2801
|
-
for (const t of sorted2) {
|
|
2802
|
-
const n = t.split("/").filter(Boolean).length;
|
|
2803
|
-
if (n === 0 || n >= segs.length || n < len)
|
|
2804
|
-
continue;
|
|
2805
|
-
const s = routeScore(`/${segs.slice(0, n).join("/")}`, t);
|
|
2806
|
-
if (s <= MATCH)
|
|
2807
|
-
continue;
|
|
2808
|
-
if (n > len || s > score) {
|
|
2809
|
-
len = n;
|
|
2810
|
-
score = s;
|
|
2811
|
-
prefix = t;
|
|
2812
|
-
}
|
|
2813
|
-
}
|
|
2814
|
-
return prefix ? `${prefix.replace(/\/+$/, "")}/**` : void 0;
|
|
2815
|
-
}
|
|
2816
|
-
var appLabelOf = (name) => `app-${sha(name).slice(0, 8)}`;
|
|
2817
|
-
function denyListHits(text3, hashes) {
|
|
2818
|
-
const hits = [];
|
|
2819
|
-
text3.toLowerCase().split("\n").forEach((line, i) => {
|
|
2820
|
-
const w = line.match(/[a-z0-9]+/g) ?? [];
|
|
2821
|
-
for (let k = 0; k < w.length; k++)
|
|
2822
|
-
if (hashes.has(sha(w[k])) || k + 1 < w.length && hashes.has(sha(`${w[k]} ${w[k + 1]}`))) {
|
|
2823
|
-
hits.push(i + 1);
|
|
2824
|
-
break;
|
|
2825
|
-
}
|
|
2826
|
-
});
|
|
2827
|
-
return hits;
|
|
2828
|
-
}
|
|
2829
|
-
function aggregateTraffic(input) {
|
|
2830
|
-
const text3 = Buffer.from(input.bytes).toString("utf8");
|
|
2831
|
-
const rows = rowsOf(text3);
|
|
2832
|
-
const shape = `a CSV with a header row, or a JSON list of rows, with an app, a method and a path column (${input.source}: app ${input.columns.app.join("/")}; method ${input.columns.method.join("/")}; path ${[...input.columns.path, ...input.columns.basepath].join("/")})`;
|
|
2833
|
-
if (!rows)
|
|
2834
|
-
return { ok: false, message: `The file doesn't read as a traffic export: give ${shape}.` };
|
|
2835
|
-
const names = [...new Set(rows.flatMap((r) => Object.keys(r)))];
|
|
2836
|
-
const col = (aliases) => {
|
|
2837
|
-
for (const a of aliases) {
|
|
2838
|
-
const hit = names.find((n) => key2(n) === key2(a));
|
|
2839
|
-
if (hit)
|
|
2840
|
-
return hit;
|
|
2841
|
-
}
|
|
2842
|
-
return void 0;
|
|
2843
|
-
};
|
|
2844
|
-
const c = {
|
|
2845
|
-
app: col(input.columns.app),
|
|
2846
|
-
method: col(input.columns.method),
|
|
2847
|
-
basepath: col(input.columns.basepath),
|
|
2848
|
-
suffix: col(input.columns.suffix),
|
|
2849
|
-
proxy: col(input.columns.proxy),
|
|
2850
|
-
count: col(input.columns.count),
|
|
2851
|
-
time: col(input.columns.time),
|
|
2852
|
-
path: void 0
|
|
3520
|
+
const fieldUse = (call, change) => {
|
|
3521
|
+
if (!change.side || !change.field || change.status)
|
|
3522
|
+
return void 0;
|
|
3523
|
+
const side = change.side;
|
|
3524
|
+
const mine = (input.repos.find((r) => r.repo === call.repo)?.facts ?? []).filter((f) => f.kind === "field" && f.owner === call.fact && (f.side ?? "request") === side).sort((a, b) => cmp4(a.id, b.id));
|
|
3525
|
+
if (!mine.length)
|
|
3526
|
+
return void 0;
|
|
3527
|
+
const want = fieldNameKey(change.field);
|
|
3528
|
+
const hit = mine.find((f) => fieldNameKey(f.name) === want);
|
|
3529
|
+
const req = side === "request";
|
|
3530
|
+
return hit ? { uses: req ? "sends" : "reads", at: `${hit.cite.file}:${hit.cite.line}` } : { uses: req ? "does-not-send" : "does-not-read" };
|
|
2853
3531
|
};
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
3532
|
+
const changes = diff.map((c) => {
|
|
3533
|
+
const older = c.endpoints.older;
|
|
3534
|
+
const matches = older ? today.matches.filter((m) => m.operation === older) : next.matches.filter((m) => m.operation === c.endpoints.newer);
|
|
3535
|
+
const forwards = matches.map((m) => {
|
|
3536
|
+
if (m.direct) {
|
|
3537
|
+
const f = facts.get(k(m.call))?.fact;
|
|
3538
|
+
const field2 = fieldUse(m.call, c);
|
|
3539
|
+
const self = {
|
|
3540
|
+
call: m.call,
|
|
3541
|
+
interface: interfaceId(m.call.component, factIdPart(f?.to ?? input.vendor.system), m.method, m.path),
|
|
3542
|
+
...field2 ? { field: field2 } : {},
|
|
3543
|
+
...m.route ? { under: m.route } : {},
|
|
3544
|
+
upstream: upstreamOf(m.route)
|
|
3545
|
+
};
|
|
3546
|
+
return {
|
|
3547
|
+
call: m.call,
|
|
3548
|
+
...m.route ? { route: m.route } : {},
|
|
3549
|
+
operation: m.operation,
|
|
3550
|
+
direct: true,
|
|
3551
|
+
callers: [self]
|
|
3552
|
+
};
|
|
3553
|
+
}
|
|
3554
|
+
const callers = m.route ? joins.filter((j) => k(j.entry) === k(m.route) || (j.gateway ?? []).some((h) => k(h.entry) === k(m.route))).map((j) => {
|
|
3555
|
+
const u = under(j.call);
|
|
3556
|
+
const field2 = fieldUse(j.call, c);
|
|
3557
|
+
return {
|
|
3558
|
+
call: j.call,
|
|
3559
|
+
interface: j.interface,
|
|
3560
|
+
...via(j),
|
|
3561
|
+
...field2 ? { field: field2 } : {},
|
|
3562
|
+
...u ? { under: u } : {},
|
|
3563
|
+
upstream: upstreamOf(u)
|
|
3564
|
+
};
|
|
3565
|
+
}) : [];
|
|
3566
|
+
return {
|
|
3567
|
+
call: m.call,
|
|
3568
|
+
...m.route ? { route: m.route } : {},
|
|
3569
|
+
...m.tie ? { tie: m.tie } : {},
|
|
3570
|
+
operation: m.operation,
|
|
3571
|
+
callers
|
|
3572
|
+
};
|
|
3573
|
+
});
|
|
3574
|
+
return { id: c.id, severity: c.severity, says: c.says, forwards };
|
|
3575
|
+
});
|
|
3576
|
+
const repos = /* @__PURE__ */ new Set();
|
|
3577
|
+
const interfaces = /* @__PURE__ */ new Set();
|
|
3578
|
+
const endpoints = /* @__PURE__ */ new Set();
|
|
3579
|
+
const entries = /* @__PURE__ */ new Set();
|
|
3580
|
+
for (const c of changes)
|
|
3581
|
+
for (const f of c.forwards) {
|
|
3582
|
+
repos.add(f.call.repo);
|
|
3583
|
+
endpoints.add(f.operation);
|
|
3584
|
+
for (const s of f.callers) {
|
|
3585
|
+
repos.add(s.call.repo);
|
|
3586
|
+
interfaces.add(s.interface);
|
|
3587
|
+
if (s.under)
|
|
3588
|
+
entries.add(k(s.under));
|
|
3589
|
+
for (const u of s.upstream) {
|
|
3590
|
+
repos.add(u.call.repo);
|
|
3591
|
+
interfaces.add(u.interface);
|
|
3592
|
+
entries.add(k(u.reaches));
|
|
3593
|
+
if (u.under)
|
|
3594
|
+
entries.add(k(u.under));
|
|
2909
3595
|
}
|
|
2910
|
-
days.push(d);
|
|
2911
|
-
} else if (!input.from || !input.to) {
|
|
2912
|
-
skipped++;
|
|
2913
|
-
continue;
|
|
2914
3596
|
}
|
|
2915
3597
|
}
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
const
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
continue;
|
|
2931
|
-
const appRaw = (r[c.app] ?? "").trim();
|
|
2932
|
-
const app = !appRaw ? "(none)" : known.get(key2(appRaw)) ?? appLabelOf(appRaw);
|
|
2933
|
-
const proxyRaw = c.proxy ? (r[c.proxy] ?? "").trim() : "";
|
|
2934
|
-
const proxy = proxyRaw && !looksSensitive(proxyRaw) ? proxyRaw : void 0;
|
|
2935
|
-
const baseRaw = c.basepath ? (r[c.basepath] ?? "").trim() : "";
|
|
2936
|
-
const basepath = baseRaw ? safePathOf(baseRaw) : void 0;
|
|
2937
|
-
for (const v of [app, proxy, basepath, path])
|
|
2938
|
-
if (v)
|
|
2939
|
-
keptValues.add(v);
|
|
2940
|
-
const k = [app, method, path, proxy ?? "", basepath ?? ""].join("\0");
|
|
2941
|
-
const row = agg.get(k) ?? {
|
|
2942
|
-
app,
|
|
2943
|
-
method,
|
|
2944
|
-
path,
|
|
2945
|
-
...proxy ? { proxy } : {},
|
|
2946
|
-
...basepath ? { basepath } : {},
|
|
2947
|
-
count: 0
|
|
2948
|
-
};
|
|
2949
|
-
row.count += count;
|
|
2950
|
-
agg.set(k, row);
|
|
3598
|
+
const endpointIds = /* @__PURE__ */ new Set();
|
|
3599
|
+
for (const e of entries) {
|
|
3600
|
+
const got = facts.get(e);
|
|
3601
|
+
if (got?.fact.kind === "entry")
|
|
3602
|
+
endpointIds.add(entryEndpointId(got.fact, componentOf(got.repo, got.fact)));
|
|
3603
|
+
}
|
|
3604
|
+
const flows = (input.flows ?? []).filter((f) => f.trigger && endpointIds.has(f.trigger) || (f.refs ?? []).some((r) => endpointIds.has(r))).map((f) => ({ id: f.id, repo: f.repo })).sort((a, b) => cmp4(a.id, b.id));
|
|
3605
|
+
for (const f of flows)
|
|
3606
|
+
repos.add(f.repo);
|
|
3607
|
+
const systems = /* @__PURE__ */ new Set([input.vendor.system]);
|
|
3608
|
+
for (const r of repos) {
|
|
3609
|
+
const s = input.systemOfRepo?.[r];
|
|
3610
|
+
if (s)
|
|
3611
|
+
systems.add(s);
|
|
2951
3612
|
}
|
|
2952
|
-
if (!agg.size)
|
|
2953
|
-
return {
|
|
2954
|
-
ok: false,
|
|
2955
|
-
message: `No row of the file is a request in the range to a route of the estate (${rows.length} read, ${outOfRange} outside it, ${skipped} without a method, path or count, ${unmatched} matching no route template of the estate): nothing to keep.`
|
|
2956
|
-
};
|
|
2957
|
-
days.sort();
|
|
2958
|
-
const from = input.from ?? days[0];
|
|
2959
|
-
const to = input.to ?? days[days.length - 1];
|
|
2960
|
-
if (!from || !to)
|
|
2961
|
-
return { ok: false, message: "The rows carry no dates: give --from and --to (YYYY-MM-DD)." };
|
|
2962
|
-
const parsed = TrafficFile.safeParse({
|
|
2963
|
-
schemaVersion: 1,
|
|
2964
|
-
source: input.source,
|
|
2965
|
-
from,
|
|
2966
|
-
to,
|
|
2967
|
-
inputSha256: createHash6("sha256").update(input.bytes).digest("hex"),
|
|
2968
|
-
rows: [...agg.values()].sort((a, b) => cmp3(a.app, b.app) || cmp3(a.proxy ?? "", b.proxy ?? "") || cmp3(a.path, b.path) || cmp3(a.method, b.method))
|
|
2969
|
-
});
|
|
2970
|
-
if (!parsed.success)
|
|
2971
|
-
return { ok: false, message: `The aggregate isn't valid: ${parsed.error.issues[0]?.message}.` };
|
|
2972
|
-
const out = trafficFileText(parsed.data);
|
|
2973
|
-
const lower = out.toLowerCase();
|
|
2974
|
-
const leaked = [...secrets].filter((s) => !keptValues.has(s) && lower.includes(s.toLowerCase()));
|
|
2975
|
-
if (leaked.length)
|
|
2976
|
-
return {
|
|
2977
|
-
ok: false,
|
|
2978
|
-
message: `Refused: ${leaked.length} value${leaked.length === 1 ? "" : "s"} of the export's dropped columns would be written. Nothing was written.`
|
|
2979
|
-
};
|
|
2980
|
-
const body = out.replace(/^inputSha256: .*$/m, "");
|
|
2981
|
-
if ([IPV4, IPV6, EMAIL, JWT, OPAQUE, UUID, HEX].some((re) => re.test(body)))
|
|
2982
|
-
return {
|
|
2983
|
-
ok: false,
|
|
2984
|
-
message: "Refused: the aggregate would hold an IP, an email or a token-looking value. Nothing was written."
|
|
2985
|
-
};
|
|
2986
|
-
const hits = input.denyHashes?.size ? denyListHits(out, input.denyHashes) : [];
|
|
2987
|
-
if (hits.length)
|
|
2988
|
-
return {
|
|
2989
|
-
ok: false,
|
|
2990
|
-
message: `Refused: the deny-list names a word on line${hits.length === 1 ? "" : "s"} ${hits.join(", ")} of the aggregate. Nothing was written.`
|
|
2991
|
-
};
|
|
2992
3613
|
return {
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3614
|
+
diff,
|
|
3615
|
+
impact: {
|
|
3616
|
+
vendor: input.vendor.system,
|
|
3617
|
+
older: versionOf(input.older),
|
|
3618
|
+
newer: versionOf(input.newer),
|
|
3619
|
+
changes,
|
|
3620
|
+
repos: sorted(repos),
|
|
3621
|
+
systems: sorted(systems),
|
|
3622
|
+
flows,
|
|
3623
|
+
interfaces: sorted(interfaces),
|
|
3624
|
+
endpoints: sorted(endpoints),
|
|
3625
|
+
gaps: today.gaps,
|
|
3626
|
+
asks: today.asks
|
|
3627
|
+
}
|
|
3001
3628
|
};
|
|
3002
3629
|
}
|
|
3003
3630
|
|
|
3004
3631
|
// packages/intake/dist/contract-files.js
|
|
3632
|
+
var import_yaml8 = __toESM(require_dist(), 1);
|
|
3633
|
+
import { readdir as readdir6, readFile as readFile6, stat as stat3 } from "node:fs/promises";
|
|
3634
|
+
import { join as join6 } from "node:path";
|
|
3005
3635
|
function safeServerUrl(url) {
|
|
3006
3636
|
const m = /^([a-z][a-z0-9+.-]*:\/\/)([^/?#]*)(.*)$/i.exec(url.trim());
|
|
3007
3637
|
if (!m) {
|
|
@@ -3020,28 +3650,28 @@ var str2 = (m, key3) => {
|
|
|
3020
3650
|
return typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
3021
3651
|
};
|
|
3022
3652
|
var mapAt = (m, key3) => {
|
|
3023
|
-
const v = (0,
|
|
3024
|
-
return (0,
|
|
3653
|
+
const v = (0, import_yaml8.isMap)(m) ? m.get(key3, true) : void 0;
|
|
3654
|
+
return (0, import_yaml8.isMap)(v) ? v : void 0;
|
|
3025
3655
|
};
|
|
3026
3656
|
function readPactFile(text3, file) {
|
|
3027
|
-
const lc = new
|
|
3657
|
+
const lc = new import_yaml8.LineCounter();
|
|
3028
3658
|
let doc;
|
|
3029
3659
|
try {
|
|
3030
|
-
doc = (0,
|
|
3660
|
+
doc = (0, import_yaml8.parseDocument)(text3, { lineCounter: lc });
|
|
3031
3661
|
} catch {
|
|
3032
3662
|
return void 0;
|
|
3033
3663
|
}
|
|
3034
|
-
if (doc.errors.length || !(0,
|
|
3664
|
+
if (doc.errors.length || !(0, import_yaml8.isMap)(doc.contents))
|
|
3035
3665
|
return void 0;
|
|
3036
3666
|
const root = doc.contents;
|
|
3037
3667
|
const consumer = str2(mapAt(root, "consumer"), "name");
|
|
3038
3668
|
const provider = str2(mapAt(root, "provider"), "name");
|
|
3039
3669
|
const list2 = root.get("interactions", true);
|
|
3040
|
-
if (!consumer || !provider || !(0,
|
|
3670
|
+
if (!consumer || !provider || !(0, import_yaml8.isSeq)(list2))
|
|
3041
3671
|
return void 0;
|
|
3042
3672
|
const out = [];
|
|
3043
3673
|
for (const it of list2.items) {
|
|
3044
|
-
if (!(0,
|
|
3674
|
+
if (!(0, import_yaml8.isMap)(it))
|
|
3045
3675
|
continue;
|
|
3046
3676
|
const type = str2(it, "type");
|
|
3047
3677
|
if (type && !/http/i.test(type))
|
|
@@ -3050,8 +3680,8 @@ function readPactFile(text3, file) {
|
|
|
3050
3680
|
if (!req)
|
|
3051
3681
|
continue;
|
|
3052
3682
|
const method = str2(req, "method");
|
|
3053
|
-
const pair = req.items.find((p) => (0,
|
|
3054
|
-
const path = pair && (0,
|
|
3683
|
+
const pair = req.items.find((p) => (0, import_yaml8.isScalar)(p.key) && p.key.value === "path");
|
|
3684
|
+
const path = pair && (0, import_yaml8.isScalar)(pair.value) ? String(pair.value.value) : void 0;
|
|
3055
3685
|
const safe = path?.startsWith("/") ? safePathOf(path) : void 0;
|
|
3056
3686
|
if (!safe)
|
|
3057
3687
|
continue;
|
|
@@ -3098,7 +3728,7 @@ function readConsumerOpenApi(text3, file, own) {
|
|
|
3098
3728
|
] : [];
|
|
3099
3729
|
});
|
|
3100
3730
|
}
|
|
3101
|
-
var
|
|
3731
|
+
var SKIP2 = /* @__PURE__ */ new Set([
|
|
3102
3732
|
".git",
|
|
3103
3733
|
"node_modules",
|
|
3104
3734
|
"vendor",
|
|
@@ -3113,19 +3743,19 @@ var SKIP = /* @__PURE__ */ new Set([
|
|
|
3113
3743
|
".idea",
|
|
3114
3744
|
".atticus"
|
|
3115
3745
|
]);
|
|
3116
|
-
var
|
|
3746
|
+
var MAX_BYTES2 = 5 * 1024 * 1024;
|
|
3117
3747
|
var PACT = /pact/i;
|
|
3118
3748
|
var SPEC = /(openapi|swagger)/i;
|
|
3119
3749
|
async function readContractFiles(dir, o) {
|
|
3120
3750
|
const files = [];
|
|
3121
3751
|
const walk2 = async (rel) => {
|
|
3122
|
-
const entries2 = await
|
|
3752
|
+
const entries2 = await readdir6(join6(dir, ...rel.split("/").filter(Boolean)), {
|
|
3123
3753
|
withFileTypes: true
|
|
3124
3754
|
}).catch(() => []);
|
|
3125
3755
|
for (const e of [...entries2].sort((a, b) => a.name < b.name ? -1 : 1)) {
|
|
3126
3756
|
const p = rel ? `${rel}/${e.name}` : e.name;
|
|
3127
3757
|
if (e.isDirectory()) {
|
|
3128
|
-
if (!
|
|
3758
|
+
if (!SKIP2.has(e.name))
|
|
3129
3759
|
await walk2(p);
|
|
3130
3760
|
} else if (e.isFile()) {
|
|
3131
3761
|
if (/\.json$/i.test(e.name) && PACT.test(p))
|
|
@@ -3138,11 +3768,11 @@ async function readContractFiles(dir, o) {
|
|
|
3138
3768
|
await walk2("");
|
|
3139
3769
|
const entries = [];
|
|
3140
3770
|
for (const p of files) {
|
|
3141
|
-
const full =
|
|
3142
|
-
const size = (await
|
|
3143
|
-
if (size === 0 || size >
|
|
3771
|
+
const full = join6(dir, ...p.split("/"));
|
|
3772
|
+
const size = (await stat3(full).catch(() => void 0))?.size ?? 0;
|
|
3773
|
+
if (size === 0 || size > MAX_BYTES2)
|
|
3144
3774
|
continue;
|
|
3145
|
-
const text3 = await
|
|
3775
|
+
const text3 = await readFile6(full, "utf8");
|
|
3146
3776
|
const got = (/\.json$/i.test(p) && PACT.test(p) ? readPactFile(text3, p) : void 0) ?? (SPEC.test(p) ? readConsumerOpenApi(text3, p, o.own ?? []) : void 0);
|
|
3147
3777
|
if (!got?.length)
|
|
3148
3778
|
continue;
|
|
@@ -3165,6 +3795,7 @@ async function readContractFiles(dir, o) {
|
|
|
3165
3795
|
}
|
|
3166
3796
|
|
|
3167
3797
|
export {
|
|
3798
|
+
joinServerVariables,
|
|
3168
3799
|
classify,
|
|
3169
3800
|
READERS,
|
|
3170
3801
|
readOpenApiSpec,
|
|
@@ -3177,9 +3808,24 @@ export {
|
|
|
3177
3808
|
sortItems,
|
|
3178
3809
|
opt,
|
|
3179
3810
|
screenFile,
|
|
3811
|
+
looksSensitive,
|
|
3812
|
+
segmentOf,
|
|
3813
|
+
safePathOf,
|
|
3814
|
+
pathTemplateOf,
|
|
3815
|
+
appLabelOf,
|
|
3816
|
+
denyListHits,
|
|
3817
|
+
aggregateTraffic,
|
|
3180
3818
|
specEndpointIds,
|
|
3181
3819
|
readVendorSpec,
|
|
3182
3820
|
operationSchemas,
|
|
3821
|
+
readProtoSpecs,
|
|
3822
|
+
readAvroSpecs,
|
|
3823
|
+
readJsonSchemaSpecs,
|
|
3824
|
+
readAsyncApiSpecs,
|
|
3825
|
+
openApiContractSpecs,
|
|
3826
|
+
specFormatOf,
|
|
3827
|
+
readContractSpecs,
|
|
3828
|
+
readRepoSpecs,
|
|
3183
3829
|
nameParts,
|
|
3184
3830
|
compareVersions,
|
|
3185
3831
|
scanInputs,
|
|
@@ -3203,13 +3849,6 @@ export {
|
|
|
3203
3849
|
diffVendorSpecs,
|
|
3204
3850
|
MAX_UPSTREAM,
|
|
3205
3851
|
vendorImpact,
|
|
3206
|
-
looksSensitive,
|
|
3207
|
-
segmentOf,
|
|
3208
|
-
safePathOf,
|
|
3209
|
-
pathTemplateOf,
|
|
3210
|
-
appLabelOf,
|
|
3211
|
-
denyListHits,
|
|
3212
|
-
aggregateTraffic,
|
|
3213
3852
|
safeServerUrl,
|
|
3214
3853
|
readPactFile,
|
|
3215
3854
|
readConsumerOpenApi,
|