From 9325e0b04df18eb7f069ce98eaee4e222581f45f Mon Sep 17 00:00:00 2001 From: EduardoFariaKruger <efk23@inf.ufpr.br> Date: Mon, 7 Apr 2025 10:51:33 -0300 Subject: [PATCH] Issue #59: ADD Swagger --- bun.lockb | Bin 158123 -> 161454 bytes docker-compose.yml | 2 +- documentation/Educational-StageDescribers.ts | 293 ++ documentation/ItemDescriber.ts | 337 ++ documentation/achievementsDescribers.ts | 301 ++ documentation/actionsDescribers.ts | 302 ++ documentation/authDescribers.ts | 204 + documentation/collectionLikesDescribers.ts | 334 ++ .../collectionResourcesDescribers.ts | 280 ++ documentation/collectionStatsDescribers.ts | 439 ++ documentation/collectionsDescribers.ts | 622 +++ documentation/comment-replyDescribers.ts | 390 ++ documentation/commentsDescribers.ts | 413 ++ documentation/compliantDescribers.ts | 371 ++ documentation/institutionDescribers.ts | 375 ++ documentation/languageDescriber.ts | 268 ++ documentation/licenseDescriber.ts | 274 ++ documentation/notificationDescriber.ts | 524 +++ documentation/object-type.ts | 263 ++ documentation/resource-educational-stages.ts | 303 ++ documentation/resource-language.ts | 302 ++ documentation/resource-likes.ts | 252 ++ documentation/resource-statsDescriber.ts | 367 ++ documentation/resource-subjectsDescriber.ts | 304 ++ documentation/resourceDescriber.ts | 417 ++ documentation/roleDescriber.ts | 233 + documentation/s3Describers.ts | 453 ++ documentation/subjectsDescriber.ts | 233 + documentation/submissionsDescriber.ts | 286 ++ documentation/uploaderDescriber.ts | 50 + documentation/user-achievementsDescriber.ts | 309 ++ documentation/user-collectionDescriber.ts | 254 ++ documentation/user-institutionDescribers.ts | 201 + documentation/user-itemDescriber.ts | 200 + documentation/user-roleDescribers.ts | 201 + documentation/user-statsDescribers.ts | 256 ++ documentation/userDescriber.ts | 322 ++ package.json | 1 + pnpm-lock.yaml | 3749 ----------------- ...lfpack.sql => 0000_volatile_whirlwind.sql} | 36 +- src/db/migrations/meta/0000_snapshot.json | 146 +- src/db/migrations/meta/_journal.json | 4 +- src/db/schema/complaint.schema.ts | 6 +- src/db/schema/index.ts | 2 +- src/db/seeds/complaints.seed.ts | 29 +- .../Educational-StageDescribers.ts | 293 ++ src/documentation/ItemDescriber.ts | 337 ++ src/documentation/achievementsDescribers.ts | 301 ++ src/documentation/actionsDescribers.ts | 302 ++ src/documentation/authDescribers.ts | 243 ++ .../collectionLikesDescribers.ts | 334 ++ .../collectionResourcesDescribers.ts | 280 ++ .../collectionStatsDescribers.ts | 439 ++ src/documentation/collectionsDescribers.ts | 622 +++ src/documentation/comment-replyDescribers.ts | 390 ++ src/documentation/commentsDescribers.ts | 427 ++ src/documentation/compliantDescribers.ts | 371 ++ src/documentation/contactDescriber.ts | 57 + src/documentation/homologationDescribers.ts | 99 + src/documentation/institutionDescribers.ts | 375 ++ src/documentation/languageDescriber.ts | 268 ++ src/documentation/licenseDescriber.ts | 274 ++ src/documentation/notificationDescriber.ts | 524 +++ src/documentation/object-type.ts | 263 ++ .../resource-educational-stages.ts | 303 ++ src/documentation/resource-language.ts | 302 ++ src/documentation/resource-likes.ts | 252 ++ src/documentation/resource-statsDescriber.ts | 367 ++ .../resource-subjectsDescriber.ts | 304 ++ src/documentation/resourceDescriber.ts | 482 +++ src/documentation/roleDescriber.ts | 233 + src/documentation/s3Describers.ts | 453 ++ src/documentation/subjectsDescriber.ts | 233 + src/documentation/submissionsDescriber.ts | 286 ++ src/documentation/uploaderDescriber.ts | 50 + .../user-achievementsDescriber.ts | 309 ++ src/documentation/user-collectionDescriber.ts | 301 ++ .../user-institutionDescribers.ts | 201 + src/documentation/user-itemDescriber.ts | 200 + src/documentation/user-roleDescribers.ts | 201 + src/documentation/user-statsDescribers.ts | 256 ++ src/documentation/userDescriber.ts | 322 ++ src/index.ts | 42 +- src/routes/achievement.route.ts | 17 +- src/routes/action.route.ts | 17 +- src/routes/auth.route.ts | 18 +- src/routes/collection-likes.route.ts | 21 +- src/routes/collection-resources.route.ts | 18 +- src/routes/collection-stats.route.ts | 29 +- src/routes/collections.route.ts | 38 +- src/routes/comment-reply.route.ts | 24 +- src/routes/comments.route.ts | 33 +- src/routes/complaints.route.ts | 21 +- src/routes/contact.route.ts | 3 +- src/routes/educational-stage.route.ts | 18 +- src/routes/homologation.route.ts | 9 +- src/routes/institution.route.ts | 27 +- src/routes/items.route.ts | 21 +- src/routes/language.route.ts | 17 +- src/routes/license.route.ts | 18 +- src/routes/notification.route.ts | 33 +- src/routes/object-type.route.ts | 18 +- .../resource-educational-stages.route.ts | 21 +- src/routes/resource-language.route.ts | 21 +- src/routes/resource-likes.route.ts | 18 +- src/routes/resource-stats.route.ts | 26 +- src/routes/resource-subjects.route.ts | 20 +- src/routes/resource.route.ts | 36 +- src/routes/role.route.ts | 18 +- src/routes/s3.route.ts | 39 +- src/routes/subjects.route.ts | 17 +- src/routes/submission.route.ts | 21 +- src/routes/uploader.route.ts | 6 +- src/routes/user-achievements.route.ts | 21 +- src/routes/user-collection.route.ts | 21 +- src/routes/user-institution.route.ts | 16 +- src/routes/user-item.route.ts | 15 +- src/routes/user-role.route.ts | 15 +- src/routes/user-stats.route.ts | 18 +- src/routes/user.route.ts | 35 +- 120 files changed, 22899 insertions(+), 4089 deletions(-) create mode 100644 documentation/Educational-StageDescribers.ts create mode 100644 documentation/ItemDescriber.ts create mode 100644 documentation/achievementsDescribers.ts create mode 100644 documentation/actionsDescribers.ts create mode 100644 documentation/authDescribers.ts create mode 100644 documentation/collectionLikesDescribers.ts create mode 100644 documentation/collectionResourcesDescribers.ts create mode 100644 documentation/collectionStatsDescribers.ts create mode 100644 documentation/collectionsDescribers.ts create mode 100644 documentation/comment-replyDescribers.ts create mode 100644 documentation/commentsDescribers.ts create mode 100644 documentation/compliantDescribers.ts create mode 100644 documentation/institutionDescribers.ts create mode 100644 documentation/languageDescriber.ts create mode 100644 documentation/licenseDescriber.ts create mode 100644 documentation/notificationDescriber.ts create mode 100644 documentation/object-type.ts create mode 100644 documentation/resource-educational-stages.ts create mode 100644 documentation/resource-language.ts create mode 100644 documentation/resource-likes.ts create mode 100644 documentation/resource-statsDescriber.ts create mode 100644 documentation/resource-subjectsDescriber.ts create mode 100644 documentation/resourceDescriber.ts create mode 100644 documentation/roleDescriber.ts create mode 100644 documentation/s3Describers.ts create mode 100644 documentation/subjectsDescriber.ts create mode 100644 documentation/submissionsDescriber.ts create mode 100644 documentation/uploaderDescriber.ts create mode 100644 documentation/user-achievementsDescriber.ts create mode 100644 documentation/user-collectionDescriber.ts create mode 100644 documentation/user-institutionDescribers.ts create mode 100644 documentation/user-itemDescriber.ts create mode 100644 documentation/user-roleDescribers.ts create mode 100644 documentation/user-statsDescribers.ts create mode 100644 documentation/userDescriber.ts delete mode 100644 pnpm-lock.yaml rename src/db/migrations/{0000_nappy_wolfpack.sql => 0000_volatile_whirlwind.sql} (95%) create mode 100644 src/documentation/Educational-StageDescribers.ts create mode 100644 src/documentation/ItemDescriber.ts create mode 100644 src/documentation/achievementsDescribers.ts create mode 100644 src/documentation/actionsDescribers.ts create mode 100644 src/documentation/authDescribers.ts create mode 100644 src/documentation/collectionLikesDescribers.ts create mode 100644 src/documentation/collectionResourcesDescribers.ts create mode 100644 src/documentation/collectionStatsDescribers.ts create mode 100644 src/documentation/collectionsDescribers.ts create mode 100644 src/documentation/comment-replyDescribers.ts create mode 100644 src/documentation/commentsDescribers.ts create mode 100644 src/documentation/compliantDescribers.ts create mode 100644 src/documentation/contactDescriber.ts create mode 100644 src/documentation/homologationDescribers.ts create mode 100644 src/documentation/institutionDescribers.ts create mode 100644 src/documentation/languageDescriber.ts create mode 100644 src/documentation/licenseDescriber.ts create mode 100644 src/documentation/notificationDescriber.ts create mode 100644 src/documentation/object-type.ts create mode 100644 src/documentation/resource-educational-stages.ts create mode 100644 src/documentation/resource-language.ts create mode 100644 src/documentation/resource-likes.ts create mode 100644 src/documentation/resource-statsDescriber.ts create mode 100644 src/documentation/resource-subjectsDescriber.ts create mode 100644 src/documentation/resourceDescriber.ts create mode 100644 src/documentation/roleDescriber.ts create mode 100644 src/documentation/s3Describers.ts create mode 100644 src/documentation/subjectsDescriber.ts create mode 100644 src/documentation/submissionsDescriber.ts create mode 100644 src/documentation/uploaderDescriber.ts create mode 100644 src/documentation/user-achievementsDescriber.ts create mode 100644 src/documentation/user-collectionDescriber.ts create mode 100644 src/documentation/user-institutionDescribers.ts create mode 100644 src/documentation/user-itemDescriber.ts create mode 100644 src/documentation/user-roleDescribers.ts create mode 100644 src/documentation/user-statsDescribers.ts create mode 100644 src/documentation/userDescriber.ts diff --git a/bun.lockb b/bun.lockb index 18a5122e4eaa8938b1051133c06b3a9e1fdff096..21895ee2a75f1cca3c0d0a06287fadd4e7396b1e 100755 GIT binary patch delta 30575 zcmZ2|nRDG+&Ix*&v-rOqUNvhHbM}+_2ctV<J3QyB#J%1)LGioU>L>L#{!f=HV`2b- zritP5OuuR;Rw!7CF)}a+FfcR}<QJEu7o`^SFfuT3F)%bRLFsP{3=BLB3=M~w7#M^Y z7#fmu^7B#|7#KcHyeJ;Hg9ReEl7)eRpMjwvBR?-6Wd2(Q1_n+Bh6X=21_nU}h6ZOg z1_o{hhK9`4)Kqg*6Ncw(5KD_oic0dcjTsiQGcfQnFf<rWwq%s|e8d1zeH}`lVt~k| z<d>x8l`$|R7A0q7mZcUIa6_EBjT>T`H#fu;?K}(&d<+Z?HzzM-l&?R;3vo+14@8wO zAH+?{P*vhQ5Dz97CF>d+F);A)K-3#@LrlrZPf0A!U|{&h53vnq%OwE@1`!5^h9d$H zb#PmGAg<pb05;dFAu}%{wJ5WsII}phs3@_L;Wa-*L3&Pp5-703g&7#c7#JGdg&__U z5rN2aLh0Ee5N~~$+{q+gZzBwm^%H|QGdD9Yvmmj!*jO0CXAy^}jueMDOA9LgNgQJO zQ*lUO-jjf+-zWj`R;MI{u9E;eyFp5dfkB*sp@CltVxN;Fn67VNmWCJ*Bn{C($e=D6 zh(pi}YDj~|UU5lLYGQ5$!vk5c1r1kZAr43~Nd$!s!xUMFL!-Ds;_(a(FrV6k1sEC< zi!1Yz85kHgFfcGkF)%a;Du5I+G=wTZ9J*P7fkBjkp<$H*#Gt&yy!^}*28KBb5Qk;t z=VvD-<)l_+q$Z|J-pedqe^`luL5_i;p;j5<q{_tH9FSXT7$9Mo#Q;h6w>23UG#MBg zN{VwbK~XtP1!ChCO$G*a28M=oRfx@tRUkI?!o)Qh7}OXT8obpR7-Se28uE1^_J!#( zFi0{m)HhsJg#`X{9SAL<%D^DZz|e3(1(J4U^%)o>7#JE%^}!k%SfTP$)gb&w1`G_+ z3=9pyh7kRy3?S<Ns6m40st&{hTXY~ELN&LZp#f&`5gmwyolu|EKz)>=1~Je;9b(Z# z6^MZyrVtB!pz^gUkhqA_U|>*SU}$hKfn*v(6G$p8E-A_@&1GP4(PUsyW?*Pg1kv>j z3=LB(AVE`O0kP=61_Of<14BbnetB_f5d*_rDE|@EM|(6F7!(;88fHW30&9qYKdm7l zQUw+7v4upLh8-kite_5))?i?eXJBYhw`E|c2f1_~Gz$KxLnQ7(>4oZ$xLOXCpQsAS zy)Eht46>j&htgu|kdQb5b>KQEUFQr5v3O^Qxk1nnHGzg$X=!GC3MjFCh6d>a7X}6u z28M?H(74aAh49^NAwFieg#>NBJ0zrH+#zY@xeY}8IF#NGb$AUljjZy7glNAf#6dDp z2e7EsLkxPO3Zd;(A#tV+O=KIPsX3AXk~UI{b29Tv7#J%2AO%7mlot1gB(9v)vOJK7 zc>N*rzo7Cg{tVzsA|*AoKsU3PA>I#?CXDN$MHZ|m^9zJ%4EBR0COtm}22}=z1_eJz zw#qEl1(&4<f*|Td{UF&kGd(ZAD3yVM3(8N+%uCTNEnxT_43U2Wr3-X(@{<!wQVVo* zGIKLa80z1IKotD)h4`R06k>38YGoP7C!a$h@@YAVB_*jT46l75E>A5kEy>I&W=JhA zEKMz{WKao*=u0gwC`wIbV7TE6iJJN05T7R|=NEy3=8P}IW5*)E;@S;6d?7)elA2VS z&cMKsTMV+6fdN(}BxfY%WHT@@s7Fn%;!vyq6$MfLAPSP^RzTgImRMX;$iTo*lv-Mx znO4b=8UwN4EEZy4Q!K>YYOxT1PJvom<_k&VJPZ)`r$NoriHGP{h==IE1)=L3&c;Iu zzKjI02O2=pk(g7=5Ck<)I}uV4TKYnAqcqe4Sb*&Efuz-iJ`nk>$&fTImJG=xbCV%S z@of^sVnI->GB7k0r{<QW7EPYVDOLX@6=HR78pO?)(;)n$qQvCXVg?4UbcpzbbV#Ck zln#-HC61KLB5*32odFTQnF@(x(`1O#ekMWkcc%};DNm9h>I#ZdOG+|RC!2Fg*5_qI z3YDkX5N8_ZK*IGLRQys7q?EMDg}B8q7h*?haZ+h!P71@4e2D(Od`Ov60i~0mv=5Xv z&xZu3ay}&9`5|<D!|yzZz;h^l8A|Vm(yO8LbST}D2Z_)^C>;l-y`i*a9>l@wP+Am9 zGehaPY={RT9;m0-2b6gLRBw>#gRU}&5A~rfR#j+{58{MGuXr6Kiel;@QOZ{b5f@{C zWF47$NC>jdE^gTD!(+qjacIiKokk@u@>TzDu{rAEqcrKZf4pg1h~<_i>T8)h6VDwK zvi=(HGwF1^zr2dlp=;gy({If_zq3>4*@1;qFMoDDR`UPIVy>5bQ#W_;U*KR=n;a=& z&loy+ri49X*W{ZL_KcS%OG?^vaxpP5*fKCQuuWblVb172d8VX2WAo&jlJ=a-m>C#+ zKn?iG3uVliL|G<BN!fuENZB*qn0!;po{5ijvXrzPqub<2X?w<=$up(x8IMiADQ(aA zZL*|{J!AajNEv&^m6K=6*fV~gd{f4rQFpSWtUYHII|G9`149GX<cAXGoa@*b7@Qaw z8rVU$Fn*YPQ`Vl*aI&PFJ!dKh1A`F*Lj%j?L>Y6==^P9UIuO@Ln=>Asd{fSziHmcx zl)N2d<K#$rd&VP^XUf}i{^Vj{umBsUC~eMJ#m&HA1NNMvv^nFk$&m^m!)Gekb57-9 zU~pkzXkeVIC~MC7golB_j)9?pb@D?Qb4I1fk&5=5QM?QcCJYP>%petveUoo0+H;=f zWni!Z>v||>&dJKhz~BK^u~5dGGmeje!3%80LNf~vK8W$mAYZY*;bUNMm^@d;n$waW zVkjfn@45UC<CrEZs#|dIL$t6?PE;^wVi1@trDDfvCIImO<7AKriYCugv1ffIz`zhN zSytMb(@YSeg%PBMv1)Rpsy*jEL6}z(rOY}12r@7@Kpd=S&S*1PQq7*TM2LaG3@o-# z#+-50<e6&roIiya7!1L2vQXZfGgp{_Aq1=fWb47nk?QuW@*)fjc9ZW)S#!pMSl}Q| zl(*mzVPJ5BM2n0$=U)*>WP-iTX)g+i3+Bm*s^**%MIq721ad6rVK@)uh_90)HSHP0 zC(qQh=bR)4(ZxO)<bhLSkRalmtf*$rDlE>x;0E@3x;T>8IaiBAR54FpsA<l`Br#b^ z+m6#k0wTx(wva;-!ULx>PG3n#xUzx5m2)zb#|q*xo}V14W6x<Q#lR2-kKA@CNT_mv z;*;|zl*a-}8mt1+3=B>nM={1so~dikIYSy^6UXF-Qs$hOq#-u3gL!;15FQ(t=OqJ) z9afN68D~tssb|l5M+RaOCpd*j$wGK+;Di}5d8WQS<J`$N_3as7PnI;W=hT#gn7}wW zQOBGybMj0Bd&cRLZyMNhUWCgmls0D)l%E`BXvgU-4^s{b_3p_x4efdN%0nU>)Gz>f zPkVBJ1P7<A0wfj~CO<SZ=S)(7c!^<hqM<qK2?YiQugQ1yta*hL85pcVSrpWSnEX&m zd$K?-Cx;>=jk8Wxv^5v(Q-t_{5z+@|5ShGCMjd1Y?-@mi6|4*l46KtCWx*EnvM525 z2?GNI)8s@Muqcz6(&Sqbc1(3jlcS96I3FrOG9Cjcx;ZtKAs%1{#Rg}GGQ>Vesc}r1 zfx!ThJQd8Dz9~<hWo*Y}p)&cFu^lIi76U^O$nl_9XDZX09A#q1x<ZSA!3vbjnI36P zzGY&^8K@1*){4^Rth2Ql7;GosHL+&8p$(E|b=P5F$en!G*qZa74g*63*tmtt796?^ z3^8C1s2F;w%fJu>=UMA9F!;fFop2tg5V@`g$xbYw6v64I56Mm};8Zt3pMfC&tPiB} zfj-Pk5YNZ}rVqrcFo4NDR5a)OYXC{fEFgb!W*Ne42dUg)2s2aB)PlnZ5|H3*z!_r% zNh_?AAL^NN&M|@{TnO)m5yW9k;2@VWh8V&GR+(iCu>iu`VGM~5us+sr#taPB;Lr*& zfdnfHC`ED3Gl7@@apF4@n1d7L%{g66Avql^$GXUrfgxn_T{9aFQ<xS|ap`6@S<2Rq zv(AixApssl_sk&41mYhPb65~5%9wLjnL`pOBPgI**O@agq=TZBRn!8?;@n^Xk53tM zCJxKVQucOCk(QIA?Cm)BS~4)0f|He^wmIu3O9qBikgr(7tr!?WC(m`X;jm(0NCG<q z6#snI$h^tc3=C;-IUyTZT!GS8iVXupGT5lCwhRo#V3xfd1A{-9)n~`RkO+3>dpib( zxXH2h)||ffFfW5_T5Aspd`MvZwr6072dj^AfU$NuFfhb|Ok)yroP5jKjx*H}Qq41i zlgCC!28JlG;}*)8vvNBzFhqkCbEY{#(gwufT}~i>-Zio2<adTd10;TDIx{eYPnNZ} z=KSCcF$XNp>E!|mdoYi6f(xhui?z4r6m*4TPfoDij;=^C&DrY8z>ooU3CLq_T_GtB zV!yr{14AarU92<QzyaoH!{P=G8)IwMc6SDbK(OQucLoM`FiYM8CffjGaX$1w&ZD-T zNb$gV#*={|1#CGeml$|K5+o})AGUcxybN*5H7~GjCf1zl-jINVc(T}=fx#0L_MCgX zA)aRe*F#J`kc<S@&1B~@`IfgG=W`!OYUG@}(Ab={$&Z1-22{Q>?em*F%g2sW-5-*W znI?lWM7}>H&=@9z67qb1h<Oa4Rub!N5O4Bb8EYo-fXTOf?KlGiAeBAC<b}HCtnC4y z`ZHF>n)7S`q(o;1rGF;&z{$7#>^LI=VP+{xn=?%boE+tE$9W|XQcQxIAe?SNkT_zV z3@Tc>f*_`|fO)5aAljM0^*viKB<F)|=5z^$_>gsSqPjV21xRjktb#S?wqS?}kf3D> zf#?AjcuWo<lV{1;an^-E>j`k^ZwrBFU<TKq-=P{9z&z7XNH~G2F>}uLP>6HDA<cO> z6cTDIlNAljIsb)1EMlIl7-r3AHaS+^nzJYj5>L#N7fPFR?g)d}!vyx)J1CD46hWMN z;SiHSwU#+&Ryd?E-~zj0ML0YMrdx1?LqeH#@<Ri2rr?Olw?geW+ae$ZD+f5ypO1hj z0k<VMIU`|d3)JS0jGTNc%#O7?l7T^Ia;%g!=k`d5v)RFp`WgwTDj}7HX%r-8*ukZ6 zWfUaPAR)OiYI0PB9VcHjBobJ_DaR=qqJ#+)C7e~!5St;X>Qpo&Z!m%U#H1E8c~+zy zQ$@_=Tak90t79M`!w71UaXyS;U~q*Lg|_CLPO%WbF@ha2F%}Y{;MNJ#_1MW$(RQq2 zaSRNOlVxSCIm6=^7(yY<Oa%*$IEdT8S%C9F9K;+*EZfIJ!W7bw?2U)Xftv2mpggcg zIn@#%#RMd=7A8Q#7Glck1W3Pw50s9W9wkh^6>G=okO--Vm_Yf1sVi}ERGb~><wRIn z0P1--B*AQ7sA<mHm&CvjHu<i%HEU=x1A_;cbu$@M8iT~lQ^3`ew>4{b3Mi}H^|t1` zm;!MxxU0dWo;rC}f*of;D#W|&lN0^TIhUkDk`Om2xH;dZLgE$Dik44<sAL33T5uZN zO9tkw)6+mD1*jyw0~LovrdT>e4<wg{q(hP`J2+p?ONXQrNUiuf9bz7&S*)4?NnhXw zDQ9v9B!NI`h9wygm5_kG2UQ79AgnT(us|uw1eNWw@ir`(Q2(=XWPzGgph71o3uYiF zJ9K4DzLjdnc{&SHvv7j^&Lp2bIV#PLsWp4@tTa2OkJ*!NrP*;h=0Nf_BPixLJ98Kq zJi#q<kSR}cCeKQ@V{*%#d@J3Kvndzi0dTd>bUJr(RE8bv?tD-M8k=Fw%2mL?;5!+_ z3Wu|nz*!%`th?FvjNV{1orRzx9HjaZoF!cZ6H9@!)`D4gGi?})CQD`6GZs&d0+X|{ z>{*IIH4w-Mi4qtq9?n_@XT2?9U~mOnYE%kh&CRf30W&~a_rO@3jAf93U<MUKOhILn zqw?%n=ahlHmuJoTx(w{SJZn~qau}->&bkC<-7N%rFVC7as{-tmJZsj?aMm9<%e4|F z+XrUd&9`B!oGevf&sa4%3QW!_uxF_Pdn(VG^(UO=Pz@7nhqKOAgFF?RXU!^H17gk1 zvta=<KtgljtVb{wXG$$3u|W#Dd9{%2!3gS6FkP;le5=HcNvUqKRH+?PM&0D7Qah%V zb(3e6+OgiPV_>kKd{@z$Nxy!wRGC%1ECYD74b-^-jj9t(^D}^l8yG;-oO)ng3=ANe znE~8UW&m|(jG*Fp=z0bg25@N!R%!<7(=dSZ0GMw9CLw%~MOIKghz40?3+01okcD<o zK8OaXcYsV(ff{UJ2Sr2WK{Pu9sLff=zyLA`G|vj^W`X9LKs0D>6=YxmR0B2|WI+*B z9z=uGLr0GpkZF**Qm8s)8svZ)5vW8B0|VHFwG0dl?34eNiwA;?YlX@ZL$fh3FmyxJ zgJ_Voy-+@gW}d9uB3=&?m<Y9N5{SdVzyP8_s;5Bt$TY|mQ=#goLFGX-Nc{{bA4G#} zpT__R%!N?(i=gr#8WhM&85ls}%fPS{DgmNF7A%8mSPm5j(I5@0pyI2c;vgC%z7ERA zMuX%xf*dkgw-w^utx(k<8f4oxsHxkb;>a|}TRWlhyFlG;1_p-xQ2qg^dSn`;{t#3g znFfg;VPJry?i0{d4VqmCNt}TicowP=M1vf54w~}W7#YCXiUTCbz`y{aK}=3Y25@fS zh060oX+cIvxQj4?=LQ%Qq3To_>mdfILltU5X>CSGV$)${VBlb2U@(D-n?Y#{sJtcA zU>imT22ieWgz{aW@~%+z?ofFjsJuUv4yuPL2!YaJP>tbG1yPLPF<*vMMg|5@cF2LM z%Y!<s463dYDqanxYoYS3Q1jZL{5~kZ9~4{+3=H)k2B?6U47FeuRKaX0JqPOYg-{J3 z8kCfmGlJ(X7`8$kumei(hSK|>L41f2JXp<ej*)=@r0)tNc)pq87ev0E;UCmuRwhUg zf<}`;LCMbq(ICnMiBm}?NC+rE`6^71I8|qYM3n|qy&e-JN)4d$#!!7$P<7T&+6F9N z&%j{M1Rh3b@BpPe1_m$<$|K%Tg+5RV1E3a!F@a}H7!sHuX(IzFp2r07*%T&7B3lUc z&@!+^3=Auw=B$M}a6QO;P;s*Xs$ese-Uc;r4^-hksQ5uBeFSRI2`2EYDZ?wM!$CAC zh(AF2AR5H{1hR;Mf#EZVgGPhwN09(U^B1Va-=G@s(IEBTq3W>FAo(9q^L|0qfoPEU zZzcvN2FA&EJLMC>GR%;eWCVpis06@6gS0b2<v}!v$qFJsMH18;HYguNGfj@I6Hf%` z;)05TXb_W^8IoT3p}GV>f}q6}%#d^^0u>j9iesZet``TXn>@EmeDaq%iOFZWIAFM* zlYxOj1*#iFgH)?Q`5+qPDs?CynFa}Ifd~c$24otfUk54<qPZCu7|fX=xy6<lk|<rF zzH(;<EmdG(U~mUH50tv08a<F`w#jGf#T`MJE*PpU6e<g%LCy<<>JEp}5m0#$4U&%p ziBJApFJ2FFTnsZLD<?wfG^lE9G)Q+kGbAf#L2b_gna04tkPFoZqCw{7L*)yh;>a{; z60Dt>0i2#0+Mx>QPebe{$pIjrbuxozTNxHW9Zoh~PpJVE=m$k*{X%HmErQ0?5-5Ku z)L;+|QV5zF1kuZ(@}QcY3N7t=a1$G37#U4%aN7aY!UpLF(V(b7ZefGOL41%nsD%yU zgJ_W7KrL)gdj>QW3T~)^n%E!(AR45Ba8nzS3n*%72Y{AXfXYq=29zc?$RVI6H^?E# zO>B@jh!1L8fLhofK8OZI&1g%Tfq`MPr9Ilx26q8QTiT;7ZBPpvR6>I2(Uvv?1E|Ff zswqG%Y*4s>=+Txov_*s5!UhEnh(FrW1~ru!7)WX$g8~n;B|p+z+J+>zv^U@Ey`x;e zYQjAsJBbRpeH;_t{=J@jWzAv6ws@<I=DR$8&Hiscv`=G?u5jp_aZ+tsw2jB)OB!i2 z&&^!;ZPGe(3I01ZbEnmT$A$j!gNAJ~K`{fxES>+g);r7SL@YM@wDfLt{ukxfMkgNi z?uq8rOo;J%{j$%p{m>fYOi{_q@Gr|PR=1Z&vDkk4*;%q_b#R!MLshhf_hjEq67>&K zY{PkG&Yrr+>cn!6junz0iX4;dw2w>tGnf0~C8d7XYG&~!**}`ELRkM^PZyY{xy}8l zmg8JOzQwcO_0Q*Ye2(Ng(4u6h;}}>DuIQQ^JI6(9Q-JDZ%UZ6hiK6j+`&vV}ew+B8 zVOz*E@7P5H&AppbBzNl-9N)GgSW)Ho!{eoI#dmVPX{~(w$y&B#^50Do^*i&k&feR# zTk*zmo~f)I8@!trU0PNYv_?7j@w|QeW-ek=io0Jc@J#p6pEDkNOp7Zc7AJmIJHGPI zg|d5!qCy<U{v)|A7v?ku1_l<T{r}P?+SXX}%6kOd(c80I<som)jUvr$LdzvTTmIpa z&b_9y)YiUGGG;=_gb&MCTgV7xEU~^)=(VHj&S|v}RcrCdYd1^OUpCz|VS$wD&3%9S zK6QVS-JHw6)@gU_veVVq%@xI!=d-DKrdgeLSbhDf$L1<yE_?nT8G*mQoVb;vD-}JD z!%YJ;g2%`JiCNI-KFonEiRT*~-wW+)J$`+ix#OF!=N4U@xxsRc(!Y(GOJ160Y<9X9 z`q_hh^D)V}$5R#W{f;&|=Fw28xpaZ=;^57hz9CLlp_5~`Ncen+<x`%X8PQ;=khs&N zRN>p{D1M&*DSsljeVkhFoBZzMD{r-uwF__j-Y>P~X`$P)-*>ol<8#-AM}=>%knlR~ zmW32{g_Boq44*8qm3K1lCU3^#$&s7FC!g5LJ9+OWZ^qKeoSVZZS8U^*oV(eZv3&B* z&Eb<Zw)0Mw-QvwyIXQDn_~aYgc_*LU;>}n+S#oRm<c=M@lWVtnGuBQ%xix&U#ZKPI zy4$=N>nB%k3!nUAC-3CD+q@YYCu?pGpFCq1@8sU?-k_ze+ruY&?B<<pyThBYb#mv9 z@X0@R^G<%d!<(^vvgOY3$t(8oPM*8do3V59%bnqqBlhx6_TA;p*gbjXuJFkm`*<h+ z-Q~^LJK1x0_~ae?cqgyj?akOf`RDHN$r<~3C&%vbW}G;A<(}}#5(juE^X~O#oIE*l zZ}{XB2Y4s%-RsRbbu#C^@W~Yic_-)Y^JbhrdFQ_H$r^`vC(G{lW}G=WbAR~c8;5u& zpWW}xID4|>f$+&4hj}O09`I(IJNe{+@W~cOcqi)~^k$qtx$<E6<QGSHC*M8j&A4!~ z=ArP(Gmi33?mgtqxOno-L*bJ>j`2>mJ?zc6baLn6@X0@p@lJkw*qd?rWXmJrlUE$) zojmu5H{;65FOP&zjyS<P+4rb7<Lb#XkA_d?ILSNt?@@2YwUa%Mg-_mbl6UgjW8RGG zC;vPaJ~`tQ@8sCy-i#Y3uRI<;S>iPBWZo0rjGHG%o(P|O;xzB%y(hdGw@&6f89uq< z4DaOJlirNmC+|ENK3U@|?_}9i-i$jZXPye5eB&(d<g=%|8Fx>XJRLr{;~ekg+SA^Q zdncbf9X{FOJnv-PGv18*Cs&>cpZwxH@8r8@ycrKp);t?NdBz3a$-QU2K?{G+hEMjm z$UE8goHygq$(`rIC;zy}JNfN7Z^q-3EzgHfUU7+c^4#;@j3+0*JRd$e;xg}K-wWQ1 zrzg+65I&jX3h(5<7rYtIPWHSQK6%F#-pOk(dNZD%{PSY?<czDllVdM=GhUp$@>2L@ ziEF%*c`ti2UY;CzIehYoYrK>9UiN0ZI+^oI_~eS~ypwaUcr#v~yz@%<WQ`lVlVz`Z zGv1t>c{P0UjT^j^&tCOrygga+TKMFSo4k{2uX!`xoqY0I_+*P)ypwgWdo$jjTzNfw z@{3!%lkZ;lW_&nV^G5jO8Mk>S_ulYkd_4K)jqu4HcX%h;-t=aCI=S;^_~ajVcqhNT z>CO0jvgNJt$t&*iPM&+qoAKr3m$$+vN8IC`?0egr@%7}Hx5FoM+~=MA_qI3V+sU4H z!YA*z&pUbT9dE|>lYia`pPcc4cXI4qZ^n<4SKbYuEb)+cGVeWa#?O-@?}bl3@sM}& z-h1ARUng_k51(A|h<9@CeQ(C^lXu<^pRDnice3mQZ^oaKGarOczVVoM^4SO8jK3#K zJ`A7S@q~AB?L%+Izmrcs44-WAly|c3BX7q4lPe#EPk!-~ck<mw-b{>)leHd)O`h?L zcXIDzZzg8O$+sSdP4;-sJK6S$Hxn!4<gO=SlYczto&5HRHxoPKWUHrPlUKapojmuc zHzVidmruhdN4(^n?EB1{k$dvYXW^4MUhz);`^=k>ce3a6@X0$~@lIa*+?$bq^3Uht zlQUlPPL6%y%_ul|<%{si5^s1X^S<<E6rLRUGJNuhH@uVgzVv1koy_?vd~(HG-pRSI zycxwO?|c<LS>qk=WZBo=jFOWxUx!b=@s4-$+1K8T(vv0Mgir2x&pWyHjW?t0<dbj0 zCtG~rovi!Tn^Asp<=gPdFFx>2zWdgjQE{^7yYR^~KJrfPedo=nJo)Ck@W~#ZcqiMw z_hwX`-1$Cy@{dn^li$7fVpN}O`5}DriqE{0=YH^J)SUeCL-^!~FT9g|KYBB2PoDWP zd@{#Z-pPMIdNb-y_WTq+dB<1Y$!kA(GwM(N`6+yI#y8%{v7fye4JWVs96nj%JMU!P zFW!vClOw-`Pd@RTck<pZ-i)S`IlqQauK2+_IrpnKqxs~WU&AMB{N$Z1`^}rta&qRk z@X0rR@=iYc&70ABvgG&h$sNCVC)a-WX0)Ar@_YDXi{HGHb$@s>+E1?h5kC3FZ{Epw ze|R%GPS*Sx&ge9`@n<-r^W>X9!x>#B8~zGsbe-J!E1c17^21-@jP8>ye}^-AOrH2V zoY8ag%irOQUXvaFgfn_ip7|%7(P#3<KjDnNlRf{2Gx|+l_&1!<fAY`2;fw*31OJ6H z22Ni2FPt%GGUNYn#^A}3|HBzWCU5*7&KNqClQEnzY-%E7IAi$Kos8j(5z_@38N(SP zr)PqwsObkmRP=O7CdP2anCXQeDt7uw5EVCFk(n`^F@Aa_h)S4#5kw_U*JNP~XH1&j z2%?gw-vm)9(+yb}!x>YjcY>(2=?_6v`gBV+#&E`r=@UUz=Jb~!Dr>qUJ7YLw_Vk$` zDrfpf5S2UKlY=pwF>m@p5S2guCx|MT9td)J;q;Xts%SbR7h^bM@$^U#RWf}eh$@}V z$;}wfST;QoM3qn938E^d3-U0AGgeN|1W{Gf4}z%b>5{yR;fyuY3qe%v^phZ}Zn`2L zV>n~|^hyxbF#RHkYTT~L&uGrbcxrp10ON8dCLR9md~%FjjFST-SU5qOsX*<5m(vwR z7^icVi-M=Z8XC7B6k)Vy=E{R^XZ2N_&L_vX45Ve71Y-a*tC~3j1K)N*ImYFT+Z7}j zS-_@om6n3`zA`YdxPq+M#>jNb2gFzfRuckN!<z`*m*xf9kA^T|3FCAHHAV%d<W!K3 zJg{0W=>Df7r>yDw)EU*74rWb%rp~yD^#EvZ6GZQ%J`Iqorccmd<UkV#8OX9dK!@?D z2gr>(8M!P#ja>!?2ARg`@}-Ox_5c1u04M}N6SSbNFKAyHG9NU+3YwS$iA8|hERa#% z(;x{328Kwe7--J*F-Q>u149&43^W7t8Y&hI6$1@3#6!gD8DgM<pwU{`l95=b7-*Ur zG=TzA8wV8w%{&=HdtC8QF)juM25YET0#uBffq`K=)PbN$GMLA9F+t|QlECWfA@iCR z(0R>dupnd>7&L?ovN#1Q23q@40TN(f08d?m3>08sU;wQ!0Qo2ls!osryhsN;wVe(X z6N1kCfIO7J2;O}L+HlO^2%6gfxgHcNAOk@wLjs`l<DhwTkeDa~14A%$%DDk*AZTg` zB*x3Yz|aU46K7yx=!8132`VN5>X$M=Jk$&olVo6E0F8%(JXGHTom`h<U|{fq1|eu- z9b~aI)MAjM+M$|d7#J8pOF=;PbU?*Ga~z=MARw_$sF)lB1H(*^00RR<7gS81fq`Kb zDD8n3tw6-;LEDxY=0FwpKpmsVz`!sUDh8X~S7Kmb04)UpSq7Tm2RTrgfq`Kq19$@= z!vu(dpuM~d^BKT<cNr!^#XLYk#K6EX0pttN4m6umV<S5S6NTdGVHJ!`wjfV|CT~F9 z&jrj344KRf44?_T3}yxfP{KdS#K3ThiGcx>;LkEKFq~szU^vgjz;J<yf#KqG$4W;1 z`g=?a4ELEB7#=V&Fg#>pV0gsD!0?!ff#C@g1H)4$28L%$3=Gei7#LnKF)+MjVqiGN z#K3TriGcw$@eRr|pgeMifq~%y0|Ucvkk>&@2L%Ts0|V%c2xdkGhBu&o6(a)!==g^x z3=9lk7#JA7GcYjx1I^J~Vqjo+z`(%p6Lfe40|Uct1_p+Q3=9nC85kJ;fM$>x85q7Y zFfhDhU|@L3z`$^Yfq~&E0|Uc*1_p-93=9l^85kHoFfcGYV_;x-&cML%f`NhIBLf4& zD+UIJy9^8r_ZS!$E;2AMTw`EhxWT}{@C!8S&cML%pMinl2WWHoeFg@GM+^)MpkpO& zGB7Y)Wnf^q#lXM-THta7lo_WdRxwJ~gH9a)<#S^O@M28Rh5_&rG|;3OXo3wiht18* zz`(=IzyQko*~|<KpsB=3%nS^(nHd-+Gcz#EVrF3IV`gBO!_2@ig_(h&i<yC8Dl-E^ zKQjZvTxJG_`OFLq)0i0;<}oucOlM|b=w@bMn83`yFatE1+QZDiFq4^qVIngFLoYJ} z1890$fti6pk(q%(nVEqBG#M_&%)lVX%)lVT%)lVb%)kJeQ0HT2VBiEzNi#Dru!Cj- zK{LF}3=Dsn7#KjS0e&(uFo0GSfR-qHWP&VBc+JGX@Scf*;SCc5189Mi33ELIgAp?W z1E>VkWoBT|V`gBmV1|@lpfwVp5^E<D0|Tfa0+nu{Qtvn;1H)-X28I)i3=C%&85mA7 zGBBKFWMDYO$iQ%nk%3`4BLl-sMg|5+Mg|6HMg|5sMh1r8j0_B*&aVd}WRb=yCI$vy zCI$va2_^;xcP0h~(CQx0@V_C*AO;48ozr=17{%+W7$D2FKm!e+GZ{c#de9bX(4wpL z&_f_V+vlyJtClQ5^YqX~fw~L~44|pe2@DJjpw(u1%nS^mX>ZW_099tl0znC81_nvc z#4s}h185ZjXfYT+GXujvCI*K8Obqo5pmh|WwHjYR?qp_Quw!Omum?pUBLf4dD44;- zz>vbkz>vzszyMm816o$KkAZ;!v~FuR0|UbzXd&3fz`y`nK-a~<z|aAmKm@Jl1C0V~ zW?*301S-WD7#PwSAS)O_8&vZ_u~WdzzyMmoAjQnU09v93S}FLOiGcw$)al6#DI|TE z85n$-85j;SFff1?hV?KoFieLQjFTA{7#bKD80r`p7(la)%?u0-O`tr;#J~VrQV;}6 zhtR@tHUk5=>;si`pk)dnpz2^P0|UbvP*5^3Fo4!7fYvF1)+iihfGnAiV`g9gRbrqz z3sm=jCTl^f30#>O7#x`y7(mqrsA>S=c4$!#TKxu^%&lZ*U}$1yV5nkdU}$7!U?^o~ zU}$D$V5nwhU;wQ=sIOsWU?^i|U}#}xU}$4zV5ntgU}$A#V5nneU?^f{U?^v1U;sI? zm>IOxn1P{!nSr4MlnbF%MJOW!0|<lGB7#;Ff<`nO85kG>m?7ez;vZCsFJ@q104?+b zO+|uAa8QZ83bfT1BnXl`04=H$rcHONU{o`eU<56RXJ7y=2CHIZU~pn&U;vdepw(#( zj0_C+jF4gpR700T<GXPC%R0v8O!c5KJy2zr#lXM-O3a`{4NBagDg>0!K{PCFfYgEb zCD6%c7#~K1S_L3^&_M+tF;Ip9MIWe6tcFHAs02I)t$1gF%4SgU2TF*bL<uTCK}91d z?SRq;DBXY-AMRjaVA#UIz|aCMn?YqVs7wbfFa*_)pb8dLmV-hTl;HO=K<d7JXrc#I zwxEy(WdcxU04;C?6}{U)>qkK81eD@IYa~GnHbL1L6b+!zUcmrK=%7#sE!qSnUQo1w znh2E)3=AM&fqV(WAU-T{gV@O8AT~%0BoAVPLj`0QNB~qOfL4`)5+$gN0EGr91VGso z<ZF=YVYvll2*?0jG)NBQb5Ll2)PO=4l+8iyACUPVc@PGPfeST|B_IJ11}OkZ^g**I zDEop80m*@A(85^|8-zi85DjuDOdZHFkQm5AAdi9AAR4r!7Q_Z&P%!|ar-0%g#6VUI z;)4<m$Z(Lx1q=+}HVeoSP<jA`1}G#zAp%kdid#_pgXBSaKp_V*1H=Z=AT^*g0#Xku zYe3?loCY$d3KajKf(9fAQjAW6G{Ou9r45iKkOiPn0;vaKQ0T$bfPxsL1{6v#HK4i; zqz+^@$U`8ta6TyhK?0z%9^}F$3=9k)Ne~A4669l$Mo?J*5(8lnA7l`yTmb0>l@TCu zkWayh3YyhG4gfh8rVeBl$Z^Pa)q@NG83-}}RI<X@ppq8G1|>`o8{|8XIuHi&L5=`9 z5)`bUCA*;d<|G3H1E>xGE%80hz`y{i7(wch9R@lr38b$I6#wY1Mk*W_U}Xco@&LIE z0Ht_X{s-j%P=yCdAE1y$&ikMuACm3s85m&s9+clfl^Q5-gIo*>a+ohcg%8MAAcH_I z2L&Za4x|ny2I7Mf7EBDp2Sq0+$U$Nt3=#u{8b}PJZwV;=ktIOU0pg>F3P>DO3WDTd zhJZ>&kRc#GNF0Vie2^s|IZ#Ol>coP?(B(m)S`VtCVc8F~t{XX@f;7P7Kx~kKAcufz zTUZEyd;*Flko;i=1_qEE%rX!S!l3d5lo&y3Ko}`4)H8sB6O@3^Bp5&`7i1a8B2c`7 z)Pdp@UEOI01_sbNa*#aC9FV1;5P&5#m^gZ<9s}inkjp^v2J!`{^a2G7%wkXwgMu9t z{~(`Ime{bQHCX&31qt{tF_>>a*@~Df1yYZkeL=kuP<IIw5}*(RVUXuQG)N5OX%HJ+ z{(}TS!G$j^fYgBM1P~3<2%=$z*n-x0Gcqu!Lfak6j0_A)j0_A4(1tgteIgF(*)uXQ zfR^ZUftG-S)`v5K_5*+xkV89k|Db&>P$v)6hXVE2Kpi<yzYNr|19kF1ok36^4b%q% z^~FH_FHpY>)KLU=u|R!0e`xm#)a?TG^FVz+P#+DX7SxdhiG%p}LGcgjEqXyae4q{; z$Z$|+57hYsb@DzzJ9D58;tvK$j}z3h1a%xi3;#f!JdnddY|zPtAaM|81+~N&z#I7( zoEgA7*1#JVK${jo9^(UTP5_N#aD&D#7#SFZK*u36GBAL4FNiWSFbFd;Fo1S2fP#yK z5z-5lhjw*AeHqXw4#?M1j0_C2j0_Ai(Ebg0w*w;s14vE<8YQ5Rvtwjn&|-viL_tvo zilTZ@Uq^$Hfx#N8Pz|(BpOJw9v@-%G4%#gNYEOb3q07j?0NN!13MCIvs~brz$TE;V z&~6GVMg|7Zt_cIEgY_9181xt!7(gBar2%tB1_pgl{DV4K#*7RMMvRbc7p9C144`cn zAPYd-EkFi>90IZ&<a&_HVGaVxff5_Y@h~xvLqX$Lpm8l{Mg|5qMg|7Z_6*S03@=6o z2GG_FPeuj?Q135+ar(O+Mk!X%AYH_C&mKl|O^`Jp?Vt@76^slF<%|prpuS)!BLhPT zBLhP*BLhPbBLhR>^p!n~)>@#QDK(4?44`-f?ZE(zRe@;GpbChdFb&ioW?)$Gb-Ph7 z<0M82P>}>WDG+v44-;dYfu4n)!Sq9YjAo{wf(&#Rr5Hy_R@=It{7j5-hK70udS>8} z18xR}hJLk$HJ$SUcY*a88|oP`JescC&nU_GcDj2%qcP*R>DB#=k}{x#2s%o0^5RCN zm4{y`f|Z-<nK3Z%Fizjl&uGLX#yI^+Kcf%h;pv7G7$q66PWPU`C}|4njDrq@R92ql zwQ)g#xCmpMp`MYR0i?SRI+T&)iR<danjdG1FoM?MgO2aioIY~`qcNky^s^HfC3WLK zJy-^YhK|VE61}1fGZDr>&>#T=LqlRwc1dMHDue4m?{wd1m(@iWOQ#D@WVB{%obEr7 zQJb-Edi6v`MaJ3F=T2mlWc)OJ`$R@##+B1wgLpfpvrc04Wi*@~Jc-d*8g`~9U*MDJ zU+1iEU}B6j(=!0M(r^00NsN+=&!@ki#3(ua$|Oc9D4TKNbk50)zKqV(!zVNPih#Ny z$iXSV$jCW;$7IH9jGoi`r!Y#I!VY1oev^K-L+G`V2%{Eg<cWcSA(|7sMW;cJ|84uV zCr_q}FxuG~8iN8UZTj6QjFQqtoZx}ehSJP+m)%|6J|VQ$PZylZD9PA6U3)5{r1We~ z2Jp$Hd(Uij<Cy6djZn90di+#INz+}NkOQKkH*iFxX13&jBf~_`kb&V0C*-g#S67do z8WENZkQ)s24D}2d9!y^g()yJXa!i+iZ~XL+LG!E;W^-{tWETC%GhjI(m5Y#(pZ*)< zEORc%DPx}e43h%XHWot7W?*3OpRPZRQIauZy5}@TV@AX2wIIrV`bLnT_jKRsjFQrj zlQJ0^lwzcEW-m~e2PI%VP%33eoBn?qqogV9;M6F?&oc3aYzfe)Gh|?Z9eTQ3%gRpH z&U-!+W1J}@QXytDZkwJyoza+yk7xRv>5LN6u)|Z=>}A^;DRl^Dk^uvQ^7Ql586_E^ z+RCRh&tObvY@ePzgHclYCiI9@#oPLE>T!zCnHcL#L2<{xaA^Ac8H~n^zSA#*D2V3i z3Nsm{7++7fp2;W)vzYPQ^!%BO#*C=8cu&7RlhGHu@t}BN*fHIH7Nevo?5Nh=m!2i9 zDBjY}#8_ttjyML`VXljeuldbi`qLaNV*rZnOVfL2F-kJtoW6V(qcNk_^xGhw@$}sf z7$q5Prt{Bclr)1K;3_F3loO)Ne}#!L&REY7lp|nAysqN8_V2&*RTFTGfb$Bc$n?0` zj1o*DBGW5oGx{*jo^F4eQIhe)^!u|JT{%s}AP4&SP1l{nD9OYkK7G%8MhV8q>4|d~ zB^jSiub#swDGfW>bw%aBeB%Yujx3<k3{+w<)J<OxQm{}0a!T8eU)33hBBm^5V(gLt zZ+&RkIDPIsMoIq*65s*&hLp&|hvxAwU}a+5EdfcOu)|$LFTYW#$`^=aVvMtZc<HwU zB!d}peSEFuCc?tR_*?>#ADpIp&t;U9h8-mPH-~XUfs)HDCdN1uh}MnMH(qBHlQUpo zfE_v;#W?4-+xPhe(Bx*wzyMYw$;2-;{oGte2~*f<v}^JWx8%G_o(B$EZ~(%NqfIJQ zv320)w_sw7GtvXcSkQFod5n_M(1U9m{PYhkl00=-1f1Bxu~IkPe;%VGBP0-{vA6|P zo`Ky03MFaS0k&^aqC)T59B^S`jI-1;(lcUU=$d|U9-}eil<BPV8I4V02i7)U3sZYs z>LLh^Y-5l**wMCvq2bGxDT?0*%YdEoV0!L+Mq@_f=?mvG!sA&2c9JdZC^;rZ13e=> zGluCO7BGs`$C*HKChVMB*g<n3RfeEi27baV?1(vteTI65hI!CQ!+7W+bl`wD)H7vZ zSOq;L7j{e?INFRrL0y#(8dzmu&^3Gf+TEqT{vbFKjEwax7&b$X*oB>O2XX?q!eT(v zgro<2+%5wH1MIvzaKstunJ_TG4&;TMhzE9@sh%-N26Dc1d9LdI>HiimvQ2+BpHYeF zu+ns{1&p(pYL%xiTfo@BRI4&QVLhV+Q>V)G2ZtCXn5L;r->{NVf@!hJbcf}P5=<La zrcYSND8aN}W%`BFj1o*2RHhefW|Uxhs51S+Mn(yy&nna9&M-<av8ql#cac$oNkVnH z<z$8Q2M^3B^a2ZV;>lRe7K|Fk)b^Q=Oi$h*5$mNOk(UJ&Y1e>8jHcPBKa`)u>Ki z2NIvCI(@@oMhO|%sj+Jx<<AmQd$)**(OA#i#8}UOVV~-BgT0IrOjlK>zXRF*Ms>Qu zVnzuw7U;38en&W8hd-AM2kS64(KBFx9oU+#e7k9)`a@7U1G&bKfx$#=dfj412__%4 z>2)A8Q`Dy0oCUc?ZTgwTj1n@iV}jqXY>)iJECSPM%)qctZQ2q>2^rX-wZgiuVpt1| zrXnnTq&EHEHbx1iKWfwVF-kCrsZZYrGTA_Vdff&_2_|p#=>a=H{#T#QbB<AhsYQMI zg(Zv<ObgYgJDg*bkbxaSt9&fRIgxouHaK;GbL(C8>2ga!2CGlM05VxxV|pLR1S^f{ zIUw;Ujp=gx86}viG^Q_D$|xZNJLvb@k$@>>F}vdsChgIfeg~xUuEz9tOBp51{zH!n zo>t4W*!sGoFI1&D0|WT9VFrc<i~X|iG?J(9L3q<ebGpqkMhTg8=t<2Vt!G`ZVb#10 zR$*$PXTZ>_IlW*RqXg3y&FKQ?86{+HL(hV~<QYAmSGVgm)D}YqhG{C(8!j^XO#iTq zQ3@j|!V(Hp5mep?N`sTEzzRkqTuE65c7n69<0<2`NqYa87@;*O!x5e7c{`C3_f?(g z4^|)&Gdzht*O{&d${etS2aCcm-RTCPD9zWMZnq1biC`{6p+Vk*rU*P~3ziFExk^@l zy22Vp2_{qh=`yR~4)tMzicg=jno)`g>bmI{Rx_Hw^C?sX(<y`Ld6z+{4Vv2?8BEUu znFz57=0pjmV8iJSTNov#zgxp-0u5Osxc^Z#!7{xOmXM8u2JK>%>GO^<N=)Zj$0!9V zQ$QS$+t@BMf?Yph9itJ*;YZdn5^D@3alpzgi2K2j4=%3^O{T8{m1hnn)6Z>3@-M7( zfkhoG%3x6lGY^(KVdVf)q63$U(DH5izYXvdY6LGtVTB0HP}KB*C^VstnBH@cQHrU< zbh_LoJc$NoD7s5vxg2U3tmFlSZoy_oA5f@*6DzttSQ>)qgT^>ipV9Q5E%2B}1S`~# z>3mz^-o}uWfgM0@nlD{vc-7|uxCAf)mDsQVnPM@0%~nPqCRpghVg(wD)7`c)`ax42 z!g%zkgp{j@P{&nu!Kx}~lrf>31G5|&5JWp4QDs4#ZNyYyJ^kMWq$vDpJzW7*p1|Z` z<qL!l&&Jbt?Zgt)u&{w8p5r#tAAm|t*dgVAOL-4;#_@B2Ll<1WvfEDY*~KU!13Hi$ zbRK(3`s20Bm#+SdC|BKWryl^R$gqVR7R`0xgc;|7R7ZpvJ+{-o?804mGHKXN16BWF zy3;4@W+WW;#5Na#sMZL;QIX>*WC>Q_<W<~E#8%JH%2x(=r3<Mrji%4rk0sYZTS0hY z9hU20DGHY0A<57P-U5NiL&V|5)O0RT@dPsjCJD*H@WvOY41-k^h%5`uQg9m}nh>=N ztaXV}tiXz3T=^NQm}$A{bdSS~n1(?cj&Mt%?F2}D0dqdgW|+62t*z;sjzEGKTtA~L z4pN;SaFkJkDc*Vdyi1G{gzGz|I_K$cE<q}4P*n$Z17U5DY7*u&n13I*Oy6@1)Fg#A zkYTQa1v0b=KHcUxqX`pCF+>p}kRW^sSc?H#+WX*YEWt}?Xel&(!zo57oQh#3EX>8w zgoY>Y!IB&#i%oxU61VAQuv;45Y~vDQ^v-2K6k4!*98xCPGTr$b`xGGqGatqIurPq7 z0YsUG+<Jp}l~7_FE#M@W{t)PY5M99GOjy`shzVLHGSQ>rgQX<&I=<g?y3a*M2^rYk zAVx)NcliG91C3;Xx|Rm;&J46`jL3?Rc8L#0JBRGj1#S|okq=4e=r$TLb^1(S_n1*a zW+C+Mh_svbn?iLho-#3->luOvYIpfex4Xh<Bm=v3qIgf}>UB)~AHhut@Gym?@ARH4 zj1n@i`zr1!N(yn=@-cx&><!KI3>eaUryl^B0lON*%FsJRs`36B@Q@0)13SfcI^R`B z38odk(>1O#`Y>^dOfS32Xk-Sv%cF1MrqI8&=R?7^g2q!AVAp=ko~g3Wck=Qt;K4Pp zSvP#A-@D3~CIh=zMDoN$&bzG}R)a@e3_&9yzkH`BTw^q1;_{n51w@PbO+Nvm75t|E zxyC5Lq~|wX>^h^78SKuKyq}goe6xb2!M2-$2BTotD9JNDiVJ-A4m9=#8m%;9V2Jmd zUU!{QLK=3Fi$a;#h9VKK1K`lG1lbN9ovZMhe&#x(1k*3S>Cdh+8p*(JbUDEHe5L#5 z6i@(zCN4}F7<m1so7`YDGK1X-Q?c`_IjfZ?$U~sfIx_|a*sU;|Pu5RzN?)T24p<{S zL$KaCHy9;kaI0VupMK#6d|Xrpc3;fN-Won}rmGd8(I{}RG8_n+E_ajBNCtNEOIYA( zzeIs8$H8NQ;5hjnJU!<oqmK;i3K;$6b_brdCe?!d4j!tj4V``kqylycOs=L}(yA#* z{-AOiVv9=nbemg@Moja=rx)B}lwg9yro{A+TZ{rc0*nR`kU`yJ5!3hGVw8}9-4c^+ zJEf!W@*R+4pdC$>@adm!!3KqmWw4B7LPu29qo()WW;DW;UJMx+9z;#Qa~l*@QPaQO zX7pi7jhXIphtWp{cJ)hl%9M?JZk@c(#0ZKHQ_$&$vD4SwVU%EMik*J!4&y8)h4|@7 zcNvXjaHkuc_~{$&GD?`8h293US}|hLuh#!6;HU(LF7(2fhBrTw?#2sqfX2b0<w{1v z^nZ65C784mr%T*pG-5QK?tPC@5)^c4_ZYS8RFfc=6v3|ac@=c*<c-v2S>T~TV^AuA z-N$ky(%?H+&$fQBrJ!LlhPO%6&)owxbRfwZR$wq$`c9X*&nO`SyV+&p_QQuWl?*!& z1&3Jj^nm-I5sKvL22U6zrdvE<lww-wGkxBDMkA)V$<seP01bhmDq`B2JYC@d<19wV z+yE2Ib~NQOu&ZyLudAFG{;2RfIBT1LG8a^(4D6Dd`Kk>%+O4Tc0*rRHCg5q3o2k=_ z9x@s+JxQIu>>*<slUnR_zDJA_GO&Ap_Up{PWgRNv1r7rvkeOV5)14kM8Zq^zO)q=I zXk-Sv9Vay5&HrB$62E~5U%}xByC=u?^MQ@01WYrS7~{+#b0ZVdr{8<TD8ck7efkfO zS+g^y>pW(ZKn{q6$BagBA43afXn?>240|yQjww?}IKy;IuX(~~A_Kc)CR5hSZ1auZ zPT+tt1<k7DWlulzgi%5UcD;_@zD@RJ_5U=%D!>EoPqU{zWt3nt%$Y9rl+lRkQqFY0 zr;HM2uzPn}{%@W4TS7Ds98TZ_3cH!-$(vnL2NeEZ1ZR6t`Om<dH+{}iMhO|%6*$kQ zm3&%g|7|x5qk*2Gg`SZCgL>Zd3n0^Bm*$xHoY}T;(v~WO3fQ$e22Qi$x3lpxA!Oq6 zrprBJlrV!`#M8mDCL><Zssf>+1$re9hoGJI4#p{G5Hi#Arsq6kl#qd4?j!N*mtoK; zvs8qN{dv<DfJ}#72XwnR&CPJyt%C>^unU8<gfxs9yB{w^$o$Tm{tl!UddE=1Wa~G| zS-rD55Gr7|5S{qeAYZd2bTUH5Jb${)b4Cdn*u6zTb{Di|WCfQaR3zn3FL=%<VFtVD zXti5rY>~bC9E1wkT}U|zi~e7mxYH3Kvm}4|zUPcCT%Kj%vjiKu%BJ(YV3d%7T~3s_ z(`JPUTkbQk4of{lBL>mD=?*U#CCp&g86A8&afPtB`*(y2tZ@g{>zy~f52P1%!O)_W zby@E?R4*a)VvRen-j=-ScR((KUAuIGJz%=qi`+v9y{q%43%q2MFoRvxbco@dyV^@8 z2ZRc&aR)a2dEWFmkY3p3Pf22bIQiv8z9IBtjXSVj<^1VuUNTC^z;2Y9CvC9n^2_8X zgkGQg=?_4rCqeI?;uUv!Id5IrafAx2aR)ZNFMqn;D@F-Z*u7R47YfK8(Rk^P&<nfJ zETArD&z+5%LCq<1*z8^PD@I8f*nLZjPtT~FpLHpdiLuT?&s5LQfI+-&`i57G5@xWQ znK<)pj=c(;wHq>-Y^G<z0K2<sqJC7b+E!ajCiwCJnfmGfUNK6j;8yYBD`d?`!MEvF zuNljtq*EEd*Pymon4V#*;QI$!jt{!w^f+_MD)~L(GU~OE$xkNj*7#}5dEQvpLe>@V z-<;9@d)n!}UbT=)pW)4wr>D-_8Z7t*F<-1~I@cS<Yf=uy$%#3MMf#u{RCN;zGIfhm z(^894^O94yKX}8)FYk;~USAiBCSCA)7QK@6Dwx5^`9;$U*_mWikpxopb@h|;i&AwB zK+}rIs;6ZzDY(E?f)<Pv>+9-+X<g6~2Q#qR(mc?Onfk@a8L7F6AW7Y{)Z!ADuKa@3 zyu^a(|I(S1;C4d9GIc?UK_;T`rw3XvscM0wz~(?L1haKb^o%X_3_-RgW#;KaW-q5V znlZ@<L)iMdP(fW&J;Uh^8B9vjD6Z4jg*sCgH2XPyV>FYJIBc2`9DtB3Ky^*^Os6Yy fGbsv!XD9V_^})2Rk)F|XMQ<jh?eDpn_QV1J&mB#H delta 28698 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 diff --git a/docker-compose.yml b/docker-compose.yml index 54f8f92..87f5403 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres ports: - - "5433:5432" + - "5432:5432" networks: - apex_network volumes: diff --git a/documentation/Educational-StageDescribers.ts b/documentation/Educational-StageDescribers.ts new file mode 100644 index 0000000..a476d41 --- /dev/null +++ b/documentation/Educational-StageDescribers.ts @@ -0,0 +1,293 @@ +import { describeRoute } from 'hono-openapi' + +// Descrição da rota POST /create +const createEducationalStageRoute = describeRoute({ + method: 'POST', + path: '/create', + tags: ['Educational-Stage'], + summary: 'Create a new educational stage', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string', description: 'Name of the educational stage' }, + description: { type: 'string', description: 'Description of the educational stage' }, + }, + required: ['name'], + }, + }, + }, + }, + responses: { + 200: { + description: 'Educational stage created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStage: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the created educational stage' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request due to invalid input', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição da rota POST /update + const updateEducationalStageRoute = describeRoute({ + method: 'POST', + path: '/update', + tags: ['Educational-Stage'], + summary: 'Update an existing educational stage', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the educational stage to update' }, + name: { type: 'string', description: 'Updated name of the educational stage' }, + description: { type: 'string', description: 'Updated description of the educational stage' }, + }, + required: ['id'], + }, + }, + }, + }, + responses: { + 200: { + description: 'Educational stage updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStage: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request due to invalid input', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição da rota POST /delete/:id + const deleteEducationalStageRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + tags: ['Educational-Stage'], + summary: 'Delete an educational stage by ID', + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the educational stage to delete', + }, + }, + ], + responses: { + 200: { + description: 'Educational stage deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStage: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request due to invalid ID', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição da rota GET /all + const getAllEducationalStagesRoute = describeRoute({ + method: 'GET', + path: '/all', + tags: ['Educational-Stage'], + summary: 'Get all educational stages', + responses: { + 200: { + description: 'List of educational stages retrieved successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStages: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição da rota GET /:id + const getEducationalStageByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + tags: ['Educational-Stage'], + summary: 'Get an educational stage by ID', + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the educational stage to retrieve', + }, + }, + ], + responses: { + 200: { + description: 'Educational stage retrieved successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStage: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request due to invalid ID', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + createEducationalStageRoute, + updateEducationalStageRoute, + deleteEducationalStageRoute, + getAllEducationalStagesRoute, + getEducationalStageByIdRoute, +} diff --git a/documentation/ItemDescriber.ts b/documentation/ItemDescriber.ts new file mode 100644 index 0000000..48422bd --- /dev/null +++ b/documentation/ItemDescriber.ts @@ -0,0 +1,337 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createItemRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new item.', + tags: ['Item'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + required: ['name', 'description', 'price', 'quantity'], + }, + }, + }, + responses: { + 200: { + description: 'Item created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateItemRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing item.', + tags: ['Item'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + required: ['id', 'name', 'description', 'price', 'quantity'], + }, + }, + }, + responses: { + 200: { + description: 'Item updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteItemRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete an item by ID.', + tags: ['Item'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Item deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /active/:id + const activeItemRoute = describeRoute({ + method: 'POST', + path: '/active/{id}', + description: 'Activate an item by ID.', + tags: ['Item'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Item activated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all (public route) + const getAllItemsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all items.', + tags: ['Item'], + responses: { + 200: { + description: 'List of items.', + content: { + 'application/json': { + type: 'object', + properties: { + items: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find items.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id (public route) + const getItemByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get an item by ID.', + tags: ['Item'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Item found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find item.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createItemRoute, + updateItemRoute, + deleteItemRoute, + activeItemRoute, + getAllItemsRoute, + getItemByIdRoute +} \ No newline at end of file diff --git a/documentation/achievementsDescribers.ts b/documentation/achievementsDescribers.ts new file mode 100644 index 0000000..b6a1ba8 --- /dev/null +++ b/documentation/achievementsDescribers.ts @@ -0,0 +1,301 @@ +import { describeRoute } from 'hono-openapi' + +const createRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new achievement', + tags: ['Achievements'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string', maxLength: 255 }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string', enum: ['inactive', 'active'] }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + required: ['name', 'repeatable', 'is_resettable', 'state'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Achievement created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not create achievement', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const updateRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing achievement', + tags: ['Achievements'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string', maxLength: 255 }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string', enum: ['inactive', 'active'] }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + required: ['id'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Achievement updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update achievement', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const deleteRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete an achievement by ID', + tags: ['Achievements'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Achievement deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not delete achievement', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const getAchievementRoute = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Get a specific achievement by ID', + tags: ['Achievements'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Achievement found successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '404': { + description: 'Achievement not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const getAchievementsRoute = describeRoute({ + method: 'GET', + path: '/', + description: 'Get all achievements', + tags: ['Achievements'], + responses: { + '200': { + description: 'Achievements found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + }, + '404': { + description: 'Achievements not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + createRoute, + updateRoute, + deleteRoute, + getAchievementRoute, + getAchievementsRoute, +} diff --git a/documentation/actionsDescribers.ts b/documentation/actionsDescribers.ts new file mode 100644 index 0000000..9942707 --- /dev/null +++ b/documentation/actionsDescribers.ts @@ -0,0 +1,302 @@ +import { describeRoute } from 'hono-openapi' + +const createActionRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new action', + tags: ['Actions'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string', maxLength: 255 }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string', enum: ['inactive', 'active'] }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + required: ['name', 'repeatable', 'is_resettable', 'state'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Action created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not create action', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + const getActionsRoute = describeRoute({ + method: 'GET', + path: '/actions', + description: 'Get all actions', + tags: ['Actions'], + responses: { + '200': { + description: 'Actions found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + }, + '404': { + description: 'Actions not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + const getActionByNameRoute = describeRoute({ + method: 'GET', + path: '/:name', + description: 'Get an action by name', + tags: ['Actions'], + parameters: [ + { + name: 'name', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + '200': { + description: 'Action found successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '404': { + description: 'Action not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + const updateActionRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing action', + tags: ['Actions'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string', maxLength: 255 }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string', enum: ['inactive', 'active'] }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + required: ['id'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Action updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update action', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + const deleteActionRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete an action by ID', + tags: ['Actions'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Action deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not delete action', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + export { + createActionRoute, + getActionsRoute, + getActionByNameRoute, + updateActionRoute, + deleteActionRoute, + } + \ No newline at end of file diff --git a/documentation/authDescribers.ts b/documentation/authDescribers.ts new file mode 100644 index 0000000..694b3cd --- /dev/null +++ b/documentation/authDescribers.ts @@ -0,0 +1,204 @@ +import { describeRoute } from 'hono-openapi' +import { HttpStatus } from '@/services/error.service' + +const signinRoute = describeRoute({ + method: 'POST', + path: '/signin', + description: 'Sign in the user with email and password', + tags: ['Auth'], // Tag adicionada + requestBody: { + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/AuthInput', // Referência ao schema de autenticação + }, + }, + }, + }, + responses: { + [HttpStatus.OK]: { + description: 'User signed in successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + token: { type: 'string' }, + }, + }, + }, + }, + }, + [HttpStatus.NOT_FOUND]: { + description: 'Invalid or non-existent user', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + code: { type: 'integer', example: HttpStatus.NOT_FOUND }, + message: { type: 'string', example: 'Invalid or inexistent user' }, + }, + }, + }, + }, + }, + }, +}) + +const signupRoute = describeRoute({ + method: 'POST', + path: '/signup', + description: 'Sign up a new user and create corresponding user stats', + tags: ['Auth'], // Tag adicionada + requestBody: { + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/UserInput', // Referência ao schema de entrada do usuário + }, + }, + }, + }, + responses: { + [HttpStatus.OK]: { + description: 'User signed up successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + user: { + $ref: '#/components/schemas/UserDto', // Referência ao schema de usuário + }, + userStats: { + $ref: '#/components/schemas/UserStatsDto', // Referência ao schema de estatísticas do usuário + }, + }, + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Error while creating user', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not create' }, + }, + }, + }, + }, + }, + }, +}) + +const requestPasswordResetRoute = describeRoute({ + method: 'POST', + path: '/request/:email', + description: 'Request password reset for the given email', + tags: ['Auth'], // Tag adicionada + parameters: [ + { + name: 'email', + in: 'path', + required: true, + schema: { type: 'string', format: 'email' }, + }, + ], + responses: { + [HttpStatus.OK]: { + description: 'Password reset ticket created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'string' }, + tokenHash: { type: 'string' }, + createdAt: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Could not send password recovery email', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not send recovery password email' }, + }, + }, + }, + }, + }, + }, +}) + +const resetPasswordRoute = describeRoute({ + method: 'POST', + path: '/reset', + description: 'Reset the password using the provided email, token, and new password', + tags: ['Auth'], // Tag adicionada + parameters: [ + { + name: 'email', + in: 'query', + required: true, + schema: { type: 'string', format: 'email' }, + }, + { + name: 'token', + in: 'query', + required: true, + schema: { type: 'string' }, + }, + { + name: 'password', + in: 'query', + required: true, + schema: { type: 'string', minLength: 8 }, + }, + ], + responses: { + [HttpStatus.OK]: { + description: 'Password reset successfully', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/UserDto', // Referência ao schema de usuário + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Could not reset password', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not send recovery password email' }, + }, + }, + }, + }, + }, + }, +}) + +export { + signinRoute, + signupRoute, + requestPasswordResetRoute, + resetPasswordRoute, +} diff --git a/documentation/collectionLikesDescribers.ts b/documentation/collectionLikesDescribers.ts new file mode 100644 index 0000000..1364ee7 --- /dev/null +++ b/documentation/collectionLikesDescribers.ts @@ -0,0 +1,334 @@ +import { describeRoute } from 'hono-openapi' + +const associateRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate likes to a collection for multiple users', + tags: ['Collection Likes'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + collectionId: { type: 'integer' }, + userIds: { type: 'array', items: { type: 'integer' } } + }, + required: ['collectionId', 'userIds'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Likes associated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not associate likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const removeLikesRoute = describeRoute({ + method: 'POST', + path: '/:collectionId/delete/:userId', + description: 'Remove likes from a collection for a user', + tags: ['Collection Likes'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + { + name: 'userId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Likes removed successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not remove likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const updateLikesRoute = describeRoute({ + method: 'POST', + path: '/update/likes', + description: 'Update likes for a collection for multiple users', + tags: ['Collection Likes'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + collectionId: { type: 'integer' }, + userIds: { type: 'array', items: { type: 'integer' } } + }, + required: ['collectionId', 'userIds'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Likes updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const getLikesByCollectionRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/likes', + description: 'Get all likes for a specific collection', + tags: ['Collection Likes'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Likes fetched successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'integer', + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not fetch likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const checkLikeExistsRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/likes/:userId/exists', + description: 'Check if a like exists for a specific collection and user', + tags: ['Collection Likes'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + { + name: 'userId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Like exists check completed successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not check if like exists', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const getCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/user/:userId/collections', + description: 'Get all collections for a specific user', + tags: ['Collection Likes'], + parameters: [ + { + name: 'userId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collections fetched successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + likesCount: { type: 'integer' }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not fetch collections', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + associateRoute, + removeLikesRoute, + updateLikesRoute, + getLikesByCollectionRoute, + checkLikeExistsRoute, + getCollectionsByUserRoute, +} diff --git a/documentation/collectionResourcesDescribers.ts b/documentation/collectionResourcesDescribers.ts new file mode 100644 index 0000000..fa01b50 --- /dev/null +++ b/documentation/collectionResourcesDescribers.ts @@ -0,0 +1,280 @@ +import { describeRoute } from 'hono-openapi' + +// Descrição para a rota POST /associate +const associateRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate resources with a collection', + tags: ['Collection Resources'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + collectionId: { type: 'integer' }, + resourceIds: { + type: 'array', + items: { type: 'integer' }, + }, + }, + required: ['collectionId', 'resourceIds'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Resources associated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to associate resources', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição para a rota POST /:collectionId/delete/:resourceId +const deleteResourceRoute = describeRoute({ + method: 'POST', + path: '/:collectionId/delete/:resourceId', + description: 'Remove resources from a collection', + tags: ['Collection Resources'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + '200': { + description: 'Resource removed successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to remove resource', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição para a rota GET /:collectionId/resources +const getResourcesRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/resources', + description: 'Get all resources of a collection', + tags: ['Collection Resources'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + '200': { + description: 'Resources fetched successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'integer' }, + resourceName: { type: 'string' }, + // Add other properties based on the resource object + }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to fetch resources', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição para a rota GET /:collectionId/resources/:resourceId/exists +const checkResourceExistsRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/resources/:resourceId/exists', + description: 'Check if a resource is associated with a collection', + tags: ['Collection Resources'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + '200': { + description: 'Resource association exists or not', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to check resource association', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição para a rota GET /resource/:resourceId/collections +const getCollectionsForResourceRoute = describeRoute({ + method: 'GET', + path: '/resource/:resourceId/collections', + description: 'Get collections associated with a resource', + tags: ['Collection Resources'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + '200': { + description: 'Collections fetched successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + collectionId: { type: 'integer' }, + collectionName: { type: 'string' }, + // Add other properties based on the collection object + }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to fetch collections', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + associateRoute, + deleteResourceRoute, + getResourcesRoute, + checkResourceExistsRoute, + getCollectionsForResourceRoute, +} diff --git a/documentation/collectionStatsDescribers.ts b/documentation/collectionStatsDescribers.ts new file mode 100644 index 0000000..963325c --- /dev/null +++ b/documentation/collectionStatsDescribers.ts @@ -0,0 +1,439 @@ +import { describeRoute } from 'hono-openapi'; + +const createRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create new collection stats', + tags: ['CollectionStats'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' } + }, + required: ['views', 'downloads', 'likes', 'shares', 'score', 'followers'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Collection stats created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not create collection stats', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateViewsRoute = describeRoute({ + method: 'POST', + path: '/update-views/:id', + description: 'Update views of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats views updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update views', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateDownloadsRoute = describeRoute({ + method: 'POST', + path: '/update-downloads/:id', + description: 'Update downloads of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats downloads updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update downloads', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateLikesRoute = describeRoute({ + method: 'POST', + path: '/update-likes/:id', + description: 'Update likes of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats likes updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateSharesRoute = describeRoute({ + method: 'POST', + path: '/update-shares/:id', + description: 'Update shares of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats shares updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update shares', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateScoreRoute = describeRoute({ + method: 'POST', + path: '/update-score/:id', + description: 'Update score of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats score updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update score', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateFollowersRoute = describeRoute({ + method: 'POST', + path: '/update-followers/:id', + description: 'Update followers of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats followers updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update followers', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const deleteCollectionStatsRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Deletes collection stats by ID.', + tags: ['CollectionStats'], + params: { + id: 'The ID of the collection stats to delete.', + }, + responses: { + 200: { + description: 'Successfully deleted collection stats.', + content: { collectionStats: 'The deleted collection stats data.' }, + }, + 400: { + description: 'Failed to delete collection stats.', + content: { status: 'error', message: 'could not delete collection stats', code: 400 }, + }, + }, +}) + + const getCollectionStatsRoute = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Retrieves collection stats by ID.', + tags: ['CollectionStats'], + params: { + id: 'The ID of the collection stats to retrieve.', + }, + responses: { + 200: { + description: 'Successfully retrieved collection stats.', + content: { collectionStats: 'The retrieved collection stats data.' }, + }, + 404: { + description: 'Collection stats not found.', + content: { status: 'error', message: 'could not find collection stats', code: 404 }, + }, + }, +}) + +export { + createRoute, + updateViewsRoute, + updateDownloadsRoute, + updateLikesRoute, + updateSharesRoute, + updateScoreRoute, + updateFollowersRoute, + deleteCollectionStatsRoute, + getCollectionStatsRoute +} diff --git a/documentation/collectionsDescribers.ts b/documentation/collectionsDescribers.ts new file mode 100644 index 0000000..81f5037 --- /dev/null +++ b/documentation/collectionsDescribers.ts @@ -0,0 +1,622 @@ +import { describeRoute } from 'hono-openapi' +const createCollectionRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Creates a new collection, which includes generating associated statistics.', + tags: ['Collections'], + request: { + body: { + collection_stats_id: { + type: 'number', + description: 'The ID of the collection statistics associated with this collection.', + example: 1 + }, + name: { + type: 'string', + description: 'The name of the collection being created.', + example: 'Art Collection' + }, + description: { + type: 'string', + description: 'A brief description of the collection.', + example: 'A collection of abstract art pieces.' + }, + created_by: { + type: 'string', + description: 'The user ID or name who is creating the collection.', + example: 'user123' + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the newly created collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The name of the newly created collection.', + example: 'Art Collection' + }, + description: { + type: 'string', + description: 'The description of the newly created collection.', + example: 'A collection of abstract art pieces.' + }, + created_at: { + type: 'string', + description: 'The date and time when the collection was created.', + example: '2025-03-26T12:34:56Z' + }, + updated_at: { + type: 'string', + description: 'The date and time when the collection was last updated.', + example: '2025-03-26T12:34:56Z' + } + }, + collectionStats: { + id: { + type: 'number', + description: 'The ID of the collection statistics.', + example: 1 + }, + created_at: { + type: 'string', + description: 'The date and time when the statistics were generated.', + example: '2025-03-26T12:30:00Z' + } + } + } + } +}); +const updateCollectionRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Updates an existing collection.', + tags: ['Collections'], + request: { + body: { + id: { + type: 'number', + description: 'The ID of the collection to update.', + example: 123 + }, + name: { + type: 'string', + description: 'The new name of the collection.', + example: 'Modern Art Collection' + }, + description: { + type: 'string', + description: 'The updated description of the collection.', + example: 'A collection of modern and contemporary art pieces.' + }, + updated_by: { + type: 'string', + description: 'The user ID or name who is updating the collection.', + example: 'user123' + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the updated collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The updated name of the collection.', + example: 'Modern Art Collection' + }, + description: { + type: 'string', + description: 'The updated description of the collection.', + example: 'A collection of modern and contemporary art pieces.' + }, + updated_at: { + type: 'string', + description: 'The date and time when the collection was last updated.', + example: '2025-03-26T14:00:00Z' + } + } + } + } +}); + +const deleteCollectionRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Deletes a collection by ID.', + tags: ['Collections'], + request: { + params: { + id: { + type: 'number', + description: 'The ID of the collection to delete.', + example: 123 + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the deleted collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The name of the deleted collection.', + example: 'Art Collection' + }, + deleted_at: { + type: 'string', + description: 'The date and time when the collection was deleted.', + example: '2025-03-26T14:30:00Z' + } + } + } + } +}); + +const deletePermanentlyCollectionRoute = describeRoute({ + method: 'POST', + path: '/delete-permanently/:id', + description: 'Permanently deletes a collection by ID.', + tags: ['Collections'], + request: { + params: { + id: { + type: 'number', + description: 'The ID of the collection to permanently delete.', + example: 123 + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the permanently deleted collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The name of the permanently deleted collection.', + example: 'Art Collection' + }, + permanently_deleted_at: { + type: 'string', + description: 'The date and time when the collection was permanently deleted.', + example: '2025-03-26T14:45:00Z' + } + } + } + } +}); + +const restoreCollectionRoute = describeRoute({ + method: 'POST', + path: '/restore/:id', + description: 'Restores a deleted collection by ID.', + tags: ['Collections'], + request: { + params: { + id: { + type: 'number', + description: 'The ID of the collection to restore.', + example: 123 + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the restored collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The name of the restored collection.', + example: 'Art Collection' + }, + restored_at: { + type: 'string', + description: 'The date and time when the collection was restored.', + example: '2025-03-26T15:00:00Z' + } + } + } + } +}); + + +const getAllCollectionsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get all collections', + tags: ['Collections'], + responses: { + '200': { + description: 'Collections found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter uma coleção específica por ID +const getCollectionRoute = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Get a specific collection by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection found successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + '404': { + description: 'Collection not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter coleções ativas de um usuário +const getActiveCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/getActiveCollectionsByUsers/:id_user', + description: 'Get active collections for a user by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Active collections found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Active collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter todas as coleções de um usuário +const getAllCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/getAllCollectionsByUsers/:id_user', + description: 'Get all collections for a user by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'All collections found for the user', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter coleções públicas de um usuário +const getPublicCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/getPublicCollectionsByUser/:id_user', + description: 'Get public collections for a user by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Public collections found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Public collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter coleções privadas de um usuário +const getPrivateCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/getPrivateCollectionsByUser/:id_user', + description: 'Get private collections for a user by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Private collections found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Private collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para download dos recursos de uma coleção +const downloadCollectionRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/download', + description: 'Download resources from a collection as a ZIP file', + tags: ['Collections'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Resources downloaded successfully', + content: { + 'application/zip': { + schema: { + type: 'string', + format: 'binary', + }, + }, + }, + }, + '404': { + description: 'No resources found for the collection', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + createCollectionRoute, + updateCollectionRoute, + deleteCollectionRoute, + deletePermanentlyCollectionRoute, + restoreCollectionRoute, + getAllCollectionsRoute, + getCollectionRoute, + getActiveCollectionsByUserRoute, + getAllCollectionsByUserRoute, + getPublicCollectionsByUserRoute, + getPrivateCollectionsByUserRoute, + downloadCollectionRoute, +} diff --git a/documentation/comment-replyDescribers.ts b/documentation/comment-replyDescribers.ts new file mode 100644 index 0000000..e0ce3c8 --- /dev/null +++ b/documentation/comment-replyDescribers.ts @@ -0,0 +1,390 @@ +import { describeRoute } from 'hono-openapi'; + +// POST /create +const createCommentReplyRouteDescription = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new reply for a comment.', + tags: ['Comment-Reply'], + requestBody: { + description: 'JSON object representing the reply to a comment.', + required: true, + schema: { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user posting the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment being replied to' }, + content: { type: 'string', description: 'Content of the reply' } + }, + required: ['user_id', 'comment_id', 'content'] + } + }, + responses: { + 200: { + description: 'Reply comment created successfully.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply comment' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment' }, + content: { type: 'string', description: 'Content of the reply' }, + created_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was created' }, + updated_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was last updated' } + } + } + } + } + }, + 400: { + description: 'Error in creating the reply comment, invalid input.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error', description: 'Status of the operation' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400, description: 'HTTP status code' }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// POST /update +const updateCommentReplyRouteDescription = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing reply to a comment.', + tags: ['Comment-Reply'], + requestBody: { + description: 'JSON object representing the updated reply to a comment.', + required: true, + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply to be updated' }, + user_id: { type: 'integer', description: 'ID of the user posting the updated reply' }, + content: { type: 'string', description: 'Updated content of the reply' } + }, + required: ['id', 'user_id', 'content'] + } + }, + responses: { + 200: { + description: 'Reply comment updated successfully.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the updated reply comment' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + content: { type: 'string', description: 'Updated content of the reply' }, + updated_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was last updated' } + } + } + } + } + }, + 400: { + description: 'Error in updating the reply comment, invalid input.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error', description: 'Status of the operation' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400, description: 'HTTP status code' }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// POST /deleteData/:id +const deleteDataCommentReplyRouteDescription = describeRoute({ + method: 'POST', + path: '/deleteData/:id', + description: 'Delete a reply comment based on its ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the reply to delete', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'Reply comment deleted successfully.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the deleted reply comment' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + content: { type: 'string', description: 'Content of the reply' }, + deleted_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was deleted' } + } + } + } + } + }, + 400: { + description: 'Error in deleting the reply comment, invalid ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error', description: 'Status of the operation' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400, description: 'HTTP status code' }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// POST /delete/:id +const deleteCommentReplyRouteDescription = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete a reply comment based on its ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the reply to delete', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'Reply comment deleted successfully.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the deleted reply comment' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + content: { type: 'string', description: 'Content of the reply' }, + deleted_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was deleted' } + } + } + } + } + }, + 400: { + description: 'Error in deleting the reply comment, invalid ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error', description: 'Status of the operation' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400, description: 'HTTP status code' }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +const findReplyByCommentRouteDescription = describeRoute({ + method: 'GET', + path: '/findReplyByComment/:comment_id', + description: 'Get active reply for a specific comment by comment ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'comment_id', + in: 'path', + description: 'ID of the comment to find active replies for', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'Active reply found for the comment.', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment' }, + content: { type: 'string', description: 'Content of the reply' }, + created_at: { type: 'string', format: 'date-time', description: 'Date the reply was created' } + } + } + } + } + } + }, + 400: { + description: 'Error finding active reply, invalid comment ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400 }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// GET /findAllReplyByComment/:comment_id +const findAllReplyByCommentRouteDescription = describeRoute({ + method: 'GET', + path: '/findAllReplyByComment/:comment_id', + description: 'Get all replies for a specific comment by comment ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'comment_id', + in: 'path', + description: 'ID of the comment to find all replies for', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'All replies found for the comment.', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment' }, + content: { type: 'string', description: 'Content of the reply' }, + created_at: { type: 'string', format: 'date-time', description: 'Date the reply was created' } + } + } + } + } + } + }, + 400: { + description: 'Error finding replies, invalid comment ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400 }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// GET /findAllReplyByUser/:id_user +const findAllReplyByUserRouteDescription = describeRoute({ + method: 'GET', + path: '/findAllReplyByUser/:id_user', + description: 'Get all replies by a specific user based on user ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'id_user', + in: 'path', + description: 'ID of the user to find all replies for', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'All replies found for the user.', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment' }, + content: { type: 'string', description: 'Content of the reply' }, + created_at: { type: 'string', format: 'date-time', description: 'Date the reply was created' } + } + } + } + } + } + }, + 400: { + description: 'Error finding replies, invalid user ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400 }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +export +{ + createCommentReplyRouteDescription, + updateCommentReplyRouteDescription, + deleteDataCommentReplyRouteDescription, + deleteCommentReplyRouteDescription, + findReplyByCommentRouteDescription, + findAllReplyByCommentRouteDescription, + findAllReplyByUserRouteDescription +} \ No newline at end of file diff --git a/documentation/commentsDescribers.ts b/documentation/commentsDescribers.ts new file mode 100644 index 0000000..b5b8b24 --- /dev/null +++ b/documentation/commentsDescribers.ts @@ -0,0 +1,413 @@ +import { describeRoute } from 'hono-openapi' + + +const createCommentRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new comment', + tags: ['Comments'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + user_id: { type: 'integer' }, + resource_id: { type: 'integer' }, + content: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + }, + required: ['user_id', 'resource_id', 'content'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Comment created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + resource_id: { type: 'integer' }, + content: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + const updateCommentRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing comment', + tags: ['Comments'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + resource_id: { type: 'integer' }, + content: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + required: ['id', 'content'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Comment updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + resource_id: { type: 'integer' }, + content: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + const deleteCommentDataRoute = describeRoute({ + method: 'POST', + path: 'deleteData/:id', + description: 'Delete comment data by ID', + tags: ['Comments'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Comment data deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + resource_id: { type: 'integer' }, + content: { type: 'string' }, + deleted_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + const deleteCommentRoute = describeRoute({ + method: 'POST', + path: 'delete/:id', + description: 'Delete a comment by ID', + tags: ['Comments'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Comment deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + resource_id: { type: 'integer' }, + content: { type: 'string' }, + deleted_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + +const findReplyByCommentRouteDescription = describeRoute({ + method: 'GET', + path: '/findReplyByComment/:comment_id', + description: 'Get active replies for a specific comment by its ID', + tags: ['Comments'], + parameters: [ + { + name: 'comment_id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the comment to find active replies for', + }, + }, + ], + responses: { + '200': { + description: 'Active replies found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + comment_id: { type: 'integer' }, + user_id: { type: 'integer' }, + reply_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error finding active replies for the comment', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + +const findAllReplyByCommentRouteDescription = describeRoute({ + method: 'GET', + path: '/findAllReplyByComment/:comment_id', + description: 'Get all replies for a specific comment by its ID', + tags: ['Comments'], + parameters: [ + { + name: 'comment_id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the comment to find all replies for', + }, + }, + ], + responses: { + '200': { + description: 'Replies found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + comment_id: { type: 'integer' }, + user_id: { type: 'integer' }, + reply_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error finding replies for the comment', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + +const findAllReplyByUserRouteDescription = describeRoute({ + method: 'GET', + path: '/findAllReplyByUser/:id_user', + description: 'Get all replies made by a specific user', + tags: ['Comments'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the user to find their replies', + }, + }, + ], + responses: { + '200': { + description: 'Replies by user found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + comment_id: { type: 'integer' }, + user_id: { type: 'integer' }, + reply_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error finding replies for the user', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + +export +{ + createCommentRoute, + updateCommentRoute, + deleteCommentDataRoute, + deleteCommentRoute, + findReplyByCommentRouteDescription, + findAllReplyByCommentRouteDescription, + findAllReplyByUserRouteDescription +} \ No newline at end of file diff --git a/documentation/compliantDescribers.ts b/documentation/compliantDescribers.ts new file mode 100644 index 0000000..dfe7561 --- /dev/null +++ b/documentation/compliantDescribers.ts @@ -0,0 +1,371 @@ +import { describeRoute } from 'hono-openapi' + + + const createComplaintRouteDescription = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new complaint', + tags: ['Complaints'], + requestBody: { + description: 'Complaint input data', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + user_id: { type: 'integer' }, + complaint_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + required: ['user_id', 'complaint_text'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Complaint created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + complaint_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error creating complaint', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to update a complaint + const updateComplaintRouteDescription = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing complaint', + tags: ['Complaints'], + requestBody: { + description: 'Complaint update data', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + complaint_text: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + required: ['id', 'complaint_text'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Complaint updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + complaint_text: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error updating complaint', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to evaluate a complaint + const evaluateComplaintRouteDescription = describeRoute({ + method: 'POST', + path: '/evaluate', + description: 'Evaluate an existing complaint', + tags: ['Complaints'], + requestBody: { + description: 'Complaint evaluation data', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + status: { type: 'string', enum: ['pending', 'resolved', 'dismissed'] }, + evaluation_comments: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + required: ['id', 'status'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Complaint evaluated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + status: { type: 'string' }, + evaluation_comments: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error evaluating complaint', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to delete a complaint + const deleteComplaintRouteDescription = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete a complaint by ID', + tags: ['Complaints'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the complaint to delete', + }, + }, + ], + responses: { + '200': { + description: 'Complaint deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + complaint_text: { type: 'string' }, + deleted_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error deleting complaint', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to get a complaint by ID + const getComplaintByIdRouteDescription = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Get a complaint by ID', + tags: ['Complaints'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the complaint to retrieve', + }, + }, + ], + responses: { + '200': { + description: 'Complaint found successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + complaint_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Complaint not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to get all complaints +const getAllComplaintsRouteDescription = describeRoute({ + method: 'GET', + path: '/', + description: 'Get all complaints', + tags: ['Complaints'], + responses: { + '200': { + description: 'Complaints found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + complaint_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'No complaints found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + +export +{ + createComplaintRouteDescription, + updateComplaintRouteDescription, + evaluateComplaintRouteDescription, + deleteComplaintRouteDescription, + getComplaintByIdRouteDescription, + getAllComplaintsRouteDescription +} \ No newline at end of file diff --git a/documentation/institutionDescribers.ts b/documentation/institutionDescribers.ts new file mode 100644 index 0000000..8ac8d5a --- /dev/null +++ b/documentation/institutionDescribers.ts @@ -0,0 +1,375 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createInstitutionRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new institution.', + tags: ['Institution'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + required: ['name', 'uf', 'city', 'cep', 'address'], + }, + }, + }, + responses: { + 200: { + description: 'Institution created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /institutions + const getInstitutionsRoute = describeRoute({ + method: 'GET', + path: '/institutions', + description: 'Get a list of all institutions.', + tags: ['Institution'], + responses: { + 200: { + description: 'List of institutions.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. No institutions found.', + }, + }, +}); + +// Descrição da rota /name/:name + const getInstitutionByNameRoute = describeRoute({ + method: 'GET', + path: '/name/{name}', + description: 'Get institution by name.', + tags: ['Institution'], + parameters: [ + { + name: 'name', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'Institution found by name.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given name does not exist.', + }, + }, +}); + +// Descrição da rota /uf/:uf + const getInstitutionByUfRoute = describeRoute({ + method: 'GET', + path: '/uf/{uf}', + description: 'Get institution by UF (state).', + tags: ['Institution'], + parameters: [ + { + name: 'uf', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'Institution found by UF.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given UF does not exist.', + }, + }, +}); + +// Descrição da rota /city/:city + const getInstitutionByCityRoute = describeRoute({ + method: 'GET', + path: '/city/{city}', + description: 'Get institution by city.', + tags: ['Institution'], + parameters: [ + { + name: 'city', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'Institution found by city.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given city does not exist.', + }, + }, +}); + +// Descrição da rota /cep/:cep + const getInstitutionByCepRoute = describeRoute({ + method: 'GET', + path: '/cep/{cep}', + description: 'Get institution by CEP.', + tags: ['Institution'], + parameters: [ + { + name: 'cep', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'Institution found by CEP.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given CEP does not exist.', + }, + }, +}); + +// Descrição da rota /update + const updateInstitutionRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing institution.', + tags: ['Institution'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + required: ['id', 'name', 'uf', 'city', 'cep', 'address'], + }, + }, + }, + responses: { + 200: { + description: 'Institution updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteInstitutionRoute = describeRoute({ + method: 'DELETE', + path: '/delete/{id}', + description: 'Delete an institution by ID.', + tags: ['Institution'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Institution deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given ID does not exist.', + }, + }, +}); + +export{ + createInstitutionRoute, + getInstitutionsRoute, + getInstitutionByNameRoute, + getInstitutionByUfRoute, + getInstitutionByCityRoute, + getInstitutionByCepRoute, + updateInstitutionRoute, + deleteInstitutionRoute +} \ No newline at end of file diff --git a/documentation/languageDescriber.ts b/documentation/languageDescriber.ts new file mode 100644 index 0000000..2ab8d49 --- /dev/null +++ b/documentation/languageDescriber.ts @@ -0,0 +1,268 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createLanguageRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new language.', + tags: ['Language'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + code: { type: 'string' }, + }, + required: ['name', 'code'], + }, + }, + }, + responses: { + 200: { + description: 'Language created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + language: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateLanguageRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing language.', + tags: ['Language'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + required: ['id', 'name', 'code'], + }, + }, + }, + responses: { + 200: { + description: 'Language updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + language: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteLanguageRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a language by ID.', + tags: ['Language'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Language deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + language: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all (public route) + const getAllLanguagesRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all languages.', + tags: ['Language'], + responses: { + 200: { + description: 'List of languages.', + content: { + 'application/json': { + type: 'object', + properties: { + languages: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find languages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id (public route) + const getLanguageByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a language by ID.', + tags: ['Language'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Language found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + language: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find language.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createLanguageRoute, + updateLanguageRoute, + deleteLanguageRoute, + getAllLanguagesRoute, + getLanguageByIdRoute +} \ No newline at end of file diff --git a/documentation/licenseDescriber.ts b/documentation/licenseDescriber.ts new file mode 100644 index 0000000..51c4444 --- /dev/null +++ b/documentation/licenseDescriber.ts @@ -0,0 +1,274 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /create + const createLicenseRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new license.', + tags: ['License'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + required: ['name', 'type', 'validity'], + }, + }, + }, + responses: { + 200: { + description: 'License created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + license: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateLicenseRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing license.', + tags: ['License'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + required: ['id', 'name', 'type', 'validity'], + }, + }, + }, + responses: { + 200: { + description: 'License updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + license: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteLicenseRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a license by ID.', + tags: ['License'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'License deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + license: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all (public route) + const getAllLicensesRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all licenses.', + tags: ['License'], + responses: { + 200: { + description: 'List of licenses.', + content: { + 'application/json': { + type: 'object', + properties: { + licenses: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find licenses.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id (public route) + const getLicenseByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a license by ID.', + tags: ['License'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'License found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + license: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find license.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createLicenseRoute, + updateLicenseRoute, + deleteLicenseRoute, + getAllLicensesRoute, + getLicenseByIdRoute +} diff --git a/documentation/notificationDescriber.ts b/documentation/notificationDescriber.ts new file mode 100644 index 0000000..d2391be --- /dev/null +++ b/documentation/notificationDescriber.ts @@ -0,0 +1,524 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createNotificationRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new notification.', + tags: ['Notification'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + required: ['action_id', 'actor_user_id', 'target_user_id', 'message'], + }, + }, + }, + responses: { + 200: { + description: 'Notification created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /notifications + const getNotificationsRoute = describeRoute({ + method: 'GET', + path: '/notifications', + description: 'Get a list of all notifications.', + tags: ['Notification'], + responses: { + 200: { + description: 'List of notifications.', + content: { + 'application/json': { + type: 'object', + properties: { + notifications: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notifications not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /action/:action_id + const getNotificationByActionRoute = describeRoute({ + method: 'GET', + path: '/action/{action_id}', + description: 'Get a notification by action ID.', + tags: ['Notification'], + parameters: [ + { + name: 'action_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by action ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by action ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /actor-user/:actor_user_id + const getNotificationByActorUserRoute = describeRoute({ + method: 'GET', + path: '/actor-user/{actor_user_id}', + description: 'Get a notification by actor user ID.', + tags: ['Notification'], + parameters: [ + { + name: 'actor_user_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by actor user ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by actor user ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /target-user/:target_user_id + const getNotificationByTargetUserRoute = describeRoute({ + method: 'GET', + path: '/target-user/{target_user_id}', + description: 'Get a notification by target user ID.', + tags: ['Notification'], + parameters: [ + { + name: 'target_user_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by target user ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by target user ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /target-resource/:target_resource_id + const getNotificationByTargetResourceRoute = describeRoute({ + method: 'GET', + path: '/target-resource/{target_resource_id}', + description: 'Get a notification by target resource ID.', + tags: ['Notification'], + parameters: [ + { + name: 'target_resource_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by target resource ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by target resource ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /target-collection/:target_collection_id + const getNotificationByTargetCollectionRoute = describeRoute({ + method: 'GET', + path: '/target-collection/{target_collection_id}', + description: 'Get a notification by target collection ID.', + tags: ['Notification'], + parameters: [ + { + name: 'target_collection_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by target collection ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by target collection ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateNotificationRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing notification.', + tags: ['Notification'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + required: ['id', 'action_id', 'actor_user_id', 'target_user_id', 'message'], + }, + }, + }, + responses: { + 200: { + description: 'Notification updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteNotificationRoute = describeRoute({ + method: 'DELETE', + path: '/delete/{id}', + description: 'Delete a notification by ID.', + tags: ['Notification'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createNotificationRoute, + getNotificationsRoute, + getNotificationByActionRoute, + getNotificationByActorUserRoute, + getNotificationByTargetUserRoute, + getNotificationByTargetResourceRoute, + getNotificationByTargetCollectionRoute, + updateNotificationRoute, + deleteNotificationRoute +} \ No newline at end of file diff --git a/documentation/object-type.ts b/documentation/object-type.ts new file mode 100644 index 0000000..caf961e --- /dev/null +++ b/documentation/object-type.ts @@ -0,0 +1,263 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createObjectTypeRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new object type.', + tags: ['Object-Type'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['name'], + }, + }, + }, + responses: { + 200: { + description: 'Object type created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + objectType: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateObjectTypeRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing object type.', + tags: ['Object-Type'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['id', 'name'], + }, + }, + }, + responses: { + 200: { + description: 'Object type updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + objectType: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteObjectTypeRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete an object type by ID.', + tags: ['Object-Type'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Object type deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + objectType: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all + const getAllObjectTypesRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all object types.', + tags: ['Object-Type'], + responses: { + 200: { + description: 'List of all object types.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Unable to fetch object types.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getObjectTypeByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get an object type by ID.', + tags: ['Object-Type'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Object type found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + objectType: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Object type not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createObjectTypeRoute, + updateObjectTypeRoute, + deleteObjectTypeRoute, + getAllObjectTypesRoute, + getObjectTypeByIdRoute +} diff --git a/documentation/resource-educational-stages.ts b/documentation/resource-educational-stages.ts new file mode 100644 index 0000000..9641ffb --- /dev/null +++ b/documentation/resource-educational-stages.ts @@ -0,0 +1,303 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /associate + const associateResourceWithEducationalStagesRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate educational stages with a resource.', + tags: ['Resource-Educational-Stages'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + educationalStageIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'educationalStageIds'], + }, + }, + }, + responses: { + 200: { + description: 'Educational stages associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate educational stages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/delete/educationalStage/:educationalStageId + const removeEducationalStageFromResourceRoute = describeRoute({ + method: 'POST', + path: '/{resourceId}/delete/educationalStage/{educationalStageId}', + description: 'Remove an educational stage from a resource.', + tags: ['Resource-Educational-Stages'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'educationalStageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Educational stage removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove educational stage.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update/educationalStages + const updateResourceEducationalStagesRoute = describeRoute({ + method: 'POST', + path: '/update/educationalStages', + description: 'Update educational stages for a resource.', + tags: ['Resource-Educational-Stages'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + educationalStageIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'educationalStageIds'], + }, + }, + }, + responses: { + 200: { + description: 'Educational stages updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update educational stages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/educationalStages + const getEducationalStagesByResourceRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/educationalStages', + description: 'Get educational stages associated with a resource.', + tags: ['Resource-Educational-Stages'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of educational stages associated with the resource.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to get educational stages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/educationalStages/:educationalStageId/exists + const checkAssociationExistsRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/educationalStages/{educationalStageId}/exists', + description: 'Check if an association exists between a resource and an educational stage.', + tags: ['Resource-Educational-Stages'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'educationalStageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Association exists.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /educationalStage/:educationalStageId/resources + const getResourcesByEducationalStageRoute = describeRoute({ + method: 'GET', + path: '/educationalStage/{educationalStageId}/resources', + description: 'Get resources associated with an educational stage.', + tags: ['Resource-Educational-Stages'], + parameters: [ + { + name: 'educationalStageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources associated with the educational stage.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to get resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + associateResourceWithEducationalStagesRoute, + removeEducationalStageFromResourceRoute, + updateResourceEducationalStagesRoute, + getEducationalStagesByResourceRoute, + checkAssociationExistsRoute, + getResourcesByEducationalStageRoute +} \ No newline at end of file diff --git a/documentation/resource-language.ts b/documentation/resource-language.ts new file mode 100644 index 0000000..2be34e6 --- /dev/null +++ b/documentation/resource-language.ts @@ -0,0 +1,302 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /associate + const associateResourceWithLanguagesRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate a resource with multiple languages.', + tags: ['Resource-Language'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + languageIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'languageIds'], + }, + }, + }, + responses: { + 200: { + description: 'Languages associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate languages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/delete/language/:languageId + const removeLanguageFromResourceRoute = describeRoute({ + method: 'POST', + path: '/{resourceId}/delete/language/{languageId}', + description: 'Remove the association between a resource and a language.', + tags: ['Resource-Language'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'languageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Language removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove language.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update/languages + const updateResourceLanguagesRoute = describeRoute({ + method: 'POST', + path: '/update/languages', + description: 'Update the language associations for a resource.', + tags: ['Resource-Language'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + languageIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'languageIds'], + }, + }, + }, + responses: { + 200: { + description: 'Languages updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update languages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/languages + const getLanguagesByResourceRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/languages', + description: 'Get all languages associated with a resource.', + tags: ['Resource-Language'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of languages associated with the resource.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch languages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/language/:languageId/exists + const checkLanguageAssociationExistsRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/language/{languageId}/exists', + description: 'Check if the association between a resource and a language exists.', + tags: ['Resource-Language'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'languageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'The association exists or not.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check the association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /language/:languageId/resources + const getResourcesByLanguageRoute = describeRoute({ + method: 'GET', + path: '/language/{languageId}/resources', + description: 'Get all resources associated with a language.', + tags: ['Resource-Language'], + parameters: [ + { + name: 'languageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources associated with the language.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + associateResourceWithLanguagesRoute, + removeLanguageFromResourceRoute, + updateResourceLanguagesRoute, + getLanguagesByResourceRoute, + checkLanguageAssociationExistsRoute, + getResourcesByLanguageRoute +} \ No newline at end of file diff --git a/documentation/resource-likes.ts b/documentation/resource-likes.ts new file mode 100644 index 0000000..9ed6348 --- /dev/null +++ b/documentation/resource-likes.ts @@ -0,0 +1,252 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /associate + const associateResourceWithLikesRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate a resource with likes from multiple users.', + tags: ['Resource-Likes'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + userIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'userIds'], + }, + }, + }, + responses: { + 200: { + description: 'Likes associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate likes.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/delete/:userId + const removeLikesFromResourceRoute = describeRoute({ + method: 'POST', + path: '/{resourceId}/delete/{userId}', + description: 'Remove likes from a resource (unlike).', + tags: ['Resource-Likes'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'userId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Likes removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove likes.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId + const getLikesByResourceRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}', + description: 'Get all likes for a specific resource.', + tags: ['Resource-Likes'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of likes for the resource.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + userId: { type: 'number' }, + likedAt: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch likes.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/likes/:userId/exists + const checkLikeAssociationExistsRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/likes/{userId}/exists', + description: 'Check if a user has liked a specific resource.', + tags: ['Resource-Likes'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'userId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Whether the user has liked the resource or not.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check like association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /user/:userId/resources + const getResourcesByUserRoute = describeRoute({ + method: 'GET', + path: '/user/{userId}/resources', + description: 'Get all resources liked by a specific user.', + tags: ['Resource-Likes'], + parameters: [ + { + name: 'userId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources liked by the user.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + resourceName: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + + +export +{ + associateResourceWithLikesRoute, + removeLikesFromResourceRoute, + getLikesByResourceRoute, + checkLikeAssociationExistsRoute, + getResourcesByUserRoute +} \ No newline at end of file diff --git a/documentation/resource-statsDescriber.ts b/documentation/resource-statsDescriber.ts new file mode 100644 index 0000000..96c5449 --- /dev/null +++ b/documentation/resource-statsDescriber.ts @@ -0,0 +1,367 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create stats for a resource.', + tags: ['Resource-Stats'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + views: { type: 'number' }, + shares: { type: 'number' }, + downloads: { type: 'number' }, + }, + required: ['resourceId', 'views', 'shares', 'downloads'], + }, + }, + }, + responses: { + 200: { + description: 'Stats created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create stats resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update stats for a resource.', + tags: ['Resource-Stats'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + views: { type: 'number' }, + shares: { type: 'number' }, + downloads: { type: 'number' }, + }, + required: ['resourceId', 'views', 'shares', 'downloads'], + }, + }, + }, + responses: { + 200: { + description: 'Stats updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update stats resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete stats for a resource.', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Stats deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete stats resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /viewUpdate/:id + const viewUpdateResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/viewUpdate/{id}', + description: 'Update the views count of a resource (increments by 1).', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Views updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update views.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /sharesUpdate/:id + const sharesUpdateResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/sharesUpdate/{id}', + description: 'Update the shares count of a resource (increments by 1).', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Shares updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update shares.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /downloadUpdate/:id + const downloadUpdateResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/downloadUpdate/{id}', + description: 'Update the downloads count of a resource (increments by 1).', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Downloads updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update downloads.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all + const getAllResourceStatsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get all stats for all resources.', + tags: ['Resource-Stats'], + responses: { + 200: { + description: 'List of all stats for resources.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + views: { type: 'number' }, + shares: { type: 'number' }, + downloads: { type: 'number' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch stats resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getResourceStatsByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get stats for a specific resource.', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Stats for the specific resource.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch stats for the resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createResourceStatsRoute, + updateResourceStatsRoute, + deleteResourceStatsRoute, + viewUpdateResourceStatsRoute, + sharesUpdateResourceStatsRoute, + downloadUpdateResourceStatsRoute, + getAllResourceStatsRoute, + getResourceStatsByIdRoute +} \ No newline at end of file diff --git a/documentation/resource-subjectsDescriber.ts b/documentation/resource-subjectsDescriber.ts new file mode 100644 index 0000000..cb43bb8 --- /dev/null +++ b/documentation/resource-subjectsDescriber.ts @@ -0,0 +1,304 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /associate + const associateResourceWithSubjectsRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate subjects with a resource.', + tags: ['Resource-Subjects'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + subjectIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'subjectIds'], + }, + }, + }, + responses: { + 200: { + description: 'Subjects associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate subjects.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/delete/subject/:subjectId + const removeSubjectFromResourceRoute = describeRoute({ + method: 'POST', + path: '/{resourceId}/delete/subject/{subjectId}', + description: 'Remove a subject from a resource.', + tags: ['Resource-Subjects'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'subjectId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Subject removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update/subjects + const updateResourceSubjectsRoute = describeRoute({ + method: 'POST', + path: '/update/subjects', + description: 'Update subjects associated with a resource.', + tags: ['Resource-Subjects'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + subjectIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'subjectIds'], + }, + }, + }, + responses: { + 200: { + description: 'Subjects updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update subjects.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/subjects + const getSubjectsByResourceRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/subjects', + description: 'Get all subjects associated with a resource.', + tags: ['Resource-Subjects'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of subjects associated with the resource.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + subjectId: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to get subjects.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/subject/:subjectId/exists + const checkAssociationExistsRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/subject/{subjectId}/exists', + description: 'Check if a subject is associated with a resource.', + tags: ['Resource-Subjects'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'subjectId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Whether the association exists or not.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /subject/:subjectId/resources + const getResourcesBySubjectRoute = describeRoute({ + method: 'GET', + path: '/subject/{subjectId}/resources', + description: 'Get all resources associated with a subject.', + tags: ['Resource-Subjects'], + parameters: [ + { + name: 'subjectId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources associated with the subject.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to get resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + + +export +{ + associateResourceWithSubjectsRoute, + removeSubjectFromResourceRoute, + updateResourceSubjectsRoute, + getSubjectsByResourceRoute, + checkAssociationExistsRoute, + getResourcesBySubjectRoute +} \ No newline at end of file diff --git a/documentation/resourceDescriber.ts b/documentation/resourceDescriber.ts new file mode 100644 index 0000000..5cf5292 --- /dev/null +++ b/documentation/resourceDescriber.ts @@ -0,0 +1,417 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /create + const createResourceRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new resource.', + tags: ['Resources'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['name', 'description'], + }, + }, + }, + responses: { + 200: { + description: 'Resource created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + stats: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateResourceRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing resource.', + tags: ['Resources'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['id'], + }, + }, + }, + responses: { + 200: { + description: 'Resource updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /deleteData/:id + const deleteResourceDataRoute = describeRoute({ + method: 'POST', + path: '/deleteData/{id}', + description: 'Delete resource data by its ID.', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Resource data deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete resource data.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteResourceRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a resource by its ID.', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Resource deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /active/:id + const activateResourceRoute = describeRoute({ + method: 'POST', + path: '/active/{id}', + description: 'Activate a resource by its ID.', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Resource activated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to activate resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all + const getAllResourcesRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get all resources.', + tags: ['Resources'], + responses: { + 200: { + description: 'List of all resources.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + 404: { + description: 'No resources found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /allResourceByUser/:user_id + const getAllResourcesByUserRoute = describeRoute({ + method: 'GET', + path: '/allResourceByUser/{user_id}', + description: 'Get all resources by a user ID.', + tags: ['Resources'], + parameters: [ + { + name: 'user_id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources for the user.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to find resources by user.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /activeResourceByUser/:user_id + const getActiveResourcesByUserRoute = describeRoute({ + method: 'GET', + path: '/activeResourceByUser/{user_id}', + description: 'Get active resources by a user ID.', + tags: ['Resources'], + parameters: [ + { + name: 'user_id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of active resources for the user.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to find active resources by user.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getResourceByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a resource by its ID.', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Resource found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to find resource by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createResourceRoute, + updateResourceRoute, + deleteResourceDataRoute, + deleteResourceRoute, + activateResourceRoute, + getAllResourcesRoute, + getAllResourcesByUserRoute, + getActiveResourcesByUserRoute, + getResourceByIdRoute +} diff --git a/documentation/roleDescriber.ts b/documentation/roleDescriber.ts new file mode 100644 index 0000000..fb65532 --- /dev/null +++ b/documentation/roleDescriber.ts @@ -0,0 +1,233 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createRoleRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new role.', + tags: ['Role'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['name'], + }, + }, + }, + responses: { + 200: { + description: 'Role created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + role: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create role.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /roles + const getRolesRoute = describeRoute({ + method: 'GET', + path: '/roles', + description: 'Get a list of all roles.', + tags: ['Role'], + responses: { + 200: { + description: 'List of all roles.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + roleId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + 404: { + description: 'No roles found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:name + const getRoleByNameRoute = describeRoute({ + method: 'GET', + path: '/{name}', + description: 'Get a role by its name.', + tags: ['Role'], + parameters: [ + { + name: 'name', + in: 'path', + required: true, + schema: { type: 'string' }, + }, + ], + responses: { + 200: { + description: 'Role found by name.', + content: { + 'application/json': { + type: 'object', + properties: { + roleId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + 404: { + description: 'Role not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateRoleRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing role.', + tags: ['Role'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['id'], + }, + }, + }, + responses: { + 200: { + description: 'Role updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + role: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update role.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteRoleRoute = describeRoute({ + method: 'DELETE', + path: '/delete/{id}', + description: 'Delete a role by its ID.', + tags: ['Role'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Role deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + role: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete role.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createRoleRoute, + getRolesRoute, + getRoleByNameRoute, + updateRoleRoute, + deleteRoleRoute +} \ No newline at end of file diff --git a/documentation/s3Describers.ts b/documentation/s3Describers.ts new file mode 100644 index 0000000..b9ccb29 --- /dev/null +++ b/documentation/s3Describers.ts @@ -0,0 +1,453 @@ +import { describeRoute } from "hono-openapi"; + + +const uploadResourceRoute = describeRoute({ + method: "POST", + path: "/upload/resource/:id_resource", + tags: ["S3"], + summary: "Faz o upload de um recurso para o S3", + description: "Permite o upload de arquivos de até 5GB e os armazena no bucket S3.", + parameters: [ + { + name: "id_resource", + in: "path", + required: true, + description: "O ID do recurso que será armazenado.", + schema: { type: "string" } + } + ], + requestBody: { + required: true, + content: { + "multipart/form-data": { + schema: { + type: "object", + properties: { + file: { + type: "string", + format: "binary", + description: "Arquivo a ser enviado (máx. 5GB)" + } + } + } + } + } + }, + responses: { + 200: { + description: "Upload bem-sucedido.", + content: { "application/json": { example: { message: "Arquivo enviado com sucesso!", status: "success" } } } + }, + 400: { + description: "Erro de validação, como arquivo ausente ou excedendo limite.", + content: { "application/json": { example: { message: "O arquivo excede o limite de 5GB.", status: "error" } } } + }, + 500: { + description: "Erro interno ao enviar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao enviar o arquivo.", status: "error" } } } + } + } +}); + +// Rota para upload de thumbnail de um recurso no S3 +const uploadThumbnailResourceRoute = describeRoute({ + method: "POST", + path: "/upload/thumbnail/resource/:id_resource", + tags: ["S3"], + summary: "Faz o upload de uma thumbnail de recurso", + description: "Permite o upload de thumbnails de recursos de até 1MB.", + parameters: [ + { + name: "id_resource", + in: "path", + required: true, + description: "O ID do recurso ao qual a thumbnail pertence.", + schema: { type: "string" } + } + ], + requestBody: { + required: true, + content: { + "multipart/form-data": { + schema: { + type: "object", + properties: { + file: { + type: "string", + format: "binary", + description: "Thumbnail a ser enviada (máx. 1MB)" + } + } + } + } + } + }, + responses: { + 200: { + description: "Upload bem-sucedido.", + content: { "application/json": { example: { message: "Arquivo enviado com sucesso!", status: "success" } } } + }, + 400: { + description: "Erro de validação, como arquivo ausente ou excedendo limite.", + content: { "application/json": { example: { message: "A thumbnail do recurso excede o limite de 1MB.", status: "error" } } } + }, + 500: { + description: "Erro interno ao enviar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao enviar o arquivo.", status: "error" } } } + } + } +}); + +// Rota para upload de thumbnail de uma coleção no S3 +const uploadThumbnailCollectionRoute = describeRoute({ + method: "POST", + path: "/upload/thumbnail/collection/:id_collection", + tags: ["S3"], + summary: "Faz o upload de uma thumbnail de coleção", + description: "Permite o upload de thumbnails de coleções de até 1MB.", + parameters: [ + { + name: "id_collection", + in: "path", + required: true, + description: "O ID da coleção à qual a thumbnail pertence.", + schema: { type: "string" } + } + ], + requestBody: { + required: true, + content: { + "multipart/form-data": { + schema: { + type: "object", + properties: { + file: { + type: "string", + format: "binary", + description: "Thumbnail a ser enviada (máx. 1MB)" + } + } + } + } + } + }, + responses: { + 200: { + description: "Upload bem-sucedido.", + content: { "application/json": { example: { message: "Arquivo enviado com sucesso!", status: "success" } } } + }, + 400: { + description: "Erro de validação, como arquivo ausente ou excedendo limite.", + content: { "application/json": { example: { message: "A thumbnail da coleção excede o limite de 1MB.", status: "error" } } } + }, + 500: { + description: "Erro interno ao enviar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao enviar o arquivo.", status: "error" } } } + } + } +}); + +// Rota para upload de avatar no S3 +const uploadAvatarRoute = describeRoute({ + method: "POST", + path: "/upload/avatar/:id_avatar", + tags: ["S3"], + summary: "Faz o upload de um avatar", + description: "Permite o upload de avatares de até 5MB para o S3.", + parameters: [ + { + name: "id_avatar", + in: "path", + required: true, + description: "O ID do avatar a ser armazenado.", + schema: { type: "string" } + } + ], + requestBody: { + required: true, + content: { + "multipart/form-data": { + schema: { + type: "object", + properties: { + file: { + type: "string", + format: "binary", + description: "Avatar a ser enviado (máx. 5MB)" + } + } + } + } + } + }, + responses: { + 200: { + description: "Upload bem-sucedido.", + content: { "application/json": { example: { message: "Arquivo enviado com sucesso!", status: "success" } } } + }, + 400: { + description: "Erro de validação, como arquivo ausente ou excedendo limite.", + content: { "application/json": { example: { message: "O avatar excede o limite de 5MB.", status: "error" } } } + }, + 500: { + description: "Erro interno ao enviar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao enviar o arquivo.", status: "error" } } } + } + } +}); + +// Rota para deletar um recurso do S3 +const deleteResourceRoute = describeRoute({ + method: "POST", + path: "/delete/resource/:id", + tags: ["S3"], + summary: "Deleta um recurso do S3", + description: "Remove um recurso específico do bucket S3.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID do recurso a ser deletado.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Recurso deletado com sucesso.", + content: { "application/json": { example: { message: "Recurso deletado com sucesso." } } } + }, + 500: { + description: "Erro ao deletar o recurso.", + content: { "application/json": { example: { error: "Erro ao deletar objeto do S3." } } } + } + } +}); + +// Rota para deletar um avatar do S3 +const deleteAvatarRoute = describeRoute({ + method: "POST", + path: "/delete/avatar/:id", + tags: ["S3"], + summary: "Deleta um avatar do S3", + description: "Remove um avatar específico do bucket S3.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID do avatar a ser deletado.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Avatar deletado com sucesso.", + content: { "application/json": { example: { message: "Avatar deletado com sucesso." } } } + }, + 500: { + description: "Erro ao deletar o avatar.", + content: { "application/json": { example: { error: "Erro ao deletar objeto do S3." } } } + } + } +}); + +// Rota para deletar a thumbnail de um recurso no S3 +const deleteThumbnailResourceRoute = describeRoute({ + method: "POST", + path: "/delete/thumbnail/resource/:id", + tags: ["S3"], + summary: "Deleta a thumbnail de um recurso do S3", + description: "Remove a thumbnail associada a um recurso do bucket S3.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID da thumbnail do recurso a ser deletada.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Thumbnail deletada com sucesso.", + content: { "application/json": { example: { message: "Thumbnail deletada com sucesso." } } } + }, + 500: { + description: "Erro ao deletar a thumbnail.", + content: { "application/json": { example: { error: "Erro ao deletar objeto do S3." } } } + } + } +}); + +// Rota para deletar a thumbnail de uma coleção no S3 +const deleteThumbnailCollectionRoute = describeRoute({ + method: "POST", + path: "/delete/thumbnail/collection/:id", + tags: ["S3"], + summary: "Deleta a thumbnail de uma coleção do S3", + description: "Remove a thumbnail associada a uma coleção do bucket S3.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID da thumbnail da coleção a ser deletada.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Thumbnail deletada com sucesso.", + content: { "application/json": { example: { message: "Thumbnail deletada com sucesso." } } } + }, + 500: { + description: "Erro ao deletar a thumbnail.", + content: { "application/json": { example: { error: "Erro ao deletar objeto do S3." } } } + } + } +}); + +// Rota para obter um recurso do S3 +const getResourceRoute = describeRoute({ + method: "GET", + path: "/get/resource/:id", + tags: ["S3"], + summary: "Obtém um recurso do S3", + description: "Recupera um arquivo de recurso do bucket S3 com base no ID fornecido.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID do recurso a ser recuperado.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Recurso obtido com sucesso.", + content: { "application/octet-stream": {} } + }, + 404: { + description: "Arquivo não encontrado.", + content: { "application/json": { example: { message: "Arquivo não encontrado" } } } + }, + 500: { + description: "Erro interno ao buscar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao buscar o arquivo" } } } + } + } +}); + +// Rota para obter uma thumbnail de recurso do S3 +const getThumbnailResourceRoute = describeRoute({ + method: "GET", + path: "/get/thumbnail/resource/:id", + tags: ["S3"], + summary: "Obtém uma thumbnail de recurso do S3", + description: "Recupera a thumbnail de um recurso do bucket S3 com base no ID fornecido.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID da thumbnail do recurso a ser recuperada.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Thumbnail de recurso obtida com sucesso.", + content: { "application/octet-stream": {} } + }, + 404: { + description: "Arquivo não encontrado.", + content: { "application/json": { example: { message: "Arquivo não encontrado" } } } + }, + 500: { + description: "Erro interno ao buscar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao buscar o arquivo" } } } + } + } +}); + +// Rota para obter uma thumbnail de coleção do S3 +const getThumbnailCollectionRoute = describeRoute({ + method: "GET", + path: "/get/thumbnail/collection/:id", + tags: ["S3"], + summary: "Obtém uma thumbnail de coleção do S3", + description: "Recupera a thumbnail de uma coleção do bucket S3 com base no ID fornecido.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID da thumbnail da coleção a ser recuperada.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Thumbnail de coleção obtida com sucesso.", + content: { "application/octet-stream": {} } + }, + 404: { + description: "Arquivo não encontrado.", + content: { "application/json": { example: { message: "Arquivo não encontrado" } } } + }, + 500: { + description: "Erro interno ao buscar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao buscar o arquivo" } } } + } + } +}); + +// Rota para obter um avatar do S3 +const getAvatarRoute = describeRoute({ + method: "GET", + path: "/get/avatar/:id", + tags: ["S3"], + summary: "Obtém um avatar do S3", + description: "Recupera um avatar do bucket S3 com base no ID fornecido.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID do avatar a ser recuperado.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Avatar obtido com sucesso.", + content: { "application/octet-stream": {} } + }, + 404: { + description: "Arquivo não encontrado.", + content: { "application/json": { example: { message: "Arquivo não encontrado" } } } + }, + 500: { + description: "Erro interno ao buscar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao buscar o arquivo" } } } + } + } +}); + +export +{ + uploadResourceRoute, + uploadThumbnailResourceRoute, + uploadThumbnailCollectionRoute, + uploadAvatarRoute, + deleteResourceRoute, + deleteAvatarRoute, + deleteThumbnailResourceRoute, + deleteThumbnailCollectionRoute, + getResourceRoute, + getThumbnailResourceRoute, + getThumbnailCollectionRoute, + getAvatarRoute +} \ No newline at end of file diff --git a/documentation/subjectsDescriber.ts b/documentation/subjectsDescriber.ts new file mode 100644 index 0000000..004e747 --- /dev/null +++ b/documentation/subjectsDescriber.ts @@ -0,0 +1,233 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createSubjectRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new subject.', + tags: ['Subjects'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['name'], + }, + }, + }, + responses: { + 200: { + description: 'Subject created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + subject: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateSubjectRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing subject.', + tags: ['Subjects'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['id'], + }, + }, + }, + responses: { + 200: { + description: 'Subject updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + subject: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteSubjectRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a subject by its ID.', + tags: ['Subjects'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Subject deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + subject: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all + const getAllSubjectsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all subjects.', + tags: ['Subjects'], + responses: { + 200: { + description: 'List of all subjects.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + subjectId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to find subjects.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getSubjectByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a subject by its ID.', + tags: ['Subjects'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Subject found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + subjectId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to find subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createSubjectRoute, + updateSubjectRoute, + deleteSubjectRoute, + getAllSubjectsRoute, + getSubjectByIdRoute +} \ No newline at end of file diff --git a/documentation/submissionsDescriber.ts b/documentation/submissionsDescriber.ts new file mode 100644 index 0000000..4daaf66 --- /dev/null +++ b/documentation/submissionsDescriber.ts @@ -0,0 +1,286 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /create + const createSubmissionRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new submission.', + tags: ['Submissions'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + userId: { type: 'number' }, + resourceId: { type: 'number' }, + content: { type: 'string' }, + }, + required: ['userId', 'resourceId', 'content'], + }, + }, + }, + responses: { + 200: { + description: 'Submission created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + submission: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateSubmissionRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing submission.', + tags: ['Submissions'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + userId: { type: 'number' }, + resourceId: { type: 'number' }, + content: { type: 'string' }, + }, + required: ['id', 'userId', 'resourceId', 'content'], + }, + }, + }, + responses: { + 200: { + description: 'Submission updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + submission: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /answer + const answerSubmissionRoute = describeRoute({ + method: 'POST', + path: '/answer', + description: 'Submit an answer to an existing submission.', + tags: ['Submissions'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + submissionId: { type: 'number' }, + answer: { type: 'string' }, + }, + required: ['submissionId', 'answer'], + }, + }, + }, + responses: { + 200: { + description: 'Submission answered successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + submission: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to answer submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteSubmissionRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a submission by its ID.', + tags: ['Submissions'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Submission deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + submission: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getSubmissionByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a submission by its ID.', + tags: ['Submissions'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Submission found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + submissionId: { type: 'number' }, + userId: { type: 'number' }, + resourceId: { type: 'number' }, + content: { type: 'string' }, + answer: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to find submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota / + const getAllSubmissionsRoute = describeRoute({ + method: 'GET', + path: '/', + description: 'Get a list of all submissions.', + tags: ['Submissions'], + responses: { + 200: { + description: 'List of all submissions.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + submissionId: { type: 'number' }, + userId: { type: 'number' }, + resourceId: { type: 'number' }, + content: { type: 'string' }, + answer: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to find submissions.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createSubmissionRoute, + updateSubmissionRoute, + answerSubmissionRoute, + deleteSubmissionRoute, + getSubmissionByIdRoute, + getAllSubmissionsRoute +} \ No newline at end of file diff --git a/documentation/uploaderDescriber.ts b/documentation/uploaderDescriber.ts new file mode 100644 index 0000000..26dc687 --- /dev/null +++ b/documentation/uploaderDescriber.ts @@ -0,0 +1,50 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /users (upload de arquivo) +const uploadUsersRoute = describeRoute({ + method: 'POST', + path: '/users', + description: 'Upload a CSV file containing user data.', + tags: ['Uploader'], + requestBody: { + content: { + 'multipart/form-data': { + type: 'object', + properties: { + file: { + type: 'string', + format: 'binary', + }, + }, + required: ['file'], + }, + }, + }, + responses: { + 200: { + description: 'Users uploaded successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 422: { + description: 'Invalid file format or failed to upload users.', + content: { + 'text/plain': { + type: 'string', + example: 'Wrong format', + }, + }, + }, + }, +}); + +export +{ + uploadUsersRoute +} \ No newline at end of file diff --git a/documentation/user-achievementsDescriber.ts b/documentation/user-achievementsDescriber.ts new file mode 100644 index 0000000..7a93fff --- /dev/null +++ b/documentation/user-achievementsDescriber.ts @@ -0,0 +1,309 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota POST /associate (associar conquistas a um usuário) + const associateUserAchievementsRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate achievements with a user.', + tags: ['User-Achievements'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + userId: { type: 'integer', description: 'ID of the user' }, + achievementIds: { + type: 'array', + items: { type: 'integer' }, + description: 'List of achievement IDs to be associated with the user' + }, + }, + required: ['userId', 'achievementIds'], + }, + }, + }, + responses: { + 200: { + description: 'Achievements associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate achievements.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /:userId/delete/achievement/:achievementId (remover uma conquista de um usuário) + const removeUserAchievementRoute = describeRoute({ + method: 'POST', + path: '/:userId/delete/achievement/:achievementId', + description: 'Remove an achievement from a user.', + tags: ['User-Achievements'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'achievementId', + in: 'path', + description: 'ID of the achievement', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Achievement removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove achievement.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /update (atualizar conquistas de um usuário) + const updateUserAchievementsRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update achievements for a user.', + tags: ['User-Achievements'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + userId: { type: 'integer', description: 'ID of the user' }, + achievementIds: { + type: 'array', + items: { type: 'integer' }, + description: 'Updated list of achievement IDs for the user' + }, + }, + required: ['userId', 'achievementIds'], + }, + }, + }, + responses: { + 200: { + description: 'Achievements updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update achievements.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:userId/achievements (obter conquistas de um usuário) + const getUserAchievementsRoute = describeRoute({ + method: 'GET', + path: '/:userId/achievements', + description: 'Get all achievements of a user.', + tags: ['User-Achievements'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User achievements retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + achievements: { type: 'array', items: { type: 'object' } }, + }, + }, + }, + }, + 400: { + description: 'Failed to retrieve user achievements.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:userId/achievements/:achievementId/exists (verificar se uma conquista está associada a um usuário) + const checkUserAchievementExistenceRoute = describeRoute({ + method: 'GET', + path: '/:userId/achievements/:achievementId/exists', + description: 'Check if an achievement is associated with a user.', + tags: ['User-Achievements'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'achievementId', + in: 'path', + description: 'ID of the achievement', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Existence check successful.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check if the association exists.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /achievements/:achievementId/users (obter usuários associados a uma conquista) + const getUsersByAchievementRoute = describeRoute({ + method: 'GET', + path: '/achievements/:achievementId/users', + description: 'Get users who have a specific achievement.', + tags: ['User-Achievements'], + parameters: [ + { + name: 'achievementId', + in: 'path', + description: 'ID of the achievement', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users associated with the achievement retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { type: 'array', items: { type: 'object' } }, + }, + }, + }, + }, + 400: { + description: 'Failed to retrieve users by achievement.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + associateUserAchievementsRoute, + removeUserAchievementRoute, + updateUserAchievementsRoute, + getUserAchievementsRoute, + checkUserAchievementExistenceRoute, + getUsersByAchievementRoute +} \ No newline at end of file diff --git a/documentation/user-collectionDescriber.ts b/documentation/user-collectionDescriber.ts new file mode 100644 index 0000000..a0ffc6c --- /dev/null +++ b/documentation/user-collectionDescriber.ts @@ -0,0 +1,254 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota POST /associate (associar coleções a um usuário) + const associateUserCollectionsRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate collections with a user.', + tags: ['User-Collection'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + userId: { type: 'integer', description: 'ID of the user' }, + collectionIds: { + type: 'array', + items: { type: 'integer' }, + description: 'List of collection IDs to be associated with the user' + }, + }, + required: ['userId', 'collectionIds'], + }, + }, + }, + responses: { + 200: { + description: 'Collections associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate collections.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /:userId/delete/:collectionId (remover coleção de um usuário) + const removeUserCollectionRoute = describeRoute({ + method: 'POST', + path: '/:userId/delete/:collectionId', + description: 'Remove a collection from a user.', + tags: ['User-Collection'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'collectionId', + in: 'path', + description: 'ID of the collection', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Collection removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove collection.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:userId/collections (obter coleções de um usuário) + const getUserCollectionsRoute = describeRoute({ + method: 'GET', + path: '/:userId/collections', + description: 'Get all collections of a user.', + tags: ['User-Collection'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User collections retrieved successfully.', + content: { + 'application/json': { + type: 'array', + items: { type: 'object' }, + }, + }, + }, + 400: { + description: 'Failed to retrieve user collections.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:userId/collections/:collectionId/exists (verificar se uma coleção está associada a um usuário) + const checkUserCollectionExistenceRoute = describeRoute({ + method: 'GET', + path: '/:userId/collections/:collectionId/exists', + description: 'Check if a collection is associated with a user.', + tags: ['User-Collection'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'collectionId', + in: 'path', + description: 'ID of the collection', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Existence check successful.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check if the association exists.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /collection/:collectionId/users (obter usuários associados a uma coleção) + const getUsersByCollectionRoute = describeRoute({ + method: 'GET', + path: '/collection/:collectionId/users', + description: 'Get users who have a specific collection.', + tags: ['User-Collection'], + parameters: [ + { + name: 'collectionId', + in: 'path', + description: 'ID of the collection', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users associated with the collection retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { type: 'array', items: { type: 'object' } }, + }, + }, + }, + }, + 400: { + description: 'Failed to retrieve users by collection.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + associateUserCollectionsRoute, + removeUserCollectionRoute, + getUserCollectionsRoute, + checkUserCollectionExistenceRoute, + getUsersByCollectionRoute +} \ No newline at end of file diff --git a/documentation/user-institutionDescribers.ts b/documentation/user-institutionDescribers.ts new file mode 100644 index 0000000..70d5dbc --- /dev/null +++ b/documentation/user-institutionDescribers.ts @@ -0,0 +1,201 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota POST /assign (atribuir instituição a um usuário) + const assignUserToInstitutionRoute = describeRoute({ + method: 'POST', + path: '/assign', + description: 'Assign an institution to a user.', + tags: ['User-Institution'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user to be assigned to an institution' }, + institution_id: { type: 'integer', description: 'ID of the institution to assign' }, + }, + required: ['user_id', 'institution_id'], + }, + }, + }, + responses: { + 200: { + description: 'User successfully assigned to the institution.', + content: { + 'application/json': { + type: 'object', + properties: { + user_institution: { type: 'object' }, // Replace with actual schema for user institution relation + }, + }, + }, + }, + 400: { + description: 'Failed to assign user to institution.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /institutions/user/:user_id (obter instituições de um usuário) + const getUserInstitutionsRoute = describeRoute({ + method: 'GET', + path: '/institutions/user/:user_id', + description: 'Get all institutions assigned to a user.', + tags: ['User-Institution'], + parameters: [ + { + name: 'user_id', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Institutions retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + institutions: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for institutions + }, + }, + }, + }, + }, + 404: { + description: 'User not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /users/institution/:institution_id (obter usuários de uma instituição) + const getInstitutionUsersRoute = describeRoute({ + method: 'GET', + path: '/users/institution/:institution_id', + description: 'Get all users assigned to a specific institution.', + tags: ['User-Institution'], + parameters: [ + { + name: 'institution_id', + in: 'path', + description: 'ID of the institution', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for users + }, + }, + }, + }, + }, + 404: { + description: 'Institution not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /revoke (revogar associação de instituição de um usuário) + const revokeUserInstitutionRoute = describeRoute({ + method: 'POST', + path: '/revoke', + description: 'Revoke the association between a user and an institution.', + tags: ['User-Institution'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user to revoke from institution' }, + institution_id: { type: 'integer', description: 'ID of the institution to revoke' }, + }, + required: ['user_id', 'institution_id'], + }, + }, + }, + responses: { + 200: { + description: 'Association successfully revoked.', + content: { + 'application/json': { + type: 'object', + properties: { + user_institution: { type: 'object' }, // Replace with actual schema for user institution relation + }, + }, + }, + }, + 400: { + description: 'Failed to revoke association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + assignUserToInstitutionRoute, + getUserInstitutionsRoute, + getInstitutionUsersRoute, + revokeUserInstitutionRoute +} diff --git a/documentation/user-itemDescriber.ts b/documentation/user-itemDescriber.ts new file mode 100644 index 0000000..bc31d06 --- /dev/null +++ b/documentation/user-itemDescriber.ts @@ -0,0 +1,200 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota POST /create (criar associação entre usuário e item) + const createUserItemAssociationRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create an association between a user and an item.', + tags: ['User-Item'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + item_id: { type: 'integer', description: 'ID of the item' }, + }, + required: ['user_id', 'item_id'], + }, + }, + }, + responses: { + 200: { + description: 'User-item association created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_item: { type: 'object' }, // Replace with actual schema for user-item relation + }, + }, + }, + }, + 400: { + description: 'Failed to create user-item association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /items/user/:user_id (obter itens associados a um usuário) + const getItemsByUserRoute = describeRoute({ + method: 'GET', + path: '/items/user/:user_id', + description: 'Get all items associated with a user.', + tags: ['User-Item'], + parameters: [ + { + name: 'user_id', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Items associated with the user retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + items: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for items + }, + }, + }, + }, + }, + 404: { + description: 'User not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /users/item/:item_id (obter usuários associados a um item) + const getUsersByItemRoute = describeRoute({ + method: 'GET', + path: '/users/item/:item_id', + description: 'Get all users associated with a specific item.', + tags: ['User-Item'], + parameters: [ + { + name: 'item_id', + in: 'path', + description: 'ID of the item', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users associated with the item retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for users + }, + }, + }, + }, + }, + 404: { + description: 'Item not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota DELETE /delete (remover associação entre usuário e item) + const deleteUserItemAssociationRoute = describeRoute({ + method: 'DELETE', + path: '/delete', + description: 'Delete an association between a user and an item.', + tags: ['User-Item'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + item_id: { type: 'integer', description: 'ID of the item' }, + }, + required: ['user_id', 'item_id'], + }, + }, + }, + responses: { + 200: { + description: 'User-item association deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_item: { type: 'object' }, // Replace with actual schema for user-item relation + }, + }, + }, + }, + 400: { + description: 'Failed to delete user-item association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createUserItemAssociationRoute, + getItemsByUserRoute, + getUsersByItemRoute, + deleteUserItemAssociationRoute +} \ No newline at end of file diff --git a/documentation/user-roleDescribers.ts b/documentation/user-roleDescribers.ts new file mode 100644 index 0000000..bffafa7 --- /dev/null +++ b/documentation/user-roleDescribers.ts @@ -0,0 +1,201 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota POST /assign (atribuir uma função a um usuário) + const assignUserRoleRoute = describeRoute({ + method: 'POST', + path: '/assign', + description: 'Assign a role to a user.', + tags: ['User-Role'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + role_id: { type: 'integer', description: 'ID of the role' }, + }, + required: ['user_id', 'role_id'], + }, + }, + }, + responses: { + 200: { + description: 'Role assigned successfully to the user.', + content: { + 'application/json': { + type: 'object', + properties: { + user_role: { type: 'object' }, // Replace with actual schema for user-role relation + }, + }, + }, + }, + 400: { + description: 'Failed to assign role to user.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /roles/user/:user_id (obter funções associadas a um usuário) + const getRolesByUserRoute = describeRoute({ + method: 'GET', + path: '/roles/user/:user_id', + description: 'Get all roles associated with a specific user.', + tags: ['User-Role'], + parameters: [ + { + name: 'user_id', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Roles associated with the user retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + roles: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for roles + }, + }, + }, + }, + }, + 404: { + description: 'User not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /users/role/:role_id (obter usuários associados a uma função) + const getUsersByRoleRoute = describeRoute({ + method: 'GET', + path: '/users/role/:role_id', + description: 'Get all users associated with a specific role.', + tags: ['User-Role'], + parameters: [ + { + name: 'role_id', + in: 'path', + description: 'ID of the role', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users associated with the role retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for users + }, + }, + }, + }, + }, + 404: { + description: 'Role not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /revoke (revogar função de um usuário) + const revokeUserRoleRoute = describeRoute({ + method: 'POST', + path: '/revoke', + description: 'Revoke a role from a user.', + tags: ['User-Role'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + role_id: { type: 'integer', description: 'ID of the role' }, + }, + required: ['user_id', 'role_id'], + }, + }, + }, + responses: { + 200: { + description: 'Role revoked successfully from the user.', + content: { + 'application/json': { + type: 'object', + properties: { + user_role: { type: 'object' }, // Replace with actual schema for user-role relation + }, + }, + }, + }, + 400: { + description: 'Failed to revoke role from user.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + + +export +{ + assignUserRoleRoute, + getRolesByUserRoute, + getUsersByRoleRoute, + revokeUserRoleRoute +} \ No newline at end of file diff --git a/documentation/user-statsDescribers.ts b/documentation/user-statsDescribers.ts new file mode 100644 index 0000000..28933a9 --- /dev/null +++ b/documentation/user-statsDescribers.ts @@ -0,0 +1,256 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota POST /update (atualiza as estatísticas de um usuário) + const updateUserStatsRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update user statistics.', + tags: ['User-Stats'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + // Include other fields relevant for updating user stats + }, + required: ['user_id'], // Add any required fields based on your schema + }, + }, + }, + responses: { + 200: { + description: 'User statistics updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_stats: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + }, + 400: { + description: 'Failed to update user statistics.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /delete/:id (deleta as estatísticas de um usuário) + const deleteUserStatsRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete user statistics by ID.', + tags: ['User-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the user statistics to delete', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User statistics deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_stats: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + }, + 400: { + description: 'Failed to delete user statistics.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + 404: { + description: 'User statistics not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /updateComments/:id (atualiza os comentários de um usuário) + const updateUserStatsCommentsRoute = describeRoute({ + method: 'POST', + path: '/updateComments/:id', + description: 'Update user statistics comments.', + tags: ['User-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the user statistics to update comments', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User statistics comments updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_stats: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + }, + 400: { + description: 'Failed to update user statistics comments.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /all (obtém todas as estatísticas de usuários) + const getAllUserStatsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get all user statistics.', + tags: ['User-Stats'], + responses: { + 200: { + description: 'All user statistics retrieved successfully.', + content: { + 'application/json': { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + 400: { + description: 'Failed to retrieve user statistics.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:id (obtém estatísticas de um usuário específico) + const getUserStatsByIdRoute = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Get specific user statistics by ID.', + tags: ['User-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the user statistics to fetch', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User statistics retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_stats: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + }, + 400: { + description: 'Failed to fetch user statistics.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + 404: { + description: 'User statistics not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + updateUserStatsRoute, + deleteUserStatsRoute, + updateUserStatsCommentsRoute, + getAllUserStatsRoute, + getUserStatsByIdRoute +} \ No newline at end of file diff --git a/documentation/userDescriber.ts b/documentation/userDescriber.ts new file mode 100644 index 0000000..b362d17 --- /dev/null +++ b/documentation/userDescriber.ts @@ -0,0 +1,322 @@ +import { describeRoute } from 'hono-openapi'; + + +const followUserRoute = describeRoute({ + method: "POST", + path: "/follow", + summary: "Seguir um usuário.", + description: "Cria uma relação de seguidor entre dois usuários, aumentando o número de seguidores e seguidos.", + request: { + body: { + type: "object", + properties: { + follower_id: { type: "number", description: "ID do usuário que está seguindo." }, + user_id: { type: "number", description: "ID do usuário que está sendo seguido." } + }, + required: ["follower_id", "user_id"] + } + }, + response: { + 200: { + description: "Usuário seguido com sucesso.", + content: { + "application/json": { + followRelation: { + type: "object", + properties: { + id: { type: "number" }, + follower_id: { type: "number" }, + user_id: { type: "number" } + } + } + } + } + }, + 400: { description: "Erro ao seguir usuário." } + } + }); + + const unfollowUserRoute = describeRoute({ + method: "POST", + path: "/unfollow", + summary: "Deixar de seguir um usuário.", + description: "Remove a relação de seguidor entre dois usuários, reduzindo o número de seguidores e seguidos.", + request: { + body: { + type: "object", + properties: { + follower_id: { type: "number", description: "ID do usuário que está deixando de seguir." }, + user_id: { type: "number", description: "ID do usuário que está sendo deixado de seguir." } + }, + required: ["follower_id", "user_id"] + } + }, + response: { + 200: { + description: "Usuário deixou de ser seguido com sucesso.", + content: { + "application/json": { + followRelation: { + type: "object", + properties: { + id: { type: "number" }, + follower_id: { type: "number" }, + user_id: { type: "number" } + } + } + } + } + }, + 400: { description: "Erro ao deixar de seguir usuário." } + } + }); + + const getFollowsRoute = describeRoute({ + method: "GET", + path: "/follows/:id", + summary: "Listar usuários seguidos.", + description: "Retorna a lista de usuários que o ID especificado segue.", + request: { + params: { + id: { type: "number", description: "ID do usuário." } + } + }, + response: { + 200: { + description: "Lista de usuários seguidos.", + content: { + "application/json": { + follows: { + type: "array", + items: { type: "object" } + } + } + } + }, + 404: { description: "Usuário não encontrado." } + } + }); + + const getFollowersRoute = describeRoute({ + method: "GET", + path: "/followers/:id", + summary: "Listar seguidores.", + description: "Retorna a lista de usuários que seguem o ID especificado.", + request: { + params: { + id: { type: "number", description: "ID do usuário." } + } + }, + response: { + 200: { + description: "Lista de seguidores.", + content: { + "application/json": { + followers: { + type: "array", + items: { type: "object" } + } + } + } + }, + 404: { description: "Usuário não encontrado." } + } + }); + + const getUsersRoute = describeRoute({ + method: "GET", + path: "/users", + summary: "Listar todos os usuários.", + description: "Retorna a lista de todos os usuários cadastrados.", + response: { + 200: { + description: "Lista de usuários.", + content: { + "application/json": { + users: { + type: "array", + items: { type: "object" } + } + } + } + } + } + }); + + const getUserByUsernameRoute = describeRoute({ + method: "GET", + path: "/:username", + summary: "Obter detalhes de um usuário pelo nome de usuário.", + description: "Retorna as informações de um usuário com base no seu nome de usuário.", + request: { + params: { + username: { type: "string", description: "Nome de usuário." } + } + }, + response: { + 200: { + description: "Usuário encontrado.", + content: { + "application/json": { + user: { type: "object" } + } + } + }, + 404: { description: "Usuário não encontrado." } + } + }); + + +const updateUserRoute = describeRoute({ + method: "POST", + path: "/update", + summary: "Atualiza as informações de um usuário.", + description: "Recebe os novos dados do usuário e atualiza no banco de dados.", + request: { + body: { + type: "object", + properties: { + id: { type: "number", description: "ID do usuário a ser atualizado." }, + name: { type: "string", description: "Novo nome do usuário." }, + email: { type: "string", description: "Novo e-mail do usuário." }, + password: { type: "string", description: "Nova senha do usuário." } + }, + required: ["id"] + } + }, + response: { + 200: { + description: "Usuário atualizado com sucesso.", + content: { + "application/json": { + user: { + type: "object", + properties: { + id: { type: "number" }, + name: { type: "string" }, + email: { type: "string" }, + updated_at: { type: "string", description: "Data da última atualização." } + } + } + } + } + }, + 400: { description: "Erro ao atualizar usuário." } + } + }); + + const confirmUserRoute = describeRoute({ + method: "POST", + path: "/confirmation/:email", + summary: "Confirma o e-mail do usuário.", + description: "Atualiza o status de confirmação do usuário baseado no e-mail informado.", + request: { + params: { + email: { type: "string", description: "E-mail do usuário a ser confirmado." } + } + }, + response: { + 200: { + description: "Usuário confirmado com sucesso.", + content: { + "application/json": { + id: { type: "number" }, + email: { type: "string" }, + confirmed_at: { type: "string", description: "Data de confirmação do e-mail." } + } + } + }, + 400: { description: "Erro ao confirmar usuário." } + } + }); + + const reactivateUserRoute = describeRoute({ + method: "POST", + path: "/reactivate/:email", + summary: "Reativa um usuário inativo.", + description: "Altera o status do usuário para ativo e atualiza a data de reativação.", + request: { + params: { + email: { type: "string", description: "E-mail do usuário a ser reativado." } + } + }, + response: { + 200: { + description: "Usuário reativado com sucesso.", + content: { + "application/json": { + id: { type: "number" }, + email: { type: "string" }, + active: { type: "boolean", description: "Status de atividade do usuário." }, + reactivated_at: { type: "string", description: "Data da reativação." } + } + } + }, + 400: { description: "Erro ao reativar usuário." } + } + }); + + const deleteUserRoute = describeRoute({ + method: "POST", + path: "/delete/:id", + summary: "Desativa um usuário.", + description: "Marca um usuário como inativo e registra a data de exclusão.", + request: { + params: { + id: { type: "number", description: "ID do usuário a ser desativado." } + } + }, + response: { + 200: { + description: "Usuário desativado com sucesso.", + content: { + "application/json": { + id: { type: "number" }, + active: { type: "boolean", description: "Status de atividade do usuário (falso)." }, + deleted_at: { type: "string", description: "Data da desativação." } + } + } + }, + 400: { description: "Erro ao desativar usuário." } + } + }); + + const systemDeleteUserRoute = describeRoute({ + method: "POST", + path: "/delete/system/:id", + summary: "Exclui um usuário permanentemente.", + description: "Remove um usuário do banco de dados de forma definitiva.", + request: { + params: { + id: { type: "number", description: "ID do usuário a ser removido permanentemente." } + } + }, + response: { + 200: { + description: "Usuário excluído permanentemente.", + content: { + "application/json": { + id: { type: "number" }, + deleted: { type: "boolean", description: "Confirmação da exclusão." } + } + } + }, + 400: { description: "Erro ao excluir usuário." } + } + }); + + +export +{ + followUserRoute, + unfollowUserRoute, + getFollowsRoute, + getFollowersRoute, + getUsersRoute, + getUserByUsernameRoute, + updateUserRoute, + confirmUserRoute, + reactivateUserRoute, + deleteUserRoute, + systemDeleteUserRoute +} \ No newline at end of file diff --git a/package.json b/package.json index 3611059..ccb1549 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@hono/swagger-ui": "^0.5.0", "@hono/zod-openapi": "^0.18.3", "@hono/zod-validator": "^0.2.2", + "@scalar/hono-api-reference": "^0.8.0", "archiver": "^7.0.1", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 9bb2fe9..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,3749 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@aws-sdk/client-s3': - specifier: ^3.750.0 - version: 3.750.0 - '@hono/swagger-ui': - specifier: ^0.5.0 - version: 0.5.0(hono@4.6.1) - '@hono/zod-openapi': - specifier: ^0.18.3 - version: 0.18.3(hono@4.6.1)(zod@3.23.8) - '@hono/zod-validator': - specifier: ^0.2.2 - version: 0.2.2(hono@4.6.1)(zod@3.23.8) - archiver: - specifier: ^7.0.1 - version: 7.0.1 - dotenv: - specifier: ^16.4.5 - version: 16.4.5 - dotenv-expand: - specifier: ^11.0.6 - version: 11.0.6 - drizzle-orm: - specifier: ^0.31.2 - version: 0.31.4(bun-types@1.1.27)(postgres@3.4.4) - drizzle-zod: - specifier: ^0.5.1 - version: 0.5.1(drizzle-orm@0.31.4(bun-types@1.1.27)(postgres@3.4.4))(zod@3.23.8) - file-type: - specifier: ^20.1.0 - version: 20.1.0 - hono: - specifier: ^4.4.8 - version: 4.6.1 - hono-openapi: - specifier: ^0.4.6 - version: 0.4.6(@hono/zod-validator@0.2.2(hono@4.6.1)(zod@3.23.8))(hono@4.6.1)(zod@3.23.8) - jwt-simple: - specifier: ^0.5.6 - version: 0.5.6 - nodemailer: - specifier: ^6.10.0 - version: 6.10.0 - postgres: - specifier: ^3.4.4 - version: 3.4.4 - reflect-metadata: - specifier: ^0.2.2 - version: 0.2.2 - typedi: - specifier: ^0.10.0 - version: 0.10.0 - zod: - specifier: ^3.23.8 - version: 3.23.8 - devDependencies: - '@eslint/js': - specifier: ^9.5.0 - version: 9.10.0 - '@types/archiver': - specifier: ^6.0.3 - version: 6.0.3 - '@types/bun': - specifier: latest - version: 1.1.9 - cross-env: - specifier: ^7.0.3 - version: 7.0.3 - drizzle-kit: - specifier: ^0.22.7 - version: 0.22.8 - eslint: - specifier: 9.x - version: 9.10.0 - eslint-config-prettier: - specifier: ^9.1.0 - version: 9.1.0(eslint@9.10.0) - globals: - specifier: ^15.6.0 - version: 15.9.0 - prettier: - specifier: ^3.3.2 - version: 3.3.3 - typescript-eslint: - specifier: ^7.14.1 - version: 7.18.0(eslint@9.10.0)(typescript@5.6.2) - -packages: - - '@apidevtools/json-schema-ref-parser@11.9.3': - resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} - engines: {node: '>= 16'} - - '@asteasolutions/zod-to-openapi@7.3.0': - resolution: {integrity: sha512-7tE/r1gXwMIvGnXVUdIqUhCU1RevEFC4Jk6Bussa0fk1ecbnnINkZzj1EOAJyE/M3AI25DnHT/zKQL1/FPFi8Q==} - peerDependencies: - zod: ^3.20.2 - - '@aws-crypto/crc32@5.2.0': - resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} - engines: {node: '>=16.0.0'} - - '@aws-crypto/crc32c@5.2.0': - resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} - - '@aws-crypto/sha1-browser@5.2.0': - resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} - - '@aws-crypto/sha256-browser@5.2.0': - resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} - - '@aws-crypto/sha256-js@5.2.0': - resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} - engines: {node: '>=16.0.0'} - - '@aws-crypto/supports-web-crypto@5.2.0': - resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} - - '@aws-crypto/util@5.2.0': - resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - - '@aws-sdk/client-s3@3.750.0': - resolution: {integrity: sha512-S9G9noCeBxchoMVkHYrRi1A1xW/VOTP2W7X34lP+Y7Wpl32yMA7IJo0fAGAuTc0q1Nu6/pXDm+oDG7rhTCA1tg==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/client-sso@3.750.0': - resolution: {integrity: sha512-y0Rx6pTQXw0E61CaptpZF65qNggjqOgymq/RYZU5vWba5DGQ+iqGt8Yq8s+jfBoBBNXshxq8l8Dl5Uq/JTY1wg==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/core@3.750.0': - resolution: {integrity: sha512-bZ5K7N5L4+Pa2epbVpUQqd1XLG2uU8BGs/Sd+2nbgTf+lNQJyIxAg/Qsrjz9MzmY8zzQIeRQEkNmR6yVAfCmmQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/credential-provider-env@3.750.0': - resolution: {integrity: sha512-In6bsG0p/P31HcH4DBRKBbcDS/3SHvEPjfXV8ODPWZO/l3/p7IRoYBdQ07C9R+VMZU2D0+/Sc/DWK/TUNDk1+Q==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/credential-provider-http@3.750.0': - resolution: {integrity: sha512-wFB9qqfa20AB0dElsQz5ZlZT5o+a+XzpEpmg0erylmGYqEOvh8NQWfDUVpRmQuGq9VbvW/8cIbxPoNqEbPtuWQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/credential-provider-ini@3.750.0': - resolution: {integrity: sha512-2YIZmyEr5RUd3uxXpxOLD9G67Bibm4I/65M6vKFP17jVMUT+R1nL7mKqmhEVO2p+BoeV+bwMyJ/jpTYG368PCg==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/credential-provider-node@3.750.0': - resolution: {integrity: sha512-THWHHAceLwsOiowPEmKyhWVDlEUxH07GHSw5AQFDvNQtGKOQl0HSIFO1mKObT2Q2Vqzji9Bq8H58SO5BFtNPRw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/credential-provider-process@3.750.0': - resolution: {integrity: sha512-Q78SCH1n0m7tpu36sJwfrUSxI8l611OyysjQeMiIOliVfZICEoHcLHLcLkiR+tnIpZ3rk7d2EQ6R1jwlXnalMQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/credential-provider-sso@3.750.0': - resolution: {integrity: sha512-FGYrDjXN/FOQVi/t8fHSv8zCk+NEvtFnuc4cZUj5OIbM4vrfFc5VaPyn41Uza3iv6Qq9rZg0QOwWnqK8lNrqUw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/credential-provider-web-identity@3.750.0': - resolution: {integrity: sha512-Nz8zs3YJ+GOTSrq+LyzbbC1Ffpt7pK38gcOyNZv76pP5MswKTUKNYBJehqwa+i7FcFQHsCk3TdhR8MT1ZR23uA==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-bucket-endpoint@3.734.0': - resolution: {integrity: sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-expect-continue@3.734.0': - resolution: {integrity: sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-flexible-checksums@3.750.0': - resolution: {integrity: sha512-ach0d2buDnX2TUausUbiXXFWFo3IegLnCrA+Rw8I9AYVpLN9lTaRwAYJwYC6zEuW9Golff8MwkYsp/OaC5tKMw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-host-header@3.734.0': - resolution: {integrity: sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-location-constraint@3.734.0': - resolution: {integrity: sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-logger@3.734.0': - resolution: {integrity: sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-recursion-detection@3.734.0': - resolution: {integrity: sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-sdk-s3@3.750.0': - resolution: {integrity: sha512-3H6Z46cmAQCHQ0z8mm7/cftY5ifiLfCjbObrbyyp2fhQs9zk6gCKzIX8Zjhw0RMd93FZi3ebRuKJWmMglf4Itw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-ssec@3.734.0': - resolution: {integrity: sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-user-agent@3.750.0': - resolution: {integrity: sha512-YYcslDsP5+2NZoN3UwuhZGkhAHPSli7HlJHBafBrvjGV/I9f8FuOO1d1ebxGdEP4HyRXUGyh+7Ur4q+Psk0ryw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/nested-clients@3.750.0': - resolution: {integrity: sha512-OH68BRF0rt9nDloq4zsfeHI0G21lj11a66qosaljtEP66PWm7tQ06feKbFkXHT5E1K3QhJW3nVyK8v2fEBY5fg==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/region-config-resolver@3.734.0': - resolution: {integrity: sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/signature-v4-multi-region@3.750.0': - resolution: {integrity: sha512-RA9hv1Irro/CrdPcOEXKwJ0DJYJwYCsauGEdRXihrRfy8MNSR9E+mD5/Fr5Rxjaq5AHM05DYnN3mg/DU6VwzSw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/token-providers@3.750.0': - resolution: {integrity: sha512-X/KzqZw41iWolwNdc8e3RMcNSMR364viHv78u6AefXOO5eRM40c4/LuST1jDzq35/LpnqRhL7/MuixOetw+sFw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/types@3.734.0': - resolution: {integrity: sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/util-arn-parser@3.723.0': - resolution: {integrity: sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/util-endpoints@3.743.0': - resolution: {integrity: sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/util-locate-window@3.723.0': - resolution: {integrity: sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/util-user-agent-browser@3.734.0': - resolution: {integrity: sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==} - - '@aws-sdk/util-user-agent-node@3.750.0': - resolution: {integrity: sha512-84HJj9G9zbrHX2opLk9eHfDceB+UIHVrmflMzWHpsmo9fDuro/flIBqaVDlE021Osj6qIM0SJJcnL6s23j7JEw==} - engines: {node: '>=18.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - - '@aws-sdk/xml-builder@3.734.0': - resolution: {integrity: sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ==} - engines: {node: '>=18.0.0'} - - '@esbuild-kit/core-utils@3.3.2': - resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} - deprecated: 'Merged into tsx: https://tsx.is' - - '@esbuild-kit/esm-loader@2.6.5': - resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} - deprecated: 'Merged into tsx: https://tsx.is' - - '@esbuild/aix-ppc64@0.19.12': - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.18.20': - resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.19.12': - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.18.20': - resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.19.12': - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.18.20': - resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.19.12': - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.18.20': - resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.19.12': - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.18.20': - resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.19.12': - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.18.20': - resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.19.12': - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.18.20': - resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.19.12': - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.18.20': - resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.19.12': - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.18.20': - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.19.12': - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.18.20': - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.19.12': - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.18.20': - resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.19.12': - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.18.20': - resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.19.12': - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.18.20': - resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.19.12': - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.18.20': - resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.19.12': - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.18.20': - resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.19.12': - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.18.20': - resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.19.12': - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-x64@0.18.20': - resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.19.12': - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-x64@0.18.20': - resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.19.12': - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/sunos-x64@0.18.20': - resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.19.12': - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.18.20': - resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.19.12': - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.18.20': - resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.19.12': - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.18.20': - resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.19.12': - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.11.0': - resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.18.0': - resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.1.0': - resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.10.0': - resolution: {integrity: sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.4': - resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.1.0': - resolution: {integrity: sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@hono/swagger-ui@0.5.0': - resolution: {integrity: sha512-MWYYSv9kC8IwFBLZdwgZZMT9zUq2C/4/ekuyEYOkHEgUMqu+FG3eebtBZ4ofMh60xYRxRR2BgQGoNIILys/PFg==} - peerDependencies: - hono: '*' - - '@hono/zod-openapi@0.18.3': - resolution: {integrity: sha512-bNlRDODnp7P9Fs13ZPajEOt13G0XwXKfKRHMEFCphQsFiD1Y+twzHaglpNAhNcflzR1DQwHY92ZS06b4LTPbIQ==} - engines: {node: '>=16.0.0'} - peerDependencies: - hono: '>=4.3.6' - zod: 3.* - - '@hono/zod-validator@0.2.2': - resolution: {integrity: sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==} - peerDependencies: - hono: '>=3.9.0' - zod: ^3.19.1 - - '@hono/zod-validator@0.4.2': - resolution: {integrity: sha512-1rrlBg+EpDPhzOV4hT9pxr5+xDVmKuz6YJl+la7VCwK6ass5ldyKm5fD+umJdV2zhHD6jROoCCv8NbTwyfhT0g==} - peerDependencies: - hono: '>=3.9.0' - zod: ^3.19.1 - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.3.0': - resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} - engines: {node: '>=18.18'} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@jsdevtools/ono@7.1.3': - resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@smithy/abort-controller@4.0.1': - resolution: {integrity: sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==} - engines: {node: '>=18.0.0'} - - '@smithy/chunked-blob-reader-native@4.0.0': - resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==} - engines: {node: '>=18.0.0'} - - '@smithy/chunked-blob-reader@5.0.0': - resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==} - engines: {node: '>=18.0.0'} - - '@smithy/config-resolver@4.0.1': - resolution: {integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==} - engines: {node: '>=18.0.0'} - - '@smithy/core@3.1.4': - resolution: {integrity: sha512-wFExFGK+7r2wYriOqe7RRIBNpvxwiS95ih09+GSLRBdoyK/O1uZA7K7pKesj5CBvwJuSBeXwLyR88WwIAY+DGA==} - engines: {node: '>=18.0.0'} - - '@smithy/credential-provider-imds@4.0.1': - resolution: {integrity: sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-codec@4.0.1': - resolution: {integrity: sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-serde-browser@4.0.1': - resolution: {integrity: sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-serde-config-resolver@4.0.1': - resolution: {integrity: sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-serde-node@4.0.1': - resolution: {integrity: sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-serde-universal@4.0.1': - resolution: {integrity: sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==} - engines: {node: '>=18.0.0'} - - '@smithy/fetch-http-handler@5.0.1': - resolution: {integrity: sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==} - engines: {node: '>=18.0.0'} - - '@smithy/hash-blob-browser@4.0.1': - resolution: {integrity: sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw==} - engines: {node: '>=18.0.0'} - - '@smithy/hash-node@4.0.1': - resolution: {integrity: sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==} - engines: {node: '>=18.0.0'} - - '@smithy/hash-stream-node@4.0.1': - resolution: {integrity: sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw==} - engines: {node: '>=18.0.0'} - - '@smithy/invalid-dependency@4.0.1': - resolution: {integrity: sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==} - engines: {node: '>=18.0.0'} - - '@smithy/is-array-buffer@2.2.0': - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} - - '@smithy/is-array-buffer@4.0.0': - resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} - engines: {node: '>=18.0.0'} - - '@smithy/md5-js@4.0.1': - resolution: {integrity: sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-content-length@4.0.1': - resolution: {integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-endpoint@4.0.5': - resolution: {integrity: sha512-cPzGZV7qStHwboFrm6GfrzQE+YDiCzWcTh4+7wKrP/ZQ4gkw+r7qDjV8GjM4N0UYsuUyLfpzLGg5hxsYTU11WA==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-retry@4.0.6': - resolution: {integrity: sha512-s8QzuOQnbdvRymD9Gt9c9zMq10wUQAHQ3z72uirrBHCwZcLTrL5iCOuVTMdka2IXOYhQE890WD5t6G24+F+Qcg==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-serde@4.0.2': - resolution: {integrity: sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-stack@4.0.1': - resolution: {integrity: sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==} - engines: {node: '>=18.0.0'} - - '@smithy/node-config-provider@4.0.1': - resolution: {integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==} - engines: {node: '>=18.0.0'} - - '@smithy/node-http-handler@4.0.2': - resolution: {integrity: sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==} - engines: {node: '>=18.0.0'} - - '@smithy/property-provider@4.0.1': - resolution: {integrity: sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==} - engines: {node: '>=18.0.0'} - - '@smithy/protocol-http@5.0.1': - resolution: {integrity: sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==} - engines: {node: '>=18.0.0'} - - '@smithy/querystring-builder@4.0.1': - resolution: {integrity: sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==} - engines: {node: '>=18.0.0'} - - '@smithy/querystring-parser@4.0.1': - resolution: {integrity: sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==} - engines: {node: '>=18.0.0'} - - '@smithy/service-error-classification@4.0.1': - resolution: {integrity: sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==} - engines: {node: '>=18.0.0'} - - '@smithy/shared-ini-file-loader@4.0.1': - resolution: {integrity: sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==} - engines: {node: '>=18.0.0'} - - '@smithy/signature-v4@5.0.1': - resolution: {integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==} - engines: {node: '>=18.0.0'} - - '@smithy/smithy-client@4.1.5': - resolution: {integrity: sha512-DMXYoYeL4QkElr216n1yodTFeATbfb4jwYM9gKn71Rw/FNA1/Sm36tkTSCsZEs7mgpG3OINmkxL9vgVFzyGPaw==} - engines: {node: '>=18.0.0'} - - '@smithy/types@4.1.0': - resolution: {integrity: sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==} - engines: {node: '>=18.0.0'} - - '@smithy/url-parser@4.0.1': - resolution: {integrity: sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==} - engines: {node: '>=18.0.0'} - - '@smithy/util-base64@4.0.0': - resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==} - engines: {node: '>=18.0.0'} - - '@smithy/util-body-length-browser@4.0.0': - resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==} - engines: {node: '>=18.0.0'} - - '@smithy/util-body-length-node@4.0.0': - resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==} - engines: {node: '>=18.0.0'} - - '@smithy/util-buffer-from@2.2.0': - resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} - engines: {node: '>=14.0.0'} - - '@smithy/util-buffer-from@4.0.0': - resolution: {integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==} - engines: {node: '>=18.0.0'} - - '@smithy/util-config-provider@4.0.0': - resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==} - engines: {node: '>=18.0.0'} - - '@smithy/util-defaults-mode-browser@4.0.6': - resolution: {integrity: sha512-N8+VCt+piupH1A7DgSVDNrVHqRLz8r6DvBkpS7EWHiIxsUk4jqGuQLjqC/gnCzmwGkVBdNruHoYAzzaSQ8e80w==} - engines: {node: '>=18.0.0'} - - '@smithy/util-defaults-mode-node@4.0.6': - resolution: {integrity: sha512-9zhx1shd1VwSSVvLZB8CM3qQ3RPD3le7A3h/UPuyh/PC7g4OaWDi2xUNzamsVoSmCGtmUBONl56lM2EU6LcH7A==} - engines: {node: '>=18.0.0'} - - '@smithy/util-endpoints@3.0.1': - resolution: {integrity: sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==} - engines: {node: '>=18.0.0'} - - '@smithy/util-hex-encoding@4.0.0': - resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==} - engines: {node: '>=18.0.0'} - - '@smithy/util-middleware@4.0.1': - resolution: {integrity: sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==} - engines: {node: '>=18.0.0'} - - '@smithy/util-retry@4.0.1': - resolution: {integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==} - engines: {node: '>=18.0.0'} - - '@smithy/util-stream@4.1.1': - resolution: {integrity: sha512-+Xvh8nhy0Wjv1y71rBVyV3eJU3356XsFQNI8dEZVNrQju7Eib8G31GWtO+zMa9kTCGd41Mflu+ZKfmQL/o2XzQ==} - engines: {node: '>=18.0.0'} - - '@smithy/util-uri-escape@4.0.0': - resolution: {integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==} - engines: {node: '>=18.0.0'} - - '@smithy/util-utf8@2.3.0': - resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} - engines: {node: '>=14.0.0'} - - '@smithy/util-utf8@4.0.0': - resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==} - engines: {node: '>=18.0.0'} - - '@smithy/util-waiter@4.0.2': - resolution: {integrity: sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==} - engines: {node: '>=18.0.0'} - - '@tokenizer/inflate@0.2.7': - resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==} - engines: {node: '>=18'} - - '@tokenizer/token@0.3.0': - resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - - '@types/archiver@6.0.3': - resolution: {integrity: sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ==} - - '@types/bun@1.1.9': - resolution: {integrity: sha512-SXJRejXpmAc3qxyN/YS4/JGWEzLf4dDBa5fLtRDipQXHqNccuMU4EUYCooXNTsylG0DmwFQsGgEDHxZF+3DqRw==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/node@20.12.14': - resolution: {integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==} - - '@types/readdir-glob@1.1.5': - resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} - - '@types/ws@8.5.12': - resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} - - '@typescript-eslint/eslint-plugin@7.18.0': - resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@7.18.0': - resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/scope-manager@7.18.0': - resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/type-utils@7.18.0': - resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@7.18.0': - resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/typescript-estree@7.18.0': - resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/utils@7.18.0': - resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - - '@typescript-eslint/visitor-keys@7.18.0': - resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} - engines: {node: ^18.18.0 || >=20.0.0} - - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - archiver-utils@5.0.2: - resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} - engines: {node: '>= 14'} - - archiver@7.0.1: - resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} - engines: {node: '>= 14'} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - - b4a@1.6.7: - resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - bare-events@2.5.4: - resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - buffer-crc32@1.0.0: - resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} - engines: {node: '>=8.0.0'} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - bun-types@1.1.27: - resolution: {integrity: sha512-rHXAiIDefeMS/fleNM1rRDYqolJGNRdch3+AuCRwcZWaqTa1vjGBNsahH/HVV7Y82frllYhJomCVSEiHzLzkgg==} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - clone@2.1.2: - resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} - engines: {node: '>=0.8'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - compress-commons@6.0.2: - resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} - engines: {node: '>= 14'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - - crc32-stream@6.0.0: - resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} - engines: {node: '>= 14'} - - cross-env@7.0.3: - resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} - engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} - hasBin: true - - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - - dotenv-expand@11.0.6: - resolution: {integrity: sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==} - engines: {node: '>=12'} - - dotenv@16.4.5: - resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} - engines: {node: '>=12'} - - drizzle-kit@0.22.8: - resolution: {integrity: sha512-VjI4wsJjk3hSqHSa3TwBf+uvH6M6pRHyxyoVbt935GUzP9tUR/BRZ+MhEJNgryqbzN2Za1KP0eJMTgKEPsalYQ==} - hasBin: true - - drizzle-orm@0.31.4: - resolution: {integrity: sha512-VGD9SH9aStF2z4QOTnVlVX/WghV/EnuEzTmsH3fSVp2E4fFgc8jl3viQrS/XUJx1ekW4rVVLJMH42SfGQdjX3Q==} - peerDependencies: - '@aws-sdk/client-rds-data': '>=3' - '@cloudflare/workers-types': '>=3' - '@electric-sql/pglite': '>=0.1.1' - '@libsql/client': '*' - '@neondatabase/serverless': '>=0.1' - '@op-engineering/op-sqlite': '>=2' - '@opentelemetry/api': ^1.4.1 - '@planetscale/database': '>=1' - '@prisma/client': '*' - '@tidbcloud/serverless': '*' - '@types/better-sqlite3': '*' - '@types/pg': '*' - '@types/react': '>=18' - '@types/sql.js': '*' - '@vercel/postgres': '>=0.8.0' - '@xata.io/client': '*' - better-sqlite3: '>=7' - bun-types: '*' - expo-sqlite: '>=13.2.0' - knex: '*' - kysely: '*' - mysql2: '>=2' - pg: '>=8' - postgres: '>=3' - prisma: '*' - react: '>=18' - sql.js: '>=1' - sqlite3: '>=5' - peerDependenciesMeta: - '@aws-sdk/client-rds-data': - optional: true - '@cloudflare/workers-types': - optional: true - '@electric-sql/pglite': - optional: true - '@libsql/client': - optional: true - '@neondatabase/serverless': - optional: true - '@op-engineering/op-sqlite': - optional: true - '@opentelemetry/api': - optional: true - '@planetscale/database': - optional: true - '@prisma/client': - optional: true - '@tidbcloud/serverless': - optional: true - '@types/better-sqlite3': - optional: true - '@types/pg': - optional: true - '@types/react': - optional: true - '@types/sql.js': - optional: true - '@vercel/postgres': - optional: true - '@xata.io/client': - optional: true - better-sqlite3: - optional: true - bun-types: - optional: true - expo-sqlite: - optional: true - knex: - optional: true - kysely: - optional: true - mysql2: - optional: true - pg: - optional: true - postgres: - optional: true - prisma: - optional: true - react: - optional: true - sql.js: - optional: true - sqlite3: - optional: true - - drizzle-zod@0.5.1: - resolution: {integrity: sha512-C/8bvzUH/zSnVfwdSibOgFjLhtDtbKYmkbPbUCq46QZyZCH6kODIMSOgZ8R7rVjoI+tCj3k06MRJMDqsIeoS4A==} - peerDependencies: - drizzle-orm: '>=0.23.13' - zod: '*' - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - esbuild-register@3.6.0: - resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} - peerDependencies: - esbuild: '>=0.12 <1' - - esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-config-prettier@9.1.0: - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-scope@8.0.2: - resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.0.0: - resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@9.10.0: - resolution: {integrity: sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.1.0: - resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-fifo@1.3.2: - resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} - - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-xml-parser@4.4.1: - resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} - hasBin: true - - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - file-type@20.1.0: - resolution: {integrity: sha512-XoxU+lETfCf+bYK3SXkxFusAvmtYQl1u/ZC4zw1DBLEsHUvh339uwYucgQnnSMz1mRCWYJrCzsbJJ95hsQbZ8A==} - engines: {node: '>=18'} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - hasBin: true - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@15.9.0: - resolution: {integrity: sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==} - engines: {node: '>=18'} - - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - hono-openapi@0.4.6: - resolution: {integrity: sha512-wSDySp2cS5Zcf1OeLG7nCP3eMsCpcDomN137T9B6/Z5Qq3D0nWgMf0I3Gl41SE1rE37OBQ0Smqx3LOP9Hk//7A==} - peerDependencies: - '@hono/arktype-validator': ^2.0.0 - '@hono/effect-validator': ^1.2.0 - '@hono/typebox-validator': ^0.2.0 || ^0.3.0 - '@hono/valibot-validator': ^0.5.1 - '@hono/zod-validator': ^0.4.1 - '@sinclair/typebox': ^0.34.9 - '@valibot/to-json-schema': ^1.0.0-beta.3 - arktype: ^2.0.0-rc.25 - effect: ^3.11.3 - hono: ^4.6.13 - openapi-types: ^12.1.3 - valibot: ^1.0.0-beta.9 - zod: ^3.23.8 - zod-openapi: ^4.0.0 - peerDependenciesMeta: - '@hono/arktype-validator': - optional: true - '@hono/effect-validator': - optional: true - '@hono/typebox-validator': - optional: true - '@hono/valibot-validator': - optional: true - '@hono/zod-validator': - optional: true - '@sinclair/typebox': - optional: true - '@valibot/to-json-schema': - optional: true - arktype: - optional: true - effect: - optional: true - hono: - optional: true - openapi-types: - optional: true - valibot: - optional: true - zod: - optional: true - zod-openapi: - optional: true - - hono@4.6.1: - resolution: {integrity: sha512-6NGwvttY1+HAFii08VYiEKI6ETPAFbpLntpm2M/MogEsAFWdZV74UNT+2M4bmqX90cIQhjlpBSP+tO+CfB0uww==} - engines: {node: '>=16.0.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-schema-walker@2.0.0: - resolution: {integrity: sha512-nXN2cMky0Iw7Af28w061hmxaPDaML5/bQD9nwm1lOoIKEGjHcRGxqWe4MfrkYThYAPjSUhmsp4bJNoLAyVn9Xw==} - engines: {node: '>=10'} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - jwt-simple@0.5.6: - resolution: {integrity: sha512-40aUybvhH9t2h71ncA1/1SbtTNCVZHgsTsTgqPUxGWDmUDrXyDf2wMNQKEbdBjbf4AI+fQhbECNTV6lWxQKUzg==} - engines: {node: '>= 0.4.0'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - lazystream@1.0.1: - resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} - engines: {node: '>= 0.6.3'} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - nodemailer@6.10.0: - resolution: {integrity: sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==} - engines: {node: '>=6.0.0'} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - openapi3-ts@4.4.0: - resolution: {integrity: sha512-9asTNB9IkKEzWMcHmVZE7Ts3kC9G7AFHfs8i7caD8HbI76gEjdkId4z/AkP83xdZsH7PLAnnbl47qZkXuxpArw==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - peek-readable@6.1.1: - resolution: {integrity: sha512-7QmvgRKhxM0E2PGV4ocfROItVode+ELI27n4q+lpufZ+tRKBu/pBP8WOmw9HXn2ui/AUizqtvaVQhcJrOkRqYg==} - engines: {node: '>=18'} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - postgres@3.4.4: - resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==} - engines: {node: '>=12'} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} - engines: {node: '>=14'} - hasBin: true - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - readdir-glob@1.1.3: - resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} - - reflect-metadata@0.2.2: - resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} - engines: {node: '>=10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - streamx@2.22.0: - resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - strnum@1.0.5: - resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} - - strtok3@10.2.1: - resolution: {integrity: sha512-Q2dTnW3UXokAvXmXvrvMoUj/me3LyJI76HNHeuGMh2o0As/vzd7eHV3ncLOyvu928vQIDbE7Vf9ldEnC7cwy1w==} - engines: {node: '>=18'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - - text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - token-types@6.0.0: - resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==} - engines: {node: '>=14.16'} - - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - typedi@0.10.0: - resolution: {integrity: sha512-v3UJF8xm68BBj6AF4oQML3ikrfK2c9EmZUyLOfShpJuItAqVBHWP/KtpGinkSsIiP6EZyyb6Z3NXyW9dgS9X1w==} - - typescript-eslint@7.18.0: - resolution: {integrity: sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - typescript@5.6.2: - resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} - engines: {node: '>=14.17'} - hasBin: true - - uint8array-extras@1.4.0: - resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==} - engines: {node: '>=18'} - - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - yaml@2.7.0: - resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} - engines: {node: '>= 14'} - hasBin: true - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zip-stream@6.0.1: - resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} - engines: {node: '>= 14'} - - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} - -snapshots: - - '@apidevtools/json-schema-ref-parser@11.9.3': - dependencies: - '@jsdevtools/ono': 7.1.3 - '@types/json-schema': 7.0.15 - js-yaml: 4.1.0 - - '@asteasolutions/zod-to-openapi@7.3.0(zod@3.23.8)': - dependencies: - openapi3-ts: 4.4.0 - zod: 3.23.8 - - '@aws-crypto/crc32@5.2.0': - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - tslib: 2.8.1 - - '@aws-crypto/crc32c@5.2.0': - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - tslib: 2.8.1 - - '@aws-crypto/sha1-browser@5.2.0': - dependencies: - '@aws-crypto/supports-web-crypto': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-locate-window': 3.723.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - - '@aws-crypto/sha256-browser@5.2.0': - dependencies: - '@aws-crypto/sha256-js': 5.2.0 - '@aws-crypto/supports-web-crypto': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-locate-window': 3.723.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - - '@aws-crypto/sha256-js@5.2.0': - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - tslib: 2.8.1 - - '@aws-crypto/supports-web-crypto@5.2.0': - dependencies: - tslib: 2.8.1 - - '@aws-crypto/util@5.2.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - - '@aws-sdk/client-s3@3.750.0': - dependencies: - '@aws-crypto/sha1-browser': 5.2.0 - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.750.0 - '@aws-sdk/credential-provider-node': 3.750.0 - '@aws-sdk/middleware-bucket-endpoint': 3.734.0 - '@aws-sdk/middleware-expect-continue': 3.734.0 - '@aws-sdk/middleware-flexible-checksums': 3.750.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-location-constraint': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-sdk-s3': 3.750.0 - '@aws-sdk/middleware-ssec': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.750.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/signature-v4-multi-region': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.743.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.750.0 - '@aws-sdk/xml-builder': 3.734.0 - '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.4 - '@smithy/eventstream-serde-browser': 4.0.1 - '@smithy/eventstream-serde-config-resolver': 4.0.1 - '@smithy/eventstream-serde-node': 4.0.1 - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/hash-blob-browser': 4.0.1 - '@smithy/hash-node': 4.0.1 - '@smithy/hash-stream-node': 4.0.1 - '@smithy/invalid-dependency': 4.0.1 - '@smithy/md5-js': 4.0.1 - '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.5 - '@smithy/middleware-retry': 4.0.6 - '@smithy/middleware-serde': 4.0.2 - '@smithy/middleware-stack': 4.0.1 - '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 - '@smithy/util-base64': 4.0.0 - '@smithy/util-body-length-browser': 4.0.0 - '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.6 - '@smithy/util-defaults-mode-node': 4.0.6 - '@smithy/util-endpoints': 3.0.1 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-retry': 4.0.1 - '@smithy/util-stream': 4.1.1 - '@smithy/util-utf8': 4.0.0 - '@smithy/util-waiter': 4.0.2 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sso@3.750.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.750.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.750.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.743.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.750.0 - '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.4 - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/hash-node': 4.0.1 - '@smithy/invalid-dependency': 4.0.1 - '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.5 - '@smithy/middleware-retry': 4.0.6 - '@smithy/middleware-serde': 4.0.2 - '@smithy/middleware-stack': 4.0.1 - '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 - '@smithy/util-base64': 4.0.0 - '@smithy/util-body-length-browser': 4.0.0 - '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.6 - '@smithy/util-defaults-mode-node': 4.0.6 - '@smithy/util-endpoints': 3.0.1 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-retry': 4.0.1 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/core@3.750.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/core': 3.1.4 - '@smithy/node-config-provider': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/signature-v4': 5.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - '@smithy/util-middleware': 4.0.1 - fast-xml-parser: 4.4.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-env@3.750.0': - dependencies: - '@aws-sdk/core': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-http@3.750.0': - dependencies: - '@aws-sdk/core': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/property-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - '@smithy/util-stream': 4.1.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-ini@3.750.0': - dependencies: - '@aws-sdk/core': 3.750.0 - '@aws-sdk/credential-provider-env': 3.750.0 - '@aws-sdk/credential-provider-http': 3.750.0 - '@aws-sdk/credential-provider-process': 3.750.0 - '@aws-sdk/credential-provider-sso': 3.750.0 - '@aws-sdk/credential-provider-web-identity': 3.750.0 - '@aws-sdk/nested-clients': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/credential-provider-imds': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-node@3.750.0': - dependencies: - '@aws-sdk/credential-provider-env': 3.750.0 - '@aws-sdk/credential-provider-http': 3.750.0 - '@aws-sdk/credential-provider-ini': 3.750.0 - '@aws-sdk/credential-provider-process': 3.750.0 - '@aws-sdk/credential-provider-sso': 3.750.0 - '@aws-sdk/credential-provider-web-identity': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/credential-provider-imds': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-process@3.750.0': - dependencies: - '@aws-sdk/core': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-sso@3.750.0': - dependencies: - '@aws-sdk/client-sso': 3.750.0 - '@aws-sdk/core': 3.750.0 - '@aws-sdk/token-providers': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-web-identity@3.750.0': - dependencies: - '@aws-sdk/core': 3.750.0 - '@aws-sdk/nested-clients': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/middleware-bucket-endpoint@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-arn-parser': 3.723.0 - '@smithy/node-config-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-config-provider': 4.0.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-expect-continue@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-flexible-checksums@3.750.0': - dependencies: - '@aws-crypto/crc32': 5.2.0 - '@aws-crypto/crc32c': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/is-array-buffer': 4.0.0 - '@smithy/node-config-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-stream': 4.1.1 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-host-header@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-location-constraint@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-logger@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-recursion-detection@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-sdk-s3@3.750.0': - dependencies: - '@aws-sdk/core': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-arn-parser': 3.723.0 - '@smithy/core': 3.1.4 - '@smithy/node-config-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/signature-v4': 5.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-stream': 4.1.1 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-ssec@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-user-agent@3.750.0': - dependencies: - '@aws-sdk/core': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.743.0 - '@smithy/core': 3.1.4 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/nested-clients@3.750.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.750.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.750.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.743.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.750.0 - '@smithy/config-resolver': 4.0.1 - '@smithy/core': 3.1.4 - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/hash-node': 4.0.1 - '@smithy/invalid-dependency': 4.0.1 - '@smithy/middleware-content-length': 4.0.1 - '@smithy/middleware-endpoint': 4.0.5 - '@smithy/middleware-retry': 4.0.6 - '@smithy/middleware-serde': 4.0.2 - '@smithy/middleware-stack': 4.0.1 - '@smithy/node-config-provider': 4.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 - '@smithy/util-base64': 4.0.0 - '@smithy/util-body-length-browser': 4.0.0 - '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.6 - '@smithy/util-defaults-mode-node': 4.0.6 - '@smithy/util-endpoints': 3.0.1 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-retry': 4.0.1 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/region-config-resolver@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/node-config-provider': 4.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.1 - tslib: 2.8.1 - - '@aws-sdk/signature-v4-multi-region@3.750.0': - dependencies: - '@aws-sdk/middleware-sdk-s3': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.0.1 - '@smithy/signature-v4': 5.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/token-providers@3.750.0': - dependencies: - '@aws-sdk/nested-clients': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/types@3.734.0': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/util-arn-parser@3.723.0': - dependencies: - tslib: 2.8.1 - - '@aws-sdk/util-endpoints@3.743.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.1.0 - '@smithy/util-endpoints': 3.0.1 - tslib: 2.8.1 - - '@aws-sdk/util-locate-window@3.723.0': - dependencies: - tslib: 2.8.1 - - '@aws-sdk/util-user-agent-browser@3.734.0': - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.1.0 - bowser: 2.11.0 - tslib: 2.8.1 - - '@aws-sdk/util-user-agent-node@3.750.0': - dependencies: - '@aws-sdk/middleware-user-agent': 3.750.0 - '@aws-sdk/types': 3.734.0 - '@smithy/node-config-provider': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@aws-sdk/xml-builder@3.734.0': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@esbuild-kit/core-utils@3.3.2': - dependencies: - esbuild: 0.18.20 - source-map-support: 0.5.21 - - '@esbuild-kit/esm-loader@2.6.5': - dependencies: - '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.8.1 - - '@esbuild/aix-ppc64@0.19.12': - optional: true - - '@esbuild/android-arm64@0.18.20': - optional: true - - '@esbuild/android-arm64@0.19.12': - optional: true - - '@esbuild/android-arm@0.18.20': - optional: true - - '@esbuild/android-arm@0.19.12': - optional: true - - '@esbuild/android-x64@0.18.20': - optional: true - - '@esbuild/android-x64@0.19.12': - optional: true - - '@esbuild/darwin-arm64@0.18.20': - optional: true - - '@esbuild/darwin-arm64@0.19.12': - optional: true - - '@esbuild/darwin-x64@0.18.20': - optional: true - - '@esbuild/darwin-x64@0.19.12': - optional: true - - '@esbuild/freebsd-arm64@0.18.20': - optional: true - - '@esbuild/freebsd-arm64@0.19.12': - optional: true - - '@esbuild/freebsd-x64@0.18.20': - optional: true - - '@esbuild/freebsd-x64@0.19.12': - optional: true - - '@esbuild/linux-arm64@0.18.20': - optional: true - - '@esbuild/linux-arm64@0.19.12': - optional: true - - '@esbuild/linux-arm@0.18.20': - optional: true - - '@esbuild/linux-arm@0.19.12': - optional: true - - '@esbuild/linux-ia32@0.18.20': - optional: true - - '@esbuild/linux-ia32@0.19.12': - optional: true - - '@esbuild/linux-loong64@0.18.20': - optional: true - - '@esbuild/linux-loong64@0.19.12': - optional: true - - '@esbuild/linux-mips64el@0.18.20': - optional: true - - '@esbuild/linux-mips64el@0.19.12': - optional: true - - '@esbuild/linux-ppc64@0.18.20': - optional: true - - '@esbuild/linux-ppc64@0.19.12': - optional: true - - '@esbuild/linux-riscv64@0.18.20': - optional: true - - '@esbuild/linux-riscv64@0.19.12': - optional: true - - '@esbuild/linux-s390x@0.18.20': - optional: true - - '@esbuild/linux-s390x@0.19.12': - optional: true - - '@esbuild/linux-x64@0.18.20': - optional: true - - '@esbuild/linux-x64@0.19.12': - optional: true - - '@esbuild/netbsd-x64@0.18.20': - optional: true - - '@esbuild/netbsd-x64@0.19.12': - optional: true - - '@esbuild/openbsd-x64@0.18.20': - optional: true - - '@esbuild/openbsd-x64@0.19.12': - optional: true - - '@esbuild/sunos-x64@0.18.20': - optional: true - - '@esbuild/sunos-x64@0.19.12': - optional: true - - '@esbuild/win32-arm64@0.18.20': - optional: true - - '@esbuild/win32-arm64@0.19.12': - optional: true - - '@esbuild/win32-ia32@0.18.20': - optional: true - - '@esbuild/win32-ia32@0.19.12': - optional: true - - '@esbuild/win32-x64@0.18.20': - optional: true - - '@esbuild/win32-x64@0.19.12': - optional: true - - '@eslint-community/eslint-utils@4.4.0(eslint@9.10.0)': - dependencies: - eslint: 9.10.0 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.11.0': {} - - '@eslint/config-array@0.18.0': - dependencies: - '@eslint/object-schema': 2.1.4 - debug: 4.3.7 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@eslint/eslintrc@3.1.0': - dependencies: - ajv: 6.12.6 - debug: 4.3.7 - espree: 10.1.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.10.0': {} - - '@eslint/object-schema@2.1.4': {} - - '@eslint/plugin-kit@0.1.0': - dependencies: - levn: 0.4.1 - - '@hono/swagger-ui@0.5.0(hono@4.6.1)': - dependencies: - hono: 4.6.1 - - '@hono/zod-openapi@0.18.3(hono@4.6.1)(zod@3.23.8)': - dependencies: - '@asteasolutions/zod-to-openapi': 7.3.0(zod@3.23.8) - '@hono/zod-validator': 0.4.2(hono@4.6.1)(zod@3.23.8) - hono: 4.6.1 - zod: 3.23.8 - - '@hono/zod-validator@0.2.2(hono@4.6.1)(zod@3.23.8)': - dependencies: - hono: 4.6.1 - zod: 3.23.8 - - '@hono/zod-validator@0.4.2(hono@4.6.1)(zod@3.23.8)': - dependencies: - hono: 4.6.1 - zod: 3.23.8 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.3.0': {} - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@jsdevtools/ono@7.1.3': {} - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@smithy/abort-controller@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/chunked-blob-reader-native@4.0.0': - dependencies: - '@smithy/util-base64': 4.0.0 - tslib: 2.8.1 - - '@smithy/chunked-blob-reader@5.0.0': - dependencies: - tslib: 2.8.1 - - '@smithy/config-resolver@4.0.1': - dependencies: - '@smithy/node-config-provider': 4.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.1 - tslib: 2.8.1 - - '@smithy/core@3.1.4': - dependencies: - '@smithy/middleware-serde': 4.0.2 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-body-length-browser': 4.0.0 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-stream': 4.1.1 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@smithy/credential-provider-imds@4.0.1': - dependencies: - '@smithy/node-config-provider': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 - tslib: 2.8.1 - - '@smithy/eventstream-codec@4.0.1': - dependencies: - '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 4.1.0 - '@smithy/util-hex-encoding': 4.0.0 - tslib: 2.8.1 - - '@smithy/eventstream-serde-browser@4.0.1': - dependencies: - '@smithy/eventstream-serde-universal': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/eventstream-serde-config-resolver@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/eventstream-serde-node@4.0.1': - dependencies: - '@smithy/eventstream-serde-universal': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/eventstream-serde-universal@4.0.1': - dependencies: - '@smithy/eventstream-codec': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/fetch-http-handler@5.0.1': - dependencies: - '@smithy/protocol-http': 5.0.1 - '@smithy/querystring-builder': 4.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-base64': 4.0.0 - tslib: 2.8.1 - - '@smithy/hash-blob-browser@4.0.1': - dependencies: - '@smithy/chunked-blob-reader': 5.0.0 - '@smithy/chunked-blob-reader-native': 4.0.0 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/hash-node@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - '@smithy/util-buffer-from': 4.0.0 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@smithy/hash-stream-node@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@smithy/invalid-dependency@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/is-array-buffer@2.2.0': - dependencies: - tslib: 2.8.1 - - '@smithy/is-array-buffer@4.0.0': - dependencies: - tslib: 2.8.1 - - '@smithy/md5-js@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@smithy/middleware-content-length@4.0.1': - dependencies: - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/middleware-endpoint@4.0.5': - dependencies: - '@smithy/core': 3.1.4 - '@smithy/middleware-serde': 4.0.2 - '@smithy/node-config-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 - '@smithy/url-parser': 4.0.1 - '@smithy/util-middleware': 4.0.1 - tslib: 2.8.1 - - '@smithy/middleware-retry@4.0.6': - dependencies: - '@smithy/node-config-provider': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/service-error-classification': 4.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-retry': 4.0.1 - tslib: 2.8.1 - uuid: 9.0.1 - - '@smithy/middleware-serde@4.0.2': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/middleware-stack@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/node-config-provider@4.0.1': - dependencies: - '@smithy/property-provider': 4.0.1 - '@smithy/shared-ini-file-loader': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/node-http-handler@4.0.2': - dependencies: - '@smithy/abort-controller': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/querystring-builder': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/property-provider@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/protocol-http@5.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/querystring-builder@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - '@smithy/util-uri-escape': 4.0.0 - tslib: 2.8.1 - - '@smithy/querystring-parser@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/service-error-classification@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - - '@smithy/shared-ini-file-loader@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/signature-v4@5.0.1': - dependencies: - '@smithy/is-array-buffer': 4.0.0 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-hex-encoding': 4.0.0 - '@smithy/util-middleware': 4.0.1 - '@smithy/util-uri-escape': 4.0.0 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@smithy/smithy-client@4.1.5': - dependencies: - '@smithy/core': 3.1.4 - '@smithy/middleware-endpoint': 4.0.5 - '@smithy/middleware-stack': 4.0.1 - '@smithy/protocol-http': 5.0.1 - '@smithy/types': 4.1.0 - '@smithy/util-stream': 4.1.1 - tslib: 2.8.1 - - '@smithy/types@4.1.0': - dependencies: - tslib: 2.8.1 - - '@smithy/url-parser@4.0.1': - dependencies: - '@smithy/querystring-parser': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/util-base64@4.0.0': - dependencies: - '@smithy/util-buffer-from': 4.0.0 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@smithy/util-body-length-browser@4.0.0': - dependencies: - tslib: 2.8.1 - - '@smithy/util-body-length-node@4.0.0': - dependencies: - tslib: 2.8.1 - - '@smithy/util-buffer-from@2.2.0': - dependencies: - '@smithy/is-array-buffer': 2.2.0 - tslib: 2.8.1 - - '@smithy/util-buffer-from@4.0.0': - dependencies: - '@smithy/is-array-buffer': 4.0.0 - tslib: 2.8.1 - - '@smithy/util-config-provider@4.0.0': - dependencies: - tslib: 2.8.1 - - '@smithy/util-defaults-mode-browser@4.0.6': - dependencies: - '@smithy/property-provider': 4.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - bowser: 2.11.0 - tslib: 2.8.1 - - '@smithy/util-defaults-mode-node@4.0.6': - dependencies: - '@smithy/config-resolver': 4.0.1 - '@smithy/credential-provider-imds': 4.0.1 - '@smithy/node-config-provider': 4.0.1 - '@smithy/property-provider': 4.0.1 - '@smithy/smithy-client': 4.1.5 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/util-endpoints@3.0.1': - dependencies: - '@smithy/node-config-provider': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/util-hex-encoding@4.0.0': - dependencies: - tslib: 2.8.1 - - '@smithy/util-middleware@4.0.1': - dependencies: - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/util-retry@4.0.1': - dependencies: - '@smithy/service-error-classification': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@smithy/util-stream@4.1.1': - dependencies: - '@smithy/fetch-http-handler': 5.0.1 - '@smithy/node-http-handler': 4.0.2 - '@smithy/types': 4.1.0 - '@smithy/util-base64': 4.0.0 - '@smithy/util-buffer-from': 4.0.0 - '@smithy/util-hex-encoding': 4.0.0 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - - '@smithy/util-uri-escape@4.0.0': - dependencies: - tslib: 2.8.1 - - '@smithy/util-utf8@2.3.0': - dependencies: - '@smithy/util-buffer-from': 2.2.0 - tslib: 2.8.1 - - '@smithy/util-utf8@4.0.0': - dependencies: - '@smithy/util-buffer-from': 4.0.0 - tslib: 2.8.1 - - '@smithy/util-waiter@4.0.2': - dependencies: - '@smithy/abort-controller': 4.0.1 - '@smithy/types': 4.1.0 - tslib: 2.8.1 - - '@tokenizer/inflate@0.2.7': - dependencies: - debug: 4.4.0 - fflate: 0.8.2 - token-types: 6.0.0 - transitivePeerDependencies: - - supports-color - - '@tokenizer/token@0.3.0': {} - - '@types/archiver@6.0.3': - dependencies: - '@types/readdir-glob': 1.1.5 - - '@types/bun@1.1.9': - dependencies: - bun-types: 1.1.27 - - '@types/json-schema@7.0.15': {} - - '@types/node@20.12.14': - dependencies: - undici-types: 5.26.5 - - '@types/readdir-glob@1.1.5': - dependencies: - '@types/node': 20.12.14 - - '@types/ws@8.5.12': - dependencies: - '@types/node': 20.12.14 - - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2)': - dependencies: - '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 7.18.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/utils': 7.18.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 9.10.0 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.6.2) - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@7.18.0(eslint@9.10.0)(typescript@5.6.2)': - dependencies: - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.2) - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.7 - eslint: 9.10.0 - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@7.18.0': - dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - - '@typescript-eslint/type-utils@7.18.0(eslint@9.10.0)(typescript@5.6.2)': - dependencies: - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.2) - '@typescript-eslint/utils': 7.18.0(eslint@9.10.0)(typescript@5.6.2) - debug: 4.3.7 - eslint: 9.10.0 - ts-api-utils: 1.3.0(typescript@5.6.2) - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@7.18.0': {} - - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.6.2)': - dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.7 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.6.2) - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@7.18.0(eslint@9.10.0)(typescript@5.6.2)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.2) - eslint: 9.10.0 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/visitor-keys@7.18.0': - dependencies: - '@typescript-eslint/types': 7.18.0 - eslint-visitor-keys: 3.4.3 - - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - acorn-jsx@5.3.2(acorn@8.12.1): - dependencies: - acorn: 8.12.1 - - acorn@8.12.1: {} - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ansi-regex@5.0.1: {} - - ansi-regex@6.1.0: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.1: {} - - archiver-utils@5.0.2: - dependencies: - glob: 10.4.5 - graceful-fs: 4.2.11 - is-stream: 2.0.1 - lazystream: 1.0.1 - lodash: 4.17.21 - normalize-path: 3.0.0 - readable-stream: 4.7.0 - - archiver@7.0.1: - dependencies: - archiver-utils: 5.0.2 - async: 3.2.6 - buffer-crc32: 1.0.0 - readable-stream: 4.7.0 - readdir-glob: 1.1.3 - tar-stream: 3.1.7 - zip-stream: 6.0.1 - - argparse@2.0.1: {} - - array-union@2.1.0: {} - - async@3.2.6: {} - - b4a@1.6.7: {} - - balanced-match@1.0.2: {} - - bare-events@2.5.4: - optional: true - - base64-js@1.5.1: {} - - bowser@2.11.0: {} - - brace-expansion@1.1.11: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - buffer-crc32@1.0.0: {} - - buffer-from@1.1.2: {} - - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bun-types@1.1.27: - dependencies: - '@types/node': 20.12.14 - '@types/ws': 8.5.12 - - callsites@3.1.0: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - clone@2.1.2: {} - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - compress-commons@6.0.2: - dependencies: - crc-32: 1.2.2 - crc32-stream: 6.0.0 - is-stream: 2.0.1 - normalize-path: 3.0.0 - readable-stream: 4.7.0 - - concat-map@0.0.1: {} - - core-util-is@1.0.3: {} - - crc-32@1.2.2: {} - - crc32-stream@6.0.0: - dependencies: - crc-32: 1.2.2 - readable-stream: 4.7.0 - - cross-env@7.0.3: - dependencies: - cross-spawn: 7.0.3 - - cross-spawn@7.0.3: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - debug@4.3.7: - dependencies: - ms: 2.1.3 - - debug@4.4.0: - dependencies: - ms: 2.1.3 - - deep-is@0.1.4: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - dotenv-expand@11.0.6: - dependencies: - dotenv: 16.4.5 - - dotenv@16.4.5: {} - - drizzle-kit@0.22.8: - dependencies: - '@esbuild-kit/esm-loader': 2.6.5 - esbuild: 0.19.12 - esbuild-register: 3.6.0(esbuild@0.19.12) - transitivePeerDependencies: - - supports-color - - drizzle-orm@0.31.4(bun-types@1.1.27)(postgres@3.4.4): - optionalDependencies: - bun-types: 1.1.27 - postgres: 3.4.4 - - drizzle-zod@0.5.1(drizzle-orm@0.31.4(bun-types@1.1.27)(postgres@3.4.4))(zod@3.23.8): - dependencies: - drizzle-orm: 0.31.4(bun-types@1.1.27)(postgres@3.4.4) - zod: 3.23.8 - - eastasianwidth@0.2.0: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - esbuild-register@3.6.0(esbuild@0.19.12): - dependencies: - debug: 4.3.7 - esbuild: 0.19.12 - transitivePeerDependencies: - - supports-color - - esbuild@0.18.20: - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - - esbuild@0.19.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - - escape-string-regexp@4.0.0: {} - - eslint-config-prettier@9.1.0(eslint@9.10.0): - dependencies: - eslint: 9.10.0 - - eslint-scope@8.0.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.0.0: {} - - eslint@9.10.0: - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) - '@eslint-community/regexpp': 4.11.0 - '@eslint/config-array': 0.18.0 - '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.10.0 - '@eslint/plugin-kit': 0.1.0 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.3.0 - '@nodelib/fs.walk': 1.2.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.7 - escape-string-regexp: 4.0.0 - eslint-scope: 8.0.2 - eslint-visitor-keys: 4.0.0 - espree: 10.1.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - espree@10.1.0: - dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) - eslint-visitor-keys: 4.0.0 - - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - esutils@2.0.3: {} - - event-target-shim@5.0.1: {} - - events@3.3.0: {} - - fast-deep-equal@3.1.3: {} - - fast-fifo@1.3.2: {} - - fast-glob@3.3.2: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-xml-parser@4.4.1: - dependencies: - strnum: 1.0.5 - - fastq@1.17.1: - dependencies: - reusify: 1.0.4 - - fflate@0.8.2: {} - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - file-type@20.1.0: - dependencies: - '@tokenizer/inflate': 0.2.7 - strtok3: 10.2.1 - token-types: 6.0.0 - uint8array-extras: 1.4.0 - transitivePeerDependencies: - - supports-color - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.3.1 - keyv: 4.5.4 - - flatted@3.3.1: {} - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - get-tsconfig@4.8.1: - dependencies: - resolve-pkg-maps: 1.0.0 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@10.4.5: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - - globals@14.0.0: {} - - globals@15.9.0: {} - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - has-flag@4.0.0: {} - - hono-openapi@0.4.6(@hono/zod-validator@0.2.2(hono@4.6.1)(zod@3.23.8))(hono@4.6.1)(zod@3.23.8): - dependencies: - json-schema-walker: 2.0.0 - optionalDependencies: - '@hono/zod-validator': 0.2.2(hono@4.6.1)(zod@3.23.8) - hono: 4.6.1 - zod: 3.23.8 - - hono@4.6.1: {} - - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - import-fresh@3.3.0: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - inherits@2.0.4: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - is-path-inside@3.0.3: {} - - is-stream@2.0.1: {} - - isarray@1.0.0: {} - - isexe@2.0.0: {} - - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-schema-walker@2.0.0: - dependencies: - '@apidevtools/json-schema-ref-parser': 11.9.3 - clone: 2.1.2 - - json-stable-stringify-without-jsonify@1.0.1: {} - - jwt-simple@0.5.6: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - lazystream@1.0.1: - dependencies: - readable-stream: 2.3.8 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - lodash@4.17.21: {} - - lru-cache@10.4.3: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.1 - - minipass@7.1.2: {} - - ms@2.1.3: {} - - natural-compare@1.4.0: {} - - nodemailer@6.10.0: {} - - normalize-path@3.0.0: {} - - openapi3-ts@4.4.0: - dependencies: - yaml: 2.7.0 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - package-json-from-dist@1.0.1: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - - path-type@4.0.0: {} - - peek-readable@6.1.1: {} - - picomatch@2.3.1: {} - - postgres@3.4.4: {} - - prelude-ls@1.2.1: {} - - prettier@3.3.3: {} - - process-nextick-args@2.0.1: {} - - process@0.11.10: {} - - punycode@2.3.1: {} - - queue-microtask@1.2.3: {} - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - readable-stream@4.7.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - - readdir-glob@1.1.3: - dependencies: - minimatch: 5.1.6 - - reflect-metadata@0.2.2: {} - - resolve-from@4.0.0: {} - - resolve-pkg-maps@1.0.0: {} - - reusify@1.0.4: {} - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.1.2: {} - - safe-buffer@5.2.1: {} - - semver@7.6.3: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - signal-exit@4.1.0: {} - - slash@3.0.0: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - streamx@2.22.0: - dependencies: - fast-fifo: 1.3.2 - text-decoder: 1.2.3 - optionalDependencies: - bare-events: 2.5.4 - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.1.0 - - strip-json-comments@3.1.1: {} - - strnum@1.0.5: {} - - strtok3@10.2.1: - dependencies: - '@tokenizer/token': 0.3.0 - peek-readable: 6.1.1 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - tar-stream@3.1.7: - dependencies: - b4a: 1.6.7 - fast-fifo: 1.3.2 - streamx: 2.22.0 - - text-decoder@1.2.3: - dependencies: - b4a: 1.6.7 - - text-table@0.2.0: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - token-types@6.0.0: - dependencies: - '@tokenizer/token': 0.3.0 - ieee754: 1.2.1 - - ts-api-utils@1.3.0(typescript@5.6.2): - dependencies: - typescript: 5.6.2 - - tslib@2.8.1: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - typedi@0.10.0: {} - - typescript-eslint@7.18.0(eslint@9.10.0)(typescript@5.6.2): - dependencies: - '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/parser': 7.18.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/utils': 7.18.0(eslint@9.10.0)(typescript@5.6.2) - eslint: 9.10.0 - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - typescript@5.6.2: {} - - uint8array-extras@1.4.0: {} - - undici-types@5.26.5: {} - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - util-deprecate@1.0.2: {} - - uuid@9.0.1: {} - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - word-wrap@1.2.5: {} - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - yaml@2.7.0: {} - - yocto-queue@0.1.0: {} - - zip-stream@6.0.1: - dependencies: - archiver-utils: 5.0.2 - compress-commons: 6.0.2 - readable-stream: 4.7.0 - - zod@3.23.8: {} diff --git a/src/db/migrations/0000_nappy_wolfpack.sql b/src/db/migrations/0000_volatile_whirlwind.sql similarity index 95% rename from src/db/migrations/0000_nappy_wolfpack.sql rename to src/db/migrations/0000_volatile_whirlwind.sql index 929b77a..dc73417 100644 --- a/src/db/migrations/0000_nappy_wolfpack.sql +++ b/src/db/migrations/0000_volatile_whirlwind.sql @@ -5,13 +5,13 @@ EXCEPTION END $$; --> statement-breakpoint DO $$ BEGIN - CREATE TYPE "public"."resource_state" AS ENUM('draft', 'submitted', 'accepted', 'reported'); + CREATE TYPE "public"."resource_state" AS ENUM('draft', 'submitted', 'accepted', 'reported', 'deleted'); EXCEPTION WHEN duplicate_object THEN null; END $$; --> statement-breakpoint DO $$ BEGIN - CREATE TYPE "public"."state" AS ENUM('active', 'inactive', 'under_review'); + CREATE TYPE "public"."review_state" AS ENUM('active', 'inactive', 'under_review'); EXCEPTION WHEN duplicate_object THEN null; END $$; @@ -22,7 +22,7 @@ CREATE TABLE IF NOT EXISTS "achievements" ( "description" text, "reward_experience" numeric, "reward_points" numeric, - "state" "state" DEFAULT 'inactive' NOT NULL, + "review_state" "review_state" DEFAULT 'under_review' NOT NULL, "repeatable" integer NOT NULL, "is_resettable" boolean NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL, @@ -41,7 +41,7 @@ CREATE TABLE IF NOT EXISTS "actions" ( CREATE TABLE IF NOT EXISTS "collection_likes" ( "id" serial PRIMARY KEY NOT NULL, "user_id" integer NOT NULL, - "collection" integer NOT NULL, + "collection_id" integer NOT NULL, CONSTRAINT "collection_likes_id_unique" UNIQUE("id") ); --> statement-breakpoint @@ -65,7 +65,7 @@ CREATE TABLE IF NOT EXISTS "collection_stats" ( --> statement-breakpoint CREATE TABLE IF NOT EXISTS "collections" ( "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255), + "name" varchar(255) NOT NULL, "description" text, "is_private" boolean DEFAULT false, "is_active" boolean, @@ -115,6 +115,9 @@ CREATE TABLE IF NOT EXISTS "complaints" ( "q2" boolean, "q3" boolean, "q4" boolean, + "q5" boolean, + "q6" boolean, + "q7" boolean, CONSTRAINT "complaints_id_unique" UNIQUE("id") ); --> statement-breakpoint @@ -142,6 +145,12 @@ CREATE TABLE IF NOT EXISTS "institutions" ( CONSTRAINT "institutions_id_unique" UNIQUE("id") ); --> statement-breakpoint +CREATE TABLE IF NOT EXISTS "item_achievements" ( + "item_id" integer NOT NULL, + "achievement_id" integer NOT NULL, + CONSTRAINT "item_achievements_item_id_achievement_id_pk" PRIMARY KEY("item_id","achievement_id") +); +--> statement-breakpoint CREATE TABLE IF NOT EXISTS "items" ( "id" serial PRIMARY KEY NOT NULL, "name" varchar(255) NOT NULL, @@ -151,7 +160,6 @@ CREATE TABLE IF NOT EXISTS "items" ( "is_active" boolean DEFAULT false, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL, - "achievement_id" integer, CONSTRAINT "items_id_unique" UNIQUE("id") ); --> statement-breakpoint @@ -235,9 +243,8 @@ CREATE TABLE IF NOT EXISTS "resources" ( "name" varchar(255) NOT NULL, "author" varchar(255) NOT NULL, "link" varchar(255), - "thumbnail" varchar(255) NOT NULL, + "thumbnail" varchar(255), "description" text, - "active" boolean DEFAULT false NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL, "published_at" timestamp, @@ -341,7 +348,6 @@ CREATE TABLE IF NOT EXISTS "users" ( "password" varchar(255) NOT NULL, "email" varchar(255) NOT NULL, "description" text DEFAULT 'sem descrição', - "institution" text DEFAULT 'sem instituição', "birthday" timestamp NOT NULL, "cpf" varchar(11) NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL, @@ -350,7 +356,7 @@ CREATE TABLE IF NOT EXISTS "users" ( "confirmation_sent_at" timestamp, "deleted_at" timestamp, "reactivated_at" timestamp, - "active" boolean DEFAULT true, + "is_active" boolean DEFAULT true, "user_stats_id" integer NOT NULL, CONSTRAINT "users_id_unique" UNIQUE("id"), CONSTRAINT "users_username_unique" UNIQUE("username"), @@ -366,7 +372,7 @@ EXCEPTION END $$; --> statement-breakpoint DO $$ BEGIN - ALTER TABLE "collection_likes" ADD CONSTRAINT "collection_likes_collection_collections_id_fk" FOREIGN KEY ("collection") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "collection_likes" ADD CONSTRAINT "collection_likes_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; @@ -456,7 +462,13 @@ EXCEPTION END $$; --> statement-breakpoint DO $$ BEGIN - ALTER TABLE "items" ADD CONSTRAINT "items_achievement_id_achievements_id_fk" FOREIGN KEY ("achievement_id") REFERENCES "public"."achievements"("id") ON DELETE no action ON UPDATE no action; + ALTER TABLE "item_achievements" ADD CONSTRAINT "item_achievements_item_id_items_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."items"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "item_achievements" ADD CONSTRAINT "item_achievements_achievement_id_achievements_id_fk" FOREIGN KEY ("achievement_id") REFERENCES "public"."achievements"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; diff --git a/src/db/migrations/meta/0000_snapshot.json b/src/db/migrations/meta/0000_snapshot.json index 156b710..8c8f76a 100644 --- a/src/db/migrations/meta/0000_snapshot.json +++ b/src/db/migrations/meta/0000_snapshot.json @@ -1,5 +1,5 @@ { - "id": "9c23b9d5-4c93-4758-bd46-cd0e95cfd455", + "id": "88278623-4429-44b9-bc5b-e4d6a0055c81", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", @@ -38,13 +38,13 @@ "primaryKey": false, "notNull": false }, - "state": { - "name": "state", - "type": "state", + "review_state": { + "name": "review_state", + "type": "review_state", "typeSchema": "public", "primaryKey": false, "notNull": true, - "default": "'inactive'" + "default": "'under_review'" }, "repeatable": { "name": "repeatable", @@ -146,8 +146,8 @@ "primaryKey": false, "notNull": true }, - "collection": { - "name": "collection", + "collection_id": { + "name": "collection_id", "type": "integer", "primaryKey": false, "notNull": true @@ -168,12 +168,12 @@ "onDelete": "cascade", "onUpdate": "no action" }, - "collection_likes_collection_collections_id_fk": { - "name": "collection_likes_collection_collections_id_fk", + "collection_likes_collection_id_collections_id_fk": { + "name": "collection_likes_collection_id_collections_id_fk", "tableFrom": "collection_likes", "tableTo": "collections", "columnsFrom": [ - "collection" + "collection_id" ], "columnsTo": [ "id" @@ -336,7 +336,7 @@ "name": "name", "type": "varchar(255)", "primaryKey": false, - "notNull": false + "notNull": true }, "description": { "name": "description", @@ -705,6 +705,24 @@ "type": "boolean", "primaryKey": false, "notNull": false + }, + "q5": { + "name": "q5", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "q6": { + "name": "q6", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "q7": { + "name": "q7", + "type": "boolean", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -928,6 +946,63 @@ } } }, + "public.item_achievements": { + "name": "item_achievements", + "schema": "", + "columns": { + "item_id": { + "name": "item_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "achievement_id": { + "name": "achievement_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "item_achievements_item_id_items_id_fk": { + "name": "item_achievements_item_id_items_id_fk", + "tableFrom": "item_achievements", + "tableTo": "items", + "columnsFrom": [ + "item_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_achievements_achievement_id_achievements_id_fk": { + "name": "item_achievements_achievement_id_achievements_id_fk", + "tableFrom": "item_achievements", + "tableTo": "achievements", + "columnsFrom": [ + "achievement_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_achievements_item_id_achievement_id_pk": { + "name": "item_achievements_item_id_achievement_id_pk", + "columns": [ + "item_id", + "achievement_id" + ] + } + }, + "uniqueConstraints": {} + }, "public.items": { "name": "items", "schema": "", @@ -982,30 +1057,10 @@ "primaryKey": false, "notNull": true, "default": "now()" - }, - "achievement_id": { - "name": "achievement_id", - "type": "integer", - "primaryKey": false, - "notNull": false } }, "indexes": {}, - "foreignKeys": { - "items_achievement_id_achievements_id_fk": { - "name": "items_achievement_id_achievements_id_fk", - "tableFrom": "items", - "tableTo": "achievements", - "columnsFrom": [ - "achievement_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, + "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": { "items_id_unique": { @@ -1631,7 +1686,7 @@ "name": "thumbnail", "type": "varchar(255)", "primaryKey": false, - "notNull": true + "notNull": false }, "description": { "name": "description", @@ -1639,13 +1694,6 @@ "primaryKey": false, "notNull": false }, - "active": { - "name": "active", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, "created_at": { "name": "created_at", "type": "timestamp", @@ -2452,13 +2500,6 @@ "notNull": false, "default": "'sem descrição'" }, - "institution": { - "name": "institution", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'sem instituição'" - }, "birthday": { "name": "birthday", "type": "timestamp", @@ -2509,8 +2550,8 @@ "primaryKey": false, "notNull": false }, - "active": { - "name": "active", + "is_active": { + "name": "is_active", "type": "boolean", "primaryKey": false, "notNull": false, @@ -2596,11 +2637,12 @@ "draft", "submitted", "accepted", - "reported" + "reported", + "deleted" ] }, - "public.state": { - "name": "state", + "public.review_state": { + "name": "review_state", "schema": "public", "values": [ "active", diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json index bcc08a2..bfbd551 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "7", - "when": 1743432081845, - "tag": "0000_nappy_wolfpack", + "when": 1744041940840, + "tag": "0000_volatile_whirlwind", "breakpoints": true } ] diff --git a/src/db/schema/complaint.schema.ts b/src/db/schema/complaint.schema.ts index 6541dbf..dc214a7 100644 --- a/src/db/schema/complaint.schema.ts +++ b/src/db/schema/complaint.schema.ts @@ -33,9 +33,9 @@ const complaintTable = pgTable('complaints', { q2: boolean('q2'), q3: boolean('q3'), q4: boolean('q4'), - q5: boolean('q4'), - q6: boolean('q4'), - q7: boolean('q4'), + q5: boolean('q5'), + q6: boolean('q6'), + q7: boolean('q7'), }) const complaintModelSchema = createSelectSchema(complaintTable) diff --git a/src/db/schema/index.ts b/src/db/schema/index.ts index d5f0bf7..adfcaeb 100644 --- a/src/db/schema/index.ts +++ b/src/db/schema/index.ts @@ -92,7 +92,6 @@ export const tables = [ roleTable, followRelationTable, complaintTable, - collectionLikesTable, userRoleRelationTable, collectionResourcesTable, institutionTable, @@ -107,4 +106,5 @@ export const tables = [ commentsTable, commentReplyTable, userCollectionTable, + collectionLikesTable, ] diff --git a/src/db/seeds/complaints.seed.ts b/src/db/seeds/complaints.seed.ts index 2cc2248..1b709cb 100644 --- a/src/db/seeds/complaints.seed.ts +++ b/src/db/seeds/complaints.seed.ts @@ -19,29 +19,8 @@ const complaintData: ComplaintInput[] = [ q2: true, q3: false, q4: false, - }, - { - state: 'complained', - description: 'I do not like this resource', - denouncer_id: 1, - resource_id: 1, - collection_id: null, - user_id: null, - q1: false, - q2: true, - q3: false, - q4: false, - }, - { - state: 'complained', - description: 'I do not like this resource', - denouncer_id: 1, - resource_id: 1, - collection_id: null, - user_id: null, - q1: false, - q2: true, - q3: false, - q4: false, - }, + q5: false, + q6: false, + q7: false + } ] diff --git a/src/documentation/Educational-StageDescribers.ts b/src/documentation/Educational-StageDescribers.ts new file mode 100644 index 0000000..a476d41 --- /dev/null +++ b/src/documentation/Educational-StageDescribers.ts @@ -0,0 +1,293 @@ +import { describeRoute } from 'hono-openapi' + +// Descrição da rota POST /create +const createEducationalStageRoute = describeRoute({ + method: 'POST', + path: '/create', + tags: ['Educational-Stage'], + summary: 'Create a new educational stage', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string', description: 'Name of the educational stage' }, + description: { type: 'string', description: 'Description of the educational stage' }, + }, + required: ['name'], + }, + }, + }, + }, + responses: { + 200: { + description: 'Educational stage created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStage: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the created educational stage' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request due to invalid input', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição da rota POST /update + const updateEducationalStageRoute = describeRoute({ + method: 'POST', + path: '/update', + tags: ['Educational-Stage'], + summary: 'Update an existing educational stage', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the educational stage to update' }, + name: { type: 'string', description: 'Updated name of the educational stage' }, + description: { type: 'string', description: 'Updated description of the educational stage' }, + }, + required: ['id'], + }, + }, + }, + }, + responses: { + 200: { + description: 'Educational stage updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStage: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request due to invalid input', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição da rota POST /delete/:id + const deleteEducationalStageRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + tags: ['Educational-Stage'], + summary: 'Delete an educational stage by ID', + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the educational stage to delete', + }, + }, + ], + responses: { + 200: { + description: 'Educational stage deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStage: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request due to invalid ID', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição da rota GET /all + const getAllEducationalStagesRoute = describeRoute({ + method: 'GET', + path: '/all', + tags: ['Educational-Stage'], + summary: 'Get all educational stages', + responses: { + 200: { + description: 'List of educational stages retrieved successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStages: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição da rota GET /:id + const getEducationalStageByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + tags: ['Educational-Stage'], + summary: 'Get an educational stage by ID', + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the educational stage to retrieve', + }, + }, + ], + responses: { + 200: { + description: 'Educational stage retrieved successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + educationalStage: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request due to invalid ID', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + createEducationalStageRoute, + updateEducationalStageRoute, + deleteEducationalStageRoute, + getAllEducationalStagesRoute, + getEducationalStageByIdRoute, +} diff --git a/src/documentation/ItemDescriber.ts b/src/documentation/ItemDescriber.ts new file mode 100644 index 0000000..331707d --- /dev/null +++ b/src/documentation/ItemDescriber.ts @@ -0,0 +1,337 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createItemRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new item.', + tags: ['Item'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + required: ['name', 'description', 'price', 'quantity'], + }, + }, + }, + responses: { + 200: { + description: 'Item created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateItemRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing item.', + tags: ['Item'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + required: ['id', 'name', 'description', 'price', 'quantity'], + }, + }, + }, + responses: { + 200: { + description: 'Item updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteItemRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete an item by ID.', + tags: ['Item'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Item deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /active/:id + const activeItemRoute = describeRoute({ + method: 'POST', + path: '/active/{id}', + description: 'Activate an item by ID.', + tags: ['Item'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Item activated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all (public route) + const getAllItemsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all items.', + tags: ['Item'], + responses: { + 200: { + description: 'List of items.', + content: { + 'application/json': { + type: 'object', + properties: { + items: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find items.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id (public route) + const getItemByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get an item by ID.', + tags: ['Item'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Item found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + item: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + price: { type: 'number' }, + quantity: { type: 'number' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find item.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createItemRoute, + updateItemRoute, + deleteItemRoute, + activeItemRoute, + getAllItemsRoute, + getItemByIdRoute +} \ No newline at end of file diff --git a/src/documentation/achievementsDescribers.ts b/src/documentation/achievementsDescribers.ts new file mode 100644 index 0000000..b6a1ba8 --- /dev/null +++ b/src/documentation/achievementsDescribers.ts @@ -0,0 +1,301 @@ +import { describeRoute } from 'hono-openapi' + +const createRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new achievement', + tags: ['Achievements'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string', maxLength: 255 }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string', enum: ['inactive', 'active'] }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + required: ['name', 'repeatable', 'is_resettable', 'state'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Achievement created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not create achievement', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const updateRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing achievement', + tags: ['Achievements'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string', maxLength: 255 }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string', enum: ['inactive', 'active'] }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + required: ['id'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Achievement updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update achievement', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const deleteRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete an achievement by ID', + tags: ['Achievements'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Achievement deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not delete achievement', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const getAchievementRoute = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Get a specific achievement by ID', + tags: ['Achievements'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Achievement found successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '404': { + description: 'Achievement not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const getAchievementsRoute = describeRoute({ + method: 'GET', + path: '/', + description: 'Get all achievements', + tags: ['Achievements'], + responses: { + '200': { + description: 'Achievements found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + }, + '404': { + description: 'Achievements not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + createRoute, + updateRoute, + deleteRoute, + getAchievementRoute, + getAchievementsRoute, +} diff --git a/src/documentation/actionsDescribers.ts b/src/documentation/actionsDescribers.ts new file mode 100644 index 0000000..9942707 --- /dev/null +++ b/src/documentation/actionsDescribers.ts @@ -0,0 +1,302 @@ +import { describeRoute } from 'hono-openapi' + +const createActionRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new action', + tags: ['Actions'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string', maxLength: 255 }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string', enum: ['inactive', 'active'] }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + required: ['name', 'repeatable', 'is_resettable', 'state'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Action created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not create action', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + const getActionsRoute = describeRoute({ + method: 'GET', + path: '/actions', + description: 'Get all actions', + tags: ['Actions'], + responses: { + '200': { + description: 'Actions found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + }, + '404': { + description: 'Actions not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + const getActionByNameRoute = describeRoute({ + method: 'GET', + path: '/:name', + description: 'Get an action by name', + tags: ['Actions'], + parameters: [ + { + name: 'name', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + '200': { + description: 'Action found successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '404': { + description: 'Action not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + const updateActionRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing action', + tags: ['Actions'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string', maxLength: 255 }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string', enum: ['inactive', 'active'] }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + required: ['id'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Action updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update action', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + const deleteActionRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete an action by ID', + tags: ['Actions'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Action deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + reward_experience: { type: 'number' }, + reward_points: { type: 'number' }, + state: { type: 'string' }, + repeatable: { type: 'integer' }, + is_resettable: { type: 'boolean' } + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not delete action', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }) + + export { + createActionRoute, + getActionsRoute, + getActionByNameRoute, + updateActionRoute, + deleteActionRoute, + } + \ No newline at end of file diff --git a/src/documentation/authDescribers.ts b/src/documentation/authDescribers.ts new file mode 100644 index 0000000..91ca7bd --- /dev/null +++ b/src/documentation/authDescribers.ts @@ -0,0 +1,243 @@ +import { describeRoute } from 'hono-openapi' +import { HttpStatus } from '@/services/error.service' + +const signinRoute = describeRoute({ + method: 'POST', + path: '/signin', + description: 'Sign in the user with email and password', + tags: ['Auth'], // Tag adicionada + requestBody: { + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/AuthInput', // Referência ao schema de autenticação + }, + }, + }, + }, + responses: { + [HttpStatus.OK]: { + description: 'User signed in successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + token: { type: 'string' }, + }, + }, + }, + }, + }, + [HttpStatus.NOT_FOUND]: { + description: 'Invalid or non-existent user', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + code: { type: 'integer', example: HttpStatus.NOT_FOUND }, + message: { type: 'string', example: 'Invalid or inexistent user' }, + }, + }, + }, + }, + }, + }, +}) + +const signupRoute = describeRoute({ + method: 'POST', + path: '/signup', + description: 'Sign up a new user and create corresponding user stats', + tags: ['Auth'], // Tag adicionada + requestBody: { + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/UserInput', // Referência ao schema de entrada do usuário + }, + }, + }, + }, + responses: { + [HttpStatus.OK]: { + description: 'User signed up successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + user: { + $ref: '#/components/schemas/UserDto', // Referência ao schema de usuário + }, + userStats: { + $ref: '#/components/schemas/UserStatsDto', // Referência ao schema de estatísticas do usuário + }, + }, + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Error while creating user', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not create' }, + }, + }, + }, + }, + }, + }, +}) + +const requestPasswordResetRoute = describeRoute({ + method: 'POST', + path: '/request/:email', + description: 'Request password reset for the given email', + tags: ['Auth'], // Tag adicionada + parameters: [ + { + name: 'email', + in: 'path', + required: true, + schema: { type: 'string', format: 'email' }, + }, + ], + responses: { + [HttpStatus.OK]: { + description: 'Password reset ticket created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'string' }, + tokenHash: { type: 'string' }, + createdAt: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Could not send password recovery email', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not send recovery password email' }, + }, + }, + }, + }, + }, + }, +}) + +const resetPasswordRoute = describeRoute({ + method: 'POST', + path: '/reset', + description: 'Reset the password using the provided email, token, and new password', + tags: ['Auth'], // Tag adicionada + parameters: [ + { + name: 'email', + in: 'query', + required: true, + schema: { type: 'string', format: 'email' }, + }, + { + name: 'token', + in: 'query', + required: true, + schema: { type: 'string' }, + }, + { + name: 'password', + in: 'query', + required: true, + schema: { type: 'string', minLength: 8 }, + }, + ], + responses: { + [HttpStatus.OK]: { + description: 'Password reset successfully', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/UserDto', // Referência ao schema de usuário + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Could not reset password', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not send recovery password email' }, + }, + }, + }, + }, + }, + }, +}) + +const confirmEmailRoute = describeRoute({ + method: 'GET', + path: '/confirm-email', + description: 'Confirma o e-mail de um usuário com base no parâmetro de query', + tags: ['Auth'], + parameters: [ + { + name: 'email', + in: 'query', + required: true, + schema: { type: 'string', format: 'email' }, + }, + ], + responses: { + 302: { + description: 'Usuário encontrado e e-mail confirmado com sucesso. Redireciona para mecred.mec.gov.br', + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Não foi possível verificar o e-mail', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'Impossible to verify email' }, + code: { type: 'number', example: 400 }, + path: { type: 'string', example: '/confirm-email' }, + suggestion: { type: 'string', example: 'Check the input and try again' }, + }, + }, + }, + }, + }, + }, +}); + + +export { + signinRoute, + signupRoute, + requestPasswordResetRoute, + resetPasswordRoute, + confirmEmailRoute +} diff --git a/src/documentation/collectionLikesDescribers.ts b/src/documentation/collectionLikesDescribers.ts new file mode 100644 index 0000000..1364ee7 --- /dev/null +++ b/src/documentation/collectionLikesDescribers.ts @@ -0,0 +1,334 @@ +import { describeRoute } from 'hono-openapi' + +const associateRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate likes to a collection for multiple users', + tags: ['Collection Likes'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + collectionId: { type: 'integer' }, + userIds: { type: 'array', items: { type: 'integer' } } + }, + required: ['collectionId', 'userIds'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Likes associated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not associate likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const removeLikesRoute = describeRoute({ + method: 'POST', + path: '/:collectionId/delete/:userId', + description: 'Remove likes from a collection for a user', + tags: ['Collection Likes'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + { + name: 'userId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Likes removed successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not remove likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const updateLikesRoute = describeRoute({ + method: 'POST', + path: '/update/likes', + description: 'Update likes for a collection for multiple users', + tags: ['Collection Likes'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + collectionId: { type: 'integer' }, + userIds: { type: 'array', items: { type: 'integer' } } + }, + required: ['collectionId', 'userIds'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Likes updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const getLikesByCollectionRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/likes', + description: 'Get all likes for a specific collection', + tags: ['Collection Likes'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Likes fetched successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'integer', + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not fetch likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const checkLikeExistsRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/likes/:userId/exists', + description: 'Check if a like exists for a specific collection and user', + tags: ['Collection Likes'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + { + name: 'userId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Like exists check completed successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not check if like exists', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +const getCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/user/:userId/collections', + description: 'Get all collections for a specific user', + tags: ['Collection Likes'], + parameters: [ + { + name: 'userId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collections fetched successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + likesCount: { type: 'integer' }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not fetch collections', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + associateRoute, + removeLikesRoute, + updateLikesRoute, + getLikesByCollectionRoute, + checkLikeExistsRoute, + getCollectionsByUserRoute, +} diff --git a/src/documentation/collectionResourcesDescribers.ts b/src/documentation/collectionResourcesDescribers.ts new file mode 100644 index 0000000..fa01b50 --- /dev/null +++ b/src/documentation/collectionResourcesDescribers.ts @@ -0,0 +1,280 @@ +import { describeRoute } from 'hono-openapi' + +// Descrição para a rota POST /associate +const associateRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate resources with a collection', + tags: ['Collection Resources'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + collectionId: { type: 'integer' }, + resourceIds: { + type: 'array', + items: { type: 'integer' }, + }, + }, + required: ['collectionId', 'resourceIds'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Resources associated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to associate resources', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição para a rota POST /:collectionId/delete/:resourceId +const deleteResourceRoute = describeRoute({ + method: 'POST', + path: '/:collectionId/delete/:resourceId', + description: 'Remove resources from a collection', + tags: ['Collection Resources'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + '200': { + description: 'Resource removed successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to remove resource', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição para a rota GET /:collectionId/resources +const getResourcesRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/resources', + description: 'Get all resources of a collection', + tags: ['Collection Resources'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + '200': { + description: 'Resources fetched successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'integer' }, + resourceName: { type: 'string' }, + // Add other properties based on the resource object + }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to fetch resources', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição para a rota GET /:collectionId/resources/:resourceId/exists +const checkResourceExistsRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/resources/:resourceId/exists', + description: 'Check if a resource is associated with a collection', + tags: ['Collection Resources'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + '200': { + description: 'Resource association exists or not', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to check resource association', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Descrição para a rota GET /resource/:resourceId/collections +const getCollectionsForResourceRoute = describeRoute({ + method: 'GET', + path: '/resource/:resourceId/collections', + description: 'Get collections associated with a resource', + tags: ['Collection Resources'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + '200': { + description: 'Collections fetched successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + collectionId: { type: 'integer' }, + collectionName: { type: 'string' }, + // Add other properties based on the collection object + }, + }, + }, + }, + }, + }, + '400': { + description: 'Failed to fetch collections', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + associateRoute, + deleteResourceRoute, + getResourcesRoute, + checkResourceExistsRoute, + getCollectionsForResourceRoute, +} diff --git a/src/documentation/collectionStatsDescribers.ts b/src/documentation/collectionStatsDescribers.ts new file mode 100644 index 0000000..4bd3f31 --- /dev/null +++ b/src/documentation/collectionStatsDescribers.ts @@ -0,0 +1,439 @@ +import { describeRoute } from 'hono-openapi'; + +const createRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create new collection stats', + tags: ['CollectionStats'], + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' } + }, + required: ['views', 'downloads', 'likes', 'shares', 'score', 'followers'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Collection stats created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not create collection stats', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateViewsRoute = describeRoute({ + method: 'POST', + path: '/update-views/:id', + description: 'Update views of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats views updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update views', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateDownloadsRoute = describeRoute({ + method: 'POST', + path: '/update-downloads/:id', + description: 'Update downloads of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats downloads updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update downloads', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateLikesRoute = describeRoute({ + method: 'POST', + path: '/update-likes/:id', + description: 'Update likes of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats likes updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update likes', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateSharesRoute = describeRoute({ + method: 'POST', + path: '/update-shares/:id', + description: 'Update shares of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats shares updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update shares', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateScoreRoute = describeRoute({ + method: 'POST', + path: '/update-score/:id', + description: 'Update score of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats score updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update score', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const updateFollowersRoute = describeRoute({ + method: 'POST', + path: '/update-followers/:id', + description: 'Update followers of collection stats by ID', + tags: ['CollectionStats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection stats followers updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + views: { type: 'integer' }, + downloads: { type: 'integer' }, + likes: { type: 'integer' }, + shares: { type: 'integer' }, + score: { type: 'number' }, + followers: { type: 'integer' }, + }, + }, + }, + }, + }, + '400': { + description: 'Bad request. Could not update followers', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const deleteCollectionStatsRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Deletes collection stats by ID.', + tags: ['CollectionStats'], + params: { + id: 'The ID of the collection stats to delete.', + }, + responses: { + 200: { + description: 'Successfully deleted collection stats.', + content: { collectionStats: 'The deleted collection stats data.' }, + }, + 400: { + description: 'Failed to delete collection stats.', + content: { status: 'error', message: 'could not delete collection stats', code: 400 }, + }, + }, +}) + + const getCollectionStatsRoute = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Retrieves collection stats by ID.', + tags: ['CollectionStats'], + params: { + id: 'The ID of the collection stats to retrieve.', + }, + responses: { + 200: { + description: 'Successfully retrieved collection stats.', + content: { collectionStats: 'The retrieved collection stats data.' }, + }, + 404: { + description: 'Collection stats not found.', + content: { status: 'error', message: 'could not find collection stats', code: 404 }, + }, + }, +}) + +export { + createRoute, + updateViewsRoute, + updateDownloadsRoute, + updateLikesRoute, + updateSharesRoute, + updateScoreRoute, + updateFollowersRoute, + deleteCollectionStatsRoute, + getCollectionStatsRoute +} diff --git a/src/documentation/collectionsDescribers.ts b/src/documentation/collectionsDescribers.ts new file mode 100644 index 0000000..a64775f --- /dev/null +++ b/src/documentation/collectionsDescribers.ts @@ -0,0 +1,622 @@ +import { describeRoute } from 'hono-openapi' +const createCollectionRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Creates a new collection, which includes generating associated statistics.', + tags: ['Collections'], + request: { + body: { + collection_stats_id: { + type: 'number', + description: 'The ID of the collection statistics associated with this collection.', + example: 1 + }, + name: { + type: 'string', + description: 'The name of the collection being created.', + example: 'Art Collection' + }, + description: { + type: 'string', + description: 'A brief description of the collection.', + example: 'A collection of abstract art pieces.' + }, + created_by: { + type: 'string', + description: 'The user ID or name who is creating the collection.', + example: 'user123' + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the newly created collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The name of the newly created collection.', + example: 'Art Collection' + }, + description: { + type: 'string', + description: 'The description of the newly created collection.', + example: 'A collection of abstract art pieces.' + }, + created_at: { + type: 'string', + description: 'The date and time when the collection was created.', + example: '2025-03-26T12:34:56Z' + }, + updated_at: { + type: 'string', + description: 'The date and time when the collection was last updated.', + example: '2025-03-26T12:34:56Z' + } + }, + collectionStats: { + id: { + type: 'number', + description: 'The ID of the collection statistics.', + example: 1 + }, + created_at: { + type: 'string', + description: 'The date and time when the statistics were generated.', + example: '2025-03-26T12:30:00Z' + } + } + } + } +}); +const updateCollectionRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Updates an existing collection.', + tags: ['Collections'], + request: { + body: { + id: { + type: 'number', + description: 'The ID of the collection to update.', + example: 123 + }, + name: { + type: 'string', + description: 'The new name of the collection.', + example: 'Modern Art Collection' + }, + description: { + type: 'string', + description: 'The updated description of the collection.', + example: 'A collection of modern and contemporary art pieces.' + }, + updated_by: { + type: 'string', + description: 'The user ID or name who is updating the collection.', + example: 'user123' + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the updated collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The updated name of the collection.', + example: 'Modern Art Collection' + }, + description: { + type: 'string', + description: 'The updated description of the collection.', + example: 'A collection of modern and contemporary art pieces.' + }, + updated_at: { + type: 'string', + description: 'The date and time when the collection was last updated.', + example: '2025-03-26T14:00:00Z' + } + } + } + } +}); + +const deleteCollectionRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Deletes a collection by ID.', + tags: ['Collections'], + request: { + params: { + id: { + type: 'number', + description: 'The ID of the collection to delete.', + example: 123 + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the deleted collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The name of the deleted collection.', + example: 'Art Collection' + }, + deleted_at: { + type: 'string', + description: 'The date and time when the collection was deleted.', + example: '2025-03-26T14:30:00Z' + } + } + } + } +}); + +const deletePermanentlyCollectionRoute = describeRoute({ + method: 'POST', + path: '/delete-permanently/:id', + description: 'Permanently deletes a collection by ID.', + tags: ['Collections'], + request: { + params: { + id: { + type: 'number', + description: 'The ID of the collection to permanently delete.', + example: 123 + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the permanently deleted collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The name of the permanently deleted collection.', + example: 'Art Collection' + }, + permanently_deleted_at: { + type: 'string', + description: 'The date and time when the collection was permanently deleted.', + example: '2025-03-26T14:45:00Z' + } + } + } + } +}); + +const restoreCollectionRoute = describeRoute({ + method: 'POST', + path: '/restore/:id', + description: 'Restores a deleted collection by ID.', + tags: ['Collections'], + request: { + params: { + id: { + type: 'number', + description: 'The ID of the collection to restore.', + example: 123 + } + } + }, + response: { + status: 200, + body: { + collection: { + id: { + type: 'number', + description: 'The ID of the restored collection.', + example: 123 + }, + name: { + type: 'string', + description: 'The name of the restored collection.', + example: 'Art Collection' + }, + restored_at: { + type: 'string', + description: 'The date and time when the collection was restored.', + example: '2025-03-26T15:00:00Z' + } + } + } + } +}); + + +const getAllCollectionsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get all collections', + tags: ['Collections'], + responses: { + '200': { + description: 'Collections found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter uma coleção específica por ID +const getCollectionRoute = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Get a specific collection by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Collection found successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + '404': { + description: 'Collection not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter coleções ativas de um usuário +const getActiveCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/getActiveCollectionsByUsers/:id_user', + description: 'Get active collections for a user by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Active collections found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Active collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter todas as coleções de um usuário +const getAllCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/getAllCollectionsByUsers/:id_user', + description: 'Get all collections for a user by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'All collections found for the user', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter coleções públicas de um usuário +const getPublicCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/getPublicCollectionsByUser/:id_user', + description: 'Get public collections for a user by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Public collections found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Public collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para obter coleções privadas de um usuário +const getPrivateCollectionsByUserRoute = describeRoute({ + method: 'GET', + path: '/getPrivateCollectionsByUser/:id_user', + description: 'Get private collections for a user by ID', + tags: ['Collections'], + parameters: [ + { + name: 'id_user', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Private collections found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Private collections not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +// Rota para download dos recursos de uma coleção +const downloadCollectionRoute = describeRoute({ + method: 'GET', + path: '/:collectionId/download', + description: 'Download resources from a collection as a ZIP file', + tags: ['Collections'], + parameters: [ + { + name: 'collectionId', + in: 'path', + required: true, + schema: { + type: 'integer', + }, + }, + ], + responses: { + '200': { + description: 'Resources downloaded successfully', + content: { + 'application/zip': { + schema: { + type: 'string', + format: 'binary', + }, + }, + }, + }, + '404': { + description: 'No resources found for the collection', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}) + +export { + createCollectionRoute, + updateCollectionRoute, + deleteCollectionRoute, + deletePermanentlyCollectionRoute, + restoreCollectionRoute, + getAllCollectionsRoute, + getCollectionRoute, + getActiveCollectionsByUserRoute, + getAllCollectionsByUserRoute, + getPublicCollectionsByUserRoute, + getPrivateCollectionsByUserRoute, + downloadCollectionRoute, +} diff --git a/src/documentation/comment-replyDescribers.ts b/src/documentation/comment-replyDescribers.ts new file mode 100644 index 0000000..e0ce3c8 --- /dev/null +++ b/src/documentation/comment-replyDescribers.ts @@ -0,0 +1,390 @@ +import { describeRoute } from 'hono-openapi'; + +// POST /create +const createCommentReplyRouteDescription = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new reply for a comment.', + tags: ['Comment-Reply'], + requestBody: { + description: 'JSON object representing the reply to a comment.', + required: true, + schema: { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user posting the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment being replied to' }, + content: { type: 'string', description: 'Content of the reply' } + }, + required: ['user_id', 'comment_id', 'content'] + } + }, + responses: { + 200: { + description: 'Reply comment created successfully.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply comment' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment' }, + content: { type: 'string', description: 'Content of the reply' }, + created_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was created' }, + updated_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was last updated' } + } + } + } + } + }, + 400: { + description: 'Error in creating the reply comment, invalid input.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error', description: 'Status of the operation' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400, description: 'HTTP status code' }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// POST /update +const updateCommentReplyRouteDescription = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing reply to a comment.', + tags: ['Comment-Reply'], + requestBody: { + description: 'JSON object representing the updated reply to a comment.', + required: true, + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply to be updated' }, + user_id: { type: 'integer', description: 'ID of the user posting the updated reply' }, + content: { type: 'string', description: 'Updated content of the reply' } + }, + required: ['id', 'user_id', 'content'] + } + }, + responses: { + 200: { + description: 'Reply comment updated successfully.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the updated reply comment' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + content: { type: 'string', description: 'Updated content of the reply' }, + updated_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was last updated' } + } + } + } + } + }, + 400: { + description: 'Error in updating the reply comment, invalid input.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error', description: 'Status of the operation' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400, description: 'HTTP status code' }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// POST /deleteData/:id +const deleteDataCommentReplyRouteDescription = describeRoute({ + method: 'POST', + path: '/deleteData/:id', + description: 'Delete a reply comment based on its ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the reply to delete', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'Reply comment deleted successfully.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the deleted reply comment' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + content: { type: 'string', description: 'Content of the reply' }, + deleted_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was deleted' } + } + } + } + } + }, + 400: { + description: 'Error in deleting the reply comment, invalid ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error', description: 'Status of the operation' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400, description: 'HTTP status code' }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// POST /delete/:id +const deleteCommentReplyRouteDescription = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete a reply comment based on its ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the reply to delete', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'Reply comment deleted successfully.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the deleted reply comment' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + content: { type: 'string', description: 'Content of the reply' }, + deleted_at: { type: 'string', format: 'date-time', description: 'Date and time the reply was deleted' } + } + } + } + } + }, + 400: { + description: 'Error in deleting the reply comment, invalid ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error', description: 'Status of the operation' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400, description: 'HTTP status code' }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +const findReplyByCommentRouteDescription = describeRoute({ + method: 'GET', + path: '/findReplyByComment/:comment_id', + description: 'Get active reply for a specific comment by comment ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'comment_id', + in: 'path', + description: 'ID of the comment to find active replies for', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'Active reply found for the comment.', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment' }, + content: { type: 'string', description: 'Content of the reply' }, + created_at: { type: 'string', format: 'date-time', description: 'Date the reply was created' } + } + } + } + } + } + }, + 400: { + description: 'Error finding active reply, invalid comment ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400 }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// GET /findAllReplyByComment/:comment_id +const findAllReplyByCommentRouteDescription = describeRoute({ + method: 'GET', + path: '/findAllReplyByComment/:comment_id', + description: 'Get all replies for a specific comment by comment ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'comment_id', + in: 'path', + description: 'ID of the comment to find all replies for', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'All replies found for the comment.', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment' }, + content: { type: 'string', description: 'Content of the reply' }, + created_at: { type: 'string', format: 'date-time', description: 'Date the reply was created' } + } + } + } + } + } + }, + 400: { + description: 'Error finding replies, invalid comment ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400 }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +// GET /findAllReplyByUser/:id_user +const findAllReplyByUserRouteDescription = describeRoute({ + method: 'GET', + path: '/findAllReplyByUser/:id_user', + description: 'Get all replies by a specific user based on user ID.', + tags: ['Comment-Reply'], + parameters: [ + { + name: 'id_user', + in: 'path', + description: 'ID of the user to find all replies for', + required: true, + schema: { type: 'integer' } + } + ], + responses: { + 200: { + description: 'All replies found for the user.', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer', description: 'ID of the reply' }, + user_id: { type: 'integer', description: 'ID of the user who posted the reply' }, + comment_id: { type: 'integer', description: 'ID of the comment' }, + content: { type: 'string', description: 'Content of the reply' }, + created_at: { type: 'string', format: 'date-time', description: 'Date the reply was created' } + } + } + } + } + } + }, + 400: { + description: 'Error finding replies, invalid user ID.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', description: 'Error message' }, + code: { type: 'integer', example: 400 }, + suggestion: { type: 'string', description: 'Suggested action to resolve the issue' } + } + } + } + } + } + } +}); + +export +{ + createCommentReplyRouteDescription, + updateCommentReplyRouteDescription, + deleteDataCommentReplyRouteDescription, + deleteCommentReplyRouteDescription, + findReplyByCommentRouteDescription, + findAllReplyByCommentRouteDescription, + findAllReplyByUserRouteDescription +} \ No newline at end of file diff --git a/src/documentation/commentsDescribers.ts b/src/documentation/commentsDescribers.ts new file mode 100644 index 0000000..1215d6d --- /dev/null +++ b/src/documentation/commentsDescribers.ts @@ -0,0 +1,427 @@ +import { describeRoute } from 'hono-openapi' + +const createCommentRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Cria um novo comentário e atualiza estatísticas de usuário e recurso', + tags: ['Comments'], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { $ref: '#/components/schemas/CommentInput' }, + }, + }, + }, + responses: { + 200: { + description: 'Comentário criado com sucesso', + content: { + 'application/json': { + schema: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + 400: { + description: 'Erro ao criar o comentário', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not create the comment' }, + suggestion: { type: 'string', example: 'check the json input and try again' }, + }, + }, + }, + }, + }, + }, +}); + +const updateCommentRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Atualiza um comentário existente com os novos dados fornecidos', + tags: ['Comments'], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { $ref: '#/components/schemas/CommentUpdate' }, + }, + }, + }, + responses: { + 200: { + description: 'Comentário atualizado com sucesso', + content: { + 'application/json': { + schema: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + 400: { + description: 'Erro ao atualizar o comentário', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not update the comment' }, + suggestion: { type: 'string', example: 'check the json update and try again' }, + }, + }, + }, + }, + }, + }, +}); + +const deleteCommentDataRoute = describeRoute({ + method: 'POST', + path: '/deleteData/{id}', + description: 'Deleta um comentário e seus dados relacionados pelo ID', + tags: ['Comments'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'integer' }, + description: 'ID do comentário', + }, + ], + responses: { + 200: { + description: 'Comentário deletado com sucesso', + content: { + 'application/json': { + schema: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + 400: { + description: 'Erro ao deletar o comentário', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not delete the comment' }, + suggestion: { type: 'string', example: 'check the id and try again' }, + }, + }, + }, + }, + }, + }, +}); + +const deleteCommentRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Deleta um comentário pelo ID', + tags: ['Comments'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'integer' }, + description: 'ID do comentário', + }, + ], + responses: { + 200: { + description: 'Comentário deletado com sucesso', + content: { + 'application/json': { + schema: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + 400: { + description: 'Erro ao deletar o comentário', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not delete the comment' }, + suggestion: { type: 'string', example: 'check the id and try again' }, + }, + }, + }, + }, + }, + }, +}); + + +const listAllCommentsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Lista todos os comentários disponíveis no sistema', + tags: ['Comments'], + responses: { + 200: { + description: 'Lista de comentários retornada com sucesso', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + comment: { + type: 'array', + items: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Nenhum comentário encontrado', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not find any comment' }, + suggestion: { type: 'string', example: 'are you sure there are comments?' }, + }, + }, + }, + }, + }, + }, +}); + +const getCommentByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Busca um comentário específico pelo seu ID', + tags: ['Comments'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Comentário retornado com sucesso', + content: { + 'application/json': { + schema: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + 400: { + description: 'Comentário não encontrado ou erro na busca', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not find the comment' }, + suggestion: { type: 'string', example: 'are you sure the comment exists?' }, + }, + }, + }, + }, + }, + }, +}); +const findCommentsByResourceRoute = describeRoute({ + method: 'GET', + path: '/findCommentsByResource/{resource_id}', + description: 'Busca comentários de um recurso específico', + tags: ['Comments'], + parameters: [ + { + name: 'resource_id', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Comentários encontrados', + content: { + 'application/json': { + schema: { + type: 'array', + items: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + }, + 400: { + description: 'Erro ao buscar comentários por recurso', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); +const findAllCommentsByResourceRoute = describeRoute({ + method: 'GET', + path: '/findAllCommentsByResource/{resource_id}', + description: 'Busca todos os comentários (inclusive inativos) de um recurso', + tags: ['Comments'], + parameters: [ + { + name: 'resource_id', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Todos os comentários retornados com sucesso', + content: { + 'application/json': { + schema: { + type: 'array', + items: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + }, + 400: { + description: 'Erro ao buscar os comentários do recurso', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); +const findCommentsByUserRoute = describeRoute({ + method: 'GET', + path: '/findCommentsByUser/{user_id}', + description: 'Busca comentários feitos por um usuário específico', + tags: ['Comments'], + parameters: [ + { + name: 'user_id', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Comentários do usuário retornados com sucesso', + content: { + 'application/json': { + schema: { + type: 'array', + items: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + }, + 400: { + description: 'Erro ao buscar comentários por usuário', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +const findAllCommentsByUserRoute = describeRoute({ + method: 'GET', + path: '/findAllCommentsByUser/{user_id}', + description: 'Busca todos os comentários (inclusive inativos) feitos por um usuário', + tags: ['Comments'], + parameters: [ + { + name: 'user_id', + in: 'path', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Todos os comentários do usuário retornados', + content: { + 'application/json': { + schema: { + type: 'array', + items: { $ref: '#/components/schemas/CommentDto' }, + }, + }, + }, + }, + 400: { + description: 'Erro ao buscar os comentários do usuário', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, +}); + +export +{ + createCommentRoute, + updateCommentRoute, + deleteCommentDataRoute, + deleteCommentRoute, + listAllCommentsRoute, + getCommentByIdRoute, + findCommentsByResourceRoute, + findAllCommentsByResourceRoute, + findCommentsByUserRoute, + findAllCommentsByUserRoute +} \ No newline at end of file diff --git a/src/documentation/compliantDescribers.ts b/src/documentation/compliantDescribers.ts new file mode 100644 index 0000000..1104989 --- /dev/null +++ b/src/documentation/compliantDescribers.ts @@ -0,0 +1,371 @@ +import { describeRoute } from 'hono-openapi' + + + const createComplaintRouteDescription = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new complaint', + tags: ['Complaints'], + requestBody: { + description: 'Complaint input data', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + user_id: { type: 'integer' }, + complaint_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + required: ['user_id', 'complaint_text'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Complaint created successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + complaint_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error creating complaint', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to update a complaint + const updateComplaintRouteDescription = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing complaint', + tags: ['Complaints'], + requestBody: { + description: 'Complaint update data', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + complaint_text: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + required: ['id', 'complaint_text'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Complaint updated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + complaint_text: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error updating complaint', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to evaluate a complaint + const evaluateComplaintRouteDescription = describeRoute({ + method: 'POST', + path: '/evaluate', + description: 'Evaluate an existing complaint', + tags: ['Complaints'], + requestBody: { + description: 'Complaint evaluation data', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + id: { type: 'integer' }, + status: { type: 'string', enum: ['pending', 'resolved', 'dismissed'] }, + evaluation_comments: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + required: ['id', 'status'], + }, + }, + }, + }, + responses: { + '200': { + description: 'Complaint evaluated successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + status: { type: 'string' }, + evaluation_comments: { type: 'string' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error evaluating complaint', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to delete a complaint + const deleteComplaintRouteDescription = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete a complaint by ID', + tags: ['Complaints'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the complaint to delete', + }, + }, + ], + responses: { + '200': { + description: 'Complaint deleted successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + complaint_text: { type: 'string' }, + deleted_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '400': { + description: 'Error deleting complaint', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to get a complaint by ID + const getComplaintByIdRouteDescription = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Get a complaint by ID', + tags: ['Complaints'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'integer', + description: 'ID of the complaint to retrieve', + }, + }, + ], + responses: { + '200': { + description: 'Complaint found successfully', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + complaint: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + complaint_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'Complaint not found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + // Route to get all complaints +const getAllComplaintsRouteDescription = describeRoute({ + method: 'GET', + path: '/', + description: 'Get all complaints', + tags: ['Complaints'], + responses: { + '200': { + description: 'Complaints found successfully', + content: { + 'application/json': { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + user_id: { type: 'integer' }, + complaint_text: { type: 'string' }, + created_at: { type: 'string', format: 'date-time' }, + updated_at: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + }, + '404': { + description: 'No complaints found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + +export +{ + createComplaintRouteDescription, + updateComplaintRouteDescription, + evaluateComplaintRouteDescription, + deleteComplaintRouteDescription, + getComplaintByIdRouteDescription, + getAllComplaintsRouteDescription +} \ No newline at end of file diff --git a/src/documentation/contactDescriber.ts b/src/documentation/contactDescriber.ts new file mode 100644 index 0000000..f7fb98b --- /dev/null +++ b/src/documentation/contactDescriber.ts @@ -0,0 +1,57 @@ +import { describeRoute } from 'hono-openapi' +import { HttpStatus } from '@/services/error.service' + +export const contactRouteDescriber = describeRoute({ + method: 'POST', + path: '/contact', + description: 'Envia uma mensagem de contato com nome, e-mail e mensagem', + tags: ['Public', 'Contact'], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { + type: 'object', + required: ['name', 'email', 'message'], + properties: { + name: { type: 'string', minLength: 1, example: 'João Silva' }, + email: { type: 'string', format: 'email', example: 'joao@email.com' }, + message: { type: 'string', minLength: 10, example: 'Gostaria de saber mais sobre seus serviços.' }, + }, + }, + }, + }, + }, + responses: { + [HttpStatus.OK]: { + description: 'Mensagem de contato enviada com sucesso', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'success' }, + name: { type: 'string', example: 'João Silva' }, + email: { type: 'string', format: 'email', example: 'joao@email.com' }, + message: { type: 'string', example: 'Gostaria de saber mais sobre seus serviços.' }, + }, + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Dados inválidos no corpo da requisição', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + error: { type: 'string', example: 'Invalid request data' }, + }, + }, + }, + }, + }, + }, + }); + \ No newline at end of file diff --git a/src/documentation/homologationDescribers.ts b/src/documentation/homologationDescribers.ts new file mode 100644 index 0000000..f02baad --- /dev/null +++ b/src/documentation/homologationDescribers.ts @@ -0,0 +1,99 @@ +import { describeRoute } from 'hono-openapi' +import { HttpStatus } from '@/services/error.service' + +const getAllHomologationRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Retorna recursos submetidos para homologação que não pertencem ao usuário atual, se ele tiver permissão', + tags: ['Homologation'], + responses: { + [HttpStatus.OK]: { + description: 'Lista de recursos disponíveis para homologação', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + resource: { + type: 'array', + items: { $ref: '#/components/schemas/HomologationResource' }, + }, + }, + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Erro ao buscar recursos submetidos', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not get resource submitted' }, + code: { type: 'number', example: 400 }, + path: { type: 'string', example: '/all' }, + suggestion: { type: 'string', example: 'check the code and try again or you can´t be here' }, + }, + }, + }, + }, + }, + }, + }); + + + const createHomologationRoute = describeRoute({ + method: 'POST', + path: '/new', + description: 'Cria uma nova submissão de homologação com base na entrada validada', + tags: ['Homologation'], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { $ref: '#/components/schemas/SubmissionUpdateSchema' }, + }, + }, + }, + responses: { + [HttpStatus.OK]: { + description: 'Submissão processada com sucesso', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string', example: 'Homologação feita com sucesso!' }, + data: { $ref: '#/components/schemas/SubmissionDto' }, + }, + }, + }, + }, + }, + [HttpStatus.BAD_REQUEST]: { + description: 'Erro ao processar a submissão', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'could not answer submission' }, + code: { type: 'number', example: 400 }, + path: { type: 'string', example: '/new' }, + suggestion: { type: 'string', example: 'check the input and try again' }, + }, + }, + }, + }, + }, + }, + }); + + +export { + getAllHomologationRoute, + createHomologationRoute +} \ No newline at end of file diff --git a/src/documentation/institutionDescribers.ts b/src/documentation/institutionDescribers.ts new file mode 100644 index 0000000..e8221a0 --- /dev/null +++ b/src/documentation/institutionDescribers.ts @@ -0,0 +1,375 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createInstitutionRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new institution.', + tags: ['Institution'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + required: ['name', 'uf', 'city', 'cep', 'address'], + }, + }, + }, + responses: { + 200: { + description: 'Institution created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /institutions + const getInstitutionsRoute = describeRoute({ + method: 'GET', + path: '/institutions', + description: 'Get a list of all institutions.', + tags: ['Institution'], + responses: { + 200: { + description: 'List of institutions.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. No institutions found.', + }, + }, +}); + +// Descrição da rota /name/:name + const getInstitutionByNameRoute = describeRoute({ + method: 'GET', + path: '/name/{name}', + description: 'Get institution by name.', + tags: ['Institution'], + parameters: [ + { + name: 'name', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'Institution found by name.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given name does not exist.', + }, + }, +}); + +// Descrição da rota /uf/:uf + const getInstitutionByUfRoute = describeRoute({ + method: 'GET', + path: '/uf/{uf}', + description: 'Get institution by UF (state).', + tags: ['Institution'], + parameters: [ + { + name: 'uf', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'Institution found by UF.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given UF does not exist.', + }, + }, +}); + +// Descrição da rota /city/:city + const getInstitutionByCityRoute = describeRoute({ + method: 'GET', + path: '/city/{city}', + description: 'Get institution by city.', + tags: ['Institution'], + parameters: [ + { + name: 'city', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'Institution found by city.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given city does not exist.', + }, + }, +}); + +// Descrição da rota /cep/:cep + const getInstitutionByCepRoute = describeRoute({ + method: 'GET', + path: '/cep/{cep}', + description: 'Get institution by CEP.', + tags: ['Institution'], + parameters: [ + { + name: 'cep', + in: 'path', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'Institution found by CEP.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given CEP does not exist.', + }, + }, +}); + +// Descrição da rota /update + const updateInstitutionRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing institution.', + tags: ['Institution'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + required: ['id', 'name', 'uf', 'city', 'cep', 'address'], + }, + }, + }, + responses: { + 200: { + description: 'Institution updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + institution: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteInstitutionRoute = describeRoute({ + method: 'DELETE', + path: '/delete/{id}', + description: 'Delete an institution by ID.', + tags: ['Institution'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Institution deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + uf: { type: 'string' }, + city: { type: 'string' }, + cep: { type: 'string' }, + address: { type: 'string' }, + }, + }, + }, + }, + 404: { + description: 'Not found. Institution with the given ID does not exist.', + }, + }, +}); + +export{ + createInstitutionRoute, + getInstitutionsRoute, + getInstitutionByNameRoute, + getInstitutionByUfRoute, + getInstitutionByCityRoute, + getInstitutionByCepRoute, + updateInstitutionRoute, + deleteInstitutionRoute +} \ No newline at end of file diff --git a/src/documentation/languageDescriber.ts b/src/documentation/languageDescriber.ts new file mode 100644 index 0000000..c4b90b7 --- /dev/null +++ b/src/documentation/languageDescriber.ts @@ -0,0 +1,268 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createLanguageRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new language.', + tags: ['Language'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + code: { type: 'string' }, + }, + required: ['name', 'code'], + }, + }, + }, + responses: { + 200: { + description: 'Language created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + language: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateLanguageRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing language.', + tags: ['Language'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + required: ['id', 'name', 'code'], + }, + }, + }, + responses: { + 200: { + description: 'Language updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + language: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteLanguageRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a language by ID.', + tags: ['Language'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Language deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + language: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all (public route) + const getAllLanguagesRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all languages.', + tags: ['Language'], + responses: { + 200: { + description: 'List of languages.', + content: { + 'application/json': { + type: 'object', + properties: { + languages: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find languages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id (public route) + const getLanguageByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a language by ID.', + tags: ['Language'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Language found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + language: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + code: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find language.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createLanguageRoute, + updateLanguageRoute, + deleteLanguageRoute, + getAllLanguagesRoute, + getLanguageByIdRoute +} \ No newline at end of file diff --git a/src/documentation/licenseDescriber.ts b/src/documentation/licenseDescriber.ts new file mode 100644 index 0000000..d4087c8 --- /dev/null +++ b/src/documentation/licenseDescriber.ts @@ -0,0 +1,274 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /create + const createLicenseRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new license.', + tags: ['License'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + required: ['name', 'type', 'validity'], + }, + }, + }, + responses: { + 200: { + description: 'License created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + license: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateLicenseRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing license.', + tags: ['License'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + required: ['id', 'name', 'type', 'validity'], + }, + }, + }, + responses: { + 200: { + description: 'License updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + license: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteLicenseRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a license by ID.', + tags: ['License'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'License deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + license: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all (public route) + const getAllLicensesRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all licenses.', + tags: ['License'], + responses: { + 200: { + description: 'List of licenses.', + content: { + 'application/json': { + type: 'object', + properties: { + licenses: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find licenses.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id (public route) + const getLicenseByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a license by ID.', + tags: ['License'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'License found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + license: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + type: { type: 'string' }, + validity: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Could not find license.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createLicenseRoute, + updateLicenseRoute, + deleteLicenseRoute, + getAllLicensesRoute, + getLicenseByIdRoute +} diff --git a/src/documentation/notificationDescriber.ts b/src/documentation/notificationDescriber.ts new file mode 100644 index 0000000..7e4243b --- /dev/null +++ b/src/documentation/notificationDescriber.ts @@ -0,0 +1,524 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createNotificationRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new notification.', + tags: ['Notification'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + required: ['action_id', 'actor_user_id', 'target_user_id', 'message'], + }, + }, + }, + responses: { + 200: { + description: 'Notification created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /notifications + const getNotificationsRoute = describeRoute({ + method: 'GET', + path: '/notifications', + description: 'Get a list of all notifications.', + tags: ['Notification'], + responses: { + 200: { + description: 'List of notifications.', + content: { + 'application/json': { + type: 'object', + properties: { + notifications: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notifications not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /action/:action_id + const getNotificationByActionRoute = describeRoute({ + method: 'GET', + path: '/action/{action_id}', + description: 'Get a notification by action ID.', + tags: ['Notification'], + parameters: [ + { + name: 'action_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by action ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by action ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /actor-user/:actor_user_id + const getNotificationByActorUserRoute = describeRoute({ + method: 'GET', + path: '/actor-user/{actor_user_id}', + description: 'Get a notification by actor user ID.', + tags: ['Notification'], + parameters: [ + { + name: 'actor_user_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by actor user ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by actor user ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /target-user/:target_user_id + const getNotificationByTargetUserRoute = describeRoute({ + method: 'GET', + path: '/target-user/{target_user_id}', + description: 'Get a notification by target user ID.', + tags: ['Notification'], + parameters: [ + { + name: 'target_user_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by target user ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by target user ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /target-resource/:target_resource_id + const getNotificationByTargetResourceRoute = describeRoute({ + method: 'GET', + path: '/target-resource/{target_resource_id}', + description: 'Get a notification by target resource ID.', + tags: ['Notification'], + parameters: [ + { + name: 'target_resource_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by target resource ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by target resource ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /target-collection/:target_collection_id + const getNotificationByTargetCollectionRoute = describeRoute({ + method: 'GET', + path: '/target-collection/{target_collection_id}', + description: 'Get a notification by target collection ID.', + tags: ['Notification'], + parameters: [ + { + name: 'target_collection_id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification found by target collection ID.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 404: { + description: 'Notification not found by target collection ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateNotificationRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing notification.', + tags: ['Notification'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + required: ['id', 'action_id', 'actor_user_id', 'target_user_id', 'message'], + }, + }, + }, + responses: { + 200: { + description: 'Notification updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteNotificationRoute = describeRoute({ + method: 'DELETE', + path: '/delete/{id}', + description: 'Delete a notification by ID.', + tags: ['Notification'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Notification deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + notification: { + type: 'object', + properties: { + id: { type: 'number' }, + action_id: { type: 'number' }, + actor_user_id: { type: 'number' }, + target_user_id: { type: 'number' }, + target_resource_id: { type: 'number' }, + target_collection_id: { type: 'number' }, + message: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createNotificationRoute, + getNotificationsRoute, + getNotificationByActionRoute, + getNotificationByActorUserRoute, + getNotificationByTargetUserRoute, + getNotificationByTargetResourceRoute, + getNotificationByTargetCollectionRoute, + updateNotificationRoute, + deleteNotificationRoute +} \ No newline at end of file diff --git a/src/documentation/object-type.ts b/src/documentation/object-type.ts new file mode 100644 index 0000000..a783b33 --- /dev/null +++ b/src/documentation/object-type.ts @@ -0,0 +1,263 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createObjectTypeRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new object type.', + tags: ['Object-Type'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['name'], + }, + }, + }, + responses: { + 200: { + description: 'Object type created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + objectType: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateObjectTypeRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing object type.', + tags: ['Object-Type'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['id', 'name'], + }, + }, + }, + responses: { + 200: { + description: 'Object type updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + objectType: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid input.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteObjectTypeRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete an object type by ID.', + tags: ['Object-Type'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Object type deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + objectType: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Invalid ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all + const getAllObjectTypesRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all object types.', + tags: ['Object-Type'], + responses: { + 200: { + description: 'List of all object types.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Unable to fetch object types.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getObjectTypeByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get an object type by ID.', + tags: ['Object-Type'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { + type: 'number', + }, + }, + ], + responses: { + 200: { + description: 'Object type found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + objectType: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + }, + 400: { + description: 'Bad request. Object type not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createObjectTypeRoute, + updateObjectTypeRoute, + deleteObjectTypeRoute, + getAllObjectTypesRoute, + getObjectTypeByIdRoute +} diff --git a/src/documentation/resource-educational-stages.ts b/src/documentation/resource-educational-stages.ts new file mode 100644 index 0000000..6b386b2 --- /dev/null +++ b/src/documentation/resource-educational-stages.ts @@ -0,0 +1,303 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /associate + const associateResourceWithEducationalStagesRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate educational stages with a resource.', + tags: ['Resource-Educational-Stages'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + educationalStageIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'educationalStageIds'], + }, + }, + }, + responses: { + 200: { + description: 'Educational stages associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate educational stages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/delete/educationalStage/:educationalStageId + const removeEducationalStageFromResourceRoute = describeRoute({ + method: 'POST', + path: '/{resourceId}/delete/educationalStage/{educationalStageId}', + description: 'Remove an educational stage from a resource.', + tags: ['Resource-Educational-Stages'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'educationalStageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Educational stage removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove educational stage.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update/educationalStages + const updateResourceEducationalStagesRoute = describeRoute({ + method: 'POST', + path: '/update/educationalStages', + description: 'Update educational stages for a resource.', + tags: ['Resource-Educational-Stages'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + educationalStageIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'educationalStageIds'], + }, + }, + }, + responses: { + 200: { + description: 'Educational stages updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update educational stages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/educationalStages + const getEducationalStagesByResourceRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/educationalStages', + description: 'Get educational stages associated with a resource.', + tags: ['Resource-Educational-Stages'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of educational stages associated with the resource.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to get educational stages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/educationalStages/:educationalStageId/exists + const checkAssociationExistsRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/educationalStages/{educationalStageId}/exists', + description: 'Check if an association exists between a resource and an educational stage.', + tags: ['Resource-Educational-Stages'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'educationalStageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Association exists.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /educationalStage/:educationalStageId/resources + const getResourcesByEducationalStageRoute = describeRoute({ + method: 'GET', + path: '/educationalStage/{educationalStageId}/resources', + description: 'Get resources associated with an educational stage.', + tags: ['Resource-Educational-Stages'], + parameters: [ + { + name: 'educationalStageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources associated with the educational stage.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to get resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + associateResourceWithEducationalStagesRoute, + removeEducationalStageFromResourceRoute, + updateResourceEducationalStagesRoute, + getEducationalStagesByResourceRoute, + checkAssociationExistsRoute, + getResourcesByEducationalStageRoute +} \ No newline at end of file diff --git a/src/documentation/resource-language.ts b/src/documentation/resource-language.ts new file mode 100644 index 0000000..0fcc800 --- /dev/null +++ b/src/documentation/resource-language.ts @@ -0,0 +1,302 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /associate + const associateResourceWithLanguagesRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate a resource with multiple languages.', + tags: ['Resource-Language'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + languageIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'languageIds'], + }, + }, + }, + responses: { + 200: { + description: 'Languages associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate languages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/delete/language/:languageId + const removeLanguageFromResourceRoute = describeRoute({ + method: 'POST', + path: '/{resourceId}/delete/language/{languageId}', + description: 'Remove the association between a resource and a language.', + tags: ['Resource-Language'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'languageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Language removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove language.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update/languages + const updateResourceLanguagesRoute = describeRoute({ + method: 'POST', + path: '/update/languages', + description: 'Update the language associations for a resource.', + tags: ['Resource-Language'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + languageIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'languageIds'], + }, + }, + }, + responses: { + 200: { + description: 'Languages updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update languages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/languages + const getLanguagesByResourceRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/languages', + description: 'Get all languages associated with a resource.', + tags: ['Resource-Language'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of languages associated with the resource.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch languages.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/language/:languageId/exists + const checkLanguageAssociationExistsRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/language/{languageId}/exists', + description: 'Check if the association between a resource and a language exists.', + tags: ['Resource-Language'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'languageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'The association exists or not.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check the association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /language/:languageId/resources + const getResourcesByLanguageRoute = describeRoute({ + method: 'GET', + path: '/language/{languageId}/resources', + description: 'Get all resources associated with a language.', + tags: ['Resource-Language'], + parameters: [ + { + name: 'languageId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources associated with the language.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + associateResourceWithLanguagesRoute, + removeLanguageFromResourceRoute, + updateResourceLanguagesRoute, + getLanguagesByResourceRoute, + checkLanguageAssociationExistsRoute, + getResourcesByLanguageRoute +} \ No newline at end of file diff --git a/src/documentation/resource-likes.ts b/src/documentation/resource-likes.ts new file mode 100644 index 0000000..afbe43b --- /dev/null +++ b/src/documentation/resource-likes.ts @@ -0,0 +1,252 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /associate + const associateResourceWithLikesRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate a resource with likes from multiple users.', + tags: ['Resource-Likes'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + userIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'userIds'], + }, + }, + }, + responses: { + 200: { + description: 'Likes associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate likes.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/delete/:userId + const removeLikesFromResourceRoute = describeRoute({ + method: 'POST', + path: '/{resourceId}/delete/{userId}', + description: 'Remove likes from a resource (unlike).', + tags: ['Resource-Likes'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'userId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Likes removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove likes.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId + const getLikesByResourceRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}', + description: 'Get all likes for a specific resource.', + tags: ['Resource-Likes'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of likes for the resource.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + userId: { type: 'number' }, + likedAt: { type: 'string', format: 'date-time' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch likes.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/likes/:userId/exists + const checkLikeAssociationExistsRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/likes/{userId}/exists', + description: 'Check if a user has liked a specific resource.', + tags: ['Resource-Likes'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'userId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Whether the user has liked the resource or not.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check like association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /user/:userId/resources + const getResourcesByUserRoute = describeRoute({ + method: 'GET', + path: '/user/{userId}/resources', + description: 'Get all resources liked by a specific user.', + tags: ['Resource-Likes'], + parameters: [ + { + name: 'userId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources liked by the user.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + resourceName: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + + +export +{ + associateResourceWithLikesRoute, + removeLikesFromResourceRoute, + getLikesByResourceRoute, + checkLikeAssociationExistsRoute, + getResourcesByUserRoute +} \ No newline at end of file diff --git a/src/documentation/resource-statsDescriber.ts b/src/documentation/resource-statsDescriber.ts new file mode 100644 index 0000000..648f00f --- /dev/null +++ b/src/documentation/resource-statsDescriber.ts @@ -0,0 +1,367 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create stats for a resource.', + tags: ['Resource-Stats'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + views: { type: 'number' }, + shares: { type: 'number' }, + downloads: { type: 'number' }, + }, + required: ['resourceId', 'views', 'shares', 'downloads'], + }, + }, + }, + responses: { + 200: { + description: 'Stats created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create stats resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update stats for a resource.', + tags: ['Resource-Stats'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + views: { type: 'number' }, + shares: { type: 'number' }, + downloads: { type: 'number' }, + }, + required: ['resourceId', 'views', 'shares', 'downloads'], + }, + }, + }, + responses: { + 200: { + description: 'Stats updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update stats resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete stats for a resource.', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Stats deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete stats resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /viewUpdate/:id + const viewUpdateResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/viewUpdate/{id}', + description: 'Update the views count of a resource (increments by 1).', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Views updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update views.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /sharesUpdate/:id + const sharesUpdateResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/sharesUpdate/{id}', + description: 'Update the shares count of a resource (increments by 1).', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Shares updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update shares.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /downloadUpdate/:id + const downloadUpdateResourceStatsRoute = describeRoute({ + method: 'POST', + path: '/downloadUpdate/{id}', + description: 'Update the downloads count of a resource (increments by 1).', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Downloads updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update downloads.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all + const getAllResourceStatsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get all stats for all resources.', + tags: ['Resource-Stats'], + responses: { + 200: { + description: 'List of all stats for resources.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + views: { type: 'number' }, + shares: { type: 'number' }, + downloads: { type: 'number' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch stats resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getResourceStatsByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get stats for a specific resource.', + tags: ['Resource-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Stats for the specific resource.', + content: { + 'application/json': { + type: 'object', + properties: { + statsResource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to fetch stats for the resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createResourceStatsRoute, + updateResourceStatsRoute, + deleteResourceStatsRoute, + viewUpdateResourceStatsRoute, + sharesUpdateResourceStatsRoute, + downloadUpdateResourceStatsRoute, + getAllResourceStatsRoute, + getResourceStatsByIdRoute +} \ No newline at end of file diff --git a/src/documentation/resource-subjectsDescriber.ts b/src/documentation/resource-subjectsDescriber.ts new file mode 100644 index 0000000..9a367d9 --- /dev/null +++ b/src/documentation/resource-subjectsDescriber.ts @@ -0,0 +1,304 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /associate + const associateResourceWithSubjectsRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate subjects with a resource.', + tags: ['Resource-Subjects'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + subjectIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'subjectIds'], + }, + }, + }, + responses: { + 200: { + description: 'Subjects associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate subjects.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/delete/subject/:subjectId + const removeSubjectFromResourceRoute = describeRoute({ + method: 'POST', + path: '/{resourceId}/delete/subject/{subjectId}', + description: 'Remove a subject from a resource.', + tags: ['Resource-Subjects'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'subjectId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Subject removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update/subjects + const updateResourceSubjectsRoute = describeRoute({ + method: 'POST', + path: '/update/subjects', + description: 'Update subjects associated with a resource.', + tags: ['Resource-Subjects'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + subjectIds: { + type: 'array', + items: { type: 'number' }, + }, + }, + required: ['resourceId', 'subjectIds'], + }, + }, + }, + responses: { + 200: { + description: 'Subjects updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update subjects.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/subjects + const getSubjectsByResourceRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/subjects', + description: 'Get all subjects associated with a resource.', + tags: ['Resource-Subjects'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of subjects associated with the resource.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + subjectId: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to get subjects.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:resourceId/subject/:subjectId/exists + const checkAssociationExistsRoute = describeRoute({ + method: 'GET', + path: '/{resourceId}/subject/{subjectId}/exists', + description: 'Check if a subject is associated with a resource.', + tags: ['Resource-Subjects'], + parameters: [ + { + name: 'resourceId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + { + name: 'subjectId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Whether the association exists or not.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /subject/:subjectId/resources + const getResourcesBySubjectRoute = describeRoute({ + method: 'GET', + path: '/subject/{subjectId}/resources', + description: 'Get all resources associated with a subject.', + tags: ['Resource-Subjects'], + parameters: [ + { + name: 'subjectId', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources associated with the subject.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to get resources.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + + +export +{ + associateResourceWithSubjectsRoute, + removeSubjectFromResourceRoute, + updateResourceSubjectsRoute, + getSubjectsByResourceRoute, + checkAssociationExistsRoute, + getResourcesBySubjectRoute +} \ No newline at end of file diff --git a/src/documentation/resourceDescriber.ts b/src/documentation/resourceDescriber.ts new file mode 100644 index 0000000..978af5e --- /dev/null +++ b/src/documentation/resourceDescriber.ts @@ -0,0 +1,482 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /create + const createResourceRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new resource.', + tags: ['Resources'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['name', 'description'], + }, + }, + }, + responses: { + 200: { + description: 'Resource created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + stats: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateResourceRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing resource.', + tags: ['Resources'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['id'], + }, + }, + }, + responses: { + 200: { + description: 'Resource updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /deleteData/:id + const deleteResourceDataRoute = describeRoute({ + method: 'POST', + path: '/deleteData/{id}', + description: 'Delete resource data by its ID.', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Resource data deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete resource data.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteResourceRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a resource by its ID.', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Resource deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /active/:id + const activateResourceRoute = describeRoute({ + method: 'POST', + path: '/active/{id}', + description: 'Activate a resource by its ID.', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Resource activated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + resource: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to activate resource.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all + const getAllResourcesRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get all resources.', + tags: ['Resources'], + responses: { + 200: { + description: 'List of all resources.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + 404: { + description: 'No resources found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /allResourceByUser/:user_id + const getAllResourcesByUserRoute = describeRoute({ + method: 'GET', + path: '/allResourceByUser/{user_id}', + description: 'Get all resources by a user ID.', + tags: ['Resources'], + parameters: [ + { + name: 'user_id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of resources for the user.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to find resources by user.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /activeResourceByUser/:user_id + const getActiveResourcesByUserRoute = describeRoute({ + method: 'GET', + path: '/activeResourceByUser/{user_id}', + description: 'Get active resources by a user ID.', + tags: ['Resources'], + parameters: [ + { + name: 'user_id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'List of active resources for the user.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to find active resources by user.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getResourceByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a resource by its ID.', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Resource found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + resourceId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to find resource by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +const downloadResourceRoute = describeRoute({ + method: 'GET', + path: '/download/{id}', + description: 'Faz o download de um recurso armazenado no S3 com base no ID fornecido', + tags: ['Resources'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'integer' }, + description: 'ID do recurso a ser baixado', + }, + ], + responses: { + 200: { + description: 'Arquivo do recurso retornado com sucesso', + content: { + '*/*': { + schema: { + type: 'string', + format: 'binary', + }, + }, + }, + headers: { + 'Content-Type': { + schema: { type: 'string', example: 'application/pdf' }, + }, + 'Content-Disposition': { + schema: { type: 'string', example: 'attachment; filename="recurso.pdf"' }, + }, + }, + }, + 404: { + description: 'Recurso ou arquivo não encontrado', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string', example: 'Recurso não encontrado' }, + }, + }, + }, + }, + }, + 500: { + description: 'Erro interno ao buscar o arquivo', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { type: 'string', example: 'Erro interno ao buscar o arquivo' }, + }, + }, + }, + }, + }, + }, +}); + + +export +{ + createResourceRoute, + updateResourceRoute, + deleteResourceDataRoute, + deleteResourceRoute, + activateResourceRoute, + getAllResourcesRoute, + getAllResourcesByUserRoute, + getActiveResourcesByUserRoute, + getResourceByIdRoute, + downloadResourceRoute +} diff --git a/src/documentation/roleDescriber.ts b/src/documentation/roleDescriber.ts new file mode 100644 index 0000000..3a76308 --- /dev/null +++ b/src/documentation/roleDescriber.ts @@ -0,0 +1,233 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createRoleRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new role.', + tags: ['Role'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['name'], + }, + }, + }, + responses: { + 200: { + description: 'Role created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + role: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create role.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /roles + const getRolesRoute = describeRoute({ + method: 'GET', + path: '/roles', + description: 'Get a list of all roles.', + tags: ['Role'], + responses: { + 200: { + description: 'List of all roles.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + roleId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + 404: { + description: 'No roles found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:name + const getRoleByNameRoute = describeRoute({ + method: 'GET', + path: '/{name}', + description: 'Get a role by its name.', + tags: ['Role'], + parameters: [ + { + name: 'name', + in: 'path', + required: true, + schema: { type: 'string' }, + }, + ], + responses: { + 200: { + description: 'Role found by name.', + content: { + 'application/json': { + type: 'object', + properties: { + roleId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + 404: { + description: 'Role not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateRoleRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing role.', + tags: ['Role'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['id'], + }, + }, + }, + responses: { + 200: { + description: 'Role updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + role: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update role.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteRoleRoute = describeRoute({ + method: 'DELETE', + path: '/delete/{id}', + description: 'Delete a role by its ID.', + tags: ['Role'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Role deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + role: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete role.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createRoleRoute, + getRolesRoute, + getRoleByNameRoute, + updateRoleRoute, + deleteRoleRoute +} \ No newline at end of file diff --git a/src/documentation/s3Describers.ts b/src/documentation/s3Describers.ts new file mode 100644 index 0000000..b9ccb29 --- /dev/null +++ b/src/documentation/s3Describers.ts @@ -0,0 +1,453 @@ +import { describeRoute } from "hono-openapi"; + + +const uploadResourceRoute = describeRoute({ + method: "POST", + path: "/upload/resource/:id_resource", + tags: ["S3"], + summary: "Faz o upload de um recurso para o S3", + description: "Permite o upload de arquivos de até 5GB e os armazena no bucket S3.", + parameters: [ + { + name: "id_resource", + in: "path", + required: true, + description: "O ID do recurso que será armazenado.", + schema: { type: "string" } + } + ], + requestBody: { + required: true, + content: { + "multipart/form-data": { + schema: { + type: "object", + properties: { + file: { + type: "string", + format: "binary", + description: "Arquivo a ser enviado (máx. 5GB)" + } + } + } + } + } + }, + responses: { + 200: { + description: "Upload bem-sucedido.", + content: { "application/json": { example: { message: "Arquivo enviado com sucesso!", status: "success" } } } + }, + 400: { + description: "Erro de validação, como arquivo ausente ou excedendo limite.", + content: { "application/json": { example: { message: "O arquivo excede o limite de 5GB.", status: "error" } } } + }, + 500: { + description: "Erro interno ao enviar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao enviar o arquivo.", status: "error" } } } + } + } +}); + +// Rota para upload de thumbnail de um recurso no S3 +const uploadThumbnailResourceRoute = describeRoute({ + method: "POST", + path: "/upload/thumbnail/resource/:id_resource", + tags: ["S3"], + summary: "Faz o upload de uma thumbnail de recurso", + description: "Permite o upload de thumbnails de recursos de até 1MB.", + parameters: [ + { + name: "id_resource", + in: "path", + required: true, + description: "O ID do recurso ao qual a thumbnail pertence.", + schema: { type: "string" } + } + ], + requestBody: { + required: true, + content: { + "multipart/form-data": { + schema: { + type: "object", + properties: { + file: { + type: "string", + format: "binary", + description: "Thumbnail a ser enviada (máx. 1MB)" + } + } + } + } + } + }, + responses: { + 200: { + description: "Upload bem-sucedido.", + content: { "application/json": { example: { message: "Arquivo enviado com sucesso!", status: "success" } } } + }, + 400: { + description: "Erro de validação, como arquivo ausente ou excedendo limite.", + content: { "application/json": { example: { message: "A thumbnail do recurso excede o limite de 1MB.", status: "error" } } } + }, + 500: { + description: "Erro interno ao enviar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao enviar o arquivo.", status: "error" } } } + } + } +}); + +// Rota para upload de thumbnail de uma coleção no S3 +const uploadThumbnailCollectionRoute = describeRoute({ + method: "POST", + path: "/upload/thumbnail/collection/:id_collection", + tags: ["S3"], + summary: "Faz o upload de uma thumbnail de coleção", + description: "Permite o upload de thumbnails de coleções de até 1MB.", + parameters: [ + { + name: "id_collection", + in: "path", + required: true, + description: "O ID da coleção à qual a thumbnail pertence.", + schema: { type: "string" } + } + ], + requestBody: { + required: true, + content: { + "multipart/form-data": { + schema: { + type: "object", + properties: { + file: { + type: "string", + format: "binary", + description: "Thumbnail a ser enviada (máx. 1MB)" + } + } + } + } + } + }, + responses: { + 200: { + description: "Upload bem-sucedido.", + content: { "application/json": { example: { message: "Arquivo enviado com sucesso!", status: "success" } } } + }, + 400: { + description: "Erro de validação, como arquivo ausente ou excedendo limite.", + content: { "application/json": { example: { message: "A thumbnail da coleção excede o limite de 1MB.", status: "error" } } } + }, + 500: { + description: "Erro interno ao enviar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao enviar o arquivo.", status: "error" } } } + } + } +}); + +// Rota para upload de avatar no S3 +const uploadAvatarRoute = describeRoute({ + method: "POST", + path: "/upload/avatar/:id_avatar", + tags: ["S3"], + summary: "Faz o upload de um avatar", + description: "Permite o upload de avatares de até 5MB para o S3.", + parameters: [ + { + name: "id_avatar", + in: "path", + required: true, + description: "O ID do avatar a ser armazenado.", + schema: { type: "string" } + } + ], + requestBody: { + required: true, + content: { + "multipart/form-data": { + schema: { + type: "object", + properties: { + file: { + type: "string", + format: "binary", + description: "Avatar a ser enviado (máx. 5MB)" + } + } + } + } + } + }, + responses: { + 200: { + description: "Upload bem-sucedido.", + content: { "application/json": { example: { message: "Arquivo enviado com sucesso!", status: "success" } } } + }, + 400: { + description: "Erro de validação, como arquivo ausente ou excedendo limite.", + content: { "application/json": { example: { message: "O avatar excede o limite de 5MB.", status: "error" } } } + }, + 500: { + description: "Erro interno ao enviar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao enviar o arquivo.", status: "error" } } } + } + } +}); + +// Rota para deletar um recurso do S3 +const deleteResourceRoute = describeRoute({ + method: "POST", + path: "/delete/resource/:id", + tags: ["S3"], + summary: "Deleta um recurso do S3", + description: "Remove um recurso específico do bucket S3.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID do recurso a ser deletado.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Recurso deletado com sucesso.", + content: { "application/json": { example: { message: "Recurso deletado com sucesso." } } } + }, + 500: { + description: "Erro ao deletar o recurso.", + content: { "application/json": { example: { error: "Erro ao deletar objeto do S3." } } } + } + } +}); + +// Rota para deletar um avatar do S3 +const deleteAvatarRoute = describeRoute({ + method: "POST", + path: "/delete/avatar/:id", + tags: ["S3"], + summary: "Deleta um avatar do S3", + description: "Remove um avatar específico do bucket S3.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID do avatar a ser deletado.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Avatar deletado com sucesso.", + content: { "application/json": { example: { message: "Avatar deletado com sucesso." } } } + }, + 500: { + description: "Erro ao deletar o avatar.", + content: { "application/json": { example: { error: "Erro ao deletar objeto do S3." } } } + } + } +}); + +// Rota para deletar a thumbnail de um recurso no S3 +const deleteThumbnailResourceRoute = describeRoute({ + method: "POST", + path: "/delete/thumbnail/resource/:id", + tags: ["S3"], + summary: "Deleta a thumbnail de um recurso do S3", + description: "Remove a thumbnail associada a um recurso do bucket S3.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID da thumbnail do recurso a ser deletada.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Thumbnail deletada com sucesso.", + content: { "application/json": { example: { message: "Thumbnail deletada com sucesso." } } } + }, + 500: { + description: "Erro ao deletar a thumbnail.", + content: { "application/json": { example: { error: "Erro ao deletar objeto do S3." } } } + } + } +}); + +// Rota para deletar a thumbnail de uma coleção no S3 +const deleteThumbnailCollectionRoute = describeRoute({ + method: "POST", + path: "/delete/thumbnail/collection/:id", + tags: ["S3"], + summary: "Deleta a thumbnail de uma coleção do S3", + description: "Remove a thumbnail associada a uma coleção do bucket S3.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID da thumbnail da coleção a ser deletada.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Thumbnail deletada com sucesso.", + content: { "application/json": { example: { message: "Thumbnail deletada com sucesso." } } } + }, + 500: { + description: "Erro ao deletar a thumbnail.", + content: { "application/json": { example: { error: "Erro ao deletar objeto do S3." } } } + } + } +}); + +// Rota para obter um recurso do S3 +const getResourceRoute = describeRoute({ + method: "GET", + path: "/get/resource/:id", + tags: ["S3"], + summary: "Obtém um recurso do S3", + description: "Recupera um arquivo de recurso do bucket S3 com base no ID fornecido.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID do recurso a ser recuperado.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Recurso obtido com sucesso.", + content: { "application/octet-stream": {} } + }, + 404: { + description: "Arquivo não encontrado.", + content: { "application/json": { example: { message: "Arquivo não encontrado" } } } + }, + 500: { + description: "Erro interno ao buscar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao buscar o arquivo" } } } + } + } +}); + +// Rota para obter uma thumbnail de recurso do S3 +const getThumbnailResourceRoute = describeRoute({ + method: "GET", + path: "/get/thumbnail/resource/:id", + tags: ["S3"], + summary: "Obtém uma thumbnail de recurso do S3", + description: "Recupera a thumbnail de um recurso do bucket S3 com base no ID fornecido.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID da thumbnail do recurso a ser recuperada.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Thumbnail de recurso obtida com sucesso.", + content: { "application/octet-stream": {} } + }, + 404: { + description: "Arquivo não encontrado.", + content: { "application/json": { example: { message: "Arquivo não encontrado" } } } + }, + 500: { + description: "Erro interno ao buscar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao buscar o arquivo" } } } + } + } +}); + +// Rota para obter uma thumbnail de coleção do S3 +const getThumbnailCollectionRoute = describeRoute({ + method: "GET", + path: "/get/thumbnail/collection/:id", + tags: ["S3"], + summary: "Obtém uma thumbnail de coleção do S3", + description: "Recupera a thumbnail de uma coleção do bucket S3 com base no ID fornecido.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID da thumbnail da coleção a ser recuperada.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Thumbnail de coleção obtida com sucesso.", + content: { "application/octet-stream": {} } + }, + 404: { + description: "Arquivo não encontrado.", + content: { "application/json": { example: { message: "Arquivo não encontrado" } } } + }, + 500: { + description: "Erro interno ao buscar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao buscar o arquivo" } } } + } + } +}); + +// Rota para obter um avatar do S3 +const getAvatarRoute = describeRoute({ + method: "GET", + path: "/get/avatar/:id", + tags: ["S3"], + summary: "Obtém um avatar do S3", + description: "Recupera um avatar do bucket S3 com base no ID fornecido.", + parameters: [ + { + name: "id", + in: "path", + required: true, + description: "O ID do avatar a ser recuperado.", + schema: { type: "string" } + } + ], + responses: { + 200: { + description: "Avatar obtido com sucesso.", + content: { "application/octet-stream": {} } + }, + 404: { + description: "Arquivo não encontrado.", + content: { "application/json": { example: { message: "Arquivo não encontrado" } } } + }, + 500: { + description: "Erro interno ao buscar o arquivo.", + content: { "application/json": { example: { message: "Erro interno ao buscar o arquivo" } } } + } + } +}); + +export +{ + uploadResourceRoute, + uploadThumbnailResourceRoute, + uploadThumbnailCollectionRoute, + uploadAvatarRoute, + deleteResourceRoute, + deleteAvatarRoute, + deleteThumbnailResourceRoute, + deleteThumbnailCollectionRoute, + getResourceRoute, + getThumbnailResourceRoute, + getThumbnailCollectionRoute, + getAvatarRoute +} \ No newline at end of file diff --git a/src/documentation/subjectsDescriber.ts b/src/documentation/subjectsDescriber.ts new file mode 100644 index 0000000..7626058 --- /dev/null +++ b/src/documentation/subjectsDescriber.ts @@ -0,0 +1,233 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /create + const createSubjectRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new subject.', + tags: ['Subjects'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['name'], + }, + }, + }, + responses: { + 200: { + description: 'Subject created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + subject: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateSubjectRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing subject.', + tags: ['Subjects'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['id'], + }, + }, + }, + responses: { + 200: { + description: 'Subject updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + subject: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteSubjectRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a subject by its ID.', + tags: ['Subjects'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Subject deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + subject: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /all + const getAllSubjectsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get a list of all subjects.', + tags: ['Subjects'], + responses: { + 200: { + description: 'List of all subjects.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + subjectId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to find subjects.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getSubjectByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a subject by its ID.', + tags: ['Subjects'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Subject found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + subjectId: { type: 'number' }, + name: { type: 'string' }, + description: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to find subject.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createSubjectRoute, + updateSubjectRoute, + deleteSubjectRoute, + getAllSubjectsRoute, + getSubjectByIdRoute +} \ No newline at end of file diff --git a/src/documentation/submissionsDescriber.ts b/src/documentation/submissionsDescriber.ts new file mode 100644 index 0000000..78fa1af --- /dev/null +++ b/src/documentation/submissionsDescriber.ts @@ -0,0 +1,286 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota /create + const createSubmissionRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create a new submission.', + tags: ['Submissions'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + userId: { type: 'number' }, + resourceId: { type: 'number' }, + content: { type: 'string' }, + }, + required: ['userId', 'resourceId', 'content'], + }, + }, + }, + responses: { + 200: { + description: 'Submission created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + submission: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to create submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /update + const updateSubmissionRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update an existing submission.', + tags: ['Submissions'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + id: { type: 'number' }, + userId: { type: 'number' }, + resourceId: { type: 'number' }, + content: { type: 'string' }, + }, + required: ['id', 'userId', 'resourceId', 'content'], + }, + }, + }, + responses: { + 200: { + description: 'Submission updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + submission: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /answer + const answerSubmissionRoute = describeRoute({ + method: 'POST', + path: '/answer', + description: 'Submit an answer to an existing submission.', + tags: ['Submissions'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + submissionId: { type: 'number' }, + answer: { type: 'string' }, + }, + required: ['submissionId', 'answer'], + }, + }, + }, + responses: { + 200: { + description: 'Submission answered successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + submission: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to answer submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /delete/:id + const deleteSubmissionRoute = describeRoute({ + method: 'POST', + path: '/delete/{id}', + description: 'Delete a submission by its ID.', + tags: ['Submissions'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Submission deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + submission: { type: 'object' }, + }, + }, + }, + }, + 400: { + description: 'Failed to delete submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota /:id + const getSubmissionByIdRoute = describeRoute({ + method: 'GET', + path: '/{id}', + description: 'Get a submission by its ID.', + tags: ['Submissions'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'number' }, + }, + ], + responses: { + 200: { + description: 'Submission found by ID.', + content: { + 'application/json': { + type: 'object', + properties: { + submissionId: { type: 'number' }, + userId: { type: 'number' }, + resourceId: { type: 'number' }, + content: { type: 'string' }, + answer: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to find submission.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota / + const getAllSubmissionsRoute = describeRoute({ + method: 'GET', + path: '/', + description: 'Get a list of all submissions.', + tags: ['Submissions'], + responses: { + 200: { + description: 'List of all submissions.', + content: { + 'application/json': { + type: 'array', + items: { + type: 'object', + properties: { + submissionId: { type: 'number' }, + userId: { type: 'number' }, + resourceId: { type: 'number' }, + content: { type: 'string' }, + answer: { type: 'string' }, + }, + }, + }, + }, + }, + 400: { + description: 'Failed to find submissions.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string' }, + message: { type: 'string' }, + code: { type: 'integer' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createSubmissionRoute, + updateSubmissionRoute, + answerSubmissionRoute, + deleteSubmissionRoute, + getSubmissionByIdRoute, + getAllSubmissionsRoute +} \ No newline at end of file diff --git a/src/documentation/uploaderDescriber.ts b/src/documentation/uploaderDescriber.ts new file mode 100644 index 0000000..6784732 --- /dev/null +++ b/src/documentation/uploaderDescriber.ts @@ -0,0 +1,50 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota /users (upload de arquivo) +const uploadUsersRoute = describeRoute({ + method: 'POST', + path: '/users', + description: 'Upload a CSV file containing user data.', + tags: ['Uploader'], + requestBody: { + content: { + 'multipart/form-data': { + type: 'object', + properties: { + file: { + type: 'string', + format: 'binary', + }, + }, + required: ['file'], + }, + }, + }, + responses: { + 200: { + description: 'Users uploaded successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 422: { + description: 'Invalid file format or failed to upload users.', + content: { + 'text/plain': { + type: 'string', + example: 'Wrong format', + }, + }, + }, + }, +}); + +export +{ + uploadUsersRoute +} \ No newline at end of file diff --git a/src/documentation/user-achievementsDescriber.ts b/src/documentation/user-achievementsDescriber.ts new file mode 100644 index 0000000..7271c7b --- /dev/null +++ b/src/documentation/user-achievementsDescriber.ts @@ -0,0 +1,309 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota POST /associate (associar conquistas a um usuário) + const associateUserAchievementsRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate achievements with a user.', + tags: ['User-Achievements'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + userId: { type: 'integer', description: 'ID of the user' }, + achievementIds: { + type: 'array', + items: { type: 'integer' }, + description: 'List of achievement IDs to be associated with the user' + }, + }, + required: ['userId', 'achievementIds'], + }, + }, + }, + responses: { + 200: { + description: 'Achievements associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate achievements.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /:userId/delete/achievement/:achievementId (remover uma conquista de um usuário) + const removeUserAchievementRoute = describeRoute({ + method: 'POST', + path: '/:userId/delete/achievement/:achievementId', + description: 'Remove an achievement from a user.', + tags: ['User-Achievements'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'achievementId', + in: 'path', + description: 'ID of the achievement', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Achievement removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove achievement.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /update (atualizar conquistas de um usuário) + const updateUserAchievementsRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update achievements for a user.', + tags: ['User-Achievements'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + userId: { type: 'integer', description: 'ID of the user' }, + achievementIds: { + type: 'array', + items: { type: 'integer' }, + description: 'Updated list of achievement IDs for the user' + }, + }, + required: ['userId', 'achievementIds'], + }, + }, + }, + responses: { + 200: { + description: 'Achievements updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to update achievements.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:userId/achievements (obter conquistas de um usuário) + const getUserAchievementsRoute = describeRoute({ + method: 'GET', + path: '/:userId/achievements', + description: 'Get all achievements of a user.', + tags: ['User-Achievements'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User achievements retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + achievements: { type: 'array', items: { type: 'object' } }, + }, + }, + }, + }, + 400: { + description: 'Failed to retrieve user achievements.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:userId/achievements/:achievementId/exists (verificar se uma conquista está associada a um usuário) + const checkUserAchievementExistenceRoute = describeRoute({ + method: 'GET', + path: '/:userId/achievements/:achievementId/exists', + description: 'Check if an achievement is associated with a user.', + tags: ['User-Achievements'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'achievementId', + in: 'path', + description: 'ID of the achievement', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Existence check successful.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check if the association exists.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /achievements/:achievementId/users (obter usuários associados a uma conquista) + const getUsersByAchievementRoute = describeRoute({ + method: 'GET', + path: '/achievements/:achievementId/users', + description: 'Get users who have a specific achievement.', + tags: ['User-Achievements'], + parameters: [ + { + name: 'achievementId', + in: 'path', + description: 'ID of the achievement', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users associated with the achievement retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { type: 'array', items: { type: 'object' } }, + }, + }, + }, + }, + 400: { + description: 'Failed to retrieve users by achievement.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + associateUserAchievementsRoute, + removeUserAchievementRoute, + updateUserAchievementsRoute, + getUserAchievementsRoute, + checkUserAchievementExistenceRoute, + getUsersByAchievementRoute +} \ No newline at end of file diff --git a/src/documentation/user-collectionDescriber.ts b/src/documentation/user-collectionDescriber.ts new file mode 100644 index 0000000..ef68437 --- /dev/null +++ b/src/documentation/user-collectionDescriber.ts @@ -0,0 +1,301 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota POST /associate (associar coleções a um usuário) + const associateUserCollectionsRoute = describeRoute({ + method: 'POST', + path: '/associate', + description: 'Associate collections with a user.', + tags: ['User-Collection'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + userId: { type: 'integer', description: 'ID of the user' }, + collectionIds: { + type: 'array', + items: { type: 'integer' }, + description: 'List of collection IDs to be associated with the user' + }, + }, + required: ['userId', 'collectionIds'], + }, + }, + }, + responses: { + 200: { + description: 'Collections associated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to associate collections.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /:userId/delete/:collectionId (remover coleção de um usuário) + const removeUserCollectionRoute = describeRoute({ + method: 'POST', + path: '/:userId/delete/:collectionId', + description: 'Remove a collection from a user.', + tags: ['User-Collection'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'collectionId', + in: 'path', + description: 'ID of the collection', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Collection removed successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + message: { type: 'string' }, + }, + }, + }, + }, + 400: { + description: 'Failed to remove collection.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:userId/collections (obter coleções de um usuário) + const getUserCollectionsRoute = describeRoute({ + method: 'GET', + path: '/:userId/collections', + description: 'Get all collections of a user.', + tags: ['User-Collection'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User collections retrieved successfully.', + content: { + 'application/json': { + type: 'array', + items: { type: 'object' }, + }, + }, + }, + 400: { + description: 'Failed to retrieve user collections.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:userId/collections/:collectionId/exists (verificar se uma coleção está associada a um usuário) + const checkUserCollectionExistenceRoute = describeRoute({ + method: 'GET', + path: '/:userId/collections/:collectionId/exists', + description: 'Check if a collection is associated with a user.', + tags: ['User-Collection'], + parameters: [ + { + name: 'userId', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + { + name: 'collectionId', + in: 'path', + description: 'ID of the collection', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Existence check successful.', + content: { + 'application/json': { + type: 'object', + properties: { + exists: { type: 'boolean' }, + }, + }, + }, + }, + 400: { + description: 'Failed to check if the association exists.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /collection/:collectionId/users (obter usuários associados a uma coleção) + const getUsersByCollectionRoute = describeRoute({ + method: 'GET', + path: '/collection/:collectionId/users', + description: 'Get users who have a specific collection.', + tags: ['User-Collection'], + parameters: [ + { + name: 'collectionId', + in: 'path', + description: 'ID of the collection', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users associated with the collection retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { type: 'array', items: { type: 'object' } }, + }, + }, + }, + }, + 400: { + description: 'Failed to retrieve users by collection.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +const getCollectionOwnerRoute = describeRoute({ + method: 'GET', + path: '/{id}/owner', + description: 'Retorna o proprietário de uma coleção com base no ID fornecido', + tags: ['User-Collection'], + parameters: [ + { + name: 'id', + in: 'path', + required: true, + schema: { type: 'integer' }, + description: 'ID da coleção', + }, + ], + responses: { + 200: { + description: 'Dados do proprietário retornados com sucesso', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/UserDto', // Substituir pelo schema correto se necessário + }, + }, + }, + }, + 400: { + description: 'Falha ao buscar o proprietário da coleção', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string', example: 'Failed to fetch owner' }, + code: { type: 'number', example: 400 }, + path: { type: 'string', example: '/{id}/owner' }, + suggestion: { type: 'string', example: 'Check the input and try again' }, + }, + }, + }, + }, + }, + }, +}); + + +export +{ + associateUserCollectionsRoute, + removeUserCollectionRoute, + getUserCollectionsRoute, + checkUserCollectionExistenceRoute, + getUsersByCollectionRoute, + getCollectionOwnerRoute +} \ No newline at end of file diff --git a/src/documentation/user-institutionDescribers.ts b/src/documentation/user-institutionDescribers.ts new file mode 100644 index 0000000..37bb556 --- /dev/null +++ b/src/documentation/user-institutionDescribers.ts @@ -0,0 +1,201 @@ +import { describeRoute } from 'hono-openapi'; + +// Descrição da rota POST /assign (atribuir instituição a um usuário) + const assignUserToInstitutionRoute = describeRoute({ + method: 'POST', + path: '/assign', + description: 'Assign an institution to a user.', + tags: ['User-Institution'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user to be assigned to an institution' }, + institution_id: { type: 'integer', description: 'ID of the institution to assign' }, + }, + required: ['user_id', 'institution_id'], + }, + }, + }, + responses: { + 200: { + description: 'User successfully assigned to the institution.', + content: { + 'application/json': { + type: 'object', + properties: { + user_institution: { type: 'object' }, // Replace with actual schema for user institution relation + }, + }, + }, + }, + 400: { + description: 'Failed to assign user to institution.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /institutions/user/:user_id (obter instituições de um usuário) + const getUserInstitutionsRoute = describeRoute({ + method: 'GET', + path: '/institutions/user/:user_id', + description: 'Get all institutions assigned to a user.', + tags: ['User-Institution'], + parameters: [ + { + name: 'user_id', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Institutions retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + institutions: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for institutions + }, + }, + }, + }, + }, + 404: { + description: 'User not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /users/institution/:institution_id (obter usuários de uma instituição) + const getInstitutionUsersRoute = describeRoute({ + method: 'GET', + path: '/users/institution/:institution_id', + description: 'Get all users assigned to a specific institution.', + tags: ['User-Institution'], + parameters: [ + { + name: 'institution_id', + in: 'path', + description: 'ID of the institution', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for users + }, + }, + }, + }, + }, + 404: { + description: 'Institution not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /revoke (revogar associação de instituição de um usuário) + const revokeUserInstitutionRoute = describeRoute({ + method: 'POST', + path: '/revoke', + description: 'Revoke the association between a user and an institution.', + tags: ['User-Institution'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user to revoke from institution' }, + institution_id: { type: 'integer', description: 'ID of the institution to revoke' }, + }, + required: ['user_id', 'institution_id'], + }, + }, + }, + responses: { + 200: { + description: 'Association successfully revoked.', + content: { + 'application/json': { + type: 'object', + properties: { + user_institution: { type: 'object' }, // Replace with actual schema for user institution relation + }, + }, + }, + }, + 400: { + description: 'Failed to revoke association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + assignUserToInstitutionRoute, + getUserInstitutionsRoute, + getInstitutionUsersRoute, + revokeUserInstitutionRoute +} diff --git a/src/documentation/user-itemDescriber.ts b/src/documentation/user-itemDescriber.ts new file mode 100644 index 0000000..c9fdfa0 --- /dev/null +++ b/src/documentation/user-itemDescriber.ts @@ -0,0 +1,200 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota POST /create (criar associação entre usuário e item) + const createUserItemAssociationRoute = describeRoute({ + method: 'POST', + path: '/create', + description: 'Create an association between a user and an item.', + tags: ['User-Item'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + item_id: { type: 'integer', description: 'ID of the item' }, + }, + required: ['user_id', 'item_id'], + }, + }, + }, + responses: { + 200: { + description: 'User-item association created successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_item: { type: 'object' }, // Replace with actual schema for user-item relation + }, + }, + }, + }, + 400: { + description: 'Failed to create user-item association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /items/user/:user_id (obter itens associados a um usuário) + const getItemsByUserRoute = describeRoute({ + method: 'GET', + path: '/items/user/:user_id', + description: 'Get all items associated with a user.', + tags: ['User-Item'], + parameters: [ + { + name: 'user_id', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Items associated with the user retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + items: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for items + }, + }, + }, + }, + }, + 404: { + description: 'User not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /users/item/:item_id (obter usuários associados a um item) + const getUsersByItemRoute = describeRoute({ + method: 'GET', + path: '/users/item/:item_id', + description: 'Get all users associated with a specific item.', + tags: ['User-Item'], + parameters: [ + { + name: 'item_id', + in: 'path', + description: 'ID of the item', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users associated with the item retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for users + }, + }, + }, + }, + }, + 404: { + description: 'Item not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota DELETE /delete (remover associação entre usuário e item) + const deleteUserItemAssociationRoute = describeRoute({ + method: 'DELETE', + path: '/delete', + description: 'Delete an association between a user and an item.', + tags: ['User-Item'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + item_id: { type: 'integer', description: 'ID of the item' }, + }, + required: ['user_id', 'item_id'], + }, + }, + }, + responses: { + 200: { + description: 'User-item association deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_item: { type: 'object' }, // Replace with actual schema for user-item relation + }, + }, + }, + }, + 400: { + description: 'Failed to delete user-item association.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + createUserItemAssociationRoute, + getItemsByUserRoute, + getUsersByItemRoute, + deleteUserItemAssociationRoute +} \ No newline at end of file diff --git a/src/documentation/user-roleDescribers.ts b/src/documentation/user-roleDescribers.ts new file mode 100644 index 0000000..ff14774 --- /dev/null +++ b/src/documentation/user-roleDescribers.ts @@ -0,0 +1,201 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota POST /assign (atribuir uma função a um usuário) + const assignUserRoleRoute = describeRoute({ + method: 'POST', + path: '/assign', + description: 'Assign a role to a user.', + tags: ['User-Role'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + role_id: { type: 'integer', description: 'ID of the role' }, + }, + required: ['user_id', 'role_id'], + }, + }, + }, + responses: { + 200: { + description: 'Role assigned successfully to the user.', + content: { + 'application/json': { + type: 'object', + properties: { + user_role: { type: 'object' }, // Replace with actual schema for user-role relation + }, + }, + }, + }, + 400: { + description: 'Failed to assign role to user.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /roles/user/:user_id (obter funções associadas a um usuário) + const getRolesByUserRoute = describeRoute({ + method: 'GET', + path: '/roles/user/:user_id', + description: 'Get all roles associated with a specific user.', + tags: ['User-Role'], + parameters: [ + { + name: 'user_id', + in: 'path', + description: 'ID of the user', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Roles associated with the user retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + roles: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for roles + }, + }, + }, + }, + }, + 404: { + description: 'User not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /users/role/:role_id (obter usuários associados a uma função) + const getUsersByRoleRoute = describeRoute({ + method: 'GET', + path: '/users/role/:role_id', + description: 'Get all users associated with a specific role.', + tags: ['User-Role'], + parameters: [ + { + name: 'role_id', + in: 'path', + description: 'ID of the role', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'Users associated with the role retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + users: { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for users + }, + }, + }, + }, + }, + 404: { + description: 'Role not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /revoke (revogar função de um usuário) + const revokeUserRoleRoute = describeRoute({ + method: 'POST', + path: '/revoke', + description: 'Revoke a role from a user.', + tags: ['User-Role'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + role_id: { type: 'integer', description: 'ID of the role' }, + }, + required: ['user_id', 'role_id'], + }, + }, + }, + responses: { + 200: { + description: 'Role revoked successfully from the user.', + content: { + 'application/json': { + type: 'object', + properties: { + user_role: { type: 'object' }, // Replace with actual schema for user-role relation + }, + }, + }, + }, + 400: { + description: 'Failed to revoke role from user.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + + +export +{ + assignUserRoleRoute, + getRolesByUserRoute, + getUsersByRoleRoute, + revokeUserRoleRoute +} \ No newline at end of file diff --git a/src/documentation/user-statsDescribers.ts b/src/documentation/user-statsDescribers.ts new file mode 100644 index 0000000..df300a0 --- /dev/null +++ b/src/documentation/user-statsDescribers.ts @@ -0,0 +1,256 @@ +import { describeRoute } from 'hono-openapi'; +// Descrição da rota POST /update (atualiza as estatísticas de um usuário) + const updateUserStatsRoute = describeRoute({ + method: 'POST', + path: '/update', + description: 'Update user statistics.', + tags: ['User-Stats'], + requestBody: { + content: { + 'application/json': { + type: 'object', + properties: { + user_id: { type: 'integer', description: 'ID of the user' }, + // Include other fields relevant for updating user stats + }, + required: ['user_id'], // Add any required fields based on your schema + }, + }, + }, + responses: { + 200: { + description: 'User statistics updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_stats: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + }, + 400: { + description: 'Failed to update user statistics.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /delete/:id (deleta as estatísticas de um usuário) + const deleteUserStatsRoute = describeRoute({ + method: 'POST', + path: '/delete/:id', + description: 'Delete user statistics by ID.', + tags: ['User-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the user statistics to delete', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User statistics deleted successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_stats: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + }, + 400: { + description: 'Failed to delete user statistics.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + 404: { + description: 'User statistics not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota POST /updateComments/:id (atualiza os comentários de um usuário) + const updateUserStatsCommentsRoute = describeRoute({ + method: 'POST', + path: '/updateComments/:id', + description: 'Update user statistics comments.', + tags: ['User-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the user statistics to update comments', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User statistics comments updated successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_stats: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + }, + 400: { + description: 'Failed to update user statistics comments.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /all (obtém todas as estatísticas de usuários) + const getAllUserStatsRoute = describeRoute({ + method: 'GET', + path: '/all', + description: 'Get all user statistics.', + tags: ['User-Stats'], + responses: { + 200: { + description: 'All user statistics retrieved successfully.', + content: { + 'application/json': { + type: 'array', + items: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + 400: { + description: 'Failed to retrieve user statistics.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +// Descrição da rota GET /:id (obtém estatísticas de um usuário específico) + const getUserStatsByIdRoute = describeRoute({ + method: 'GET', + path: '/:id', + description: 'Get specific user statistics by ID.', + tags: ['User-Stats'], + parameters: [ + { + name: 'id', + in: 'path', + description: 'ID of the user statistics to fetch', + required: true, + schema: { type: 'integer' }, + }, + ], + responses: { + 200: { + description: 'User statistics retrieved successfully.', + content: { + 'application/json': { + type: 'object', + properties: { + user_stats: { type: 'object' }, // Replace with actual schema for user stats + }, + }, + }, + }, + 400: { + description: 'Failed to fetch user statistics.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + 404: { + description: 'User statistics not found.', + content: { + 'application/json': { + type: 'object', + properties: { + status: { type: 'string', example: 'error' }, + message: { type: 'string' }, + code: { type: 'integer' }, + path: { type: 'string' }, + suggestion: { type: 'string' }, + }, + }, + }, + }, + }, +}); + +export +{ + updateUserStatsRoute, + deleteUserStatsRoute, + updateUserStatsCommentsRoute, + getAllUserStatsRoute, + getUserStatsByIdRoute +} \ No newline at end of file diff --git a/src/documentation/userDescriber.ts b/src/documentation/userDescriber.ts new file mode 100644 index 0000000..ecbf433 --- /dev/null +++ b/src/documentation/userDescriber.ts @@ -0,0 +1,322 @@ +import { describeRoute } from 'hono-openapi'; + + +const followUserRoute = describeRoute({ + method: "POST", + path: "/follow", + summary: "Seguir um usuário.", + description: "Cria uma relação de seguidor entre dois usuários, aumentando o número de seguidores e seguidos.", + request: { + body: { + type: "object", + properties: { + follower_id: { type: "number", description: "ID do usuário que está seguindo." }, + user_id: { type: "number", description: "ID do usuário que está sendo seguido." } + }, + required: ["follower_id", "user_id"] + } + }, + response: { + 200: { + description: "Usuário seguido com sucesso.", + content: { + "application/json": { + followRelation: { + type: "object", + properties: { + id: { type: "number" }, + follower_id: { type: "number" }, + user_id: { type: "number" } + } + } + } + } + }, + 400: { description: "Erro ao seguir usuário." } + } + }); + + const unfollowUserRoute = describeRoute({ + method: "POST", + path: "/unfollow", + summary: "Deixar de seguir um usuário.", + description: "Remove a relação de seguidor entre dois usuários, reduzindo o número de seguidores e seguidos.", + request: { + body: { + type: "object", + properties: { + follower_id: { type: "number", description: "ID do usuário que está deixando de seguir." }, + user_id: { type: "number", description: "ID do usuário que está sendo deixado de seguir." } + }, + required: ["follower_id", "user_id"] + } + }, + response: { + 200: { + description: "Usuário deixou de ser seguido com sucesso.", + content: { + "application/json": { + followRelation: { + type: "object", + properties: { + id: { type: "number" }, + follower_id: { type: "number" }, + user_id: { type: "number" } + } + } + } + } + }, + 400: { description: "Erro ao deixar de seguir usuário." } + } + }); + + const getFollowsRoute = describeRoute({ + method: "GET", + path: "/follows/:id", + summary: "Listar usuários seguidos.", + description: "Retorna a lista de usuários que o ID especificado segue.", + request: { + params: { + id: { type: "number", description: "ID do usuário." } + } + }, + response: { + 200: { + description: "Lista de usuários seguidos.", + content: { + "application/json": { + follows: { + type: "array", + items: { type: "object" } + } + } + } + }, + 404: { description: "Usuário não encontrado." } + } + }); + + const getFollowersRoute = describeRoute({ + method: "GET", + path: "/followers/:id", + summary: "Listar seguidores.", + description: "Retorna a lista de usuários que seguem o ID especificado.", + request: { + params: { + id: { type: "number", description: "ID do usuário." } + } + }, + response: { + 200: { + description: "Lista de seguidores.", + content: { + "application/json": { + followers: { + type: "array", + items: { type: "object" } + } + } + } + }, + 404: { description: "Usuário não encontrado." } + } + }); + + const getUsersRoute = describeRoute({ + method: "GET", + path: "/users", + summary: "Listar todos os usuários.", + description: "Retorna a lista de todos os usuários cadastrados.", + response: { + 200: { + description: "Lista de usuários.", + content: { + "application/json": { + users: { + type: "array", + items: { type: "object" } + } + } + } + } + } + }); + + const getUserByUsernameRoute = describeRoute({ + method: "GET", + path: "/:username", + summary: "Obter detalhes de um usuário pelo nome de usuário.", + description: "Retorna as informações de um usuário com base no seu nome de usuário.", + request: { + params: { + username: { type: "string", description: "Nome de usuário." } + } + }, + response: { + 200: { + description: "Usuário encontrado.", + content: { + "application/json": { + user: { type: "object" } + } + } + }, + 404: { description: "Usuário não encontrado." } + } + }); + + +const updateUserRoute = describeRoute({ + method: "POST", + path: "/update", + summary: "Atualiza as informações de um usuário.", + description: "Recebe os novos dados do usuário e atualiza no banco de dados.", + request: { + body: { + type: "object", + properties: { + id: { type: "number", description: "ID do usuário a ser atualizado." }, + name: { type: "string", description: "Novo nome do usuário." }, + email: { type: "string", description: "Novo e-mail do usuário." }, + password: { type: "string", description: "Nova senha do usuário." } + }, + required: ["id"] + } + }, + response: { + 200: { + description: "Usuário atualizado com sucesso.", + content: { + "application/json": { + user: { + type: "object", + properties: { + id: { type: "number" }, + name: { type: "string" }, + email: { type: "string" }, + updated_at: { type: "string", description: "Data da última atualização." } + } + } + } + } + }, + 400: { description: "Erro ao atualizar usuário." } + } + }); + + const confirmUserRoute = describeRoute({ + method: "POST", + path: "/confirmation/:email", + summary: "Confirma o e-mail do usuário.", + description: "Atualiza o status de confirmação do usuário baseado no e-mail informado.", + request: { + params: { + email: { type: "string", description: "E-mail do usuário a ser confirmado." } + } + }, + response: { + 200: { + description: "Usuário confirmado com sucesso.", + content: { + "application/json": { + id: { type: "number" }, + email: { type: "string" }, + confirmed_at: { type: "string", description: "Data de confirmação do e-mail." } + } + } + }, + 400: { description: "Erro ao confirmar usuário." } + } + }); + + const reactivateUserRoute = describeRoute({ + method: "POST", + path: "/reactivate/:email", + summary: "Reativa um usuário inativo.", + description: "Altera o status do usuário para ativo e atualiza a data de reativação.", + request: { + params: { + email: { type: "string", description: "E-mail do usuário a ser reativado." } + } + }, + response: { + 200: { + description: "Usuário reativado com sucesso.", + content: { + "application/json": { + id: { type: "number" }, + email: { type: "string" }, + active: { type: "boolean", description: "Status de atividade do usuário." }, + reactivated_at: { type: "string", description: "Data da reativação." } + } + } + }, + 400: { description: "Erro ao reativar usuário." } + } + }); + + const deleteUserRoute = describeRoute({ + method: "POST", + path: "/delete/:id", + summary: "Desativa um usuário.", + description: "Marca um usuário como inativo e registra a data de exclusão.", + request: { + params: { + id: { type: "number", description: "ID do usuário a ser desativado." } + } + }, + response: { + 200: { + description: "Usuário desativado com sucesso.", + content: { + "application/json": { + id: { type: "number" }, + active: { type: "boolean", description: "Status de atividade do usuário (falso)." }, + deleted_at: { type: "string", description: "Data da desativação." } + } + } + }, + 400: { description: "Erro ao desativar usuário." } + } + }); + + const systemDeleteUserRoute = describeRoute({ + method: "POST", + path: "/delete/system/:id", + summary: "Exclui um usuário permanentemente.", + description: "Remove um usuário do banco de dados de forma definitiva.", + request: { + params: { + id: { type: "number", description: "ID do usuário a ser removido permanentemente." } + } + }, + response: { + 200: { + description: "Usuário excluído permanentemente.", + content: { + "application/json": { + id: { type: "number" }, + deleted: { type: "boolean", description: "Confirmação da exclusão." } + } + } + }, + 400: { description: "Erro ao excluir usuário." } + } + }); + + +export +{ + followUserRoute, + unfollowUserRoute, + getFollowsRoute, + getFollowersRoute, + getUsersRoute, + getUserByUsernameRoute, + updateUserRoute, + confirmUserRoute, + reactivateUserRoute, + deleteUserRoute, + systemDeleteUserRoute +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 810bd7f..14b251f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -38,8 +38,8 @@ import { publicUserAchievementsRoute, userAchievementsRouter } from './routes/us import { actionRouter } from './routes/action.route' import { notificationRouter } from './routes/notification.route' import { userItemRouter } from './routes/user-item.route' -import { swaggerUI } from '@hono/swagger-ui' -import { OpenAPIHono } from "@hono/zod-openapi"; +import { openAPISpecs } from 'hono-openapi' +import { Scalar } from '@scalar/hono-api-reference' import { commentsRouter, publicCommentsRoute } from './routes/comments.route' import { publicCommentsReplyRoute, commentReplyRouter } from './routes/comment-reply.route' import { publicUserCollectionsRoutes, userCollectionsRoute } from './routes/user-collection.route' @@ -49,7 +49,7 @@ import { contactRoute } from './routes/contact.route' -const app = new OpenAPIHono(); +const app = new Hono(); app.use('*', logger()) app.use('*', prettyJSON()) @@ -61,19 +61,35 @@ app.use( }) ) -// The openapi.json will be available at /doc -app.doc("/doc", { - openapi: "3.0.0", - info: { - version: "1.0.0", - title: "My API", - }, -}); - // swagger ui doc will be available at {server url}/ui // fell free to change the url // swaggerUI url must have same path as openapi.json -app.get("/ui", swaggerUI({ url: "/doc" })); +app.get( + '/openapi', + openAPISpecs(app, { + documentation: { + components: { + securitySchemes: { + bearerAuth: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + }, + }, + }, + security: [{ bearerAuth: [] }], + }, + }) +) + +app.get( + '/docs', + Scalar({ + theme: 'saturn', + spec: { url: '/openapi' }, + }) +) + app.use( '/api/upload', diff --git a/src/routes/achievement.route.ts b/src/routes/achievement.route.ts index fad3cf0..1639057 100644 --- a/src/routes/achievement.route.ts +++ b/src/routes/achievement.route.ts @@ -5,11 +5,18 @@ import { zValidator } from "@hono/zod-validator"; import { achievementSchemas } from "@/db/schema/achievements.schema"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import { + createRoute, + updateRoute, + deleteRoute, + getAchievementRoute, + getAchievementsRoute, +} from "../documentation/achievementsDescribers" const service = Container.get(AchievementService) export const achievementRouter = honoWithJwt() - .post('/create', zValidator('json', achievementSchemas.achievementInputSchema), + .post('/create', createRoute, zValidator('json', achievementSchemas.achievementInputSchema), async (c) => { try { const input = await c.req.valid('json') @@ -33,7 +40,7 @@ export const achievementRouter = honoWithJwt() } } ) - .post('/update', zValidator('json', achievementSchemas.achievementUpdateSchema), + .post('/update', updateRoute, zValidator('json', achievementSchemas.achievementUpdateSchema), async (c) => { try { const input = await c.req.valid('json') @@ -59,7 +66,7 @@ export const achievementRouter = honoWithJwt() } } ) - .post('/delete/:id', async (c) => { + .post('/delete/:id', deleteRoute, async (c) => { try { const id = +c.req.param('id') @@ -83,7 +90,7 @@ export const achievementRouter = honoWithJwt() }) export const publicAchievementRouter = new Hono() - .get('/:id', async (c) => { + .get('/:id', getAchievementRoute, async (c) => { try { const id = +c.req.param('id') @@ -104,7 +111,7 @@ export const achievementRouter = honoWithJwt() ) } }) - .get('/', async (c) => { + .get('/', getAchievementsRoute, async (c) => { try { const achievements = achievementSchemas.achievementDtoSchema.array().parse( await service.findMany() diff --git a/src/routes/action.route.ts b/src/routes/action.route.ts index eb219c1..4f91c58 100644 --- a/src/routes/action.route.ts +++ b/src/routes/action.route.ts @@ -5,11 +5,18 @@ import { zValidator } from "@hono/zod-validator" import { actionSchemas } from "@/db/schema/actions.schema" import { createApexError, HttpStatus } from "@/services/error.service" import { z } from "zod" +import { + createActionRoute, + getActionsRoute, + getActionByNameRoute, + updateActionRoute, + deleteActionRoute, +} from "../documentation/actionsDescribers" const service = Container.get(ActionService) export const actionRouter = honoWithJwt() -.post('/create', zValidator('json', actionSchemas.input), +.post('/create', createActionRoute, zValidator('json', actionSchemas.input), async (c) => { try{ const input = await c.req.valid('json') @@ -32,7 +39,7 @@ export const actionRouter = honoWithJwt() ) } }) -.get('/actions', +.get('/actions', getActionsRoute, async (c) => { try { const actions = z.array(actionSchemas.dto).parse(await service.findMany()) @@ -42,7 +49,7 @@ export const actionRouter = honoWithJwt() return c.notFound() } }) -.get('/:name', +.get('/:name', getActionByNameRoute, async (c) => { try { const name = c.req.param('name') @@ -54,7 +61,7 @@ export const actionRouter = honoWithJwt() return c.notFound() } }) -.post('/update', +.post('/update', updateActionRoute, zValidator('json', actionSchemas.update), async (c) => { try { @@ -76,7 +83,7 @@ export const actionRouter = honoWithJwt() } } ) -.delete('/delete/:id', +.delete('/delete/:id', deleteActionRoute, async (c) =>{ try{ const id: number = +c.req.param('id') diff --git a/src/routes/auth.route.ts b/src/routes/auth.route.ts index e8e329f..11171e5 100644 --- a/src/routes/auth.route.ts +++ b/src/routes/auth.route.ts @@ -9,13 +9,21 @@ import { zValidator } from '@hono/zod-validator' import { Hono } from 'hono' import Container from 'typedi' import jwt from 'jwt-simple'; +import { + signinRoute, + signupRoute, + requestPasswordResetRoute, + resetPasswordRoute, + confirmEmailRoute +} from "../documentation/authDescribers" + const authService = Container.get(AuthService) const userService = Container.get(UserService) const userStatsService = Container.get(UserStatsService) export const authRouter = new Hono().post( - '/signin', + '/signin', signinRoute, zValidator('json', authSchema), async (c) => { try { @@ -38,7 +46,7 @@ export const authRouter = new Hono().post( } } ) -.post('/signup', +.post('/signup', signupRoute, zValidator('json', userSchemas.userInputSchema), async (c) => { try { @@ -63,7 +71,7 @@ export const authRouter = new Hono().post( } } ) - .post('/recoveryPassword/:id', + .post('/recoveryPassword/:id', requestPasswordResetRoute, async (c) => { try { const id: number = +c.req.param('id') @@ -112,7 +120,7 @@ export const authRouter = new Hono().post( } ) .post( - '/reset/password-reset', + '/reset/password-reset', resetPasswordRoute, zValidator('json', userSchemas.userUpdateSchema), async (c) => { try { @@ -162,7 +170,7 @@ export const authRouter = new Hono().post( } } ) - .get("/confirm-email", async (c) => { + .get("/confirm-email", confirmEmailRoute, async (c) => { try { const emailArray = c.req.queries("email"); diff --git a/src/routes/collection-likes.route.ts b/src/routes/collection-likes.route.ts index bb38aee..f690292 100644 --- a/src/routes/collection-likes.route.ts +++ b/src/routes/collection-likes.route.ts @@ -5,6 +5,15 @@ import { honoWithJwt } from ".."; import { zValidator } from "@hono/zod-validator"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import +{ + associateRoute, + removeLikesRoute, + updateLikesRoute, + getLikesByCollectionRoute, + checkLikeExistsRoute, + getCollectionsByUserRoute, +} from "../documentation/collectionLikesDescribers" const associateSchema = z.object({ collectionId: z.number(), @@ -14,7 +23,7 @@ const associateSchema = z.object({ const service = Container.get(CollectionLikesService); export const collectionLikesRoutes = honoWithJwt() - .post('/associate', zValidator('json', associateSchema), + .post('/associate', associateRoute, zValidator('json', associateSchema), async (c) => { try { const { collectionId, userIds } = await c.req.valid('json'); @@ -34,7 +43,7 @@ export const collectionLikesRoutes = honoWithJwt() } } ) - .post('/:collectionId/delete/:userId', + .post('/:collectionId/delete/:userId', removeLikesRoute, async (c) => { try { const collectionId = +c.req.param('collectionId'); @@ -55,7 +64,7 @@ export const collectionLikesRoutes = honoWithJwt() } } ) - .post('/update/likes', zValidator('json', associateSchema), + .post('/update/likes', updateLikesRoute, zValidator('json', associateSchema), async (c) => { try { const { collectionId, userIds } = await collectionId.req.valid('json'); @@ -77,7 +86,7 @@ export const collectionLikesRoutes = honoWithJwt() ) export const publicCollectionLikesRoutes = new Hono() - .get('/:collectionId/likes', + .get('/:collectionId/likes', getLikesByCollectionRoute, async (c) => { try { const collectionId = +c.req.param('collectionId'); @@ -97,7 +106,7 @@ export const collectionLikesRoutes = honoWithJwt() } } ) - .get('/:collectionId/likes/:userId/exists', + .get('/:collectionId/likes/:userId/exists', checkLikeExistsRoute, async (c) => { try { const collectionId = +c.req.param('collectionId'); @@ -118,7 +127,7 @@ export const collectionLikesRoutes = honoWithJwt() } } ) - .get('/user/:userId/collections', + .get('/user/:userId/collections', getCollectionsByUserRoute, async (c) => { try { const userId = +c.req.param('userId'); diff --git a/src/routes/collection-resources.route.ts b/src/routes/collection-resources.route.ts index 83b3494..769fdd6 100644 --- a/src/routes/collection-resources.route.ts +++ b/src/routes/collection-resources.route.ts @@ -5,7 +5,13 @@ import { honoWithJwt } from ".."; import { zValidator } from "@hono/zod-validator"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; - +import { + associateRoute, + deleteResourceRoute, + getResourcesRoute, + checkResourceExistsRoute, + getCollectionsForResourceRoute, +} from "../documentation/collectionResourcesDescribers" const associateSchema = z.object({ collectionId: z.number(), @@ -16,7 +22,7 @@ const service = Container.get(CollectionResourcesService); export const collectionResourcesRoutes = honoWithJwt() // associate resources with collection - .post('/associate', zValidator('json', associateSchema), + .post('/associate', associateRoute, zValidator('json', associateSchema), async (c) => { try { const { collectionId, resourceIds } = await c.req.valid('json'); @@ -36,7 +42,7 @@ export const collectionResourcesRoutes = honoWithJwt() } } ) - .post('/:collectionId/delete/:resourceId', + .post('/:collectionId/delete/:resourceId', deleteResourceRoute, async (c) => { try { const collectionId = +c.req.param('collectionId'); @@ -61,7 +67,7 @@ export const collectionResourcesRoutes = honoWithJwt() export const publicCollectionResourcesRoutes = new Hono() // get all resources of a collection - .get('/:collectionId/resources', + .get('/:collectionId/resources', getResourcesRoute, async (c) => { try { const collectionId = +c.req.param('collectionId'); @@ -82,7 +88,7 @@ export const publicCollectionResourcesRoutes = new Hono() } ) // check if resource is associated with collection - .get('/:collectionId/resources/:resourceId/exists', + .get('/:collectionId/resources/:resourceId/exists', checkResourceExistsRoute, async (c) => { try { const collectionId = +c.req.param('collectionId'); @@ -104,7 +110,7 @@ export const publicCollectionResourcesRoutes = new Hono() } ) // get collections of a resource - .get('/resource/:resourceId/collections', + .get('/resource/:resourceId/collections', getCollectionsForResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); diff --git a/src/routes/collection-stats.route.ts b/src/routes/collection-stats.route.ts index d1e88d8..437b11f 100644 --- a/src/routes/collection-stats.route.ts +++ b/src/routes/collection-stats.route.ts @@ -5,12 +5,23 @@ import { zValidator } from "@hono/zod-validator"; import { collectionStatsSchemas } from "@/db/schema/collection-stats.schema"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import { + createRoute, + updateViewsRoute, + updateDownloadsRoute, + updateLikesRoute, + updateSharesRoute, + updateScoreRoute, + updateFollowersRoute, + deleteCollectionStatsRoute, + getCollectionStatsRoute +} from "../documentation/collectionStatsDescribers" const service = Container.get(CollectionStatsService); export const collectionsStatsRouter = honoWithJwt() .post( - '/create', + '/create', createRoute, zValidator('json', collectionStatsSchemas.collectionStatsInputSchema), async (c) => { try { @@ -35,7 +46,7 @@ export const collectionsStatsRouter = honoWithJwt() } ) .post( - '/update-views/:id', async (c) => { + '/update-views/:id', updateViewsRoute, async (c) => { try { const id = +c.req.param('id') @@ -59,7 +70,7 @@ export const collectionsStatsRouter = honoWithJwt() } ) .post( - '/update-downloads/:id', async (c) => { + '/update-downloads/:id', updateDownloadsRoute, async (c) => { try { const id = +c.req.param('id') @@ -83,7 +94,7 @@ export const collectionsStatsRouter = honoWithJwt() } ) .post( - '/update-likes/:id', async (c) => { + '/update-likes/:id', updateLikesRoute, async (c) => { try { const id = +c.req.param('id') @@ -107,7 +118,7 @@ export const collectionsStatsRouter = honoWithJwt() } ) .post( - '/update-shares/:id', async (c) => { + '/update-shares/:id', updateSharesRoute, async (c) => { try { const id = +c.req.param('id') @@ -131,7 +142,7 @@ export const collectionsStatsRouter = honoWithJwt() } ) .post( - '/update-score/:id', async (c) => { + '/update-score/:id', updateScoreRoute, async (c) => { try { const id = +c.req.param('id') @@ -155,7 +166,7 @@ export const collectionsStatsRouter = honoWithJwt() } ) .post( - '/update-followers/:id', async (c) => { + '/update-followers/:id', updateFollowersRoute, async (c) => { try { const id = +c.req.param('id') @@ -179,7 +190,7 @@ export const collectionsStatsRouter = honoWithJwt() } ) .post( - '/delete/:id', async (c) => { + '/delete/:id', deleteCollectionStatsRoute, async (c) => { try { const id = +c.req.param('id') @@ -204,7 +215,7 @@ export const collectionsStatsRouter = honoWithJwt() ) export const getCollectionsStats = new Hono() - .get('/:id', async (c) => { + .get('/:id', getCollectionStatsRoute, async (c) => { try { const id = +c.req.param('id') diff --git a/src/routes/collections.route.ts b/src/routes/collections.route.ts index 5a6e9e1..fcca066 100644 --- a/src/routes/collections.route.ts +++ b/src/routes/collections.route.ts @@ -13,6 +13,20 @@ import { CollectionResourcesService } from "@/services/collection-resources.serv import { ResourceService } from "@/services/resource.service"; import { addObjectTypeNameArray } from "./resource.route"; +import { + createCollectionRoute, + updateCollectionRoute, + deleteCollectionRoute, + deletePermanentlyCollectionRoute, + restoreCollectionRoute, + getAllCollectionsRoute, + getCollectionRoute, + getActiveCollectionsByUserRoute, + getAllCollectionsByUserRoute, + getPublicCollectionsByUserRoute, + getPrivateCollectionsByUserRoute, + downloadCollectionRoute, +} from "../documentation/collectionsDescribers" const service = Container.get(CollectionsService); const serviceStats = Container.get(CollectionStatsService); @@ -21,7 +35,7 @@ const resourceService = Container.get(ResourceService) export const collectionsRouter = honoWithJwt() .post( - '/create', + '/create', createCollectionRoute, zValidator('json', collectionSchemas.collectionInputSchema), async (c) => { try { @@ -52,7 +66,7 @@ export const collectionsRouter = honoWithJwt() } ) .post( - '/update', + '/update', updateCollectionRoute, zValidator('json', collectionSchemas.collectionUpdateSchema), async (c) => { try { @@ -79,7 +93,7 @@ export const collectionsRouter = honoWithJwt() } } ) - .post('/delete/:id', async (c) => { + .post('/delete/:id', deleteCollectionRoute, async (c) => { try { const id = +c.req.param('id') @@ -101,7 +115,7 @@ export const collectionsRouter = honoWithJwt() ) } }) - .post('/delete-permanently/:id', async (c) => { + .post('/delete-permanently/:id', deletePermanentlyCollectionRoute, async (c) => { try { const id = +c.req.param('id') @@ -123,7 +137,7 @@ export const collectionsRouter = honoWithJwt() ) } }) - .post('/restore/:id', async (c) => { + .post('/restore/:id', restoreCollectionRoute, async (c) => { try { const id = +c.req.param('id') @@ -147,7 +161,7 @@ export const collectionsRouter = honoWithJwt() }) export const getCollections = new Hono() - .get('/all', async (c) => { + .get('/all', getAllCollectionsRoute, async (c) => { try { const collections = collectionSchemas.collectionDtoSchema.array().parse( await service.findMany() @@ -193,7 +207,7 @@ export const getCollections = new Hono() - .get('getActiveCollectionsByUsers/:id_user', + .get('getActiveCollectionsByUsers/:id_user', getActiveCollectionsByUserRoute, async (c) => { try { const id_user = +c.req.param('id_user') @@ -216,7 +230,7 @@ export const getCollections = new Hono() } }) - .get('getAllCollectionsByUsers/:id_user', async (c) => { + .get('getAllCollectionsByUsers/:id_user', getAllCollectionsByUserRoute, async (c) => { try { const id = +c.req.param('id_user') @@ -239,7 +253,7 @@ export const getCollections = new Hono() } }) - .get('getPublicCollectionsByUser/:id_user', async (c) => { + .get('getPublicCollectionsByUser/:id_user', getPublicCollectionsByUserRoute, async (c) => { try { const id = +c.req.param('id_user') @@ -262,7 +276,7 @@ export const getCollections = new Hono() } }) - .get('getPrivateCollectionsByUser/:id_user', async (c) => { + .get('getPrivateCollectionsByUser/:id_user', getPrivateCollectionsByUserRoute, async (c) => { try { const id = +c.req.param('id_user') @@ -285,7 +299,7 @@ export const getCollections = new Hono() } }) - .get("/:collectionId/download", async (c) => { + .get("/:collectionId/download", downloadCollectionRoute, async (c) => { try { const collectionId = +c.req.param("collectionId"); @@ -376,7 +390,7 @@ export const getCollections = new Hono() ); } }) - .get("/:id/resources", + .get("/:id/resources", getCollectionRoute, async(c) => { try { const id = +c.req.param('id') diff --git a/src/routes/comment-reply.route.ts b/src/routes/comment-reply.route.ts index fc67c8b..014d8b9 100644 --- a/src/routes/comment-reply.route.ts +++ b/src/routes/comment-reply.route.ts @@ -9,6 +9,16 @@ import { UserStatsService } from "@/services/user-stats.service"; import { ResourceStatsService } from "@/services/resource-stats.service"; import { CommentsService } from "@/services/comments.sevice"; +import { + createCommentReplyRouteDescription, + updateCommentReplyRouteDescription, + deleteDataCommentReplyRouteDescription, + deleteCommentReplyRouteDescription, + findReplyByCommentRouteDescription, + findAllReplyByCommentRouteDescription, + findAllReplyByUserRouteDescription +} from "../documentation/comment-replyDescribers" + const service = Container.get(CommentReplyService) const serviceUserStats = Container.get(UserStatsService) const serviceStatsResource = Container.get(ResourceStatsService) @@ -16,7 +26,7 @@ const serviceComment = Container.get(CommentsService) export const commentReplyRouter = honoWithJwt() - .post('/create', + .post('/create', createCommentReplyRouteDescription, zValidator('json', commentReplySchema.input), async (c) => { try { @@ -49,7 +59,7 @@ export const commentReplyRouter = honoWithJwt() ) - .post('/update', + .post('/update', updateCommentReplyRouteDescription, zValidator('json', commentReplySchema.update), async (c) => { try { @@ -71,7 +81,7 @@ export const commentReplyRouter = honoWithJwt() } ) - .post('deleteData/:id', + .post('deleteData/:id', deleteDataCommentReplyRouteDescription, async (c) => { try { const id = +c.req.param('id') @@ -94,7 +104,7 @@ export const commentReplyRouter = honoWithJwt() } ) - .post('delete/:id', + .post('delete/:id', deleteCommentReplyRouteDescription, async (c) => { try { const id = +c.req.param('id') @@ -119,7 +129,7 @@ export const commentReplyRouter = honoWithJwt() export const publicCommentsReplyRoute = new Hono() // get active reply by comment - .get('/findReplyByComment/:comment_id', async (c) => { + .get('/findReplyByComment/:comment_id', findReplyByCommentRouteDescription, async (c) => { try { const id_comment = +c.req.param('comment_id') const comments = commentReplySchema.dto.array().parse(await service.findReplyByComment(id_comment)); @@ -140,7 +150,7 @@ export const publicCommentsReplyRoute = new Hono() }) // get all reply by comment - .get('/findAllReplyByComment/:comment_id', async (c) => { + .get('/findAllReplyByComment/:comment_id', findAllReplyByCommentRouteDescription, async (c) => { try { const id_comment = +c.req.param('comment_id') const comments = commentReplySchema.dto.array().parse(await service.findAllReplyByComment(id_comment)); @@ -161,7 +171,7 @@ export const publicCommentsReplyRoute = new Hono() }) // get all reply by user - .get('/findAllReplyByUser/:id_user', async (c) => { + .get('/findAllReplyByUser/:id_user', findAllReplyByUserRouteDescription, async (c) => { try { const id_user = +c.req.param('id_user') const comments = commentReplySchema.dto.array().parse(await service.findAllReplyByUser(id_user)); diff --git a/src/routes/comments.route.ts b/src/routes/comments.route.ts index 70fa6f0..d4f385e 100644 --- a/src/routes/comments.route.ts +++ b/src/routes/comments.route.ts @@ -8,6 +8,19 @@ import { Hono } from "hono"; import { UserStatsService } from "@/services/user-stats.service"; import { ResourceStatsService } from "@/services/resource-stats.service"; +import { + createCommentRoute, + updateCommentRoute, + deleteCommentDataRoute, + deleteCommentRoute, + listAllCommentsRoute, + getCommentByIdRoute, + findCommentsByResourceRoute, + findAllCommentsByResourceRoute, + findCommentsByUserRoute, + findAllCommentsByUserRoute +} from "../documentation/commentsDescribers" + const service = Container.get(CommentsService); const serviceUserStats = Container.get(UserStatsService) const serviceStatsResource = Container.get(ResourceStatsService) @@ -15,7 +28,7 @@ const serviceStatsResource = Container.get(ResourceStatsService) export const commentsRouter = honoWithJwt() //create a comment - .post('/create', + .post('/create', createCommentRoute, zValidator('json', commentsSchema.input), async (c) => { @@ -44,7 +57,7 @@ export const commentsRouter = honoWithJwt() ) - .post('/update', + .post('/update', updateCommentRoute, zValidator('json', commentsSchema.update), async (c) => { try { @@ -70,7 +83,7 @@ export const commentsRouter = honoWithJwt() ) - .post('deleteData/:id', + .post('deleteData/:id', deleteCommentDataRoute, async (c) => { try { const id = +c.req.param('id') @@ -93,7 +106,7 @@ export const commentsRouter = honoWithJwt() } ) - .post('delete/:id', + .post('delete/:id', deleteCommentRoute, async (c) => { try { const id = +c.req.param('id') @@ -116,7 +129,7 @@ export const commentsRouter = honoWithJwt() ) export const publicCommentsRoute = new Hono() - .get('/all', async (c) => { + .get('/all', listAllCommentsRoute, async (c) => { try { const comment = commentsSchema.dto.array().parse(await service.findMany()) return c.json({ comment }) @@ -136,7 +149,7 @@ export const publicCommentsRoute = new Hono() ) // encontrar um comentário com base no id - .get('/:id', + .get('/:id', getCommentByIdRoute, async (c) => { try { const id = +c.req.param('id') @@ -160,7 +173,7 @@ export const publicCommentsRoute = new Hono() ) // get all resource by resource - .get('/findCommentsByResource/:resource_id', async (c) => { + .get('/findCommentsByResource/:resource_id', findCommentsByResourceRoute, async (c) => { try { const id_resource = +c.req.param('resource_id') const comments =commentsSchema.dto.array().parse( await service.findCommentsByResource(id_resource)); @@ -181,7 +194,7 @@ export const publicCommentsRoute = new Hono() }) // get active resource by resource - .get('/findAllCommentsByResource/:resource_id', async (c) => { + .get('/findAllCommentsByResource/:resource_id', findAllCommentsByResourceRoute, async (c) => { try { const id_resource = +c.req.param('resource_id') const resource = commentsSchema.dto.array().parse(await service.findAllCommentsByResource(id_resource)) @@ -205,7 +218,7 @@ export const publicCommentsRoute = new Hono() // get active resource by user - .get('/findCommentsByUser/:user_id', async (c) => { + .get('/findCommentsByUser/:user_id', findCommentsByUserRoute, async (c) => { try { const user_id = +c.req.param('user_id') const resource = commentsSchema.dto.array().parse(await service.findCommentsByUser(user_id)) @@ -228,7 +241,7 @@ export const publicCommentsRoute = new Hono() // get all comments by user - .get('/findAllCommentsByUser/:user_id', async (c) => { + .get('/findAllCommentsByUser/:user_id', findAllCommentsByUserRoute, async (c) => { try { const user_id = +c.req.param('user_id') const resources =commentsSchema.dto.array().parse( await service.findAllCommentsByUser(user_id)); diff --git a/src/routes/complaints.route.ts b/src/routes/complaints.route.ts index 637e724..649cd0e 100644 --- a/src/routes/complaints.route.ts +++ b/src/routes/complaints.route.ts @@ -5,11 +5,20 @@ import { complaintSchemas } from "@/db/schema/complaint.schema"; import { zValidator } from "@hono/zod-validator"; import { createApexError, HttpStatus } from "@/services/error.service"; +import { + createComplaintRouteDescription, + updateComplaintRouteDescription, + evaluateComplaintRouteDescription, + deleteComplaintRouteDescription, + getComplaintByIdRouteDescription, + getAllComplaintsRouteDescription +} from "../documentation/compliantDescribers" + const service = Container.get(ComplaintService); export const complaintsRouter = honoWithJwt() .post( - '/create', + '/create', createComplaintRouteDescription, zValidator('json', complaintSchemas.complaintInputSchema), async (c) => { try { @@ -35,7 +44,7 @@ export const complaintsRouter = honoWithJwt() } ) .post( - '/update', + '/update', updateComplaintRouteDescription, zValidator('json', complaintSchemas.complaintUpdateSchema), async (c) => { try { @@ -63,7 +72,7 @@ export const complaintsRouter = honoWithJwt() } ) .post( - '/evaluate', + '/evaluate', evaluateComplaintRouteDescription, zValidator('json', complaintSchemas.complaintUpdateSchema), async (c) => { try { @@ -88,7 +97,7 @@ export const complaintsRouter = honoWithJwt() } } ) -.post('/delete/:id', async (c) => { +.post('/delete/:id', deleteComplaintRouteDescription, async (c) => { try { const id = +c.req.param('id') @@ -110,7 +119,7 @@ export const complaintsRouter = honoWithJwt() ) } }) -.get('/:id', async (c) => { +.get('/:id', getComplaintByIdRouteDescription, async (c) => { try { const id = +c.req.param('id') @@ -132,7 +141,7 @@ export const complaintsRouter = honoWithJwt() ) } }) -.get('/', async (c) => { +.get('/', getAllComplaintsRouteDescription, async (c) => { try { const complaints = complaintSchemas.complaintDtoSchema.array().parse( await service.findMany() diff --git a/src/routes/contact.route.ts b/src/routes/contact.route.ts index 7905c50..df0f038 100644 --- a/src/routes/contact.route.ts +++ b/src/routes/contact.route.ts @@ -3,11 +3,12 @@ import { zValidator } from "@hono/zod-validator"; import { Hono } from "hono"; import Container from "typedi"; import { z } from "zod"; +import { contactRouteDescriber } from "../documentation/contactDescriber" const contactService = Container.get(ContactService) export const contactRoute = new Hono() - .post('/contact', + .post('/contact', contactRouteDescriber, zValidator('json', z.object({ name: z.string().min(1, 'Name is required'), email: z.string().email(), diff --git a/src/routes/educational-stage.route.ts b/src/routes/educational-stage.route.ts index e01e27c..1412263 100644 --- a/src/routes/educational-stage.route.ts +++ b/src/routes/educational-stage.route.ts @@ -5,13 +5,19 @@ import { zValidator } from "@hono/zod-validator"; import { educationalStageSchema } from "@/db/schema/educational-stage.schema"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; - +import { + createEducationalStageRoute, + updateEducationalStageRoute, + deleteEducationalStageRoute, + getAllEducationalStagesRoute, + getEducationalStageByIdRoute, +} from "../documentation/Educational-StageDescribers" const service = Container.get(EducationalStageService); export const educationalStageRouter = honoWithJwt() - .post('/create', + .post('/create', createEducationalStageRoute, zValidator('json', educationalStageSchema.input), async (c) => { try { @@ -34,7 +40,7 @@ export const educationalStageRouter = honoWithJwt() } ) - .post('/update', + .post('/update', updateEducationalStageRoute, zValidator('json', educationalStageSchema.update), async (c) => { try { @@ -57,7 +63,7 @@ export const educationalStageRouter = honoWithJwt() } ) - .post('/delete/:id', + .post('/delete/:id', deleteEducationalStageRoute, async (c) => { try { const id = +c.req.param('id') @@ -82,7 +88,7 @@ export const educationalStageRouter = honoWithJwt() export const publicEducationalStageRouter = new Hono() - .get('/all', + .get('/all', getAllEducationalStagesRoute, async (c) => { try { const educationalStages = educationalStageSchema.dto.array().parse(await service.findMany()) @@ -103,7 +109,7 @@ export const publicEducationalStageRouter = new Hono() } ) - .get('/:id', + .get('/:id', getEducationalStageByIdRoute, async (c) => { try { const id = +c.req.param('id') diff --git a/src/routes/homologation.route.ts b/src/routes/homologation.route.ts index 5f54c34..d6f4b8f 100644 --- a/src/routes/homologation.route.ts +++ b/src/routes/homologation.route.ts @@ -8,7 +8,10 @@ import { SubmissionService } from "@/services/submission.service"; import { HomologationService } from "@/services/homologation.service"; import { ResourceService } from "@/services/resource.service"; - +import { + getAllHomologationRoute, + createHomologationRoute +} from "../documentation/homologationDescribers" const serviceHomologation = Container.get(HomologationService) const service = Container.get(SubmissionService); @@ -29,7 +32,7 @@ export const inputSchemaHomologation = z.object({ export const homologationRouter = honoWithJwt() //pegar os que estao abertos para homologaçção - .get('/all', async (c) => { + .get('/all', getAllHomologationRoute, async (c) => { const user = c.get('jwtPayload').id; try { @@ -68,7 +71,7 @@ export const homologationRouter = honoWithJwt() }) - .post('/new', zValidator('json', submissionSchemas.submissionUpdateSchema), + .post('/new', createHomologationRoute, zValidator('json', submissionSchemas.submissionUpdateSchema), async (c) => { try { diff --git a/src/routes/institution.route.ts b/src/routes/institution.route.ts index ef4fd30..b32b1fe 100644 --- a/src/routes/institution.route.ts +++ b/src/routes/institution.route.ts @@ -6,9 +6,20 @@ import { institutionSchemas } from "@/db/schema/institution.schema"; import { createApexError, HttpStatus } from "@/services/error.service"; import { z } from "zod"; +import { + createInstitutionRoute, + getInstitutionsRoute, + getInstitutionByNameRoute, + getInstitutionByUfRoute, + getInstitutionByCityRoute, + getInstitutionByCepRoute, + updateInstitutionRoute, + deleteInstitutionRoute +} from "../documentation/institutionDescribers" + const service = Container.get(InstitutionService) export const institutionRouter = honoWithJwt() -.post('/create', zValidator('json', institutionSchemas.input), +.post('/create', createInstitutionRoute, zValidator('json', institutionSchemas.input), async (c) => { try{ const input = await c.req.valid('json') @@ -29,7 +40,7 @@ export const institutionRouter = honoWithJwt() ) } }) -.get('/institutions', +.get('/institutions', getInstitutionsRoute, async (c) => { try{ const institutions = z.array(institutionSchemas.dto).parse(await service.findMany()) @@ -39,7 +50,7 @@ export const institutionRouter = honoWithJwt() } } ) -.get('/name/:name', +.get('/name/:name', getInstitutionByNameRoute, async (c) => { try{ const name = c.req.param('name') @@ -51,7 +62,7 @@ export const institutionRouter = honoWithJwt() } } ) -.get('/uf/:uf', +.get('/uf/:uf', getInstitutionByUfRoute, async (c) => { try{ const uf = c.req.param('uf') @@ -63,7 +74,7 @@ export const institutionRouter = honoWithJwt() } } ) -.get('/city/:city', +.get('/city/:city', getInstitutionByCityRoute, async (c) => { try{ const city = c.req.param('city') @@ -75,7 +86,7 @@ export const institutionRouter = honoWithJwt() } } ) -.get('/cep/:cep', +.get('/cep/:cep', getInstitutionByCepRoute, async (c) => { try{ const cep = c.req.param('cep') @@ -87,7 +98,7 @@ export const institutionRouter = honoWithJwt() } } ) -.post('/update', +.post('/update', updateInstitutionRoute, zValidator('json', institutionSchemas.update), async (c) => { try{ @@ -109,7 +120,7 @@ export const institutionRouter = honoWithJwt() } } ) -.delete('/delete/:id', +.delete('/delete/:id', deleteInstitutionRoute, async (c) => { try{ const id: number = +c.req.param('id') diff --git a/src/routes/items.route.ts b/src/routes/items.route.ts index 910e267..782fa18 100644 --- a/src/routes/items.route.ts +++ b/src/routes/items.route.ts @@ -6,11 +6,20 @@ import { itemsSchema } from "@/db/schema/item.schema"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import { + createItemRoute, + updateItemRoute, + deleteItemRoute, + activeItemRoute, + getAllItemsRoute, + getItemByIdRoute +} from "../documentation/ItemDescriber" + const service = Container.get(ItemsService); export const itemsRouter = honoWithJwt() - .post('/create', + .post('/create', createItemRoute, zValidator('json', itemsSchema.input), async (c) => { try { @@ -33,7 +42,7 @@ export const itemsRouter = honoWithJwt() } ) - .post('/update', + .post('/update', updateItemRoute, zValidator('json', itemsSchema.update), async (c) => { try { @@ -56,7 +65,7 @@ export const itemsRouter = honoWithJwt() } ) - .post('/delete/:id', + .post('/delete/:id', deleteItemRoute, async (c) => { try { const id = +c.req.param('id') @@ -78,7 +87,7 @@ export const itemsRouter = honoWithJwt() } ) - .post('/active/:id', + .post('/active/:id', activeItemRoute, async (c) => { try { const id = +c.req.param('id') @@ -102,7 +111,7 @@ export const itemsRouter = honoWithJwt() export const publicItemsRouter = new Hono() -.get('/all', +.get('/all', getAllItemsRoute, async (c) => { try { const items = itemsSchema.dto.array().parse(await service.findMany()) @@ -123,7 +132,7 @@ export const publicItemsRouter = new Hono() } ) -.get('/:id', +.get('/:id', getItemByIdRoute, async (c) => { try { const id = +c.req.param('id') diff --git a/src/routes/language.route.ts b/src/routes/language.route.ts index 06b1749..ff2c4e2 100644 --- a/src/routes/language.route.ts +++ b/src/routes/language.route.ts @@ -6,12 +6,19 @@ import { createApexError, HttpStatus } from "@/services/error.service"; import { languageSchema } from "@/db/schema/language.schema"; import { Hono } from "hono"; +import { + createLanguageRoute, + updateLanguageRoute, + deleteLanguageRoute, + getAllLanguagesRoute, + getLanguageByIdRoute +} from "../documentation/languageDescriber" const service = Container.get(LanguageService) export const languageRouter = honoWithJwt() - .post('/create', + .post('/create', createLanguageRoute, zValidator('json', languageSchema.input), async (c) => { try { @@ -34,7 +41,7 @@ export const languageRouter = honoWithJwt() } ) - .post('/update', + .post('/update', updateLanguageRoute, zValidator('json', languageSchema.update), async (c) => { @@ -58,7 +65,7 @@ export const languageRouter = honoWithJwt() } ) - .post('/delete/:id', + .post('/delete/:id', deleteLanguageRoute, async (c) => { try { const id = +c.req.param('id') @@ -82,7 +89,7 @@ export const languageRouter = honoWithJwt() export const publicLanguageRouter = new Hono() - .get('/all', + .get('/all', getAllLanguagesRoute, async (c) => { try { const languages = await service.findMany() @@ -102,7 +109,7 @@ export const publicLanguageRouter = new Hono() } ) - .get('/:id', + .get('/:id', getLanguageByIdRoute, async (c) => { try { const id = +c.req.param('id') diff --git a/src/routes/license.route.ts b/src/routes/license.route.ts index cef1eaa..8875083 100644 --- a/src/routes/license.route.ts +++ b/src/routes/license.route.ts @@ -6,11 +6,19 @@ import { licenseSchema } from "@/db/schema/license.schema"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import { + createLicenseRoute, + updateLicenseRoute, + deleteLicenseRoute, + getAllLicensesRoute, + getLicenseByIdRoute +} from "../documentation/licenseDescriber" + const service = Container.get(LicenseService); export const licenseRouter = honoWithJwt() - .post('/create', + .post('/create', createLicenseRoute, zValidator('json', licenseSchema.input), async (c) => { try { @@ -33,7 +41,7 @@ export const licenseRouter = honoWithJwt() } ) - .post('/update', + .post('/update', updateLicenseRoute, zValidator('json', licenseSchema.update), async (c) => { try { @@ -56,7 +64,7 @@ export const licenseRouter = honoWithJwt() } ) - .post('/delete/:id', + .post('/delete/:id', deleteLicenseRoute, async (c) => { try { const id = + c.req.param('id') @@ -81,7 +89,7 @@ export const licenseRouter = honoWithJwt() export const publicLicenseRouter = new Hono() - .get('/all', async (c) => { + .get('/all', getAllLicensesRoute, async (c) => { try { const licenses = licenseSchema.dto.array().parse(await service.findMany()) @@ -101,7 +109,7 @@ export const publicLicenseRouter = new Hono() } ) - .get('/:id', async (c) => { + .get('/:id', getLicenseByIdRoute, async (c) => { try { const id = + c.req.param('id') const license = licenseSchema.dto.parse(await service.find(id)) diff --git a/src/routes/notification.route.ts b/src/routes/notification.route.ts index b4384c8..b1a352c 100644 --- a/src/routes/notification.route.ts +++ b/src/routes/notification.route.ts @@ -6,10 +6,23 @@ import { createApexError, HttpStatus } from "@/services/error.service" import { z } from "zod" import { notificationSchemas } from "@/db/relations/notification.relation" +import +{ + createNotificationRoute, + getNotificationsRoute, + getNotificationByActionRoute, + getNotificationByActorUserRoute, + getNotificationByTargetUserRoute, + getNotificationByTargetResourceRoute, + getNotificationByTargetCollectionRoute, + updateNotificationRoute, + deleteNotificationRoute +} from "../documentation/notificationDescriber" + const service = Container.get(NotificationService) export const notificationRouter = honoWithJwt() -.post('/create', zValidator('json', notificationSchemas.input), +.post('/create', createNotificationRoute, zValidator('json', notificationSchemas.input), async (c) => { try{ const input = await c.req.valid('json') @@ -32,7 +45,7 @@ export const notificationRouter = honoWithJwt() ) } }) -.get('/notifications', +.get('/notifications', getNotificationsRoute, async (c) => { try { const notifications = z.array(notificationSchemas.dto).parse(await service.findMany()) @@ -42,8 +55,8 @@ export const notificationRouter = honoWithJwt() return c.notFound() } }) -.get('/action/:action_id', - async (c) =>{ +.get('/action/:action_id', getNotificationByActionRoute, + async (c) =>{ try { const action_id = +c.req.param('action_id') @@ -55,7 +68,7 @@ export const notificationRouter = honoWithJwt() } } ) -.get('/actor-user/:actor_user_id', +.get('/actor-user/:actor_user_id', getNotificationByActorUserRoute, async (c) =>{ try { const actor_user_id = +c.req.param('actor_user_id') @@ -68,7 +81,7 @@ export const notificationRouter = honoWithJwt() } } ) -.get('/target-user/:target_user_id', +.get('/target-user/:target_user_id', getNotificationByTargetUserRoute, async (c) =>{ try { const target_user_id = +c.req.param('target_user_id') @@ -81,7 +94,7 @@ export const notificationRouter = honoWithJwt() } } ) -.get('/target-resource/:target_resource_id', +.get('/target-resource/:target_resource_id', getNotificationByTargetResourceRoute, async (c) =>{ try { const target_resource_id = +c.req.param('target_resource_id') @@ -94,7 +107,7 @@ export const notificationRouter = honoWithJwt() } } ) -.get('/target-collection/:target_collection_id', +.get('/target-collection/:target_collection_id', getNotificationByTargetCollectionRoute, async (c) =>{ try { const target_collection_id = +c.req.param('target_collection_id') @@ -108,7 +121,7 @@ export const notificationRouter = honoWithJwt() } ) .post('/update', - zValidator('json', notificationSchemas.update), + zValidator('json', notificationSchemas.update), updateNotificationRoute, async (c) => { try { const input = await c.req.valid('json') @@ -129,7 +142,7 @@ export const notificationRouter = honoWithJwt() } } ) -.delete('/delete/:id', +.delete('/delete/:id', deleteNotificationRoute, async (c) =>{ try{ const id: number = +c.req.param('id') diff --git a/src/routes/object-type.route.ts b/src/routes/object-type.route.ts index 0c51d4e..654baa3 100644 --- a/src/routes/object-type.route.ts +++ b/src/routes/object-type.route.ts @@ -6,10 +6,18 @@ import { zValidator } from "@hono/zod-validator"; import { objectTypeSchema } from "@/db/schema/object-type.schema"; import { Hono } from "hono"; +import { + createObjectTypeRoute, + updateObjectTypeRoute, + deleteObjectTypeRoute, + getAllObjectTypesRoute, + getObjectTypeByIdRoute +} from "../documentation/object-type" + const service = Container.get(ObjectTypeService); export const objectTypeRouter = honoWithJwt() - .post('/create', + .post('/create', createObjectTypeRoute, zValidator('json', objectTypeSchema.input), async (c) => { try { @@ -33,7 +41,7 @@ export const objectTypeRouter = honoWithJwt() } ) - .post('/update', + .post('/update', updateObjectTypeRoute, zValidator('json', objectTypeSchema.update), async (c) => { try { @@ -58,7 +66,7 @@ export const objectTypeRouter = honoWithJwt() ) - .post('/delete/:id', + .post('/delete/:id', deleteObjectTypeRoute, async (c) => { try { const id = +c.req.param('id') @@ -83,7 +91,7 @@ export const objectTypeRouter = honoWithJwt() export const publicObjectTypeRouter = new Hono() - .get('/all', + .get('/all', getAllObjectTypesRoute, async (c) => { try { const objectTypes = await service.findMany() @@ -104,7 +112,7 @@ export const objectTypeRouter = honoWithJwt() } ) - .get('/:id', + .get('/:id', getObjectTypeByIdRoute, async (c) => { try { const id = +c.req.param('id') diff --git a/src/routes/resource-educational-stages.route.ts b/src/routes/resource-educational-stages.route.ts index 7570899..f1b51f2 100644 --- a/src/routes/resource-educational-stages.route.ts +++ b/src/routes/resource-educational-stages.route.ts @@ -6,6 +6,15 @@ import { createApexError, HttpStatus } from "@/services/error.service"; import { zValidator } from "@hono/zod-validator"; import { Hono } from "hono"; +import { + associateResourceWithEducationalStagesRoute, + removeEducationalStageFromResourceRoute, + updateResourceEducationalStagesRoute, + getEducationalStagesByResourceRoute, + checkAssociationExistsRoute, + getResourcesByEducationalStageRoute +} from "../documentation/resource-educational-stages" + const associateSchema = z.object({ resourceId: z.number(), educationalStageIds: z.array(z.number()), @@ -16,7 +25,7 @@ const service = Container.get(ResourceEducationalStagesService); export const resourceEducationalStagesRouter = honoWithJwt() .post( - '/associate', + '/associate', associateResourceWithEducationalStagesRoute, zValidator('json', associateSchema), async (c) => { try { @@ -39,7 +48,7 @@ export const resourceEducationalStagesRouter = honoWithJwt() ) .post( - '/:resourceId/delete/educationalStage/:educationalStageId', + '/:resourceId/delete/educationalStage/:educationalStageId', removeEducationalStageFromResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -62,7 +71,7 @@ export const resourceEducationalStagesRouter = honoWithJwt() ) .post( - '/update/educationalStages', + '/update/educationalStages', updateResourceEducationalStagesRoute, zValidator('json', associateSchema), async (c) => { try { @@ -88,7 +97,7 @@ export const resourceEducationalStagesRouter = honoWithJwt() export const publicResourceEducationalStagesRouter = new Hono() .get( - '/:resourceId/educationalStages', + '/:resourceId/educationalStages', getEducationalStagesByResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -110,7 +119,7 @@ export const publicResourceEducationalStagesRouter = new Hono() ) .get( - '/:resourceId/educationalStages/:educationalStageId/exists', + '/:resourceId/educationalStages/:educationalStageId/exists', checkAssociationExistsRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -133,7 +142,7 @@ export const publicResourceEducationalStagesRouter = new Hono() ) .get( - '/educationalStage/:educationalStageId/resources', + '/educationalStage/:educationalStageId/resources', getResourcesByEducationalStageRoute, async (c) => { try { const educationalStageId = +c.req.param('educationalStageId'); diff --git a/src/routes/resource-language.route.ts b/src/routes/resource-language.route.ts index 02b8abd..d3eebf7 100644 --- a/src/routes/resource-language.route.ts +++ b/src/routes/resource-language.route.ts @@ -6,6 +6,15 @@ import Container from 'typedi'; import { z } from 'zod'; import { honoWithJwt } from '..'; +import { + associateResourceWithLanguagesRoute, + removeLanguageFromResourceRoute, + updateResourceLanguagesRoute, + getLanguagesByResourceRoute, + checkLanguageAssociationExistsRoute, + getResourcesByLanguageRoute +} from "../documentation/resource-language" + // Definição dos esquemas de validação const associateSchema = z.object({ resourceId: z.number(), @@ -18,7 +27,7 @@ const service = Container.get(ResourceLanguageService); export const resourceLanguageRouter = honoWithJwt() // Associa um recurso a várias linguagens .post( - '/associate', + '/associate', associateResourceWithLanguagesRoute, zValidator('json', associateSchema), async (c) => { try { @@ -41,7 +50,7 @@ export const resourceLanguageRouter = honoWithJwt() ) // Remove a associação entre um recurso e uma linguagem .post( - '/:resourceId/delete/language/:languageId', + '/:resourceId/delete/language/:languageId', removeLanguageFromResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -65,7 +74,7 @@ export const resourceLanguageRouter = honoWithJwt() // Atualiza as associações de linguagens de um recurso .post( - '/update/languages', + '/update/languages', updateResourceLanguagesRoute, zValidator('json', associateSchema), async (c) => { try { @@ -90,7 +99,7 @@ export const resourceLanguageRouter = honoWithJwt() export const publicResourceLanguageRouter = new Hono() // Obtém todas as linguagens associadas a um recurso .get( - '/:resourceId/languages', + '/:resourceId/languages', getLanguagesByResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -112,7 +121,7 @@ export const resourceLanguageRouter = honoWithJwt() ) // Verifica se a associação entre um recurso e uma linguagem existe .get( - '/:resourceId/language/:languageId/exists', + '/:resourceId/language/:languageId/exists', checkLanguageAssociationExistsRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -135,7 +144,7 @@ export const resourceLanguageRouter = honoWithJwt() ) // Obtém todos os recursos associados a uma linguagem .get( - '/language/:languageId/resources', + '/language/:languageId/resources', getResourcesByLanguageRoute, async (c) => { try { const languageId = +c.req.param('languageId'); diff --git a/src/routes/resource-likes.route.ts b/src/routes/resource-likes.route.ts index f7da069..79dc51b 100644 --- a/src/routes/resource-likes.route.ts +++ b/src/routes/resource-likes.route.ts @@ -4,11 +4,19 @@ import { honoWithJwt } from ".."; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import { + associateResourceWithLikesRoute, + removeLikesFromResourceRoute, + getLikesByResourceRoute, + checkLikeAssociationExistsRoute, + getResourcesByUserRoute +} from "../documentation/resource-likes" + const service = Container.get(ResourceLikesService); export const resourceLikesRoutes = honoWithJwt() // the user has liked the resource - .post('/like/:resourceId', + .post('/like/:resourceId', associateResourceWithLikesRoute, async (c) => { //pega o id do usuario logado const userIds = c.get('jwtPayload').id; @@ -33,7 +41,7 @@ export const resourceLikesRoutes = honoWithJwt() } ) // remove likes from resource, the user has unliked the resource - .post('/:resourceId/delete/:userId', + .post('/:resourceId/delete/:userId', removeLikesFromResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -57,7 +65,7 @@ export const resourceLikesRoutes = honoWithJwt() export const publicResourceLikesRoutes = new Hono() // get likes by resource id - .get('/:resourceId', + .get('/:resourceId', getLikesByResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -79,7 +87,7 @@ export const publicResourceLikesRoutes = new Hono() ) // verify if association exists, the user has liked the resource - .get('/:resourceId/likes/:userId/exists', + .get('/:resourceId/likes/:userId/exists', checkLikeAssociationExistsRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -102,7 +110,7 @@ export const publicResourceLikesRoutes = new Hono() ) // get resources liked by user - .get('/user/:userId/resources', + .get('/user/:userId/resources', getResourcesByUserRoute, async (c) => { try { const userId = +c.req.param('userId'); diff --git a/src/routes/resource-stats.route.ts b/src/routes/resource-stats.route.ts index db325bf..17299ed 100644 --- a/src/routes/resource-stats.route.ts +++ b/src/routes/resource-stats.route.ts @@ -6,12 +6,22 @@ import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; import { resourceStatsSchema } from "@/db/schema/resource-stats.schema"; +import { + createResourceStatsRoute, + updateResourceStatsRoute, + deleteResourceStatsRoute, + viewUpdateResourceStatsRoute, + sharesUpdateResourceStatsRoute, + downloadUpdateResourceStatsRoute, + getAllResourceStatsRoute, + getResourceStatsByIdRoute +} from "../documentation/resource-statsDescriber" const service = Container.get(ResourceStatsService) export const resourceStatsRouter = honoWithJwt() // rota para criar as stats de um recurso - .post('/create', + .post('/create', createResourceStatsRoute, zValidator('json', resourceStatsSchema.input), async (c) => { try { @@ -37,7 +47,7 @@ export const resourceStatsRouter = honoWithJwt() ) // rota para atualizar as stats de um recurso - .post('/update', + .post('/update', updateResourceStatsRoute, zValidator('json', resourceStatsSchema.update), async (c) => { @@ -62,7 +72,7 @@ export const resourceStatsRouter = honoWithJwt() ) // rota para deletar as stats de um recurso - .post('/delete/:id', + .post('/delete/:id', deleteResourceStatsRoute, async (c) => { try { const id = +c.req.param('id') @@ -86,7 +96,7 @@ export const resourceStatsRouter = honoWithJwt() export const publicResourceStatsRouter = new Hono() //rota para atualizar as views de um recurso, cada chamada soma 1 as views - .post('/viewUpdate/:id', + .post('/viewUpdate/:id', viewUpdateResourceStatsRoute, async (c) => { try { const id = +c.req.param('id') @@ -109,7 +119,7 @@ export const publicResourceStatsRouter = new Hono() ) //rota para atualizar as shares de um recurso, cada chamada soma 1 as shares - .post('/sharesUpdate/:id', + .post('/sharesUpdate/:id', sharesUpdateResourceStatsRoute, async (c) => { try { const id = +c.req.param('id') @@ -132,7 +142,7 @@ export const publicResourceStatsRouter = new Hono() ) //rota para atualizar os downloads de um recurso, cada chamada soma 1 aos downloads - .post('/downloadUpdate/:id', + .post('/downloadUpdate/:id', downloadUpdateResourceStatsRoute, async (c) => { try { const id = +c.req.param('id') @@ -155,7 +165,7 @@ export const publicResourceStatsRouter = new Hono() ) //rota para pegar todas as stats de todos os recursos - .get('/all', async (c) => { + .get('/all', getAllResourceStatsRoute, async (c) => { try { const resourceStats = resourceStatsSchema.dto.array().parse(await service.findMany()) @@ -176,7 +186,7 @@ export const publicResourceStatsRouter = new Hono() ) //rota para pegar as stats de um recurso especifico - .get('/:id', + .get('/:id', getResourceStatsByIdRoute, async (c) => { try { const id = +c.req.param('id') diff --git a/src/routes/resource-subjects.route.ts b/src/routes/resource-subjects.route.ts index b479417..15de69e 100644 --- a/src/routes/resource-subjects.route.ts +++ b/src/routes/resource-subjects.route.ts @@ -6,6 +6,14 @@ import { zValidator } from "@hono/zod-validator"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import { + associateResourceWithSubjectsRoute, + removeSubjectFromResourceRoute, + updateResourceSubjectsRoute, + getSubjectsByResourceRoute, + checkAssociationExistsRoute, + getResourcesBySubjectRoute +} from "../documentation/resource-subjectsDescriber" const associateSchema = z.object({ resourceId: z.number(), @@ -17,7 +25,7 @@ const service = Container.get(ResourceSubjectsService); export const resourceSubjectsRouter = honoWithJwt() .post( - '/associate', + '/associate', associateResourceWithSubjectsRoute, zValidator('json', associateSchema), async (c) => { try { @@ -40,7 +48,7 @@ export const resourceSubjectsRouter = honoWithJwt() ) .post( - '/:resourceId/delete/subject/:subjectId', + '/:resourceId/delete/subject/:subjectId', removeSubjectFromResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -64,7 +72,7 @@ export const resourceSubjectsRouter = honoWithJwt() .post( - '/update/subjects', + '/update/subjects', updateResourceSubjectsRoute, zValidator('json', associateSchema), async (c) => { try { @@ -90,7 +98,7 @@ export const publicResourceSubjectsRouter = new Hono() //obtem todas as disciplinas associadas a um recurso .get( - '/:resourceId/subjects', + '/:resourceId/subjects', getSubjectsByResourceRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -113,7 +121,7 @@ export const publicResourceSubjectsRouter = new Hono() .get( - '/:resourceId/subject/:subjectId/exists', + '/:resourceId/subject/:subjectId/exists', checkAssociationExistsRoute, async (c) => { try { const resourceId = +c.req.param('resourceId'); @@ -136,7 +144,7 @@ export const publicResourceSubjectsRouter = new Hono() ) .get( - '/subject/:subjectId/resources', + '/subject/:subjectId/resources', getResourcesBySubjectRoute, async (c) => { try { const subjectId = +c.req.param('subjectId'); diff --git a/src/routes/resource.route.ts b/src/routes/resource.route.ts index 7e9e769..72bb601 100644 --- a/src/routes/resource.route.ts +++ b/src/routes/resource.route.ts @@ -13,6 +13,20 @@ import { ObjectTypeService } from "@/services/object-type.service"; import { ResourceEducationalStagesService } from "@/services/resource-educational-stages.service"; import { ResourceSubjectsService } from "@/services/resource-subjects.service"; +import { + createResourceRoute, + updateResourceRoute, + deleteResourceDataRoute, + deleteResourceRoute, + activateResourceRoute, + getAllResourcesRoute, + getAllResourcesByUserRoute, + getActiveResourcesByUserRoute, + getResourceByIdRoute, + downloadResourceRoute +} from "../documentation/resourceDescriber" + + const service = Container.get(ResourceService); const serviceStats = Container.get(ResourceStatsService); const objectTypeService = Container.get(ObjectTypeService); @@ -60,7 +74,7 @@ async function addObjectTypeNameToResource(resource: ResourceModel): Promise<Res export const resourceRouter = honoWithJwt() // create a resource - .post('/create', + .post('/create', createResourceRoute, zValidator('json', resourceSchema.input), async (c) => { @@ -95,7 +109,7 @@ export const resourceRouter = honoWithJwt() ) // update a resource - .post('/update', + .post('/update', updateResourceRoute, zValidator('json', resourceSchema.update), async (c) => { try { @@ -118,7 +132,7 @@ export const resourceRouter = honoWithJwt() }) // rota para deletar um recurso - .post('/deleteData/:id', + .post('/deleteData/:id', deleteResourceDataRoute, async (c) => { try { const id = +c.req.param('id') @@ -142,8 +156,8 @@ export const resourceRouter = honoWithJwt() } ) - // get resource by id, aceitos e nao aceitos - .get('/:id', + // get resource by id aceitos e nao aceitos + .get('/:id', deleteResourceRoute, async (c) => { try { const id = +c.req.param('id') @@ -169,7 +183,7 @@ export const resourceRouter = honoWithJwt() ) //rota para dizer que o recurso foi deletado - .post('/delete/:id', + .post('/delete/:id', activateResourceRoute, async (c) => { try { const id = +c.req.param('id') @@ -196,7 +210,7 @@ export const resourceRouter = honoWithJwt() export const publicResourceRouter = new Hono() // get all resources - .get('/all', async (c) => { + .get('/all', getAllResourcesRoute, async (c) => { try { const resource = resourceSchema.dto.array().parse(await service.findMany()); @@ -219,7 +233,7 @@ export const publicResourceRouter = new Hono() ) // get all resource by user - .get('/allResourceByUser/:user_id', async (c) => { + .get('/allResourceByUser/:user_id', getAllResourcesByUserRoute, async (c) => { try { const user_id = +c.req.param('user_id') const resources = resourceSchema.dto.array().parse(await service.allResourceByUser(user_id)); @@ -266,7 +280,7 @@ export const publicResourceRouter = new Hono() ) // get active resource by user - .get('/activeResourceByUser/:user_id', async (c) => { + .get('/activeResourceByUser/:user_id', getActiveResourcesByUserRoute, async (c) => { try { const user_id = +c.req.param('user_id') const resource = resourceSchema.dto.array().parse(await service.activeResourceByUser(user_id)) @@ -290,7 +304,7 @@ export const publicResourceRouter = new Hono() } }) - .get('/:id', async (c) => { + .get('/:id', getResourceByIdRoute, async (c) => { try { const id = +c.req.param('id'); @@ -336,7 +350,7 @@ export const publicResourceRouter = new Hono() - .get("/download/:id", async (ctx) => { + .get("/download/:id", downloadResourceRoute, async (ctx) => { const id = ctx.req.param("id"); try { diff --git a/src/routes/role.route.ts b/src/routes/role.route.ts index 7c1a892..5b941c5 100644 --- a/src/routes/role.route.ts +++ b/src/routes/role.route.ts @@ -6,10 +6,18 @@ import { roleSchemas } from "@/db/schema/roles.schema" import { createApexError, HttpStatus } from "@/services/error.service" import { z } from "zod" +import { + createRoleRoute, + getRolesRoute, + getRoleByNameRoute, + updateRoleRoute, + deleteRoleRoute +} from "../documentation/roleDescriber" + const service = Container.get(RoleService) export const roleRouter = honoWithJwt() -.post('/create', zValidator('json', roleSchemas.input), +.post('/create', createRoleRoute, zValidator('json', roleSchemas.input), async (c) => { try{ const input = await c.req.valid('json') @@ -32,7 +40,7 @@ export const roleRouter = honoWithJwt() ) } }) -.get('/roles', +.get('/roles', getRolesRoute, async (c) => { try { const roles = z.array(roleSchemas.dto).parse(await service.findMany()) @@ -42,7 +50,7 @@ export const roleRouter = honoWithJwt() return c.notFound() } }) -.get('/:name', +.get('/:name', getRoleByNameRoute, async (c) => { try { const name = c.req.param('name') @@ -54,7 +62,7 @@ export const roleRouter = honoWithJwt() return c.notFound() } }) -.post('/update', +.post('/update', updateRoleRoute, zValidator('json', roleSchemas.update), async (c) => { try { @@ -76,7 +84,7 @@ export const roleRouter = honoWithJwt() } } ) -.delete('/delete/:id', +.delete('/delete/:id', deleteRoleRoute, async (c) =>{ try{ const id: number = +c.req.param('id') diff --git a/src/routes/s3.route.ts b/src/routes/s3.route.ts index 4804696..a57af7d 100644 --- a/src/routes/s3.route.ts +++ b/src/routes/s3.route.ts @@ -3,6 +3,21 @@ import { zValidator } from "@hono/zod-validator"; import { Hono } from "hono"; import { z } from "zod"; +import { + uploadResourceRoute, + uploadThumbnailResourceRoute, + uploadThumbnailCollectionRoute, + uploadAvatarRoute, + deleteResourceRoute, + deleteAvatarRoute, + deleteThumbnailResourceRoute, + deleteThumbnailCollectionRoute, + getResourceRoute, + getThumbnailResourceRoute, + getThumbnailCollectionRoute, + getAvatarRoute +} from "../documentation/s3Describers" + const resourceUploadSchema = z.object({ id_resource: z.string().min(1, 'id_resource é obrigatório'), content_type: z.string().min(1, 'content_type é obrigatório') @@ -23,7 +38,7 @@ export const s3Routes = new Hono() //rota de enviar blob para o s3 //id_ resource é o id do recurso //faz o upload do conteudo do recurso - .post('/upload/resource', + .post('/upload/resource', uploadResourceRoute, async (ctx) => { const formData = await ctx.req.formData(); const id_resource = formData.get('id_resource'); @@ -66,7 +81,7 @@ export const s3Routes = new Hono() ) // envio de fotos de thumbnail do recurso - .post('/upload/thumbnail/resource', zValidator('json',resourceUploadSchema ), + .post('/upload/thumbnail/resource', uploadThumbnailResourceRoute, zValidator('json',resourceUploadSchema ), async (ctx) => { const { id_resource, content_type } = ctx.req.valid('json'); @@ -111,7 +126,7 @@ export const s3Routes = new Hono() // envio de fotos de thumbnail da coleção - .post('/upload/thumbnail/collection', zValidator('json',collectionUploadSchema ), + .post('/upload/thumbnail/collection', uploadThumbnailCollectionRoute, zValidator('json',collectionUploadSchema ), async (ctx) => { const { id_collection, content_type } = ctx.req.valid('json'); @@ -155,7 +170,7 @@ export const s3Routes = new Hono() // envio de fotos de thumbnail da coleção - .post('/upload/avatar', zValidator('json', userUploadSchema ), + .post('/upload/avatar', uploadAvatarRoute, zValidator('json', userUploadSchema ), async (ctx) => { const { id_user, content_type } = ctx.req.valid('json'); @@ -198,7 +213,7 @@ export const s3Routes = new Hono() } ) - .post("/delete/resource/:id", async (c) => { + .post("/delete/resource/:id", deleteResourceRoute, async (c) => { const id = c.req.param("id"); try { @@ -209,7 +224,7 @@ export const s3Routes = new Hono() } }) - .post("/delete/avatar/:id", async (c) => { + .post("/delete/avatar/:id", deleteAvatarRoute, async (c) => { const id = c.req.param("id"); try { @@ -220,7 +235,7 @@ export const s3Routes = new Hono() } }) - .post("/delete/thumbnail/resource/:id", async (c) => { + .post("/delete/thumbnail/resource/:id", deleteThumbnailResourceRoute, async (c) => { const id = c.req.param("id"); try { @@ -231,7 +246,7 @@ export const s3Routes = new Hono() } }) - .post("/delete/thumbnail/collection/:id", async (c) => { + .post("/delete/thumbnail/collection/:id", deleteThumbnailCollectionRoute, async (c) => { const id = c.req.param("id"); try { @@ -246,7 +261,7 @@ export const s3Routes = new Hono() - .get("get/resource/:id", + .get("get/resource/:id", getResourceRoute, async (ctx) => { const id = ctx.req.param("id"); @@ -280,7 +295,7 @@ export const s3Routes = new Hono() } ) - .get("get/thumbnail/resource/:id", + .get("get/thumbnail/resource/:id", getThumbnailResourceRoute, async (ctx) => { const id = ctx.req.param("id"); @@ -315,7 +330,7 @@ export const s3Routes = new Hono() - .get("get/thumbnail/collection/:id", + .get("get/thumbnail/collection/:id", getThumbnailCollectionRoute, async (ctx) => { const id = ctx.req.param("id"); @@ -348,7 +363,7 @@ export const s3Routes = new Hono() } ) - .get("get/avatar/:id", + .get("get/avatar/:id", getAvatarRoute, async (ctx) => { const id = ctx.req.param("id"); diff --git a/src/routes/subjects.route.ts b/src/routes/subjects.route.ts index ff981a9..97ff367 100644 --- a/src/routes/subjects.route.ts +++ b/src/routes/subjects.route.ts @@ -6,13 +6,20 @@ import { subjectSchema } from "@/db/schema/subjects.schema"; import { Hono } from "hono"; import { zValidator } from "@hono/zod-validator"; +import { + createSubjectRoute, + updateSubjectRoute, + deleteSubjectRoute, + getAllSubjectsRoute, + getSubjectByIdRoute +} from "../documentation/subjectsDescriber" const service = Container.get(SubjectsService) export const subjectsRouter = honoWithJwt() //rota com token - .post('/create', + .post('/create', createSubjectRoute, zValidator('json', subjectSchema.input), async (c) => { try { @@ -35,7 +42,7 @@ export const subjectsRouter = honoWithJwt() } ) - .post('/update', + .post('/update', updateSubjectRoute, zValidator('json', subjectSchema.update), async (c) => { @@ -59,7 +66,7 @@ export const subjectsRouter = honoWithJwt() } ) - .post('delete/:id', + .post('delete/:id', deleteSubjectRoute, async (c) => { try { const id = +c.req.param('id') @@ -83,7 +90,7 @@ export const subjectsRouter = honoWithJwt() export const publicSubjectsRouter = new Hono() - .get('/all', + .get('/all', getAllSubjectsRoute, async (c) => { try { const subjects = await service.findMany() @@ -103,7 +110,7 @@ export const publicSubjectsRouter = new Hono() } ) - .get('/:id', + .get('/:id', getSubjectByIdRoute, async (c) => { try { const id = +c.req.param('id') diff --git a/src/routes/submission.route.ts b/src/routes/submission.route.ts index 764a5ed..eeade6d 100644 --- a/src/routes/submission.route.ts +++ b/src/routes/submission.route.ts @@ -5,11 +5,20 @@ import { zValidator } from "@hono/zod-validator"; import { submissionSchemas } from "@/db/schema/submission.schema"; import { createApexError, HttpStatus } from "@/services/error.service"; +import { + createSubmissionRoute, + updateSubmissionRoute, + answerSubmissionRoute, + deleteSubmissionRoute, + getSubmissionByIdRoute, + getAllSubmissionsRoute +} from "../documentation/submissionsDescriber" + const service = Container.get(SubmissionService); export const submissionRouter = honoWithJwt() .post( - '/create', + '/create', createSubmissionRoute, zValidator('json', submissionSchemas.submissionInputSchema), async (c) => { try { @@ -35,7 +44,7 @@ export const submissionRouter = honoWithJwt() } ) .post( - '/update', + '/update', updateSubmissionRoute, zValidator('json', submissionSchemas.submissionUpdateSchema), async (c) => { try { @@ -63,7 +72,7 @@ export const submissionRouter = honoWithJwt() } ) .post( - '/answer', + '/answer', answerSubmissionRoute, zValidator('json', submissionSchemas.submissionUpdateSchema), async (c) => { try { @@ -89,7 +98,7 @@ export const submissionRouter = honoWithJwt() } ) - .post('/delete/:id', async (c) => { + .post('/delete/:id', deleteSubmissionRoute, async (c) => { try { const id = +c.req.param('id') @@ -111,7 +120,7 @@ export const submissionRouter = honoWithJwt() ) } }) - .get('/:id', async (c) => { + .get('/:id', getSubmissionByIdRoute, async (c) => { try { const id = +c.req.param('id') @@ -133,7 +142,7 @@ export const submissionRouter = honoWithJwt() ) } }) - .get('/', async (c) => { + .get('/', getAllSubmissionsRoute, async (c) => { try { const submissions = submissionSchemas.submissionDtoSchema.array().parse( await service.findMany() diff --git a/src/routes/uploader.route.ts b/src/routes/uploader.route.ts index 21992e8..8f2b33a 100644 --- a/src/routes/uploader.route.ts +++ b/src/routes/uploader.route.ts @@ -4,10 +4,14 @@ import { z } from 'zod' import { userSchemas, type UserInput } from '@/db/schema/user.schema' import { honoWithJwt } from '..' +import { + uploadUsersRoute +} from "../documentation/uploaderDescriber" + const service = Container.get(UploaderService) export const uploaderRouter = honoWithJwt().post( - '/users', + '/users', uploadUsersRoute, async (c) => { const body = await c.req.parseBody() const file = body['file'] diff --git a/src/routes/user-achievements.route.ts b/src/routes/user-achievements.route.ts index 526f0a3..9e5c4df 100644 --- a/src/routes/user-achievements.route.ts +++ b/src/routes/user-achievements.route.ts @@ -6,6 +6,15 @@ import { zValidator } from "@hono/zod-validator"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import { + associateUserAchievementsRoute, + removeUserAchievementRoute, + updateUserAchievementsRoute, + getUserAchievementsRoute, + checkUserAchievementExistenceRoute, + getUsersByAchievementRoute +} from "../documentation/user-achievementsDescriber" + const associateSchema = z.object({ userId: z.number(), achievementIds: z.array(z.number()), @@ -14,7 +23,7 @@ const associateSchema = z.object({ const service = Container.get(UserAchievementsService); export const userAchievementsRouter = honoWithJwt() - .post('/associate', zValidator('json', associateSchema), + .post('/associate', associateUserAchievementsRoute, zValidator('json', associateSchema), async (c) => { try { const { userId, achievementIds } = await c.req.valid('json'); @@ -34,7 +43,7 @@ export const userAchievementsRouter = honoWithJwt() } } ) - .post('/:userId/delete/achievement/:achievementId', + .post('/:userId/delete/achievement/:achievementId', removeUserAchievementRoute, async (c) => { try { const userId = +c.req.param('userId'); @@ -55,7 +64,7 @@ export const userAchievementsRouter = honoWithJwt() } } ) - .post('/update', zValidator('json', associateSchema), + .post('/update', updateUserAchievementsRoute, zValidator('json', associateSchema), async (c) => { try { const { userId, achievementIds } = await c.req.valid('json'); @@ -77,7 +86,7 @@ export const userAchievementsRouter = honoWithJwt() ) export const publicUserAchievementsRoute = new Hono() - .get('/:userId/achievements', + .get('/:userId/achievements', getUserAchievementsRoute, async (c) => { try { const userId = +c.req.param('userId'); @@ -97,7 +106,7 @@ export const publicUserAchievementsRoute = new Hono() } } ) - .get('/:userId/achievements/:achievementId/exists', + .get('/:userId/achievements/:achievementId/exists', checkUserAchievementExistenceRoute, async (c) => { try { const userId = +c.req.param('userId'); @@ -118,7 +127,7 @@ export const publicUserAchievementsRoute = new Hono() } } ) - .get('/achievements/:achievementId/users', + .get('/achievements/:achievementId/users', getUsersByAchievementRoute, async (c) => { try { const achievementId = +c.req.param('achievementId'); diff --git a/src/routes/user-collection.route.ts b/src/routes/user-collection.route.ts index 5ee498b..cea0af8 100644 --- a/src/routes/user-collection.route.ts +++ b/src/routes/user-collection.route.ts @@ -6,6 +6,15 @@ import { zValidator } from "@hono/zod-validator"; import { createApexError, HttpStatus } from "@/services/error.service"; import { Hono } from "hono"; +import { + associateUserCollectionsRoute, + removeUserCollectionRoute, + getUserCollectionsRoute, + checkUserCollectionExistenceRoute, + getUsersByCollectionRoute, + getCollectionOwnerRoute +} from "../documentation/user-collectionDescriber" + const associateSchema = z.object({ userId: z.number(), collectionIds: z.array(z.number()), @@ -14,7 +23,7 @@ const associateSchema = z.object({ const service = Container.get(UserCollectionsService); export const userCollectionsRoute = honoWithJwt() - .post('/associate', zValidator('json', associateSchema), + .post('/associate', associateUserCollectionsRoute, zValidator('json', associateSchema), async (c) => { try { const {userId, collectionIds } = await c.req.valid('json'); @@ -34,7 +43,7 @@ export const userCollectionsRoute = honoWithJwt() } } ) - .post('/:userId/delete/:collectionId', + .post('/:userId/delete/:collectionId', removeUserCollectionRoute, async (c) => { try { const userid = +c.req.param('userId'); @@ -57,7 +66,7 @@ export const userCollectionsRoute = honoWithJwt() ) export const publicUserCollectionsRoutes = new Hono() - .get('/:userId/collections', + .get('/:userId/collections', getUserCollectionsRoute, async (c) => { try { const userId = +c.req.param('userId'); @@ -77,7 +86,7 @@ export const publicUserCollectionsRoutes = new Hono() } } ) - .get('/:userId/collections/:collectionId/exists', + .get('/:userId/collections/:collectionId/exists', checkUserCollectionExistenceRoute, async (c) => { try { const userId = +c.req.param('userId'); @@ -98,7 +107,7 @@ export const publicUserCollectionsRoutes = new Hono() } } ) - .get(':collectionId/users', + .get(':collectionId/users', getUsersByCollectionRoute, async (c) => { try { const collectionId = +c.req.param('collectionId'); @@ -118,7 +127,7 @@ export const publicUserCollectionsRoutes = new Hono() } } ) - .get('/:id/owner', + .get('/:id/owner', getCollectionOwnerRoute, async (c) => { try { const id = +c.req.param('id'); diff --git a/src/routes/user-institution.route.ts b/src/routes/user-institution.route.ts index 823a73b..a053519 100644 --- a/src/routes/user-institution.route.ts +++ b/src/routes/user-institution.route.ts @@ -10,12 +10,20 @@ import { userSchemas, type UserProfile } from "@/db/schema/user.schema"; import { InstitutionService } from "@/services/institution.service"; import { institutionSchemas, type InstitutionModel } from "@/db/schema/institution.schema"; +import { + assignUserToInstitutionRoute, + getUserInstitutionsRoute, + getInstitutionUsersRoute, + revokeUserInstitutionRoute +} from "../documentation/user-institutionDescribers" + + const service = Container.get(UserInstitutionRelationService) const userService = Container.get(UserService) const institutionService = Container.get(InstitutionService) export const userInstitutionRouter = honoWithJwt() - .post('/assign', zValidator('json', userInstitutionRelationSchemas.input), + .post('/assign', assignUserToInstitutionRoute, zValidator('json', userInstitutionRelationSchemas.input), async (c) => { try{ const input = await c.req.valid('json') @@ -46,7 +54,7 @@ export const userInstitutionRouter = honoWithJwt() ) } }) - .get('/institutions/user/:user_id', async (c) =>{ + .get('/institutions/user/:user_id', getUserInstitutionsRoute, async (c) =>{ try{ const user_id = +c.req.param('user_id') const institutions_by_user = z.array(userInstitutionRelationSchemas.model).parse(await service.findByUserId(user_id)) @@ -64,7 +72,7 @@ export const userInstitutionRouter = honoWithJwt() return c.notFound() } }) - .get('/users/institution/:institution_id', async (c) =>{ + .get('/users/institution/:institution_id', getInstitutionUsersRoute, async (c) =>{ try{ const institution_id = +c.req.param('institution_id') const users_by_institution = z.array(userInstitutionRelationSchemas.model).parse(await service.findByInstitutionId(institution_id)) @@ -84,7 +92,7 @@ export const userInstitutionRouter = honoWithJwt() return c.notFound() } }) - .post('/revoke', + .post('/revoke', revokeUserInstitutionRoute, zValidator('json', userInstitutionRelationSchemas.input), async (c) =>{ try{ diff --git a/src/routes/user-item.route.ts b/src/routes/user-item.route.ts index ce11239..bf030d9 100644 --- a/src/routes/user-item.route.ts +++ b/src/routes/user-item.route.ts @@ -10,12 +10,19 @@ import { ItemsService } from "@/services/items.service"; import { itemsSchema, type ItemsModel } from "@/db/schema/item.schema"; import { UserItemRelationService } from "@/services/user-item.relation.service"; +import { + createUserItemAssociationRoute, + getItemsByUserRoute, + getUsersByItemRoute, + deleteUserItemAssociationRoute +} from "../documentation/user-itemDescriber" + const service = Container.get(UserItemRelationService) const userService = Container.get(UserService) const itemService = Container.get(ItemsService) export const userItemRouter = honoWithJwt() - .post('/create', zValidator('json', userItemRelationSchemas.input), + .post('/create', createUserItemAssociationRoute, zValidator('json', userItemRelationSchemas.input), async (c) => { try{ const input = await c.req.valid('json') @@ -43,7 +50,7 @@ export const userItemRouter = honoWithJwt() ) } }) - .get('/items/user/:user_id', async (c) =>{ + .get('/items/user/:user_id', getItemsByUserRoute, async (c) =>{ try{ const user_id = +c.req.param('user_id') const items_by_user = z.array(userItemRelationSchemas.model).parse(await service.findByUserId(user_id)) @@ -61,7 +68,7 @@ export const userItemRouter = honoWithJwt() return c.notFound() } }) - .get('/users/item/:item_id', async (c) =>{ + .get('/users/item/:item_id', getUsersByItemRoute, async (c) =>{ try{ const item_id = +c.req.param('item_id') const users_by_item = z.array(userItemRelationSchemas.model).parse(await service.findByItemId(item_id)) @@ -81,7 +88,7 @@ export const userItemRouter = honoWithJwt() return c.notFound() } }) - .delete('/delete', + .delete('/delete', deleteUserItemAssociationRoute, zValidator('json', userItemRelationSchemas.input), async (c) =>{ try{ diff --git a/src/routes/user-role.route.ts b/src/routes/user-role.route.ts index 8bf7437..729eefe 100644 --- a/src/routes/user-role.route.ts +++ b/src/routes/user-role.route.ts @@ -10,12 +10,19 @@ import { userSchemas, type UserProfile } from "@/db/schema/user.schema"; import { RoleService } from "@/services/role.service"; import { roleSchemas, type RoleModel } from "@/db/schema/roles.schema"; +import { + assignUserRoleRoute, + getRolesByUserRoute, + getUsersByRoleRoute, + revokeUserRoleRoute +} from "../documentation/user-roleDescribers" + const service = Container.get(UserRoleRelationService) const userService = Container.get(UserService) const roleService = Container.get(RoleService) export const userRoleRouter = honoWithJwt() - .post('/assign', zValidator('json', userRoleRelationSchemas.input), + .post('/assign', assignUserRoleRoute, zValidator('json', userRoleRelationSchemas.input), async (c) => { try{ const input = await c.req.valid('json') @@ -43,7 +50,7 @@ export const userRoleRouter = honoWithJwt() ) } }) - .get('/roles/user/:user_id', async (c) =>{ + .get('/roles/user/:user_id', getRolesByUserRoute, async (c) =>{ try{ const user_id = +c.req.param('user_id') const roles_by_user = z.array(userRoleRelationSchemas.model).parse(await service.findByUserId(user_id)) @@ -61,7 +68,7 @@ export const userRoleRouter = honoWithJwt() return c.notFound() } }) - .get('/users/role/:role_id', async (c) =>{ + .get('/users/role/:role_id', getUsersByRoleRoute, async (c) =>{ try{ const role_id = +c.req.param('role_id') const users_by_role = z.array(userRoleRelationSchemas.model).parse(await service.findByRoleId(role_id)) @@ -81,7 +88,7 @@ export const userRoleRouter = honoWithJwt() return c.notFound() } }) - .post('/revoke', + .post('/revoke', revokeUserRoleRoute, zValidator('json', userRoleRelationSchemas.input), async (c) =>{ try{ diff --git a/src/routes/user-stats.route.ts b/src/routes/user-stats.route.ts index 0e53ee7..e477678 100644 --- a/src/routes/user-stats.route.ts +++ b/src/routes/user-stats.route.ts @@ -5,11 +5,19 @@ import { zValidator } from "@hono/zod-validator"; import { userStatsSchemas } from "@/db/schema/user-stats.schema"; import { createApexError, HttpStatus } from "@/services/error.service"; +import { + updateUserStatsRoute, + deleteUserStatsRoute, + updateUserStatsCommentsRoute, + getAllUserStatsRoute, + getUserStatsByIdRoute +} from "../documentation/user-statsDescribers" + const service = Container.get(UserStatsService) export const userStatsRouter = honoWithJwt() /* Update é uma rota própria ou vai estar embutida nas rotas das devidas estatisticas */ - .post('/update', + .post('/update', updateUserStatsRoute, zValidator('json', userStatsSchemas.update), async (c) => { try { @@ -35,7 +43,7 @@ export const userStatsRouter = honoWithJwt() }) /* Nao deveria ter como deletar um user stats sozinho */ - .post('/delete/:id', + .post('/delete/:id', deleteUserStatsRoute, zValidator('json', userStatsSchemas.update), async (c) => { try { @@ -58,7 +66,7 @@ export const userStatsRouter = honoWithJwt() } }) - .post('/updateComments/:id', + .post('/updateComments/:id', updateUserStatsCommentsRoute, async (c) => { try { const id = +c.req.param('id') @@ -81,7 +89,7 @@ export const userStatsRouter = honoWithJwt() ) /* Obtém todos os user stats */ - .get('/all', async (c) => { + .get('/all', getAllUserStatsRoute, async (c) => { try { const stats = await service.getAll() return c.json(stats) @@ -100,7 +108,7 @@ export const userStatsRouter = honoWithJwt() }) /* Obtém um user stats específico */ - .get('/:id', async (c) => { + .get('/:id', getUserStatsByIdRoute, async (c) => { try { const id = +c.req.param('id') const stat = await service.getById(id) diff --git a/src/routes/user.route.ts b/src/routes/user.route.ts index 2b928dd..38d4c77 100644 --- a/src/routes/user.route.ts +++ b/src/routes/user.route.ts @@ -9,13 +9,26 @@ import { followRelationSchemas } from '@/db/relations/followers.relation' import { UserStatsService } from '@/services/user-stats.service' import { FollowRelationService } from '@/services/follow.relation.service' +import { + followUserRoute, + unfollowUserRoute, + getFollowsRoute, + getFollowersRoute, + getUsersRoute, + getUserByUsernameRoute, + updateUserRoute, + confirmUserRoute, + reactivateUserRoute, + deleteUserRoute, + systemDeleteUserRoute +} from "../documentation/userDescriber" const service = Container.get(UserService) const followService = Container.get(FollowRelationService) const userStatsService = Container.get(UserStatsService) export const userRouter = honoWithJwt() - .post('/follow/:user_to_follow_id', + .post('/follow/:user_to_follow_id', followUserRoute, async (c) => { try { const follower_id = c.get('jwtPayload').id; @@ -54,7 +67,7 @@ export const userRouter = honoWithJwt() } } ) - .post('/unfollow', + .post('/unfollow', unfollowUserRoute, zValidator('json', followRelationSchemas.input), async (c) => { try { @@ -95,7 +108,7 @@ export const userRouter = honoWithJwt() } } ) - .get('/follows/:id', // check who this id follows + .get('/follows/:id', getFollowsRoute,// check who this id follows async (c) => { try { const id = +c.req.param('id') @@ -113,7 +126,7 @@ export const userRouter = honoWithJwt() return c.notFound() } }) - .get('/followers/:id', //check who follows this id + .get('/followers/:id', getFollowersRoute,//check who follows this id async (c) => { try { const id = +c.req.param('id') @@ -132,7 +145,7 @@ export const userRouter = honoWithJwt() return c.notFound() } }) - .get('/users', async (c) => { + .get('/users', getUsersRoute, async (c) => { const p = c.get('jwtPayload') console.log({ p }) @@ -143,7 +156,7 @@ export const userRouter = honoWithJwt() return c.json({ users: ret }) }) - .get('/:username', async (c) => { + .get('/:username', getUserByUsernameRoute, async (c) => { try { const username = c.req.param('username') const user = await service.findByUsername(username) @@ -154,7 +167,7 @@ export const userRouter = honoWithJwt() return c.notFound() } }) - .post('/update', + .post('/update', updateUserRoute, zValidator('json', userSchemas.userUpdateSchema), async (c) => { try { @@ -180,7 +193,7 @@ export const userRouter = honoWithJwt() } }) - .post('/confirmation/:email', + .post('/confirmation/:email', confirmUserRoute, async (c) => { try { const email: string = c.req.param('email') @@ -208,7 +221,7 @@ export const userRouter = honoWithJwt() ) } }) - .post('/reactivate/:email', + .post('/reactivate/:email', reactivateUserRoute, async (c) => { try { const email: string = c.req.param('email') @@ -238,7 +251,7 @@ export const userRouter = honoWithJwt() ) } }) - .post('/delete/:id', + .post('/delete/:id', deleteUserRoute, async (c) => { try { const id: number = +c.req.param('id') @@ -268,7 +281,7 @@ export const userRouter = honoWithJwt() ) } }) - .post('/delete/system/:id', + .post('/delete/system/:id', systemDeleteUserRoute, async (c) => { try { const id: number = +c.req.param('id') -- GitLab