@maycombhq/atticus 2.0.0-beta.10 → 2.0.0-beta.11
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-GZ4TKR3Q.js → chunk-23VFQHFQ.js} +33 -134
- package/dist/{chunk-VKMTFIWS.js → chunk-26DBAGOP.js} +18 -18
- package/dist/{chunk-PKCMRPPB.js → chunk-27EDZN52.js} +33 -27
- package/dist/{chunk-AJJK7GLO.js → chunk-2K2ZEJVR.js} +3 -3
- package/dist/{chunk-XRO65C7V.js → chunk-3DDJLI7N.js} +8 -6
- package/dist/{chunk-XQ3YIV5R.js → chunk-3LU6YCSQ.js} +6 -6
- package/dist/{chunk-XTVDAHH2.js → chunk-3WU7LVTL.js} +5 -5
- package/dist/{chunk-6GNS32SI.js → chunk-4AYZQ3SY.js} +4 -4
- package/dist/{chunk-6VBXAGJX.js → chunk-4ONORLK5.js} +14 -14
- package/dist/{chunk-7TGYNOXD.js → chunk-4URR24DD.js} +7 -7
- package/dist/{chunk-CIUHAHM6.js → chunk-4UZJOQYK.js} +8 -8
- package/dist/chunk-4Y4FY34K.js +34 -0
- package/dist/{chunk-52R2YXP5.js → chunk-4YWRU7JK.js} +16 -16
- package/dist/chunk-52WCHTVZ.js +41 -0
- package/dist/{chunk-YIEOFHOL.js → chunk-55TBYJF2.js} +17 -11
- package/dist/{chunk-MH5OCRUM.js → chunk-5ACUW753.js} +2 -2
- package/dist/chunk-5BJFMAQU.js +32 -0
- package/dist/{chunk-YPBQNJHA.js → chunk-5ICB2BXH.js} +8 -8
- package/dist/{chunk-YGKYFMSL.js → chunk-5NZSJ5ZG.js} +3 -3
- package/dist/{chunk-YPIEYQF4.js → chunk-5P5BGG5L.js} +6 -6
- package/dist/{chunk-B7434AE2.js → chunk-5RUMHLIS.js} +2 -2
- package/dist/{chunk-5MI2SEV5.js → chunk-5TY4DTHQ.js} +3 -3
- package/dist/{chunk-NIXVDQVO.js → chunk-5V5BJACL.js} +2 -2
- package/dist/{chunk-7DUDLVFJ.js → chunk-6E2GJANQ.js} +20 -20
- package/dist/{chunk-RK6MKKKP.js → chunk-6N2GUZMZ.js} +1 -1
- package/dist/{chunk-LK44ULGI.js → chunk-6RGIM2ZH.js} +32 -6
- package/dist/{chunk-OS7PQ35Z.js → chunk-6V3DTQWK.js} +22 -22
- package/dist/{chunk-OSGQW2Z6.js → chunk-77RSRG3A.js} +8 -8
- package/dist/{chunk-5YIBJXGB.js → chunk-7A7IG7OA.js} +10 -10
- package/dist/{chunk-YLAJAI2W.js → chunk-7HQOZALR.js} +11 -11
- package/dist/{chunk-XB5RFZHH.js → chunk-7HWXYP4H.js} +12 -12
- package/dist/{chunk-PIVKU64W.js → chunk-7J7UY46S.js} +2 -2
- package/dist/{chunk-62YMDXY6.js → chunk-7KXYMC2P.js} +16 -16
- package/dist/{chunk-23M2LUYM.js → chunk-7LCQ7JAM.js} +1 -1
- package/dist/{chunk-5XN76FTF.js → chunk-7RGCQ4VZ.js} +5 -5
- package/dist/{chunk-CHC5FKTU.js → chunk-7RUMD56V.js} +1 -1
- package/dist/{chunk-IUD3ME4E.js → chunk-7S3XFWOU.js} +4 -4
- package/dist/{chunk-ZONE6E3Z.js → chunk-7SZPENUP.js} +2 -2
- package/dist/{chunk-T6USVBEJ.js → chunk-7VFVQX5K.js} +5 -5
- package/dist/chunk-ACWQDL6T.js +37 -0
- package/dist/{chunk-AKJTKMXU.js → chunk-ANCI3LFS.js} +5 -5
- package/dist/{chunk-B3O52AUQ.js → chunk-ASKDCMW5.js} +4 -4
- package/dist/chunk-ATNG5VOZ.js +122 -0
- package/dist/{chunk-I7IWQIEB.js → chunk-B3QOYE74.js} +4 -4
- package/dist/chunk-B3UHYXHU.js +41 -0
- package/dist/{chunk-GXJVY6WT.js → chunk-BA5DTXHQ.js} +5 -5
- package/dist/{chunk-5XDNUJ4P.js → chunk-BKFGGJKA.js} +2 -2
- package/dist/{chunk-DDAHCPGA.js → chunk-BQNEHB5U.js} +12 -12
- package/dist/{chunk-P3TKKBAH.js → chunk-BUWSOQLU.js} +4 -4
- package/dist/{chunk-X4W4XXWP.js → chunk-BX52REMA.js} +5 -5
- package/dist/{chunk-4SVJNVEE.js → chunk-BXBCMGIQ.js} +2 -0
- package/dist/{chunk-CRE4BJHM.js → chunk-C2YGYTU6.js} +23 -23
- package/dist/{chunk-7URGP4DD.js → chunk-C5JFMAXX.js} +12 -12
- package/dist/chunk-C75W7VXX.js +42 -0
- package/dist/{chunk-NGPU2ARF.js → chunk-CAN3EBE5.js} +1 -1
- package/dist/{chunk-FR7JPYBD.js → chunk-CE4S5ZY3.js} +12 -12
- package/dist/{chunk-BMHGA7WD.js → chunk-CRQ73DIF.js} +12 -12
- package/dist/{chunk-KIAI6PWL.js → chunk-CZI2ACNT.js} +17 -17
- package/dist/chunk-D7MWYJZF.js +43 -0
- package/dist/chunk-DDAEAZEV.js +54 -0
- package/dist/{chunk-G2E5MNYP.js → chunk-DGKNOPSE.js} +7 -7
- package/dist/{chunk-UF7TAFJM.js → chunk-DQNKG4HY.js} +18 -18
- package/dist/{chunk-6TJCUYC5.js → chunk-DS3ZEJVN.js} +3 -3
- package/dist/{chunk-3QAKDIEU.js → chunk-DYWTQXP4.js} +23 -23
- package/dist/chunk-E25G46RW.js +54 -0
- package/dist/{chunk-F2FOQLJ7.js → chunk-EAQFRD2B.js} +6 -6
- package/dist/{chunk-W5OYJMBT.js → chunk-EATSD7YD.js} +5 -5
- package/dist/{chunk-YGR6OCHQ.js → chunk-EBWIOODZ.js} +8 -14
- package/dist/{chunk-LVGBKKSM.js → chunk-EHUYLNLC.js} +15 -15
- package/dist/{chunk-IDGSU7JF.js → chunk-EI4KQYJ3.js} +9 -9
- package/dist/{chunk-FQSRHTTC.js → chunk-EQOSXLK3.js} +15 -15
- package/dist/{chunk-KC5DROFC.js → chunk-EV4TEFOD.js} +14 -14
- package/dist/{chunk-2KDSXJFJ.js → chunk-EW7MRMD5.js} +24 -6
- package/dist/{chunk-FZL2HNWP.js → chunk-EZSZFI54.js} +3 -3
- package/dist/{chunk-MKRBG5EF.js → chunk-FMRMTI7W.js} +1 -1
- package/dist/{chunk-E3JYO547.js → chunk-FOQXYMOR.js} +20 -20
- package/dist/{chunk-G5SFOH7P.js → chunk-G3PBLW4K.js} +8 -18
- package/dist/{chunk-2XM6PYQQ.js → chunk-G7WZH54P.js} +33 -11
- package/dist/{chunk-FTV6I76U.js → chunk-GG6HIU74.js} +25 -25
- package/dist/{chunk-6EDQE7GO.js → chunk-GMJXC5AL.js} +2 -2
- package/dist/chunk-GPLFYLGH.js +130 -0
- package/dist/{chunk-UR7RMZ3R.js → chunk-GVFUEGGM.js} +2 -2
- package/dist/{chunk-WGZWR4RF.js → chunk-GWSWS264.js} +5 -5
- package/dist/{chunk-NPCD54I7.js → chunk-H4VJO3M2.js} +8 -5
- package/dist/{chunk-73VPWF5R.js → chunk-HGQZTUAC.js} +4 -4
- package/dist/{chunk-2RX7PI2Y.js → chunk-HOUUBE74.js} +4 -4
- package/dist/{chunk-BDEKREZH.js → chunk-HQMCHHY5.js} +3 -3
- package/dist/{chunk-DPHCFZ7W.js → chunk-HR4DVO6X.js} +3 -3
- package/dist/chunk-HZYFLEWO.js +39 -0
- package/dist/chunk-IA2RKC6I.js +279 -0
- package/dist/{chunk-AY2IUF4K.js → chunk-IILZ7J3L.js} +541 -64
- package/dist/chunk-IRW64JFF.js +247 -0
- package/dist/{chunk-BJPMKJTL.js → chunk-IVHN2VYG.js} +100 -2
- package/dist/{chunk-OEI7LVRP.js → chunk-IWZPGIGT.js} +24 -24
- package/dist/{chunk-QICFHVRW.js → chunk-IY4PHPHT.js} +4 -4
- package/dist/{chunk-ZE3P35DA.js → chunk-J27QGXO4.js} +9 -9
- package/dist/{chunk-BMCKL3VQ.js → chunk-JBSD57N7.js} +24 -24
- package/dist/{chunk-67J3VZBA.js → chunk-JEUXCIRD.js} +5 -5
- package/dist/{chunk-577AJVRS.js → chunk-JMOLB347.js} +1976 -282
- package/dist/{chunk-7EKESFWV.js → chunk-JQX6BSE4.js} +11 -11
- package/dist/{chunk-YXJ4XOHF.js → chunk-JRPQX2EK.js} +4 -4
- package/dist/{chunk-MTEBM4Y4.js → chunk-JUQHYTXN.js} +18 -12
- package/dist/{chunk-APSVL2AI.js → chunk-JUZ75OG4.js} +15 -15
- package/dist/{chunk-7GB4ZRE2.js → chunk-KIWEBM6G.js} +12 -12
- package/dist/{chunk-KM2FBM3T.js → chunk-KLKENMWQ.js} +282 -50
- package/dist/chunk-KQK6SQPE.js +48 -0
- package/dist/{chunk-TM7LC37P.js → chunk-KQRYW7OS.js} +179 -115
- package/dist/{chunk-65C57N7P.js → chunk-KU4T2CXJ.js} +19 -19
- package/dist/{chunk-GFXLPJWY.js → chunk-KXZR2BLL.js} +2 -2
- package/dist/{chunk-MGVYVW7Q.js → chunk-L7I5PKGD.js} +1 -1
- package/dist/{chunk-XKS6THI5.js → chunk-LDIARP6F.js} +2 -2
- package/dist/{chunk-NNUASOAA.js → chunk-LEHZTKB3.js} +12 -12
- package/dist/{chunk-FJCFYKVO.js → chunk-LS3WR2RF.js} +86 -29
- package/dist/{chunk-Y4BRGOJR.js → chunk-LUPW4WLK.js} +13 -10
- package/dist/{chunk-HE4ZQXZM.js → chunk-LVBPY2M6.js} +14 -4
- package/dist/{chunk-EX6ZXS5K.js → chunk-LZWVK4YY.js} +4 -4
- package/dist/chunk-MCWWMMLN.js +48 -0
- package/dist/{chunk-BXIX7S7O.js → chunk-MKC7P5LD.js} +15 -15
- package/dist/{chunk-JQ7XQPQS.js → chunk-MKIULIUQ.js} +4 -4
- package/dist/{chunk-D3PO4DOZ.js → chunk-MMB2OHUY.js} +4 -2
- package/dist/{chunk-MTAUZW2Z.js → chunk-MQNBEO3N.js} +210 -104
- package/dist/{chunk-4PJADZRR.js → chunk-MSL3CLHX.js} +16 -16
- package/dist/{chunk-5KTOPOEP.js → chunk-MV4637YA.js} +25 -25
- package/dist/{chunk-WARBF2KY.js → chunk-MYKQVS5W.js} +4 -4
- package/dist/{chunk-4QUQEBFT.js → chunk-MYOW3RPC.js} +6 -6
- package/dist/{chunk-ROTY5J2L.js → chunk-NBGBMRIS.js} +1 -1
- package/dist/{chunk-BUYJL3GJ.js → chunk-NBQO75XT.js} +1 -1
- package/dist/chunk-NCR24CPV.js +41 -0
- package/dist/chunk-NDW4ROST.js +38 -0
- package/dist/{chunk-AWECWW5Y.js → chunk-NELU7LSL.js} +13 -11
- package/dist/{chunk-R64GLVBO.js → chunk-NG5R2WIY.js} +10 -10
- package/dist/{chunk-ZZXF6OOJ.js → chunk-NH5QH3WS.js} +2 -2
- package/dist/{chunk-XIWYUQZQ.js → chunk-NIYB5K5B.js} +9 -9
- package/dist/{chunk-LDKUC2QJ.js → chunk-NR5T46ZY.js} +17 -17
- package/dist/{chunk-PEF5OEMB.js → chunk-NX6QEEOA.js} +4 -4
- package/dist/{chunk-OGRWQ562.js → chunk-O6ILVBYB.js} +2 -2
- package/dist/{chunk-Y7KBQ4BD.js → chunk-OFWYZH6B.js} +22 -22
- package/dist/{chunk-N3NBWIYQ.js → chunk-OHXTB6CO.js} +11 -9
- package/dist/chunk-OJN7WME4.js +34 -0
- package/dist/{chunk-2HMWX4T6.js → chunk-OR5VRULZ.js} +11 -11
- package/dist/{chunk-UBWCUP3G.js → chunk-ORZSD2KD.js} +2 -2
- package/dist/{chunk-V2TH46ZY.js → chunk-OXVVRJDQ.js} +12 -12
- package/dist/{chunk-7YYEKTYF.js → chunk-PQW7PYUR.js} +8 -8
- package/dist/{chunk-EZIUFEN6.js → chunk-Q32Y5T2U.js} +12 -12
- package/dist/{chunk-FOGG4AUR.js → chunk-QWHTTA2X.js} +23 -7
- package/dist/{chunk-HKTUIMH4.js → chunk-R3RVFCJ2.js} +3 -3
- package/dist/{chunk-J5LHDJU4.js → chunk-R3VFLYZZ.js} +7 -7
- package/dist/{chunk-QKEFZRHS.js → chunk-R6UTCLH5.js} +17 -17
- package/dist/{chunk-SS66Q4VE.js → chunk-RB2VSED2.js} +12 -12
- package/dist/chunk-REWZE2XI.js +53 -0
- package/dist/{chunk-MF7QH4AX.js → chunk-RIEFYHXI.js} +5 -5
- package/dist/{chunk-7F2RUWPU.js → chunk-RJDP642F.js} +1 -1
- package/dist/{chunk-YFSSNGLR.js → chunk-RWMSJP7H.js} +31 -29
- package/dist/{chunk-JMSEEBN4.js → chunk-S2FDPN32.js} +1 -1
- package/dist/chunk-S5LSDXV4.js +40 -0
- package/dist/{chunk-OJLRFGBP.js → chunk-S7ZWCMDO.js} +79 -15
- package/dist/{chunk-ILFKECGI.js → chunk-SG5KY4VB.js} +4 -4
- package/dist/{chunk-FEZE6NIA.js → chunk-SH7AZZDA.js} +18 -18
- package/dist/{chunk-E3Z67HRK.js → chunk-SILY6ZEZ.js} +4 -4
- package/dist/{chunk-5IALSMZ2.js → chunk-SINJKQSI.js} +14 -14
- package/dist/chunk-SIUDWWKS.js +47 -0
- package/dist/{chunk-XEG3FE2R.js → chunk-SKMHS4CL.js} +1 -1
- package/dist/chunk-SNHOLLGN.js +280 -0
- package/dist/{chunk-LTQANUDH.js → chunk-SUQZGPVG.js} +25 -25
- package/dist/{chunk-47QE246J.js → chunk-T6ESD5KM.js} +5 -5
- package/dist/{chunk-YVLMBAYE.js → chunk-TC3KTG33.js} +3 -3
- package/dist/{chunk-IV7BCWWN.js → chunk-TCADP67G.js} +3 -3
- package/dist/{chunk-6JLPXDWN.js → chunk-TEBBD4XH.js} +5 -5
- package/dist/{chunk-F7UQR4ZX.js → chunk-TGEOLIAK.js} +3 -3
- package/dist/{chunk-FMKKVWZD.js → chunk-TQYBXDVH.js} +2 -2
- package/dist/{chunk-TZDSDDSV.js → chunk-TZXHUDI6.js} +2 -2
- package/dist/{chunk-YMOJD5BO.js → chunk-U5PDQTLA.js} +3 -3
- package/dist/{chunk-CNKGYDMG.js → chunk-U6YKL7SI.js} +23 -23
- package/dist/{chunk-7UKVYFQ2.js → chunk-UABFFMWH.js} +8 -8
- package/dist/{chunk-XPEEICAO.js → chunk-UFBKJOWB.js} +15 -15
- package/dist/chunk-UFTQIK2J.js +43 -0
- package/dist/{chunk-ZP4FJHR4.js → chunk-UNFCFJMF.js} +18 -18
- package/dist/{chunk-IZNSAEBX.js → chunk-UTR67XU2.js} +2 -2
- package/dist/{chunk-6GWHKMQR.js → chunk-V4XKYGLK.js} +4 -4
- package/dist/{chunk-ISNZYKAS.js → chunk-VYNZED7B.js} +21 -21
- package/dist/{chunk-FV5YFR6I.js → chunk-WCLAOKCH.js} +9 -9
- package/dist/chunk-WFYHOXTB.js +29 -0
- package/dist/{chunk-QWVBEK4P.js → chunk-WGU6NIUV.js} +13 -13
- package/dist/{chunk-R4TBNKKC.js → chunk-WIMOJMAK.js} +974 -489
- package/dist/{chunk-XKZHAD6Y.js → chunk-WKXOEIOY.js} +15 -15
- package/dist/chunk-WUE6HKIU.js +790 -0
- package/dist/{chunk-R6B6XAKK.js → chunk-WUP77GG2.js} +4 -4
- package/dist/{chunk-RRVT4MPS.js → chunk-XF3DATVU.js} +18 -18
- package/dist/{chunk-KIHOIVST.js → chunk-XJAJQGXJ.js} +3 -3
- package/dist/{chunk-Y5PZHS4K.js → chunk-XKJRPVJO.js} +5 -5
- package/dist/{chunk-N4QZJJVB.js → chunk-XNRPCI23.js} +5 -5
- package/dist/{chunk-XNYNEEBR.js → chunk-XOVLGBKI.js} +18 -18
- package/dist/{chunk-GR6YKM55.js → chunk-XPJR74MA.js} +95 -13
- package/dist/{chunk-4GZXS6S2.js → chunk-XPWSNKF3.js} +226 -8
- package/dist/{chunk-LRS573EX.js → chunk-XR5DD5DQ.js} +4 -4
- package/dist/{chunk-PGKHJYOB.js → chunk-XZJE6WIT.js} +1 -1
- package/dist/{chunk-3GTZ2OON.js → chunk-Y5AYBGLB.js} +16 -10
- package/dist/{chunk-OIU657QQ.js → chunk-YLAM4HZH.js} +4 -4
- package/dist/{chunk-JF2NSTFO.js → chunk-YVCOQ5TZ.js} +3 -3
- package/dist/{chunk-F7YL2RZ4.js → chunk-YWOMGMZB.js} +23 -23
- package/dist/{chunk-WLIIQ2A4.js → chunk-YWZDAZMA.js} +7 -7
- package/dist/{chunk-JAA53T23.js → chunk-Z2EYRUOH.js} +20 -20
- package/dist/{chunk-UYYN2IUZ.js → chunk-Z46OXTBE.js} +6 -6
- package/dist/chunk-ZHWSL6SR.js +45 -0
- package/dist/chunk-ZJQUIG3A.js +87 -0
- package/dist/{chunk-T4RTWMJD.js → chunk-ZKUDS7JG.js} +5 -5
- package/dist/{chunk-HHUFVJF7.js → chunk-ZTNS3L5Z.js} +6 -6
- package/dist/files.json +471 -423
- package/dist/packages/sdk/npm/index.js +2300 -1983
- package/dist/packages/ui/dist/assets/{elk-api-Mo5w5xCa.js → elk-api-DDup23Us.js} +2 -2
- package/dist/packages/ui/dist/assets/{index-Bp3XhPHX.css → index-C0JEkXyN.css} +1 -1
- package/dist/packages/ui/dist/assets/index-mTOWhQZm.js +29 -0
- package/dist/packages/ui/dist/index.html +2 -2
- package/package.json +5 -5
- 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-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/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-5V5BJACL.js";
|
|
16
16
|
import {
|
|
17
17
|
openapiExtractor,
|
|
18
18
|
readOpenApiDocument
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-GVFUEGGM.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-BKFGGJKA.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-JMOLB347.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";
|
|
@@ -168,6 +168,10 @@ function classify(fileName, bytes) {
|
|
|
168
168
|
return { classification: "diagram" };
|
|
169
169
|
if (/^<(!doctype html|html)\b/i.test(head))
|
|
170
170
|
return { classification: "document" };
|
|
171
|
+
if (ext === "proto" || /^(syntax\s*=\s*["']proto[23]["']|package\s+[\w.]+\s*;)/m.test(head))
|
|
172
|
+
return { classification: "protobuf" };
|
|
173
|
+
if (ext === "avsc" || /^\{/.test(head) && /"type"\s*:\s*"record"/.test(head) && /"fields"\s*:/.test(head))
|
|
174
|
+
return { classification: "avro" };
|
|
171
175
|
if (["json", "yaml", "yml"].includes(ext) || /^[[{]/.test(head)) {
|
|
172
176
|
let data;
|
|
173
177
|
try {
|
|
@@ -200,7 +204,10 @@ import { createHash } from "node:crypto";
|
|
|
200
204
|
var READERS = {
|
|
201
205
|
openapi: `${openapiExtractor.id}@${openapiExtractor.version}`,
|
|
202
206
|
asyncapi: "asyncapi@0.1.0",
|
|
203
|
-
payload: "payload@0.1.0"
|
|
207
|
+
payload: "payload@0.1.0",
|
|
208
|
+
// ADR 0164: a topic's message spec.
|
|
209
|
+
protobuf: "protobuf@0.1.0",
|
|
210
|
+
avro: "avro@0.1.0"
|
|
204
211
|
};
|
|
205
212
|
var short = (s) => createHash("sha256").update(s).digest("hex").slice(0, 6);
|
|
206
213
|
function oneFile(path, text3) {
|
|
@@ -416,9 +423,9 @@ var opt = {
|
|
|
416
423
|
};
|
|
417
424
|
|
|
418
425
|
// 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";
|
|
426
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
427
|
+
import { readdir as readdir2, readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
428
|
+
import { join as join2, relative, resolve, sep } from "node:path";
|
|
422
429
|
|
|
423
430
|
// packages/intake/dist/screen-file.js
|
|
424
431
|
var PK = (b) => b[0] === 80 && b[1] === 75;
|
|
@@ -460,10 +467,314 @@ function screenFile(path, bytes) {
|
|
|
460
467
|
}
|
|
461
468
|
}
|
|
462
469
|
|
|
470
|
+
// packages/intake/dist/contract-specs.js
|
|
471
|
+
var import_yaml4 = __toESM(require_dist(), 1);
|
|
472
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
473
|
+
import { join } from "node:path";
|
|
474
|
+
|
|
475
|
+
// packages/intake/dist/traffic.js
|
|
476
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
477
|
+
var cmp = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
478
|
+
var key = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
479
|
+
var sha = (s) => createHash3("sha256").update(s, "utf8").digest("hex");
|
|
480
|
+
var IPV4 = /\b\d{1,3}(?:\.\d{1,3}){3}\b/;
|
|
481
|
+
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;
|
|
482
|
+
var EMAIL = /[^\s@/]+@[^\s@/]+/;
|
|
483
|
+
var JWT = /\beyJ[A-Za-z0-9_-]{6,}/;
|
|
484
|
+
var OPAQUE = /\b(?=[A-Za-z0-9+_-]*\d)(?=[A-Za-z0-9+_-]*[A-Za-z])[A-Za-z0-9+_-]{24,}={0,2}/;
|
|
485
|
+
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;
|
|
486
|
+
var HEX = /\b[0-9a-f]{16,}\b/i;
|
|
487
|
+
function looksSensitive(v) {
|
|
488
|
+
return [IPV4, IPV6, EMAIL, JWT, OPAQUE, UUID, HEX].some((re) => re.test(v));
|
|
489
|
+
}
|
|
490
|
+
function rowsOf(text3) {
|
|
491
|
+
const t = text3.replace(/^\uFEFF/, "").trim();
|
|
492
|
+
if (!t)
|
|
493
|
+
return void 0;
|
|
494
|
+
if (t.startsWith("[") || t.startsWith("{")) {
|
|
495
|
+
let v;
|
|
496
|
+
try {
|
|
497
|
+
v = JSON.parse(t);
|
|
498
|
+
} catch {
|
|
499
|
+
return void 0;
|
|
500
|
+
}
|
|
501
|
+
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;
|
|
502
|
+
if (!Array.isArray(list2) || !list2.length)
|
|
503
|
+
return void 0;
|
|
504
|
+
const out = [];
|
|
505
|
+
for (const r of list2) {
|
|
506
|
+
if (!r || typeof r !== "object" || Array.isArray(r))
|
|
507
|
+
return void 0;
|
|
508
|
+
const row = {};
|
|
509
|
+
for (const [k, x] of Object.entries(r))
|
|
510
|
+
if (typeof x === "string" || typeof x === "number")
|
|
511
|
+
row[k] = String(x);
|
|
512
|
+
out.push(row);
|
|
513
|
+
}
|
|
514
|
+
return out;
|
|
515
|
+
}
|
|
516
|
+
const recs = parseCsv(t);
|
|
517
|
+
if (recs.length < 2)
|
|
518
|
+
return void 0;
|
|
519
|
+
const head = recs[0].cells.map((c) => c.trim());
|
|
520
|
+
if (head.length < 2)
|
|
521
|
+
return void 0;
|
|
522
|
+
return recs.slice(1).map((r) => {
|
|
523
|
+
const row = {};
|
|
524
|
+
head.forEach((h, i) => row[h] = (r.cells[i] ?? "").trim());
|
|
525
|
+
return row;
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
function dayOf(v) {
|
|
529
|
+
const m = /^(\d{4}-\d{2}-\d{2})/.exec(v.trim());
|
|
530
|
+
if (m)
|
|
531
|
+
return m[1];
|
|
532
|
+
if (/^\d{12,13}$/.test(v.trim()))
|
|
533
|
+
return new Date(Number(v)).toISOString().slice(0, 10);
|
|
534
|
+
return void 0;
|
|
535
|
+
}
|
|
536
|
+
var VERSION = /^v\d+(?:\.\d+)*$/i;
|
|
537
|
+
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}>)$/;
|
|
538
|
+
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}";
|
|
539
|
+
function barePath(path) {
|
|
540
|
+
let p = path.trim().split(/[?#]/, 1)[0] ?? "";
|
|
541
|
+
p = p.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]*/i, "");
|
|
542
|
+
return p.replace(/;[^/]*/g, "");
|
|
543
|
+
}
|
|
544
|
+
function safePathOf(path) {
|
|
545
|
+
const p = barePath(path);
|
|
546
|
+
if (!p.startsWith("/"))
|
|
547
|
+
return void 0;
|
|
548
|
+
return `/${p.split("/").filter(Boolean).map(segmentOf).join("/")}`;
|
|
549
|
+
}
|
|
550
|
+
var MATCH = 100;
|
|
551
|
+
function pathTemplateOf(path, templates) {
|
|
552
|
+
const p = barePath(path);
|
|
553
|
+
if (!p.startsWith("/"))
|
|
554
|
+
return void 0;
|
|
555
|
+
const sorted2 = [...templates].sort();
|
|
556
|
+
let best;
|
|
557
|
+
let score = 0;
|
|
558
|
+
for (const t of sorted2) {
|
|
559
|
+
const s = routeScore(p, t);
|
|
560
|
+
if (s > MATCH && s > score) {
|
|
561
|
+
score = s;
|
|
562
|
+
best = t;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
if (best)
|
|
566
|
+
return best;
|
|
567
|
+
const segs = p.split("/").filter(Boolean);
|
|
568
|
+
let prefix;
|
|
569
|
+
let len = 0;
|
|
570
|
+
score = 0;
|
|
571
|
+
for (const t of sorted2) {
|
|
572
|
+
const n = t.split("/").filter(Boolean).length;
|
|
573
|
+
if (n === 0 || n >= segs.length || n < len)
|
|
574
|
+
continue;
|
|
575
|
+
const s = routeScore(`/${segs.slice(0, n).join("/")}`, t);
|
|
576
|
+
if (s <= MATCH)
|
|
577
|
+
continue;
|
|
578
|
+
if (n > len || s > score) {
|
|
579
|
+
len = n;
|
|
580
|
+
score = s;
|
|
581
|
+
prefix = t;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return prefix ? `${prefix.replace(/\/+$/, "")}/**` : void 0;
|
|
585
|
+
}
|
|
586
|
+
var appLabelOf = (name) => `app-${sha(name).slice(0, 8)}`;
|
|
587
|
+
function denyListHits(text3, hashes) {
|
|
588
|
+
const hits = [];
|
|
589
|
+
text3.toLowerCase().split("\n").forEach((line, i) => {
|
|
590
|
+
const w = line.match(/[a-z0-9]+/g) ?? [];
|
|
591
|
+
for (let k = 0; k < w.length; k++)
|
|
592
|
+
if (hashes.has(sha(w[k])) || k + 1 < w.length && hashes.has(sha(`${w[k]} ${w[k + 1]}`))) {
|
|
593
|
+
hits.push(i + 1);
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
return hits;
|
|
598
|
+
}
|
|
599
|
+
function aggregateTraffic(input) {
|
|
600
|
+
const text3 = Buffer.from(input.bytes).toString("utf8");
|
|
601
|
+
const rows = rowsOf(text3);
|
|
602
|
+
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("/")})`;
|
|
603
|
+
if (!rows)
|
|
604
|
+
return { ok: false, message: `The file doesn't read as a traffic export: give ${shape}.` };
|
|
605
|
+
const names = [...new Set(rows.flatMap((r) => Object.keys(r)))];
|
|
606
|
+
const col = (aliases) => {
|
|
607
|
+
for (const a of aliases) {
|
|
608
|
+
const hit = names.find((n) => key(n) === key(a));
|
|
609
|
+
if (hit)
|
|
610
|
+
return hit;
|
|
611
|
+
}
|
|
612
|
+
return void 0;
|
|
613
|
+
};
|
|
614
|
+
const c = {
|
|
615
|
+
app: col(input.columns.app),
|
|
616
|
+
method: col(input.columns.method),
|
|
617
|
+
basepath: col(input.columns.basepath),
|
|
618
|
+
suffix: col(input.columns.suffix),
|
|
619
|
+
proxy: col(input.columns.proxy),
|
|
620
|
+
count: col(input.columns.count),
|
|
621
|
+
time: col(input.columns.time),
|
|
622
|
+
path: void 0
|
|
623
|
+
};
|
|
624
|
+
if (!c.basepath || !c.suffix)
|
|
625
|
+
c.path = col(input.columns.path);
|
|
626
|
+
const missing = [
|
|
627
|
+
!c.app ? "app" : "",
|
|
628
|
+
!c.method ? "method" : "",
|
|
629
|
+
!c.path && !(c.basepath && c.suffix) ? "path" : ""
|
|
630
|
+
].filter(Boolean);
|
|
631
|
+
if (missing.length)
|
|
632
|
+
return {
|
|
633
|
+
ok: false,
|
|
634
|
+
message: `The file has no ${missing.join(", ")} column, so it can't be kept as aggregates: give ${shape}.`
|
|
635
|
+
};
|
|
636
|
+
const range = (v) => v && /^\d{4}-\d{2}-\d{2}$/.test(v) ? v : void 0;
|
|
637
|
+
if (input.from && !range(input.from) || input.to && !range(input.to))
|
|
638
|
+
return { ok: false, message: "--from and --to are days: YYYY-MM-DD." };
|
|
639
|
+
if ((!input.from || !input.to) && !c.time)
|
|
640
|
+
return {
|
|
641
|
+
ok: false,
|
|
642
|
+
message: "The export has no date column: give --from and --to (YYYY-MM-DD) for the range it covers."
|
|
643
|
+
};
|
|
644
|
+
const kept = new Set(Object.values(c).filter((x) => !!x));
|
|
645
|
+
const dropped = names.filter((n) => !kept.has(n)).sort();
|
|
646
|
+
const secrets = /* @__PURE__ */ new Set();
|
|
647
|
+
const keptValues = /* @__PURE__ */ new Set();
|
|
648
|
+
const agg = /* @__PURE__ */ new Map();
|
|
649
|
+
let outOfRange = 0;
|
|
650
|
+
let skipped2 = 0;
|
|
651
|
+
let unmatched = 0;
|
|
652
|
+
const known = /* @__PURE__ */ new Map();
|
|
653
|
+
for (const a of input.apps ?? [])
|
|
654
|
+
if (a.trim() && !known.has(key(a)))
|
|
655
|
+
known.set(key(a), a.trim());
|
|
656
|
+
const days = [];
|
|
657
|
+
for (const r of rows) {
|
|
658
|
+
for (const n of dropped) {
|
|
659
|
+
const v = (r[n] ?? "").trim();
|
|
660
|
+
const q = /^(?:[a-z][a-z0-9+.-]*:\/\/|\/)/i.test(v) ? v.split(/[?#]/)[1] ?? "" : v;
|
|
661
|
+
if (q.length >= 6)
|
|
662
|
+
secrets.add(q);
|
|
663
|
+
}
|
|
664
|
+
for (const n of [c.path, c.suffix, c.basepath]) {
|
|
665
|
+
const v = n ? r[n] ?? "" : "";
|
|
666
|
+
const q = v.split(/[?#]/)[1] ?? "";
|
|
667
|
+
if (q.length >= 4)
|
|
668
|
+
secrets.add(q);
|
|
669
|
+
for (const m of (v.split(/[?#]/, 1)[0] ?? "").match(/;[^/]*/g) ?? [])
|
|
670
|
+
if (m.length >= 5)
|
|
671
|
+
secrets.add(m.slice(1));
|
|
672
|
+
}
|
|
673
|
+
if (c.time) {
|
|
674
|
+
const d = dayOf(r[c.time] ?? "");
|
|
675
|
+
if (d) {
|
|
676
|
+
if (input.from && d < input.from || input.to && d > input.to) {
|
|
677
|
+
outOfRange++;
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
days.push(d);
|
|
681
|
+
} else if (!input.from || !input.to) {
|
|
682
|
+
skipped2++;
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
const method = (r[c.method] ?? "").trim().toUpperCase();
|
|
687
|
+
const rawPath = c.path ? r[c.path] ?? "" : `${(r[c.basepath] ?? "").replace(/\/+$/, "")}/${(r[c.suffix] ?? "").replace(/^\/+/, "")}`;
|
|
688
|
+
const countText = c.count ? (r[c.count] ?? "").trim() : "1";
|
|
689
|
+
const count = Number(countText);
|
|
690
|
+
if (!/^[A-Z]{3,10}$/.test(method) || !barePath(rawPath).startsWith("/") || !Number.isInteger(count) || count < 0) {
|
|
691
|
+
skipped2++;
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
const path = pathTemplateOf(rawPath, input.templates);
|
|
695
|
+
if (!path) {
|
|
696
|
+
unmatched++;
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
if (count === 0)
|
|
700
|
+
continue;
|
|
701
|
+
const appRaw = (r[c.app] ?? "").trim();
|
|
702
|
+
const app = !appRaw ? "(none)" : known.get(key(appRaw)) ?? appLabelOf(appRaw);
|
|
703
|
+
const proxyRaw = c.proxy ? (r[c.proxy] ?? "").trim() : "";
|
|
704
|
+
const proxy = proxyRaw && !looksSensitive(proxyRaw) ? proxyRaw : void 0;
|
|
705
|
+
const baseRaw = c.basepath ? (r[c.basepath] ?? "").trim() : "";
|
|
706
|
+
const basepath = baseRaw ? safePathOf(baseRaw) : void 0;
|
|
707
|
+
for (const v of [app, proxy, basepath, path])
|
|
708
|
+
if (v)
|
|
709
|
+
keptValues.add(v);
|
|
710
|
+
const k = [app, method, path, proxy ?? "", basepath ?? ""].join("\0");
|
|
711
|
+
const row = agg.get(k) ?? {
|
|
712
|
+
app,
|
|
713
|
+
method,
|
|
714
|
+
path,
|
|
715
|
+
...proxy ? { proxy } : {},
|
|
716
|
+
...basepath ? { basepath } : {},
|
|
717
|
+
count: 0
|
|
718
|
+
};
|
|
719
|
+
row.count += count;
|
|
720
|
+
agg.set(k, row);
|
|
721
|
+
}
|
|
722
|
+
if (!agg.size)
|
|
723
|
+
return {
|
|
724
|
+
ok: false,
|
|
725
|
+
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.`
|
|
726
|
+
};
|
|
727
|
+
days.sort();
|
|
728
|
+
const from = input.from ?? days[0];
|
|
729
|
+
const to = input.to ?? days[days.length - 1];
|
|
730
|
+
if (!from || !to)
|
|
731
|
+
return { ok: false, message: "The rows carry no dates: give --from and --to (YYYY-MM-DD)." };
|
|
732
|
+
const parsed = TrafficFile.safeParse({
|
|
733
|
+
schemaVersion: 1,
|
|
734
|
+
source: input.source,
|
|
735
|
+
from,
|
|
736
|
+
to,
|
|
737
|
+
inputSha256: createHash3("sha256").update(input.bytes).digest("hex"),
|
|
738
|
+
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))
|
|
739
|
+
});
|
|
740
|
+
if (!parsed.success)
|
|
741
|
+
return { ok: false, message: `The aggregate isn't valid: ${parsed.error.issues[0]?.message}.` };
|
|
742
|
+
const out = trafficFileText(parsed.data);
|
|
743
|
+
const lower = out.toLowerCase();
|
|
744
|
+
const leaked = [...secrets].filter((s) => !keptValues.has(s) && lower.includes(s.toLowerCase()));
|
|
745
|
+
if (leaked.length)
|
|
746
|
+
return {
|
|
747
|
+
ok: false,
|
|
748
|
+
message: `Refused: ${leaked.length} value${leaked.length === 1 ? "" : "s"} of the export's dropped columns would be written. Nothing was written.`
|
|
749
|
+
};
|
|
750
|
+
const body = out.replace(/^inputSha256: .*$/m, "");
|
|
751
|
+
if ([IPV4, IPV6, EMAIL, JWT, OPAQUE, UUID, HEX].some((re) => re.test(body)))
|
|
752
|
+
return {
|
|
753
|
+
ok: false,
|
|
754
|
+
message: "Refused: the aggregate would hold an IP, an email or a token-looking value. Nothing was written."
|
|
755
|
+
};
|
|
756
|
+
const hits = input.denyHashes?.size ? denyListHits(out, input.denyHashes) : [];
|
|
757
|
+
if (hits.length)
|
|
758
|
+
return {
|
|
759
|
+
ok: false,
|
|
760
|
+
message: `Refused: the deny-list names a word on line${hits.length === 1 ? "" : "s"} ${hits.join(", ")} of the aggregate. Nothing was written.`
|
|
761
|
+
};
|
|
762
|
+
return {
|
|
763
|
+
ok: true,
|
|
764
|
+
file: parsed.data,
|
|
765
|
+
text: out,
|
|
766
|
+
read: rows.length,
|
|
767
|
+
outOfRange,
|
|
768
|
+
skipped: skipped2,
|
|
769
|
+
unmatched,
|
|
770
|
+
dropped
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
|
|
463
774
|
// packages/intake/dist/vendor-ops.js
|
|
464
775
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
465
|
-
import { createHash as
|
|
466
|
-
var short2 = (s) =>
|
|
776
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
777
|
+
var short2 = (s) => createHash4("sha256").update(s).digest("hex").slice(0, 6);
|
|
467
778
|
function specEndpointIds(component, ops) {
|
|
468
779
|
const ids = ops.map((o) => endpointId(component, o.method, o.normalizedPath));
|
|
469
780
|
const count = /* @__PURE__ */ new Map();
|
|
@@ -775,12 +1086,442 @@ function operationSchemas(spec) {
|
|
|
775
1086
|
});
|
|
776
1087
|
}
|
|
777
1088
|
|
|
1089
|
+
// packages/intake/dist/contract-specs.js
|
|
1090
|
+
var MAX_BYTES = 1024 * 1024;
|
|
1091
|
+
var SKIP = /* @__PURE__ */ new Set([
|
|
1092
|
+
".git",
|
|
1093
|
+
"node_modules",
|
|
1094
|
+
"vendor",
|
|
1095
|
+
"target",
|
|
1096
|
+
"build",
|
|
1097
|
+
"dist",
|
|
1098
|
+
"out",
|
|
1099
|
+
"bin",
|
|
1100
|
+
"obj",
|
|
1101
|
+
".gradle",
|
|
1102
|
+
".idea",
|
|
1103
|
+
".venv",
|
|
1104
|
+
"__pycache__"
|
|
1105
|
+
]);
|
|
1106
|
+
var cmp2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
1107
|
+
function readProtoSpecs(path, text3) {
|
|
1108
|
+
const proto3 = /^\s*syntax\s*=\s*["']proto3["']/m.test(text3);
|
|
1109
|
+
let pkg = "";
|
|
1110
|
+
const out = [];
|
|
1111
|
+
const stack = [];
|
|
1112
|
+
let inComment = false;
|
|
1113
|
+
text3.split(/\r?\n/).forEach((raw, i) => {
|
|
1114
|
+
let line = raw;
|
|
1115
|
+
if (inComment) {
|
|
1116
|
+
const end = line.indexOf("*/");
|
|
1117
|
+
if (end < 0)
|
|
1118
|
+
return;
|
|
1119
|
+
line = line.slice(end + 2);
|
|
1120
|
+
inComment = false;
|
|
1121
|
+
}
|
|
1122
|
+
line = line.replace(/\/\*.*?\*\//g, "").replace(/\/\/.*$/, "");
|
|
1123
|
+
const open = line.indexOf("/*");
|
|
1124
|
+
if (open >= 0) {
|
|
1125
|
+
inComment = true;
|
|
1126
|
+
line = line.slice(0, open);
|
|
1127
|
+
}
|
|
1128
|
+
const n = i + 1;
|
|
1129
|
+
const p = /^\s*package\s+([\w.]+)\s*;/.exec(line);
|
|
1130
|
+
if (p)
|
|
1131
|
+
pkg = p[1];
|
|
1132
|
+
const message = /^\s*message\s+(\w+)\s*\{/.exec(line);
|
|
1133
|
+
const oneof = /^\s*oneof\s+(\w+)\s*\{/.exec(line);
|
|
1134
|
+
const other = /^\s*(enum|service|extend|extensions)\b[^{]*\{/.exec(line);
|
|
1135
|
+
let rest = line;
|
|
1136
|
+
if (message) {
|
|
1137
|
+
const outer = stack.filter((f) => f.kind === "message").map((f) => f.name);
|
|
1138
|
+
const name = [...outer, message[1]].join(".");
|
|
1139
|
+
const spec = {
|
|
1140
|
+
kind: "message",
|
|
1141
|
+
format: "protobuf",
|
|
1142
|
+
role: "schema",
|
|
1143
|
+
file: path,
|
|
1144
|
+
line: n,
|
|
1145
|
+
name: pkg ? `${pkg}.${name}` : name,
|
|
1146
|
+
fields: []
|
|
1147
|
+
};
|
|
1148
|
+
out.push(spec);
|
|
1149
|
+
stack.push({ kind: "message", name: message[1], spec });
|
|
1150
|
+
rest = line.slice(line.indexOf("{") + 1);
|
|
1151
|
+
} else if (oneof || other) {
|
|
1152
|
+
stack.push({ kind: oneof ? "oneof" : "other", name: "" });
|
|
1153
|
+
rest = line.slice(line.indexOf("{") + 1);
|
|
1154
|
+
} else {
|
|
1155
|
+
const top = stack.at(-1);
|
|
1156
|
+
const owner = top?.kind === "message" ? top : top?.kind === "oneof" ? stack.at(-2) : void 0;
|
|
1157
|
+
const f = /^\s*(optional|required|repeated)?\s*(map\s*<[^>]+>|[\w.]+)\s+(\w+)\s*=\s*(\d+)\s*(\[[^\]]*\])?\s*;/.exec(line);
|
|
1158
|
+
if (f && owner?.kind === "message" && owner.spec && !["reserved", "option"].includes(f[2])) {
|
|
1159
|
+
const label = f[1];
|
|
1160
|
+
owner.spec.fields.push({
|
|
1161
|
+
side: "message",
|
|
1162
|
+
name: f[3],
|
|
1163
|
+
type: label === "repeated" ? `repeated ${f[2]}` : f[2].replace(/\s+/g, ""),
|
|
1164
|
+
// proto2's `required` must be there; anything else may be left out (proto3 has no required).
|
|
1165
|
+
required: label === "required" && !proto3,
|
|
1166
|
+
number: Number(f[4]),
|
|
1167
|
+
at: `${path}:${n}`
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
for (const _ of rest.matchAll(/\}/g))
|
|
1172
|
+
stack.pop();
|
|
1173
|
+
});
|
|
1174
|
+
return out;
|
|
1175
|
+
}
|
|
1176
|
+
function lineOfName(lines, from, name) {
|
|
1177
|
+
const re = new RegExp(`"name"\\s*:\\s*"${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"`);
|
|
1178
|
+
for (let i = Math.max(0, from); i < lines.length; i++)
|
|
1179
|
+
if (re.test(lines[i]))
|
|
1180
|
+
return i + 1;
|
|
1181
|
+
return from + 1;
|
|
1182
|
+
}
|
|
1183
|
+
function readAvroSpecs(path, text3) {
|
|
1184
|
+
let data;
|
|
1185
|
+
try {
|
|
1186
|
+
data = JSON.parse(text3);
|
|
1187
|
+
} catch {
|
|
1188
|
+
return [];
|
|
1189
|
+
}
|
|
1190
|
+
const lines = text3.split(/\r?\n/);
|
|
1191
|
+
const out = [];
|
|
1192
|
+
let cursor = 0;
|
|
1193
|
+
const typeName = (t) => {
|
|
1194
|
+
if (typeof t === "string")
|
|
1195
|
+
return t;
|
|
1196
|
+
if (Array.isArray(t))
|
|
1197
|
+
return t.map(typeName).join("|");
|
|
1198
|
+
if (t && typeof t === "object") {
|
|
1199
|
+
const o = t;
|
|
1200
|
+
if (o.type === "array")
|
|
1201
|
+
return `repeated ${typeName(o.items)}`;
|
|
1202
|
+
if (o.type === "map")
|
|
1203
|
+
return `map<string,${typeName(o.values)}>`;
|
|
1204
|
+
if (typeof o.logicalType === "string")
|
|
1205
|
+
return String(o.type);
|
|
1206
|
+
if (typeof o.name === "string")
|
|
1207
|
+
return o.name;
|
|
1208
|
+
return typeName(o.type);
|
|
1209
|
+
}
|
|
1210
|
+
return "";
|
|
1211
|
+
};
|
|
1212
|
+
const record = (r, ns) => {
|
|
1213
|
+
if (r.type !== "record" || typeof r.name !== "string" || !Array.isArray(r.fields))
|
|
1214
|
+
return;
|
|
1215
|
+
const space = typeof r.namespace === "string" ? r.namespace : ns;
|
|
1216
|
+
const line = lineOfName(lines, cursor, r.name);
|
|
1217
|
+
cursor = line;
|
|
1218
|
+
const spec = {
|
|
1219
|
+
kind: "message",
|
|
1220
|
+
format: "avro",
|
|
1221
|
+
role: "schema",
|
|
1222
|
+
file: path,
|
|
1223
|
+
line,
|
|
1224
|
+
name: space ? `${space}.${r.name}` : r.name,
|
|
1225
|
+
fields: []
|
|
1226
|
+
};
|
|
1227
|
+
out.push(spec);
|
|
1228
|
+
r.fields.forEach((f, i) => {
|
|
1229
|
+
if (!f || typeof f !== "object")
|
|
1230
|
+
return;
|
|
1231
|
+
const x = f;
|
|
1232
|
+
if (typeof x.name !== "string")
|
|
1233
|
+
return;
|
|
1234
|
+
const at = lineOfName(lines, cursor, x.name);
|
|
1235
|
+
cursor = at;
|
|
1236
|
+
const nullable = Array.isArray(x.type) && x.type.includes("null");
|
|
1237
|
+
const type = typeName(Array.isArray(x.type) ? x.type.filter((t) => t !== "null") : x.type);
|
|
1238
|
+
spec.fields.push({
|
|
1239
|
+
side: "message",
|
|
1240
|
+
name: x.name,
|
|
1241
|
+
...type ? { type } : {},
|
|
1242
|
+
required: !nullable && !("default" in x),
|
|
1243
|
+
number: i,
|
|
1244
|
+
at: `${path}:${at}`
|
|
1245
|
+
});
|
|
1246
|
+
const inner = Array.isArray(x.type) ? x.type : [x.type];
|
|
1247
|
+
for (const t of inner)
|
|
1248
|
+
if (t && typeof t === "object")
|
|
1249
|
+
record(t, space);
|
|
1250
|
+
});
|
|
1251
|
+
};
|
|
1252
|
+
for (const r of Array.isArray(data) ? data : [data])
|
|
1253
|
+
if (r && typeof r === "object")
|
|
1254
|
+
record(r, "");
|
|
1255
|
+
return out;
|
|
1256
|
+
}
|
|
1257
|
+
var lineAt = (d, node) => {
|
|
1258
|
+
const r = node?.range;
|
|
1259
|
+
return r ? d.lc.linePos(r[0]).line : 1;
|
|
1260
|
+
};
|
|
1261
|
+
function deref2(d, node, depth = 0) {
|
|
1262
|
+
if (!(0, import_yaml4.isMap)(node) || depth > 8)
|
|
1263
|
+
return node;
|
|
1264
|
+
const ref = node.get("$ref");
|
|
1265
|
+
if (typeof ref !== "string" || !ref.startsWith("#/"))
|
|
1266
|
+
return node;
|
|
1267
|
+
let at = d.root;
|
|
1268
|
+
for (const p of ref.slice(2).split("/"))
|
|
1269
|
+
at = (0, import_yaml4.isMap)(at) ? at.get(p.replace(/~1/g, "/").replace(/~0/g, "~"), true) : void 0;
|
|
1270
|
+
return deref2(d, at, depth + 1);
|
|
1271
|
+
}
|
|
1272
|
+
function propsOf(d, schema, prefix, depth, out) {
|
|
1273
|
+
const s = deref2(d, schema);
|
|
1274
|
+
if (!(0, import_yaml4.isMap)(s) || depth > 6)
|
|
1275
|
+
return;
|
|
1276
|
+
const props = s.get("properties", true);
|
|
1277
|
+
const req = s.get("required", true);
|
|
1278
|
+
const required = new Set((0, import_yaml4.isSeq)(req) ? req.items.map((x) => (0, import_yaml4.isScalar)(x) ? String(x.value) : "") : []);
|
|
1279
|
+
if (!(0, import_yaml4.isMap)(props))
|
|
1280
|
+
return;
|
|
1281
|
+
for (const p of props.items) {
|
|
1282
|
+
if (!(0, import_yaml4.isScalar)(p.key))
|
|
1283
|
+
continue;
|
|
1284
|
+
const name = prefix ? `${prefix}.${String(p.key.value)}` : String(p.key.value);
|
|
1285
|
+
const v = deref2(d, p.value);
|
|
1286
|
+
const type = (0, import_yaml4.isMap)(v) ? v.get("type") : void 0;
|
|
1287
|
+
out.push({
|
|
1288
|
+
side: "message",
|
|
1289
|
+
name,
|
|
1290
|
+
...typeof type === "string" ? { type } : {},
|
|
1291
|
+
required: required.has(String(p.key.value)),
|
|
1292
|
+
at: `${d.path}:${lineAt(d, p.key)}`
|
|
1293
|
+
});
|
|
1294
|
+
if ((0, import_yaml4.isMap)(v)) {
|
|
1295
|
+
if (type === "array")
|
|
1296
|
+
propsOf(d, v.get("items", true), `${name}[]`, depth + 1, out);
|
|
1297
|
+
else
|
|
1298
|
+
propsOf(d, v, name, depth + 1, out);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
function docOf(path, text3) {
|
|
1303
|
+
const lc = new import_yaml4.LineCounter();
|
|
1304
|
+
const doc = (0, import_yaml4.parseDocument)(text3, { lineCounter: lc });
|
|
1305
|
+
return (0, import_yaml4.isMap)(doc.contents) ? { path, lc, root: doc.contents } : void 0;
|
|
1306
|
+
}
|
|
1307
|
+
function readJsonSchemaSpecs(path, text3) {
|
|
1308
|
+
const d = docOf(path, text3);
|
|
1309
|
+
if (!d)
|
|
1310
|
+
return [];
|
|
1311
|
+
const title = d.root.get("title");
|
|
1312
|
+
const id = d.root.get("$id");
|
|
1313
|
+
const fields = [];
|
|
1314
|
+
propsOf(d, d.root, "", 0, fields);
|
|
1315
|
+
if (!fields.length)
|
|
1316
|
+
return [];
|
|
1317
|
+
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, "");
|
|
1318
|
+
return [
|
|
1319
|
+
{ kind: "message", format: "json-schema", role: "schema", file: path, line: 1, name, fields }
|
|
1320
|
+
];
|
|
1321
|
+
}
|
|
1322
|
+
function readAsyncApiSpecs(path, text3) {
|
|
1323
|
+
const d = docOf(path, text3);
|
|
1324
|
+
if (!d || d.root.get("asyncapi") === void 0)
|
|
1325
|
+
return [];
|
|
1326
|
+
const out = [];
|
|
1327
|
+
const channels = d.root.get("channels", true);
|
|
1328
|
+
if (!(0, import_yaml4.isMap)(channels))
|
|
1329
|
+
return out;
|
|
1330
|
+
const add = (topic, message) => {
|
|
1331
|
+
const m = deref2(d, message);
|
|
1332
|
+
if (!(0, import_yaml4.isMap)(m))
|
|
1333
|
+
return;
|
|
1334
|
+
const oneOf = m.get("oneOf", true);
|
|
1335
|
+
if ((0, import_yaml4.isSeq)(oneOf)) {
|
|
1336
|
+
for (const x of oneOf.items)
|
|
1337
|
+
add(topic, x);
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
const payload = m.get("payload", true);
|
|
1341
|
+
const fields = [];
|
|
1342
|
+
propsOf(d, payload, "", 0, fields);
|
|
1343
|
+
const p = deref2(d, payload);
|
|
1344
|
+
const title = (0, import_yaml4.isMap)(p) ? p.get("title") : void 0;
|
|
1345
|
+
const name = m.get("name") ?? m.get("title") ?? title;
|
|
1346
|
+
out.push({
|
|
1347
|
+
kind: "message",
|
|
1348
|
+
format: "asyncapi",
|
|
1349
|
+
role: "schema",
|
|
1350
|
+
file: path,
|
|
1351
|
+
line: lineAt(d, m),
|
|
1352
|
+
topic,
|
|
1353
|
+
...typeof name === "string" && name ? { name } : {},
|
|
1354
|
+
fields
|
|
1355
|
+
});
|
|
1356
|
+
};
|
|
1357
|
+
for (const c of channels.items) {
|
|
1358
|
+
if (!(0, import_yaml4.isScalar)(c.key))
|
|
1359
|
+
continue;
|
|
1360
|
+
const ch = deref2(d, c.value);
|
|
1361
|
+
if (!(0, import_yaml4.isMap)(ch))
|
|
1362
|
+
continue;
|
|
1363
|
+
const address = ch.get("address");
|
|
1364
|
+
const topic = typeof address === "string" && address ? address : String(c.key.value);
|
|
1365
|
+
for (const op of ["publish", "subscribe"]) {
|
|
1366
|
+
const o = ch.get(op, true);
|
|
1367
|
+
if ((0, import_yaml4.isMap)(o))
|
|
1368
|
+
add(topic, o.get("message", true));
|
|
1369
|
+
}
|
|
1370
|
+
const msgs = ch.get("messages", true);
|
|
1371
|
+
if ((0, import_yaml4.isMap)(msgs))
|
|
1372
|
+
for (const m of msgs.items)
|
|
1373
|
+
add(topic, m.value);
|
|
1374
|
+
}
|
|
1375
|
+
return out;
|
|
1376
|
+
}
|
|
1377
|
+
function openApiContractSpecs(spec) {
|
|
1378
|
+
return spec.operations.map((o) => {
|
|
1379
|
+
const [file, line] = splitAt(o.cite, spec.path);
|
|
1380
|
+
const field2 = (side) => (f) => ({
|
|
1381
|
+
side,
|
|
1382
|
+
name: f.name,
|
|
1383
|
+
...f.type ? { type: f.type } : {},
|
|
1384
|
+
...f.required !== void 0 ? { required: f.required } : {},
|
|
1385
|
+
...f.in ? { in: f.in } : {},
|
|
1386
|
+
at: f.cite
|
|
1387
|
+
});
|
|
1388
|
+
return {
|
|
1389
|
+
kind: "operation",
|
|
1390
|
+
format: "openapi",
|
|
1391
|
+
role: "consumer",
|
|
1392
|
+
file,
|
|
1393
|
+
line,
|
|
1394
|
+
method: o.method,
|
|
1395
|
+
path: o.fullPath,
|
|
1396
|
+
id: o.id,
|
|
1397
|
+
fields: [...o.request.map(field2("request")), ...o.response.map(field2("response"))],
|
|
1398
|
+
...o.errors?.length ? { errors: o.errors.map((e) => ({ status: e.status, at: e.cite })) } : {}
|
|
1399
|
+
};
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
function splitAt(cite, path) {
|
|
1403
|
+
const m = /^(.*):(\d+)$/.exec(cite);
|
|
1404
|
+
return m ? [m[1], Number(m[2])] : [path, 1];
|
|
1405
|
+
}
|
|
1406
|
+
function specFormatOf(name, text3) {
|
|
1407
|
+
const lower = name.toLowerCase();
|
|
1408
|
+
if (lower.endsWith(".proto"))
|
|
1409
|
+
return "protobuf";
|
|
1410
|
+
if (lower.endsWith(".avsc"))
|
|
1411
|
+
return "avro";
|
|
1412
|
+
if (!/\.(ya?ml|json)$/.test(lower))
|
|
1413
|
+
return void 0;
|
|
1414
|
+
const head = text3.slice(0, 4e3);
|
|
1415
|
+
if (/^\s*["']?(openapi|swagger)["']?\s*:/m.test(head))
|
|
1416
|
+
return "openapi";
|
|
1417
|
+
if (/^\s*["']?asyncapi["']?\s*:/m.test(head))
|
|
1418
|
+
return "asyncapi";
|
|
1419
|
+
if (/"type"\s*:\s*"record"/.test(head) && /"fields"\s*:/.test(head))
|
|
1420
|
+
return "avro";
|
|
1421
|
+
if (/["']?\$schema["']?\s*:/.test(head) && /json-schema\.org/.test(head))
|
|
1422
|
+
return "json-schema";
|
|
1423
|
+
return void 0;
|
|
1424
|
+
}
|
|
1425
|
+
function readContractSpecs(path, text3) {
|
|
1426
|
+
switch (specFormatOf(path, text3)) {
|
|
1427
|
+
case "protobuf":
|
|
1428
|
+
return readProtoSpecs(path, text3);
|
|
1429
|
+
case "avro":
|
|
1430
|
+
return readAvroSpecs(path, text3);
|
|
1431
|
+
case "json-schema":
|
|
1432
|
+
return readJsonSchemaSpecs(path, text3);
|
|
1433
|
+
case "asyncapi":
|
|
1434
|
+
return readAsyncApiSpecs(path, text3);
|
|
1435
|
+
case "openapi": {
|
|
1436
|
+
const spec = readVendorSpec(path, text3, "spec");
|
|
1437
|
+
return spec ? openApiContractSpecs(spec) : [];
|
|
1438
|
+
}
|
|
1439
|
+
default:
|
|
1440
|
+
return [];
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
var sameShape = (a, b) => normalizePath(a).replace(/\{[^}]*\}/g, "{}") === normalizePath(b).replace(/\{[^}]*\}/g, "{}");
|
|
1444
|
+
var SPEC_FILE = /\.(proto|avsc|ya?ml|json)$/i;
|
|
1445
|
+
function cmpPath(a, b) {
|
|
1446
|
+
const x = a.split("/");
|
|
1447
|
+
const y = b.split("/");
|
|
1448
|
+
for (let i = 0; i < Math.min(x.length, y.length); i++) {
|
|
1449
|
+
const c = cmp2(x[i], y[i]);
|
|
1450
|
+
if (c)
|
|
1451
|
+
return c;
|
|
1452
|
+
}
|
|
1453
|
+
return x.length - y.length;
|
|
1454
|
+
}
|
|
1455
|
+
var skipped = (p) => p.split("/").slice(0, -1).some((d) => SKIP.has(d) || d.startsWith("."));
|
|
1456
|
+
function folderTree(dir) {
|
|
1457
|
+
return {
|
|
1458
|
+
async files() {
|
|
1459
|
+
const out = [];
|
|
1460
|
+
const walk2 = async (rel) => {
|
|
1461
|
+
const entries = await readdir(join(dir, ...rel.split("/").filter(Boolean)), {
|
|
1462
|
+
withFileTypes: true
|
|
1463
|
+
}).catch(() => []);
|
|
1464
|
+
for (const e of [...entries].sort((a, b) => cmp2(a.name, b.name))) {
|
|
1465
|
+
const p = rel ? `${rel}/${e.name}` : e.name;
|
|
1466
|
+
if (e.isDirectory()) {
|
|
1467
|
+
if (!SKIP.has(e.name) && !e.name.startsWith("."))
|
|
1468
|
+
await walk2(p);
|
|
1469
|
+
} else if (e.isFile() && SPEC_FILE.test(e.name)) {
|
|
1470
|
+
const size = (await stat(join(dir, ...p.split("/"))).catch(() => void 0))?.size;
|
|
1471
|
+
out.push({ path: p, size: size ?? 0 });
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
await walk2("");
|
|
1476
|
+
return out;
|
|
1477
|
+
},
|
|
1478
|
+
read: (p) => readFile(join(dir, ...p.split("/")), "utf8").catch(() => void 0)
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
async function readRepoSpecs(dir, o) {
|
|
1482
|
+
const tree = o.tree ?? folderTree(dir);
|
|
1483
|
+
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);
|
|
1484
|
+
const own = o.facts.filter((f) => f.kind === "entry" && f.entryType === "rest");
|
|
1485
|
+
const specs = [];
|
|
1486
|
+
for (const p of files) {
|
|
1487
|
+
const text3 = await tree.read(p);
|
|
1488
|
+
if (text3 === void 0 || !specFormatOf(p, text3))
|
|
1489
|
+
continue;
|
|
1490
|
+
const got = readContractSpecs(p, text3);
|
|
1491
|
+
if (!got.length)
|
|
1492
|
+
continue;
|
|
1493
|
+
if (o.denyHashes?.size && denyListHits(text3, o.denyHashes).length) {
|
|
1494
|
+
o.onRefused?.(`${p}: the deny-list names a word in it, so its specs are left out.`);
|
|
1495
|
+
continue;
|
|
1496
|
+
}
|
|
1497
|
+
for (const s of got) {
|
|
1498
|
+
if (s.kind !== "operation") {
|
|
1499
|
+
specs.push(s);
|
|
1500
|
+
continue;
|
|
1501
|
+
}
|
|
1502
|
+
const vendorPath = readVendorSpec(p, text3, "spec")?.operations.find((x) => x.id === s.id);
|
|
1503
|
+
const paths = [s.path ?? "", vendorPath?.path ?? ""].filter(Boolean);
|
|
1504
|
+
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];
|
|
1505
|
+
const { id: _id, ...rest } = s;
|
|
1506
|
+
specs.push(entry ? { ...rest, role: "own", entry: entry.id } : rest);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
return {
|
|
1510
|
+
schemaVersion: 1,
|
|
1511
|
+
repo: o.repo,
|
|
1512
|
+
...o.commit ? { commit: o.commit } : {},
|
|
1513
|
+
specs
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
|
|
778
1517
|
// packages/intake/dist/scan-inputs.js
|
|
779
1518
|
var SPECS = ["openapi", "swagger", "asyncapi"];
|
|
780
1519
|
var EVIDENCE_SOURCE = {
|
|
781
1520
|
openapi: "spec",
|
|
782
1521
|
swagger: "spec",
|
|
783
1522
|
asyncapi: "spec",
|
|
1523
|
+
protobuf: "spec",
|
|
1524
|
+
avro: "spec",
|
|
784
1525
|
diagram: "diagram",
|
|
785
1526
|
image: "document",
|
|
786
1527
|
document: "document",
|
|
@@ -798,14 +1539,14 @@ async function walk(dir, skip) {
|
|
|
798
1539
|
return;
|
|
799
1540
|
let entries;
|
|
800
1541
|
try {
|
|
801
|
-
entries = await
|
|
1542
|
+
entries = await readdir2(d, { withFileTypes: true });
|
|
802
1543
|
} catch {
|
|
803
1544
|
return;
|
|
804
1545
|
}
|
|
805
1546
|
for (const e of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
806
1547
|
if (e.name.startsWith("."))
|
|
807
1548
|
continue;
|
|
808
|
-
const full =
|
|
1549
|
+
const full = join2(d, e.name);
|
|
809
1550
|
if (e.isDirectory())
|
|
810
1551
|
await go(full);
|
|
811
1552
|
else if (e.isFile())
|
|
@@ -816,7 +1557,7 @@ async function walk(dir, skip) {
|
|
|
816
1557
|
return out;
|
|
817
1558
|
}
|
|
818
1559
|
var DATE = /(?:^|[-_ .])((\d{4})-?(\d{2})-?(\d{2}))(?=$|[-_ .])/;
|
|
819
|
-
var
|
|
1560
|
+
var VERSION2 = /(?:^|[-_ .])v(\d+(?:[._]\d+)*)(?=$|[-_ .])/i;
|
|
820
1561
|
function nameParts(stem) {
|
|
821
1562
|
let rest = stem;
|
|
822
1563
|
let date;
|
|
@@ -829,7 +1570,7 @@ function nameParts(stem) {
|
|
|
829
1570
|
}
|
|
830
1571
|
}
|
|
831
1572
|
let version;
|
|
832
|
-
const v =
|
|
1573
|
+
const v = VERSION2.exec(rest);
|
|
833
1574
|
if (v) {
|
|
834
1575
|
version = v[1].replace(/_/g, ".");
|
|
835
1576
|
rest = rest.replace(v[0], "");
|
|
@@ -855,23 +1596,23 @@ function systemsInName(stem, systems) {
|
|
|
855
1596
|
return systems.filter((sys) => [sys.id, sys.name, ...sys.aliases].some((n) => slug(n) && s.includes(`-${slug(n)}-`))).map((sys) => sys.id).sort();
|
|
856
1597
|
}
|
|
857
1598
|
async function scanInputs(o) {
|
|
858
|
-
const orgPackDir = typeof o.orgPack === "string" ? o.orgPack :
|
|
1599
|
+
const orgPackDir = typeof o.orgPack === "string" ? o.orgPack : join2(orgPackDirOf(o.root));
|
|
859
1600
|
const op = typeof o.orgPack === "object" ? o.orgPack : await loadOrgPack(orgPackDir);
|
|
860
1601
|
const systems = op.profiles.flatMap((p) => p.profile?.systems ?? []);
|
|
861
1602
|
const legend = op.profiles.find((p) => p.profile?.legend)?.profile?.legend;
|
|
862
1603
|
const records = o.records ?? [];
|
|
863
1604
|
const ingestors = o.ingestors ?? [drawioIngestor];
|
|
864
1605
|
const scannedAt = o.scannedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
865
|
-
const inputsDir = o.inputsDir ??
|
|
1606
|
+
const inputsDir = o.inputsDir ?? join2(o.root, "inputs");
|
|
866
1607
|
const problems = [];
|
|
867
1608
|
const triage = [];
|
|
868
1609
|
const authors = /* @__PURE__ */ new Map();
|
|
869
1610
|
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
|
|
1611
|
+
const st = await stat2(inputsDir).catch(() => void 0);
|
|
871
1612
|
const paths = st?.isDirectory() ? await walk(inputsDir, wikiDirs) : [];
|
|
872
1613
|
const files = [];
|
|
873
1614
|
for (const abs of paths) {
|
|
874
|
-
const bytes = new Uint8Array(await
|
|
1615
|
+
const bytes = new Uint8Array(await readFile2(abs));
|
|
875
1616
|
const path = `inputs/${posix(relative(inputsDir, abs))}`;
|
|
876
1617
|
const name = path.split("/").pop();
|
|
877
1618
|
const c = classify(name, bytes);
|
|
@@ -879,7 +1620,7 @@ async function scanInputs(o) {
|
|
|
879
1620
|
abs,
|
|
880
1621
|
path,
|
|
881
1622
|
bytes,
|
|
882
|
-
hash:
|
|
1623
|
+
hash: createHash5("sha256").update(bytes).digest("hex"),
|
|
883
1624
|
stem: name.includes(".") ? name.slice(0, name.lastIndexOf(".")) : name,
|
|
884
1625
|
inbox: path.startsWith("inputs/inbox/"),
|
|
885
1626
|
...c.data !== void 0 ? { data: c.data } : {},
|
|
@@ -949,7 +1690,7 @@ async function scanInputs(o) {
|
|
|
949
1690
|
const heads = members.filter((m) => !m.doc.supersededBy);
|
|
950
1691
|
if (heads.length < 2)
|
|
951
1692
|
continue;
|
|
952
|
-
const distinct = (vals,
|
|
1693
|
+
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
1694
|
const byVersion = distinct(heads.map((h) => h.doc.version), compareVersions);
|
|
954
1695
|
const byDate = !byVersion && distinct(heads.map((h) => h.doc.date), (a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
955
1696
|
if (byVersion || byDate) {
|
|
@@ -1106,6 +1847,43 @@ async function scanInputs(o) {
|
|
|
1106
1847
|
} catch {
|
|
1107
1848
|
}
|
|
1108
1849
|
}
|
|
1850
|
+
if (cls === "protobuf" || cls === "avro") {
|
|
1851
|
+
const specs = cls === "protobuf" ? readProtoSpecs(f.path, text3()) : readAvroSpecs(f.path, text3());
|
|
1852
|
+
const named = new Set(systemsInName(f.stem, systems));
|
|
1853
|
+
for (const s of specs) {
|
|
1854
|
+
const res = s.name ? resolveName(s.name.split(".").slice(0, -1).join(" ")) : void 0;
|
|
1855
|
+
if (res?.id && !named.size)
|
|
1856
|
+
named.add(systemOf(res.id));
|
|
1857
|
+
}
|
|
1858
|
+
for (const s of named)
|
|
1859
|
+
linked.add(s);
|
|
1860
|
+
if (current && specs.length) {
|
|
1861
|
+
for (const s of specs) {
|
|
1862
|
+
const p = parseRecord({
|
|
1863
|
+
schemaVersion: 1,
|
|
1864
|
+
kind: "Schema",
|
|
1865
|
+
id: boundedId("schema.", slug(s.name ?? f.stem)),
|
|
1866
|
+
status: "current",
|
|
1867
|
+
confidence: "verified",
|
|
1868
|
+
format: cls,
|
|
1869
|
+
ref: `${f.path}#${s.name ?? ""}`,
|
|
1870
|
+
fields: s.fields.map((x) => ({
|
|
1871
|
+
name: x.name,
|
|
1872
|
+
...x.type ? { type: x.type } : {},
|
|
1873
|
+
...x.required !== void 0 ? { required: x.required } : {}
|
|
1874
|
+
})),
|
|
1875
|
+
evidence: [{ source: "spec", path: f.path, line: s.line, side: "definition" }]
|
|
1876
|
+
});
|
|
1877
|
+
if (!p.ok)
|
|
1878
|
+
continue;
|
|
1879
|
+
const schema = p.record;
|
|
1880
|
+
out.push(schema);
|
|
1881
|
+
f.doc.records.push(schema.id);
|
|
1882
|
+
}
|
|
1883
|
+
f.doc.status = "read";
|
|
1884
|
+
f.doc.reader = cls === "protobuf" ? READERS.protobuf : READERS.avro;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1109
1887
|
if (current && cls === "payload" && f.data !== void 0) {
|
|
1110
1888
|
const schema = readPayload(f.path, boundedId("payload.", f.doc.id.slice(4)), f.data);
|
|
1111
1889
|
out.push(schema);
|
|
@@ -1415,11 +2193,11 @@ function imageItems(records) {
|
|
|
1415
2193
|
};
|
|
1416
2194
|
});
|
|
1417
2195
|
}
|
|
1418
|
-
var
|
|
2196
|
+
var key2 = (action, target, value) => `${action}|${target}|${JSON.stringify(value ?? null)}`;
|
|
1419
2197
|
function buildTriage(input) {
|
|
1420
2198
|
const decisions = (input.decisions ?? []).filter((d) => d.kind === "CuratedDecision" && d.status === "current");
|
|
1421
2199
|
const decidedIds = new Set(decisions.map((d) => d.id));
|
|
1422
|
-
const decidedKeys = new Set(decisions.map((d) =>
|
|
2200
|
+
const decidedKeys = new Set(decisions.map((d) => key2(d.action, d.target, d.value)));
|
|
1423
2201
|
const docs = new Map((input.inputs?.documents ?? []).map((d) => [d.path, d.id]));
|
|
1424
2202
|
const docIdOf = (path) => docs.get(path) ?? boundedId("doc.", slug(path.split("/").pop().replace(/\.[^.]+$/, "")));
|
|
1425
2203
|
const records = input.records;
|
|
@@ -1432,7 +2210,7 @@ function buildTriage(input) {
|
|
|
1432
2210
|
...imageItems([...records, ...inputRecords]),
|
|
1433
2211
|
...readingItems(input)
|
|
1434
2212
|
];
|
|
1435
|
-
const open = all.filter((i) => !i.options.some((o) => decidedIds.has(o.decision.id) || decidedKeys.has(
|
|
2213
|
+
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
2214
|
const items = sortItems(open);
|
|
1437
2215
|
return {
|
|
1438
2216
|
items,
|
|
@@ -1473,9 +2251,9 @@ function buildTriage(input) {
|
|
|
1473
2251
|
}
|
|
1474
2252
|
|
|
1475
2253
|
// packages/intake/dist/work-items.js
|
|
1476
|
-
var
|
|
1477
|
-
import { readdir as
|
|
1478
|
-
import { join as
|
|
2254
|
+
var import_yaml5 = __toESM(require_dist(), 1);
|
|
2255
|
+
import { readdir as readdir3, readFile as readFile3 } from "node:fs/promises";
|
|
2256
|
+
import { join as join3, relative as relative2, sep as sep2 } from "node:path";
|
|
1479
2257
|
var WORK_ITEM_READER = "work-items@0.1.0";
|
|
1480
2258
|
var isObj3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1481
2259
|
var text = (v) => {
|
|
@@ -1654,7 +2432,7 @@ function readWorkItemExport(path, bytes) {
|
|
|
1654
2432
|
return void 0;
|
|
1655
2433
|
let data;
|
|
1656
2434
|
try {
|
|
1657
|
-
data = (0,
|
|
2435
|
+
data = (0, import_yaml5.parse)(content);
|
|
1658
2436
|
} catch {
|
|
1659
2437
|
return void 0;
|
|
1660
2438
|
}
|
|
@@ -1677,19 +2455,19 @@ function readWorkItemExport(path, bytes) {
|
|
|
1677
2455
|
return items;
|
|
1678
2456
|
}
|
|
1679
2457
|
async function readWorkItemExports(o) {
|
|
1680
|
-
const dir = o.inputsDir ??
|
|
2458
|
+
const dir = o.inputsDir ?? join3(o.root, "inputs");
|
|
1681
2459
|
const files = [];
|
|
1682
2460
|
async function walk2(d) {
|
|
1683
2461
|
let entries;
|
|
1684
2462
|
try {
|
|
1685
|
-
entries = await
|
|
2463
|
+
entries = await readdir3(d, { withFileTypes: true });
|
|
1686
2464
|
} catch {
|
|
1687
2465
|
return;
|
|
1688
2466
|
}
|
|
1689
2467
|
for (const e of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
1690
2468
|
if (e.name.startsWith("."))
|
|
1691
2469
|
continue;
|
|
1692
|
-
const full =
|
|
2470
|
+
const full = join3(d, e.name);
|
|
1693
2471
|
if (e.isDirectory())
|
|
1694
2472
|
await walk2(full);
|
|
1695
2473
|
else if (/\.(json|ya?ml|csv)$/i.test(e.name))
|
|
@@ -1706,7 +2484,7 @@ async function readWorkItemExports(o) {
|
|
|
1706
2484
|
const path = `inputs/${relative2(dir, full).split(sep2).join("/")}`;
|
|
1707
2485
|
let bytes;
|
|
1708
2486
|
try {
|
|
1709
|
-
bytes = new Uint8Array(await
|
|
2487
|
+
bytes = new Uint8Array(await readFile3(full));
|
|
1710
2488
|
} catch (e) {
|
|
1711
2489
|
out.problems.push({ path, message: `can't read it: ${e.message}` });
|
|
1712
2490
|
continue;
|
|
@@ -1721,9 +2499,9 @@ async function readWorkItemExports(o) {
|
|
|
1721
2499
|
}
|
|
1722
2500
|
|
|
1723
2501
|
// packages/intake/dist/service-requests.js
|
|
1724
|
-
var
|
|
1725
|
-
import { readdir as
|
|
1726
|
-
import { join as
|
|
2502
|
+
var import_yaml6 = __toESM(require_dist(), 1);
|
|
2503
|
+
import { readdir as readdir4, readFile as readFile4 } from "node:fs/promises";
|
|
2504
|
+
import { join as join4, relative as relative3, sep as sep3 } from "node:path";
|
|
1727
2505
|
var SERVICE_REQUEST_READER = "service-requests@0.1.0";
|
|
1728
2506
|
var isObj4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1729
2507
|
var text2 = (v) => {
|
|
@@ -1874,7 +2652,7 @@ function readServiceRequestExport(path, bytes) {
|
|
|
1874
2652
|
return void 0;
|
|
1875
2653
|
let data;
|
|
1876
2654
|
try {
|
|
1877
|
-
data = (0,
|
|
2655
|
+
data = (0, import_yaml6.parse)(content);
|
|
1878
2656
|
} catch {
|
|
1879
2657
|
return void 0;
|
|
1880
2658
|
}
|
|
@@ -1904,19 +2682,19 @@ function readServiceRequestExport(path, bytes) {
|
|
|
1904
2682
|
return out;
|
|
1905
2683
|
}
|
|
1906
2684
|
async function readServiceRequestExports(o) {
|
|
1907
|
-
const dir = o.inputsDir ??
|
|
2685
|
+
const dir = o.inputsDir ?? join4(o.root, "inputs");
|
|
1908
2686
|
const found = [];
|
|
1909
2687
|
async function walk2(d) {
|
|
1910
2688
|
let entries;
|
|
1911
2689
|
try {
|
|
1912
|
-
entries = await
|
|
2690
|
+
entries = await readdir4(d, { withFileTypes: true });
|
|
1913
2691
|
} catch {
|
|
1914
2692
|
return;
|
|
1915
2693
|
}
|
|
1916
2694
|
for (const e of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
1917
2695
|
if (e.name.startsWith("."))
|
|
1918
2696
|
continue;
|
|
1919
|
-
const full =
|
|
2697
|
+
const full = join4(d, e.name);
|
|
1920
2698
|
if (e.isDirectory())
|
|
1921
2699
|
await walk2(full);
|
|
1922
2700
|
else if (/\.(json|ya?ml|csv)$/i.test(e.name))
|
|
@@ -1933,7 +2711,7 @@ async function readServiceRequestExports(o) {
|
|
|
1933
2711
|
const path = `inputs/${relative3(dir, full).split(sep3).join("/")}`;
|
|
1934
2712
|
let bytes;
|
|
1935
2713
|
try {
|
|
1936
|
-
bytes = new Uint8Array(await
|
|
2714
|
+
bytes = new Uint8Array(await readFile4(full));
|
|
1937
2715
|
} catch (e) {
|
|
1938
2716
|
out.problems.push({ path, message: `can't read it: ${e.message}` });
|
|
1939
2717
|
continue;
|
|
@@ -1948,15 +2726,15 @@ async function readServiceRequestExports(o) {
|
|
|
1948
2726
|
}
|
|
1949
2727
|
|
|
1950
2728
|
// packages/intake/dist/change-inputs.js
|
|
1951
|
-
var
|
|
1952
|
-
import { createHash as
|
|
1953
|
-
import { mkdir, readdir as
|
|
1954
|
-
import { join as
|
|
2729
|
+
var import_yaml7 = __toESM(require_dist(), 1);
|
|
2730
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
2731
|
+
import { mkdir, readdir as readdir5, readFile as readFile5 } from "node:fs/promises";
|
|
2732
|
+
import { join as join5 } from "node:path";
|
|
1955
2733
|
var INPUTS_DIR = "inputs";
|
|
1956
2734
|
var INPUTS_INDEX = "inputs/index.yaml";
|
|
1957
2735
|
var INPUTS_READ_DIR = "inputs/read";
|
|
1958
2736
|
var CHANGE_INPUTS_SCHEMA_VERSION = 1;
|
|
1959
|
-
var sha256 = (b) =>
|
|
2737
|
+
var sha256 = (b) => createHash6("sha256").update(b).digest("hex");
|
|
1960
2738
|
var KEYS = [
|
|
1961
2739
|
"path",
|
|
1962
2740
|
"name",
|
|
@@ -1976,10 +2754,10 @@ var KEYS = [
|
|
|
1976
2754
|
"defences"
|
|
1977
2755
|
];
|
|
1978
2756
|
async function readChangeInputs(dir) {
|
|
1979
|
-
const text3 = await
|
|
2757
|
+
const text3 = await readFile5(join5(dir, ...INPUTS_INDEX.split("/")), "utf8").catch(() => "");
|
|
1980
2758
|
let data;
|
|
1981
2759
|
try {
|
|
1982
|
-
data = text3 ? (0,
|
|
2760
|
+
data = text3 ? (0, import_yaml7.parse)(text3) : void 0;
|
|
1983
2761
|
} catch {
|
|
1984
2762
|
data = void 0;
|
|
1985
2763
|
}
|
|
@@ -2000,7 +2778,7 @@ async function writeIndex(dir, index) {
|
|
|
2000
2778
|
o[k] = f[k];
|
|
2001
2779
|
return o;
|
|
2002
2780
|
});
|
|
2003
|
-
await writeFileAtomic(
|
|
2781
|
+
await writeFileAtomic(join5(dir, ...INPUTS_INDEX.split("/")), `# Files attached to this change (ADR 0113): atticus change attach writes this file.
|
|
2004
2782
|
${toCanonicalYaml({ schemaVersion: index.schemaVersion, files }, ["schemaVersion", "files"])}`);
|
|
2005
2783
|
}
|
|
2006
2784
|
var isText = (b) => {
|
|
@@ -2091,7 +2869,7 @@ function readText(input, bytes, older) {
|
|
|
2091
2869
|
async function attachToChange(dir, files, o) {
|
|
2092
2870
|
const index = await readChangeInputs(dir);
|
|
2093
2871
|
const out = { added: [], refused: [], notes: [] };
|
|
2094
|
-
const taken = new Set(await
|
|
2872
|
+
const taken = new Set(await readdir5(join5(dir, INPUTS_DIR)).catch(() => []));
|
|
2095
2873
|
taken.add("index.yaml").add("read");
|
|
2096
2874
|
const replaced = o.replaces ? index.files.find((x) => x.path === o.replaces.trim().replace(/\\/g, "/")) : void 0;
|
|
2097
2875
|
let changed = false;
|
|
@@ -2178,11 +2956,11 @@ async function attachToChange(dir, files, o) {
|
|
|
2178
2956
|
const where = o.elsewhere?.(hash);
|
|
2179
2957
|
if (where)
|
|
2180
2958
|
out.notes.push(`${name} is also in the metarepo's inputs as ${where}.`);
|
|
2181
|
-
await mkdir(
|
|
2182
|
-
await writeFileAtomic(
|
|
2959
|
+
await mkdir(join5(dir, INPUTS_DIR), { recursive: true });
|
|
2960
|
+
await writeFileAtomic(join5(dir, INPUTS_DIR, target), f.bytes);
|
|
2183
2961
|
const text3 = readText(input, f.bytes, older);
|
|
2184
2962
|
if (text3 !== void 0)
|
|
2185
|
-
await writeFileAtomic(
|
|
2963
|
+
await writeFileAtomic(join5(dir, ...input.readAs.split("/")), text3);
|
|
2186
2964
|
index.files.push(input);
|
|
2187
2965
|
out.added.push(input);
|
|
2188
2966
|
}
|
|
@@ -2208,7 +2986,7 @@ async function changeInputSources(dir, rel) {
|
|
|
2208
2986
|
for (const f of (await readChangeInputs(dir)).files) {
|
|
2209
2987
|
if (f.supersededBy || f.defences?.risk === "high")
|
|
2210
2988
|
continue;
|
|
2211
|
-
const read = f.readAs ? await
|
|
2989
|
+
const read = f.readAs ? await readFile5(join5(dir, ...f.readAs.split("/")), "utf8").catch(() => void 0) : void 0;
|
|
2212
2990
|
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
2991
|
out.push({
|
|
2214
2992
|
id: f.path,
|
|
@@ -2237,7 +3015,7 @@ var KIND_ORDER2 = [
|
|
|
2237
3015
|
"error-schema",
|
|
2238
3016
|
"error-removed"
|
|
2239
3017
|
];
|
|
2240
|
-
var
|
|
3018
|
+
var cmp3 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
2241
3019
|
var opKey = (o) => `${o.method} ${normalizePath(o.fullPath)}`;
|
|
2242
3020
|
var opName = (o) => `${o.method} ${o.path}`;
|
|
2243
3021
|
var list = (xs) => xs.length <= 1 ? xs[0] ?? "" : `${xs.slice(0, -1).join(", ")} and ${xs.at(-1)}`;
|
|
@@ -2302,7 +3080,7 @@ function diffVendorSpecs(older, newer) {
|
|
|
2302
3080
|
});
|
|
2303
3081
|
for (const [o, n] of pairs)
|
|
2304
3082
|
out.push(...operationChanges(o, n));
|
|
2305
|
-
return out.sort((a, b) =>
|
|
3083
|
+
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
3084
|
}
|
|
2307
3085
|
var opOf = (o) => ({
|
|
2308
3086
|
method: o.method,
|
|
@@ -2493,7 +3271,7 @@ function fieldChanges(olds, news, side, at, base) {
|
|
|
2493
3271
|
|
|
2494
3272
|
// packages/intake/dist/vendor-impact.js
|
|
2495
3273
|
var MAX_UPSTREAM = 4;
|
|
2496
|
-
var
|
|
3274
|
+
var cmp4 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
2497
3275
|
var sorted = (xs) => [...new Set(xs)].sort();
|
|
2498
3276
|
var joinVendorOf = (input, spec) => ({
|
|
2499
3277
|
system: input.vendor.system,
|
|
@@ -2516,7 +3294,7 @@ var versionOf = (v) => ({
|
|
|
2516
3294
|
function vendorImpact(input) {
|
|
2517
3295
|
const diff = diffVendorSpecs(input.older.spec, input.newer.spec);
|
|
2518
3296
|
const bundle = input.bundleFolders ? { bundleFolders: input.bundleFolders } : {};
|
|
2519
|
-
const
|
|
3297
|
+
const join7 = joinFacts({
|
|
2520
3298
|
repos: input.repos,
|
|
2521
3299
|
...input.targets ? { targets: input.targets } : {},
|
|
2522
3300
|
...input.facing ? { facing: input.facing } : {},
|
|
@@ -2556,8 +3334,8 @@ function vendorImpact(input) {
|
|
|
2556
3334
|
const f = facts.get(k(call))?.fact;
|
|
2557
3335
|
return f?.kind === "call" && f.from ? endOf(call.repo, f.from) : void 0;
|
|
2558
3336
|
};
|
|
2559
|
-
const hops = new Set(
|
|
2560
|
-
const joins =
|
|
3337
|
+
const hops = new Set(join7.joins.flatMap((j) => (j.gateway ?? []).map((h) => k(h.call))));
|
|
3338
|
+
const joins = join7.joins.filter((j) => j.how !== "topic" && !hops.has(k(j.call)));
|
|
2561
3339
|
const via = (j) => j.gateway?.length ? { via: j.gateway.map((h) => h.route) } : {};
|
|
2562
3340
|
const upstreamOf = (start) => {
|
|
2563
3341
|
const out = [];
|
|
@@ -2586,422 +3364,121 @@ function vendorImpact(input) {
|
|
|
2586
3364
|
}
|
|
2587
3365
|
return out;
|
|
2588
3366
|
};
|
|
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
|
|
3367
|
+
const fieldUse = (call, change) => {
|
|
3368
|
+
if (!change.side || !change.field || change.status)
|
|
3369
|
+
return void 0;
|
|
3370
|
+
const side = change.side;
|
|
3371
|
+
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));
|
|
3372
|
+
if (!mine.length)
|
|
3373
|
+
return void 0;
|
|
3374
|
+
const want = fieldNameKey(change.field);
|
|
3375
|
+
const hit = mine.find((f) => fieldNameKey(f.name) === want);
|
|
3376
|
+
const req = side === "request";
|
|
3377
|
+
return hit ? { uses: req ? "sends" : "reads", at: `${hit.cite.file}:${hit.cite.line}` } : { uses: req ? "does-not-send" : "does-not-read" };
|
|
2853
3378
|
};
|
|
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
|
-
|
|
3379
|
+
const changes = diff.map((c) => {
|
|
3380
|
+
const older = c.endpoints.older;
|
|
3381
|
+
const matches = older ? today.matches.filter((m) => m.operation === older) : next.matches.filter((m) => m.operation === c.endpoints.newer);
|
|
3382
|
+
const forwards = matches.map((m) => {
|
|
3383
|
+
if (m.direct) {
|
|
3384
|
+
const f = facts.get(k(m.call))?.fact;
|
|
3385
|
+
const field2 = fieldUse(m.call, c);
|
|
3386
|
+
const self = {
|
|
3387
|
+
call: m.call,
|
|
3388
|
+
interface: interfaceId(m.call.component, factIdPart(f?.to ?? input.vendor.system), m.method, m.path),
|
|
3389
|
+
...field2 ? { field: field2 } : {},
|
|
3390
|
+
...m.route ? { under: m.route } : {},
|
|
3391
|
+
upstream: upstreamOf(m.route)
|
|
3392
|
+
};
|
|
3393
|
+
return {
|
|
3394
|
+
call: m.call,
|
|
3395
|
+
...m.route ? { route: m.route } : {},
|
|
3396
|
+
operation: m.operation,
|
|
3397
|
+
direct: true,
|
|
3398
|
+
callers: [self]
|
|
3399
|
+
};
|
|
3400
|
+
}
|
|
3401
|
+
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) => {
|
|
3402
|
+
const u = under(j.call);
|
|
3403
|
+
const field2 = fieldUse(j.call, c);
|
|
3404
|
+
return {
|
|
3405
|
+
call: j.call,
|
|
3406
|
+
interface: j.interface,
|
|
3407
|
+
...via(j),
|
|
3408
|
+
...field2 ? { field: field2 } : {},
|
|
3409
|
+
...u ? { under: u } : {},
|
|
3410
|
+
upstream: upstreamOf(u)
|
|
3411
|
+
};
|
|
3412
|
+
}) : [];
|
|
3413
|
+
return {
|
|
3414
|
+
call: m.call,
|
|
3415
|
+
...m.route ? { route: m.route } : {},
|
|
3416
|
+
...m.tie ? { tie: m.tie } : {},
|
|
3417
|
+
operation: m.operation,
|
|
3418
|
+
callers
|
|
3419
|
+
};
|
|
3420
|
+
});
|
|
3421
|
+
return { id: c.id, severity: c.severity, says: c.says, forwards };
|
|
3422
|
+
});
|
|
3423
|
+
const repos = /* @__PURE__ */ new Set();
|
|
3424
|
+
const interfaces = /* @__PURE__ */ new Set();
|
|
3425
|
+
const endpoints = /* @__PURE__ */ new Set();
|
|
3426
|
+
const entries = /* @__PURE__ */ new Set();
|
|
3427
|
+
for (const c of changes)
|
|
3428
|
+
for (const f of c.forwards) {
|
|
3429
|
+
repos.add(f.call.repo);
|
|
3430
|
+
endpoints.add(f.operation);
|
|
3431
|
+
for (const s of f.callers) {
|
|
3432
|
+
repos.add(s.call.repo);
|
|
3433
|
+
interfaces.add(s.interface);
|
|
3434
|
+
if (s.under)
|
|
3435
|
+
entries.add(k(s.under));
|
|
3436
|
+
for (const u of s.upstream) {
|
|
3437
|
+
repos.add(u.call.repo);
|
|
3438
|
+
interfaces.add(u.interface);
|
|
3439
|
+
entries.add(k(u.reaches));
|
|
3440
|
+
if (u.under)
|
|
3441
|
+
entries.add(k(u.under));
|
|
2909
3442
|
}
|
|
2910
|
-
days.push(d);
|
|
2911
|
-
} else if (!input.from || !input.to) {
|
|
2912
|
-
skipped++;
|
|
2913
|
-
continue;
|
|
2914
3443
|
}
|
|
2915
3444
|
}
|
|
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);
|
|
3445
|
+
const endpointIds = /* @__PURE__ */ new Set();
|
|
3446
|
+
for (const e of entries) {
|
|
3447
|
+
const got = facts.get(e);
|
|
3448
|
+
if (got?.fact.kind === "entry")
|
|
3449
|
+
endpointIds.add(entryEndpointId(got.fact, componentOf(got.repo, got.fact)));
|
|
3450
|
+
}
|
|
3451
|
+
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));
|
|
3452
|
+
for (const f of flows)
|
|
3453
|
+
repos.add(f.repo);
|
|
3454
|
+
const systems = /* @__PURE__ */ new Set([input.vendor.system]);
|
|
3455
|
+
for (const r of repos) {
|
|
3456
|
+
const s = input.systemOfRepo?.[r];
|
|
3457
|
+
if (s)
|
|
3458
|
+
systems.add(s);
|
|
2951
3459
|
}
|
|
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
3460
|
return {
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3461
|
+
diff,
|
|
3462
|
+
impact: {
|
|
3463
|
+
vendor: input.vendor.system,
|
|
3464
|
+
older: versionOf(input.older),
|
|
3465
|
+
newer: versionOf(input.newer),
|
|
3466
|
+
changes,
|
|
3467
|
+
repos: sorted(repos),
|
|
3468
|
+
systems: sorted(systems),
|
|
3469
|
+
flows,
|
|
3470
|
+
interfaces: sorted(interfaces),
|
|
3471
|
+
endpoints: sorted(endpoints),
|
|
3472
|
+
gaps: today.gaps,
|
|
3473
|
+
asks: today.asks
|
|
3474
|
+
}
|
|
3001
3475
|
};
|
|
3002
3476
|
}
|
|
3003
3477
|
|
|
3004
3478
|
// packages/intake/dist/contract-files.js
|
|
3479
|
+
var import_yaml8 = __toESM(require_dist(), 1);
|
|
3480
|
+
import { readdir as readdir6, readFile as readFile6, stat as stat3 } from "node:fs/promises";
|
|
3481
|
+
import { join as join6 } from "node:path";
|
|
3005
3482
|
function safeServerUrl(url) {
|
|
3006
3483
|
const m = /^([a-z][a-z0-9+.-]*:\/\/)([^/?#]*)(.*)$/i.exec(url.trim());
|
|
3007
3484
|
if (!m) {
|
|
@@ -3020,28 +3497,28 @@ var str2 = (m, key3) => {
|
|
|
3020
3497
|
return typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
3021
3498
|
};
|
|
3022
3499
|
var mapAt = (m, key3) => {
|
|
3023
|
-
const v = (0,
|
|
3024
|
-
return (0,
|
|
3500
|
+
const v = (0, import_yaml8.isMap)(m) ? m.get(key3, true) : void 0;
|
|
3501
|
+
return (0, import_yaml8.isMap)(v) ? v : void 0;
|
|
3025
3502
|
};
|
|
3026
3503
|
function readPactFile(text3, file) {
|
|
3027
|
-
const lc = new
|
|
3504
|
+
const lc = new import_yaml8.LineCounter();
|
|
3028
3505
|
let doc;
|
|
3029
3506
|
try {
|
|
3030
|
-
doc = (0,
|
|
3507
|
+
doc = (0, import_yaml8.parseDocument)(text3, { lineCounter: lc });
|
|
3031
3508
|
} catch {
|
|
3032
3509
|
return void 0;
|
|
3033
3510
|
}
|
|
3034
|
-
if (doc.errors.length || !(0,
|
|
3511
|
+
if (doc.errors.length || !(0, import_yaml8.isMap)(doc.contents))
|
|
3035
3512
|
return void 0;
|
|
3036
3513
|
const root = doc.contents;
|
|
3037
3514
|
const consumer = str2(mapAt(root, "consumer"), "name");
|
|
3038
3515
|
const provider = str2(mapAt(root, "provider"), "name");
|
|
3039
3516
|
const list2 = root.get("interactions", true);
|
|
3040
|
-
if (!consumer || !provider || !(0,
|
|
3517
|
+
if (!consumer || !provider || !(0, import_yaml8.isSeq)(list2))
|
|
3041
3518
|
return void 0;
|
|
3042
3519
|
const out = [];
|
|
3043
3520
|
for (const it of list2.items) {
|
|
3044
|
-
if (!(0,
|
|
3521
|
+
if (!(0, import_yaml8.isMap)(it))
|
|
3045
3522
|
continue;
|
|
3046
3523
|
const type = str2(it, "type");
|
|
3047
3524
|
if (type && !/http/i.test(type))
|
|
@@ -3050,8 +3527,8 @@ function readPactFile(text3, file) {
|
|
|
3050
3527
|
if (!req)
|
|
3051
3528
|
continue;
|
|
3052
3529
|
const method = str2(req, "method");
|
|
3053
|
-
const pair = req.items.find((p) => (0,
|
|
3054
|
-
const path = pair && (0,
|
|
3530
|
+
const pair = req.items.find((p) => (0, import_yaml8.isScalar)(p.key) && p.key.value === "path");
|
|
3531
|
+
const path = pair && (0, import_yaml8.isScalar)(pair.value) ? String(pair.value.value) : void 0;
|
|
3055
3532
|
const safe = path?.startsWith("/") ? safePathOf(path) : void 0;
|
|
3056
3533
|
if (!safe)
|
|
3057
3534
|
continue;
|
|
@@ -3098,7 +3575,7 @@ function readConsumerOpenApi(text3, file, own) {
|
|
|
3098
3575
|
] : [];
|
|
3099
3576
|
});
|
|
3100
3577
|
}
|
|
3101
|
-
var
|
|
3578
|
+
var SKIP2 = /* @__PURE__ */ new Set([
|
|
3102
3579
|
".git",
|
|
3103
3580
|
"node_modules",
|
|
3104
3581
|
"vendor",
|
|
@@ -3113,19 +3590,19 @@ var SKIP = /* @__PURE__ */ new Set([
|
|
|
3113
3590
|
".idea",
|
|
3114
3591
|
".atticus"
|
|
3115
3592
|
]);
|
|
3116
|
-
var
|
|
3593
|
+
var MAX_BYTES2 = 5 * 1024 * 1024;
|
|
3117
3594
|
var PACT = /pact/i;
|
|
3118
3595
|
var SPEC = /(openapi|swagger)/i;
|
|
3119
3596
|
async function readContractFiles(dir, o) {
|
|
3120
3597
|
const files = [];
|
|
3121
3598
|
const walk2 = async (rel) => {
|
|
3122
|
-
const entries2 = await
|
|
3599
|
+
const entries2 = await readdir6(join6(dir, ...rel.split("/").filter(Boolean)), {
|
|
3123
3600
|
withFileTypes: true
|
|
3124
3601
|
}).catch(() => []);
|
|
3125
3602
|
for (const e of [...entries2].sort((a, b) => a.name < b.name ? -1 : 1)) {
|
|
3126
3603
|
const p = rel ? `${rel}/${e.name}` : e.name;
|
|
3127
3604
|
if (e.isDirectory()) {
|
|
3128
|
-
if (!
|
|
3605
|
+
if (!SKIP2.has(e.name))
|
|
3129
3606
|
await walk2(p);
|
|
3130
3607
|
} else if (e.isFile()) {
|
|
3131
3608
|
if (/\.json$/i.test(e.name) && PACT.test(p))
|
|
@@ -3138,11 +3615,11 @@ async function readContractFiles(dir, o) {
|
|
|
3138
3615
|
await walk2("");
|
|
3139
3616
|
const entries = [];
|
|
3140
3617
|
for (const p of files) {
|
|
3141
|
-
const full =
|
|
3142
|
-
const size = (await
|
|
3143
|
-
if (size === 0 || size >
|
|
3618
|
+
const full = join6(dir, ...p.split("/"));
|
|
3619
|
+
const size = (await stat3(full).catch(() => void 0))?.size ?? 0;
|
|
3620
|
+
if (size === 0 || size > MAX_BYTES2)
|
|
3144
3621
|
continue;
|
|
3145
|
-
const text3 = await
|
|
3622
|
+
const text3 = await readFile6(full, "utf8");
|
|
3146
3623
|
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
3624
|
if (!got?.length)
|
|
3148
3625
|
continue;
|
|
@@ -3177,9 +3654,24 @@ export {
|
|
|
3177
3654
|
sortItems,
|
|
3178
3655
|
opt,
|
|
3179
3656
|
screenFile,
|
|
3657
|
+
looksSensitive,
|
|
3658
|
+
segmentOf,
|
|
3659
|
+
safePathOf,
|
|
3660
|
+
pathTemplateOf,
|
|
3661
|
+
appLabelOf,
|
|
3662
|
+
denyListHits,
|
|
3663
|
+
aggregateTraffic,
|
|
3180
3664
|
specEndpointIds,
|
|
3181
3665
|
readVendorSpec,
|
|
3182
3666
|
operationSchemas,
|
|
3667
|
+
readProtoSpecs,
|
|
3668
|
+
readAvroSpecs,
|
|
3669
|
+
readJsonSchemaSpecs,
|
|
3670
|
+
readAsyncApiSpecs,
|
|
3671
|
+
openApiContractSpecs,
|
|
3672
|
+
specFormatOf,
|
|
3673
|
+
readContractSpecs,
|
|
3674
|
+
readRepoSpecs,
|
|
3183
3675
|
nameParts,
|
|
3184
3676
|
compareVersions,
|
|
3185
3677
|
scanInputs,
|
|
@@ -3203,13 +3695,6 @@ export {
|
|
|
3203
3695
|
diffVendorSpecs,
|
|
3204
3696
|
MAX_UPSTREAM,
|
|
3205
3697
|
vendorImpact,
|
|
3206
|
-
looksSensitive,
|
|
3207
|
-
segmentOf,
|
|
3208
|
-
safePathOf,
|
|
3209
|
-
pathTemplateOf,
|
|
3210
|
-
appLabelOf,
|
|
3211
|
-
denyListHits,
|
|
3212
|
-
aggregateTraffic,
|
|
3213
3698
|
safeServerUrl,
|
|
3214
3699
|
readPactFile,
|
|
3215
3700
|
readConsumerOpenApi,
|