Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

index.js 6.8 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  1. const express = require('express')
  2. const instrument = require('../lib/instrument-middleware')
  3. const haltOnDroppedConnection = require('./halt-on-dropped-connection')
  4. const abort = require('./abort')
  5. const timeout = require('./timeout')
  6. const morgan = require('morgan')
  7. const datadog = require('./connect-datadog')
  8. const rateLimit = require('./rate-limit')
  9. const cors = require('./cors')
  10. const helmet = require('helmet')
  11. const csp = require('./csp')
  12. const cookieParser = require('./cookie-parser')
  13. const csrf = require('./csrf')
  14. const handleCsrfErrors = require('./handle-csrf-errors')
  15. const compression = require('compression')
  16. const disableCachingOnSafari = require('./disable-caching-on-safari')
  17. const setFastlySurrogateKey = require('./set-fastly-surrogate-key')
  18. const setFastlyCacheHeaders = require('./set-fastly-cache-headers')
  19. const catchBadAcceptLanguage = require('./catch-bad-accept-language')
  20. const reqUtils = require('./req-utils')
  21. const recordRedirect = require('./record-redirect')
  22. const connectSlashes = require('connect-slashes')
  23. const handleErrors = require('./handle-errors')
  24. const { NODE_ENV } = process.env
  25. const isDevelopment = NODE_ENV === 'development'
  26. const isTest = NODE_ENV === 'test' || process.env.GITHUB_ACTIONS === 'true'
  27. // Catch unhandled promise rejections and passing them to Express's error handler
  28. // https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016
  29. const asyncMiddleware = fn =>
  30. (req, res, next) => {
  31. Promise.resolve(fn(req, res, next)).catch(next)
  32. }
  33. module.exports = function (app) {
  34. // *** Request connection management ***
  35. if (!isTest) app.use(timeout)
  36. app.use(abort)
  37. // *** Development tools ***
  38. app.use(morgan('dev', { skip: (req, res) => !isDevelopment }))
  39. // *** Observability ***
  40. if (process.env.DD_API_KEY) {
  41. app.use(datadog)
  42. }
  43. // *** Early exits ***
  44. // Don't use the proxy's IP, use the requester's for rate limiting
  45. // See https://expressjs.com/en/guide/behind-proxies.html
  46. app.set('trust proxy', 1)
  47. app.use(rateLimit)
  48. app.use(instrument('./handle-invalid-paths'))
  49. app.use(instrument('./handle-next-data-path'))
  50. // *** Security ***
  51. app.use(cors)
  52. app.use(helmet({
  53. // Override referrerPolicy to match the browser's default: "strict-origin-when-cross-origin".
  54. // Helmet now defaults to "no-referrer", which is a problem for our archived assets proxying.
  55. referrerPolicy: {
  56. policy: 'strict-origin-when-cross-origin'
  57. }
  58. }))
  59. app.use(csp) // Must come after helmet
  60. app.use(cookieParser) // Must come before csrf
  61. app.use(express.json()) // Must come before csrf
  62. app.use(csrf)
  63. app.use(handleCsrfErrors) // Must come before regular handle-errors
  64. // *** Headers ***
  65. app.set('etag', false) // We will manage our own ETags if desired
  66. app.use(compression())
  67. app.use(disableCachingOnSafari)
  68. app.use(setFastlySurrogateKey)
  69. app.use(catchBadAcceptLanguage)
  70. // *** Config and context for redirects ***
  71. app.use(reqUtils) // Must come before record-redirect and events
  72. app.use(recordRedirect)
  73. app.use(instrument('./detect-language')) // Must come before context, breadcrumbs, find-page, handle-errors, homepages
  74. app.use(asyncMiddleware(instrument('./context'))) // Must come before early-access-*, handle-redirects
  75. app.use(asyncMiddleware(instrument('./contextualizers/short-versions'))) // Support version shorthands
  76. // *** Redirects, 3xx responses ***
  77. // I ordered these by use frequency
  78. app.use(connectSlashes(false))
  79. app.use(instrument('./redirects/external'))
  80. app.use(instrument('./redirects/help-to-docs'))
  81. app.use(instrument('./redirects/language-code-redirects')) // Must come before contextualizers
  82. app.use(instrument('./redirects/handle-redirects')) // Must come before contextualizers
  83. // *** Config and context for rendering ***
  84. app.use(asyncMiddleware(instrument('./find-page'))) // Must come before archived-enterprise-versions, breadcrumbs, featured-links, products, render-page
  85. app.use(instrument('./block-robots'))
  86. // Check for a dropped connection before proceeding
  87. app.use(haltOnDroppedConnection)
  88. // *** Rendering, 2xx responses ***
  89. // I largely ordered these by use frequency
  90. app.use(asyncMiddleware(instrument('./archived-enterprise-versions-assets'))) // Must come before static/assets
  91. app.use('/dist', express.static('dist', {
  92. index: false,
  93. etag: false,
  94. immutable: true,
  95. lastModified: false,
  96. maxAge: '28 days' // Could be infinite given our fingerprinting
  97. }))
  98. app.use('/assets', express.static('assets', {
  99. index: false,
  100. etag: false,
  101. lastModified: false,
  102. maxAge: '1 day' // Relatively short in case we update images
  103. }))
  104. app.use('/public', express.static('data/graphql', {
  105. index: false,
  106. etag: false,
  107. lastModified: false,
  108. maxAge: '7 days' // A bit longer since releases are more sparse
  109. }))
  110. app.use('/events', asyncMiddleware(instrument('./events')))
  111. app.use('/search', asyncMiddleware(instrument('./search')))
  112. app.use(asyncMiddleware(instrument('./archived-enterprise-versions')))
  113. app.use(instrument('./robots'))
  114. app.use(/(\/.*)?\/early-access$/, instrument('./contextualizers/early-access-links'))
  115. app.use('/categories.json', asyncMiddleware(instrument('./categories-for-support')))
  116. app.use(instrument('./loaderio-verification'))
  117. app.get('/_500', asyncMiddleware(instrument('./trigger-error')))
  118. // Check for a dropped connection before proceeding (again)
  119. app.use(haltOnDroppedConnection)
  120. // *** Preparation for render-page: contextualizers ***
  121. app.use(asyncMiddleware(instrument('./contextualizers/release-notes')))
  122. app.use(instrument('./contextualizers/graphql'))
  123. app.use(instrument('./contextualizers/rest'))
  124. app.use(instrument('./contextualizers/webhooks'))
  125. app.use(asyncMiddleware(instrument('./contextualizers/whats-new-changelog')))
  126. app.use(instrument('./contextualizers/layout'))
  127. app.use(instrument('./contextualizers/current-product-tree'))
  128. app.use(asyncMiddleware(instrument('./contextualizers/generic-toc')))
  129. app.use(asyncMiddleware(instrument('./contextualizers/breadcrumbs')))
  130. app.use(asyncMiddleware(instrument('./contextualizers/early-access-breadcrumbs')))
  131. app.use(asyncMiddleware(instrument('./contextualizers/product-examples')))
  132. app.use(asyncMiddleware(instrument('./dev-toc')))
  133. app.use(asyncMiddleware(instrument('./featured-links')))
  134. app.use(asyncMiddleware(instrument('./learning-track')))
  135. app.use(asyncMiddleware(instrument('./is-next-request')))
  136. // *** Headers for pages only ***
  137. app.use(setFastlyCacheHeaders)
  138. // handle serving NextJS bundled code (/_next/*)
  139. if (process.env.FEATURE_NEXTJS) {
  140. app.use(instrument('./next'))
  141. }
  142. // Check for a dropped connection before proceeding (again)
  143. app.use(haltOnDroppedConnection)
  144. // *** Rendering, must go almost last ***
  145. app.get('/*', asyncMiddleware(instrument('./render-page')))
  146. // *** Error handling, must go last ***
  147. app.use(handleErrors)
  148. }
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...