From c342fa1902c13953a975e29a5550f7d48cbfcff4 Mon Sep 17 00:00:00 2001 From: e Date: Wed, 21 Feb 2024 18:47:12 +0100 Subject: [PATCH] initial commit --- .github/workflows/ci.yml | 32 +++ .gitignore | 4 + Dockerfile | 17 ++ assets/contact.html | 39 +++ assets/index.html | 42 +++ assets/portrait.png | Bin 0 -> 37554 bytes assets/style.css | 41 +++ assets/thanks.html | 33 +++ docker-compose.yml | 15 + package.json | 24 ++ readme.md | 3 + src/index.ts | 83 ++++++ tsconfig.json | 17 ++ yarn.lock | 579 +++++++++++++++++++++++++++++++++++++++ 14 files changed, 929 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 assets/contact.html create mode 100644 assets/index.html create mode 100644 assets/portrait.png create mode 100644 assets/style.css create mode 100644 assets/thanks.html create mode 100644 docker-compose.yml create mode 100644 package.json create mode 100644 readme.md create mode 100644 src/index.ts create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..24abbcc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: + - "*" + +jobs: + docker_build_and_publish: + name: Build and push Docker image to Docker Hub + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Push to Docker Hub + uses: docker/build-push-action@v1 # Info: https://github.com/docker/build-push-action/tree/releases/v1#tags + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + repository: ${{ secrets.DOCKERHUB_REPOSITORY }} + tag_with_ref: true # Info: https://github.com/docker/build-push-action/tree/releases/v1#tag_with_ref + tag_with_sha: true # Info: https://github.com/docker/build-push-action/tree/releases/v1#tag_with_sha + tags: ${{ env.GITHUB_REF }} + # helm_build_and_publish: + # name: Build and push helm chart + # runs-on: ubuntu-latest + # steps: [ ] + # update_gitops: + # name: Update Gitops repo to use latest version + # runs-on: ubuntu-latest + # steps: [ ] \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..719784c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules +lib +tsconfig.tsbuildinfo +.envrc \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1d104cf --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM node:21-alpine + +WORKDIR /usr/src/app + +COPY package.json /usr/src/app +COPY yarn.lock /usr/src/app + +RUN yarn + +COPY src /usr/src/app/src +COPY tsconfig.json /usr/src/app + +RUN yarn build + +COPY assets /usr/src/app/assets + +CMD node lib/index.js \ No newline at end of file diff --git a/assets/contact.html b/assets/contact.html new file mode 100644 index 0000000..7815b21 --- /dev/null +++ b/assets/contact.html @@ -0,0 +1,39 @@ + + + + + Eirik Kultorp's homepage + + + + + +
+

Contact me

+

+ Leave me a message +

+ +
+ + + +
+ +
+ + + \ No newline at end of file diff --git a/assets/index.html b/assets/index.html new file mode 100644 index 0000000..33f5453 --- /dev/null +++ b/assets/index.html @@ -0,0 +1,42 @@ + + + + + Eirik Kultorp's homepage + + + + + + +
+

Eirik Kultorp

+

+ Software engineer interested in high-performance computing, devops and infra, and knowledge representation. + Enjoys sci-fi and racket sports. + Based in Oslo. +

+ + + +
+ + + \ No newline at end of file diff --git a/assets/portrait.png b/assets/portrait.png new file mode 100644 index 0000000000000000000000000000000000000000..0d971042a2aba419a424ddfb60ac728fbe1d202e GIT binary patch literal 37554 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

