From 781962dce069247478df1a40bc8227583f758204 Mon Sep 17 00:00:00 2001 From: xidongdong-153 Date: Sun, 3 Dec 2023 18:06:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=95=B0=E6=8D=AE=E5=85=B3=E8=81=94?= =?UTF-8?q?=E4=B8=8E=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE=E5=B5=8C=E5=A5=97?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E7=9A=84=E5=88=86=E7=B1=BB=E5=92=8C=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E5=AE=9E=E7=8E=B0=20-=20=E5=AE=9E=E7=8E=B0=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E3=80=81=E8=AF=84=E8=AE=BA=E3=80=81=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=20-=20=E4=BD=BF=E7=94=A8=E4=BA=86Materialize?= =?UTF-8?q?d=20Path=E5=AE=9E=E7=8E=B0=E6=A0=91=E5=BD=A2=E5=B5=8C=E5=A5=97?= =?UTF-8?q?=20-=20=E5=AF=B9=E5=88=86=E7=B1=BB=E3=80=81=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E3=80=81=E6=A0=87=E7=AD=BE=E7=9A=84=E5=AD=98=E5=82=A8=E5=BA=93?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E8=87=AA=E5=AE=9A=E4=B9=89=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/database4.db | Bin 20480 -> 77824 bytes back/database6.db | Bin 61440 -> 73728 bytes package.json | 14 +- pnpm-lock.yaml | 700 +++++++++--------- src/config/database.config.ts | 2 +- src/modules/content/constants.ts | 1 + src/modules/content/content.module.ts | 24 +- .../controllers/category.controller.ts | 95 +++ .../content/controllers/comment.controller.ts | 78 ++ src/modules/content/controllers/index.ts | 3 + .../content/controllers/post.controller.ts | 5 +- .../content/controllers/tag.controller.ts | 92 +++ src/modules/content/dtos/category.dto.ts | 63 ++ src/modules/content/dtos/comment.dto.ts | 61 ++ src/modules/content/dtos/index.ts | 3 + src/modules/content/dtos/post.dto.ts | 21 + src/modules/content/dtos/tag.dto.ts | 60 ++ .../content/entities/category.entity.ts | 57 ++ .../content/entities/comment.entity.ts | 53 ++ src/modules/content/entities/index.ts | 3 + src/modules/content/entities/post.entity.ts | 82 +- src/modules/content/entities/tag.entity.ts | 29 + .../repositories/category.repository.ts | 81 ++ .../repositories/comment.repository.ts | 137 ++++ src/modules/content/repositories/index.ts | 3 + .../content/repositories/post.repository.ts | 14 +- .../content/repositories/tag.repository.ts | 18 + .../content/services/category.service.ts | 129 ++++ .../content/services/comment.service.ts | 123 +++ src/modules/content/services/index.ts | 4 +- src/modules/content/services/post.service.ts | 104 ++- src/modules/content/services/tag.service.ts | 63 ++ .../content/subscribers/post.subscriber.ts | 2 +- src/modules/database/helpers.ts | 47 +- 34 files changed, 1756 insertions(+), 415 deletions(-) create mode 100644 src/modules/content/controllers/category.controller.ts create mode 100644 src/modules/content/controllers/comment.controller.ts create mode 100644 src/modules/content/controllers/tag.controller.ts create mode 100644 src/modules/content/dtos/category.dto.ts create mode 100644 src/modules/content/dtos/comment.dto.ts create mode 100644 src/modules/content/dtos/tag.dto.ts create mode 100644 src/modules/content/entities/category.entity.ts create mode 100644 src/modules/content/entities/comment.entity.ts create mode 100644 src/modules/content/entities/tag.entity.ts create mode 100644 src/modules/content/repositories/category.repository.ts create mode 100644 src/modules/content/repositories/comment.repository.ts create mode 100644 src/modules/content/repositories/tag.repository.ts create mode 100644 src/modules/content/services/category.service.ts create mode 100644 src/modules/content/services/comment.service.ts create mode 100644 src/modules/content/services/tag.service.ts diff --git a/back/database4.db b/back/database4.db index 6f8106d1c2e47479f731ba9f586db14457b80ff1..06686f64815a923115dd607ee4707c80fd937894 100644 GIT binary patch literal 77824 zcmeI4?{6GO8OQH@{+-yHQouxzvT++6L$=J$?2p+K2#n(tlf(&$tu{!NyFU{vah%#0 z(!3y!p-n(}kydKbl=g++G$~5jRHBuds#V}GsDzLxLPDa=*?t2Oyx|4BVCH`8-TLn0 zOC>~OzANwA_w4M>cRtVa%S`|p0Qes$lN+F!oB!5#b6?d2ll zqJq(&e^7n)p=}*~yLYG0vz+T43)i^A8mGHTlE;U>w`b&DkmXU~rKP9@b1N)7KDJ2-w|Xmo5`?ccR~QV+Rr=$zUC2~6UIHVHyKvOJrF z{pzlL2S!F88&h|W9I8Mms~A)djO-dYFfukgaxkvD=q8D9N^%ppcaH2C5&jt-IygME zb3|Gu_V1J)D_M4^s}wa31>QhW?528xWRTR+Gqz718Xg}Naw>{q+YWXAfziD~2M*P5 zc@65p!JglxzOc|XnNAfVdhY3Cq6?XP@@wsVPw!6J+>^PPLYX*<8-(GczD5}JENpy4 zq>-Lp_(q&Yf#tdpH+9>0O`AHl%YEh=M!gdN8;42Trw~quQ}n)icW4-Zr7xSOPCwF)V7Ju9mWV@oO)KIbGIg0;~Umb z(;7O}xf@WWHJy@o+4{2_q};oIqzmWN}UdX8GKWi0>yvwAPAfd}RX>xvAVSnR?Dc?R|R( z)=Ir%N0aPUGS42_($P0Ckp6{|NVr1Tgx;3=X%;(1^!Me&DU3@EGOQ@MTry4}kpcyx zYA$>xS8Xl(yL^Qxcr-kHYGyVNy}B$c47t-MMEsWq#rWc?6cZ71G?+PcyqIbyy<<~z zM~Vqrx=7r_zlRL>XG4+Li43n(Z8`b34;-I4H83dC{NxE~{1g|~?^8-ye0r^Z!ywdV zmd&{?dX303oq*6t7($2E45`KOLEiFH^c)9AiVq`oJC5&srM>TwJC@Bwu4I-};2PMZ<%eniAB_>hV{(H}18^!JaB_{_zJ)8*30=n7> zOF2qwPcM)GF_wsF(V=)OY5a8F_%?+qH`IO^j8=6F1Q z4E6|rc6Wc2Qlj2`Z_x8ekGJtJ8=uGCj`!P_e|JZ zQ>iVfPR3HHz!qx)#ELZ2twl;G%inr?>DBAyWff`BbX}uVB~F&HtjX(`&U7W}_Z-U-3)H&i2h7$CJK&lp zW{R3gsOLqx?pvXMuk{m^@GLd6%!=!;m=@YPdnWd7mH@gW01|Q|h`dO%L|cUb+tXah z!{x-&eV0iI!^4lMOD`=hU%Hro?SPJzRR{!phA{ zOP9|tUthFWZoj;A<>vB@8}{=i0C6-;*l)^fjeHc04o+?H6ei13Lx`s2?63gCxa8$)dKGOLVz8K#v7r)sB@3m zCSjggEx?Qgm}?23S<_r4K$_-T69QP|_|!8*>^scVjKC$DSiTl95t`iR1~YY*5Maat zj3xxECLjcm`AkB9?orQV9@oTru^?a*s(FEHXvDGz4QLQjE8zkb3t(#tFp9}gi2<55 ztofFtfY1wcLS2oA5!DPPvVw=y)O?FtrZ2h!;_+%1&{zO%LV#Z50z+TuOP3UUyO52P zh>AEdHQlu&d9G_t5EvRKkzv}586LH&73i@7{Voc|i)mn(kLuL?QH_jJKT$!$vWD3$ z`t$DI!>Qg|$~onxvO)Psd9wH8-sgJ{E5?1&)k7u-fB*=900@8p2!H?xfB*=9z-NcR z_RK`OnKig>S+JSKvMyP$nMJKmS+JR9rw&=LndPB&S+JR9oHkjondO$&Le)(yi)4x# z*IvG88OTg@HM7c4nExwZPbq&=eydzlE-TL}v&vJ-nDQ-Q#0CN&00JNY0w4eaAOHd& z00JNY0{?de9>@%&tKXBiJ62n)_SF`%ZMDT{U2S2R)fU>aDKpSjU6;N&W2ftWKB&9l znXX4Nd(&%uq^GmwM)_U-Ua`xscWe;5B6e&b00JNY0w4eaAOHd&00JNY0wD0eCm`Pm z$NT?{zP`}(`~UL$|KgwiVFLjW009sH0T2KI5C8!X009sH0T5Wn1mx%cG5=r34o1^J z00ck)1V8`;KmY_l00ck)1VBI#!2BO!00JNY0w4eaAOHd&00JNY0w4ea>z@EV|G)ly zj240b2!H?xfB*=900@8p2!H?xfB@$Ihyf4)0T2KI5C8!X009sH0T2KI5Lo{N@cIAs z?_;zO1V8`;KmY_l00ck)1V8`;KmY_V|3?gf00@8p2!H?xfB*=900@8p2!O!)CxH3? z`u8zf2m&Ag0w4eaAOHd&00JNY0w4eanExXNKmY_l00ck)1V8`;KmY_l00cl_{S%P$ z|89k(l)ozuRNnXrF>r)v4H>xfB*=900@8p2!OzSLf}ky&xE}-mD-Z( zWGs~mY-%%NMVjexLo-a%*E|*(niYh$=TbNDh?Rf;Z2sDXrOR*KdH3wf2XE%zxO(T- zA|;gNZ@sh)=N_GmD3>bSIMx~@^G5+}=8*5q|eXSx#gdyZu}wySG?z--O11Fm`0 z<(f&T=S8~iTcLli^%IrwEH$&titDeK7TP*{CiZTY0JGT)uI`UcPz0XiEqnjz*ajptCHo3j&g+`SyeWJ&YVfcP!1MOb8%E zAn*-K3k{1$wg?37c+~=|Sb)`p08%S}%(o>3grcFGxULp(-xmVxNHpFE1xB5F%r*)0 z%xVEBFCqmA!6TQre*{#(YV7zOoS%)xxq}GB?K6;0HX;3 zs|g4JWImG+pnKFana4GYb3wo+RPzGY(1>Lb8qgr5R>B1=7QogPU=)*~5(6}ASo1AO z0ihS@gt{6JBdQrpWCahYsreSQOkZ>d#N*X2ps@hD+?QeL_+=#~I}-LvsI({S6%V#0 z>=m%B345iznS`Cj99q7ZVO_BvJ+^meHm8f}+S!}gnwC*f?8Um1FT0BK{|{5jzmOP z%wk!WEZEGVR;Mi3%(7F5EZEHQP`fPH%rZ`!EZEF)OKYL(CYD7qMU9P@FIqFHbhkWo z$wQ|+bjU-yJhaI}t2|`np(T?^73Tk`O)1R(KRdYsB_IF-AOHd&00JNY0w4eaAOHd& zuoeM1ufM1He~-MQnEzt~0T2KI5C8!X009sH0T2KI5C8!XSic1D|NqvnZ_zRk009sH V0T2KI5C8!X009sH0T3t?_zw-M2sZ!# delta 717 zcmZp8z|ydQae}m<5Ca1PD-<&UY2JxC#-c(DdPNI(fjlNY1qQxoJ_X*#ypK04Dy-o) zXm;Ra7q_-%Y!fd@Ov*_uNzEC{RGWOCgP*He3242#I%6C2<{uoh7-cni zxt}m_alK&R&)|E>m&N;G8M5L?&KK-bVh!NAhW x$i&LX2#e65@bYA!mnDGl0s@Rc%)-B(pPT;%e=Of4ev{3L1`GK%@APwL1OQLnuD$>O diff --git a/back/database6.db b/back/database6.db index a22200a00b35bc7b6e6c04eb28376b2828f6902b..c45dabe338a04f52a94a426f22abac1a16369c5c 100644 GIT binary patch delta 3345 zcma)8du&_P8NW~8>)5`>K~+tNQai@TE$dD0`{6VxX$Vr4Hmrr)z%-QJ=ax1P>bQ() z(j2RW7N(AttA?_5B{0w`jnzzM8i7HX_6HIhgGu`Xr0m6-G}Xj1O_jDk7}~jZV&cAJ z>)s=u-}%n>`37s7|B-q7d7DPkY~5k7?drsZ+$yXXpb;8cHm%aOhul^7gEpD6l!Kw`UX z7Tj-4<;UFVf;;i(RNl;gd(@tqEVz?}(J#kZ2lfv3KRB3ruz$y{!BqN7Q-7TL<%YE5 zj=Kfd=`W;H4)j+Tn{fS3x}7aWw^50mJX-q7*rek=zVqIPMjgd8Jx%6S+muy7S53_p zO-XV@#~-5Z7~VO2@8CnJ^sOz^sr!dh>FZUdQ=8M1=7gKxk{ajjyHH#S(`rIG>q1PbCSE0L};#j)Fi;kygn&60vt(hKY+YKs+>s8!*=9-GOT29qf6vhhUL8NrW zKNr;^;OIAHDv`~iPXYgL(Im=L(AX?`MJ z$FMl&?~Zn$Tl|m6KkBetx<_~vsV;Q-(D+!v9W@UZreObwv|0`a3#JuhF)V^3DTwhr z`ouwBqPC!|J|EiX7pU?L)l@p^?+_bWAO#8DL%>zA3>Ls2z;PBbmd%3~!BgN6co^z`pYcB(-e25^^Jq=j^6TfX9D8Q*o#TtIyiF%? z5naCc{L-27p1Xyv@}N* zU2bvq?4>t?r<)**c0}epO_4R16*=ByC0&(SoilA#v@BhQ=c%h{Dh&7KpS>gc-sm}o z1QG&122X-VKp9AoJPr13#tpO?YBDfvhL8vh{qfO^e_?7LjR6k<72s7`_kRuS9l~(K z5L7|dI7?*(MS=_E1&%d&Sz;~Qa&?W&0B9&1T1&$_TLdy=GCs(0z_xy7^Rm&>nT zdTZv={PD%pPp|yy1^5V@AhNu`azct%a-5hGxn|ZN7X{r`bxmMh*|S;6vo%)tbc>Za z*>Y4_5*^L%YDQR>+=Qpn27)rOqA`N3Sr>0by!gX&i!Yy8E+1XK@FomF!wUJFq&Bs} zTgwX7R#=(;{tyZip&aC1xzc*_$AArTq!|V*iyPq}#?PK4Zs4MsG^x4x(P-w`*8&%A zkd7`)$A`fKy9uK?8BOu*g5IiH{e_D#A8WNHRcq}@n2-O6RsQ!u54yLRfY*xc*1KEX z+*+|6`aLYR5BF`LBk=V1m__EE*u_|1^h`7n$wTH{kz$FXW5xiFARP!TilsE{W!HKJ z(o7^8E{f|9VfZa`(3$$y$*AJiLWq+YN1Bw(>A+Bmd5PzvF<3GP` zI9|Flv~Ivasx{u$8}%RQk(kvwlykh0lO+GeB=keBGlzb(`=OuSVNfI*aTDTgeb9dz zj~REZ5kvn^2NU{s`vcoDOc7f@$-mlH010#z>J5u5IKi6 zP04`=gsIA=t(dZ4t$va;W7@@$l#zhMeoON1Fb@x&HX5q%&F+l9KN+G09P$Rk6UnW# xfUS1sl3T+fN*NthTbKd)qF}2Jf<9D~!fqc{{CV?5ckkG;Rj31(b2;aH-}%lr zGky1@zSrV#px_W81ZIxFMfrQdg;1TOyR~ zYN%GMRISVU!T1eTvVi&;H zHPt7#)|YKfuH9H)w#Zdp!{`4G9Tn=T@Uv1UtXqtI!dhKCs#T~~JWh|*VZXKnqk;$X zs)-$fflsx|xWfa^uX=~1)cO_c$Iy%b9S=(Lba|kuK(#_4I@E^eq*5wjgawd+>b#Wl z)P>?cWl-VjpH0t?9a#}mt=d}Jug<=VZya`4nDrJPc>|~Z_2V0Fi=X>SWDp5FhTota zmV@Y&w|-zKmfpg#mQ3#E`~ zdtJooVQKE#g;enLb+v*DOCUf diff --git a/package.json b/package.json index 8cfb75d..aed6dce 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@nestjs/platform-fastify": "^10.2.10", "@nestjs/swagger": "^7.1.16", "@nestjs/typeorm": "^10.0.1", - "better-sqlite3": "^9.1.1", + "better-sqlite3": "^9.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "deepmerge": "^4.3.1", @@ -41,18 +41,18 @@ "@nestjs/schematics": "^10.0.3", "@nestjs/testing": "^10.2.10", "@swc/cli": "^0.1.63", - "@swc/core": "^1.3.99", + "@swc/core": "^1.3.100", "@types/jest": "^29.5.10", "@types/lodash": "^4.14.202", - "@types/node": "^20.10.0", + "@types/node": "^20.10.2", "@types/sanitize-html": "^2.9.5", "@types/supertest": "^2.0.16", - "@typescript-eslint/eslint-plugin": "^6.12.0", - "@typescript-eslint/parser": "^6.12.0", - "eslint": "^8.54.0", + "@typescript-eslint/eslint-plugin": "^6.13.1", + "@typescript-eslint/parser": "^6.13.1", + "eslint": "^8.55.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", - "eslint-config-prettier": "^9.0.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.29.0", "eslint-plugin-jest": "^27.6.0", "eslint-plugin-prettier": "^5.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52ba9cf..718053e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,8 +17,8 @@ dependencies: specifier: ^10.0.1 version: 10.0.1(@nestjs/common@10.2.10)(@nestjs/core@10.2.10)(reflect-metadata@0.1.13)(rxjs@7.8.1)(typeorm@0.3.17) better-sqlite3: - specifier: ^9.1.1 - version: 9.1.1 + specifier: ^9.2.0 + version: 9.2.0 class-transformer: specifier: ^0.5.1 version: 0.5.1 @@ -45,12 +45,12 @@ dependencies: version: 2.11.0 typeorm: specifier: ^0.3.17 - version: 0.3.17(better-sqlite3@9.1.1)(ts-node@10.9.1) + version: 0.3.17(better-sqlite3@9.2.0)(ts-node@10.9.1) devDependencies: '@nestjs/cli': specifier: ^10.2.1 - version: 10.2.1(@swc/cli@0.1.63)(@swc/core@1.3.99) + version: 10.2.1(@swc/cli@0.1.63)(@swc/core@1.3.100) '@nestjs/schematics': specifier: ^10.0.3 version: 10.0.3(chokidar@3.5.3)(typescript@5.2.2) @@ -59,10 +59,10 @@ devDependencies: version: 10.2.10(@nestjs/common@10.2.10)(@nestjs/core@10.2.10) '@swc/cli': specifier: ^0.1.63 - version: 0.1.63(@swc/core@1.3.99) + version: 0.1.63(@swc/core@1.3.100) '@swc/core': - specifier: ^1.3.99 - version: 1.3.99 + specifier: ^1.3.100 + version: 1.3.100 '@types/jest': specifier: ^29.5.10 version: 29.5.10 @@ -70,8 +70,8 @@ devDependencies: specifier: ^4.14.202 version: 4.14.202 '@types/node': - specifier: ^20.10.0 - version: 20.10.0 + specifier: ^20.10.2 + version: 20.10.2 '@types/sanitize-html': specifier: ^2.9.5 version: 2.9.5 @@ -79,38 +79,38 @@ devDependencies: specifier: ^2.0.16 version: 2.0.16 '@typescript-eslint/eslint-plugin': - specifier: ^6.12.0 - version: 6.12.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0)(typescript@5.3.2) + specifier: ^6.13.1 + version: 6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.55.0)(typescript@5.3.2) '@typescript-eslint/parser': - specifier: ^6.12.0 - version: 6.12.0(eslint@8.54.0)(typescript@5.3.2) + specifier: ^6.13.1 + version: 6.13.1(eslint@8.55.0)(typescript@5.3.2) eslint: - specifier: ^8.54.0 - version: 8.54.0 + specifier: ^8.55.0 + version: 8.55.0 eslint-config-airbnb-base: specifier: ^15.0.0 - version: 15.0.0(eslint-plugin-import@2.29.0)(eslint@8.54.0) + version: 15.0.0(eslint-plugin-import@2.29.0)(eslint@8.55.0) eslint-config-airbnb-typescript: specifier: ^17.1.0 - version: 17.1.0(@typescript-eslint/eslint-plugin@6.12.0)(@typescript-eslint/parser@6.12.0)(eslint-plugin-import@2.29.0)(eslint@8.54.0) + version: 17.1.0(@typescript-eslint/eslint-plugin@6.13.1)(@typescript-eslint/parser@6.13.1)(eslint-plugin-import@2.29.0)(eslint@8.55.0) eslint-config-prettier: - specifier: ^9.0.0 - version: 9.0.0(eslint@8.54.0) + specifier: ^9.1.0 + version: 9.1.0(eslint@8.55.0) eslint-plugin-import: specifier: ^2.29.0 - version: 2.29.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0) + version: 2.29.0(@typescript-eslint/parser@6.13.1)(eslint@8.55.0) eslint-plugin-jest: specifier: ^27.6.0 - version: 27.6.0(@typescript-eslint/eslint-plugin@6.12.0)(eslint@8.54.0)(jest@29.7.0)(typescript@5.3.2) + version: 27.6.0(@typescript-eslint/eslint-plugin@6.13.1)(eslint@8.55.0)(jest@29.7.0)(typescript@5.3.2) eslint-plugin-prettier: specifier: ^5.0.1 - version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.1.0) + version: 5.0.1(eslint-config-prettier@9.1.0)(eslint@8.55.0)(prettier@3.1.0) eslint-plugin-unused-imports: specifier: ^3.0.0 - version: 3.0.0(@typescript-eslint/eslint-plugin@6.12.0)(eslint@8.54.0) + version: 3.0.0(@typescript-eslint/eslint-plugin@6.13.1)(eslint@8.55.0) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.10.0)(ts-node@10.9.1) + version: 29.7.0(@types/node@20.10.2)(ts-node@10.9.1) prettier: specifier: ^3.1.0 version: 3.1.0 @@ -122,13 +122,13 @@ devDependencies: version: 6.3.3 ts-jest: specifier: ^29.1.1 - version: 29.1.1(@babel/core@7.23.3)(jest@29.7.0)(typescript@5.3.2) + version: 29.1.1(@babel/core@7.23.5)(jest@29.7.0)(typescript@5.3.2) ts-loader: specifier: ^9.5.1 version: 9.5.1(typescript@5.3.2)(webpack@5.89.0) ts-node: specifier: ^10.9.1 - version: 10.9.1(@swc/core@1.3.99)(@types/node@20.10.0)(typescript@5.3.2) + version: 10.9.1(@swc/core@1.3.100)(@types/node@20.10.2)(typescript@5.3.2) tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 @@ -197,33 +197,33 @@ packages: - chokidar dev: true - /@babel/code-frame@7.23.4: - resolution: {integrity: sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==} + /@babel/code-frame@7.23.5: + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.23.4 chalk: 2.4.2 dev: true - /@babel/compat-data@7.23.3: - resolution: {integrity: sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==} + /@babel/compat-data@7.23.5: + resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.23.3: - resolution: {integrity: sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==} + /@babel/core@7.23.5: + resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.23.4 - '@babel/generator': 7.23.4 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.5 '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.3) - '@babel/helpers': 7.23.4 - '@babel/parser': 7.23.4 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) + '@babel/helpers': 7.23.5 + '@babel/parser': 7.23.5 '@babel/template': 7.22.15 - '@babel/traverse': 7.23.4 - '@babel/types': 7.23.4 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 convert-source-map: 2.0.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -233,11 +233,11 @@ packages: - supports-color dev: true - /@babel/generator@7.23.4: - resolution: {integrity: sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==} + /@babel/generator@7.23.5: + resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 jsesc: 2.5.2 @@ -247,8 +247,8 @@ packages: resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/compat-data': 7.23.3 - '@babel/helper-validator-option': 7.22.15 + '@babel/compat-data': 7.23.5 + '@babel/helper-validator-option': 7.23.5 browserslist: 4.22.1 lru-cache: 5.1.1 semver: 6.3.1 @@ -264,30 +264,30 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 dev: true /@babel/helper-module-imports@7.22.15: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 dev: true - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.3): + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 @@ -304,14 +304,14 @@ packages: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 dev: true /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 dev: true /@babel/helper-string-parser@7.23.4: @@ -324,18 +324,18 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-option@7.22.15: - resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} + /@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helpers@7.23.4: - resolution: {integrity: sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==} + /@babel/helpers@7.23.5: + resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/traverse': 7.23.4 - '@babel/types': 7.23.4 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 transitivePeerDependencies: - supports-color dev: true @@ -349,145 +349,145 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser@7.23.4: - resolution: {integrity: sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==} + /@babel/parser@7.23.5: + resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.3): + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.3): + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.5): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.3): + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.5): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.3): + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.3): + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.3): + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5): resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.3): + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.3): + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.3): + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.3): + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.3): + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.3): + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.3): + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.3): + /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5): resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/runtime@7.23.4: - resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==} + /@babel/runtime@7.23.5: + resolution: {integrity: sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 @@ -497,31 +497,31 @@ packages: resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.4 - '@babel/parser': 7.23.4 - '@babel/types': 7.23.4 + '@babel/code-frame': 7.23.5 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 dev: true - /@babel/traverse@7.23.4: - resolution: {integrity: sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==} + /@babel/traverse@7.23.5: + resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.4 - '@babel/generator': 7.23.4 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.4 - '@babel/types': 7.23.4 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types@7.23.4: - resolution: {integrity: sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==} + /@babel/types@7.23.5: + resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.23.4 @@ -546,13 +546,13 @@ packages: dependencies: '@jridgewell/trace-mapping': 0.3.9 - /@eslint-community/eslint-utils@4.4.0(eslint@8.54.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.55.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 dependencies: - eslint: 8.54.0 + eslint: 8.55.0 eslint-visitor-keys: 3.4.3 dev: true @@ -561,8 +561,8 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/eslintrc@2.1.3: - resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 @@ -578,8 +578,8 @@ packages: - supports-color dev: true - /@eslint/js@8.54.0: - resolution: {integrity: sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==} + /@eslint/js@8.55.0: + resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -681,7 +681,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -702,14 +702,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.10.0)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@20.10.2)(ts-node@10.9.1) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -737,7 +737,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 jest-mock: 29.7.0 dev: true @@ -764,7 +764,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.10.0 + '@types/node': 20.10.2 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -797,7 +797,7 @@ packages: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.20 - '@types/node': 20.10.0 + '@types/node': 20.10.2 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -859,7 +859,7 @@ packages: resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.20 babel-plugin-istanbul: 6.1.1 @@ -885,7 +885,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.10.0 + '@types/node': 20.10.2 '@types/yargs': 17.0.32 chalk: 4.1.2 dev: true @@ -949,7 +949,7 @@ packages: os-filter-obj: 2.0.0 dev: true - /@nestjs/cli@10.2.1(@swc/cli@0.1.63)(@swc/core@1.3.99): + /@nestjs/cli@10.2.1(@swc/cli@0.1.63)(@swc/core@1.3.100): resolution: {integrity: sha512-CAJAQwmxFZfB3RTvqz/eaXXWpyU+mZ4QSqfBYzjneTsPgF+uyOAW3yQpaLNn9Dfcv39R9UxSuAhayv6yuFd+Jg==} engines: {node: '>= 16.14'} hasBin: true @@ -966,8 +966,8 @@ packages: '@angular-devkit/schematics': 16.2.8(chokidar@3.5.3) '@angular-devkit/schematics-cli': 16.2.8(chokidar@3.5.3) '@nestjs/schematics': 10.0.3(chokidar@3.5.3)(typescript@5.2.2) - '@swc/cli': 0.1.63(@swc/core@1.3.99) - '@swc/core': 1.3.99 + '@swc/cli': 0.1.63(@swc/core@1.3.100) + '@swc/core': 1.3.100 chalk: 4.1.2 chokidar: 3.5.3 cli-table3: 0.6.3 @@ -985,7 +985,7 @@ packages: tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.1.0 typescript: 5.2.2 - webpack: 5.89.0(@swc/core@1.3.99) + webpack: 5.89.0(@swc/core@1.3.100) webpack-node-externals: 3.0.0 transitivePeerDependencies: - esbuild @@ -1164,7 +1164,7 @@ packages: '@nestjs/core': 10.2.10(@nestjs/common@10.2.10)(reflect-metadata@0.1.13)(rxjs@7.8.1) reflect-metadata: 0.1.13 rxjs: 7.8.1 - typeorm: 0.3.17(better-sqlite3@9.1.1)(ts-node@10.9.1) + typeorm: 0.3.17(better-sqlite3@9.2.0)(ts-node@10.9.1) uuid: 9.0.1 dev: false @@ -1244,7 +1244,7 @@ packages: resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} dev: false - /@swc/cli@0.1.63(@swc/core@1.3.99): + /@swc/cli@0.1.63(@swc/core@1.3.100): resolution: {integrity: sha512-EM9oxxHzmmsprYRbGqsS2M4M/Gr5Gkcl0ROYYIdlUyTkhOiX822EQiRCpPCwdutdnzH2GyaTN7wc6i0Y+CKd3A==} engines: {node: '>= 12.13'} hasBin: true @@ -1256,7 +1256,7 @@ packages: optional: true dependencies: '@mole-inc/bin-wrapper': 8.0.1 - '@swc/core': 1.3.99 + '@swc/core': 1.3.100 commander: 7.2.0 fast-glob: 3.3.2 semver: 7.5.4 @@ -1264,24 +1264,24 @@ packages: source-map: 0.7.4 dev: true - /@swc/core-darwin-arm64@1.3.99: - resolution: {integrity: sha512-Qj7Jct68q3ZKeuJrjPx7k8SxzWN6PqLh+VFxzA+KwLDpQDPzOlKRZwkIMzuFjLhITO4RHgSnXoDk/Syz0ZeN+Q==} + /@swc/core-darwin-arm64@1.3.100: + resolution: {integrity: sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] requiresBuild: true optional: true - /@swc/core-darwin-x64@1.3.99: - resolution: {integrity: sha512-wR7m9QVJjgiBu1PSOHy7s66uJPa45Kf9bZExXUL+JAa9OQxt5y+XVzr+n+F045VXQOwdGWplgPnWjgbUUHEVyw==} + /@swc/core-darwin-x64@1.3.100: + resolution: {integrity: sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA==} engines: {node: '>=10'} cpu: [x64] os: [darwin] requiresBuild: true optional: true - /@swc/core-linux-arm64-gnu@1.3.99: - resolution: {integrity: sha512-gcGv1l5t0DScEONmw5OhdVmEI/o49HCe9Ik38zzH0NtDkc+PDYaCcXU5rvfZP2qJFaAAr8cua8iJcOunOSLmnA==} + /@swc/core-linux-arm64-gnu@1.3.100: + resolution: {integrity: sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -1289,8 +1289,8 @@ packages: requiresBuild: true optional: true - /@swc/core-linux-arm64-musl@1.3.99: - resolution: {integrity: sha512-XL1/eUsTO8BiKsWq9i3iWh7H99iPO61+9HYiWVKhSavknfj4Plbn+XyajDpxsauln5o8t+BRGitymtnAWJM4UQ==} + /@swc/core-linux-arm64-musl@1.3.100: + resolution: {integrity: sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -1298,8 +1298,8 @@ packages: requiresBuild: true optional: true - /@swc/core-linux-x64-gnu@1.3.99: - resolution: {integrity: sha512-fGrXYE6DbTfGNIGQmBefYxSk3rp/1lgbD0nVg4rl4mfFRQPi7CgGhrrqSuqZ/ezXInUIgoCyvYGWFSwjLXt/Qg==} + /@swc/core-linux-x64-gnu@1.3.100: + resolution: {integrity: sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -1307,8 +1307,8 @@ packages: requiresBuild: true optional: true - /@swc/core-linux-x64-musl@1.3.99: - resolution: {integrity: sha512-kvgZp/mqf3IJ806gUOL6gN6VU15+DfzM1Zv4Udn8GqgXiUAvbQehrtruid4Snn5pZTLj4PEpSCBbxgxK1jbssA==} + /@swc/core-linux-x64-musl@1.3.100: + resolution: {integrity: sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -1316,32 +1316,32 @@ packages: requiresBuild: true optional: true - /@swc/core-win32-arm64-msvc@1.3.99: - resolution: {integrity: sha512-yt8RtZ4W/QgFF+JUemOUQAkVW58cCST7mbfKFZ1v16w3pl3NcWd9OrtppFIXpbjU1rrUX2zp2R7HZZzZ2Zk/aQ==} + /@swc/core-win32-arm64-msvc@1.3.100: + resolution: {integrity: sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw==} engines: {node: '>=10'} cpu: [arm64] os: [win32] requiresBuild: true optional: true - /@swc/core-win32-ia32-msvc@1.3.99: - resolution: {integrity: sha512-62p5fWnOJR/rlbmbUIpQEVRconICy5KDScWVuJg1v3GPLBrmacjphyHiJC1mp6dYvvoEWCk/77c/jcQwlXrDXw==} + /@swc/core-win32-ia32-msvc@1.3.100: + resolution: {integrity: sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A==} engines: {node: '>=10'} cpu: [ia32] os: [win32] requiresBuild: true optional: true - /@swc/core-win32-x64-msvc@1.3.99: - resolution: {integrity: sha512-PdppWhkoS45VGdMBxvClVgF1hVjqamtvYd82Gab1i4IV45OSym2KinoDCKE1b6j3LwBLOn2J9fvChGSgGfDCHQ==} + /@swc/core-win32-x64-msvc@1.3.100: + resolution: {integrity: sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ==} engines: {node: '>=10'} cpu: [x64] os: [win32] requiresBuild: true optional: true - /@swc/core@1.3.99: - resolution: {integrity: sha512-8O996RfuPC4ieb4zbYMfbyCU9k4gSOpyCNnr7qBQ+o7IEmh8JCV6B8wwu+fT/Om/6Lp34KJe1IpJ/24axKS6TQ==} + /@swc/core@1.3.100: + resolution: {integrity: sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw==} engines: {node: '>=10'} requiresBuild: true peerDependencies: @@ -1353,15 +1353,15 @@ packages: '@swc/counter': 0.1.2 '@swc/types': 0.1.5 optionalDependencies: - '@swc/core-darwin-arm64': 1.3.99 - '@swc/core-darwin-x64': 1.3.99 - '@swc/core-linux-arm64-gnu': 1.3.99 - '@swc/core-linux-arm64-musl': 1.3.99 - '@swc/core-linux-x64-gnu': 1.3.99 - '@swc/core-linux-x64-musl': 1.3.99 - '@swc/core-win32-arm64-msvc': 1.3.99 - '@swc/core-win32-ia32-msvc': 1.3.99 - '@swc/core-win32-x64-msvc': 1.3.99 + '@swc/core-darwin-arm64': 1.3.100 + '@swc/core-darwin-x64': 1.3.100 + '@swc/core-linux-arm64-gnu': 1.3.100 + '@swc/core-linux-arm64-musl': 1.3.100 + '@swc/core-linux-x64-gnu': 1.3.100 + '@swc/core-linux-x64-musl': 1.3.100 + '@swc/core-win32-arm64-msvc': 1.3.100 + '@swc/core-win32-ia32-msvc': 1.3.100 + '@swc/core-win32-x64-msvc': 1.3.100 /@swc/counter@0.1.2: resolution: {integrity: sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==} @@ -1395,8 +1395,8 @@ packages: /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@babel/parser': 7.23.4 - '@babel/types': 7.23.4 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 '@types/babel__generator': 7.6.7 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.4 @@ -1405,20 +1405,20 @@ packages: /@types/babel__generator@7.6.7: resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 dev: true /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: - '@babel/parser': 7.23.4 - '@babel/types': 7.23.4 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 dev: true /@types/babel__traverse@7.20.4: resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 dev: true /@types/cacheable-request@6.0.3: @@ -1426,7 +1426,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 20.10.0 + '@types/node': 20.10.2 '@types/responselike': 1.0.3 dev: true @@ -1437,12 +1437,12 @@ packages: /@types/eslint-scope@3.7.7: resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} dependencies: - '@types/eslint': 8.44.7 + '@types/eslint': 8.44.8 '@types/estree': 1.0.5 dev: true - /@types/eslint@8.44.7: - resolution: {integrity: sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==} + /@types/eslint@8.44.8: + resolution: {integrity: sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==} dependencies: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 @@ -1455,7 +1455,7 @@ packages: /@types/graceful-fs@4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: - '@types/node': 20.10.0 + '@types/node': 20.10.2 dev: true /@types/http-cache-semantics@4.0.4: @@ -1496,22 +1496,22 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.10.0 + '@types/node': 20.10.2 dev: true /@types/lodash@4.14.202: resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} dev: true - /@types/node@20.10.0: - resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==} + /@types/node@20.10.2: + resolution: {integrity: sha512-37MXfxkb0vuIlRKHNxwCkb60PNBpR94u4efQuN4JgIAm66zfCDXGSAFCef9XUWFovX2R1ok6Z7MHhtdVXXkkIw==} dependencies: undici-types: 5.26.5 /@types/responselike@1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 20.10.0 + '@types/node': 20.10.2 dev: true /@types/sanitize-html@2.9.5: @@ -1528,17 +1528,17 @@ packages: resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} dev: true - /@types/superagent@4.1.22: - resolution: {integrity: sha512-GMaOrnnUsjChvH8zlzdDPARRXky8bU3E8xsU/fOclgqsINekbwDu1+wzJzJaGzZP91SGpOutf5Te5pm5M/qCWg==} + /@types/superagent@4.1.24: + resolution: {integrity: sha512-mEafCgyKiMFin24SDzWN7yAADt4gt6YawFiNMp0QS5ZPboORfyxFt0s3VzJKhTaKg9py/4FUmrHLTNfJKt9Rbw==} dependencies: '@types/cookiejar': 2.1.5 - '@types/node': 20.10.0 + '@types/node': 20.10.2 dev: true /@types/supertest@2.0.16: resolution: {integrity: sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==} dependencies: - '@types/superagent': 4.1.22 + '@types/superagent': 4.1.24 dev: true /@types/validator@13.11.7: @@ -1554,8 +1554,8 @@ packages: '@types/yargs-parser': 21.0.3 dev: true - /@typescript-eslint/eslint-plugin@6.12.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0)(typescript@5.3.2): - resolution: {integrity: sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==} + /@typescript-eslint/eslint-plugin@6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.55.0)(typescript@5.3.2): + resolution: {integrity: sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -1566,13 +1566,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.12.0(eslint@8.54.0)(typescript@5.3.2) - '@typescript-eslint/scope-manager': 6.12.0 - '@typescript-eslint/type-utils': 6.12.0(eslint@8.54.0)(typescript@5.3.2) - '@typescript-eslint/utils': 6.12.0(eslint@8.54.0)(typescript@5.3.2) - '@typescript-eslint/visitor-keys': 6.12.0 + '@typescript-eslint/parser': 6.13.1(eslint@8.55.0)(typescript@5.3.2) + '@typescript-eslint/scope-manager': 6.13.1 + '@typescript-eslint/type-utils': 6.13.1(eslint@8.55.0)(typescript@5.3.2) + '@typescript-eslint/utils': 6.13.1(eslint@8.55.0)(typescript@5.3.2) + '@typescript-eslint/visitor-keys': 6.13.1 debug: 4.3.4 - eslint: 8.54.0 + eslint: 8.55.0 graphemer: 1.4.0 ignore: 5.3.0 natural-compare: 1.4.0 @@ -1583,8 +1583,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.12.0(eslint@8.54.0)(typescript@5.3.2): - resolution: {integrity: sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==} + /@typescript-eslint/parser@6.13.1(eslint@8.55.0)(typescript@5.3.2): + resolution: {integrity: sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1593,12 +1593,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.12.0 - '@typescript-eslint/types': 6.12.0 - '@typescript-eslint/typescript-estree': 6.12.0(typescript@5.3.2) - '@typescript-eslint/visitor-keys': 6.12.0 + '@typescript-eslint/scope-manager': 6.13.1 + '@typescript-eslint/types': 6.13.1 + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) + '@typescript-eslint/visitor-keys': 6.13.1 debug: 4.3.4 - eslint: 8.54.0 + eslint: 8.55.0 typescript: 5.3.2 transitivePeerDependencies: - supports-color @@ -1612,16 +1612,16 @@ packages: '@typescript-eslint/visitor-keys': 5.62.0 dev: true - /@typescript-eslint/scope-manager@6.12.0: - resolution: {integrity: sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==} + /@typescript-eslint/scope-manager@6.13.1: + resolution: {integrity: sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.12.0 - '@typescript-eslint/visitor-keys': 6.12.0 + '@typescript-eslint/types': 6.13.1 + '@typescript-eslint/visitor-keys': 6.13.1 dev: true - /@typescript-eslint/type-utils@6.12.0(eslint@8.54.0)(typescript@5.3.2): - resolution: {integrity: sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==} + /@typescript-eslint/type-utils@6.13.1(eslint@8.55.0)(typescript@5.3.2): + resolution: {integrity: sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1630,10 +1630,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.12.0(typescript@5.3.2) - '@typescript-eslint/utils': 6.12.0(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) + '@typescript-eslint/utils': 6.13.1(eslint@8.55.0)(typescript@5.3.2) debug: 4.3.4 - eslint: 8.54.0 + eslint: 8.55.0 ts-api-utils: 1.0.3(typescript@5.3.2) typescript: 5.3.2 transitivePeerDependencies: @@ -1645,8 +1645,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/types@6.12.0: - resolution: {integrity: sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==} + /@typescript-eslint/types@6.13.1: + resolution: {integrity: sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==} engines: {node: ^16.0.0 || >=18.0.0} dev: true @@ -1671,8 +1671,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.12.0(typescript@5.3.2): - resolution: {integrity: sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==} + /@typescript-eslint/typescript-estree@6.13.1(typescript@5.3.2): + resolution: {integrity: sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -1680,8 +1680,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.12.0 - '@typescript-eslint/visitor-keys': 6.12.0 + '@typescript-eslint/types': 6.13.1 + '@typescript-eslint/visitor-keys': 6.13.1 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -1692,19 +1692,19 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@5.62.0(eslint@8.54.0)(typescript@5.3.2): + /@typescript-eslint/utils@5.62.0(eslint@8.55.0)(typescript@5.3.2): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.2) - eslint: 8.54.0 + eslint: 8.55.0 eslint-scope: 5.1.1 semver: 7.5.4 transitivePeerDependencies: @@ -1712,19 +1712,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.12.0(eslint@8.54.0)(typescript@5.3.2): - resolution: {integrity: sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==} + /@typescript-eslint/utils@6.13.1(eslint@8.55.0)(typescript@5.3.2): + resolution: {integrity: sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 6.12.0 - '@typescript-eslint/types': 6.12.0 - '@typescript-eslint/typescript-estree': 6.12.0(typescript@5.3.2) - eslint: 8.54.0 + '@typescript-eslint/scope-manager': 6.13.1 + '@typescript-eslint/types': 6.13.1 + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) + eslint: 8.55.0 semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -1739,11 +1739,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@6.12.0: - resolution: {integrity: sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==} + /@typescript-eslint/visitor-keys@6.13.1: + resolution: {integrity: sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.12.0 + '@typescript-eslint/types': 6.13.1 eslint-visitor-keys: 3.4.3 dev: true @@ -2116,17 +2116,17 @@ packages: - supports-color dev: false - /babel-jest@29.7.0(@babel/core@7.23.3): + /babel-jest@29.7.0(@babel/core@7.23.5): resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.23.3) + babel-preset-jest: 29.6.3(@babel/core@7.23.5) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -2152,40 +2152,40 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/template': 7.22.15 - '@babel/types': 7.23.4 + '@babel/types': 7.23.5 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.4 dev: true - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.3): + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.5): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.3 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.3) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.3) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.3) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.3) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.3) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.3) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.3) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.3) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.3) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.3) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.3) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.3) + '@babel/core': 7.23.5 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.5) dev: true - /babel-preset-jest@29.6.3(@babel/core@7.23.3): + /babel-preset-jest@29.6.3(@babel/core@7.23.5): resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.3) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.5) dev: true /balanced-match@1.0.2: @@ -2194,8 +2194,8 @@ packages: /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - /better-sqlite3@9.1.1: - resolution: {integrity: sha512-FhW7bS7cXwkB2SFnPJrSGPmQerVSCzwBgmQ1cIRcYKxLsyiKjljzCbyEqqhYXo5TTBqt5BISiBj2YE2Sy2ynaA==} + /better-sqlite3@9.2.0: + resolution: {integrity: sha512-MEm49nfxCU6Yn5rTyXJhnTmjuom0YFrU76/7AC+7PMcftAwIVJ2VtBF6HSPRwQ/WWXw/sSbnPRPUSZ6vMXMniQ==} requiresBuild: true dependencies: bindings: 1.5.0 @@ -2281,9 +2281,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001564 - electron-to-chromium: 1.4.594 - node-releases: 2.0.13 + caniuse-lite: 1.0.30001565 + electron-to-chromium: 1.4.601 + node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.1) dev: true @@ -2365,8 +2365,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001564: - resolution: {integrity: sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==} + /caniuse-lite@1.0.30001565: + resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==} dev: true /chalk@2.4.2: @@ -2618,7 +2618,7 @@ packages: typescript: 5.2.2 dev: true - /create-jest@29.7.0(@types/node@20.10.0)(ts-node@10.9.1): + /create-jest@29.7.0(@types/node@20.10.2)(ts-node@10.9.1): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -2627,7 +2627,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.10.0)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@20.10.2)(ts-node@10.9.1) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -2661,7 +2661,7 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.5 dev: false /debug@3.2.7: @@ -2850,8 +2850,8 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /electron-to-chromium@1.4.594: - resolution: {integrity: sha512-xT1HVAu5xFn7bDfkjGQi9dNpMqGchUkebwf1GL7cZN32NSwwlHRPMSDJ1KN6HkS0bWUtndbSQZqvpQftKG2uFQ==} + /electron-to-chromium@1.4.601: + resolution: {integrity: sha512-SpwUMDWe9tQu8JX5QCO1+p/hChAi9AE9UpoC3rcHVc+gdCGlbT3SGb5I1klgb952HRIyvt9wZhSz9bNBYz9swA==} dev: true /emittery@0.13.1: @@ -2919,7 +2919,7 @@ packages: is-weakref: 1.0.2 object-inspect: 1.13.1 object-keys: 1.1.1 - object.assign: 4.1.4 + object.assign: 4.1.5 regexp.prototype.flags: 1.5.1 safe-array-concat: 1.0.1 safe-regex-test: 1.0.0 @@ -2985,7 +2985,7 @@ packages: engines: {node: '>=12'} dev: true - /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.0)(eslint@8.54.0): + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.0)(eslint@8.55.0): resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -2993,14 +2993,14 @@ packages: eslint-plugin-import: ^2.25.2 dependencies: confusing-browser-globals: 1.0.11 - eslint: 8.54.0 - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0) - object.assign: 4.1.4 + eslint: 8.55.0 + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.13.1)(eslint@8.55.0) + object.assign: 4.1.5 object.entries: 1.1.7 semver: 6.3.1 dev: true - /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.12.0)(@typescript-eslint/parser@6.12.0)(eslint-plugin-import@2.29.0)(eslint@8.54.0): + /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.13.1)(@typescript-eslint/parser@6.13.1)(eslint-plugin-import@2.29.0)(eslint@8.55.0): resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} peerDependencies: '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 @@ -3008,20 +3008,20 @@ packages: eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 6.12.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0)(typescript@5.3.2) - '@typescript-eslint/parser': 6.12.0(eslint@8.54.0)(typescript@5.3.2) - eslint: 8.54.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.0)(eslint@8.54.0) - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0) + '@typescript-eslint/eslint-plugin': 6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.55.0)(typescript@5.3.2) + '@typescript-eslint/parser': 6.13.1(eslint@8.55.0)(typescript@5.3.2) + eslint: 8.55.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.0)(eslint@8.55.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.13.1)(eslint@8.55.0) dev: true - /eslint-config-prettier@9.0.0(eslint@8.54.0): - resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} + /eslint-config-prettier@9.1.0(eslint@8.55.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.54.0 + eslint: 8.55.0 dev: true /eslint-import-resolver-node@0.3.9: @@ -3034,7 +3034,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.12.0)(eslint-import-resolver-node@0.3.9)(eslint@8.54.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.13.1)(eslint-import-resolver-node@0.3.9)(eslint@8.55.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -3055,15 +3055,15 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.12.0(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/parser': 6.13.1(eslint@8.55.0)(typescript@5.3.2) debug: 3.2.7 - eslint: 8.54.0 + eslint: 8.55.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0): + /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.13.1)(eslint@8.55.0): resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} engines: {node: '>=4'} peerDependencies: @@ -3073,16 +3073,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.12.0(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/parser': 6.13.1(eslint@8.55.0)(typescript@5.3.2) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.54.0 + eslint: 8.55.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.12.0)(eslint-import-resolver-node@0.3.9)(eslint@8.54.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.13.1)(eslint-import-resolver-node@0.3.9)(eslint@8.55.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -3098,7 +3098,7 @@ packages: - supports-color dev: true - /eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.12.0)(eslint@8.54.0)(jest@29.7.0)(typescript@5.3.2): + /eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.13.1)(eslint@8.55.0)(jest@29.7.0)(typescript@5.3.2): resolution: {integrity: sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -3111,16 +3111,16 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.12.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0)(typescript@5.3.2) - '@typescript-eslint/utils': 5.62.0(eslint@8.54.0)(typescript@5.3.2) - eslint: 8.54.0 - jest: 29.7.0(@types/node@20.10.0)(ts-node@10.9.1) + '@typescript-eslint/eslint-plugin': 6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.55.0)(typescript@5.3.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.55.0)(typescript@5.3.2) + eslint: 8.55.0 + jest: 29.7.0(@types/node@20.10.2)(ts-node@10.9.1) transitivePeerDependencies: - supports-color - typescript dev: true - /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.1.0): + /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.1.0)(eslint@8.55.0)(prettier@3.1.0): resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -3134,14 +3134,14 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.54.0 - eslint-config-prettier: 9.0.0(eslint@8.54.0) + eslint: 8.55.0 + eslint-config-prettier: 9.1.0(eslint@8.55.0) prettier: 3.1.0 prettier-linter-helpers: 1.0.0 - synckit: 0.8.5 + synckit: 0.8.6 dev: true - /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.12.0)(eslint@8.54.0): + /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.13.1)(eslint@8.55.0): resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -3151,8 +3151,8 @@ packages: '@typescript-eslint/eslint-plugin': optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.12.0(@typescript-eslint/parser@6.12.0)(eslint@8.54.0)(typescript@5.3.2) - eslint: 8.54.0 + '@typescript-eslint/eslint-plugin': 6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.55.0)(typescript@5.3.2) + eslint: 8.55.0 eslint-rule-composer: 0.3.0 dev: true @@ -3182,15 +3182,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.54.0: - resolution: {integrity: sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==} + /eslint@8.55.0: + resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.3 - '@eslint/js': 8.54.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.55.0 '@humanwhocodes/config-array': 0.11.13 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -3473,12 +3473,12 @@ packages: find-my-way: 7.7.0 light-my-request: 5.11.0 pino: 8.16.2 - process-warning: 2.3.1 + process-warning: 2.3.2 proxy-addr: 2.0.7 rfdc: 1.3.0 secure-json-parse: 2.7.0 semver: 7.5.4 - toad-cache: 3.3.0 + toad-cache: 3.3.1 transitivePeerDependencies: - supports-color dev: false @@ -3608,7 +3608,7 @@ packages: typescript: '>3.6.0' webpack: ^5.11.0 dependencies: - '@babel/code-frame': 7.23.4 + '@babel/code-frame': 7.23.5 chalk: 4.1.2 chokidar: 3.5.3 cosmiconfig: 8.3.6(typescript@5.2.2) @@ -3621,7 +3621,7 @@ packages: semver: 7.5.4 tapable: 2.2.1 typescript: 5.2.2 - webpack: 5.89.0(@swc/core@1.3.99) + webpack: 5.89.0(@swc/core@1.3.100) dev: true /form-data@4.0.0: @@ -4290,8 +4290,8 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.23.3 - '@babel/parser': 7.23.4 + '@babel/core': 7.23.5 + '@babel/parser': 7.23.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -4303,8 +4303,8 @@ packages: resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} engines: {node: '>=10'} dependencies: - '@babel/core': 7.23.3 - '@babel/parser': 7.23.4 + '@babel/core': 7.23.5 + '@babel/parser': 7.23.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.5.4 @@ -4370,7 +4370,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -4391,7 +4391,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@20.10.0)(ts-node@10.9.1): + /jest-cli@29.7.0(@types/node@20.10.2)(ts-node@10.9.1): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -4405,10 +4405,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.10.0)(ts-node@10.9.1) + create-jest: 29.7.0(@types/node@20.10.2)(ts-node@10.9.1) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.10.0)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@20.10.2)(ts-node@10.9.1) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -4419,7 +4419,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@20.10.0)(ts-node@10.9.1): + /jest-config@29.7.0(@types/node@20.10.2)(ts-node@10.9.1): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -4431,11 +4431,11 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.0 - babel-jest: 29.7.0(@babel/core@7.23.3) + '@types/node': 20.10.2 + babel-jest: 29.7.0(@babel/core@7.23.5) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -4454,7 +4454,7 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1(@swc/core@1.3.99)(@types/node@20.10.0)(typescript@5.3.2) + ts-node: 10.9.1(@swc/core@1.3.100)(@types/node@20.10.2)(typescript@5.3.2) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -4495,7 +4495,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -4511,7 +4511,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.10.0 + '@types/node': 20.10.2 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -4546,7 +4546,7 @@ packages: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/code-frame': 7.23.4 + '@babel/code-frame': 7.23.5 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -4562,7 +4562,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 jest-util: 29.7.0 dev: true @@ -4617,7 +4617,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -4648,7 +4648,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -4671,15 +4671,15 @@ packages: resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.3 - '@babel/generator': 7.23.4 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.3) - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.3) - '@babel/types': 7.23.4 + '@babel/core': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.5) + '@babel/types': 7.23.5 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.3) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.5) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -4700,7 +4700,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -4725,7 +4725,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.0 + '@types/node': 20.10.2 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -4737,7 +4737,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.10.0 + '@types/node': 20.10.2 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -4746,13 +4746,13 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.10.0 + '@types/node': 20.10.2 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@20.10.0)(ts-node@10.9.1): + /jest@29.7.0(@types/node@20.10.2)(ts-node@10.9.1): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -4765,7 +4765,7 @@ packages: '@jest/core': 29.7.0(ts-node@10.9.1) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.10.0)(ts-node@10.9.1) + jest-cli: 29.7.0(@types/node@20.10.2)(ts-node@10.9.1) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -4878,7 +4878,7 @@ packages: resolution: {integrity: sha512-qkFCeloXCOMpmEdZ/MV91P8AT4fjwFXWaAFz3lUeStM8RcoM1ks4J/F8r1b3r6y/H4u3ACEJ1T+Gv5bopj7oDA==} dependencies: cookie: 0.5.0 - process-warning: 2.3.1 + process-warning: 2.3.2 set-cookie-parser: 2.6.0 dev: false @@ -5172,8 +5172,8 @@ packages: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true - /node-releases@2.0.13: - resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} dev: true /normalize-path@3.0.0: @@ -5221,8 +5221,8 @@ packages: engines: {node: '>= 0.4'} dev: true - /object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 @@ -5406,7 +5406,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.23.4 + '@babel/code-frame': 7.23.5 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -5517,7 +5517,7 @@ packages: on-exit-leak-free: 2.1.2 pino-abstract-transport: 1.1.0 pino-std-serializers: 6.2.2 - process-warning: 2.3.1 + process-warning: 2.3.2 quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.4.3 @@ -5542,8 +5542,8 @@ packages: engines: {node: '>=4'} dev: true - /postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + /postcss@8.4.32: + resolution: {integrity: sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 @@ -5597,8 +5597,8 @@ packages: react-is: 18.2.0 dev: true - /process-warning@2.3.1: - resolution: {integrity: sha512-JjBvFEn7MwFbzUDa2SRtKJSsyO0LlER4V/FmwLMhBlXNbGgGxdyFCxIdMDLerWUycsVUyaoM9QFLvppFy4IWaQ==} + /process-warning@2.3.2: + resolution: {integrity: sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA==} dev: false /process@0.11.10: @@ -5898,7 +5898,7 @@ packages: htmlparser2: 8.0.2 is-plain-object: 5.0.0 parse-srcset: 1.0.2 - postcss: 8.4.31 + postcss: 8.4.32 dev: false /schema-utils@3.3.0: @@ -6290,8 +6290,8 @@ packages: engines: {node: '>=0.10'} dev: true - /synckit@0.8.5: - resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==} + /synckit@0.8.6: + resolution: {integrity: sha512-laHF2savN6sMeHCjLRkheIU4wo3Zg9Ln5YOjOo7sZ5dVQW8yF5pPE5SIw1dsPhq3TRp1jisKRCdPhfs/1WMqDA==} engines: {node: ^14.18.0 || >=16.0.0} dependencies: '@pkgr/utils': 2.4.2 @@ -6323,7 +6323,7 @@ packages: readable-stream: 3.6.2 dev: false - /terser-webpack-plugin@5.3.9(@swc/core@1.3.99)(webpack@5.89.0): + /terser-webpack-plugin@5.3.9(@swc/core@1.3.100)(webpack@5.89.0): resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -6340,12 +6340,12 @@ packages: optional: true dependencies: '@jridgewell/trace-mapping': 0.3.20 - '@swc/core': 1.3.99 + '@swc/core': 1.3.100 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.1 terser: 5.24.0 - webpack: 5.89.0(@swc/core@1.3.99) + webpack: 5.89.0(@swc/core@1.3.100) dev: true /terser@5.24.0: @@ -6423,8 +6423,8 @@ packages: is-number: 7.0.0 dev: true - /toad-cache@3.3.0: - resolution: {integrity: sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==} + /toad-cache@3.3.1: + resolution: {integrity: sha512-oE5vIpiyKEuyYJiyp0gYhiD1o7BmiPCJZX9pboK9X6EfdYYmNsk8m7J1kBwMt6H/avuDsCdEhassrMMxwW7h3Q==} engines: {node: '>=12'} dev: false @@ -6460,7 +6460,7 @@ packages: typescript: 5.3.2 dev: true - /ts-jest@29.1.1(@babel/core@7.23.3)(jest@29.7.0)(typescript@5.3.2): + /ts-jest@29.1.1(@babel/core@7.23.5)(jest@29.7.0)(typescript@5.3.2): resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -6481,10 +6481,10 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.23.3 + '@babel/core': 7.23.5 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.10.0)(ts-node@10.9.1) + jest: 29.7.0(@types/node@20.10.2)(ts-node@10.9.1) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -6507,10 +6507,10 @@ packages: semver: 7.5.4 source-map: 0.7.4 typescript: 5.3.2 - webpack: 5.89.0(@swc/core@1.3.99) + webpack: 5.89.0(@swc/core@1.3.100) dev: true - /ts-node@10.9.1(@swc/core@1.3.99)(@types/node@20.10.0)(typescript@5.3.2): + /ts-node@10.9.1(@swc/core@1.3.100)(@types/node@20.10.2)(typescript@5.3.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -6525,12 +6525,12 @@ packages: optional: true dependencies: '@cspotcode/source-map-support': 0.8.1 - '@swc/core': 1.3.99 + '@swc/core': 1.3.100 '@tsconfig/node10': 1.0.9 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.10.0 + '@types/node': 20.10.2 acorn: 8.11.2 acorn-walk: 8.3.0 arg: 4.1.3 @@ -6651,7 +6651,7 @@ packages: is-typed-array: 1.1.12 dev: true - /typeorm@0.3.17(better-sqlite3@9.1.1)(ts-node@10.9.1): + /typeorm@0.3.17(better-sqlite3@9.2.0)(ts-node@10.9.1): resolution: {integrity: sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==} engines: {node: '>= 12.9.0'} hasBin: true @@ -6711,7 +6711,7 @@ packages: dependencies: '@sqltools/formatter': 1.2.5 app-root-path: 3.1.0 - better-sqlite3: 9.1.1 + better-sqlite3: 9.2.0 buffer: 6.0.3 chalk: 4.1.2 cli-highlight: 2.1.11 @@ -6722,7 +6722,7 @@ packages: mkdirp: 2.1.6 reflect-metadata: 0.1.13 sha.js: 2.4.11 - ts-node: 10.9.1(@swc/core@1.3.99)(@types/node@20.10.0)(typescript@5.3.2) + ts-node: 10.9.1(@swc/core@1.3.100)(@types/node@20.10.2)(typescript@5.3.2) tslib: 2.6.2 uuid: 9.0.1 yargs: 17.7.2 @@ -6842,7 +6842,7 @@ packages: engines: {node: '>=10.13.0'} dev: true - /webpack@5.89.0(@swc/core@1.3.99): + /webpack@5.89.0(@swc/core@1.3.100): resolution: {integrity: sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==} engines: {node: '>=10.13.0'} hasBin: true @@ -6873,7 +6873,7 @@ packages: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.9(@swc/core@1.3.99)(webpack@5.89.0) + terser-webpack-plugin: 5.3.9(@swc/core@1.3.100)(webpack@5.89.0) watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: diff --git a/src/config/database.config.ts b/src/config/database.config.ts index dcb9b3e..94916ee 100644 --- a/src/config/database.config.ts +++ b/src/config/database.config.ts @@ -17,7 +17,7 @@ export const database = (): TypeOrmModuleOptions => ({ // database: 'ink_apps', // 以下为sqlite配置 type: 'better-sqlite3', - database: resolve(__dirname, '../../back/database4.db'), + database: resolve(__dirname, '../../back/database6.db'), synchronize: true, autoLoadEntities: true, }); diff --git a/src/modules/content/constants.ts b/src/modules/content/constants.ts index f149fed..f19e17d 100644 --- a/src/modules/content/constants.ts +++ b/src/modules/content/constants.ts @@ -13,5 +13,6 @@ export enum PostOrderType { CREATED = 'createdAt', UPDATED = 'updatedAt', PUBLISHED = 'publishedAt', + COMMENTCOUNT = 'commentCount', CUSTOM = 'custom', } diff --git a/src/modules/content/content.module.ts b/src/modules/content/content.module.ts index 80f4b5d..970eeed 100644 --- a/src/modules/content/content.module.ts +++ b/src/modules/content/content.module.ts @@ -2,21 +2,25 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { PostController } from '@/modules/content/controllers'; -import { PostEntity } from '@/modules/content/entities'; - -import { PostRepository } from '@/modules/content/repositories'; -import { PostService, SanitizeService } from '@/modules/content/services'; +import { SanitizeService } from '@/modules/content/services/sanitize.service'; import { PostSubscriber } from '@/modules/content/subscribers'; import { DatabaseModule } from '@/modules/database/database.module'; +import * as controllers from './controllers'; +import * as entities from './entities'; +import * as repositories from './repositories'; +import * as services from './services'; + @Module({ imports: [ - TypeOrmModule.forFeature([PostEntity]), - DatabaseModule.forRepository([PostRepository]), + TypeOrmModule.forFeature(Object.values(entities)), + DatabaseModule.forRepository(Object.values(repositories)), + ], + controllers: Object.values(controllers), + providers: [...Object.values(services), PostSubscriber, SanitizeService], + exports: [ + ...Object.values(services), + DatabaseModule.forRepository(Object.values(repositories)), ], - controllers: [PostController], - providers: [PostService, PostSubscriber, SanitizeService], - exports: [PostService, DatabaseModule.forRepository([PostRepository])], }) export class ContentModule {} diff --git a/src/modules/content/controllers/category.controller.ts b/src/modules/content/controllers/category.controller.ts new file mode 100644 index 0000000..8fb3bad --- /dev/null +++ b/src/modules/content/controllers/category.controller.ts @@ -0,0 +1,95 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseUUIDPipe, + Patch, + Post, + Query, + SerializeOptions, + UseInterceptors, + ValidationPipe, +} from '@nestjs/common'; + +import { CreateCategoryDto, QueryCategoryDto, UpdateCategoryDto } from '@/modules/content/dtos'; +import { CategoryService } from '@/modules/content/services'; +import { AppIntercepter } from '@/modules/core/providers'; + +@UseInterceptors(AppIntercepter) +@Controller('categories') +export class CategoryController { + constructor(protected service: CategoryService) {} + + @Get('tree') + @SerializeOptions({ groups: ['category-tree'] }) + async tree() { + return this.service.findTress(); + } + + @Get() + @SerializeOptions({ groups: ['category-list'] }) + async list( + @Query( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + forbidUnknownValues: true, + validationError: { target: false }, + }), + ) + options: QueryCategoryDto, + ) { + return this.service.paginate(options); + } + + @Get(':id') + @SerializeOptions({ groups: ['category-detail'] }) + async detail(@Param('id', new ParseUUIDPipe()) id: string) { + return this.service.detail(id); + } + + @Post() + @SerializeOptions({ groups: ['category-detail'] }) + async create( + @Body( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + forbidUnknownValues: true, + validationError: { target: false }, + groups: ['create'], + }), + ) + data: CreateCategoryDto, + ) { + return this.service.create(data); + } + + @Patch() + @SerializeOptions({ groups: ['category-detail'] }) + async update( + @Body( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + forbidUnknownValues: true, + validationError: { target: false }, + groups: ['update'], + }), + ) + data: UpdateCategoryDto, + ) { + return this.service.update(data); + } + + @Delete(':id') + @SerializeOptions({ groups: ['category-detail'] }) + async delete(@Param('id', new ParseUUIDPipe()) id: string) { + return this.service.delete(id); + } +} diff --git a/src/modules/content/controllers/comment.controller.ts b/src/modules/content/controllers/comment.controller.ts new file mode 100644 index 0000000..657a2f1 --- /dev/null +++ b/src/modules/content/controllers/comment.controller.ts @@ -0,0 +1,78 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseUUIDPipe, + Post, + Query, + SerializeOptions, + UseInterceptors, + ValidationPipe, +} from '@nestjs/common'; + +import { CreateCommentDto, QueryCommentDto, QueryCommentTreeDto } from '@/modules/content/dtos'; +import { CommentService } from '@/modules/content/services'; +import { AppIntercepter } from '@/modules/core/providers'; + +@UseInterceptors(AppIntercepter) +@Controller('comments') +export class CommentController { + constructor(protected service: CommentService) {} + + @Get('tree') + @SerializeOptions({ groups: ['comment-tree'] }) + async tree( + @Query( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + forbidUnknownValues: true, + validationError: { target: false }, + }), + ) + query: QueryCommentTreeDto, + ) { + return this.service.findTrees(query); + } + + @Get() + @SerializeOptions({ groups: ['comment-list'] }) + async list( + @Query( + new ValidationPipe({ + transform: true, + forbidUnknownValues: true, + validationError: { target: false }, + }), + ) + query: QueryCommentDto, + ) { + return this.service.paginate(query); + } + + @Post() + @SerializeOptions({ groups: ['comment-detail'] }) + async store( + @Body( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + forbidUnknownValues: true, + validationError: { target: false }, + }), + ) + data: CreateCommentDto, + ) { + return this.service.create(data); + } + + @Delete(':id') + @SerializeOptions({ groups: ['comment-detail'] }) + async delete(@Param('id', new ParseUUIDPipe()) id: string) { + return this.service.delete(id); + } +} diff --git a/src/modules/content/controllers/index.ts b/src/modules/content/controllers/index.ts index 66c1b42..92546eb 100644 --- a/src/modules/content/controllers/index.ts +++ b/src/modules/content/controllers/index.ts @@ -1 +1,4 @@ +export * from './category.controller'; +export * from './comment.controller'; export * from './post.controller'; +export * from './tag.controller'; diff --git a/src/modules/content/controllers/post.controller.ts b/src/modules/content/controllers/post.controller.ts index 465616a..c93c813 100644 --- a/src/modules/content/controllers/post.controller.ts +++ b/src/modules/content/controllers/post.controller.ts @@ -13,10 +13,9 @@ import { ValidationPipe, } from '@nestjs/common'; -import { CreatePostDto, UpdatePostDto } from '@/modules/content/dtos'; +import { CreatePostDto, QueryPostDto, UpdatePostDto } from '@/modules/content/dtos'; import { PostService } from '@/modules/content/services'; import { AppIntercepter } from '@/modules/core/providers'; -import { PaginateOptions } from '@/modules/database/types'; /** * 文章控制器 @@ -39,7 +38,7 @@ export class PostController { validationError: { target: false }, }), ) - options: PaginateOptions, + options: QueryPostDto, ) { return this.postService.paginate(options); } diff --git a/src/modules/content/controllers/tag.controller.ts b/src/modules/content/controllers/tag.controller.ts new file mode 100644 index 0000000..4158430 --- /dev/null +++ b/src/modules/content/controllers/tag.controller.ts @@ -0,0 +1,92 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseUUIDPipe, + Patch, + Post, + Query, + SerializeOptions, + UseInterceptors, + ValidationPipe, +} from '@nestjs/common'; + +import { CreateTagDto, QueryCategoryDto, UpdateTagDto } from '@/modules/content/dtos'; +import { TagService } from '@/modules/content/services'; +import { AppIntercepter } from '@/modules/core/providers'; + +@UseInterceptors(AppIntercepter) +@Controller('tags') +export class TagController { + constructor(protected service: TagService) {} + + @Get() + @SerializeOptions({}) + async list( + @Query( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + forbidUnknownValues: true, + validationError: { target: false }, + }), + ) + options: QueryCategoryDto, + ) { + return this.service.paginate(options); + } + + @Get(':id') + @SerializeOptions({}) + async detail( + @Param('id', new ParseUUIDPipe()) + id: string, + ) { + return this.service.detail(id); + } + + @Post() + @SerializeOptions({}) + async store( + @Body( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + forbidUnknownValues: true, + validationError: { target: false }, + groups: ['create'], + }), + ) + data: CreateTagDto, + ) { + return this.service.create(data); + } + + @Patch() + @SerializeOptions({}) + async update( + @Body( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + forbidUnknownValues: true, + validationError: { target: false }, + groups: ['update'], + }), + ) + data: UpdateTagDto, + ) { + return this.service.update(data); + } + + @Delete(':id') + @SerializeOptions({}) + async delete(@Param('id', new ParseUUIDPipe()) id: string) { + return this.service.delete(id); + } +} diff --git a/src/modules/content/dtos/category.dto.ts b/src/modules/content/dtos/category.dto.ts new file mode 100644 index 0000000..3ad295e --- /dev/null +++ b/src/modules/content/dtos/category.dto.ts @@ -0,0 +1,63 @@ +import { PartialType } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { + IsDefined, + IsNotEmpty, + IsNumber, + IsOptional, + IsUUID, + MaxLength, + Min, + ValidateIf, +} from 'class-validator'; +import { toNumber } from 'lodash'; + +import { PaginateOptions } from '@/modules/database/types'; + +export class QueryCategoryDto implements PaginateOptions { + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: '当前页数必须大于1' }) + @IsNumber() + @IsOptional() + page = 1; + + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: '每页显示数量必须大于1' }) + @IsNumber() + @IsOptional() + limit: 10; +} + +/** + * 分类新增验证 + */ +export class CreateCategoryDto { + @MaxLength(25, { + always: true, + message: '分类名称长度最大为$constraint1', + }) + @IsNotEmpty({ groups: ['create'], message: '分类名称不能为空' }) + @IsOptional({ groups: ['update'] }) + name: string; + + @IsUUID(undefined, { always: true, message: '父分类ID格式不正确' }) + @ValidateIf((value) => value.parent !== null && value.parent) + @IsOptional({ always: true }) + @Transform(({ value }) => (value === 'null' ? null : value)) + parent?: string; + + @Transform(({ value }) => toNumber(value)) + @Min(0, { always: true, message: '排序值必须大于0' }) + @IsNumber(undefined, { always: true }) + @IsOptional({ always: true }) + customOrder = 0; +} + +/** + * 分类更新验证 + */ +export class UpdateCategoryDto extends PartialType(CreateCategoryDto) { + @IsUUID(undefined, { groups: ['update'], message: '分类ID格式不正确' }) + @IsDefined({ groups: ['update'], message: '分类ID必须指定' }) + id: string; +} diff --git a/src/modules/content/dtos/comment.dto.ts b/src/modules/content/dtos/comment.dto.ts new file mode 100644 index 0000000..b3f833e --- /dev/null +++ b/src/modules/content/dtos/comment.dto.ts @@ -0,0 +1,61 @@ +import { PickType } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { + IsDefined, + IsNotEmpty, + IsNumber, + IsOptional, + IsUUID, + MaxLength, + Min, + ValidateIf, +} from 'class-validator'; + +import { toNumber } from 'lodash'; + +import { PaginateOptions } from '@/modules/database/types'; + +/** + * 评论分页查询验证 + */ +export class QueryCommentDto implements PaginateOptions { + @IsUUID(undefined, { message: 'ID格式错误' }) + @IsOptional() + post?: string; + + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: '当前页数必须大于1' }) + @IsNumber() + @IsOptional() + page = 1; + + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: '每页显示数量必须大于1' }) + @IsNumber() + @IsOptional() + limit: 10; +} + +/** + * 评论树查询 + */ +export class QueryCommentTreeDto extends PickType(QueryCommentDto, ['post']) {} + +/** + * 评论新增验证 + */ +export class CreateCommentDto { + @MaxLength(1000, { message: '评论内容长度最大为$constraint1' }) + @IsNotEmpty({ message: '评论内容不能为空' }) + body: string; + + @IsUUID(undefined, { message: 'ID格式错误' }) + @IsDefined({ message: 'ID必须指定' }) + post: string; + + @IsUUID(undefined, { message: 'ID格式错误' }) + @ValidateIf((value) => value.parent !== null && value.parent) + @IsOptional({ always: true }) + @Transform(({ value }) => (value === 'null' ? null : value)) + parent?: string; +} diff --git a/src/modules/content/dtos/index.ts b/src/modules/content/dtos/index.ts index f9efaaa..48adeb3 100644 --- a/src/modules/content/dtos/index.ts +++ b/src/modules/content/dtos/index.ts @@ -1 +1,4 @@ +export * from './category.dto'; +export * from './comment.dto'; export * from './post.dto'; +export * from './tag.dto'; diff --git a/src/modules/content/dtos/post.dto.ts b/src/modules/content/dtos/post.dto.ts index 372c38b..edf7994 100644 --- a/src/modules/content/dtos/post.dto.ts +++ b/src/modules/content/dtos/post.dto.ts @@ -46,6 +46,14 @@ export class QueryPostDto implements PaginateOptions { @IsNumber() @IsOptional() limit: 10; + + @IsUUID(undefined, { message: '分类ID必须是UUID' }) + @IsOptional() + category?: string; + + @IsUUID(undefined, { message: '标签ID必须是UUID' }) + @IsOptional() + tag?: string; } /** @@ -93,6 +101,19 @@ export class CreatePostDto { @IsNumber(undefined, { always: true }) @IsOptional({ always: true }) customOrder = 0; + + @IsUUID(undefined, { message: '分类ID必须是UUID', each: true, always: true }) + @IsOptional({ groups: ['update'] }) + category: string; + + @IsUUID(undefined, { + each: true, + always: true, + message: '每个标签ID必须是UUID', + }) + @IsNotEmpty({ groups: ['create'], message: '至少需要一个标签' }) + @IsOptional({ always: true }) + tags?: string[]; } /** diff --git a/src/modules/content/dtos/tag.dto.ts b/src/modules/content/dtos/tag.dto.ts new file mode 100644 index 0000000..f7f48ba --- /dev/null +++ b/src/modules/content/dtos/tag.dto.ts @@ -0,0 +1,60 @@ +import { PartialType } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { + IsDefined, + IsNotEmpty, + IsNumber, + IsOptional, + IsUUID, + MaxLength, + Min, +} from 'class-validator'; +import { toNumber } from 'lodash'; + +import { PaginateOptions } from '@/modules/database/types'; + +/** + * 标签分页查询验证 + */ +export class QueryTagsDto implements PaginateOptions { + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: '当前页数必须大于1' }) + @IsNumber() + @IsOptional() + page = 1; + + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: '每页显示数量必须大于1' }) + @IsNumber() + @IsOptional() + limit: 10; +} + +/** + * 标签新增验证 + */ +export class CreateTagDto { + @MaxLength(25, { + always: true, + message: '标签名称长度最大为$constraint1', + }) + @IsNotEmpty({ groups: ['create'], message: '标签名称不能为空' }) + @IsOptional({ groups: ['update'] }) + name: string; + + @MaxLength(255, { + always: true, + message: '标签描述长度最大为$constraint1', + }) + @IsOptional({ always: true }) + description?: string; +} + +/** + * 标签更新验证 + */ +export class UpdateTagDto extends PartialType(CreateTagDto) { + @IsUUID(undefined, { groups: ['update'], message: '标签ID格式不正确' }) + @IsDefined({ groups: ['update'], message: '标签ID必须指定' }) + id: string; +} diff --git a/src/modules/content/entities/category.entity.ts b/src/modules/content/entities/category.entity.ts new file mode 100644 index 0000000..219d01d --- /dev/null +++ b/src/modules/content/entities/category.entity.ts @@ -0,0 +1,57 @@ +import { Exclude, Expose, Type } from 'class-transformer'; +import { + BaseEntity, + Column, + DeleteDateColumn, + Entity, + Index, + OneToMany, + PrimaryColumn, + Relation, + Tree, + TreeChildren, + TreeParent, +} from 'typeorm'; + +import { PostEntity } from './post.entity'; + +@Exclude() +@Tree('materialized-path') +@Entity('content_categories') +export class CategoryEntity extends BaseEntity { + @Expose() + @PrimaryColumn({ type: 'varchar', generated: 'uuid', length: 36 }) + id: string; + + @Expose() + @Column({ comment: '分类名称' }) + @Index({ fulltext: true }) + name: string; + + @Expose({ groups: ['category-tree', 'category-list', 'category-detail'] }) + @Column({ comment: '分类排序', default: 0 }) + customOrder: number; + + @Expose() + @Type(() => Date) + @DeleteDateColumn({ + comment: '删除时间', + }) + deletedAt: Date; + + @Expose({ groups: ['category-list'] }) + depth = 0; + + @Expose({ groups: ['category-detail', 'category-list'] }) + @TreeParent({ onDelete: 'NO ACTION' }) + parent: Relation | null; + + @Expose({ groups: ['category-tree'] }) + @TreeChildren({ cascade: true }) + children: Relation[]; + + @OneToMany(() => PostEntity, (post) => post.category, { + cascade: true, + }) + posts: Relation; +} diff --git a/src/modules/content/entities/comment.entity.ts b/src/modules/content/entities/comment.entity.ts new file mode 100644 index 0000000..9759d7e --- /dev/null +++ b/src/modules/content/entities/comment.entity.ts @@ -0,0 +1,53 @@ +import { Exclude, Expose } from 'class-transformer'; +import { + BaseEntity, + Column, + CreateDateColumn, + Entity, + ManyToOne, + PrimaryColumn, + Relation, + Tree, + TreeChildren, + TreeParent, +} from 'typeorm'; + +import { PostEntity } from '@/modules/content/entities/post.entity'; + +@Exclude() +@Tree('materialized-path') +@Entity('content_comments') +export class CommentEntity extends BaseEntity { + @Expose() + @PrimaryColumn({ type: 'varchar', generated: 'uuid', length: 36 }) + id: string; + + @Expose() + @Column({ comment: '评论内容', type: 'text' }) + body: string; + + @Expose() + @CreateDateColumn({ + comment: '创建时间', + }) + createdAt: Date; + + @Expose() + @ManyToOne(() => PostEntity, (post) => post.comments, { + nullable: false, + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + post: Relation; + + @Expose({ groups: ['comment-list'] }) + depth = 0; + + @Expose({ groups: ['comment-detail', 'comment-list'] }) + @TreeParent({ onDelete: 'NO ACTION' }) + parent: Relation | null; + + @Expose({ groups: ['comment-tree'] }) + @TreeChildren({ cascade: true }) + children: Relation; +} diff --git a/src/modules/content/entities/index.ts b/src/modules/content/entities/index.ts index b2450aa..6e55285 100644 --- a/src/modules/content/entities/index.ts +++ b/src/modules/content/entities/index.ts @@ -1 +1,4 @@ +export * from './category.entity'; +export * from './comment.entity'; export * from './post.entity'; +export * from './tag.entity'; diff --git a/src/modules/content/entities/post.entity.ts b/src/modules/content/entities/post.entity.ts index 550f265..9aa1a52 100644 --- a/src/modules/content/entities/post.entity.ts +++ b/src/modules/content/entities/post.entity.ts @@ -1,55 +1,115 @@ -import { Exclude, Expose } from 'class-transformer'; +import { Exclude, Expose, Type } from 'class-transformer'; import { BaseEntity, Column, CreateDateColumn, + DeleteDateColumn, Entity, + Index, + JoinTable, + ManyToMany, + ManyToOne, + OneToMany, PrimaryColumn, + Relation, UpdateDateColumn, } from 'typeorm'; -import { PostBodyType } from '@/modules/content/constants'; +import { PostBodyType } from '../constants'; + +import { CategoryEntity } from './category.entity'; +import { CommentEntity } from './comment.entity'; +import { TagEntity } from './tag.entity'; @Exclude() @Entity('content_posts') export class PostEntity extends BaseEntity { @Expose() - @PrimaryColumn({ type: 'varchar', generated: 'uuid', length: '36' }) + @PrimaryColumn({ type: 'varchar', generated: 'uuid', length: 36 }) id: string; @Expose() @Column({ comment: '文章标题' }) + @Index({ fulltext: true }) title: string; @Expose({ groups: ['post-detail'] }) @Column({ comment: '文章内容', type: 'text' }) + @Index({ fulltext: true }) body: string; @Expose() - @Column({ comment: '文章摘要', nullable: true }) - summary: string; + @Column({ comment: '文章描述', nullable: true }) + @Index({ fulltext: true }) + summary?: string; @Expose() @Column({ comment: '关键字', type: 'simple-array', nullable: true }) keywords?: string[]; @Expose() - @Column({ comment: '文章类型', type: 'varchar', default: PostBodyType.MD }) + @Column({ + comment: '文章类型', + type: 'varchar', + // 如果是mysql或者postgresql你可以使用enum类型 + // enum: PostBodyType, + default: PostBodyType.MD, + }) type: PostBodyType; @Expose() - @Column({ comment: '发布时间', type: 'varchar', nullable: true }) + @Column({ + comment: '发布时间', + type: 'varchar', + nullable: true, + }) publishedAt?: Date | null; @Expose() - @CreateDateColumn({ comment: '创建时间' }) + @Column({ comment: '自定义文章排序', default: 0 }) + customOrder: number; + + @Expose() + @CreateDateColumn({ + comment: '创建时间', + }) createdAt: Date; @Expose() - @UpdateDateColumn({ comment: '更新时间' }) + @UpdateDateColumn({ + comment: '更新时间', + }) updatedAt: Date; @Expose() - @Column({ comment: '文章自定义排序', default: 0 }) - customOrder: number; + @Type(() => Date) + @DeleteDateColumn({ + comment: '删除时间', + }) + deletedAt: Date; + + /** + * 通过queryBuilder生成的评论数量(虚拟字段) + */ + @Expose() + commentCount: number; + + @Expose() + @ManyToOne(() => CategoryEntity, (category) => category.posts, { + nullable: true, + onDelete: 'SET NULL', + }) + category: Relation; + + @Expose() + @ManyToMany(() => TagEntity, (tag) => tag.posts, { + cascade: true, + }) + @JoinTable() + tags: Relation[]; + + @OneToMany(() => CommentEntity, (comment) => comment.post, { + cascade: true, + }) + comments: Relation[]; } diff --git a/src/modules/content/entities/tag.entity.ts b/src/modules/content/entities/tag.entity.ts new file mode 100644 index 0000000..2498f1c --- /dev/null +++ b/src/modules/content/entities/tag.entity.ts @@ -0,0 +1,29 @@ +import { Exclude, Expose } from 'class-transformer'; +import { Column, Entity, ManyToMany, PrimaryColumn, Relation } from 'typeorm'; + +import { PostEntity } from '@/modules/content/entities/post.entity'; + +@Exclude() +@Entity('content_tags') +export class TagEntity { + @Expose() + @PrimaryColumn({ type: 'varchar', generated: 'uuid', length: 36 }) + id: string; + + @Expose() + @Column({ comment: '标签名称' }) + name: string; + + @Expose() + @Column({ comment: '标签描述', nullable: true }) + description?: string; + + @ManyToMany(() => PostEntity, (post) => post.tags) + posts: Relation; + + /** + * 通过QueryBuilder生成的文章数量(虚拟字段) + */ + @Expose() + postCount: number; +} diff --git a/src/modules/content/repositories/category.repository.ts b/src/modules/content/repositories/category.repository.ts new file mode 100644 index 0000000..c5807fe --- /dev/null +++ b/src/modules/content/repositories/category.repository.ts @@ -0,0 +1,81 @@ +import { unset } from 'lodash'; +import { FindOptionsUtils, FindTreeOptions, TreeRepository } from 'typeorm'; + +import { CategoryEntity } from '@/modules/content/entities'; +import { CustomRepository } from '@/modules/database/decorators'; + +@CustomRepository(CategoryEntity) +export class CategoryRepository extends TreeRepository { + /** + * 构建基础查询器 + */ + buildBaseQB() { + return this.createQueryBuilder('category').leftJoinAndSelect('category.parent', 'parent'); + } + + /** + * 查询顶级分类 + * @param options + */ + findRoots(options?: FindTreeOptions) { + const escapeAlias = (alias: string) => this.manager.connection.driver.escape(alias); + const escapeColumn = (column: string) => this.manager.connection.driver.escape(column); + + const joinColumn = this.metadata.treeParentRelation!.joinColumns[0]; + const parentPropertyName = joinColumn.givenDatabaseName || joinColumn.databaseName; + + const qb = this.buildBaseQB().orderBy('category.customOrder', 'ASC'); + FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, options); + + return qb + .where(`${escapeAlias('category')}.${escapeColumn(parentPropertyName)} IS NULL`) + .getMany(); + } + + /** + * 查询后代分类 + * @param entity + * @param options + */ + findDescendants(entity: CategoryEntity, options?: FindTreeOptions) { + const qb = this.createDescendantsQueryBuilder('category', 'treeClosure', entity); + FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, options); + qb.orderBy('category.customOrder', 'ASC'); + + return qb.getMany(); + } + + /** + * 查询祖先分类 + * @param entity + * @param options + */ + findAncestors(entity: CategoryEntity, options?: FindTreeOptions) { + const qb = this.createAncestorsQueryBuilder('category', 'treeClosure', entity); + FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, options); + qb.orderBy('category.customOrder', 'ASC'); + + return qb.getMany(); + } + + /** + * 打平并展开树 + * @param trees + * @param depth + * @param parent + */ + async toFlatTrees(trees: CategoryEntity[], depth = 0, parent: CategoryEntity | null = null) { + const data: Omit[] = []; + + for (const tree of trees) { + tree.depth = depth; + tree.parent = parent; + const { children } = tree; + unset(tree, 'children'); + data.push(tree); + data.push(...(await this.toFlatTrees(children, depth + 1, tree))); + } + + return data as CategoryEntity[]; + } +} diff --git a/src/modules/content/repositories/comment.repository.ts b/src/modules/content/repositories/comment.repository.ts new file mode 100644 index 0000000..b5f6b4a --- /dev/null +++ b/src/modules/content/repositories/comment.repository.ts @@ -0,0 +1,137 @@ +import { pick, unset } from 'lodash'; +import { + FindOptionsUtils, + FindTreeOptions, + SelectQueryBuilder, + TreeRepository, + TreeRepositoryUtils, +} from 'typeorm'; + +import { CommentEntity } from '@/modules/content/entities'; +import { CustomRepository } from '@/modules/database/decorators'; + +type FindCommentTreeOptions = FindTreeOptions & { + addQuery?: (query: SelectQueryBuilder) => SelectQueryBuilder; +}; + +@CustomRepository(CommentEntity) +export class CommentRepository extends TreeRepository { + /** + * 构建基础查询器 + */ + buildBaseQB(qb: SelectQueryBuilder): SelectQueryBuilder { + return qb + .leftJoinAndSelect(`comment.parent`, 'parent') + .leftJoinAndSelect(`comment.post`, 'post') + .orderBy('comment.createdAt', 'DESC'); + } + + /** + * 查询树 + * @param options + */ + async findTrees(options: FindCommentTreeOptions = {}) { + options.relations = ['parent', 'children']; + + const roots = await this.findRoots(options); + await Promise.all(roots.map((root) => this.findDescendantsTree(root, options))); + + return roots; + } + + /** + * 查询顶级评论 + * @param options + */ + findRoots(options: FindCommentTreeOptions = {}) { + const { addQuery, ...rest } = options; + const escapeAlias = (alias: string) => this.manager.connection.driver.escape(alias); + const escapeColumn = (column: string) => this.manager.connection.driver.escape(column); + + const joinColumn = this.metadata.treeParentRelation!.joinColumns[0]; + const parentPropertyName = joinColumn.givenDatabaseName || joinColumn.databaseName; + + let qb = this.buildBaseQB(this.createQueryBuilder('comment')); + FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, rest); + qb.where(`${escapeAlias('comment')}.${escapeColumn(parentPropertyName)} IS NULL`); + qb = addQuery ? addQuery(qb) : qb; + + return qb.getMany(); + } + + /** + * 创建后代查询器 + * @param closureTableAlias + * @param entity + * @param options + */ + createDtsQueryBuilder( + closureTableAlias: string, + entity: CommentEntity, + options: FindCommentTreeOptions = {}, + ): SelectQueryBuilder { + const { addQuery } = options; + const qb = this.buildBaseQB( + super.createDescendantsQueryBuilder('comment', closureTableAlias, entity), + ); + + return addQuery ? addQuery(qb) : qb; + } + + /** + * 查询后代树 + * @param entity + * @param options + */ + async findDescendantsTree( + entity: CommentEntity, + options: FindCommentTreeOptions = {}, + ): Promise { + const qb: SelectQueryBuilder = this.createDtsQueryBuilder( + 'treeClosure', + entity, + options, + ); + FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, pick(options, ['relations', 'depth'])); + + const entities = await qb.getRawAndEntities(); + const relationMaps = TreeRepositoryUtils.createRelationMaps( + this.manager, + this.metadata, + 'comment', + entities.raw, + ); + + TreeRepositoryUtils.buildChildrenEntityTree( + this.metadata, + entity, + entities.entities, + relationMaps, + { + depth: -1, + ...pick(options, ['relations']), + }, + ); + + return entity; + } + + /** + * 打平并展开树 + * @param trees + * @param depth + */ + async toFlatTrees(trees: CommentEntity[], depth = 0) { + const data: Omit[] = []; + + for (const tree of trees) { + tree.depth = depth; + const { children } = tree; + unset(tree, 'children'); + data.push(tree); + data.push(...(await this.toFlatTrees(children, depth + 1))); + } + + return data as CommentEntity[]; + } +} diff --git a/src/modules/content/repositories/index.ts b/src/modules/content/repositories/index.ts index 626f965..5a00ce8 100644 --- a/src/modules/content/repositories/index.ts +++ b/src/modules/content/repositories/index.ts @@ -1 +1,4 @@ +export * from './category.repository'; +export * from './comment.repository'; export * from './post.repository'; +export * from './tag.repository'; diff --git a/src/modules/content/repositories/post.repository.ts b/src/modules/content/repositories/post.repository.ts index 1e8d443..eff5608 100644 --- a/src/modules/content/repositories/post.repository.ts +++ b/src/modules/content/repositories/post.repository.ts @@ -1,11 +1,21 @@ import { Repository } from 'typeorm'; -import { PostEntity } from '@/modules/content/entities'; +import { CommentEntity, PostEntity } from '@/modules/content/entities'; import { CustomRepository } from '@/modules/database/decorators'; @CustomRepository(PostEntity) export class PostRepository extends Repository { buildBaseQB() { - return this.createQueryBuilder('post'); + // 在查询之前先查询出评论数量在添加到commentCount字段上 + return this.createQueryBuilder('post') + .leftJoinAndSelect('post.category', 'category') + .leftJoinAndSelect('post.tags', 'tags') + .addSelect((subQuery) => { + return subQuery + .select('COUNT(c.id)', 'count') + .from(CommentEntity, 'c') + .where('c.post.id = post.id'); + }, 'commentCount') + .loadRelationCountAndMap('post.commentCount', 'post.comments'); } } diff --git a/src/modules/content/repositories/tag.repository.ts b/src/modules/content/repositories/tag.repository.ts new file mode 100644 index 0000000..ada14a3 --- /dev/null +++ b/src/modules/content/repositories/tag.repository.ts @@ -0,0 +1,18 @@ +import { Repository } from 'typeorm'; + +import { PostEntity, TagEntity } from '@/modules/content/entities'; +import { CustomRepository } from '@/modules/database/decorators'; + +@CustomRepository(TagEntity) +export class TagRepository extends Repository { + buildBaseQB() { + return this.createQueryBuilder('tag') + .leftJoinAndSelect('tag.posts', 'posts') + .addSelect( + (subQuery) => subQuery.select('COUNT(p.id)', 'count').from(PostEntity, 'p'), + 'postCount', + ) + .orderBy('postCount', 'DESC') + .loadRelationCountAndMap('tag.postCount', 'tag.posts'); + } +} diff --git a/src/modules/content/services/category.service.ts b/src/modules/content/services/category.service.ts new file mode 100644 index 0000000..4ac6fb5 --- /dev/null +++ b/src/modules/content/services/category.service.ts @@ -0,0 +1,129 @@ +import { Injectable } from '@nestjs/common'; + +import { isNil, omit } from 'lodash'; +import { EntityNotFoundError } from 'typeorm'; + +import { CreateCategoryDto, QueryCategoryDto, UpdateCategoryDto } from '@/modules/content/dtos'; +import { CategoryEntity } from '@/modules/content/entities'; +import { CategoryRepository } from '@/modules/content/repositories'; +import { treePaginate } from '@/modules/database/helpers'; + +/** + * 分类数据操作 + */ +@Injectable() +export class CategoryService { + constructor(protected repository: CategoryRepository) {} + + /** + * 查询分类树 + */ + async findTress() { + return this.repository.findTrees(); + } + + /** + * 获取分页数据 + * @param options 分页选项 + */ + async paginate(options: QueryCategoryDto) { + const tree = await this.repository.findTrees(); + const data = await this.repository.toFlatTrees(tree); + + return treePaginate(options, data); + } + + /** + * 获取数据详情 + * @param id + */ + async detail(id: string) { + return this.repository.findOneOrFail({ + where: { id }, + relations: ['parent'], + }); + } + + /** + * 新增分类 + * @param data + */ + async create(data: CreateCategoryDto) { + const item = await this.repository.save({ + ...data, + parent: await this.getParent(undefined, data.parent), + }); + + return this.detail(item.id); + } + + /** + * 更新分类 + * @param data + */ + async update(data: UpdateCategoryDto) { + await this.repository.update(data.id, omit(data, ['id', 'parent'])); + const item = await this.detail(data.id); + const parent = await this.getParent(item.parent?.id, data.parent); + const sholdUpdateParent = + (!isNil(item.parent) && !isNil(parent) && item.parent.id !== parent.id) || + (isNil(item.parent) && !isNil(parent)) || + (!isNil(item.parent) && isNil(parent)); + + // 父分类单独更新 + if (parent !== undefined && sholdUpdateParent) { + item.parent = parent; + await this.repository.save(item, { reload: true }); + } + + return item; + } + + /** + * 删除分类 + * @param id + */ + async delete(id: string) { + const item = await this.repository.findOneOrFail({ + where: { id }, + relations: ['parent', 'children'], + }); + + // 把子分类提升一级 + if (!isNil(item.children) && item.children.length > 0) { + const nchildren = [...item.children].map((c) => { + c.parent = item.parent; + return item; + }); + + await this.repository.save(nchildren, { reload: true }); + } + + return this.repository.remove(item); + } + + /** + * 获取请求传入的父分类 + * @param current 当前分类的ID + * @param parentId + */ + protected async getParent(current?: string, parentId?: string) { + if (current === parentId) return undefined; + + let parent: CategoryEntity | undefined; + + if (parentId !== undefined) { + if (parentId !== null) return null; + + parent = await this.repository.findOne({ where: { id: parentId } }); + + if (!parent) + throw new EntityNotFoundError( + CategoryEntity, + `Parent category ${parentId} not exists !`, + ); + } + + return parent; + } +} diff --git a/src/modules/content/services/comment.service.ts b/src/modules/content/services/comment.service.ts new file mode 100644 index 0000000..e80e974 --- /dev/null +++ b/src/modules/content/services/comment.service.ts @@ -0,0 +1,123 @@ +import { ForbiddenException, Injectable } from '@nestjs/common'; + +import { isNil } from 'lodash'; + +import { EntityNotFoundError, SelectQueryBuilder } from 'typeorm'; + +import { CreateCommentDto, QueryCommentDto, QueryCommentTreeDto } from '@/modules/content/dtos'; +import { CommentEntity } from '@/modules/content/entities'; +import { CommentRepository, PostRepository } from '@/modules/content/repositories'; +import { treePaginate } from '@/modules/database/helpers'; + +/** + * 评论数据操作 + */ +@Injectable() +export class CommentService { + constructor( + protected repository: CommentRepository, + protected postRepository: PostRepository, + ) {} + + /** + * 直接查询评论树 + * @param options + */ + async findTrees(options: QueryCommentTreeDto = {}) { + return this.repository.findTrees({ + addQuery: (qb) => { + return isNil(options.post) ? qb : qb.where('post.id = :id', { id: options.post }); + }, + }); + } + + /** + * 查找一篇文章的评论并分页 + * @param dto + */ + async paginate(dto: QueryCommentDto) { + const { post, ...query } = dto; + const addQuery = (qb: SelectQueryBuilder) => { + const condition: Record = {}; + if (!isNil(post)) condition.post = post; + return Object.keys(condition).length > 0 ? qb.andWhere(condition) : qb; + }; + + const data = await this.repository.findRoots({ addQuery }); + + let comments: CommentEntity[] = []; + + for (let i = 0; i < data.length; i++) { + const c = data[i]; + comments.push( + await this.repository.findDescendantsTree(c, { + addQuery, + }), + ); + } + comments = await this.repository.toFlatTrees(comments); + return treePaginate(query, comments); + } + + /** + * 新增评论 + * @param data + * @param user + */ + async create(data: CreateCommentDto) { + const parent = await this.getParent(undefined, data.parent); + + if (!isNil(parent) && parent.post.id !== data.post) { + throw new ForbiddenException('Parent comment and child comment must belong same post!'); + } + + const item = await this.repository.save({ + ...data, + parent, + post: await this.getPost(data.post), + }); + + return this.repository.findOneOrFail({ where: { id: item.id } }); + } + + /** + * 删除评论 + * @param id + */ + async delete(id: string) { + const comment = await this.repository.findOneOrFail({ where: { id: id ?? null } }); + return this.repository.remove(comment); + } + + /** + * 获取评论所属文章实例 + * @parem id + */ + protected async getPost(id: string) { + return !isNil(id) ? this.postRepository.findOneOrFail({ where: { id } }) : id; + } + + /** + * 获取请求传入的父分类 + * @param current 当前分类的ID + * @param parentId + */ + protected async getParent(current?: string, parentId?: string) { + if (current === parentId) return undefined; + let parent: CommentEntity | undefined; + if (parentId !== undefined) { + if (parentId === null) return null; + parent = await this.repository.findOne({ + relations: ['parent', 'post'], + where: { id: parentId }, + }); + if (!parent) + throw new EntityNotFoundError( + CommentEntity, + `Parent comment ${parentId} not exists !`, + ); + } + + return parent; + } +} diff --git a/src/modules/content/services/index.ts b/src/modules/content/services/index.ts index e0eabc7..7d64e84 100644 --- a/src/modules/content/services/index.ts +++ b/src/modules/content/services/index.ts @@ -1,2 +1,4 @@ +export * from './category.service'; +export * from './comment.service'; export * from './post.service'; -export * from './sanitize.service'; +export * from './tag.service'; diff --git a/src/modules/content/services/post.service.ts b/src/modules/content/services/post.service.ts index 30f8851..39524d5 100644 --- a/src/modules/content/services/post.service.ts +++ b/src/modules/content/services/post.service.ts @@ -1,27 +1,37 @@ import { Injectable } from '@nestjs/common'; -import { isFunction, isNil, omit } from 'lodash'; +import { isArray, isFunction, isNil, omit } from 'lodash'; -import { EntityNotFoundError, IsNull, Not, SelectQueryBuilder } from 'typeorm'; +import { EntityNotFoundError, In, IsNull, Not, SelectQueryBuilder } from 'typeorm'; import { PostOrderType } from '@/modules/content/constants'; -import { CreatePostDto, UpdatePostDto } from '@/modules/content/dtos'; +import { CreatePostDto, QueryPostDto, UpdatePostDto } from '@/modules/content/dtos'; import { PostEntity } from '@/modules/content/entities'; -import { PostRepository } from '@/modules/content/repositories'; +import { CategoryRepository, PostRepository, TagRepository } from '@/modules/content/repositories'; +import { CategoryService } from '@/modules/content/services/category.service'; import { paginate } from '@/modules/database/helpers'; -import { PaginateOptions, QueryHook } from '@/modules/database/types'; +import { QueryHook } from '@/modules/database/types'; + +type FindParams = { + [key in keyof Omit]: QueryPostDto[key]; +}; @Injectable() export class PostService { - constructor(protected repository: PostRepository) {} + constructor( + protected repository: PostRepository, + protected categoryRepository: CategoryRepository, + protected categoryService: CategoryService, + protected tagRepository: TagRepository, + ) {} /** * 获取分页数据 * @param options 分页选项 * @param callback 添加额外的查询 */ - async paginate(options: PaginateOptions, callback?: QueryHook) { + async paginate(options: QueryPostDto, callback?: QueryHook) { const qb = await this.buildListQuery(this.repository.buildBaseQB(), options, callback); return paginate(qb, options); } @@ -45,7 +55,21 @@ export class PostService { * @param data */ async create(data: CreatePostDto) { - const item = await this.repository.save(data); + const createPostDto = { + ...data, + // 文章所属的分类 + category: !isNil(data.category) + ? await this.categoryRepository.findOneOrFail({ where: { id: data.category } }) + : null, + // 文章关联的标签 + tags: isArray(data.tags) + ? await this.tagRepository.findBy({ + id: In(data.tags), + }) + : [], + }; + + const item = await this.repository.save(createPostDto); return this.detail(item.id); } @@ -55,7 +79,28 @@ export class PostService { * @param data */ async update(data: UpdatePostDto) { - await this.repository.update(data.id, omit(data, ['id'])); + const post = await this.detail(data.id); + + if (data.category !== undefined) { + // 更新分类 + const category = isNil(data.category) + ? null + : await this.categoryRepository.findOneByOrFail({ id: data.category }); + post.category = category; + this.repository.save(post, { reload: true }); + } + + if (isArray(data.tags)) { + // 更新文章关联标签 + await this.repository + .createQueryBuilder('post') + .relation(PostEntity, 'tags') + .of(post) + .addAndRemove(data.tags, post.tags ?? []); + } + + await this.repository.update(data.id, omit(data, ['id', 'tags', 'category'])); + return this.detail(data.id); } @@ -76,23 +121,26 @@ export class PostService { */ protected async buildListQuery( qb: SelectQueryBuilder, - options: Record, + options: FindParams, callback?: QueryHook, ) { - const { orderBy, isPublished } = options; - let newQb = qb; + const { category, tag, orderBy, isPublished } = options; if (typeof isPublished === 'boolean') { - newQb = isPublished - ? newQb.where({ + isPublished + ? qb.where({ publishedAt: Not(IsNull()), }) - : newQb.where({ + : qb.where({ publishedAt: IsNull(), }); } - newQb = this.queryOrderBy(newQb, orderBy); - if (callback) return callback(newQb); - return newQb; + + this.queryOrderBy(qb, orderBy); + if (category) await this.queryByCategory(category, qb); + // 查询某个标签关联的文章 + if (tag) qb.where('tags.id = :id', { id: tag }); + if (callback) return callback(qb); + return qb; } /** @@ -108,13 +156,31 @@ export class PostService { return qb.orderBy('post.updatedAt', 'DESC'); case PostOrderType.PUBLISHED: return qb.orderBy('post.publishedAt', 'DESC'); + case PostOrderType.COMMENTCOUNT: + return qb.orderBy('commentCount', 'DESC'); case PostOrderType.CUSTOM: return qb.orderBy('customOrder', 'DESC'); default: return qb .orderBy('post.createdAt', 'DESC') .addOrderBy('post.updatedAt', 'DESC') - .addOrderBy('post.publishedAt', 'DESC'); + .addOrderBy('post.publishedAt', 'DESC') + .addOrderBy('post.commentCount', 'DESC'); } } + + /** + * 查询出分类及后代分类下的所有文章的Query构建 + * @param id + * @param qb + */ + protected async queryByCategory(id: string, qb: SelectQueryBuilder) { + const root = await this.categoryService.detail(id); + const tree = await this.categoryRepository.findDescendantsTree(root); + const flatDes = await this.categoryRepository.toFlatTrees(tree.children); + const ids = [tree.id, ...flatDes.map((item) => item.id)]; + return qb.where('category.id IN (:...ids)', { + ids, + }); + } } diff --git a/src/modules/content/services/tag.service.ts b/src/modules/content/services/tag.service.ts new file mode 100644 index 0000000..e101e1c --- /dev/null +++ b/src/modules/content/services/tag.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@nestjs/common'; + +import { omit } from 'lodash'; + +import { CreateTagDto, QueryTagsDto, UpdateTagDto } from '@/modules/content/dtos'; +import { TagRepository } from '@/modules/content/repositories'; +import { paginate } from '@/modules/database/helpers'; + +/** + * 标签数据操作 + */ +@Injectable() +export class TagService { + constructor(protected repository: TagRepository) {} + + /** + * 获取标签数据 + * @param options 分页选项 + * @param callback 添加额外的查询 + */ + async paginate(options: QueryTagsDto) { + const qb = this.repository.buildBaseQB(); + return paginate(qb, options); + } + + /** + * 查询单个标签信息 + * @param id + * @param callback 添加额外的查询 + */ + async detail(id: string) { + const qb = this.repository.buildBaseQB(); + qb.where(`tag.id = :id`, { id }); + return qb.getOneOrFail(); + } + + /** + * 创建标签 + * @param data + */ + async create(data: CreateTagDto) { + const item = await this.repository.save(data); + return this.detail(item.id); + } + + /** + * 更新标签 + * @param data + */ + async update(data: UpdateTagDto) { + await this.repository.update(data.id, omit(data, ['id'])); + return this.detail(data.id); + } + + /** + * 删除标签 + * @param id + */ + async delete(id: string) { + const item = await this.repository.findOneByOrFail({ id }); + return this.repository.remove(item); + } +} diff --git a/src/modules/content/subscribers/post.subscriber.ts b/src/modules/content/subscribers/post.subscriber.ts index 24d15b6..b1e4b70 100644 --- a/src/modules/content/subscribers/post.subscriber.ts +++ b/src/modules/content/subscribers/post.subscriber.ts @@ -3,7 +3,7 @@ import { DataSource, EventSubscriber } from 'typeorm'; import { PostBodyType } from '@/modules/content/constants'; import { PostEntity } from '@/modules/content/entities'; import { PostRepository } from '@/modules/content/repositories'; -import { SanitizeService } from '@/modules/content/services'; +import { SanitizeService } from '@/modules/content/services/sanitize.service'; @EventSubscriber() export class PostSubscriber { diff --git a/src/modules/database/helpers.ts b/src/modules/database/helpers.ts index aac21e3..5fe2fde 100644 --- a/src/modules/database/helpers.ts +++ b/src/modules/database/helpers.ts @@ -13,34 +13,61 @@ export const paginate = async ( options: PaginateOptions, ): Promise> => { const limit = isNil(options.limit) || options.limit < 1 ? 1 : options.limit; - const page = isNil(options.page) || options.page < 1 ? 1 : options.page; - const start = page >= 1 ? page - 1 : 0; - const totalItems = await qb.getCount(); - qb.take(limit).skip(start * limit); - const items = await qb.getMany(); - const totalPages = totalItems % limit === 0 ? Math.floor(totalItems / limit) : Math.floor(totalItems / limit) + 1; - const remainder = totalItems % limit !== 0 ? totalItems % limit : limit; - const itemCount = page < totalPages ? limit : remainder; - return { items, meta: { totalItems, - totalPages, itemCount, perPage: limit, + totalPages, currentPage: page, }, }; }; + +/** + * 数据手动分页函数 + * @param options 分页选项 + * @param data 数据列表 + */ +export const treePaginate = ( + options: PaginateOptions, + data: E[], +): PaginateReturn => { + const { page, limit } = options; + let items: E[] = []; + const totalItems = data.length; + const totalRst = totalItems / limit; + const totalPages = + totalRst > Math.floor(totalRst) ? Math.floor(totalRst) + 1 : Math.floor(totalRst); + + let itemCount = 0; + + if (page <= totalPages) { + itemCount = page === totalPages ? totalItems - (totalPages - 1) * limit : limit; + const start = (page - 1) * limit; + items = data.slice(start, start + itemCount); + } + + return { + meta: { + itemCount, + totalItems, + perPage: limit, + totalPages, + currentPage: page, + }, + items, + }; +};