mirror of
https://github.com/nestjs/nest.git
synced 2026-02-24 00:02:56 +00:00
Compare commits
593 Commits
seclace-fe
...
v7.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca7e348478 | ||
|
|
67e15afbf3 | ||
|
|
d59c7b87bd | ||
|
|
cf5e5bceca | ||
|
|
b5e8197500 | ||
|
|
17969748e9 | ||
|
|
8836251c88 | ||
|
|
d74e173e59 | ||
|
|
9511984f2c | ||
|
|
eb7decd35c | ||
|
|
cd6555edd3 | ||
|
|
5b15dbfbaa | ||
|
|
8dcced7256 | ||
|
|
cf10752f40 | ||
|
|
1789753248 | ||
|
|
fb62ffe48c | ||
|
|
f38223ade4 | ||
|
|
f95b219a3c | ||
|
|
b4adc2c771 | ||
|
|
d56267fb99 | ||
|
|
2971ba6a3c | ||
|
|
f7e4885c2d | ||
|
|
cce0bc6407 | ||
|
|
ed4becbe99 | ||
|
|
3cac1ca2b2 | ||
|
|
9059c3d5ac | ||
|
|
3433ab06f4 | ||
|
|
55bd8ab1c7 | ||
|
|
2e5eb4b8e9 | ||
|
|
59ad650c8f | ||
|
|
764d26b28e | ||
|
|
2f29d7790b | ||
|
|
6a53d1e131 | ||
|
|
d37f68d05e | ||
|
|
72c16ccd9a | ||
|
|
3f9be96815 | ||
|
|
7bcf90cb8c | ||
|
|
f4f85f254c | ||
|
|
fc625f2957 | ||
|
|
61b6c7df25 | ||
|
|
79caf671ea | ||
|
|
e24f23d030 | ||
|
|
d184f906ff | ||
|
|
7efc27c186 | ||
|
|
27de22fdfb | ||
|
|
2342c65efc | ||
|
|
7d03b2d78d | ||
|
|
c0e6139419 | ||
|
|
f574663414 | ||
|
|
7f3a9955be | ||
|
|
cc828d493a | ||
|
|
dda9d52c4c | ||
|
|
1194fbae9f | ||
|
|
b3542806d8 | ||
|
|
3991fb9525 | ||
|
|
91cf3190b3 | ||
|
|
1ddeaa2aad | ||
|
|
2bdcdb5814 | ||
|
|
bb4ed69b0e | ||
|
|
b69f3be0aa | ||
|
|
96136f72e7 | ||
|
|
724403067b | ||
|
|
12b807f149 | ||
|
|
07237a07c7 | ||
|
|
0e7197c828 | ||
|
|
7c64c77031 | ||
|
|
ba2bdea524 | ||
|
|
12b9940b65 | ||
|
|
8a02e39001 | ||
|
|
b82f6f6b5b | ||
|
|
6a754515a1 | ||
|
|
517cad59e9 | ||
|
|
2714f57fcf | ||
|
|
e91d1b1ced | ||
|
|
6e49223e4c | ||
|
|
0b33f8fe31 | ||
|
|
b315162269 | ||
|
|
cd21b2ff93 | ||
|
|
4a1eed1e44 | ||
|
|
09a3ad2950 | ||
|
|
5e9d5c57ed | ||
|
|
d7c69707f6 | ||
|
|
f6114abea9 | ||
|
|
33d6c393e0 | ||
|
|
97edbe0c2a | ||
|
|
2e9fcb1a42 | ||
|
|
2581903818 | ||
|
|
ab4295ed02 | ||
|
|
f05786d8c1 | ||
|
|
772e589327 | ||
|
|
82d0171bcf | ||
|
|
706f55488c | ||
|
|
adce6c8ec0 | ||
|
|
7d209e3d8f | ||
|
|
a718809f30 | ||
|
|
25ba42cca2 | ||
|
|
eb1828431d | ||
|
|
038beb0c54 | ||
|
|
2a7bf6a357 | ||
|
|
dc35501e74 | ||
|
|
570dc303c9 | ||
|
|
300f0e39a5 | ||
|
|
c76e12eb17 | ||
|
|
5ca6a1e794 | ||
|
|
eb8f58a624 | ||
|
|
9e7c610ebe | ||
|
|
f17d29bf99 | ||
|
|
59c6cebb22 | ||
|
|
75e1e71e10 | ||
|
|
d4f93cd909 | ||
|
|
b5d553604d | ||
|
|
41764370eb | ||
|
|
e14670ee16 | ||
|
|
1c4ab360e3 | ||
|
|
5126ff4abc | ||
|
|
54570aa0c8 | ||
|
|
0b02176c2b | ||
|
|
9f14b14b9e | ||
|
|
9c60cc82e3 | ||
|
|
471335a336 | ||
|
|
6ebe9bf1e0 | ||
|
|
d8715eb7ff | ||
|
|
84bc3581cd | ||
|
|
439736f051 | ||
|
|
410fe85081 | ||
|
|
7ea7fd1f85 | ||
|
|
e3a2c74558 | ||
|
|
7a8696365c | ||
|
|
1d15dc650e | ||
|
|
ff75c1297c | ||
|
|
033ac9cab2 | ||
|
|
4f6d658467 | ||
|
|
5435fab03b | ||
|
|
c573fb3b89 | ||
|
|
ae08b12119 | ||
|
|
75e110f4c0 | ||
|
|
230b84f163 | ||
|
|
60b2615d25 | ||
|
|
b8ce4121ed | ||
|
|
486a40b852 | ||
|
|
6337793a84 | ||
|
|
e5f0f54946 | ||
|
|
eee8faf433 | ||
|
|
07cb5a83e1 | ||
|
|
fa10ab7f7c | ||
|
|
f315ca2b90 | ||
|
|
b397cec0fd | ||
|
|
0d6ae6fe88 | ||
|
|
34f74561de | ||
|
|
28b1784966 | ||
|
|
a683a545af | ||
|
|
d1816a3199 | ||
|
|
3e4f8bcbf1 | ||
|
|
a09e77a50a | ||
|
|
7970c29f16 | ||
|
|
09fea2b45c | ||
|
|
3f68b08bfc | ||
|
|
5ba0164f35 | ||
|
|
d768b5df32 | ||
|
|
5388ffb09b | ||
|
|
3fae1c2503 | ||
|
|
2aa0881b46 | ||
|
|
55032c15f4 | ||
|
|
de54172f6b | ||
|
|
2dcff086b3 | ||
|
|
edadbb1af9 | ||
|
|
d562bc0225 | ||
|
|
f8e788a929 | ||
|
|
07237f5aed | ||
|
|
0432284865 | ||
|
|
e2c8f74f19 | ||
|
|
19b4083936 | ||
|
|
baadb3f925 | ||
|
|
f9ce824eaf | ||
|
|
43a4ea4d39 | ||
|
|
138e2c41f0 | ||
|
|
53d3574a43 | ||
|
|
f3a8f7f174 | ||
|
|
47cd27e0cc | ||
|
|
91d7564d92 | ||
|
|
b236e30231 | ||
|
|
dc1bd46c03 | ||
|
|
8c146fe341 | ||
|
|
c49c271c22 | ||
|
|
b59965ba76 | ||
|
|
b1ed6db4fb | ||
|
|
661664d8be | ||
|
|
64df4a96c9 | ||
|
|
7775081159 | ||
|
|
dcf3ca0d4c | ||
|
|
9ee7c3ffa3 | ||
|
|
1f8b45bf9b | ||
|
|
97061348f5 | ||
|
|
a8da4f74da | ||
|
|
1bc9939000 | ||
|
|
e4184145cb | ||
|
|
3e0fb387a0 | ||
|
|
630c3be032 | ||
|
|
1f880c7e8b | ||
|
|
47184d4ddb | ||
|
|
822bbba826 | ||
|
|
91f44a0978 | ||
|
|
53965ec396 | ||
|
|
e394f73a39 | ||
|
|
f76ea42d4d | ||
|
|
bfcd6f25d6 | ||
|
|
d08c7c742b | ||
|
|
0fa229529e | ||
|
|
47fcaaf855 | ||
|
|
a4ea40dacc | ||
|
|
48ab7359e4 | ||
|
|
cb65d90249 | ||
|
|
341746313a | ||
|
|
d1d583af07 | ||
|
|
60e77e92e2 | ||
|
|
306adf0b3f | ||
|
|
092a6af52c | ||
|
|
5462d1d152 | ||
|
|
9179b43f94 | ||
|
|
824b543a94 | ||
|
|
25d9e138c1 | ||
|
|
e32270c202 | ||
|
|
643d74df46 | ||
|
|
2bda4fca88 | ||
|
|
d5807f160b | ||
|
|
fe9afa34ee | ||
|
|
79c5014d82 | ||
|
|
3208409654 | ||
|
|
0845dab3a3 | ||
|
|
56a24622b6 | ||
|
|
62b0330a1c | ||
|
|
c0acada6a8 | ||
|
|
75830c9eaf | ||
|
|
bb71ceaf3d | ||
|
|
34a6704b12 | ||
|
|
cbda11b4fb | ||
|
|
b4c06f2242 | ||
|
|
1cb1c76f03 | ||
|
|
ff6365225d | ||
|
|
902e6cd322 | ||
|
|
ca065578f8 | ||
|
|
221c2c839f | ||
|
|
a0b84ffd1e | ||
|
|
e6233cbd5b | ||
|
|
a2e1cfcd62 | ||
|
|
8d2c79fa83 | ||
|
|
8a2c6063b7 | ||
|
|
a4f8419698 | ||
|
|
4044d60583 | ||
|
|
16ba70cba2 | ||
|
|
c31f2f6c5f | ||
|
|
b463a8e93b | ||
|
|
4e736b925c | ||
|
|
ec29c7e19c | ||
|
|
36c2ed1b9e | ||
|
|
8dac4d0f1c | ||
|
|
289e04dc86 | ||
|
|
90bfda4311 | ||
|
|
dd9086d612 | ||
|
|
c8e678682a | ||
|
|
7b03a6c361 | ||
|
|
6634898334 | ||
|
|
c7d890e604 | ||
|
|
1d938fd911 | ||
|
|
995e2870d5 | ||
|
|
6bb1d88d36 | ||
|
|
ea8fe39e43 | ||
|
|
3b189faa67 | ||
|
|
535dff89c0 | ||
|
|
7aed631783 | ||
|
|
06f68651ec | ||
|
|
447e1e3ed6 | ||
|
|
c8f5fc483d | ||
|
|
2379f9775e | ||
|
|
d4943751fa | ||
|
|
86e98dc74f | ||
|
|
6f658624fd | ||
|
|
aad7ec2862 | ||
|
|
1ee4bc56b0 | ||
|
|
bacdc8676b | ||
|
|
36ba59553c | ||
|
|
9e9c649e6b | ||
|
|
0bb5f91a67 | ||
|
|
011ae85143 | ||
|
|
b6433fc7ee | ||
|
|
12a92d98c4 | ||
|
|
142005573e | ||
|
|
9349189a1a | ||
|
|
8fff239f1b | ||
|
|
c7fee93706 | ||
|
|
c70bbb1923 | ||
|
|
1e98a8e790 | ||
|
|
2d33f52b63 | ||
|
|
1280dd6188 | ||
|
|
2b7725bef5 | ||
|
|
a39a6e9ca5 | ||
|
|
29ad228655 | ||
|
|
f9e39c1b20 | ||
|
|
b6374e8b0d | ||
|
|
a11da77144 | ||
|
|
10bd87cb7f | ||
|
|
b2d37b8de6 | ||
|
|
ab2c58d573 | ||
|
|
de577292e3 | ||
|
|
04cb13aa4d | ||
|
|
380a68d3be | ||
|
|
abdeee69b4 | ||
|
|
47e25265f6 | ||
|
|
e95d527ed9 | ||
|
|
694704c27b | ||
|
|
a92f1262e4 | ||
|
|
f2b382538b | ||
|
|
87bdf87d2f | ||
|
|
afc19bdd5d | ||
|
|
649033ddbc | ||
|
|
a215322ace | ||
|
|
0c2e73c78e | ||
|
|
74d7a2f4ca | ||
|
|
fb44f21e96 | ||
|
|
b271d89146 | ||
|
|
1f6deb0c11 | ||
|
|
392a13f758 | ||
|
|
e0a2eb7398 | ||
|
|
426a3b04f2 | ||
|
|
f0973d607f | ||
|
|
55a828a901 | ||
|
|
23181cb819 | ||
|
|
a5a8712668 | ||
|
|
77fc5da848 | ||
|
|
b2bd950cc9 | ||
|
|
e5db8e414e | ||
|
|
678986aa7e | ||
|
|
f4d8fad2d4 | ||
|
|
aaf4cb591e | ||
|
|
41f59daa58 | ||
|
|
8a253c5f76 | ||
|
|
1117b246c6 | ||
|
|
661424f389 | ||
|
|
d8ab987130 | ||
|
|
92908c8f0f | ||
|
|
5e820cc788 | ||
|
|
8edb035a87 | ||
|
|
4022347860 | ||
|
|
6ee10bef9d | ||
|
|
cf2c279be2 | ||
|
|
4c9d1de10e | ||
|
|
1a0b213d97 | ||
|
|
8a7fc27513 | ||
|
|
17edde1a22 | ||
|
|
387f918973 | ||
|
|
11794b99c0 | ||
|
|
4a14444088 | ||
|
|
44a23593aa | ||
|
|
e84d90ae86 | ||
|
|
e7ee336b8c | ||
|
|
7b241818a5 | ||
|
|
6d68283c4b | ||
|
|
f2726c19cb | ||
|
|
87c06eef42 | ||
|
|
810bb029be | ||
|
|
e5dc2c29a5 | ||
|
|
94a21eb683 | ||
|
|
ddb75ae335 | ||
|
|
90506e09a6 | ||
|
|
fc704b7cb9 | ||
|
|
307fbbf9df | ||
|
|
bf09428376 | ||
|
|
99de33c79e | ||
|
|
017791186d | ||
|
|
f5a3269561 | ||
|
|
002878e091 | ||
|
|
d439758319 | ||
|
|
95f7eadd8d | ||
|
|
1bade34fe1 | ||
|
|
c591059904 | ||
|
|
cf65f16ff3 | ||
|
|
3a4b17271b | ||
|
|
799ccc24d5 | ||
|
|
67bdae06e9 | ||
|
|
33b40ff44f | ||
|
|
fb3040f866 | ||
|
|
6c986e8c8d | ||
|
|
f54f864b94 | ||
|
|
e834ec7f5f | ||
|
|
12de529a48 | ||
|
|
c604ad18a9 | ||
|
|
3ce5a028c7 | ||
|
|
a2bf742111 | ||
|
|
b0dc39e589 | ||
|
|
653cc9a787 | ||
|
|
18547a3879 | ||
|
|
50f91e798b | ||
|
|
95269309f8 | ||
|
|
ac37717cc3 | ||
|
|
352e643c1a | ||
|
|
83c2ebfcba | ||
|
|
edbac299c8 | ||
|
|
9a694cb853 | ||
|
|
2376aa43a5 | ||
|
|
9ae9aa3059 | ||
|
|
014824121b | ||
|
|
09ab0087af | ||
|
|
647235f1ac | ||
|
|
b14b0f4376 | ||
|
|
7f5750660a | ||
|
|
ac87ed8448 | ||
|
|
2cd6cb9460 | ||
|
|
e4682d537d | ||
|
|
e4b8e5d08e | ||
|
|
88f7bd5583 | ||
|
|
8b8156981a | ||
|
|
2b15735a33 | ||
|
|
ec0190eeaa | ||
|
|
571eff638d | ||
|
|
f23eba1f08 | ||
|
|
765a3191ae | ||
|
|
915d346855 | ||
|
|
d6e4af4b30 | ||
|
|
f729b2edd1 | ||
|
|
55c5ec8f46 | ||
|
|
aa17f033ab | ||
|
|
cc6cfef4f0 | ||
|
|
9edc6b8fe7 | ||
|
|
016116a71c | ||
|
|
2c1407ad77 | ||
|
|
57435c2135 | ||
|
|
761d5d458a | ||
|
|
c0d3152492 | ||
|
|
c007ef4025 | ||
|
|
e4598e484d | ||
|
|
2e928ca46f | ||
|
|
0262e9fac1 | ||
|
|
7dfb6ce9d7 | ||
|
|
3e7fd83e61 | ||
|
|
f12ad1bc3a | ||
|
|
10c8dd40d5 | ||
|
|
995aba763c | ||
|
|
c4e87f51f9 | ||
|
|
e2674c6326 | ||
|
|
c34e6901ae | ||
|
|
d0dd846fcf | ||
|
|
b70a5ebff9 | ||
|
|
005c2c4360 | ||
|
|
edffcc5463 | ||
|
|
d9e4bf47db | ||
|
|
4fb7177f3b | ||
|
|
88aa0cef8b | ||
|
|
9b11c86175 | ||
|
|
8fde3283ac | ||
|
|
8832d15ba0 | ||
|
|
515dbdb2c4 | ||
|
|
3870e1d98e | ||
|
|
a835bf29f4 | ||
|
|
f3fc345cf2 | ||
|
|
2d99ddc0a1 | ||
|
|
eebbb26de3 | ||
|
|
4dc5c7514c | ||
|
|
364085771e | ||
|
|
9d829f5753 | ||
|
|
8484c0c922 | ||
|
|
2ab3629a8a | ||
|
|
4c4242f37d | ||
|
|
25a478a5a6 | ||
|
|
d4c6cfeed0 | ||
|
|
4bb193f64d | ||
|
|
dce8d9c5e8 | ||
|
|
7a7a71d911 | ||
|
|
956baed7cc | ||
|
|
5d484c53ae | ||
|
|
da4b1a3cce | ||
|
|
abb465d4dc | ||
|
|
789f8a4b30 | ||
|
|
549bb979de | ||
|
|
1ef5fb8572 | ||
|
|
1a0d47a22d | ||
|
|
fc0d73e971 | ||
|
|
eb4e40873d | ||
|
|
0609d6e647 | ||
|
|
cb944970ac | ||
|
|
417d312692 | ||
|
|
c48b2efbfa | ||
|
|
fad533ba4d | ||
|
|
430e9cf8b3 | ||
|
|
f77d1df06b | ||
|
|
814b3b58e6 | ||
|
|
a998251239 | ||
|
|
9f19643924 | ||
|
|
6cba88126a | ||
|
|
f400673401 | ||
|
|
fbcb1c44a4 | ||
|
|
e21a71568a | ||
|
|
4396820aab | ||
|
|
5a507d4293 | ||
|
|
82c9ce272c | ||
|
|
3b0e266084 | ||
|
|
65f6c5fe51 | ||
|
|
d68bb4a9db | ||
|
|
ada8808742 | ||
|
|
269b01d449 | ||
|
|
e06915f148 | ||
|
|
c0ecc34881 | ||
|
|
94f52fc741 | ||
|
|
c6039a326f | ||
|
|
7f58fc6d85 | ||
|
|
19d459aded | ||
|
|
f153d5f6bb | ||
|
|
89321242cc | ||
|
|
46318a7514 | ||
|
|
6757530709 | ||
|
|
640bf671ff | ||
|
|
4945764719 | ||
|
|
fed0f75565 | ||
|
|
5fcbd1a59b | ||
|
|
150a763c05 | ||
|
|
4870a55adb | ||
|
|
e35016ce7c | ||
|
|
52da4bb224 | ||
|
|
173dffe37c | ||
|
|
55c737e305 | ||
|
|
76ff1016da | ||
|
|
7c7125ac7f | ||
|
|
58eb602c09 | ||
|
|
e936dd0da0 | ||
|
|
3f456f09b1 | ||
|
|
09f87ac0d4 | ||
|
|
37aca3d3c6 | ||
|
|
7d5ff96957 | ||
|
|
4f91f18f3c | ||
|
|
3fe047ca55 | ||
|
|
6cf3f468c3 | ||
|
|
8dff04260c | ||
|
|
661370e3e8 | ||
|
|
e57f4a6b28 | ||
|
|
1d852b2ebf | ||
|
|
fc5d61b357 | ||
|
|
e58a1efe3d | ||
|
|
616cb19832 | ||
|
|
3510629672 | ||
|
|
0a84b2e59b | ||
|
|
def30207ae | ||
|
|
c377a19f15 | ||
|
|
4eb449dd3d | ||
|
|
41b7f58bb3 | ||
|
|
0d13d2ef32 | ||
|
|
f3d2b0c2f5 | ||
|
|
3bc1c93bee | ||
|
|
c62d9817c7 | ||
|
|
c19acf05ec | ||
|
|
72ed4b595e | ||
|
|
f74375baa8 | ||
|
|
7ac6624a3c | ||
|
|
26b266048e | ||
|
|
e5a4bb66f4 | ||
|
|
793b991621 | ||
|
|
1fc4833c06 | ||
|
|
f92ccae9d4 | ||
|
|
73094c3b43 | ||
|
|
51b18db412 | ||
|
|
f53cc505f1 | ||
|
|
5ed98e220c | ||
|
|
142a2e9113 | ||
|
|
a5bcb21388 | ||
|
|
0b38029830 | ||
|
|
0a94d65490 | ||
|
|
691383c0a2 | ||
|
|
8e6b6fa969 | ||
|
|
6135b623a0 | ||
|
|
e743162482 | ||
|
|
522ae200b5 | ||
|
|
296e1aecf7 | ||
|
|
7076aa46ee | ||
|
|
38a0610d38 | ||
|
|
e060888d37 | ||
|
|
6562f9faab | ||
|
|
abb4471d64 | ||
|
|
134ef15093 | ||
|
|
4ebe4504b9 | ||
|
|
95b904efee | ||
|
|
605e5baf58 | ||
|
|
263b38e302 | ||
|
|
9cba17d040 | ||
|
|
16b593765b | ||
|
|
0168673d45 | ||
|
|
333677f009 | ||
|
|
d6bc71ddd4 | ||
|
|
47fd693e15 | ||
|
|
6f1675f594 | ||
|
|
8d809c56ea | ||
|
|
e0dc092745 | ||
|
|
cf44f1ab2c | ||
|
|
08559a1bbc | ||
|
|
182792ef24 | ||
|
|
4b7dcd6b2c |
@@ -70,10 +70,10 @@ jobs:
|
||||
docker:
|
||||
- image: circleci/node:10
|
||||
|
||||
test_node_8:
|
||||
test_node_14:
|
||||
<<: *unit-tests-template
|
||||
docker:
|
||||
- image: circleci/node:8
|
||||
- image: circleci/node:14
|
||||
|
||||
lint:
|
||||
working_directory: ~/nest
|
||||
@@ -160,15 +160,15 @@ workflows:
|
||||
build-and-test:
|
||||
jobs:
|
||||
- build
|
||||
- test_node_14:
|
||||
requires:
|
||||
- build
|
||||
- test_node_12:
|
||||
requires:
|
||||
- build
|
||||
- test_node_10:
|
||||
requires:
|
||||
- build
|
||||
- test_node_8:
|
||||
requires:
|
||||
- build
|
||||
- lint:
|
||||
requires:
|
||||
- build
|
||||
|
||||
@@ -19,6 +19,8 @@ module.exports = {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
},
|
||||
};
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017-2019 Kamil Myśliwiec <http://kamilmysliwiec.com>
|
||||
Copyright (c) 2017-2020 Kamil Mysliwiec <https://kamilmysliwiec.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
57
Readme.md
57
Readme.md
@@ -38,6 +38,14 @@ Nest is a framework for building efficient, scalable <a href="http://nodejs.org"
|
||||
* To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
|
||||
* 要查看中文 [指南](readme_zh.md), 请访问 [docs.nestjs.cn](https://docs.nestjs.cn). :books:
|
||||
|
||||
## Questions
|
||||
|
||||
For questions and support please use the official [Discord channel](https://discord.gg/G7Qnnhy). The issue list of this repo is **exclusively** for bug reports and feature requests.
|
||||
|
||||
## Issues
|
||||
|
||||
Please make sure to read the [Issue Reporting Checklist](https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md#-submitting-an-issue) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
|
||||
|
||||
## Consulting
|
||||
|
||||
With official support, you can get expert help straight from Nest core team. We provide dedicated technical support, migration strategies, advice on best practices (and design decisions), PR reviews, and team augmentation. Read more about [support here](https://enterprise.nestjs.com).
|
||||
@@ -46,32 +54,39 @@ With official support, you can get expert help straight from Nest core team. We
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
#### Principal Sponsor
|
||||
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="320" /></a>
|
||||
#### Principal Sponsors
|
||||
<table style="text-align:center;"><tr><td>
|
||||
<a href="https://github.com/Sanofi-IADC" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/sanofi.png" width="180" valign="middle" /></a></td><td>
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="180" valign="middle" /></a></td>
|
||||
</tr></table>
|
||||
|
||||
#### Silver Sponsors
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" height="95" /></a>
|
||||
<a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="150" valign="middle" /></a>
|
||||
<a href="http://www.leogistics.com" target="_blank"><img src="https://nestjs.com/img/leogistics-logo.jpeg" width="150" valign="middle" /></a>
|
||||
|
||||
<table style="text-align:center;"><tr><td>
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a> </td><td>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" width="100" /></a> </td><td>
|
||||
<a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="170" valign="middle" /></a> </td><td>
|
||||
<a href="http://www.leogistics.com" target="_blank"><img src="https://nestjs.com/img/leogistics-logo.jpeg" width="150" valign="middle" /></td></tr></table>
|
||||
|
||||
#### Sponsors
|
||||
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a> <a href="https://blueanchor.io/" target="_blank"><img src="https://nestjs.com/img/blueanchor.png" width="150" valign="middle" /></a>
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> <a href="https://hostpresto.com" target="_blank"><img src="https://nestjs.com/img/hostpresto.png" height="24" valign="middle" /></a>
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" height="14" valign="middle" /></a>
|
||||
<a href="https://buddy.works/" target="_blank"><img src="https://nestjs.com/img/buddy-logo.svg" height="25" valign="middle" /></a>
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" height="25" valign="middle" /></a> <a href="https://genuinebee.com/" target="_blank"><img src="https://nestjs.com/img/genuinebee.svg" height="27" valign="middle" /></a> <a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" height="20" valign="middle" /></a> <a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" height="22" valign="middle" /></a> <a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" height="19" valign="middle" /></a> <a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" height="20" valign="middle" /></a>
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" height="18" valign="middle" /></a>
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a>
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a>
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a>
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a>
|
||||
<a href="https://tekhattan.com" target="_blank"><img src="https://nestjs.com/img/tekhattan-logo.png" width="110" valign="middle" /></a>
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a>
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a>
|
||||
|
||||
<table><tr><td align="center" valign="middle">
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a></td><td align="center" valign="middle">
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" width="72" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" width="125" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" width="100" valign="middle" /></a> </td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" width="95" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" width="107" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" width="71" valign="middle" /></a></td><td align="center" valign="middle">
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a></td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://tekhattan.com" target="_blank"><img src="https://nestjs.com/img/tekhattan-logo.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://www.thebigphonestore.co.uk/" target="_blank"><img src="https://nestjs.com/img/the-big-phone-store-logo.png" width="65" valign="middle" /></a></td></tr></table>
|
||||
|
||||
## Backers
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ services:
|
||||
- "9001:9001"
|
||||
restart: always
|
||||
mysql:
|
||||
image: mysql:5.7.29
|
||||
image: mysql:5.7.30
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: test
|
||||
|
||||
@@ -2,9 +2,22 @@
|
||||
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
|
||||
# ------------------------------------------------------
|
||||
|
||||
type Recipe {
|
||||
id: ID!
|
||||
title: String!
|
||||
description: String
|
||||
creationDate: Date!
|
||||
ingredients: [String!]!
|
||||
}
|
||||
|
||||
"""Date custom scalar type"""
|
||||
scalar Date
|
||||
|
||||
type Query {
|
||||
recipe(id: String!): Recipe!
|
||||
recipes(skip: Int = 0, take: Int = 25): [Recipe!]!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
addRecipe(newRecipeData: NewRecipeInput!): Recipe!
|
||||
removeRecipe(id: String!): Boolean!
|
||||
@@ -16,19 +29,6 @@ input NewRecipeInput {
|
||||
ingredients: [String!]!
|
||||
}
|
||||
|
||||
type Query {
|
||||
recipe(id: String!): Recipe!
|
||||
recipes(skip: Int = 0, take: Int = 25): [Recipe!]!
|
||||
}
|
||||
|
||||
type Recipe {
|
||||
id: ID!
|
||||
title: String!
|
||||
description: String
|
||||
creationDate: Date!
|
||||
ingredients: [String!]!
|
||||
}
|
||||
|
||||
type Subscription {
|
||||
recipeAdded: Recipe!
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ class TestController {
|
||||
}
|
||||
|
||||
@Get('tests/wildcard_nested')
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
wildcard_nested() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ class TestController {
|
||||
}
|
||||
|
||||
@Get('tests/wildcard_nested')
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
wildcard_nested() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
34
integration/injector/e2e/introspection.spec.ts
Normal file
34
integration/injector/e2e/introspection.spec.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Scope } from '@nestjs/common';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { ScopedModule, STATIC_FACTORY } from '../src/scoped/scoped.module';
|
||||
import { ScopedService } from '../src/scoped/scoped.service';
|
||||
import { TransientService } from '../src/scoped/transient.service';
|
||||
|
||||
describe('Providers introspection', () => {
|
||||
let testingModule: TestingModule;
|
||||
let moduleRef: ModuleRef;
|
||||
|
||||
beforeEach(async () => {
|
||||
testingModule = await Test.createTestingModule({
|
||||
imports: [ScopedModule],
|
||||
}).compile();
|
||||
moduleRef = testingModule.get(ModuleRef);
|
||||
});
|
||||
|
||||
it('should properly introspect a transient provider', async () => {
|
||||
const introspectionResult = moduleRef.introspect(TransientService);
|
||||
expect(introspectionResult.scope).to.be.equal(Scope.TRANSIENT);
|
||||
});
|
||||
|
||||
it('should properly introspect a singleton provider', async () => {
|
||||
const introspectionResult = moduleRef.introspect(STATIC_FACTORY);
|
||||
expect(introspectionResult.scope).to.be.equal(Scope.DEFAULT);
|
||||
});
|
||||
|
||||
it('should properly introspect a request-scoped provider', async () => {
|
||||
const introspectionResult = moduleRef.introspect(ScopedService);
|
||||
expect(introspectionResult.scope).to.be.equal(Scope.REQUEST);
|
||||
});
|
||||
});
|
||||
@@ -3,9 +3,15 @@ import { InvalidClassScopeException } from '@nestjs/core/errors/exceptions/inval
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { ScopedController } from '../src/scoped/scoped.controller';
|
||||
import { ScopedModule } from '../src/scoped/scoped.module';
|
||||
import {
|
||||
REQUEST_SCOPED_FACTORY,
|
||||
ScopedModule,
|
||||
STATIC_FACTORY,
|
||||
TRANSIENT_SCOPED_FACTORY,
|
||||
} from '../src/scoped/scoped.module';
|
||||
import { ScopedService } from '../src/scoped/scoped.service';
|
||||
import { TransientService } from '../src/scoped/transient.service';
|
||||
import { Transient3Service } from '../src/scoped/transient3.service';
|
||||
|
||||
describe('Scoped Instances', () => {
|
||||
let testingModule: TestingModule;
|
||||
@@ -20,20 +26,47 @@ describe('Scoped Instances', () => {
|
||||
const contextId = createContextId();
|
||||
const transient1 = await testingModule.resolve(TransientService, contextId);
|
||||
const transient2 = await testingModule.resolve(TransientService, contextId);
|
||||
const transientFactory = await testingModule.resolve(
|
||||
TRANSIENT_SCOPED_FACTORY,
|
||||
);
|
||||
|
||||
expect(transient1).to.be.instanceOf(TransientService);
|
||||
expect(transient2).to.be.instanceOf(TransientService);
|
||||
expect(transient1).to.be.equal(transient2);
|
||||
expect(transientFactory).to.be.true;
|
||||
});
|
||||
|
||||
it('should dynamically resolve nested transient provider', async () => {
|
||||
const contextId = createContextId();
|
||||
const transientTwoDepthLevel = await testingModule.resolve(
|
||||
TransientService,
|
||||
contextId,
|
||||
);
|
||||
const transientThreeDepthLevel = await testingModule.resolve(
|
||||
Transient3Service,
|
||||
contextId,
|
||||
);
|
||||
|
||||
expect(transientTwoDepthLevel.svc.logger).to.not.be.undefined;
|
||||
expect(transientThreeDepthLevel.svc.svc.logger).to.not.be.undefined;
|
||||
});
|
||||
|
||||
it('should dynamically resolve request-scoped provider', async () => {
|
||||
const request1 = await testingModule.resolve(ScopedService);
|
||||
const request2 = await testingModule.resolve(ScopedService);
|
||||
const request3 = await testingModule.resolve(ScopedService, { id: 1 });
|
||||
|
||||
const ctxId = { id: 1 };
|
||||
const requestProvider = { host: 'localhost' };
|
||||
testingModule.registerRequestByContextId(requestProvider, ctxId);
|
||||
|
||||
const request3 = await testingModule.resolve(ScopedService, ctxId);
|
||||
const requestFactory = await testingModule.resolve(REQUEST_SCOPED_FACTORY);
|
||||
|
||||
expect(request1).to.be.instanceOf(ScopedService);
|
||||
expect(request2).to.be.instanceOf(ScopedService);
|
||||
expect(request3).to.not.be.equal(request2);
|
||||
expect(requestFactory).to.be.true;
|
||||
expect(request3.request).to.be.equal(requestProvider);
|
||||
});
|
||||
|
||||
it('should dynamically resolve request-scoped controller', async () => {
|
||||
@@ -46,11 +79,19 @@ describe('Scoped Instances', () => {
|
||||
expect(request3).to.not.be.equal(request2);
|
||||
});
|
||||
|
||||
it('should throw an exception when "get()" method is used', async () => {
|
||||
it('should throw an exception when "get()" method is used for scoped providers', () => {
|
||||
try {
|
||||
testingModule.get(ScopedController);
|
||||
} catch (err) {
|
||||
expect(err).to.be.instanceOf(InvalidClassScopeException);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw an exception when "resolve()" method is used for static providers', async () => {
|
||||
try {
|
||||
await testingModule.resolve(STATIC_FACTORY);
|
||||
} catch (err) {
|
||||
expect(err).to.be.instanceOf(InvalidClassScopeException);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,35 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { Module, Scope } from '@nestjs/common';
|
||||
import { ScopedController } from './scoped.controller';
|
||||
import { ScopedService } from './scoped.service';
|
||||
import { TransientService } from './transient.service';
|
||||
import { Transient2Service } from './transient2.service';
|
||||
import { Transient3Service } from './transient3.service';
|
||||
|
||||
export const STATIC_FACTORY = 'STATIC_FACTORY';
|
||||
export const REQUEST_SCOPED_FACTORY = 'REQUEST_SCOPED_FACTORY';
|
||||
export const TRANSIENT_SCOPED_FACTORY = 'TRANSIENT_SCOPED_FACTORY';
|
||||
|
||||
@Module({
|
||||
controllers: [ScopedController],
|
||||
providers: [ScopedService, TransientService, Transient2Service],
|
||||
providers: [
|
||||
ScopedService,
|
||||
TransientService,
|
||||
Transient2Service,
|
||||
Transient3Service,
|
||||
{
|
||||
provide: STATIC_FACTORY,
|
||||
useFactory: () => true,
|
||||
},
|
||||
{
|
||||
provide: REQUEST_SCOPED_FACTORY,
|
||||
useFactory: () => true,
|
||||
scope: Scope.REQUEST,
|
||||
},
|
||||
{
|
||||
provide: TRANSIENT_SCOPED_FACTORY,
|
||||
useFactory: () => true,
|
||||
scope: Scope.TRANSIENT,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class ScopedModule {}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { Injectable, Scope } from '@nestjs/common';
|
||||
import { Inject, Injectable, Scope } from '@nestjs/common';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.REQUEST })
|
||||
export class ScopedService {}
|
||||
export class ScopedService {
|
||||
constructor(@Inject(REQUEST) public readonly request) {}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ import { Transient2Service } from './transient2.service';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
export class TransientService {
|
||||
constructor(private readonly svc: Transient2Service) {}
|
||||
constructor(public readonly svc: Transient2Service) {}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Injectable, Scope } from '@nestjs/common';
|
||||
import { Injectable, Logger, Scope } from '@nestjs/common';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
export class Transient2Service {}
|
||||
export class Transient2Service {
|
||||
logger = new Logger();
|
||||
}
|
||||
|
||||
7
integration/injector/src/scoped/transient3.service.ts
Normal file
7
integration/injector/src/scoped/transient3.service.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Injectable, Scope } from '@nestjs/common';
|
||||
import { TransientService } from './transient.service';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
export class Transient3Service {
|
||||
constructor(public readonly svc: TransientService) {}
|
||||
}
|
||||
@@ -25,8 +25,11 @@ describe('GRPC transport', () => {
|
||||
app.connectMicroservice({
|
||||
transport: Transport.GRPC,
|
||||
options: {
|
||||
package: 'math',
|
||||
protoPath: join(__dirname, '../src/grpc/math.proto'),
|
||||
package: ['math', 'math2'],
|
||||
protoPath: [
|
||||
join(__dirname, '../src/grpc/math.proto'),
|
||||
join(__dirname, '../src/grpc/math2.proto'),
|
||||
],
|
||||
},
|
||||
});
|
||||
// Start gRPC microservice
|
||||
@@ -47,7 +50,19 @@ describe('GRPC transport', () => {
|
||||
|
||||
it(`GRPC Sending and Receiving HTTP POST`, () => {
|
||||
return request(server)
|
||||
.post('/')
|
||||
.post('/sum')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200, { result: 15 });
|
||||
});
|
||||
|
||||
it(`GRPC Sending and Receiving HTTP POST (multiple proto)`, async () => {
|
||||
await request(server)
|
||||
.post('/multi/sum')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200, { result: 15 });
|
||||
|
||||
await request(server)
|
||||
.post('/multi/sum2')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200, { result: 15 });
|
||||
});
|
||||
|
||||
@@ -31,9 +31,9 @@ export class GrpcController {
|
||||
],
|
||||
},
|
||||
})
|
||||
client2: ClientGrpc;
|
||||
clientMulti: ClientGrpc;
|
||||
|
||||
@Post()
|
||||
@Post('sum')
|
||||
@HttpCode(200)
|
||||
call(@Body() data: number[]): Observable<number> {
|
||||
const svc = this.client.getService<any>('Math');
|
||||
@@ -77,10 +77,17 @@ export class GrpcController {
|
||||
});
|
||||
}
|
||||
|
||||
@Post()
|
||||
@Post('multi/sum')
|
||||
@HttpCode(200)
|
||||
call2(@Body() data: number[]): Observable<number> {
|
||||
const svc = this.client2.getService<any>('Math2');
|
||||
callMultiSum(@Body() data: number[]): Observable<number> {
|
||||
const svc = this.clientMulti.getService<any>('Math');
|
||||
return svc.sum({ data });
|
||||
}
|
||||
|
||||
@Post('multi/sum2')
|
||||
@HttpCode(200)
|
||||
callMultiSum2(@Body() data: number[]): Observable<number> {
|
||||
const svc = this.clientMulti.getService<any>('Math2');
|
||||
return svc.sum2({ data });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "7.0.5"
|
||||
"version": "7.3.0"
|
||||
}
|
||||
|
||||
10118
package-lock.json
generated
10118
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
127
package.json
127
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/core",
|
||||
"version": "7.0.3",
|
||||
"version": "7.0.11",
|
||||
"description": "Modern, fast, powerful node.js web framework",
|
||||
"homepage": "https://nestjs.com",
|
||||
"repository": {
|
||||
@@ -27,7 +27,7 @@
|
||||
"test": "nyc --require ts-node/register mocha packages/**/*.spec.ts --reporter spec --retries 3 --require 'node_modules/reflect-metadata/Reflect.js' --exit",
|
||||
"test:integration": "mocha \"integration/*/{,!(node_modules)/**/}/*.spec.ts\" --reporter spec --require ts-node/register --require 'node_modules/reflect-metadata/Reflect.js' --exit",
|
||||
"test:docker:up": "docker-compose -f integration/docker-compose.yml up -d",
|
||||
"test:docker:down": "docker-compose -f integration/docker-compose.yml down -d",
|
||||
"test:docker:down": "docker-compose -f integration/docker-compose.yml down",
|
||||
"lint": "concurrently 'npm run lint:packages' 'npm run lint:integration' 'npm run lint:spec'",
|
||||
"lint:integration": "eslint 'integration/*/{,!(node_modules)/**/}/*.ts' -c '.eslintrc.spec.js' --fix",
|
||||
"lint:packages": "eslint 'packages/**/**.ts' --fix --ignore-pattern 'packages/**/*.spec.ts'",
|
||||
@@ -54,115 +54,114 @@
|
||||
"@nuxtjs/opencollective": "0.2.2",
|
||||
"axios": "0.19.2",
|
||||
"class-transformer": "0.2.3",
|
||||
"class-validator": "0.11.1",
|
||||
"class-validator": "0.12.2",
|
||||
"cli-color": "2.0.0",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.17.1",
|
||||
"fast-json-stringify": "1.18.0",
|
||||
"fast-json-stringify": "2.2.1",
|
||||
"fast-safe-stringify": "2.0.7",
|
||||
"iterare": "1.2.0",
|
||||
"iterare": "1.2.1",
|
||||
"object-hash": "2.0.3",
|
||||
"path-to-regexp": "3.2.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rxjs": "6.5.4",
|
||||
"rxjs": "6.5.5",
|
||||
"socket.io": "2.3.0",
|
||||
"uuid": "7.0.2",
|
||||
"tslib": "1.11.1"
|
||||
"uuid": "8.2.0",
|
||||
"tslib": "2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codechecks/client": "0.1.10",
|
||||
"@commitlint/cli": "8.3.5",
|
||||
"@commitlint/config-angular": "8.3.4",
|
||||
"@grpc/proto-loader": "0.5.3",
|
||||
"@nestjs/graphql": "7.1.1",
|
||||
"@nestjs/mongoose": "6.4.0",
|
||||
"@nestjs/typeorm": "7.0.0",
|
||||
"@commitlint/cli": "9.0.1",
|
||||
"@commitlint/config-angular": "9.0.1",
|
||||
"@grpc/proto-loader": "0.5.4",
|
||||
"@nestjs/graphql": "7.4.6",
|
||||
"@nestjs/mongoose": "7.0.1",
|
||||
"@nestjs/typeorm": "7.1.0",
|
||||
"@types/amqplib": "0.5.13",
|
||||
"@types/bytes": "3.1.0",
|
||||
"@types/cache-manager": "2.10.2",
|
||||
"@types/chai": "4.2.10",
|
||||
"@types/cache-manager": "2.10.3",
|
||||
"@types/chai": "4.2.11",
|
||||
"@types/chai-as-promised": "7.1.2",
|
||||
"@types/cors": "2.8.6",
|
||||
"@types/express": "4.17.3",
|
||||
"@types/express": "4.17.6",
|
||||
"@types/fastify-cors": "2.1.0",
|
||||
"@types/gulp": "4.0.6",
|
||||
"@types/kafka-node": "2.0.9",
|
||||
"@types/mocha": "7.0.2",
|
||||
"@types/mongoose": "5.7.7",
|
||||
"@types/mongoose": "5.7.29",
|
||||
"@types/node": "10.17.3",
|
||||
"@types/redis": "2.8.16",
|
||||
"@types/redis": "2.8.22",
|
||||
"@types/reflect-metadata": "0.0.5",
|
||||
"@types/sinon": "7.5.2",
|
||||
"@types/socket.io": "2.1.4",
|
||||
"@types/ws": "7.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "2.25.0",
|
||||
"@typescript-eslint/parser": "2.25.0",
|
||||
"@types/sinon": "9.0.4",
|
||||
"@types/socket.io": "2.1.8",
|
||||
"@types/ws": "7.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "3.5.0",
|
||||
"@typescript-eslint/parser": "3.5.0",
|
||||
"amqp-connection-manager": "3.2.0",
|
||||
"amqplib": "0.5.5",
|
||||
"apollo-server-express": "2.11.0",
|
||||
"artillery": "1.6.0",
|
||||
"amqplib": "0.5.6",
|
||||
"apollo-server-express": "2.15.1",
|
||||
"artillery": "1.6.1",
|
||||
"awesome-typescript-loader": "5.2.1",
|
||||
"body-parser": "1.19.0",
|
||||
"bytes": "3.1.0",
|
||||
"cache-manager": "3.2.1",
|
||||
"cache-manager": "3.3.0",
|
||||
"chai": "4.2.0",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"clang-format": "1.4.0",
|
||||
"commitlint-circle": "1.0.0",
|
||||
"concurrently": "5.1.0",
|
||||
"conventional-changelog": "3.1.18",
|
||||
"core-js": "3.6.4",
|
||||
"coveralls": "3.0.11",
|
||||
"concurrently": "5.2.0",
|
||||
"conventional-changelog": "3.1.21",
|
||||
"core-js": "3.6.5",
|
||||
"coveralls": "3.1.0",
|
||||
"delete-empty": "3.0.0",
|
||||
"engine.io-client": "3.4.0",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-config-prettier": "6.10.1",
|
||||
"eslint-plugin-import": "2.20.1",
|
||||
"engine.io-client": "3.4.3",
|
||||
"eslint": "7.3.1",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"eslint-plugin-import": "2.22.0",
|
||||
"fancy-log": "1.3.3",
|
||||
"fastify": "2.13.0",
|
||||
"fastify-cors": "3.0.2",
|
||||
"fastify-formbody": "3.1.0",
|
||||
"fastify-multipart": "1.0.5",
|
||||
"fastify-static": "2.6.0",
|
||||
"graphql": "14.6.0",
|
||||
"graphql-tools": "4.0.7",
|
||||
"grpc": "1.24.2",
|
||||
"fastify": "2.15.1",
|
||||
"fastify-cors": "3.0.3",
|
||||
"fastify-formbody": "3.2.0",
|
||||
"fastify-multipart": "1.0.6",
|
||||
"fastify-static": "2.7.0",
|
||||
"graphql": "15.2.0",
|
||||
"graphql-tools": "6.0.11",
|
||||
"grpc": "1.24.3",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-clang-format": "1.0.27",
|
||||
"gulp-clean": "0.4.0",
|
||||
"gulp-sourcemaps": "2.6.5",
|
||||
"gulp-typescript": "5.0.1",
|
||||
"gulp-watch": "5.0.1",
|
||||
"husky": "4.2.3",
|
||||
"imports-loader": "0.8.0",
|
||||
"husky": "4.2.5",
|
||||
"imports-loader": "1.1.0",
|
||||
"json-loader": "0.5.7",
|
||||
"kafkajs": "1.12.0",
|
||||
"lerna": "2.11.0",
|
||||
"lint-staged": "10.0.9",
|
||||
"lint-staged": "10.2.11",
|
||||
"markdown-table": "2.0.0",
|
||||
"merge-graphql-schemas": "1.7.6",
|
||||
"mocha": "7.1.1",
|
||||
"mongoose": "5.9.6",
|
||||
"mqtt": "3.0.0",
|
||||
"merge-graphql-schemas": "1.7.8",
|
||||
"mocha": "7.1.2",
|
||||
"mongoose": "5.9.20",
|
||||
"mqtt": "4.1.0",
|
||||
"multer": "1.4.2",
|
||||
"mysql": "2.18.1",
|
||||
"nats": "1.4.8",
|
||||
"nodemon": "2.0.2",
|
||||
"nyc": "15.0.0",
|
||||
"prettier": "2.0.2",
|
||||
"nats": "1.4.9",
|
||||
"nodemon": "2.0.4",
|
||||
"nyc": "15.1.0",
|
||||
"prettier": "2.0.5",
|
||||
"redis": "3.0.2",
|
||||
"rxjs-compat": "6.5.4",
|
||||
"sinon": "9.0.1",
|
||||
"rxjs-compat": "6.5.5",
|
||||
"sinon": "9.0.2",
|
||||
"sinon-chai": "3.5.0",
|
||||
"socket.io-client": "2.3.0",
|
||||
"subscriptions-transport-ws": "0.9.16",
|
||||
"supertest": "4.0.2",
|
||||
"ts-morph": "7.0.0",
|
||||
"ts-node": "8.8.1",
|
||||
"typeorm": "0.2.24",
|
||||
"typescript": "3.7.2",
|
||||
"ts-morph": "7.1.2",
|
||||
"ts-node": "8.10.2",
|
||||
"typeorm": "0.2.25",
|
||||
"typescript": "3.9.5",
|
||||
"wrk": "1.2.0",
|
||||
"ws": "7.2.3"
|
||||
"ws": "7.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
@@ -193,7 +192,7 @@
|
||||
"packages/microservices/microservices-module.ts",
|
||||
"packages/core/middleware/middleware-module.ts",
|
||||
"packages/core/injector/module-ref.ts",
|
||||
"packages/core/injector/container-scanner.ts",
|
||||
"packages/core/injector/instance-links-host.ts",
|
||||
"packages/common/cache/**/*",
|
||||
"packages/common/serializer/**/*",
|
||||
"packages/common/services/logger.service.ts"
|
||||
|
||||
@@ -38,6 +38,14 @@ Nest is a framework for building efficient, scalable <a href="http://nodejs.org"
|
||||
* To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
|
||||
* 要查看中文 [指南](readme_zh.md), 请访问 [docs.nestjs.cn](https://docs.nestjs.cn). :books:
|
||||
|
||||
## Questions
|
||||
|
||||
For questions and support please use the official [Discord channel](https://discord.gg/G7Qnnhy). The issue list of this repo is **exclusively** for bug reports and feature requests.
|
||||
|
||||
## Issues
|
||||
|
||||
Please make sure to read the [Issue Reporting Checklist](https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md#-submitting-an-issue) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
|
||||
|
||||
## Consulting
|
||||
|
||||
With official support, you can get expert help straight from Nest core team. We provide dedicated technical support, migration strategies, advice on best practices (and design decisions), PR reviews, and team augmentation. Read more about [support here](https://enterprise.nestjs.com).
|
||||
@@ -48,30 +56,35 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors
|
||||
|
||||
#### Principal Sponsor
|
||||
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="320" /></a>
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="220" /></a>
|
||||
|
||||
#### Silver Sponsors
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" height="95" /></a>
|
||||
<a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="150" valign="middle" /></a>
|
||||
<a href="http://www.leogistics.com" target="_blank"><img src="https://nestjs.com/img/leogistics-logo.jpeg" width="150" valign="middle" /></a>
|
||||
|
||||
<table style="text-align:center;"><tr><td>
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a> </td><td>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" width="100" /></a> </td><td>
|
||||
<a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="170" valign="middle" /></a> </td><td>
|
||||
<a href="http://www.leogistics.com" target="_blank"><img src="https://nestjs.com/img/leogistics-logo.jpeg" width="150" valign="middle" /></td></tr></table>
|
||||
|
||||
#### Sponsors
|
||||
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a> <a href="https://blueanchor.io/" target="_blank"><img src="https://nestjs.com/img/blueanchor.png" width="150" valign="middle" /></a>
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> <a href="https://hostpresto.com" target="_blank"><img src="https://nestjs.com/img/hostpresto.png" height="24" valign="middle" /></a>
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" height="14" valign="middle" /></a>
|
||||
<a href="https://buddy.works/" target="_blank"><img src="https://nestjs.com/img/buddy-logo.svg" height="25" valign="middle" /></a>
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" height="25" valign="middle" /></a> <a href="https://genuinebee.com/" target="_blank"><img src="https://nestjs.com/img/genuinebee.svg" height="27" valign="middle" /></a> <a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" height="20" valign="middle" /></a> <a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" height="22" valign="middle" /></a> <a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" height="19" valign="middle" /></a> <a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" height="20" valign="middle" /></a>
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" height="18" valign="middle" /></a>
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a>
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a>
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a>
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a>
|
||||
<a href="https://tekhattan.com" target="_blank"><img src="https://nestjs.com/img/tekhattan-logo.png" width="110" valign="middle" /></a>
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a>
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a>
|
||||
|
||||
<table><tr><td align="center" valign="middle">
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a></td><td align="center" valign="middle">
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" width="72" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" width="125" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" width="100" valign="middle" /></a> </td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" width="95" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" width="107" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" width="71" valign="middle" /></a></td><td align="center" valign="middle">
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a></td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://tekhattan.com" target="_blank"><img src="https://nestjs.com/img/tekhattan-logo.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://www.thebigphonestore.co.uk/" target="_blank"><img src="https://nestjs.com/img/the-big-phone-store-logo.png" width="65" valign="middle" /></a></td></tr></table>
|
||||
|
||||
## Backers
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
HttpServer,
|
||||
NestInterceptor,
|
||||
} from '../../interfaces';
|
||||
import { isNil } from '../../utils/shared.utils';
|
||||
import {
|
||||
CACHE_KEY_METADATA,
|
||||
CACHE_MANAGER,
|
||||
@@ -44,13 +45,13 @@ export class CacheInterceptor implements NestInterceptor {
|
||||
}
|
||||
try {
|
||||
const value = await this.cacheManager.get(key);
|
||||
if (value) {
|
||||
if (typeof value !== 'undefined') {
|
||||
return of(value);
|
||||
}
|
||||
|
||||
return next.handle().pipe(
|
||||
tap(response => {
|
||||
const args = ttl ? [key, response, { ttl }] : [key, response];
|
||||
const args = isNil(ttl) ? [key, response] : [key, response, { ttl }];
|
||||
this.cacheManager.set(...args);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ export type CustomDecorator<TKey = string> = MethodDecorator &
|
||||
*
|
||||
* Requires two parameters:
|
||||
* - `key` - a value defining the key under which the metadata is stored
|
||||
* - `value[]` - array of metadata values to be associated with `key`
|
||||
* - `value` - metadata to be associated with `key`
|
||||
*
|
||||
* This metadata can be reflected using the `Reflector` class.
|
||||
*
|
||||
|
||||
@@ -5,7 +5,7 @@ import { REDIRECT_METADATA } from '../../constants';
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export function Redirect(url: string, statusCode?: number): MethodDecorator {
|
||||
export function Redirect(url = '', statusCode?: number): MethodDecorator {
|
||||
return (
|
||||
target: object,
|
||||
key: string | symbol,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import Axios, {
|
||||
AxiosInstance,
|
||||
AxiosPromise,
|
||||
AxiosRequestConfig,
|
||||
AxiosResponse,
|
||||
AxiosPromise,
|
||||
CancelTokenSource,
|
||||
} from 'axios';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Inject } from '../decorators';
|
||||
@@ -72,13 +73,14 @@ export class HttpService {
|
||||
...args: any[]
|
||||
) {
|
||||
return new Observable<AxiosResponse<T>>(subscriber => {
|
||||
let config = args[args.length - 1];
|
||||
if (!config) {
|
||||
config = {};
|
||||
args[args.length - 1] = config;
|
||||
const config: AxiosRequestConfig = { ...(args[args.length - 1] || {}) };
|
||||
|
||||
let cancelSource: CancelTokenSource;
|
||||
if (!config.cancelToken) {
|
||||
cancelSource = Axios.CancelToken.source();
|
||||
config.cancelToken = cancelSource.token;
|
||||
}
|
||||
const cancelSource = Axios.CancelToken.source();
|
||||
config.cancelToken = cancelSource.token;
|
||||
|
||||
axios(...args)
|
||||
.then(res => {
|
||||
subscriber.next(res);
|
||||
@@ -88,7 +90,11 @@ export class HttpService {
|
||||
subscriber.error(err);
|
||||
});
|
||||
return () => {
|
||||
if (config.responseType !== 'stream') {
|
||||
if (config.responseType === 'stream') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cancelSource) {
|
||||
cancelSource.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,8 +30,11 @@ export {
|
||||
INestApplication,
|
||||
INestApplicationContext,
|
||||
INestMicroservice,
|
||||
IntrospectionResult,
|
||||
MiddlewareConsumer,
|
||||
ModuleMetadata,
|
||||
NestApplicationOptions,
|
||||
NestHybridApplicationOptions,
|
||||
NestInterceptor,
|
||||
NestMiddleware,
|
||||
NestModule,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ExecutionContext } from './execution-context.interface';
|
||||
*/
|
||||
export interface CallHandler<T = any> {
|
||||
/**
|
||||
* Returns an `Observable` reprsenting the response stream from the route
|
||||
* Returns an `Observable` representing the response stream from the route
|
||||
* handler.
|
||||
*/
|
||||
handle(): Observable<T>;
|
||||
|
||||
@@ -15,12 +15,9 @@ export * from './features/pipe-transform.interface';
|
||||
export * from './hooks';
|
||||
export * from './http/http-server.interface';
|
||||
export * from './injectable.interface';
|
||||
export * from './microservices/nest-hybrid-application-options.interface';
|
||||
export * from './middleware';
|
||||
export * from './modules/dynamic-module.interface';
|
||||
export * from './modules/forward-reference.interface';
|
||||
export * from './modules/module-metadata.interface';
|
||||
export * from './modules/nest-module.interface';
|
||||
export * from './modules/provider.interface';
|
||||
export * from './modules';
|
||||
export * from './nest-application-context.interface';
|
||||
export * from './nest-application-options.interface';
|
||||
export * from './nest-application.interface';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface NestHybridApplicationOptions {
|
||||
inheritAppConfig?: boolean;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './dynamic-module.interface';
|
||||
export * from './forward-reference.interface';
|
||||
export * from './introspection-result.interface';
|
||||
export * from './module-metadata.interface';
|
||||
export * from './nest-module.interface';
|
||||
export * from './provider.interface';
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Scope } from '../scope-options.interface';
|
||||
|
||||
/**
|
||||
* @publicApi
|
||||
*/
|
||||
export interface IntrospectionResult {
|
||||
/**
|
||||
* Enum defining lifetime of host class or factory.
|
||||
*/
|
||||
scope: Scope;
|
||||
}
|
||||
@@ -34,6 +34,15 @@ export interface INestApplicationContext {
|
||||
options?: { strict: boolean },
|
||||
): Promise<TResult>;
|
||||
|
||||
/**
|
||||
* Registers the request/context object for a given context ID (DI container sub-tree).
|
||||
* @returns {void}
|
||||
*/
|
||||
registerRequestByContextId<T = any>(
|
||||
request: T,
|
||||
contextId: { id: number },
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Terminates the application
|
||||
* @returns {Promise<void>}
|
||||
|
||||
@@ -2,7 +2,12 @@ import { CorsOptions } from './external/cors-options.interface';
|
||||
import { CanActivate } from './features/can-activate.interface';
|
||||
import { NestInterceptor } from './features/nest-interceptor.interface';
|
||||
import { HttpServer } from './http/http-server.interface';
|
||||
import { ExceptionFilter, INestMicroservice, PipeTransform } from './index';
|
||||
import {
|
||||
ExceptionFilter,
|
||||
INestMicroservice,
|
||||
NestHybridApplicationOptions,
|
||||
PipeTransform,
|
||||
} from './index';
|
||||
import { INestApplicationContext } from './nest-application-context.interface';
|
||||
import { WebSocketAdapter } from './websockets/web-socket-adapter.interface';
|
||||
|
||||
@@ -80,9 +85,13 @@ export interface INestApplication extends INestApplicationContext {
|
||||
* to a hybrid instance.
|
||||
*
|
||||
* @param {T} options Microservice options object
|
||||
* @param {NestHybridApplicationOptions} hybridOptions Hybrid options object
|
||||
* @returns {INestMicroservice}
|
||||
*/
|
||||
connectMicroservice<T extends object = any>(options: T): INestMicroservice;
|
||||
connectMicroservice<T extends object = any>(
|
||||
options: T,
|
||||
hybridOptions?: NestHybridApplicationOptions,
|
||||
): INestMicroservice;
|
||||
|
||||
/**
|
||||
* Returns array of the microservices connected to the NestApplication.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/common",
|
||||
"version": "7.0.5",
|
||||
"version": "7.3.0",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@common)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"homepage": "https://nestjs.com",
|
||||
@@ -19,8 +19,9 @@
|
||||
"dependencies": {
|
||||
"axios": "0.19.2",
|
||||
"cli-color": "2.0.0",
|
||||
"tslib": "1.11.1",
|
||||
"uuid": "7.0.2"
|
||||
"iterare": "1.2.1",
|
||||
"tslib": "2.0.0",
|
||||
"uuid": "8.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"reflect-metadata": "^0.1.12",
|
||||
|
||||
22
packages/common/pipes/default-value.pipe.ts
Normal file
22
packages/common/pipes/default-value.pipe.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ArgumentMetadata, Injectable, PipeTransform } from '../index';
|
||||
import { isNil } from '../utils/shared.utils';
|
||||
|
||||
/**
|
||||
* Defines the built-in DefaultValue Pipe
|
||||
*
|
||||
* @see [Built-in Pipes](https://docs.nestjs.com/pipes#built-in-pipes)
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
@Injectable()
|
||||
export class DefaultValuePipe<T = any, R = any>
|
||||
implements PipeTransform<T, T | R> {
|
||||
constructor(private readonly defaultValue: R) {}
|
||||
|
||||
transform(value?: T, _metadata?: ArgumentMetadata): T | R {
|
||||
if (isNil(value)) {
|
||||
return this.defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './default-value.pipe';
|
||||
export * from './parse-array.pipe';
|
||||
export * from './parse-bool.pipe';
|
||||
export * from './parse-int.pipe';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import iterate from 'iterare';
|
||||
import { iterate } from 'iterare';
|
||||
import { Optional } from '../decorators';
|
||||
import { Injectable } from '../decorators/core';
|
||||
import { HttpStatus } from '../enums/http-status.enum';
|
||||
@@ -159,7 +159,7 @@ export class ValidationPipe implements PipeTransform<any> {
|
||||
private stripProtoKeys(value: Record<string, any>) {
|
||||
delete value.__proto__;
|
||||
const keys = Object.keys(value);
|
||||
keys
|
||||
iterate(keys)
|
||||
.filter(key => typeof value[key] === 'object' && value[key])
|
||||
.forEach(key => this.stripProtoKeys(value[key]));
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Inject, Injectable } from '../decorators/core';
|
||||
import { Inject, Injectable, Optional } from '../decorators/core';
|
||||
import { CallHandler, ExecutionContext, NestInterceptor } from '../interfaces';
|
||||
import { ClassTransformOptions } from '../interfaces/external/class-transform-options.interface';
|
||||
import { loadPackage } from '../utils/load-package.util';
|
||||
import { isObject } from '../utils/shared.utils';
|
||||
import { CallHandler, ExecutionContext, NestInterceptor } from '../interfaces';
|
||||
import { CLASS_SERIALIZER_OPTIONS } from './class-serializer.constants';
|
||||
|
||||
let classTransformer: any = {};
|
||||
@@ -20,7 +20,10 @@ const REFLECTOR = 'Reflector';
|
||||
|
||||
@Injectable()
|
||||
export class ClassSerializerInterceptor implements NestInterceptor {
|
||||
constructor(@Inject(REFLECTOR) protected readonly reflector: any) {
|
||||
constructor(
|
||||
@Inject(REFLECTOR) protected readonly reflector: any,
|
||||
@Optional() protected readonly defaultOptions: ClassTransformOptions = {},
|
||||
) {
|
||||
classTransformer = loadPackage(
|
||||
'class-transformer',
|
||||
'ClassSerializerInterceptor',
|
||||
@@ -30,7 +33,11 @@ export class ClassSerializerInterceptor implements NestInterceptor {
|
||||
}
|
||||
|
||||
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
||||
const options = this.getContextOptions(context);
|
||||
const contextOptions = this.getContextOptions(context);
|
||||
const options = {
|
||||
...this.defaultOptions,
|
||||
...contextOptions,
|
||||
};
|
||||
return next
|
||||
.handle()
|
||||
.pipe(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { expect } from 'chai';
|
||||
import { ROUTE_ARGS_METADATA } from '../../constants';
|
||||
import { Bind } from '../../decorators/core/bind.decorator';
|
||||
import { ROUTE_ARGS_METADATA } from '@nestjs/common/constants';
|
||||
import { Req } from '../../decorators/http/route-params.decorator';
|
||||
|
||||
describe('@Bind', () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ParseIntPipe } from '@nestjs/common';
|
||||
import { ROUTE_ARGS_METADATA } from '@nestjs/common/constants';
|
||||
import { expect } from 'chai';
|
||||
import { ROUTE_ARGS_METADATA } from '../../constants';
|
||||
import { createParamDecorator } from '../../decorators/http/create-route-param-metadata.decorator';
|
||||
import { ParseIntPipe } from '../../index';
|
||||
|
||||
describe('createParamDecorator', () => {
|
||||
let result;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect } from 'chai';
|
||||
import { Redirect } from '../../decorators/http/redirect.decorator';
|
||||
import { REDIRECT_METADATA } from '../../constants';
|
||||
import { HttpStatus } from '@nestjs/common';
|
||||
import { Redirect } from '../../decorators/http/redirect.decorator';
|
||||
import { HttpStatus } from '../../index';
|
||||
|
||||
describe('@Redirect', () => {
|
||||
const url = 'http://test.com';
|
||||
|
||||
@@ -8,17 +8,17 @@ class Guard {}
|
||||
describe('@UseGuards', () => {
|
||||
const guards = [Guard, Guard];
|
||||
|
||||
@UseGuards(...(guards as any))
|
||||
@UseGuards(...guards)
|
||||
class Test {}
|
||||
|
||||
class TestWithMethod {
|
||||
@UseGuards(...(guards as any))
|
||||
@UseGuards(...guards)
|
||||
public static test() {}
|
||||
}
|
||||
|
||||
class Test2 {
|
||||
@UseGuards(...(guards as any))
|
||||
@UseGuards(...(guards as any))
|
||||
@UseGuards(...guards)
|
||||
@UseGuards(...guards)
|
||||
public static test() {}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ class Interceptor {}
|
||||
describe('@UseInterceptors', () => {
|
||||
const interceptors = [Interceptor, Interceptor];
|
||||
|
||||
@UseInterceptors(...(interceptors as any))
|
||||
@UseInterceptors(...interceptors)
|
||||
class Test {}
|
||||
|
||||
class TestWithMethod {
|
||||
@UseInterceptors(...(interceptors as any))
|
||||
@UseInterceptors(...interceptors)
|
||||
public static test() {}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ class Pipe {
|
||||
describe('@UsePipes', () => {
|
||||
const pipes = [new Pipe(), new Pipe()];
|
||||
|
||||
@UsePipes(...(pipes as any))
|
||||
@UsePipes(...pipes)
|
||||
class Test {}
|
||||
|
||||
class TestWithMethod {
|
||||
@UsePipes(...(pipes as any))
|
||||
@UsePipes(...pipes)
|
||||
public static test() {}
|
||||
}
|
||||
|
||||
|
||||
18
packages/common/test/http/http.service.spec.ts
Normal file
18
packages/common/test/http/http.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { expect } from 'chai';
|
||||
import { HttpService } from '../../http/http.service';
|
||||
import { AxiosRequestConfig, AxiosInstance } from 'axios';
|
||||
|
||||
describe('HttpService', () => {
|
||||
it('should not mutate user-given axios options object', done => {
|
||||
const http = new HttpService({ get: () => Promise.resolve() } as any);
|
||||
const options: AxiosRequestConfig = {};
|
||||
|
||||
http
|
||||
.get('/', options)
|
||||
.toPromise()
|
||||
.then(() => {
|
||||
expect(options.cancelToken).to.be.undefined;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
20
packages/common/test/pipes/default-value.pipe.spec.ts
Normal file
20
packages/common/test/pipes/default-value.pipe.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { expect } from 'chai';
|
||||
import { DefaultValuePipe } from '../../pipes/default-value.pipe';
|
||||
|
||||
describe('DefaultValuePipe', () => {
|
||||
const defaultValue = 'default';
|
||||
const target = new DefaultValuePipe(defaultValue);
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return original value if one was provided', () => {
|
||||
const value = 'value';
|
||||
const result = target.transform(value);
|
||||
expect(result).to.equal(value);
|
||||
});
|
||||
|
||||
it('should return default value if no value was provided', () => {
|
||||
const result = target.transform(undefined);
|
||||
expect(result).to.equal(defaultValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -38,6 +38,14 @@ Nest is a framework for building efficient, scalable <a href="http://nodejs.org"
|
||||
* To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
|
||||
* 要查看中文 [指南](readme_zh.md), 请访问 [docs.nestjs.cn](https://docs.nestjs.cn). :books:
|
||||
|
||||
## Questions
|
||||
|
||||
For questions and support please use the official [Discord channel](https://discord.gg/G7Qnnhy). The issue list of this repo is **exclusively** for bug reports and feature requests.
|
||||
|
||||
## Issues
|
||||
|
||||
Please make sure to read the [Issue Reporting Checklist](https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md#-submitting-an-issue) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
|
||||
|
||||
## Consulting
|
||||
|
||||
With official support, you can get expert help straight from Nest core team. We provide dedicated technical support, migration strategies, advice on best practices (and design decisions), PR reviews, and team augmentation. Read more about [support here](https://enterprise.nestjs.com).
|
||||
@@ -48,30 +56,35 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors
|
||||
|
||||
#### Principal Sponsor
|
||||
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="320" /></a>
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="220" /></a>
|
||||
|
||||
#### Silver Sponsors
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" height="95" /></a>
|
||||
<a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="150" valign="middle" /></a>
|
||||
<a href="http://www.leogistics.com" target="_blank"><img src="https://nestjs.com/img/leogistics-logo.jpeg" width="150" valign="middle" /></a>
|
||||
|
||||
<table style="text-align:center;"><tr><td>
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a> </td><td>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" width="100" /></a> </td><td>
|
||||
<a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="170" valign="middle" /></a> </td><td>
|
||||
<a href="http://www.leogistics.com" target="_blank"><img src="https://nestjs.com/img/leogistics-logo.jpeg" width="150" valign="middle" /></td></tr></table>
|
||||
|
||||
#### Sponsors
|
||||
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a> <a href="https://blueanchor.io/" target="_blank"><img src="https://nestjs.com/img/blueanchor.png" width="150" valign="middle" /></a>
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> <a href="https://hostpresto.com" target="_blank"><img src="https://nestjs.com/img/hostpresto.png" height="24" valign="middle" /></a>
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" height="14" valign="middle" /></a>
|
||||
<a href="https://buddy.works/" target="_blank"><img src="https://nestjs.com/img/buddy-logo.svg" height="25" valign="middle" /></a>
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" height="25" valign="middle" /></a> <a href="https://genuinebee.com/" target="_blank"><img src="https://nestjs.com/img/genuinebee.svg" height="27" valign="middle" /></a> <a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" height="20" valign="middle" /></a> <a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" height="22" valign="middle" /></a> <a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" height="19" valign="middle" /></a> <a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" height="20" valign="middle" /></a>
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" height="18" valign="middle" /></a>
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a>
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a>
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a>
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a>
|
||||
<a href="https://tekhattan.com" target="_blank"><img src="https://nestjs.com/img/tekhattan-logo.png" width="110" valign="middle" /></a>
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a>
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a>
|
||||
|
||||
<table><tr><td align="center" valign="middle">
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a></td><td align="center" valign="middle">
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" width="72" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" width="125" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" width="100" valign="middle" /></a> </td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" width="95" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" width="107" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" width="71" valign="middle" /></a></td><td align="center" valign="middle">
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a></td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://tekhattan.com" target="_blank"><img src="https://nestjs.com/img/tekhattan-logo.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://www.thebigphonestore.co.uk/" target="_blank"><img src="https://nestjs.com/img/the-big-phone-store-logo.png" width="65" valign="middle" /></a></td></tr></table>
|
||||
|
||||
## Backers
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@ import { INVALID_MODULE_MESSAGE } from '../messages';
|
||||
import { RuntimeException } from './runtime.exception';
|
||||
|
||||
export class InvalidModuleException extends RuntimeException {
|
||||
constructor(trace: any[]) {
|
||||
const scope = (trace || []).map(module => module.name).join(' -> ');
|
||||
super(INVALID_MODULE_MESSAGE`${scope}`);
|
||||
constructor(parentModule: any, index: number, scope: any[]) {
|
||||
super(INVALID_MODULE_MESSAGE(parentModule, index, scope));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { UNDEFINED_FORWARDREF_MESSAGE } from '../messages';
|
||||
import { RuntimeException } from './runtime.exception';
|
||||
import { Type } from '@nestjs/common';
|
||||
|
||||
export class UndefinedForwardRefException extends RuntimeException {
|
||||
constructor(scope: Type<any>[]) {
|
||||
super(UNDEFINED_FORWARDREF_MESSAGE(scope));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { RuntimeException } from './runtime.exception';
|
||||
import { UNDEFINED_MODULE_MESSAGE } from '../messages';
|
||||
|
||||
export class UndefinedModuleException extends RuntimeException {
|
||||
constructor(parentModule: any, index: number, scope: any[]) {
|
||||
super(UNDEFINED_MODULE_MESSAGE(parentModule, index, scope));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { RuntimeException } from './runtime.exception';
|
||||
|
||||
export class UnknownElementException extends RuntimeException {
|
||||
constructor(name?: string) {
|
||||
constructor(name?: string | symbol) {
|
||||
name = name && name.toString();
|
||||
super(
|
||||
`Nest could not find ${
|
||||
name || 'given'
|
||||
|
||||
@@ -2,7 +2,7 @@ import { UNKNOWN_EXPORT_MESSAGE } from '../messages';
|
||||
import { RuntimeException } from './runtime.exception';
|
||||
|
||||
export class UnknownExportException extends RuntimeException {
|
||||
constructor(token: string, module: string) {
|
||||
super(UNKNOWN_EXPORT_MESSAGE(token, module));
|
||||
constructor(token: string | symbol, moduleName: string) {
|
||||
super(UNKNOWN_EXPORT_MESSAGE(token, moduleName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ const getDependencyName = (dependency: InjectorDependency): string =>
|
||||
const getModuleName = (module: Module) =>
|
||||
(module && getInstanceName(module.metatype)) || 'current';
|
||||
|
||||
const stringifyScope = (scope: any[]): string =>
|
||||
(scope || []).map(getInstanceName).join(' -> ');
|
||||
|
||||
export const UNKNOWN_DEPENDENCIES_MESSAGE = (
|
||||
type: string | symbol,
|
||||
unknownDependencyContext: InjectorDependencyContext,
|
||||
@@ -84,17 +87,50 @@ export const INVALID_MIDDLEWARE_MESSAGE = (
|
||||
name: string,
|
||||
) => `The middleware doesn't provide the 'use' method (${name})`;
|
||||
|
||||
export const INVALID_MODULE_MESSAGE = (
|
||||
text: TemplateStringsArray,
|
||||
scope: string,
|
||||
) =>
|
||||
`Nest cannot create the module instance. Often, this is because of a circular dependency between modules. Use forwardRef() to avoid it.
|
||||
export const UNDEFINED_FORWARDREF_MESSAGE = (
|
||||
scope: Type<any>[],
|
||||
) => `Nest cannot create the module instance. Often, this is because of a circular dependency between modules. Use forwardRef() to avoid it.
|
||||
|
||||
(Read more: https://docs.nestjs.com/fundamentals/circular-dependency)
|
||||
Scope [${scope}]
|
||||
`;
|
||||
Scope [${stringifyScope(scope)}]
|
||||
`;
|
||||
|
||||
export const INVALID_MODULE_MESSAGE = (
|
||||
parentModule: any,
|
||||
index: number,
|
||||
scope: any[],
|
||||
) => {
|
||||
const parentModuleName = parentModule?.name || 'module';
|
||||
|
||||
return `Nest cannot create the ${parentModuleName} instance.
|
||||
Received an unexpected value at index [${index}] of the ${parentModuleName} "imports" array.
|
||||
|
||||
Scope [${stringifyScope(scope)}]`;
|
||||
};
|
||||
|
||||
export const UNDEFINED_MODULE_MESSAGE = (
|
||||
parentModule: any,
|
||||
index: number,
|
||||
scope: any[],
|
||||
) => {
|
||||
const parentModuleName = parentModule?.name || 'module';
|
||||
|
||||
return `Nest cannot create the ${parentModuleName} instance.
|
||||
The module at index [${index}] of the ${parentModuleName} "imports" array is undefined.
|
||||
|
||||
Potential causes:
|
||||
- A circular dependency between modules. Use forwardRef() to avoid it. Read more: https://docs.nestjs.com/fundamentals/circular-dependency
|
||||
- The module at index [${index}] is of type "undefined". Check your import statements and the type of the module.
|
||||
|
||||
Scope [${stringifyScope(scope)}]`;
|
||||
};
|
||||
|
||||
export const UNKNOWN_EXPORT_MESSAGE = (
|
||||
token: string | symbol = 'item',
|
||||
module: string,
|
||||
) => {
|
||||
token = isSymbol(token) ? token.toString() : token;
|
||||
|
||||
export const UNKNOWN_EXPORT_MESSAGE = (token = 'item', module: string) => {
|
||||
return `Nest cannot export a provider/module that is not a part of the currently processed module (${module}). Please verify whether the exported ${token} is available in this particular context.
|
||||
|
||||
Possible Solutions:
|
||||
|
||||
@@ -2,7 +2,7 @@ import { FILTER_CATCH_EXCEPTIONS } from '@nestjs/common/constants';
|
||||
import { Type } from '@nestjs/common/interfaces';
|
||||
import { ExceptionFilter } from '@nestjs/common/interfaces/exceptions/exception-filter.interface';
|
||||
import { isEmpty, isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { iterate } from 'iterare';
|
||||
import { ContextCreator } from '../helpers/context-creator';
|
||||
import { STATIC_CONTEXT } from '../injector/constants';
|
||||
import { NestContainer } from '../injector/container';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HttpException } from '@nestjs/common';
|
||||
import { HttpException, Type } from '@nestjs/common';
|
||||
import { ExceptionFilterMetadata } from '@nestjs/common/interfaces/exceptions/exception-filter-metadata.interface';
|
||||
import { ArgumentsHost } from '@nestjs/common/interfaces/features/arguments-host.interface';
|
||||
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
||||
@@ -26,14 +26,15 @@ export class ExceptionsHandler extends BaseExceptionFilter {
|
||||
exception: T,
|
||||
ctx: ArgumentsHost,
|
||||
): boolean {
|
||||
if (isEmpty(this.filters)) return false;
|
||||
if (isEmpty(this.filters)) {
|
||||
return false;
|
||||
}
|
||||
const isInstanceOf = (metatype: Type<unknown>) =>
|
||||
exception instanceof metatype;
|
||||
|
||||
const filter = this.filters.find(({ exceptionMetatypes }) => {
|
||||
const typeExists =
|
||||
!exceptionMetatypes.length ||
|
||||
exceptionMetatypes.some(
|
||||
ExceptionMetatype => exception instanceof ExceptionMetatype,
|
||||
);
|
||||
!exceptionMetatypes.length || exceptionMetatypes.some(isInstanceOf);
|
||||
return typeExists;
|
||||
});
|
||||
filter && filter.func(exception, ctx);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { RouterProxyCallback } from '../router/router-proxy';
|
||||
import { BaseExceptionFilterContext } from './base-exception-filter-context';
|
||||
import { ExternalExceptionsHandler } from './external-exceptions-handler';
|
||||
import { iterate } from 'iterare';
|
||||
|
||||
export class ExternalExceptionFilterContext extends BaseExceptionFilterContext {
|
||||
constructor(
|
||||
@@ -54,10 +55,11 @@ export class ExternalExceptionFilterContext extends BaseExceptionFilterContext {
|
||||
return globalFilters;
|
||||
}
|
||||
const scopedFilterWrappers = this.config.getGlobalRequestFilters() as InstanceWrapper[];
|
||||
const scopedFilters = scopedFilterWrappers
|
||||
const scopedFilters = iterate(scopedFilterWrappers)
|
||||
.map(wrapper => wrapper.getInstanceByContextId(contextId, inquirerId))
|
||||
.filter(host => host)
|
||||
.map(host => host.instance);
|
||||
.filter(host => !!host)
|
||||
.map(host => host.instance)
|
||||
.toArray();
|
||||
|
||||
return globalFilters.concat(scopedFilters) as T;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Type } from '@nestjs/common';
|
||||
import { ExceptionFilterMetadata } from '@nestjs/common/interfaces/exceptions';
|
||||
import { ArgumentsHost } from '@nestjs/common/interfaces/features/arguments-host.interface';
|
||||
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
||||
@@ -29,11 +30,13 @@ export class ExternalExceptionsHandler extends ExternalExceptionFilter {
|
||||
if (isEmpty(this.filters)) {
|
||||
return null;
|
||||
}
|
||||
const isInstanceOf = metatype => exception instanceof metatype;
|
||||
const filter = this.filters.find(({ exceptionMetatypes, func }) => {
|
||||
const hasMetatype =
|
||||
const isInstanceOf = (metatype: Type<unknown>) =>
|
||||
exception instanceof metatype;
|
||||
|
||||
const filter = this.filters.find(({ exceptionMetatypes }) => {
|
||||
const typeExists =
|
||||
!exceptionMetatypes.length || exceptionMetatypes.some(isInstanceOf);
|
||||
return hasMetatype;
|
||||
return typeExists;
|
||||
});
|
||||
return filter ? filter.func(exception, host) : null;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CanActivate } from '@nestjs/common';
|
||||
import { GUARDS_METADATA } from '@nestjs/common/constants';
|
||||
import { Controller } from '@nestjs/common/interfaces';
|
||||
import { isEmpty, isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { iterate } from 'iterare';
|
||||
import { ApplicationConfig } from '../application-config';
|
||||
import { ContextCreator } from '../helpers/context-creator';
|
||||
import { STATIC_CONTEXT } from '../injector/constants';
|
||||
@@ -100,10 +100,11 @@ export class GuardsContextCreator extends ContextCreator {
|
||||
return globalGuards;
|
||||
}
|
||||
const scopedGuardWrappers = this.config.getGlobalRequestGuards() as InstanceWrapper[];
|
||||
const scopedGuards = scopedGuardWrappers
|
||||
const scopedGuards = iterate(scopedGuardWrappers)
|
||||
.map(wrapper => wrapper.getInstanceByContextId(contextId, inquirerId))
|
||||
.filter(host => host)
|
||||
.map(host => host.instance);
|
||||
.filter(host => !!host)
|
||||
.map(host => host.instance)
|
||||
.toArray();
|
||||
|
||||
return globalGuards.concat(scopedGuards) as T;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { BeforeApplicationShutdown } from '@nestjs/common';
|
||||
import { isNil } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
import { iterate } from 'iterare';
|
||||
import {
|
||||
getNonTransientInstances,
|
||||
getTransientInstances,
|
||||
} from '../injector/transient-instances';
|
||||
} from '../injector/helpers/transient-instances';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
|
||||
/**
|
||||
* Checks if the given instance has the `beforeApplicationShutdown` function
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { OnApplicationBootstrap } from '@nestjs/common';
|
||||
import { isNil } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
import { iterate } from 'iterare';
|
||||
import {
|
||||
getNonTransientInstances,
|
||||
getTransientInstances,
|
||||
} from '../injector/transient-instances';
|
||||
} from '../injector/helpers/transient-instances';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
|
||||
/**
|
||||
* Checks if the given instance has the `onApplicationBootstrap` function
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { OnApplicationShutdown } from '@nestjs/common';
|
||||
import { isNil } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
import { iterate } from 'iterare';
|
||||
import {
|
||||
getNonTransientInstances,
|
||||
getTransientInstances,
|
||||
} from '../injector/transient-instances';
|
||||
} from '../injector/helpers/transient-instances';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
|
||||
/**
|
||||
* Checks if the given instance has the `onApplicationShutdown` function
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { OnModuleDestroy } from '@nestjs/common';
|
||||
import { isNil } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
import { iterate } from 'iterare';
|
||||
import {
|
||||
getNonTransientInstances,
|
||||
getTransientInstances,
|
||||
} from '../injector/transient-instances';
|
||||
} from '../injector/helpers/transient-instances';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
|
||||
/**
|
||||
* Returns true or false if the given instance has a `onModuleDestroy` function
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { OnModuleInit } from '@nestjs/common';
|
||||
import { isNil } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
import { iterate } from 'iterare';
|
||||
import {
|
||||
getNonTransientInstances,
|
||||
getTransientInstances,
|
||||
} from '../injector/transient-instances';
|
||||
} from '../injector/helpers/transient-instances';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { Module } from '../injector/module';
|
||||
|
||||
/**
|
||||
* Returns true or false if the given instance has a `onModuleInit` function
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
import { Type } from '@nestjs/common';
|
||||
import { Abstract, Scope } from '@nestjs/common/interfaces';
|
||||
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import { InvalidClassScopeException } from '../errors/exceptions/invalid-class-scope.exception';
|
||||
import { UnknownElementException } from '../errors/exceptions/unknown-element.exception';
|
||||
import { NestContainer } from './container';
|
||||
import { InstanceWrapper } from './instance-wrapper';
|
||||
import { Module } from './module';
|
||||
|
||||
type HostCollection = 'providers' | 'controllers' | 'injectables';
|
||||
|
||||
export class ContainerScanner {
|
||||
private flatContainer: Partial<Module>;
|
||||
|
||||
constructor(private readonly container: NestContainer) {}
|
||||
|
||||
public find<TInput = any, TResult = TInput>(
|
||||
typeOrToken: Type<TInput> | Abstract<TInput> | string | symbol,
|
||||
): TResult {
|
||||
this.initFlatContainer();
|
||||
return this.findInstanceByToken<TInput, TResult>(
|
||||
typeOrToken,
|
||||
this.flatContainer,
|
||||
);
|
||||
}
|
||||
|
||||
public getWrapperCollectionPair<TInput = any, TResult = TInput>(
|
||||
typeOrToken: Type<TInput> | Abstract<TInput> | string | symbol,
|
||||
): [InstanceWrapper<TResult>, Map<string, InstanceWrapper>] {
|
||||
this.initFlatContainer();
|
||||
return this.getWrapperCollectionPairByHost<TInput, TResult>(
|
||||
typeOrToken,
|
||||
this.flatContainer,
|
||||
);
|
||||
}
|
||||
|
||||
public findInstanceByToken<TInput = any, TResult = TInput>(
|
||||
metatypeOrToken: Type<TInput> | Abstract<TInput> | string | symbol,
|
||||
contextModule: Partial<Module>,
|
||||
): TResult {
|
||||
const [instanceWrapper] = this.getWrapperCollectionPairByHost(
|
||||
metatypeOrToken,
|
||||
contextModule,
|
||||
);
|
||||
if (
|
||||
instanceWrapper.scope === Scope.REQUEST ||
|
||||
instanceWrapper.scope === Scope.TRANSIENT
|
||||
) {
|
||||
throw new InvalidClassScopeException(metatypeOrToken);
|
||||
}
|
||||
return (instanceWrapper.instance as unknown) as TResult;
|
||||
}
|
||||
|
||||
public getWrapperCollectionPairByHost<TInput = any, TResult = TInput>(
|
||||
metatypeOrToken: Type<TInput> | Abstract<TInput> | string | symbol,
|
||||
contextModule: Partial<Module>,
|
||||
): [InstanceWrapper<TResult>, Map<string, InstanceWrapper>] {
|
||||
const name = isFunction(metatypeOrToken)
|
||||
? (metatypeOrToken as Function).name
|
||||
: metatypeOrToken;
|
||||
const collectionName = this.getHostCollection(
|
||||
name as string,
|
||||
contextModule,
|
||||
);
|
||||
const instanceWrapper = contextModule[collectionName].get(name as string);
|
||||
if (!instanceWrapper) {
|
||||
throw new UnknownElementException(name && name.toString());
|
||||
}
|
||||
return [
|
||||
instanceWrapper as InstanceWrapper<TResult>,
|
||||
contextModule[collectionName],
|
||||
];
|
||||
}
|
||||
|
||||
private initFlatContainer() {
|
||||
if (this.flatContainer) {
|
||||
return;
|
||||
}
|
||||
const modules = this.container.getModules();
|
||||
const initialValue: Record<string, any[]> = {
|
||||
providers: [],
|
||||
controllers: [],
|
||||
injectables: [],
|
||||
};
|
||||
const merge = <T = unknown>(
|
||||
initial: Map<string, T> | T[],
|
||||
arr: Map<string, T>,
|
||||
) => [...initial, ...arr];
|
||||
|
||||
const partialModule = ([...modules.values()].reduce(
|
||||
(current, next) => ({
|
||||
providers: merge(current.providers, next.providers),
|
||||
controllers: merge(current.controllers, next.controllers),
|
||||
injectables: merge(current.injectables, next.injectables),
|
||||
}),
|
||||
initialValue,
|
||||
) as any) as Partial<Module>;
|
||||
|
||||
this.flatContainer = {
|
||||
providers: new Map(partialModule.providers),
|
||||
controllers: new Map(partialModule.controllers),
|
||||
injectables: new Map(partialModule.injectables),
|
||||
};
|
||||
}
|
||||
|
||||
private getHostCollection(
|
||||
token: string,
|
||||
{ providers, controllers }: Partial<Module>,
|
||||
): HostCollection {
|
||||
if (providers.has(token)) {
|
||||
return 'providers';
|
||||
}
|
||||
if (controllers.has(token)) {
|
||||
return 'controllers';
|
||||
}
|
||||
return 'injectables';
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common/interfaces/injectable.interface';
|
||||
import { Type } from '@nestjs/common/interfaces/type.interface';
|
||||
import { ApplicationConfig } from '../application-config';
|
||||
import { CircularDependencyException } from '../errors/exceptions/circular-dependency.exception';
|
||||
import { InvalidModuleException } from '../errors/exceptions/invalid-module.exception';
|
||||
import { UndefinedForwardRefException } from '../errors/exceptions/undefined-forwardref.exception';
|
||||
import { UnknownModuleException } from '../errors/exceptions/unknown-module.exception';
|
||||
import { ExternalContextCreator } from '../helpers/external-context-creator';
|
||||
import { HttpAdapterHost } from '../helpers/http-adapter-host';
|
||||
@@ -55,8 +55,10 @@ export class NestContainer {
|
||||
metatype: Type<any> | DynamicModule | Promise<DynamicModule>,
|
||||
scope: Type<any>[],
|
||||
): Promise<Module> {
|
||||
// In DependenciesScanner#scanForModules we already check for undefined or invalid modules
|
||||
// We sill need to catch the edge-case of `forwardRef(() => undefined)`
|
||||
if (!metatype) {
|
||||
throw new InvalidModuleException(scope);
|
||||
throw new UndefinedForwardRefException(scope);
|
||||
}
|
||||
const { type, dynamicMetadata, token } = await this.moduleCompiler.compile(
|
||||
metatype,
|
||||
@@ -64,7 +66,7 @@ export class NestContainer {
|
||||
if (this.modules.has(token)) {
|
||||
return;
|
||||
}
|
||||
const moduleRef = new Module(type, scope, this);
|
||||
const moduleRef = new Module(type, this);
|
||||
this.modules.set(token, moduleRef);
|
||||
this.addDynamicMetadata(token, dynamicMetadata, [].concat(scope, type));
|
||||
|
||||
@@ -180,11 +182,11 @@ export class NestContainer {
|
||||
}
|
||||
|
||||
public replace(toReplace: any, options: any & { scope: any[] | null }) {
|
||||
this.modules.forEach(module => module.replace(toReplace, options));
|
||||
this.modules.forEach(moduleRef => moduleRef.replace(toReplace, options));
|
||||
}
|
||||
|
||||
public bindGlobalScope() {
|
||||
this.modules.forEach(module => this.bindGlobalsToImports(module));
|
||||
this.modules.forEach(moduleRef => this.bindGlobalsToImports(moduleRef));
|
||||
}
|
||||
|
||||
public bindGlobalsToImports(moduleRef: Module) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import iterate from 'iterare';
|
||||
|
||||
import { InstanceWrapper } from './instance-wrapper';
|
||||
import { iterate } from 'iterare';
|
||||
import { InstanceWrapper } from '../instance-wrapper';
|
||||
|
||||
/**
|
||||
* Returns the instances which are transient
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
isString,
|
||||
isUndefined,
|
||||
} from '@nestjs/common/utils/shared.utils';
|
||||
import { iterate } from 'iterare';
|
||||
import { RuntimeException } from '../errors/exceptions/runtime.exception';
|
||||
import { UndefinedDependencyException } from '../errors/exceptions/undefined-dependency.exception';
|
||||
import { UnknownDependenciesException } from '../errors/exceptions/unknown-dependencies.exception';
|
||||
@@ -612,7 +613,7 @@ export class Injector {
|
||||
if (!isObject(instance)) {
|
||||
return undefined;
|
||||
}
|
||||
properties
|
||||
iterate(properties)
|
||||
.filter(item => !isNil(item.instance))
|
||||
.forEach(item => (instance[item.key] = item.instance));
|
||||
}
|
||||
@@ -665,8 +666,11 @@ export class Injector {
|
||||
wrapper?: InstanceWrapper,
|
||||
): Promise<T> {
|
||||
if (!wrapper) {
|
||||
const ctor = instance.constructor;
|
||||
wrapper = collection.get(ctor && ctor.name);
|
||||
const providerCtor = instance.constructor;
|
||||
const injectionToken =
|
||||
(providerCtor && providerCtor.name) ||
|
||||
((providerCtor as unknown) as string);
|
||||
wrapper = collection.get(injectionToken);
|
||||
}
|
||||
await this.loadInstance(wrapper, collection, moduleRef, ctx, wrapper);
|
||||
await this.loadEnhancersPerContext(wrapper, ctx, wrapper);
|
||||
|
||||
79
packages/core/injector/instance-links-host.ts
Normal file
79
packages/core/injector/instance-links-host.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Abstract, Type } from '@nestjs/common';
|
||||
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import { UnknownElementException } from '../errors/exceptions/unknown-element.exception';
|
||||
import { NestContainer } from './container';
|
||||
import { InstanceWrapper } from './instance-wrapper';
|
||||
import { Module } from './module';
|
||||
|
||||
type InstanceToken = string | symbol | Type<any> | Abstract<any> | Function;
|
||||
type HostCollection = 'providers' | 'controllers' | 'injectables';
|
||||
|
||||
export interface InstanceLink<T = any> {
|
||||
token: InstanceToken;
|
||||
wrapperRef: InstanceWrapper<T>;
|
||||
collection: Map<any, InstanceWrapper>;
|
||||
moduleId: string;
|
||||
}
|
||||
|
||||
export class InstanceLinksHost {
|
||||
private readonly instanceLinks = new Map<InstanceToken, InstanceLink[]>();
|
||||
|
||||
constructor(private readonly container: NestContainer) {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
get<T = any>(token: InstanceToken, moduleId?: string): InstanceLink<T> {
|
||||
const name = isFunction(token)
|
||||
? (token as Function).name
|
||||
: (token as string | symbol);
|
||||
const modulesMap = this.instanceLinks.get(name);
|
||||
|
||||
if (!modulesMap) {
|
||||
throw new UnknownElementException(name);
|
||||
}
|
||||
const instanceLink = moduleId
|
||||
? modulesMap.find(item => item.moduleId === moduleId)
|
||||
: modulesMap[0];
|
||||
|
||||
if (!instanceLink) {
|
||||
throw new UnknownElementException(name);
|
||||
}
|
||||
return instanceLink;
|
||||
}
|
||||
|
||||
private initialize() {
|
||||
const modules = this.container.getModules();
|
||||
modules.forEach(moduleRef => {
|
||||
const { providers, injectables, controllers } = moduleRef;
|
||||
providers.forEach((wrapper, token) =>
|
||||
this.addLink(wrapper, token, moduleRef, 'providers'),
|
||||
);
|
||||
injectables.forEach((wrapper, token) =>
|
||||
this.addLink(wrapper, token, moduleRef, 'injectables'),
|
||||
);
|
||||
controllers.forEach((wrapper, token) =>
|
||||
this.addLink(wrapper, token, moduleRef, 'controllers'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private addLink(
|
||||
wrapper: InstanceWrapper,
|
||||
token: InstanceToken,
|
||||
moduleRef: Module,
|
||||
collectionName: HostCollection,
|
||||
) {
|
||||
const instanceLink: InstanceLink = {
|
||||
moduleId: moduleRef.id,
|
||||
wrapperRef: wrapper,
|
||||
collection: moduleRef[collectionName],
|
||||
token,
|
||||
};
|
||||
const existingLinks = this.instanceLinks.get(token);
|
||||
if (!existingLinks) {
|
||||
this.instanceLinks.set(token, [instanceLink]);
|
||||
} else {
|
||||
existingLinks.push(instanceLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from '@nestjs/common/interfaces';
|
||||
import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util';
|
||||
import { isNil, isUndefined } from '@nestjs/common/utils/shared.utils';
|
||||
import { iterate } from 'iterare';
|
||||
import { STATIC_CONTEXT } from './constants';
|
||||
import { Module } from './module';
|
||||
|
||||
@@ -37,9 +38,9 @@ export class InstanceWrapper<T = any> {
|
||||
public readonly name: any;
|
||||
public readonly async?: boolean;
|
||||
public readonly host?: Module;
|
||||
public readonly scope?: Scope = Scope.DEFAULT;
|
||||
public readonly isAlias: boolean = false;
|
||||
|
||||
public scope?: Scope = Scope.DEFAULT;
|
||||
public metatype: Type<T> | Function;
|
||||
public inject?: (string | symbol | Function | Type<any>)[];
|
||||
public forwardRef?: boolean;
|
||||
@@ -255,9 +256,11 @@ export class InstanceWrapper<T = any> {
|
||||
): boolean {
|
||||
const isDependencyTreeStatic = this.isDependencyTreeStatic();
|
||||
|
||||
return ((!isDependencyTreeStatic &&
|
||||
return (
|
||||
!isDependencyTreeStatic &&
|
||||
contextId !== STATIC_CONTEXT &&
|
||||
(!this.isTransient || (this.isTransient && inquirer))) as any) as boolean;
|
||||
(!this.isTransient || (this.isTransient && !!inquirer))
|
||||
);
|
||||
}
|
||||
|
||||
public isLazyTransient(
|
||||
@@ -279,10 +282,11 @@ export class InstanceWrapper<T = any> {
|
||||
contextId: ContextId,
|
||||
inquirer?: InstanceWrapper,
|
||||
): boolean {
|
||||
const isSelfRequested = inquirer === this;
|
||||
return (
|
||||
this.isDependencyTreeStatic() &&
|
||||
contextId !== STATIC_CONTEXT &&
|
||||
inquirer === this
|
||||
(isSelfRequested || (inquirer && inquirer.scope === Scope.TRANSIENT))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -297,7 +301,8 @@ export class InstanceWrapper<T = any> {
|
||||
return (
|
||||
this.isDependencyTreeStatic() &&
|
||||
contextId === STATIC_CONTEXT &&
|
||||
(!this.isTransient || (isStaticTransient && !!inquirer))
|
||||
(!this.isTransient ||
|
||||
(isStaticTransient && !!inquirer && !inquirer.isTransient))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -306,15 +311,17 @@ export class InstanceWrapper<T = any> {
|
||||
return [];
|
||||
}
|
||||
const instances = [...this.transientMap.values()];
|
||||
return instances
|
||||
return iterate(instances)
|
||||
.map(item => item.get(STATIC_CONTEXT))
|
||||
.filter(item => !!item);
|
||||
.filter(item => !!item)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
public mergeWith(provider: Provider) {
|
||||
if ((provider as ValueProvider).useValue) {
|
||||
this.metatype = null;
|
||||
this.inject = null;
|
||||
this.scope = Scope.DEFAULT;
|
||||
|
||||
this.setInstanceByContextId(STATIC_CONTEXT, {
|
||||
instance: (provider as ValueProvider).useValue,
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
import { Type } from '@nestjs/common';
|
||||
import { IntrospectionResult, Scope, Type } from '@nestjs/common';
|
||||
import { InvalidClassScopeException } from '../errors/exceptions/invalid-class-scope.exception';
|
||||
import { UnknownElementException } from '../errors/exceptions/unknown-element.exception';
|
||||
import { getClassScope } from '../helpers/get-class-scope';
|
||||
import { NestContainer } from './container';
|
||||
import { ContainerScanner } from './container-scanner';
|
||||
import { Injector } from './injector';
|
||||
import { InstanceLinksHost } from './instance-links-host';
|
||||
import { ContextId, InstanceWrapper } from './instance-wrapper';
|
||||
import { Module } from './module';
|
||||
|
||||
export abstract class ModuleRef {
|
||||
private readonly injector = new Injector();
|
||||
private readonly containerScanner: ContainerScanner;
|
||||
private _instanceLinksHost: InstanceLinksHost;
|
||||
|
||||
constructor(protected readonly container: NestContainer) {
|
||||
this.containerScanner = new ContainerScanner(container);
|
||||
private get instanceLinksHost() {
|
||||
if (!this._instanceLinksHost) {
|
||||
this._instanceLinksHost = new InstanceLinksHost(this.container);
|
||||
}
|
||||
return this._instanceLinksHost;
|
||||
}
|
||||
|
||||
constructor(protected readonly container: NestContainer) {}
|
||||
|
||||
public abstract get<TInput = any, TResult = TInput>(
|
||||
typeOrToken: Type<TInput> | string | symbol,
|
||||
options?: { strict: boolean },
|
||||
@@ -25,10 +32,70 @@ export abstract class ModuleRef {
|
||||
): Promise<TResult>;
|
||||
public abstract create<T = any>(type: Type<T>): Promise<T>;
|
||||
|
||||
public introspect<T = any>(
|
||||
token: Type<T> | string | symbol,
|
||||
): IntrospectionResult {
|
||||
const { wrapperRef } = this.instanceLinksHost.get(token);
|
||||
|
||||
let scope = Scope.DEFAULT;
|
||||
if (!wrapperRef.isDependencyTreeStatic()) {
|
||||
scope = Scope.REQUEST;
|
||||
} else if (wrapperRef.isTransient) {
|
||||
scope = Scope.TRANSIENT;
|
||||
}
|
||||
return { scope };
|
||||
}
|
||||
|
||||
public registerRequestByContextId<T = any>(request: T, contextId: ContextId) {
|
||||
this.container.registerRequestProvider(request, contextId);
|
||||
}
|
||||
|
||||
protected find<TInput = any, TResult = TInput>(
|
||||
typeOrToken: Type<TInput> | string | symbol,
|
||||
contextModule?: Module,
|
||||
): TResult {
|
||||
return this.containerScanner.find<TInput, TResult>(typeOrToken);
|
||||
const moduleId = contextModule && contextModule.id;
|
||||
const { wrapperRef } = this.instanceLinksHost.get<TResult>(
|
||||
typeOrToken,
|
||||
moduleId,
|
||||
);
|
||||
if (
|
||||
wrapperRef.scope === Scope.REQUEST ||
|
||||
wrapperRef.scope === Scope.TRANSIENT
|
||||
) {
|
||||
throw new InvalidClassScopeException(typeOrToken);
|
||||
}
|
||||
return wrapperRef.instance;
|
||||
}
|
||||
|
||||
protected async resolvePerContext<TInput = any, TResult = TInput>(
|
||||
typeOrToken: Type<TInput> | string | symbol,
|
||||
contextModule: Module,
|
||||
contextId: ContextId,
|
||||
options?: { strict: boolean },
|
||||
): Promise<TResult> {
|
||||
const isStrictModeEnabled = options && options.strict;
|
||||
const instanceLink = isStrictModeEnabled
|
||||
? this.instanceLinksHost.get(typeOrToken, contextModule.id)
|
||||
: this.instanceLinksHost.get(typeOrToken);
|
||||
|
||||
const { wrapperRef, collection } = instanceLink;
|
||||
if (wrapperRef.isDependencyTreeStatic() && !wrapperRef.isTransient) {
|
||||
return this.get(typeOrToken);
|
||||
}
|
||||
|
||||
const ctorHost = wrapperRef.instance || { constructor: typeOrToken };
|
||||
const instance = await this.injector.loadPerContext(
|
||||
ctorHost,
|
||||
wrapperRef.host,
|
||||
collection,
|
||||
contextId,
|
||||
wrapperRef,
|
||||
);
|
||||
if (!instance) {
|
||||
throw new UnknownElementException();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected async instantiateClass<T = any>(
|
||||
@@ -38,8 +105,8 @@ export abstract class ModuleRef {
|
||||
const wrapper = new InstanceWrapper({
|
||||
name: type && type.name,
|
||||
metatype: type,
|
||||
instance: undefined,
|
||||
isResolved: false,
|
||||
scope: getClassScope(type),
|
||||
host: moduleRef,
|
||||
});
|
||||
return new Promise<T>(async (resolve, reject) => {
|
||||
@@ -64,47 +131,4 @@ export abstract class ModuleRef {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected findInstanceByToken<TInput = any, TResult = TInput>(
|
||||
metatypeOrToken: Type<TInput> | string | symbol,
|
||||
contextModule: Module,
|
||||
): TResult {
|
||||
return this.containerScanner.findInstanceByToken<TInput, TResult>(
|
||||
metatypeOrToken,
|
||||
contextModule,
|
||||
);
|
||||
}
|
||||
|
||||
protected async resolvePerContext<TInput = any, TResult = TInput>(
|
||||
typeOrToken: Type<TInput> | string | symbol,
|
||||
contextModule: Module,
|
||||
contextId: ContextId,
|
||||
options?: { strict: boolean },
|
||||
): Promise<TResult> {
|
||||
let wrapper: InstanceWrapper, collection: Map<string, InstanceWrapper>;
|
||||
if (!(options && options.strict)) {
|
||||
[wrapper, collection] = this.containerScanner.getWrapperCollectionPair(
|
||||
typeOrToken,
|
||||
);
|
||||
} else {
|
||||
[
|
||||
wrapper,
|
||||
collection,
|
||||
] = this.containerScanner.getWrapperCollectionPairByHost(
|
||||
typeOrToken,
|
||||
contextModule,
|
||||
);
|
||||
}
|
||||
const instance = await this.injector.loadPerContext(
|
||||
wrapper.instance,
|
||||
wrapper.host,
|
||||
collection,
|
||||
contextId,
|
||||
wrapper,
|
||||
);
|
||||
if (!instance) {
|
||||
throw new UnknownElementException();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
isSymbol,
|
||||
isUndefined,
|
||||
} from '@nestjs/common/utils/shared.utils';
|
||||
import { iterate } from 'iterare';
|
||||
import { ApplicationConfig } from '../application-config';
|
||||
import { InvalidClassException } from '../errors/exceptions/invalid-class.exception';
|
||||
import { RuntimeException } from '../errors/exceptions/runtime.exception';
|
||||
@@ -49,7 +50,6 @@ export class Module {
|
||||
|
||||
constructor(
|
||||
private readonly _metatype: Type<any>,
|
||||
private readonly _scope: Type<any>[],
|
||||
private readonly container: NestContainer,
|
||||
) {
|
||||
this.addCoreProviders();
|
||||
@@ -60,10 +60,6 @@ export class Module {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get scope(): Type<any>[] {
|
||||
return this._scope;
|
||||
}
|
||||
|
||||
get providers(): Map<any, InstanceWrapper<Injectable>> {
|
||||
return this._providers;
|
||||
}
|
||||
@@ -397,15 +393,16 @@ export class Module {
|
||||
return token;
|
||||
}
|
||||
const importsArray = [...this._imports.values()];
|
||||
const importsNames = importsArray
|
||||
.filter(item => item)
|
||||
const importsNames = iterate(importsArray)
|
||||
.filter(item => !!item)
|
||||
.map(({ metatype }) => metatype)
|
||||
.filter(metatype => metatype)
|
||||
.map(({ name }) => name);
|
||||
.filter(metatype => !!metatype)
|
||||
.map(({ name }) => name)
|
||||
.toArray();
|
||||
|
||||
if (!importsNames.includes(token as any)) {
|
||||
if (!importsNames.includes(token as string)) {
|
||||
const { name } = this.metatype;
|
||||
throw new UnknownExportException(token as any, name);
|
||||
throw new UnknownExportException(token, name);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
@@ -482,7 +479,7 @@ export class Module {
|
||||
return [...this._providers].filter(([_, wrapper]) => !wrapper.isAlias);
|
||||
}
|
||||
|
||||
public createModuleReferenceType(): any {
|
||||
public createModuleReferenceType(): Type<ModuleRef> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const self = this;
|
||||
return class extends ModuleRef {
|
||||
@@ -494,10 +491,9 @@ export class Module {
|
||||
typeOrToken: Type<TInput> | string | symbol,
|
||||
options: { strict: boolean } = { strict: true },
|
||||
): TResult {
|
||||
if (!(options && options.strict)) {
|
||||
return this.find<TInput, TResult>(typeOrToken);
|
||||
}
|
||||
return this.findInstanceByToken<TInput, TResult>(typeOrToken, self);
|
||||
return !(options && options.strict)
|
||||
? this.find<TInput, TResult>(typeOrToken)
|
||||
: this.find<TInput, TResult>(typeOrToken, self);
|
||||
}
|
||||
|
||||
public resolve<TInput = any, TResult = TInput>(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INTERCEPTORS_METADATA } from '@nestjs/common/constants';
|
||||
import { Controller, NestInterceptor } from '@nestjs/common/interfaces';
|
||||
import { isEmpty, isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { iterate } from 'iterare';
|
||||
import { ApplicationConfig } from '../application-config';
|
||||
import { ContextCreator } from '../helpers/context-creator';
|
||||
import { STATIC_CONTEXT } from '../injector/constants';
|
||||
@@ -104,10 +104,11 @@ export class InterceptorsContextCreator extends ContextCreator {
|
||||
return globalInterceptors;
|
||||
}
|
||||
const scopedInterceptorWrappers = this.config.getGlobalRequestInterceptors() as InstanceWrapper[];
|
||||
const scopedInterceptors = scopedInterceptorWrappers
|
||||
const scopedInterceptors = iterate(scopedInterceptorWrappers)
|
||||
.map(wrapper => wrapper.getInstanceByContextId(contextId, inquirerId))
|
||||
.filter(host => host)
|
||||
.map(host => host.instance);
|
||||
.filter(host => !!host)
|
||||
.map(host => host.instance)
|
||||
.toArray();
|
||||
|
||||
return globalInterceptors.concat(scopedInterceptors) as T;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
isFunction,
|
||||
isNil,
|
||||
} from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { iterate } from 'iterare';
|
||||
|
||||
export class MetadataScanner {
|
||||
public scanFromPrototype<T extends Injectable, R = any>(
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { MiddlewareConfiguration } from '@nestjs/common/interfaces/middleware/middleware-configuration.interface';
|
||||
import { RoutesMapper } from './routes-mapper';
|
||||
import { filterMiddleware } from './utils';
|
||||
import { iterate } from 'iterare';
|
||||
|
||||
export class MiddlewareBuilder implements MiddlewareConsumer {
|
||||
private readonly middlewareCollection = new Set<MiddlewareConfiguration>();
|
||||
@@ -49,21 +50,16 @@ export class MiddlewareBuilder implements MiddlewareConsumer {
|
||||
public exclude(
|
||||
...routes: Array<string | RouteInfo>
|
||||
): MiddlewareConfigProxy {
|
||||
const { routesMapper } = this.builder;
|
||||
this.excludedRoutes = this.mapRoutesToFlatList(
|
||||
routes.map(route => routesMapper.mapRouteToRouteInfo(route)),
|
||||
);
|
||||
this.excludedRoutes = this.getRoutesFlatList(routes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public forRoutes(
|
||||
...routes: Array<string | Type<any> | RouteInfo>
|
||||
): MiddlewareConsumer {
|
||||
const { middlewareCollection, routesMapper } = this.builder;
|
||||
const { middlewareCollection } = this.builder;
|
||||
|
||||
const forRoutes = this.mapRoutesToFlatList(
|
||||
routes.map(route => routesMapper.mapRouteToRouteInfo(route)),
|
||||
);
|
||||
const forRoutes = this.getRoutesFlatList(routes);
|
||||
const configuration = {
|
||||
middleware: filterMiddleware(
|
||||
this.middleware,
|
||||
@@ -76,8 +72,15 @@ export class MiddlewareBuilder implements MiddlewareConsumer {
|
||||
return this.builder;
|
||||
}
|
||||
|
||||
private mapRoutesToFlatList(forRoutes: RouteInfo[][]): RouteInfo[] {
|
||||
return forRoutes.reduce((a, b) => a.concat(b));
|
||||
private getRoutesFlatList(
|
||||
routes: Array<string | Type<any> | RouteInfo>,
|
||||
): RouteInfo[] {
|
||||
const { routesMapper } = this.builder;
|
||||
|
||||
return iterate(routes)
|
||||
.map(route => routesMapper.mapRouteToRouteInfo(route))
|
||||
.flatten()
|
||||
.toArray();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { HttpServer, RouteInfo, Type } from '@nestjs/common/interfaces';
|
||||
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import * as pathToRegexp from 'path-to-regexp';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { iterate } from 'iterare';
|
||||
|
||||
type RouteInfoRegex = RouteInfo & { regex: RegExp };
|
||||
|
||||
@@ -16,10 +17,11 @@ export const filterMiddleware = <T extends Function | Type<any> = any>(
|
||||
...route,
|
||||
regex: pathToRegexp(route.path),
|
||||
}));
|
||||
return []
|
||||
return iterate([])
|
||||
.concat(middleware)
|
||||
.filter(isFunction)
|
||||
.map((item: T) => mapToClass(item, excluded, httpAdapter));
|
||||
.map((item: T) => mapToClass(item, excluded, httpAdapter))
|
||||
.toArray();
|
||||
};
|
||||
|
||||
export const mapToClass = <T extends Function | Type<any>>(
|
||||
|
||||
@@ -4,10 +4,12 @@ import {
|
||||
LoggerService,
|
||||
ShutdownSignal,
|
||||
} from '@nestjs/common';
|
||||
import { Abstract } from '@nestjs/common/interfaces';
|
||||
import { Abstract, Scope } from '@nestjs/common/interfaces';
|
||||
import { Type } from '@nestjs/common/interfaces/type.interface';
|
||||
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
||||
import { iterate } from 'iterare';
|
||||
import { MESSAGES } from './constants';
|
||||
import { InvalidClassScopeException } from './errors/exceptions/invalid-class-scope.exception';
|
||||
import { UnknownElementException } from './errors/exceptions/unknown-element.exception';
|
||||
import { UnknownModuleException } from './errors/exceptions/unknown-module.exception';
|
||||
import { createContextId } from './helpers';
|
||||
@@ -20,9 +22,8 @@ import {
|
||||
} from './hooks';
|
||||
import { ContextId } from './injector';
|
||||
import { NestContainer } from './injector/container';
|
||||
import { ContainerScanner } from './injector/container-scanner';
|
||||
import { Injector } from './injector/injector';
|
||||
import { InstanceWrapper } from './injector/instance-wrapper';
|
||||
import { InstanceLinksHost } from './injector/instance-links-host';
|
||||
import { Module } from './injector/module';
|
||||
|
||||
/**
|
||||
@@ -33,15 +34,20 @@ export class NestApplicationContext implements INestApplicationContext {
|
||||
protected readonly injector = new Injector();
|
||||
private shutdownCleanupRef?: (...args: unknown[]) => unknown;
|
||||
private readonly activeShutdownSignals = new Array<string>();
|
||||
private readonly containerScanner: ContainerScanner;
|
||||
private _instanceLinksHost: InstanceLinksHost;
|
||||
|
||||
private get instanceLinksHost() {
|
||||
if (!this._instanceLinksHost) {
|
||||
this._instanceLinksHost = new InstanceLinksHost(this.container);
|
||||
}
|
||||
return this._instanceLinksHost;
|
||||
}
|
||||
|
||||
constructor(
|
||||
protected readonly container: NestContainer,
|
||||
private readonly scope = new Array<Type<any>>(),
|
||||
private contextModule: Module = null,
|
||||
) {
|
||||
this.containerScanner = new ContainerScanner(container);
|
||||
}
|
||||
) {}
|
||||
|
||||
public selectContextModule() {
|
||||
const modules = this.container.getModules().values();
|
||||
@@ -66,13 +72,9 @@ export class NestApplicationContext implements INestApplicationContext {
|
||||
typeOrToken: Type<TInput> | Abstract<TInput> | string | symbol,
|
||||
options: { strict: boolean } = { strict: false },
|
||||
): TResult {
|
||||
if (!(options && options.strict)) {
|
||||
return this.find<TInput, TResult>(typeOrToken);
|
||||
}
|
||||
return this.findInstanceByToken<TInput, TResult>(
|
||||
typeOrToken,
|
||||
this.contextModule,
|
||||
);
|
||||
return !(options && options.strict)
|
||||
? this.find<TInput, TResult>(typeOrToken)
|
||||
: this.find<TInput, TResult>(typeOrToken, this.contextModule);
|
||||
}
|
||||
|
||||
public resolve<TInput = any, TResult = TInput>(
|
||||
@@ -88,6 +90,10 @@ export class NestApplicationContext implements INestApplicationContext {
|
||||
);
|
||||
}
|
||||
|
||||
public registerRequestByContextId<T = any>(request: T, contextId: ContextId) {
|
||||
this.container.registerRequestProvider(request, contextId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initalizes the Nest application.
|
||||
* Calls the Nest lifecycle events.
|
||||
@@ -110,7 +116,7 @@ export class NestApplicationContext implements INestApplicationContext {
|
||||
await this.callBeforeShutdownHook();
|
||||
await this.dispose();
|
||||
await this.callShutdownHook();
|
||||
await this.unsubscribeFromProcessSignals();
|
||||
this.unsubscribeFromProcessSignals();
|
||||
}
|
||||
|
||||
public useLogger(logger: LoggerService) {
|
||||
@@ -137,10 +143,11 @@ export class NestApplicationContext implements INestApplicationContext {
|
||||
signals = Array.from(new Set(signals));
|
||||
}
|
||||
|
||||
signals = signals
|
||||
signals = iterate(signals)
|
||||
.map((signal: string) => signal.toString().toUpperCase().trim())
|
||||
// filter out the signals which is already listening to
|
||||
.filter(signal => !this.activeShutdownSignals.includes(signal));
|
||||
.filter(signal => !this.activeShutdownSignals.includes(signal))
|
||||
.toArray();
|
||||
|
||||
this.listenToShutdownSignals(signals);
|
||||
return this;
|
||||
@@ -253,18 +260,20 @@ export class NestApplicationContext implements INestApplicationContext {
|
||||
|
||||
protected find<TInput = any, TResult = TInput>(
|
||||
typeOrToken: Type<TInput> | Abstract<TInput> | string | symbol,
|
||||
contextModule?: Module,
|
||||
): TResult {
|
||||
return this.containerScanner.find<TInput, TResult>(typeOrToken);
|
||||
}
|
||||
|
||||
protected findInstanceByToken<TInput = any, TResult = TInput>(
|
||||
metatypeOrToken: Type<TInput> | Abstract<TInput> | string | symbol,
|
||||
contextModule: Partial<Module>,
|
||||
): TResult {
|
||||
return this.containerScanner.findInstanceByToken<TInput, TResult>(
|
||||
metatypeOrToken,
|
||||
contextModule,
|
||||
const moduleId = contextModule && contextModule.id;
|
||||
const { wrapperRef } = this.instanceLinksHost.get<TResult>(
|
||||
typeOrToken,
|
||||
moduleId,
|
||||
);
|
||||
if (
|
||||
wrapperRef.scope === Scope.REQUEST ||
|
||||
wrapperRef.scope === Scope.TRANSIENT
|
||||
) {
|
||||
throw new InvalidClassScopeException(typeOrToken);
|
||||
}
|
||||
return wrapperRef.instance;
|
||||
}
|
||||
|
||||
protected async resolvePerContext<TInput = any, TResult = TInput>(
|
||||
@@ -273,23 +282,20 @@ export class NestApplicationContext implements INestApplicationContext {
|
||||
contextId: ContextId,
|
||||
options?: { strict: boolean },
|
||||
): Promise<TResult> {
|
||||
let wrapper: InstanceWrapper, collection: Map<string, InstanceWrapper>;
|
||||
if (!(options && options.strict)) {
|
||||
[wrapper, collection] = this.containerScanner.getWrapperCollectionPair(
|
||||
typeOrToken,
|
||||
);
|
||||
} else {
|
||||
[
|
||||
wrapper,
|
||||
collection,
|
||||
] = this.containerScanner.getWrapperCollectionPairByHost(
|
||||
typeOrToken,
|
||||
contextModule,
|
||||
);
|
||||
const isStrictModeEnabled = options && options.strict;
|
||||
const instanceLink = isStrictModeEnabled
|
||||
? this.instanceLinksHost.get(typeOrToken, contextModule.id)
|
||||
: this.instanceLinksHost.get(typeOrToken);
|
||||
|
||||
const { wrapperRef, collection } = instanceLink;
|
||||
if (wrapperRef.isDependencyTreeStatic() && !wrapperRef.isTransient) {
|
||||
return this.get(typeOrToken);
|
||||
}
|
||||
|
||||
const ctorHost = wrapperRef.instance || { constructor: typeOrToken };
|
||||
const instance = await this.injector.loadPerContext(
|
||||
wrapper.instance,
|
||||
wrapper.host,
|
||||
ctorHost,
|
||||
wrapperRef.host,
|
||||
collection,
|
||||
contextId,
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
HttpServer,
|
||||
INestApplication,
|
||||
INestMicroservice,
|
||||
NestHybridApplicationOptions,
|
||||
NestInterceptor,
|
||||
PipeTransform,
|
||||
WebSocketAdapter,
|
||||
@@ -13,7 +14,7 @@ import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-applicati
|
||||
import { Logger } from '@nestjs/common/services/logger.service';
|
||||
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
||||
import { isObject, validatePath } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { iterate } from 'iterare';
|
||||
import { platform } from 'os';
|
||||
import { AbstractHttpAdapter } from './adapters';
|
||||
import { ApplicationConfig } from './application-config';
|
||||
@@ -170,17 +171,23 @@ export class NestApplication extends NestApplicationContext
|
||||
this.routesResolver.registerExceptionHandler();
|
||||
}
|
||||
|
||||
public connectMicroservice<T extends object>(options: T): INestMicroservice {
|
||||
public connectMicroservice<T extends object>(
|
||||
microserviceOptions: T,
|
||||
hybridAppOptions: NestHybridApplicationOptions = {},
|
||||
): INestMicroservice {
|
||||
const { NestMicroservice } = loadPackage(
|
||||
'@nestjs/microservices',
|
||||
'NestFactory',
|
||||
() => require('@nestjs/microservices'),
|
||||
);
|
||||
const { inheritAppConfig } = hybridAppOptions;
|
||||
const applicationConfig = inheritAppConfig
|
||||
? this.config
|
||||
: new ApplicationConfig();
|
||||
|
||||
const applicationConfig = new ApplicationConfig();
|
||||
const instance = new NestMicroservice(
|
||||
this.container,
|
||||
options,
|
||||
microserviceOptions,
|
||||
applicationConfig,
|
||||
);
|
||||
instance.registerListeners();
|
||||
|
||||
@@ -190,7 +190,7 @@ export class NestFactoryStatic {
|
||||
prop: string,
|
||||
): Function {
|
||||
return (...args: unknown[]) => {
|
||||
let result;
|
||||
let result: unknown;
|
||||
ExceptionsZone.run(() => {
|
||||
result = receiver[prop](...args);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/core",
|
||||
"version": "7.0.5",
|
||||
"version": "7.3.0",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@core)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -29,11 +29,14 @@
|
||||
"dependencies": {
|
||||
"@nuxtjs/opencollective": "0.2.2",
|
||||
"fast-safe-stringify": "2.0.7",
|
||||
"iterare": "1.2.0",
|
||||
"iterare": "1.2.1",
|
||||
"object-hash": "2.0.3",
|
||||
"path-to-regexp": "3.2.0",
|
||||
"tslib": "1.11.1",
|
||||
"uuid": "7.0.2"
|
||||
"tslib": "2.0.0",
|
||||
"uuid": "8.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "7.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^7.0.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { PIPES_METADATA } from '@nestjs/common/constants';
|
||||
import { Controller, PipeTransform } from '@nestjs/common/interfaces';
|
||||
import { isEmpty, isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import iterate from 'iterare';
|
||||
import { iterate } from 'iterare';
|
||||
import { ApplicationConfig } from '../application-config';
|
||||
import { ContextCreator } from '../helpers/context-creator';
|
||||
import { STATIC_CONTEXT } from '../injector/constants';
|
||||
@@ -96,10 +96,11 @@ export class PipesContextCreator extends ContextCreator {
|
||||
return globalPipes;
|
||||
}
|
||||
const scopedPipeWrappers = this.config.getGlobalRequestPipes() as InstanceWrapper[];
|
||||
const scopedPipes = scopedPipeWrappers
|
||||
const scopedPipes = iterate(scopedPipeWrappers)
|
||||
.map(wrapper => wrapper.getInstanceByContextId(contextId, inquirerId))
|
||||
.filter(host => host)
|
||||
.map(host => host.instance);
|
||||
.filter(host => !!host)
|
||||
.map(host => host.instance)
|
||||
.toArray();
|
||||
|
||||
return globalPipes.concat(scopedPipes) as T;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { STATIC_CONTEXT } from '../injector/constants';
|
||||
import { NestContainer } from '../injector/container';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { RouterProxyCallback } from './router-proxy';
|
||||
import { iterate } from 'iterare';
|
||||
|
||||
export class RouterExceptionFilters extends BaseExceptionFilterContext {
|
||||
constructor(
|
||||
@@ -52,10 +53,11 @@ export class RouterExceptionFilters extends BaseExceptionFilterContext {
|
||||
return globalFilters;
|
||||
}
|
||||
const scopedFilterWrappers = this.config.getGlobalRequestFilters() as InstanceWrapper[];
|
||||
const scopedFilters = scopedFilterWrappers
|
||||
const scopedFilters = iterate(scopedFilterWrappers)
|
||||
.map(wrapper => wrapper.getInstanceByContextId(contextId, inquirerId))
|
||||
.filter(host => host)
|
||||
.map(host => host.instance);
|
||||
.filter(host => !!host)
|
||||
.map(host => host.instance)
|
||||
.toArray();
|
||||
|
||||
return globalFilters.concat(scopedFilters) as T;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
isNil,
|
||||
isUndefined,
|
||||
} from '@nestjs/common/utils/shared.utils';
|
||||
import { iterate } from 'iterare';
|
||||
import { ApplicationConfig } from './application-config';
|
||||
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from './constants';
|
||||
import { CircularDependencyException } from './errors/exceptions/circular-dependency.exception';
|
||||
@@ -42,6 +43,8 @@ import { NestContainer } from './injector/container';
|
||||
import { InstanceWrapper } from './injector/instance-wrapper';
|
||||
import { Module } from './injector/module';
|
||||
import { MetadataScanner } from './metadata-scanner';
|
||||
import { InvalidModuleException } from './errors/exceptions/invalid-module.exception';
|
||||
import { UndefinedModuleException } from './errors/exceptions/undefined-module.exception';
|
||||
|
||||
interface ApplicationProviderWrapper {
|
||||
moduleKey: string;
|
||||
@@ -89,7 +92,14 @@ export class DependenciesScanner {
|
||||
...((module as DynamicModule).imports || []),
|
||||
];
|
||||
|
||||
for (const innerModule of modules) {
|
||||
for (const [index, innerModule] of modules.entries()) {
|
||||
// In case of a circular dependency (ES module system), JavaScript will resolve the type to `undefined`.
|
||||
if (innerModule === undefined) {
|
||||
throw new UndefinedModuleException(module, index, scope);
|
||||
}
|
||||
if (!innerModule) {
|
||||
throw new InvalidModuleException(module, index, scope);
|
||||
}
|
||||
if (ctxRegistry.includes(innerModule)) {
|
||||
continue;
|
||||
}
|
||||
@@ -259,7 +269,7 @@ export class DependenciesScanner {
|
||||
|
||||
public async calculateModulesDistance(modules: ModulesContainer) {
|
||||
const modulesGenerator = modules.values();
|
||||
const rootModule = modulesGenerator.next().value;
|
||||
const rootModule = modulesGenerator.next().value as Module;
|
||||
const modulesStack = [rootModule];
|
||||
|
||||
const calculateDistance = (moduleRef: Module, distance = 1) => {
|
||||
@@ -378,24 +388,20 @@ export class DependenciesScanner {
|
||||
* to all controllers metadata storage
|
||||
*/
|
||||
public addScopedEnhancersMetadata() {
|
||||
const scopedGlobalProviders = this.applicationProvidersApplyMap.filter(
|
||||
wrapper => this.isRequestOrTransient(wrapper.scope),
|
||||
);
|
||||
iterate(this.applicationProvidersApplyMap)
|
||||
.filter(wrapper => this.isRequestOrTransient(wrapper.scope))
|
||||
.forEach(({ moduleKey, providerKey }) => {
|
||||
const modulesContainer = this.container.getModules();
|
||||
const { injectables } = modulesContainer.get(moduleKey);
|
||||
const instanceWrapper = injectables.get(providerKey);
|
||||
|
||||
scopedGlobalProviders.forEach(({ moduleKey, providerKey }) => {
|
||||
const modulesContainer = this.container.getModules();
|
||||
const { injectables } = modulesContainer.get(moduleKey);
|
||||
const instanceWrapper = injectables.get(providerKey);
|
||||
|
||||
const modules = [...modulesContainer.values()];
|
||||
const controllersArray = modules.map(module => [
|
||||
...module.controllers.values(),
|
||||
]);
|
||||
const controllers = this.flatten(controllersArray);
|
||||
controllers.forEach(controller =>
|
||||
controller.addEnhancerMetadata(instanceWrapper),
|
||||
);
|
||||
});
|
||||
iterate(modulesContainer.values())
|
||||
.map(module => module.controllers.values())
|
||||
.flatten()
|
||||
.forEach(controller =>
|
||||
controller.addEnhancerMetadata(instanceWrapper),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public applyApplicationProviders() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@nestjs/common';
|
||||
import { isObject } from '@nestjs/common/utils/shared.utils';
|
||||
import { isEmpty, isObject } from '@nestjs/common/utils/shared.utils';
|
||||
|
||||
/**
|
||||
* Helper class providing Nest reflection capabilities.
|
||||
@@ -53,7 +53,14 @@ export class Reflector {
|
||||
metadataKey: TKey,
|
||||
targets: (Type<any> | Function)[],
|
||||
): TResult {
|
||||
const metadataCollection = this.getAll(metadataKey, targets);
|
||||
const metadataCollection = this.getAll<TResult, TKey>(
|
||||
metadataKey,
|
||||
targets,
|
||||
).filter(item => item !== undefined);
|
||||
|
||||
if (isEmpty(metadataCollection)) {
|
||||
return metadataCollection as TResult;
|
||||
}
|
||||
return metadataCollection.reduce((a, b) => {
|
||||
if (Array.isArray(a)) {
|
||||
return a.concat(b);
|
||||
|
||||
@@ -2,161 +2,204 @@ import { expect } from 'chai';
|
||||
import { UnknownDependenciesException } from '../../../errors/exceptions/unknown-dependencies.exception';
|
||||
import { Module } from '../../../injector/module';
|
||||
import { stringCleaner } from '../../utils/string.cleaner';
|
||||
import {
|
||||
UNDEFINED_MODULE_MESSAGE,
|
||||
INVALID_MODULE_MESSAGE,
|
||||
} from '../../../errors/messages';
|
||||
|
||||
describe('UnknownDependenciesMessage', () => {
|
||||
const index = 0;
|
||||
it('should display class', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, CatService). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
describe('Error Messages', () => {
|
||||
const CatsModule = { name: 'CatsModule' };
|
||||
const AppModule = { name: 'AppModule' };
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
describe('UNKNOWN_DEPENDENCIES_MESSAGE', () => {
|
||||
const index = 0;
|
||||
it('should display class', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, CatService). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
|
||||
class CatService {}
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatService', {
|
||||
index,
|
||||
dependencies: ['', CatService],
|
||||
}).message,
|
||||
);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should display the provide token', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, MY_TOKEN). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
})
|
||||
`);
|
||||
|
||||
class CatService {}
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatService', {
|
||||
index,
|
||||
dependencies: ['', 'MY_TOKEN'],
|
||||
}).message,
|
||||
);
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatService', {
|
||||
index,
|
||||
dependencies: ['', CatService],
|
||||
}).message,
|
||||
);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should display the provide token', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, MY_TOKEN). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatService', {
|
||||
index,
|
||||
dependencies: ['', 'MY_TOKEN'],
|
||||
}).message,
|
||||
);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should display the function name', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, CatFunction). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
|
||||
function CatFunction() {}
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatService', {
|
||||
index,
|
||||
dependencies: ['', CatFunction],
|
||||
}).message,
|
||||
);
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should use "+" if unknown dependency name', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, +). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should display the function name', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, CatFunction). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
`);
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatService', {
|
||||
index,
|
||||
dependencies: ['', undefined],
|
||||
}).message,
|
||||
);
|
||||
function CatFunction() {}
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatService', {
|
||||
index,
|
||||
dependencies: ['', CatFunction],
|
||||
}).message,
|
||||
);
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should use "+" if unknown dependency name', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, +). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatService', {
|
||||
index,
|
||||
dependencies: ['', undefined],
|
||||
}).message,
|
||||
);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should display the module name', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, MY_TOKEN). Please make sure that the argument dependency at index [0] is available in the TestModule context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current TestModule?
|
||||
- If dependency is exported from a separate @Module, is that module imported within TestModule?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
|
||||
class MetaType {
|
||||
name: string;
|
||||
}
|
||||
class TestModule {
|
||||
metatype: MetaType;
|
||||
}
|
||||
const myModule = new TestModule();
|
||||
const myMetaType = new MetaType();
|
||||
myMetaType.name = 'TestModule';
|
||||
myModule.metatype = myMetaType;
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException(
|
||||
'CatService',
|
||||
{ index, dependencies: ['', 'MY_TOKEN'] },
|
||||
myModule as Module,
|
||||
).message,
|
||||
);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should display the symbol name of the provider', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the Symbol(CatProvider) (?). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException(Symbol('CatProvider'), {
|
||||
index,
|
||||
dependencies: [''],
|
||||
}).message,
|
||||
);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should display the symbol dependency of the provider', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatProvider (?, Symbol(DogProvider)). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatProvider', {
|
||||
index,
|
||||
dependencies: ['', Symbol('DogProvider')],
|
||||
}).message,
|
||||
);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
});
|
||||
it('should display the module name', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatService (?, MY_TOKEN). Please make sure that the argument dependency at index [0] is available in the TestModule context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current TestModule?
|
||||
- If dependency is exported from a separate @Module, is that module imported within TestModule?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
describe('UNDEFINED_MODULE_EXCEPTION', () => {
|
||||
it('should display the module name with the undefined index and scope', () => {
|
||||
const expectedMessage = stringCleaner(`Nest cannot create the CatsModule instance.
|
||||
The module at index [0] of the CatsModule "imports" array is undefined.
|
||||
|
||||
class MetaType {
|
||||
name: string;
|
||||
}
|
||||
class TestModule {
|
||||
metatype: MetaType;
|
||||
}
|
||||
const myModule = new TestModule();
|
||||
const myMetaType = new MetaType();
|
||||
myMetaType.name = 'TestModule';
|
||||
myModule.metatype = myMetaType;
|
||||
Potential causes:
|
||||
- A circular dependency between modules. Use forwardRef() to avoid it. Read more: https://docs.nestjs.com/fundamentals/circular-dependency
|
||||
- The module at index [0] is of type "undefined". Check your import statements and the type of the module.
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException(
|
||||
'CatService',
|
||||
{ index, dependencies: ['', 'MY_TOKEN'] },
|
||||
myModule as Module,
|
||||
).message,
|
||||
);
|
||||
Scope [AppModule -> CatsModule]`);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
const actualMessage = stringCleaner(
|
||||
UNDEFINED_MODULE_MESSAGE(CatsModule, 0, [AppModule, CatsModule]),
|
||||
);
|
||||
|
||||
expect(actualMessage).to.be.eq(expectedMessage);
|
||||
});
|
||||
});
|
||||
it('should display the symbol name of the provider', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the Symbol(CatProvider) (?). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
describe('INVALID_MODULE_MESSAGE', () => {
|
||||
it('should display the module name with the invalid index and scope', () => {
|
||||
const expectedMessage = stringCleaner(`Nest cannot create the CatsModule instance.
|
||||
Received an unexpected value at index [0] of the CatsModule "imports" array.
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException(Symbol('CatProvider'), {
|
||||
index,
|
||||
dependencies: [''],
|
||||
}).message,
|
||||
);
|
||||
Scope [AppModule -> CatsModule]`);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
});
|
||||
it('should display the symbol dependency of the provider', () => {
|
||||
const expectedResult = stringCleaner(`Nest can't resolve dependencies of the CatProvider (?, Symbol(DogProvider)). Please make sure that the argument dependency at index [0] is available in the current context.
|
||||
const actualMessage = stringCleaner(
|
||||
INVALID_MODULE_MESSAGE(CatsModule, 0, [AppModule, CatsModule]),
|
||||
);
|
||||
|
||||
Potential solutions:
|
||||
- If dependency is a provider, is it part of the current current?
|
||||
- If dependency is exported from a separate @Module, is that module imported within current?
|
||||
@Module({
|
||||
imports: [ /* the Module containing dependency */ ]
|
||||
})
|
||||
`);
|
||||
|
||||
const actualMessage = stringCleaner(
|
||||
new UnknownDependenciesException('CatProvider', {
|
||||
index,
|
||||
dependencies: ['', Symbol('DogProvider')],
|
||||
}).message,
|
||||
);
|
||||
|
||||
expect(actualMessage).to.equal(expectedResult);
|
||||
expect(actualMessage).to.be.eq(expectedMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
49
packages/core/test/hooks/before-app-shutdown.hook.spec.ts
Normal file
49
packages/core/test/hooks/before-app-shutdown.hook.spec.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { BeforeApplicationShutdown } from '@nestjs/common';
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import { callBeforeAppShutdownHook } from '../../hooks/before-app-shutdown.hook';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
import { Module } from '../../injector/module';
|
||||
|
||||
class SampleProvider implements BeforeApplicationShutdown {
|
||||
beforeApplicationShutdown(signal?: string) {}
|
||||
}
|
||||
|
||||
class SampleModule implements BeforeApplicationShutdown {
|
||||
beforeApplicationShutdown(signal?: string) {}
|
||||
}
|
||||
|
||||
class WithoutHookProvider {}
|
||||
|
||||
describe('BeforeAppShutdown', () => {
|
||||
let moduleRef: Module;
|
||||
let sampleProvider: SampleProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
sampleProvider = new SampleProvider();
|
||||
moduleRef = new Module(SampleModule, new NestContainer());
|
||||
|
||||
const moduleWrapperRef = moduleRef.getProviderByKey(SampleModule.name);
|
||||
moduleWrapperRef.instance = new SampleModule();
|
||||
|
||||
moduleRef.addProvider({
|
||||
provide: SampleProvider,
|
||||
useValue: sampleProvider,
|
||||
});
|
||||
moduleRef.addProvider({
|
||||
provide: WithoutHookProvider,
|
||||
useValue: new WithoutHookProvider(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('callBeforeAppShutdownHook', () => {
|
||||
it('should call "beforeApplicationShutdown" hook for the entire module', async () => {
|
||||
const signal = 'SIGTERM';
|
||||
|
||||
const hookSpy = sinon.spy(sampleProvider, 'beforeApplicationShutdown');
|
||||
await callBeforeAppShutdownHook(moduleRef, signal);
|
||||
|
||||
expect(hookSpy.calledWith(signal)).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
47
packages/core/test/hooks/on-app-bootstrap.hook.spec.ts
Normal file
47
packages/core/test/hooks/on-app-bootstrap.hook.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { OnApplicationBootstrap } from '@nestjs/common';
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import { callModuleBootstrapHook } from '../../hooks/on-app-bootstrap.hook';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
import { Module } from '../../injector/module';
|
||||
|
||||
class SampleProvider implements OnApplicationBootstrap {
|
||||
onApplicationBootstrap() {}
|
||||
}
|
||||
|
||||
class SampleModule implements OnApplicationBootstrap {
|
||||
onApplicationBootstrap() {}
|
||||
}
|
||||
|
||||
class WithoutHookProvider {}
|
||||
|
||||
describe('OnApplicationBootstrap', () => {
|
||||
let moduleRef: Module;
|
||||
let sampleProvider: SampleProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
sampleProvider = new SampleProvider();
|
||||
moduleRef = new Module(SampleModule, new NestContainer());
|
||||
|
||||
const moduleWrapperRef = moduleRef.getProviderByKey(SampleModule.name);
|
||||
moduleWrapperRef.instance = new SampleModule();
|
||||
|
||||
moduleRef.addProvider({
|
||||
provide: SampleProvider,
|
||||
useValue: sampleProvider,
|
||||
});
|
||||
moduleRef.addProvider({
|
||||
provide: WithoutHookProvider,
|
||||
useValue: new WithoutHookProvider(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('callModuleBootstrapHook', () => {
|
||||
it('should call "onApplicationBootstrap" hook for the entire module', async () => {
|
||||
const hookSpy = sinon.spy(sampleProvider, 'onApplicationBootstrap');
|
||||
await callModuleBootstrapHook(moduleRef);
|
||||
|
||||
expect(hookSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
47
packages/core/test/hooks/on-app-shutdown.hook.spec.ts
Normal file
47
packages/core/test/hooks/on-app-shutdown.hook.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { OnApplicationShutdown } from '@nestjs/common';
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import { callAppShutdownHook } from '../../hooks/on-app-shutdown.hook';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
import { Module } from '../../injector/module';
|
||||
|
||||
class SampleProvider implements OnApplicationShutdown {
|
||||
onApplicationShutdown() {}
|
||||
}
|
||||
|
||||
class SampleModule implements OnApplicationShutdown {
|
||||
onApplicationShutdown() {}
|
||||
}
|
||||
|
||||
class WithoutHookProvider {}
|
||||
|
||||
describe('OnApplicationShutdown', () => {
|
||||
let moduleRef: Module;
|
||||
let sampleProvider: SampleProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
sampleProvider = new SampleProvider();
|
||||
moduleRef = new Module(SampleModule, new NestContainer());
|
||||
|
||||
const moduleWrapperRef = moduleRef.getProviderByKey(SampleModule.name);
|
||||
moduleWrapperRef.instance = new SampleModule();
|
||||
|
||||
moduleRef.addProvider({
|
||||
provide: SampleProvider,
|
||||
useValue: sampleProvider,
|
||||
});
|
||||
moduleRef.addProvider({
|
||||
provide: WithoutHookProvider,
|
||||
useValue: new WithoutHookProvider(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('callAppShutdownHook', () => {
|
||||
it('should call "onApplicationShutdown" hook for the entire module', async () => {
|
||||
const hookSpy = sinon.spy(sampleProvider, 'onApplicationShutdown');
|
||||
await callAppShutdownHook(moduleRef);
|
||||
|
||||
expect(hookSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
47
packages/core/test/hooks/on-module-destroy.hook.spec.ts
Normal file
47
packages/core/test/hooks/on-module-destroy.hook.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { OnModuleDestroy } from '@nestjs/common';
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import { callModuleDestroyHook } from '../../hooks/on-module-destroy.hook';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
import { Module } from '../../injector/module';
|
||||
|
||||
class SampleProvider implements OnModuleDestroy {
|
||||
onModuleDestroy() {}
|
||||
}
|
||||
|
||||
class SampleModule implements OnModuleDestroy {
|
||||
onModuleDestroy() {}
|
||||
}
|
||||
|
||||
class WithoutHookProvider {}
|
||||
|
||||
describe('OnModuleDestroy', () => {
|
||||
let moduleRef: Module;
|
||||
let sampleProvider: SampleProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
sampleProvider = new SampleProvider();
|
||||
moduleRef = new Module(SampleModule, new NestContainer());
|
||||
|
||||
const moduleWrapperRef = moduleRef.getProviderByKey(SampleModule.name);
|
||||
moduleWrapperRef.instance = new SampleModule();
|
||||
|
||||
moduleRef.addProvider({
|
||||
provide: SampleProvider,
|
||||
useValue: sampleProvider,
|
||||
});
|
||||
moduleRef.addProvider({
|
||||
provide: WithoutHookProvider,
|
||||
useValue: new WithoutHookProvider(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('callModuleDestroyHook', () => {
|
||||
it('should call "onModuleDestroy" hook for the entire module', async () => {
|
||||
const hookSpy = sinon.spy(sampleProvider, 'onModuleDestroy');
|
||||
await callModuleDestroyHook(moduleRef);
|
||||
|
||||
expect(hookSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
47
packages/core/test/hooks/on-module-init.hook.spec.ts
Normal file
47
packages/core/test/hooks/on-module-init.hook.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { OnModuleInit } from '@nestjs/common';
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import { callModuleInitHook } from '../../hooks/on-module-init.hook';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
import { Module } from '../../injector/module';
|
||||
|
||||
class SampleProvider implements OnModuleInit {
|
||||
onModuleInit() {}
|
||||
}
|
||||
|
||||
class SampleModule implements OnModuleInit {
|
||||
onModuleInit() {}
|
||||
}
|
||||
|
||||
class WithoutHookProvider {}
|
||||
|
||||
describe('OnModuleInit', () => {
|
||||
let moduleRef: Module;
|
||||
let sampleProvider: SampleProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
sampleProvider = new SampleProvider();
|
||||
moduleRef = new Module(SampleModule, new NestContainer());
|
||||
|
||||
const moduleWrapperRef = moduleRef.getProviderByKey(SampleModule.name);
|
||||
moduleWrapperRef.instance = new SampleModule();
|
||||
|
||||
moduleRef.addProvider({
|
||||
provide: SampleProvider,
|
||||
useValue: sampleProvider,
|
||||
});
|
||||
moduleRef.addProvider({
|
||||
provide: WithoutHookProvider,
|
||||
useValue: new WithoutHookProvider(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('callModuleInitHook', () => {
|
||||
it('should call "onModuleInit" hook for the entire module', async () => {
|
||||
const hookSpy = sinon.spy(sampleProvider, 'onModuleInit');
|
||||
await callModuleInitHook(moduleRef);
|
||||
|
||||
expect(hookSpy.called).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -36,7 +36,7 @@ describe('Injector', () => {
|
||||
let mainTest, depOne, depTwo;
|
||||
|
||||
beforeEach(() => {
|
||||
moduleDeps = new Module(DependencyTwo as any, [], new NestContainer());
|
||||
moduleDeps = new Module(DependencyTwo, new NestContainer());
|
||||
mainTest = new InstanceWrapper({
|
||||
name: 'MainTest',
|
||||
metatype: MainTest,
|
||||
@@ -133,7 +133,7 @@ describe('Injector', () => {
|
||||
let test;
|
||||
|
||||
beforeEach(() => {
|
||||
moduleDeps = new Module(Test as any, [], new NestContainer());
|
||||
moduleDeps = new Module(Test, new NestContainer());
|
||||
test = new InstanceWrapper({
|
||||
name: 'Test',
|
||||
metatype: Test,
|
||||
@@ -712,12 +712,12 @@ describe('Injector', () => {
|
||||
const wrapper = new InstanceWrapper();
|
||||
wrapper.addEnhancerMetadata(
|
||||
new InstanceWrapper({
|
||||
host: new Module(class {}, [], new NestContainer()),
|
||||
host: new Module(class {}, new NestContainer()),
|
||||
}),
|
||||
);
|
||||
wrapper.addEnhancerMetadata(
|
||||
new InstanceWrapper({
|
||||
host: new Module(class {}, [], new NestContainer()),
|
||||
host: new Module(class {}, new NestContainer()),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('Module', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
container = new NestContainer();
|
||||
module = new Module(TestModule as any, [], container);
|
||||
module = new Module(TestModule, container);
|
||||
});
|
||||
|
||||
it('should add controller', () => {
|
||||
@@ -418,7 +418,7 @@ describe('Module', () => {
|
||||
it('should behave as identity', () => {
|
||||
const metatype = { name: token };
|
||||
(module as any)._imports = new Set([
|
||||
new Module(metatype as any, [], new NestContainer()),
|
||||
new Module(metatype as any, new NestContainer()),
|
||||
]);
|
||||
expect(module.validateExportedProvider(token)).to.be.eql(token);
|
||||
});
|
||||
|
||||
@@ -33,8 +33,8 @@ describe('MiddlewareContainer', () => {
|
||||
const nestContainer = new NestContainer();
|
||||
const modules = nestContainer.getModules();
|
||||
|
||||
modules.set('Module', new Module(ExampleModule, [], nestContainer));
|
||||
modules.set('Test', new Module(ExampleModule, [], nestContainer));
|
||||
modules.set('Module', new Module(ExampleModule, nestContainer));
|
||||
modules.set('Test', new Module(ExampleModule, nestContainer));
|
||||
|
||||
container = new MiddlewareContainer(nestContainer);
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('MiddlewareModule', () => {
|
||||
const stubContainer = new NestContainer();
|
||||
stubContainer
|
||||
.getModules()
|
||||
.set('Test', new Module(class {}, [], stubContainer));
|
||||
.set('Test', new Module(class {}, stubContainer));
|
||||
|
||||
await middlewareModule.loadConfiguration(
|
||||
new MiddlewareContainer(stubContainer),
|
||||
@@ -87,7 +87,7 @@ describe('MiddlewareModule', () => {
|
||||
nestContainer = new NestContainer();
|
||||
nestContainer
|
||||
.getModules()
|
||||
.set('Test', new Module(TestModule, [], nestContainer));
|
||||
.set('Test', new Module(TestModule, nestContainer));
|
||||
});
|
||||
it('should throw "RuntimeException" exception when middleware is not stored in container', () => {
|
||||
const route = { path: 'Test' };
|
||||
@@ -162,7 +162,7 @@ describe('MiddlewareModule', () => {
|
||||
const stubContainer = new NestContainer();
|
||||
stubContainer
|
||||
.getModules()
|
||||
.set('Test', new Module(TestModule, [], stubContainer));
|
||||
.set('Test', new Module(TestModule, stubContainer));
|
||||
|
||||
const container = new MiddlewareContainer(stubContainer);
|
||||
const moduleKey = 'Test';
|
||||
@@ -178,7 +178,7 @@ describe('MiddlewareModule', () => {
|
||||
);
|
||||
sinon
|
||||
.stub(stubContainer, 'getModuleByKey')
|
||||
.callsFake(() => new Module(class {}, [], stubContainer));
|
||||
.callsFake(() => new Module(class {}, stubContainer));
|
||||
middlewareModule['container'] = stubContainer;
|
||||
|
||||
await middlewareModule.registerRouteMiddleware(
|
||||
|
||||
54
packages/core/test/nest-application.spec.ts
Normal file
54
packages/core/test/nest-application.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { expect } from 'chai';
|
||||
import { NestApplication } from '../nest-application';
|
||||
import { ApplicationConfig } from '../application-config';
|
||||
import { NestContainer } from '../injector';
|
||||
import { NoopHttpAdapter } from './utils/noop-adapter.spec';
|
||||
|
||||
describe('NestApplication', () => {
|
||||
describe('Hybrid Application', () => {
|
||||
class Interceptor {
|
||||
public intercept(context, next) {
|
||||
return next();
|
||||
}
|
||||
}
|
||||
it('default should use new ApplicationConfig', () => {
|
||||
const applicationConfig = new ApplicationConfig();
|
||||
const container = new NestContainer(applicationConfig);
|
||||
const instance = new NestApplication(
|
||||
container,
|
||||
new NoopHttpAdapter({}),
|
||||
applicationConfig,
|
||||
{},
|
||||
);
|
||||
instance.useGlobalInterceptors(new Interceptor());
|
||||
const microservice = instance.connectMicroservice({});
|
||||
expect((instance as any).config.getGlobalInterceptors().length).to.equal(
|
||||
1,
|
||||
);
|
||||
expect(
|
||||
(microservice as any).applicationConfig.getGlobalInterceptors().length,
|
||||
).to.equal(0);
|
||||
});
|
||||
it('should inherit existing ApplicationConfig', () => {
|
||||
const applicationConfig = new ApplicationConfig();
|
||||
const container = new NestContainer(applicationConfig);
|
||||
const instance = new NestApplication(
|
||||
container,
|
||||
new NoopHttpAdapter({}),
|
||||
applicationConfig,
|
||||
{},
|
||||
);
|
||||
instance.useGlobalInterceptors(new Interceptor());
|
||||
const microservice = instance.connectMicroservice(
|
||||
{},
|
||||
{ inheritAppConfig: true },
|
||||
);
|
||||
expect((instance as any).config.getGlobalInterceptors().length).to.equal(
|
||||
1,
|
||||
);
|
||||
expect(
|
||||
(microservice as any).applicationConfig.getGlobalInterceptors().length,
|
||||
).to.equal(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -12,6 +12,8 @@ import { NestContainer } from '../injector/container';
|
||||
import { InstanceWrapper } from '../injector/instance-wrapper';
|
||||
import { MetadataScanner } from '../metadata-scanner';
|
||||
import { DependenciesScanner } from '../scanner';
|
||||
import { UndefinedModuleException } from '../errors/exceptions/undefined-module.exception';
|
||||
import { InvalidModuleException } from '../errors/exceptions/invalid-module.exception';
|
||||
|
||||
describe('DependenciesScanner', () => {
|
||||
class Guard {}
|
||||
@@ -36,6 +38,16 @@ describe('DependenciesScanner', () => {
|
||||
})
|
||||
class TestModule {}
|
||||
|
||||
@Module({
|
||||
imports: [undefined],
|
||||
})
|
||||
class UndefinedModule {}
|
||||
|
||||
@Module({
|
||||
imports: [null],
|
||||
})
|
||||
class InvalidModule {}
|
||||
|
||||
let scanner: DependenciesScanner;
|
||||
let mockContainer: sinon.SinonMock;
|
||||
let container: NestContainer;
|
||||
@@ -432,4 +444,20 @@ describe('DependenciesScanner', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('scanForModules', () => {
|
||||
it('should throw an exception when the imports array includes undefined', () => {
|
||||
try {
|
||||
scanner.scanForModules(UndefinedModule, [UndefinedModule]);
|
||||
} catch (exception) {
|
||||
expect(exception instanceof UndefinedModuleException).to.be.true;
|
||||
}
|
||||
});
|
||||
it('should throw an exception when the imports array includes an invalid value', () => {
|
||||
try {
|
||||
scanner.scanForModules(InvalidModule, [InvalidModule]);
|
||||
} catch (exception) {
|
||||
expect(exception instanceof InvalidModuleException).to.be.true;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,6 +38,14 @@ Nest is a framework for building efficient, scalable <a href="http://nodejs.org"
|
||||
* To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
|
||||
* 要查看中文 [指南](readme_zh.md), 请访问 [docs.nestjs.cn](https://docs.nestjs.cn). :books:
|
||||
|
||||
## Questions
|
||||
|
||||
For questions and support please use the official [Discord channel](https://discord.gg/G7Qnnhy). The issue list of this repo is **exclusively** for bug reports and feature requests.
|
||||
|
||||
## Issues
|
||||
|
||||
Please make sure to read the [Issue Reporting Checklist](https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md#-submitting-an-issue) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
|
||||
|
||||
## Consulting
|
||||
|
||||
With official support, you can get expert help straight from Nest core team. We provide dedicated technical support, migration strategies, advice on best practices (and design decisions), PR reviews, and team augmentation. Read more about [support here](https://enterprise.nestjs.com).
|
||||
@@ -48,30 +56,35 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors
|
||||
|
||||
#### Principal Sponsor
|
||||
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="320" /></a>
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="220" /></a>
|
||||
|
||||
#### Silver Sponsors
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" height="95" /></a>
|
||||
<a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="150" valign="middle" /></a>
|
||||
<a href="http://www.leogistics.com" target="_blank"><img src="https://nestjs.com/img/leogistics-logo.jpeg" width="150" valign="middle" /></a>
|
||||
|
||||
<table style="text-align:center;"><tr><td>
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a> </td><td>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" width="100" /></a> </td><td>
|
||||
<a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="170" valign="middle" /></a> </td><td>
|
||||
<a href="http://www.leogistics.com" target="_blank"><img src="https://nestjs.com/img/leogistics-logo.jpeg" width="150" valign="middle" /></td></tr></table>
|
||||
|
||||
#### Sponsors
|
||||
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a> <a href="https://blueanchor.io/" target="_blank"><img src="https://nestjs.com/img/blueanchor.png" width="150" valign="middle" /></a>
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> <a href="https://hostpresto.com" target="_blank"><img src="https://nestjs.com/img/hostpresto.png" height="24" valign="middle" /></a>
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" height="14" valign="middle" /></a>
|
||||
<a href="https://buddy.works/" target="_blank"><img src="https://nestjs.com/img/buddy-logo.svg" height="25" valign="middle" /></a>
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" height="25" valign="middle" /></a> <a href="https://genuinebee.com/" target="_blank"><img src="https://nestjs.com/img/genuinebee.svg" height="27" valign="middle" /></a> <a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" height="20" valign="middle" /></a> <a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" height="22" valign="middle" /></a> <a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" height="19" valign="middle" /></a> <a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" height="20" valign="middle" /></a>
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" height="18" valign="middle" /></a>
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a>
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a>
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a>
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a>
|
||||
<a href="https://tekhattan.com" target="_blank"><img src="https://nestjs.com/img/tekhattan-logo.png" width="110" valign="middle" /></a>
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a>
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a>
|
||||
|
||||
<table><tr><td align="center" valign="middle">
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a></td><td align="center" valign="middle">
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" width="72" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" width="125" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" width="100" valign="middle" /></a> </td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" width="95" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" width="107" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" width="71" valign="middle" /></a></td><td align="center" valign="middle">
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a></td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://tekhattan.com" target="_blank"><img src="https://nestjs.com/img/tekhattan-logo.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://www.thebigphonestore.co.uk/" target="_blank"><img src="https://nestjs.com/img/the-big-phone-store-logo.png" width="65" valign="middle" /></a></td></tr></table>
|
||||
|
||||
## Backers
|
||||
|
||||
|
||||
@@ -89,22 +89,14 @@ export class ClientGrpcProxy extends ClientProxy implements ClientGrpc {
|
||||
}
|
||||
|
||||
const keepaliveOptions = this.getKeepaliveOptions();
|
||||
const options: Record<string, unknown> = isObject(this.options)
|
||||
? {
|
||||
...this.options,
|
||||
...maxMessageLengthOptions,
|
||||
...keepaliveOptions,
|
||||
loader: '',
|
||||
}
|
||||
: {
|
||||
...maxMessageLengthOptions,
|
||||
};
|
||||
const options: Record<string, string | number> = {
|
||||
...(this.options.channelOptions || {}),
|
||||
...maxMessageLengthOptions,
|
||||
...keepaliveOptions,
|
||||
};
|
||||
|
||||
const credentials =
|
||||
options.credentials || grpcPackage.credentials.createInsecure();
|
||||
|
||||
delete options.credentials;
|
||||
delete options.keepalive;
|
||||
this.options.credentials || grpcPackage.credentials.createInsecure();
|
||||
|
||||
const grpcClient = new clientRef[name](this.url, credentials, options);
|
||||
this.clients.set(name, grpcClient);
|
||||
@@ -134,7 +126,7 @@ export class ClientGrpcProxy extends ClientProxy implements ClientGrpc {
|
||||
this.options.keepalive,
|
||||
)) {
|
||||
const key = keepaliveKeys[optionKey];
|
||||
if (!key) {
|
||||
if (key === undefined) {
|
||||
continue;
|
||||
}
|
||||
keepaliveOptions[key] = optionValue;
|
||||
|
||||
@@ -93,11 +93,18 @@ export class ClientKafka extends ClientProxy {
|
||||
return this.producer;
|
||||
}
|
||||
this.client = this.createClient();
|
||||
|
||||
const partitionAssigners = [
|
||||
(
|
||||
config: ConstructorParameters<
|
||||
typeof KafkaRoundRobinPartitionAssigner
|
||||
>[0],
|
||||
) => new KafkaRoundRobinPartitionAssigner(config),
|
||||
] as any[];
|
||||
|
||||
const consumerOptions = Object.assign(
|
||||
{
|
||||
partitionAssigners: [
|
||||
(config: any) => new KafkaRoundRobinPartitionAssigner(config),
|
||||
],
|
||||
partitionAssigners,
|
||||
},
|
||||
this.options.consumer || {},
|
||||
{
|
||||
|
||||
@@ -93,11 +93,11 @@ export class ClientRedis extends ClientProxy {
|
||||
}
|
||||
|
||||
public getClientOptions(error$: Subject<Error>): Partial<ClientOpts> {
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
const retry_strategy = (options: RetryStrategyOptions) =>
|
||||
this.createRetryStrategy(options, error$);
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
...(this.options || {}),
|
||||
retry_strategy,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ export const SUBSCRIBE = 'subscribe';
|
||||
export const CANCEL_EVENT = 'cancelled';
|
||||
|
||||
export const PATTERN_METADATA = 'microservices:pattern';
|
||||
export const TRANSPORT_METADATA = 'microservices:transport';
|
||||
export const CLIENT_CONFIGURATION_METADATA = 'microservices:client';
|
||||
export const PATTERN_HANDLER_METADATA = 'microservices:handler_type';
|
||||
export const CLIENT_METADATA = 'microservices:is_client_instance';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user