b_puYoJ?NXa~|X9Wqv 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≧tlM>TK z@y2ATESoPn8D8?!$afZ=g^j5&bWQt08V!4d9mxTa5ec1D~ed*f`|j>dUI=X z(9P99Upc+`$-i*RRX_f%Q>$NmGxx?@UEWo|_L1+o;hOUoH~w2=s$H7Nlj0}hO}A;b zCS!Q%`~|rE;C@k?v;2c$;zYj(jd(>+GI|@74uPGrp2flvyD_z8u+(*n-=~1B0yJ^5 z!obQEL}^%|V&w!u9ofgi2IdZE_y+d11Y+3&@Mw+&u{#9ZmNVD* zgE?Lc832%h%SwEZS^%vec?PK~r;u`WVLGT<{?PlM5-O@Kjj2^pa=(=2e zqe&)e3I6Pz)syFuy9;^A&`(Qk(A9!{MTzRu(S{l}$C#5~>0jJ)^LuWD-7i0S;sm_y z(+q#d1KWMKE#5q}!+%;&&5uqT%UDy+GO?RMB>W3?I`zT@xU@EfYp*H^6O+20Q(x0& z(>!b~c1whPQ?QC(S+H1%z~K*AmQps9-{)i+Ue2QpH}&!qvz>(}R%%y^DPOF9XM3NF z&nP>|z{lnYKoud$e5C+QtpFhXYEibrh!==DRSV@)(}QIhi%ub+oaXAfv^9n^7m$4% zlTFR~c@A=+@3RnM&xE$D4?^wL1BSY2#YkUb>I2x^-2U`#yYC0?zr+0KW6!Ldc(eD< zn_0eNf$i8m2X?P-G>?wP@b|45?xwi+6=Ld|SQOm=A=fkm&gCmxaQfV3xcaKSNW1uC zcFk@_wVjGt%Yepo1km$jVPl8VR@X}osDyol=oygkca&?_Yb=?{Fq<|d>ZbBr(1v>z zz6lB$1{MZr&a{K?D$uC%gtLmqr@K`?47NH|_e0bk@HJ86ql}BXrOQt6efH&xaQ5<= zWBP`4jn1(b5=J6eFyJMR zw;w(V!^M(gdo(Q2Ta0ils(4BgPjD(MpyiEZbIgj0 z3|F@Slv!tTrhY9Q#|6tY)VZMl?2rZJ^O-oSV~1L)4+JyKSxUl2e!0Gd=@bsA#*n9VWM@lxKQV)s35<7(n;+gdc zDs}p0#O`Ey6V`ILll&d^9GK)mKwu|7PfoOmeMTE4MrOIPJ%;la z*Wq~wZ0l|grzpo^z5$LS0jk|^B1{ppzcE{B5;rm}JQsM6lTjk|Z^(y~`B3cB`nFx( z9>Gs-3@&`?=$+U9!k(h}ug6cGKlRq^y4P0T@xXT9ZTt2%#qcL4S1vrdSr4zV6vJae zi$FQ7X>)RL9?EEqb~6)XRBx--A2E%<#>`mI|sMjbRFzpUUCpHCU$Fr7@7`r zmZBA83QX|}4w5z?$r72u5x_Poe}$Axs(@hy1&B*nTkg~i zixf2gnhCCE3b3HEQ{(F|3J3_nvdM#}Sk3QfP-aR3LKPIG^FW`+bw|<8JNEnOvln1( ziWV{>Kvh$}OO?IAgjq>^GW9c!iPKoRbxN% z-dp$o{+{LCzgyJf&wceXtgo1@5 zCME4ojb^1D9YHxzdhMI~C8{}~AWwbKHrBlH8U70K%`7Rj9p}JqJW$0(?Eq~2M+zGf zyJS;?vYQf;Ts}#8!fsx!>z2D#Go@(MrdV=+u}g@k5E#d(pm0?F?8*i_d+s8vPLQHi zfhv>jOtecypwc?;eQadvy%Imm+E%vF(Vr+xLE9q@s`#ih6&l6ObhG*J=GMlC%fkHp zdk-J{>he-znZ$@tTwY58|26WB-WkHJHUBidYz z8ll}9UA1Q)tgWvLLT8mXZ%X4sbr-fB$G#?&d*N6ifD8-ekfySu1(ffWyftn*?3q-}@YrnV^FBG&I+3Neij=G``*rYY_i&K5U)` z1`_L8QSOK45eU?TlRDx-hmga7Yx)SRK_cE(YMk z>{)S3i-KzTkPVSGGM)#1CP9J`u(7ONvz-s;#iGWzpg%pBQ^0^SzmgRd57;8IFy!h? zq2Nc;;e%_N^@B@`!(Y1h=KcSBd5`(k<^8XG>G*MY%Y853F~IhLn-AVLHiMto+^j!Y z3>L4VaBnz)Mg(YmcZt%@aD@CIW-GG9t;7dtDnrv~P?Ci|E8OL5bjl#n!y z(}r?sBM(Fy2>6-C){;lt3vMl7W#hT^hgB(`Tfr2J(?4mXW+nmbVAV+O?t(%V6f|d3 z0;WMxGMhZ8$c?QsHED1$wG|$f8MzI+<*u(fR-291Yp^z^_|D|>sQd!~27V{N6_1bz zsM5LjYrtOu0E$6gy-LWmVnsts3@gX%RLv>1TUgl#V~1mfeJ5pALGy`aV^l1| z?L!+^4xGO4uEl?6SGGR;C$GMG?v3u%zVfyQHe?salkrbEV)OT=(|QrJYTEHc)Y=*k zF*wo!m?-LS!1_TG7ZzNVBC!e`ixETa#&`;6&R>Q<`sPVk7~BFk99(jnaY_^t?1Fn} zi8n9_=nn85fEP_gY*TO=Hs14JotHVH)>OJK$?1`0tJ$W-C%y$hK(&ax84FWHd)E5# zXfA`?2()I|Ig)J%fIr`gSUS9XW!(L25(DXd&KRXC$C%nE4z2?{Ttic&5txN z+=Jc|HF{x02O?v|K(Lo}!)&K6QMtwS3o6ec`+VwFPCtCbvqo~SGq}a z7}GAhjlbwNGO{&eK(&B1?3Ps8fT@x7Lv5r|U9ch27P*2sK%4?oKicQE5P!>Bu(@ri z^i`n~6b#k_mF5Fbg^j0n@_RA~25WY%4zeR{-ZDf-R;3AP`tW3fyRbGH!`Ula@a)Sg zaA|eJQGYkSYLVD#(pD1d$ZC)ri>SY6ou9+f7xP5tv@q>Z6Dcd50;g(h+rf>ja5shc zzYbt^bG+a%=ELjb$-}=rdj8bW+i&{!OACYl@_$b}cP87J*I3?Gz;^Eq`)+dh_LJW* z(@!i^yKY_G!etwh=SD5bb8+oU%300I0Rj&CEFx^zX0?J}UjVjv!F3V%J1-_F2GA7X z+P}Cpfj>QY4#v|8KK#HPuy5JWq5lGn+5-R~)IS#%i<6sYvsQ^2sIi)P+?tT-$O897tVg1^GF)ga2sBX&z@8v~$QZy6epsGEBK927S|} zX6ZigUN)9(t@Jh`6R#p`VBCygw6=ZAQdxawJQ{!IzFV*VQf174xanZ=`QLm4rw!f~ zz;^3FxOO?oXYu8?U z2^j#g5J;H}9_g>(!uk|8o;*W=cOE=?8|>YKa@Yuvx58^A%TWw}_L;X~YnENftgvrJ&W^GALZ~^Q?wzh;I}~5Us&_w!Q1E%zA~{aSsccux$D~;U+OXUR z1xMW)2sL)nnqwU+xUxBdQ|DITgICWeIHF7TRtv6GAPTB zY@91r-+%iJ|7oyL{n}$E&b(&Vux~4{-E$8N&D#D?xe@=9abvE5YCx`0sQN|>Z%Yof z-2lgDtlS@Aa*H9}CLPV3vP4?CfW{Jv7?nVcwp@u&5b^3~A4RF3n4=QLPChyQ^=Ig) z|APQA z_>2q;>tnROhL7|hqEMw48thR>C`9W@C`(?BglE zY+O>=z+=%Kc}?GK2)`NLOhPFU;f<%P=D+L~=SzQb64oap_|W&<35Tv8!m!vT*``88 zLc@xOtu03d#x*Q1ERoE{6fQU)v(7_UV`IFB2L^*h`&v`iUOwY@3U+<+Y@qRWJP_+0 z`#Dw++wXLK;&B#~33b|(=SZcG*{awpv?j$#YaI9(7m3w~{g=`h2g!G-~uTXSBYc4XZnqGj-E)$1DaeW&+eLgMB z)^vJob9>|1Vr520Z@K=9<-q>d@}T~$<0oF}brJh>2ex~!8~(+qS^AmA6d$i`SHw1Vqi-(VIGT0tPv!yyeu^vmkYM9 zp?i`k7vYZ{KLanFIS==L*CF`+`)-Hbi&FwLBb11=qGabPiQTddpXOF?jz&C9$TLN- zE8a(UEtEeRE1~WT*8?EHRj5Kl`_2bL*<&Pxm19}1Vebk#d)9~woFvMoAn!BOJYri= z3}EEAg%>Ygfv1zVjRyS=*;Z%Jk(=VC06$NY#w;VTX3DZQ!A~Ry9DQtMx>o7E z@EKJ6p%ma#K}L=Q`Sv_25L>?}nMApSc08Wjl6*#SEes{|LWauCBhLT866b)Ydx4HwFftrzB3j~qVmrNyH7?WLt_ek1kG{Br}g`>x-6bW{!hkzp4ei+PQ_{> z`=2JKD&z=^#$gQVYvt7&aY1Nlo-~&<)>!B{=qM&e#M>j#MoD&6DaDIu!E3reBU0H2 zTf55($b31Xu;ng1du1EW{J~T3^%LjehaP+{9J%vq$6{R)C+7hS78dC&8s>8=N@)YP zY%>vd2TzK#q(cfBEAktF@2?dZl_+1$wlV@LI`Sd`Vu6p(AO@zQ8`5fu{R=l! z*)TiWAj^byrvb^Nm$w0)c;-d;#&Z|o<#oqlVB{;BPb=@T3zy1~RAk*~c2xOez~7$* zKygVGSE*JpMyh(;reD!wSXt&NQvz)M@siK!dGm+fEZ9Gjcyl1+38J|byFQ>vl9Wv# zo+e^=KcC0ufa+ejwyuAF7zx`qi9(x}w+ASCk9Jo)`p~AzHQ#Z{{9&HBLuZdg0iFnOh31S+sY-7m9 z$Wc=_?xG?L+ju8tBW#dLmAolP(LtNUNgRg54^W;rJmTWm%6d9+NMHg3$AS+qij_kI z&9H#YZR=RZ37ooc1)ey40nWT~88#{Gg7FH6HrpM{1Uar@7LerTw~qzPU5}MYF)*iq zr{<8IlvJMgEH9mN4JF>WO1D8z<2hkGQpXWM#1N!gn9K z=I7pYV7up@dxp*0iyzvvy!&r$j+=+;a(VaW`ouxKXns)UFzv-?*~vha32HA2Ap&*+ zY_W{i2XJ~&G-V}s!s1w^NfHDIZ(-CZJWle3$DV~}&aS{;e&D@u*G*T$d+_{RJtCHr z*hpN&QjX7v=ChHraqJ|*K!m_j3WZ>Iu!iF>7V0$2he0iSF;jdF0$2^A3gU5L7*m^a z=zil-qXoEdX#-w-kKycvRe15$HMrz}Zhcz7$SjdE0PNVa)zc>O+K=YAZ~pt% zW+yCV?wNG$jde&UOPfw_#ZY->9=O0H4uPc9!g2Wz-nY4Mo(#zBGksAX!eCI&4a| zJdzCDJu|@s#KaD+O-uOZ(=Wld&Rl@!&R&Eo8>lfIkR$P=F(Rkdj*I7GKe)jt+KtQD5J;dNB*j9FMC?0&x5UuHXe7#6RF>poOgyME~MsWTt9#hx1`wPXD0RC7TIA*K@vC?oc=s%X3* znwHp;J%qW=8>97mI$;WEIqc@2k|jkQq^DJJzxo!qaD8f!}-V1e`p#4wuFQN;75b0s$BWc|gSq z=D;>Jotr?Rzqah|MzKkfxi*kTPP&F#x{8f%daAxP%FcW1d$$iU)l0*=r*)+F;%l8f zWB8jX4~{pY za)YG&6~i!VvjE1#^gF8Veth|x&%p^tRle`Y?eM)vZh?Kf4asSo5PpFuBRV0ooohk^ zBt4?UJ^|f~da?jGWC9{B4A^69o!8)I)i^nF)gisdo;U-)?*Q%WD#jUhtS*5lvx$Xa z3P@}^Qby7>mLPf+Hgby(mjK{lQ@;e|BbMrVC*dBQV%I6;2`$02U`o!v)`XMlj2gXyzveTN+ ziJ|=mtDR0qplNFf7$j9KPe3V+cQHdMNXLMdZhQ-2!gE+sYV7dxah(SG0TN4^bF9@z ziT=cZCRRCOzvQfQE%r7v%3B~RvEm5+@BHBt@Z~>!5{}$`J=}5A0a#jGg3XN$NBzen zpACltSXx?w-HR10Ryb1&FmSRKsM;PenyYt=3XFyiuA*Td=Nh?zJ$rVOW^#RV3{O7u zJUsp4t8nTSjBZsqYPL-5PHCou3>n*swo(uWDPdqh>qP*r^A{;gy!TEt?K81_LRoTY zvu4R%`rb~cUs{yIiQnV)yZd2wJ=SYL<9?^#eO+Xp0e{+pX$^}5Sz!BV_v{z%-uHmD zgTMaF*XxJsV&UedM&CZiVl-nn*&7sI04pi+3{%50L+v&WYQ)rli*lMND^U#>)Etsm zjOEdt1o4QlDhqY(U^GB500ue>5}wnkhSvRf@*qR~X0eX(M2p`(SV@Zn8hwfciGt2h zA@LZxe`tV*V(O@ho3DX^4JSK&<5UVO!hj0b3BH@17z^ z>+k%I*w#i;dByY4YD3)bXipH!PFLv}4{Qiv|Lcw$?+3H=$mg2LLr${3t*-erGE*>& zdpIFzs2i3~3Oc0dFzk3rAp@9nhK}fFpw57(y>TGcwBVuCTwY*2T_DailC@ze1v)mCRl5Q*6y^r$up0xR;ZwTk{gVH>*GXdqT-_&++f=7 zyT3NIO*L_t5!KQZk3EvB;s{QuvI1oWANpE0Dm|N-#JPiv-szXc!tY*9lK_3}^`G+R zE$pQ%l1J|bLhdqU2=WV+D+C;>z`Hd+(*;amjQ zCpYIx4nSIcPBwe`PVReLe0HANvekBkjC$qvOmnjlPFK{)Jzs533`J2# zZv{*Cl?kyY3S?Mf-rEC|wXK*KF}tQKo?D2t6Ip&c^N#-Z00Q|1;rE-);>FMR-NQeP z(+DaL=;Uc?TngbHC_ued|9JlXt3s~I;;MWQGj>M$2owW{o31-TjO6h0yJI5-A@1_+VQJ*K7jSR+k z4A4$V+_V#21MnL^nfmW8w)b$+GT;mJB$d}u_I@%jC?DTb;wb( zc>dFCeaK3m>!WJ%@7z1-bMt^-xeNZ?5B#}4q`-hbn`F(~dBMXv?qt9CenQwUedDUo zAWKfII0%XA@+HN1)oBr0eLVfKyuo=EH*G{EbFAMjr{Tx_jGb4Y*7}#TARYa$Physe~M{x7l_??z{fH(`V;=Xh@cNdWQsC-)A ztbWBnIUA|i4#$wrn~%FG@6y+p8un<;DX2TSRFR8`dY1=nWZKDi@Hw_XODD3`j7f@t zIL5lU0V|7@PHqcuq5FO`mmOBOZ!_>5iv3R~m(zP(Rp$n=pTL;FpG@#mMmc24! z*W1Cy&Qa=ko#u}7bplZmfMANsgMf=NX&Gv(qu6%~8g_ z`oS2FAXQ#Y;e**oOrlP|)laAG(HwuqX^P^>YePN@uwXT`9LV8G`CgVjp#?r)M}21_ zvGu`M3Zb$JWDF!KOXQUxrsbm3-OMyMO2IAobh^>hOM5DV7XCW*i7JUOT2k<8t$-<% z%CkQDzaA@!7R+z8gwobRsp9eIJAE5D-YA{^^#Eox{9t#|`2(TGa{kLi^`rpZ=mXKa zVQ%7fc>J{u@hm$?!Nl#_)_XB`!~9*uD)*dt!d|)P^EeO@`xl+80M&Vx=!(4>$q#Bn5s~SZ$bjT9StNyRlIp% z#xrSO(#~gDx43&nScX}xKQ0Zqq~V+p&MxEtFe zZOgAsOC}YO#MccuoY7lS$KBj`UQfv(%2{GfUrFEB(Ca&?Cq)2CjQZBI18fu)Af{+h zB}!rNuTPs5H;_FZ(_TpbJqDI^04boQn>2pbK=5G6O=znx$%N&;$CEW*9uQ2KQ17&) zm^nw8Ql!@biXJKzUrS}~oo&S6q4Nd^TC1(ARyiI|O7&*VbEPl&27o2EDgvOCn&mcmpN%ZtkUCL>AXNZW_7RI@V$#IzaeG?Q zgQRhrxza~L(sy%Il-wO-6~7TV3P4vpYDi!$sVCQuK2|oJ+uZn5lS6vHj|<4LoZbHM zn9}}*F+s;wEnSD)?-)V%^?P3FTkrOK1E^72Q*0@*$SK~^HHe8xx>nt`y6j_IZ_0sG zotFUk0Ad8OG5a_RyQhsR%adY?c(T&pOdYx`rhk`02T0PvSPlv37_t@6>*#CJ3Hxj4sdc*JVk<0TO^OQ@6Vg3{Qcb8CT)d#7P8MpZ)EFF>(bw? zdRXM=LTYxQH~cYuEyCO%hYY0T5_`dP&fN?$wVan|Y7*NUBVQBr@)9P5^& z1adbkfAqB%f2P;tF?3koq|Zv};tiLwq&W5S5e~N6< z`?Kz)eF{{oXA@@TB4ve)QCFt$T$c@l4q@VFIL86YTzNUxW?r7PX7irO?}JPS+dXOR z(Oey~*1m85-T5ajQLQ^wEebGn4T!r7c z@8Q`*p0j}s*KX2xNlvd*tnah-GzL-z1_iVj;Em2jp-;-QI*zE1Dd1~;&*KL63U8Sx-Jk7jk$eobva-5>e#O4u2G7`i!9#=Z2F$d*SAGe-K_YHD?A;Pro zhj{E*Djigg^y2kc0~s&yPFc9P&RqTJv$;CdYb1RqeQzEX?CW=nP0UaeE#a(NUfteT za+EE1Ul%U7QB!SKKN}p}jdB~mk1fshCpXu9TuW}8xjyvGQ{VXd+Uk^uJI(E@HbLnE zg1>LO@6Rf^IfyBL-2bX0yqmUNt#48ByJlbsULF0y;XHwIo(z`TWPQ)=bmPY*=bED> zrA+aro5up@`WqHKqK|VZmBxhV}Q<4yIJfcmfZU>koU+yYyuJ>h&X`0zcBOPB3nf4*&wB#sJ zZa?JeiT50jyW8HZ`cnW;iAvMhPMvALQv{IP&-xqzTPuVzw0#kC7&Z1=RAE!^rOrw@ zAnlU{(&zLuXTI>id0*}t?V~#!I>oZ@?z7t-|nff6SIS%>8?#V09*f9 zbzD`t=yryzMx9L@U^^6$>ACM*T5=0CkG<=|h&d_|Ypz<)19-DWA61>zpLV<5^G@^L z>#IBWyUlXt-|wd!3~=fEKyod8KZlg^{R8sC*E(iV@xGFKK8JkbXT!!0*;|9`6ti;e zzNU5O+DLkm@{oSS?pT;aGgS*lOfYH%x3=N$-T>tTw}GXa$A0Dt=f{)&=-L6>34MJX8>O}{k+>z&qi<7tYGux# zU)<=jq3IsNy_cuFeMRq89ven4=e+fElqT(LAKx8++UR-R4m8WhWcG4;jp3 z(eh;;8<%f?7WDDxAXt1~yz@n}tSv9C`pWB}cT>g#)ay{```XR;GYIjgOC?e}p( zxwT0PFi0sM+jNXeVud7J#OU-#1rD|IDnIm3k@M3#7kqd^v8Tz0o^U zm-H>8I7!&ZS?p2{NyL4KOP{T?XRbQ$^|c@Gx%8dfrVssWuYX#H0(v?&EGg@mLn7(# b`1}6{W5C+u62=On00000NkvXXu0mjfg+v+B literal 0 HcmV?d00001 diff --git a/assets/style.css b/assets/style.css new file mode 100644 index 0000000..6bf11cb --- /dev/null +++ b/assets/style.css @@ -0,0 +1,41 @@ +.social-button { + height: 2em; + width: 2em; +} + + +body { + height: 100vh; + margin: 0; +} + +main { + display: flex; + flex-direction: column; + align-items: center; + font-family: 'Courier'; + height: 100%; + font-size: 1em; +} + +#portrait { + width: 150px; + border-radius: 100%; +} + +main>* { + max-width: 19em; + text-align: center; +} + +input, +textarea { + width: 100%; + padding: 12px 20px; + margin: 8px 0; + box-sizing: border-box; +} + +textarea { + height: 10em; +} \ No newline at end of file diff --git a/assets/thanks.html b/assets/thanks.html new file mode 100644 index 0000000..6d201c2 --- /dev/null +++ b/assets/thanks.html @@ -0,0 +1,33 @@ + + + + + Eirik Kultorp's homepage + + + + + + +

+

Message sent

+

+ Thanks for your message! +

+
+ + + \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4657ee0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: '2' +services: + homepage: + build: . + ports: + - "3000:3000" + environment: + PORT: 3000 + TO_EMAIL: $TO_EMAIL + SMTP_HOST: $SMTP_HOST + SMTP_SECURE: $SMTP_SECURE + SMTP_PORT: $SMTP_PORT + SMTP_SERVICE: $SMTP_SERVICE + SMTP_AUTH_USER: $SMTP_AUTH_USER + SMTP_AUTH_PASS: $SMTP_AUTH_PASS diff --git a/package.json b/package.json new file mode 100644 index 0000000..8e89e71 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "scripts": { + "build": "tsc", + "start": "nodemon lib/index.js" + }, + "dependencies": { + "@types/express": "^4.17.21", + "@types/nodemailer": "^6.4.14", + "body-parser": "^1.20.2", + "email-validator": "^2.0.4", + "express": "^4.18.2", + "express-async-errors": "^3.1.1", + "nodemailer": "^6.9.10", + "typescript": "^5.3.3" + }, + "type": "module", + "name": "mailer", + "version": "0.0.1", + "description": "writes an email to a preconfigured address upon receipt of a post request", + "main": "lib/index.js", + "repository": "https://github.com/ekulno/contact-form-mailer", + "author": "ekulno", + "license": "MIT" +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..0f95121 --- /dev/null +++ b/readme.md @@ -0,0 +1,3 @@ +# homepage + +Source of my homepage [ekul.no](https://ekul.no). \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..eb0add0 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,83 @@ +import 'express-async-errors'; +import express, {NextFunction, Request, Response} from "express"; +import bodyParser from "body-parser"; +import nodemailer from 'nodemailer'; +import { validate as validateEmail } from 'email-validator'; + +const app = express(); + +app.use(bodyParser.urlencoded({ extended: false })) +app.use(bodyParser.json()) + +const port = process.env['PORT'] || 3000; + +const toMail = process.env['TO_EMAIL']; + +const smtp = { + service: process.env['SMTP_SERVICE']!, + host: process.env['SMTP_HOST']!, + port: parseInt(process.env['SMTP_PORT']!), + secure: !!(process.env['SMTP_SECURE'] && process.env['SMTP_SECURE'] != 'false'), + auth: { + user: process.env['SMTP_AUTH_USER']!, + pass: process.env['SMTP_AUTH_PASS']!, + } +} + +const transporter = nodemailer.createTransport(smtp); + +interface ContactRequest { + email: string; + message: string; + name?: string; + subject?: string; +}; + +app.get('/', async (req, res)=>{ + res.sendFile(process.cwd()+'/assets/index.html') +}); +app.get('/style.css', async (req, res)=>{ + res.sendFile(process.cwd()+'/assets/style.css') +}); +app.get('/portrait.png', async (req, res)=>{ + res.sendFile(process.cwd()+'/assets/portrait.png') +}); +app.get('/contact', async (req, res)=>{ + res.sendFile(process.cwd()+'/assets/contact.html') +}); + +app.post("/contact", async (req, res) => { + const { email, message, name, subject } = req.body as ContactRequest; + if (!validateEmail(email)) { + res.status(400).send("Invalid email"); + return; + } + if (!message.trim()) { + res.status(400).send("No message"); + return; + } + const info = await transporter.sendMail({ + from: `<${smtp.auth.user}>`, + replyTo: `${name?`"${name}"`:''} <${email}>`, + to: toMail, + subject: subject || "Contact form message", + text: message + }); + + if (info.rejected.length) { + res.status(500).send("Failed to send message"); + return; + } + res.sendFile(process.cwd()+'/assets/thanks.html') +}); + +app.use(async (err:Error, req:Request, res:Response, next:NextFunction) => { + console.error(err.stack) + res.status(500).send('Internal server error'); + return; +}); + + +app.listen(port, () => { + console.log(`[server]: Server is running at http://localhost:${port}`); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..77578f2 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution":"node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + + "outDir": "./lib", + "rootDir": "./src" + }, + "preserveSymlinks": false, + "compileOnSave": true, + "include": ["./src/**/*"], +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..b1c5e0f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,579 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@^4.17.33": + version "4.17.43" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz#10d8444be560cb789c4735aea5eac6e5af45df54" + integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@^4.17.21": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + +"@types/mime@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45" + integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw== + +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + +"@types/node@*": + version "20.11.20" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.20.tgz#f0a2aee575215149a62784210ad88b3a34843659" + integrity sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg== + dependencies: + undici-types "~5.26.4" + +"@types/nodemailer@^6.4.14": + version "6.4.14" + resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.14.tgz#5c81a5e856db7f8ede80013e6dbad7c5fb2283e2" + integrity sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA== + dependencies: + "@types/node" "*" + +"@types/qs@*": + version "6.9.11" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.11.tgz#208d8a30bc507bd82e03ada29e4732ea46a6bbda" + integrity sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/send@*": + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.5" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033" + integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ== + dependencies: + "@types/http-errors" "*" + "@types/mime" "*" + "@types/node" "*" + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +body-parser@1.20.2, body-parser@^1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +email-validator@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed" + integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +express-async-errors@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/express-async-errors/-/express-async-errors-3.1.1.tgz#6053236d61d21ddef4892d6bd1d736889fc9da41" + integrity sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng== + +express@^4.18.2: + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +nodemailer@^6.9.10: + version "6.9.13" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.13.tgz#5b292bf1e92645f4852ca872c56a6ba6c4a3d3d6" + integrity sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA== + +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +side-channel@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^5.3.3: + version "5.4.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.4.tgz#eb2471e7b0a5f1377523700a21669dce30c2d952" + integrity sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==