@mindful-web/marko-web 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/.eslintignore +3 -0
  2. package/LICENSE +21 -0
  3. package/browser/.eslintrc.js +1 -0
  4. package/browser/components/element-id.js +1 -0
  5. package/browser/components/gated-download/wufoo.vue +97 -0
  6. package/browser/components/image-slide.vue +54 -0
  7. package/browser/components/image-slider.vue +87 -0
  8. package/browser/components/index.js +15 -0
  9. package/browser/components/load-more-trigger.vue +129 -0
  10. package/browser/components/oembed.vue +133 -0
  11. package/browser/components/trigger-in-view-event.vue +41 -0
  12. package/browser/components/trigger-screen-change-event.vue +94 -0
  13. package/browser/event-bus.js +5 -0
  14. package/browser/index.js +83 -0
  15. package/browser/jquery-full.js +3 -0
  16. package/browser/jquery.js +3 -0
  17. package/browser/utils/clean-path.js +4 -0
  18. package/browser/vue.js +3 -0
  19. package/components/browser-component/script.marko +10 -0
  20. package/components/browser-component/script.marko.js +39 -0
  21. package/components/browser-component.marko +25 -0
  22. package/components/browser-component.marko.js +75 -0
  23. package/components/deferred-stylesheet.marko +6 -0
  24. package/components/deferred-stylesheet.marko.js +28 -0
  25. package/components/document/components/body-wrapper.marko +8 -0
  26. package/components/document/components/body-wrapper.marko.js +33 -0
  27. package/components/document/components/error.marko +26 -0
  28. package/components/document/components/error.marko.js +88 -0
  29. package/components/document/components/live-reload.marko +7 -0
  30. package/components/document/components/live-reload.marko.js +30 -0
  31. package/components/document/components/polyfill.marko +8 -0
  32. package/components/document/components/polyfill.marko.js +33 -0
  33. package/components/document/components/styles.marko +20 -0
  34. package/components/document/components/styles.marko.js +61 -0
  35. package/components/document/container.marko +15 -0
  36. package/components/document/container.marko.js +54 -0
  37. package/components/document/index.marko +63 -0
  38. package/components/document/index.marko.js +139 -0
  39. package/components/document/marko.json +46 -0
  40. package/components/element/array.marko +19 -0
  41. package/components/element/array.marko.js +67 -0
  42. package/components/element/audio.marko +5 -0
  43. package/components/element/audio.marko.js +33 -0
  44. package/components/element/block.marko +11 -0
  45. package/components/element/block.marko.js +44 -0
  46. package/components/element/clear.marko +4 -0
  47. package/components/element/clear.marko.js +32 -0
  48. package/components/element/components/image.marko +32 -0
  49. package/components/element/components/image.marko.js +62 -0
  50. package/components/element/components/text.marko +11 -0
  51. package/components/element/components/text.marko.js +37 -0
  52. package/components/element/content/address1.marko +14 -0
  53. package/components/element/content/address1.marko.js +40 -0
  54. package/components/element/content/address2.marko +14 -0
  55. package/components/element/content/address2.marko.js +40 -0
  56. package/components/element/content/audio.marko +13 -0
  57. package/components/element/content/audio.marko.js +39 -0
  58. package/components/element/content/authors.marko +12 -0
  59. package/components/element/content/authors.marko.js +43 -0
  60. package/components/element/content/body.marko +28 -0
  61. package/components/element/content/body.marko.js +66 -0
  62. package/components/element/content/byline.marko +15 -0
  63. package/components/element/content/byline.marko.js +41 -0
  64. package/components/element/content/city-state-zip.marko +14 -0
  65. package/components/element/content/city-state-zip.marko.js +40 -0
  66. package/components/element/content/contributors.marko +12 -0
  67. package/components/element/content/contributors.marko.js +43 -0
  68. package/components/element/content/country.marko +14 -0
  69. package/components/element/content/country.marko.js +40 -0
  70. package/components/element/content/embed-code.marko +15 -0
  71. package/components/element/content/embed-code.marko.js +41 -0
  72. package/components/element/content/end-date.marko +17 -0
  73. package/components/element/content/end-date.marko.js +43 -0
  74. package/components/element/content/ends.marko +14 -0
  75. package/components/element/content/ends.marko.js +40 -0
  76. package/components/element/content/fax.marko +14 -0
  77. package/components/element/content/fax.marko.js +40 -0
  78. package/components/element/content/images.marko +12 -0
  79. package/components/element/content/images.marko.js +43 -0
  80. package/components/element/content/marko.json +328 -0
  81. package/components/element/content/mobile.marko +14 -0
  82. package/components/element/content/mobile.marko.js +40 -0
  83. package/components/element/content/name.marko +15 -0
  84. package/components/element/content/name.marko.js +41 -0
  85. package/components/element/content/phone.marko +14 -0
  86. package/components/element/content/phone.marko.js +40 -0
  87. package/components/element/content/photographers.marko +12 -0
  88. package/components/element/content/photographers.marko.js +43 -0
  89. package/components/element/content/public-email.marko +19 -0
  90. package/components/element/content/public-email.marko.js +47 -0
  91. package/components/element/content/published.marko +17 -0
  92. package/components/element/content/published.marko.js +43 -0
  93. package/components/element/content/short-name.marko +15 -0
  94. package/components/element/content/short-name.marko.js +41 -0
  95. package/components/element/content/sidebar-stubs.marko +24 -0
  96. package/components/element/content/sidebar-stubs.marko.js +63 -0
  97. package/components/element/content/sidebars.marko +27 -0
  98. package/components/element/content/sidebars.marko.js +63 -0
  99. package/components/element/content/source.marko +14 -0
  100. package/components/element/content/source.marko.js +40 -0
  101. package/components/element/content/sponsors.marko +12 -0
  102. package/components/element/content/sponsors.marko.js +43 -0
  103. package/components/element/content/start-date.marko +17 -0
  104. package/components/element/content/start-date.marko.js +43 -0
  105. package/components/element/content/starts.marko +14 -0
  106. package/components/element/content/starts.marko.js +40 -0
  107. package/components/element/content/teaser.marko +15 -0
  108. package/components/element/content/teaser.marko.js +41 -0
  109. package/components/element/content/title.marko +14 -0
  110. package/components/element/content/title.marko.js +40 -0
  111. package/components/element/content/tollfree.marko +14 -0
  112. package/components/element/content/tollfree.marko.js +40 -0
  113. package/components/element/content/transcript.marko +22 -0
  114. package/components/element/content/transcript.marko.js +53 -0
  115. package/components/element/content/website.marko +22 -0
  116. package/components/element/content/website.marko.js +51 -0
  117. package/components/element/date.marko +2 -0
  118. package/components/element/date.marko.js +27 -0
  119. package/components/element/extract-render.js +1 -0
  120. package/components/element/image/caption.marko +15 -0
  121. package/components/element/image/caption.marko.js +41 -0
  122. package/components/element/image/credit.marko +15 -0
  123. package/components/element/image/credit.marko.js +41 -0
  124. package/components/element/image/display-name.marko +14 -0
  125. package/components/element/image/display-name.marko.js +40 -0
  126. package/components/element/image/marko.json +38 -0
  127. package/components/element/image/slider.marko +18 -0
  128. package/components/element/image/slider.marko.js +50 -0
  129. package/components/element/img.marko +12 -0
  130. package/components/element/img.marko.js +43 -0
  131. package/components/element/index.marko +12 -0
  132. package/components/element/index.marko.js +47 -0
  133. package/components/element/link.marko +25 -0
  134. package/components/element/link.marko.js +54 -0
  135. package/components/element/magazine-issue/description.marko +14 -0
  136. package/components/element/magazine-issue/description.marko.js +40 -0
  137. package/components/element/magazine-issue/digital-edition-url.marko +22 -0
  138. package/components/element/magazine-issue/digital-edition-url.marko.js +51 -0
  139. package/components/element/magazine-issue/marko.json +42 -0
  140. package/components/element/magazine-issue/name.marko +14 -0
  141. package/components/element/magazine-issue/name.marko.js +40 -0
  142. package/components/element/magazine-issue/pdf-url.marko +22 -0
  143. package/components/element/magazine-issue/pdf-url.marko.js +51 -0
  144. package/components/element/magazine-publication/cancel-url.marko +22 -0
  145. package/components/element/magazine-publication/cancel-url.marko.js +51 -0
  146. package/components/element/magazine-publication/change-address-url.marko +22 -0
  147. package/components/element/magazine-publication/change-address-url.marko.js +51 -0
  148. package/components/element/magazine-publication/description.marko +14 -0
  149. package/components/element/magazine-publication/description.marko.js +40 -0
  150. package/components/element/magazine-publication/einquiry-url.marko +22 -0
  151. package/components/element/magazine-publication/einquiry-url.marko.js +51 -0
  152. package/components/element/magazine-publication/marko.json +82 -0
  153. package/components/element/magazine-publication/name.marko +14 -0
  154. package/components/element/magazine-publication/name.marko.js +40 -0
  155. package/components/element/magazine-publication/renewal-url.marko +22 -0
  156. package/components/element/magazine-publication/renewal-url.marko.js +51 -0
  157. package/components/element/magazine-publication/reprints-url.marko +22 -0
  158. package/components/element/magazine-publication/reprints-url.marko.js +51 -0
  159. package/components/element/magazine-publication/subscribe-url.marko +22 -0
  160. package/components/element/magazine-publication/subscribe-url.marko.js +51 -0
  161. package/components/element/marko.json +211 -0
  162. package/components/element/obj-array.marko +17 -0
  163. package/components/element/obj-array.marko.js +56 -0
  164. package/components/element/obj-audio.marko +20 -0
  165. package/components/element/obj-audio.marko.js +50 -0
  166. package/components/element/obj-date.marko +25 -0
  167. package/components/element/obj-date.marko.js +55 -0
  168. package/components/element/obj-nodes.marko +20 -0
  169. package/components/element/obj-nodes.marko.js +62 -0
  170. package/components/element/obj-text.marko +23 -0
  171. package/components/element/obj-text.marko.js +53 -0
  172. package/components/element/obj.marko +23 -0
  173. package/components/element/obj.marko.js +61 -0
  174. package/components/element/object-link.js +49 -0
  175. package/components/element/object-type.js +9 -0
  176. package/components/element/picture.marko +38 -0
  177. package/components/element/picture.marko.js +85 -0
  178. package/components/element/show-element.js +8 -0
  179. package/components/element/text.marko +37 -0
  180. package/components/element/text.marko.js +76 -0
  181. package/components/element/website-section/description.marko +16 -0
  182. package/components/element/website-section/description.marko.js +44 -0
  183. package/components/element/website-section/hierarchy.marko +19 -0
  184. package/components/element/website-section/hierarchy.marko.js +60 -0
  185. package/components/element/website-section/marko.json +31 -0
  186. package/components/element/website-section/name.marko +18 -0
  187. package/components/element/website-section/name.marko.js +46 -0
  188. package/components/font/google.marko +6 -0
  189. package/components/font/google.marko.js +41 -0
  190. package/components/font/link.marko +14 -0
  191. package/components/font/link.marko.js +45 -0
  192. package/components/font/marko.json +21 -0
  193. package/components/font/typekit.marko +5 -0
  194. package/components/font/typekit.marko.js +38 -0
  195. package/components/load-more/index.marko +53 -0
  196. package/components/load-more/index.marko.js +119 -0
  197. package/components/load-more/marko.json +30 -0
  198. package/components/load-more/trigger.marko +11 -0
  199. package/components/load-more/trigger.marko.js +40 -0
  200. package/components/marko.json +37 -0
  201. package/components/node/body.marko +40 -0
  202. package/components/node/body.marko.js +112 -0
  203. package/components/node/element.marko +6 -0
  204. package/components/node/element.marko.js +39 -0
  205. package/components/node/footer.marko +19 -0
  206. package/components/node/footer.marko.js +63 -0
  207. package/components/node/header.marko +19 -0
  208. package/components/node/header.marko.js +63 -0
  209. package/components/node/image-inner-wrapper.marko +61 -0
  210. package/components/node/image-inner-wrapper.marko.js +116 -0
  211. package/components/node/image-wrapper.marko +34 -0
  212. package/components/node/image-wrapper.marko.js +98 -0
  213. package/components/node/image.marko +51 -0
  214. package/components/node/image.marko.js +93 -0
  215. package/components/node/index.marko +35 -0
  216. package/components/node/index.marko.js +100 -0
  217. package/components/node/marko.json +189 -0
  218. package/components/node/utils/image-height.js +3 -0
  219. package/components/node/utils/image-values.js +17 -0
  220. package/components/node-list/body.marko +19 -0
  221. package/components/node-list/body.marko.js +50 -0
  222. package/components/node-list/element.marko +3 -0
  223. package/components/node-list/element.marko.js +35 -0
  224. package/components/node-list/footer.marko +19 -0
  225. package/components/node-list/footer.marko.js +50 -0
  226. package/components/node-list/header.marko +19 -0
  227. package/components/node-list/header.marko.js +50 -0
  228. package/components/node-list/index.marko +36 -0
  229. package/components/node-list/index.marko.js +93 -0
  230. package/components/node-list/marko.json +121 -0
  231. package/components/node-list/node.marko +15 -0
  232. package/components/node-list/node.marko.js +49 -0
  233. package/components/node-list/nodes.marko +82 -0
  234. package/components/node-list/nodes.marko.js +126 -0
  235. package/components/page/container.marko +13 -0
  236. package/components/page/container.marko.js +46 -0
  237. package/components/page/description.marko +4 -0
  238. package/components/page/description.marko.js +26 -0
  239. package/components/page/image.marko +50 -0
  240. package/components/page/image.marko.js +122 -0
  241. package/components/page/layouts/content.marko +23 -0
  242. package/components/page/layouts/content.marko.js +63 -0
  243. package/components/page/layouts/default.marko +20 -0
  244. package/components/page/layouts/default.marko.js +61 -0
  245. package/components/page/layouts/dynamic-page.marko +19 -0
  246. package/components/page/layouts/dynamic-page.marko.js +59 -0
  247. package/components/page/layouts/magazine-issue.marko +19 -0
  248. package/components/page/layouts/magazine-issue.marko.js +59 -0
  249. package/components/page/layouts/magazine-publication.marko +19 -0
  250. package/components/page/layouts/magazine-publication.marko.js +59 -0
  251. package/components/page/layouts/marko.json +86 -0
  252. package/components/page/layouts/website-section.marko +25 -0
  253. package/components/page/layouts/website-section.marko.js +78 -0
  254. package/components/page/marko.json +93 -0
  255. package/components/page/metadata/components/common.marko +54 -0
  256. package/components/page/metadata/components/common.marko.js +117 -0
  257. package/components/page/metadata/content.marko +147 -0
  258. package/components/page/metadata/content.marko.js +216 -0
  259. package/components/page/metadata/default.marko +2 -0
  260. package/components/page/metadata/default.marko.js +29 -0
  261. package/components/page/metadata/dynamic-page.marko +40 -0
  262. package/components/page/metadata/dynamic-page.marko.js +84 -0
  263. package/components/page/metadata/google-structured-data/content.js +138 -0
  264. package/components/page/metadata/magazine-issue.marko +39 -0
  265. package/components/page/metadata/magazine-issue.marko.js +83 -0
  266. package/components/page/metadata/magazine-publication.marko +35 -0
  267. package/components/page/metadata/magazine-publication.marko.js +79 -0
  268. package/components/page/metadata/marko.json +32 -0
  269. package/components/page/metadata/website-section.marko +48 -0
  270. package/components/page/metadata/website-section.marko.js +92 -0
  271. package/components/page/rel-canonical.marko +13 -0
  272. package/components/page/rel-canonical.marko.js +42 -0
  273. package/components/page/title.marko +18 -0
  274. package/components/page/title.marko.js +46 -0
  275. package/components/page/wrapper.marko +16 -0
  276. package/components/page/wrapper.marko.js +63 -0
  277. package/components/resolve/marko.json +6 -0
  278. package/components/resolve/page.marko +10 -0
  279. package/components/resolve/page.marko.js +49 -0
  280. package/components/rss/marko.json +10 -0
  281. package/components/rss/website-section.marko +17 -0
  282. package/components/rss/website-section.marko.js +46 -0
  283. package/config/abstract-config.js +42 -0
  284. package/config/core.js +48 -0
  285. package/config/site.js +6 -0
  286. package/express/apollo.js +34 -0
  287. package/express/asset-loader.js +55 -0
  288. package/express/cdn.js +27 -0
  289. package/express/css-loader.js +117 -0
  290. package/express/embedded-media.js +31 -0
  291. package/express/error-handlers.js +113 -0
  292. package/express/find-content-alias.js +30 -0
  293. package/express/get-redirect.js +44 -0
  294. package/express/graphql-proxy.js +17 -0
  295. package/express/index.js +153 -0
  296. package/express/json-error-handler.js +30 -0
  297. package/express/load-document.js +3 -0
  298. package/express/load-more.js +6 -0
  299. package/express/load-object.js +10 -0
  300. package/express/oembed.js +18 -0
  301. package/express/rss.js +19 -0
  302. package/express/sitemaps.js +16 -0
  303. package/express/website-context.js +19 -0
  304. package/index.js +8 -0
  305. package/integration/test-website-boot.js +198 -0
  306. package/marko.json +6 -0
  307. package/middleware/disabled-features.js +15 -0
  308. package/middleware/index.js +15 -0
  309. package/middleware/page-node/index.js +45 -0
  310. package/middleware/page-node/resolved.js +26 -0
  311. package/middleware/with-content.js +54 -0
  312. package/middleware/with-dynamic-page.js +37 -0
  313. package/middleware/with-load-more.js +9 -0
  314. package/middleware/with-magazine-issue.js +24 -0
  315. package/middleware/with-magazine-publication.js +24 -0
  316. package/middleware/with-website-section.js +47 -0
  317. package/package.json +64 -0
  318. package/scss/carousel.scss +42 -0
  319. package/scss/document.scss +55 -0
  320. package/scss/fonts/alata-fallback.scss +7 -0
  321. package/scss/fonts/alegreya-fallback.scss +6 -0
  322. package/scss/fonts/arimo-fallback.scss +7 -0
  323. package/scss/fonts/fira-sans-fallback.scss +7 -0
  324. package/scss/fonts/ibm-plex-sans-fallback.scss +7 -0
  325. package/scss/fonts/informapro-fallback.scss +6 -0
  326. package/scss/fonts/lato-fallback.scss +7 -0
  327. package/scss/fonts/manrope-fallback.scss +6 -0
  328. package/scss/fonts/merriweather-fallback.scss +7 -0
  329. package/scss/fonts/montserrat-fallback.scss +7 -0
  330. package/scss/fonts/open-sans-condensed-fallback.scss +6 -0
  331. package/scss/fonts/open-sans-fallback.scss +7 -0
  332. package/scss/fonts/oswald-fallback.scss +7 -0
  333. package/scss/fonts/poppins-fallback.scss +6 -0
  334. package/scss/fonts/pt-sans-fallback.scss +6 -0
  335. package/scss/fonts/pt-serif-fallback.scss +6 -0
  336. package/scss/fonts/public-sans-fallback.scss +7 -0
  337. package/scss/fonts/raleway-fallback.scss +6 -0
  338. package/scss/fonts/roboto-condensed-fallback.scss +7 -0
  339. package/scss/fonts/roboto-fallback.scss +7 -0
  340. package/scss/fonts/roboto-slab-fallback.scss +7 -0
  341. package/scss/fonts/solitaire-mvb-pro-fallback.scss +6 -0
  342. package/scss/fonts/source-sans-4-fallback.scss +7 -0
  343. package/scss/fonts/source-serif-pro-fallback.scss +7 -0
  344. package/scss/fonts/synthese-fallback.scss +6 -0
  345. package/scss/fonts/zilla-slab-fallback.scss +6 -0
  346. package/scss/load-more.scss +3 -0
  347. package/scss/node-list.scss +144 -0
  348. package/scss/node.scss +371 -0
  349. package/scss/page-image.scss +15 -0
  350. package/start-server.js +169 -0
  351. package/utils/apply-query-params.js +16 -0
  352. package/utils/build-content-input.js +9 -0
  353. package/utils/build-marko-global.js +1 -0
  354. package/utils/default-value.js +1 -0
  355. package/utils/embedded-media/facebook-oembed.js +50 -0
  356. package/utils/embedded-media/image.js +71 -0
  357. package/utils/embedded-media/index.js +8 -0
  358. package/utils/embedded-media/instagram-oembed.js +57 -0
  359. package/utils/embedded-media/oembed.js +18 -0
  360. package/utils/hierarchy-aliases.js +3 -0
  361. package/utils/hierarchy-ids.js +3 -0
  362. package/utils/index.js +11 -0
  363. package/utils/is-dev.js +1 -0
  364. package/utils/published-content/description.js +1 -0
  365. package/utils/render-ssr-component-from-marko.js +18 -0
  366. package/utils/render-ssr-component.js +15 -0
  367. package/utils/should-collapse.js +1 -0
@@ -0,0 +1,113 @@
1
+ const { STATUS_CODES } = require('http');
2
+ const createError = require('http-errors');
3
+ const setRouteKind = require('@mindful-web/marko-express/utils/set-route-kind');
4
+ const errorTemplate = require('../components/document/components/error');
5
+ const getRedirect = require('./get-redirect');
6
+ const findContentAlias = require('./find-content-alias');
7
+ const applyQueryParams = require('../utils/apply-query-params');
8
+
9
+ const { isArray } = Array;
10
+ const { error } = console;
11
+
12
+ const noCache = (res) => {
13
+ res.setHeader('Surrogate-Control', 'no-store');
14
+ res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
15
+ res.setHeader('Pragma', 'no-cache');
16
+ res.setHeader('Expires', '0');
17
+ };
18
+
19
+ const renderError = (res, { statusCode, err, template }) => {
20
+ setRouteKind(res, { kind: 'error', type: statusCode });
21
+ res.status(statusCode);
22
+ res.marko(template || errorTemplate, {
23
+ statusCode,
24
+ statusMessage: STATUS_CODES[statusCode],
25
+ error: err,
26
+ });
27
+ };
28
+
29
+ const handleNetworkErrorResult = (res, { statusCode, result, template }) => {
30
+ const message = result.errors && isArray(result.errors) ? result.errors[0].message : 'Unknown fatal.';
31
+ return renderError(res, { statusCode, err: new Error(message), template });
32
+ };
33
+
34
+ const render = (res, { statusCode, err, template }) => {
35
+ const { networkError } = err;
36
+ if (networkError) {
37
+ if (networkError.result) {
38
+ return handleNetworkErrorResult(res, { statusCode, result: networkError.result, template });
39
+ }
40
+ return renderError(res, { statusCode, err: networkError, template });
41
+ }
42
+ return renderError(res, { statusCode, err, template });
43
+ };
44
+
45
+ const redirectOrError = ({
46
+ app,
47
+ req,
48
+ res,
49
+ err,
50
+ redirectHandler,
51
+ statusCode,
52
+ template,
53
+ fatalErrorHandler,
54
+ }) => {
55
+ getRedirect(req, redirectHandler, app).then((redirect) => {
56
+ if (redirect) {
57
+ const { code, to } = redirect;
58
+ // attempt to disable cache on temporary redirects
59
+ if ([302, 307].includes(code)) noCache(res);
60
+ res.redirect(code, to);
61
+ } else {
62
+ render(res, { statusCode, err, template });
63
+ }
64
+ }).catch(() => {
65
+ try {
66
+ render(res, { statusCode, err, template });
67
+ } catch (e) {
68
+ fatalErrorHandler(err);
69
+ }
70
+ });
71
+ };
72
+
73
+ module.exports = (app, { template, redirectHandler, onFatalError }) => {
74
+ // Force Express to throw an error on 404s.
75
+ app.use((req, res, next) => { // eslint-disable-line no-unused-vars
76
+ throw createError(404, `No page found for '${req.path}'`);
77
+ });
78
+
79
+ const fatalErrorHandler = (err) => {
80
+ error('Unable to render error template!', err);
81
+ if (typeof onFatalError === 'function') onFatalError(err);
82
+ };
83
+
84
+ // Error handler.
85
+ // @todo handle logging
86
+ app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
87
+ const statusCode = err.status || err.statusCode || 500;
88
+ const opts = {
89
+ app,
90
+ req,
91
+ res,
92
+ err,
93
+ redirectHandler,
94
+ statusCode,
95
+ template,
96
+ fatalErrorHandler,
97
+ };
98
+
99
+ // Attempt to load aliased content (when applicable).
100
+ if (statusCode === 404) {
101
+ findContentAlias({ req }).then((redirectTo) => {
102
+ if (redirectTo) {
103
+ const { query } = req;
104
+ res.redirect(301, applyQueryParams({ path: redirectTo, query }));
105
+ } else {
106
+ redirectOrError(opts);
107
+ }
108
+ }).catch(() => redirectOrError(opts));
109
+ } else {
110
+ redirectOrError(opts);
111
+ }
112
+ });
113
+ };
@@ -0,0 +1,30 @@
1
+ const gql = require('graphql-tag');
2
+ const { get } = require('@mindful-web/object-path');
3
+ const buildContentInput = require('../utils/build-content-input');
4
+
5
+ const query = gql`
6
+
7
+ query WebsiteContentPageAlias($input: ContentAliasQueryInput!) {
8
+ contentAlias(input: $input) {
9
+ id
10
+ siteContext {
11
+ path
12
+ }
13
+ }
14
+ }
15
+
16
+ `;
17
+
18
+ module.exports = async ({ req }) => {
19
+ const { apollo, path } = req;
20
+ if (!path) return null;
21
+ const alias = path.replace(/\/+$/, '').replace(/^\/+/, '');
22
+ if (!alias) return null;
23
+
24
+ const input = buildContentInput({ req });
25
+ input.alias = alias;
26
+ const variables = { input };
27
+ const { data } = await apollo.query({ query, variables });
28
+ if (!data || !data.contentAlias) return null;
29
+ return get(data, 'contentAlias.siteContext.path');
30
+ };
@@ -0,0 +1,44 @@
1
+ const gql = require('graphql-tag');
2
+
3
+ const query = gql`
4
+ query WebsiteRedirect($input: WebsiteRedirectQueryInput!) {
5
+ websiteRedirect(input: $input) {
6
+ to
7
+ code
8
+ }
9
+ }
10
+ `;
11
+
12
+ /**
13
+ * @param {object} req The Express request object.
14
+ * @param {function} [handler] An optional redirect handler to execute if no redirect was found.
15
+ * Must return an object of `{ to, code }` or `null`
16
+ * @param {object} app The Express app object.
17
+ */
18
+ module.exports = async (req, handler, app) => {
19
+ const { apollo, path, query: params } = req;
20
+ const from = path.replace(/\/$/, '');
21
+ const variables = { input: { from, params } };
22
+ const { data } = await apollo.query({ query, variables });
23
+ const { websiteRedirect } = data;
24
+ const { to } = websiteRedirect || {};
25
+ if (to) return websiteRedirect;
26
+ const pathDecoded = decodeURIComponent(from);
27
+ if (pathDecoded !== from) {
28
+ const variablesForDecoded = { input: { from: pathDecoded, params } };
29
+ const { data: dataForDecoded } = await apollo.query({ query, variables: variablesForDecoded });
30
+ const { websiteRedirect: decodedRedirect } = dataForDecoded;
31
+ const { to: redirectToDecoded } = decodedRedirect || {};
32
+ if (redirectToDecoded) return decodedRedirect;
33
+ }
34
+ // Attempt to find a redirect using the handler.
35
+ if (typeof handler !== 'function') return null;
36
+ const result = await handler({
37
+ from,
38
+ params,
39
+ req,
40
+ app,
41
+ });
42
+ if (!result || !result.to) return null;
43
+ return { ...result, code: result.code || 301 };
44
+ };
@@ -0,0 +1,17 @@
1
+ const proxy = require('express-http-proxy');
2
+
3
+ module.exports = (app, { graphqlUri, headers }) => {
4
+ const mountPoint = '/__graphql';
5
+ const opts = {
6
+ proxyReqPathResolver: ({ originalUrl }) => originalUrl.replace(mountPoint, ''),
7
+ proxyReqOptDecorator: (reqOpts, req) => {
8
+ const proxyHeaders = {
9
+ ...reqOpts.headers,
10
+ ...headers,
11
+ 'x-forwarded-proto': req.protocol,
12
+ };
13
+ return { ...reqOpts, headers: proxyHeaders };
14
+ },
15
+ };
16
+ app.use(mountPoint, proxy(graphqlUri, opts));
17
+ };
@@ -0,0 +1,153 @@
1
+ const { buildRequestHeaders } = require('@mindful-web/tenant-context');
2
+ const createApolloClient = require('@mindful-web/apollo-ssr');
3
+ const { cleanMarkoResponse, markoMiddleware } = require('@mindful-web/marko-express/middleware');
4
+ const cookieParser = require('cookie-parser');
5
+ const express = require('express');
6
+ const path = require('path');
7
+ const helmet = require('helmet');
8
+ const { nanoid } = require('nanoid');
9
+ const apollo = require('./apollo');
10
+ const graphqlProxy = require('./graphql-proxy');
11
+ const embeddedMedia = require('./embedded-media');
12
+ const loadObject = require('./load-object');
13
+ const loadDocument = require('./load-document');
14
+ const oembed = require('./oembed');
15
+ const cdn = require('./cdn');
16
+ const assetLoader = require('./asset-loader');
17
+ const cssLoader = require('./css-loader');
18
+ const rss = require('./rss');
19
+ const sitemaps = require('./sitemaps');
20
+ const { version } = require('../package.json');
21
+ const websiteContext = require('./website-context');
22
+ const CoreConfig = require('../config/core');
23
+ const SiteConfig = require('../config/site');
24
+
25
+ module.exports = (config = {}) => {
26
+ const {
27
+ rootDir,
28
+ tenantKey,
29
+ siteId,
30
+ sitePackage,
31
+ graphqlUri,
32
+ baseBrowseGraphqlUri,
33
+ gqlCacheResponses,
34
+ gqlCacheSiteContext,
35
+ } = config;
36
+ const distDir = path.resolve(rootDir, 'dist');
37
+ const app = express();
38
+ const serverDir = path.resolve(rootDir, 'server');
39
+
40
+ app.use((req, res, next) => {
41
+ // set unique request id.
42
+ req.id = nanoid();
43
+ next();
44
+ });
45
+
46
+ // Add async block error handler.
47
+ app.locals.onAsyncBlockError = config.onAsyncBlockError;
48
+
49
+ // Register global document, components and fragments.
50
+ app.locals.components = loadObject(config.components);
51
+ app.locals.fragments = loadObject(config.fragments);
52
+ app.locals.document = loadDocument(config.document);
53
+
54
+ // Register compiled Vue components for use with SSR rendering
55
+ app.locals.compiledVueComponents = require(path.join(distDir, 'ssr.js')); // eslint-disable-line
56
+
57
+ // Add cookie parsing
58
+ app.use(cookieParser());
59
+
60
+ // Add helment
61
+ if (config.helmetConfig !== false) {
62
+ app.use(helmet({
63
+ ...config.helmetConfig,
64
+ frameguard: false,
65
+ }));
66
+ }
67
+
68
+ // Set the tenant key to the app.
69
+ app.locals.tenantKey = tenantKey;
70
+
71
+ // Set the core config.
72
+ app.locals.config = new CoreConfig({ ...config.coreConfig, rootDir, distDir });
73
+
74
+ // Set the website config to the app.
75
+ app.locals.site = new SiteConfig(config.siteConfig);
76
+
77
+ // Apply embedded media handlers.
78
+ embeddedMedia(app, config.embeddedMediaHandlers);
79
+
80
+ // Apply request origin.
81
+ app.use((req, res, next) => {
82
+ res.locals.requestOrigin = `${req.protocol}://${req.get('host')}`;
83
+ next();
84
+ });
85
+
86
+ // Apply versions.
87
+ app.use((req, res, next) => {
88
+ res.set('x-version', `Site:${sitePackage.version}|Core:${version}`);
89
+ next();
90
+ });
91
+
92
+ // Register apollo client and server proxy.
93
+ const headers = {
94
+ ...buildRequestHeaders({ tenantKey, siteId }),
95
+ ...(gqlCacheSiteContext && { 'x-cache-site-context': 'true' }),
96
+ ...(gqlCacheResponses && { 'x-cache-responses': 'true' }),
97
+ };
98
+ apollo(app, graphqlUri, {
99
+ name: sitePackage.name,
100
+ version: sitePackage.version,
101
+ link: { headers },
102
+ });
103
+ graphqlProxy(app, { graphqlUri, headers });
104
+
105
+ // Base browse middleware
106
+ if (baseBrowseGraphqlUri) {
107
+ app.use((req, res, next) => {
108
+ const client = createApolloClient({
109
+ uri: baseBrowseGraphqlUri,
110
+ headers: { 'x-tenant-key': tenantKey },
111
+ config: { name: sitePackage.name, version: sitePackage.version },
112
+ });
113
+ req.$baseBrowse = client;
114
+ res.locals.$baseBrowse = client;
115
+ next();
116
+ });
117
+ }
118
+
119
+ // Set website context.
120
+ app.use(websiteContext(app.locals.config));
121
+
122
+ // Load CDN info before dist and CSS loading (but after the website context).
123
+ app.use(cdn({
124
+ enabled: ['true', '1'].includes(process.env.USE_ASSET_CDN),
125
+ origin: process.env.ASSET_CDN_ORIGIN || 'https://cdn.parameter1.com',
126
+ siteVersion: sitePackage.version,
127
+ }));
128
+ app.use(cssLoader({ distDir }));
129
+ app.use(assetLoader({ distDir }));
130
+
131
+ // Register the Marko middleware.
132
+ app.use(markoMiddleware());
133
+ app.use(cleanMarkoResponse());
134
+
135
+ // Serve static assets
136
+ app.use('/dist/css', express.static(`${distDir}/css`, { maxAge: '2y', immutable: true }));
137
+ app.use('/dist/js', express.static(`${distDir}/js`, { maxAge: '2y', immutable: true }));
138
+ app.use('/dist', express.static(distDir));
139
+
140
+ // Register public files.
141
+ app.use(express.static(path.join(serverDir, 'public')));
142
+
143
+ // Register sitemaps.
144
+ sitemaps(app, { ...config.sitemapsHeaders, ...headers });
145
+
146
+ // Register RSS Feeds.
147
+ rss(app, headers);
148
+
149
+ // Register oEmbed
150
+ oembed(app);
151
+
152
+ return app;
153
+ };
@@ -0,0 +1,30 @@
1
+ const isDev = require('../utils/is-dev');
2
+
3
+ const { isArray } = Array;
4
+
5
+ const render = (res, { status, err }) => {
6
+ const { message, stack } = err;
7
+ const obj = { error: true, status, message };
8
+ if (isDev && stack) obj.stack = stack.split('\n');
9
+ res.status(status).json(obj);
10
+ };
11
+
12
+ const renderNetworkErrorResult = (res, { status, result }) => {
13
+ const message = result.errors && isArray(result.errors) ? result.errors[0].message : 'Unknown fatal.';
14
+ render(res, { status, err: new Error(message) });
15
+ };
16
+
17
+ // eslint-disable-next-line no-unused-vars
18
+ module.exports = () => (err, req, res, next) => {
19
+ const status = err.statusCode || err.status || 500;
20
+ const { networkError } = err;
21
+ if (networkError) {
22
+ if (networkError.result) {
23
+ renderNetworkErrorResult(res, { status, result: networkError.result });
24
+ } else {
25
+ render(res, { status, err: networkError });
26
+ }
27
+ } else {
28
+ render(res, { status, err });
29
+ }
30
+ };
@@ -0,0 +1,3 @@
1
+ const defaultDocument = require('../components/document');
2
+
3
+ module.exports = (document) => document || defaultDocument;
@@ -0,0 +1,6 @@
1
+ const withLoadMore = require('../middleware/with-load-more');
2
+
3
+ module.exports = (app) => {
4
+ const { config } = app.locals;
5
+ app.use(config.loadMoreMountPoint(), withLoadMore());
6
+ };
@@ -0,0 +1,10 @@
1
+ const { getAsObject, get } = require('@mindful-web/object-path');
2
+ const { dasherize } = require('@mindful-web/inflector');
3
+
4
+ const { keys } = Object;
5
+
6
+ module.exports = (value) => {
7
+ const v = getAsObject(value);
8
+ const obj = keys(v).reduce((o, k) => ({ ...o, [dasherize(k)]: v[k] }), {});
9
+ return { get: (name) => get(obj, dasherize(name)) };
10
+ };
@@ -0,0 +1,18 @@
1
+ const proxy = require('express-http-proxy');
2
+
3
+ const { OEMBED_URI } = process.env;
4
+ if (!OEMBED_URI) throw new Error('Missing required environment variable: OEMBED_URI.');
5
+
6
+ module.exports = (app) => {
7
+ const { config } = app.locals;
8
+ const mountPoint = config.oembedMountPoint();
9
+ const opts = {
10
+ proxyReqPathResolver: ({ originalUrl }) => originalUrl.replace(mountPoint, '/'),
11
+ proxyReqOptDecorator: (reqOpts, req) => {
12
+ const headers = { ...reqOpts.headers };
13
+ headers['x-forwarded-proto'] = req.protocol;
14
+ return { ...reqOpts, headers };
15
+ },
16
+ };
17
+ app.use(mountPoint, proxy(OEMBED_URI, opts));
18
+ };
package/express/rss.js ADDED
@@ -0,0 +1,19 @@
1
+ const proxy = require('express-http-proxy');
2
+
3
+ const SERVICE_URI = process.env.RSS_URI;
4
+ if (!SERVICE_URI) throw new Error('Missing required environment variable: RSS_URI.');
5
+
6
+ module.exports = (app, tenantContext) => {
7
+ const { config } = app.locals;
8
+ const mountPoint = config.rssMountPoint();
9
+ const opts = {
10
+ proxyReqPathResolver: ({ originalUrl }) => originalUrl.replace(mountPoint, ''),
11
+ proxyReqOptDecorator: (reqOpts, req) => {
12
+ const headers = { ...reqOpts.headers, ...tenantContext };
13
+ headers['x-forwarded-proto'] = req.protocol;
14
+ headers['x-mount-point'] = mountPoint;
15
+ return { ...reqOpts, headers };
16
+ },
17
+ };
18
+ app.use(`${mountPoint}/:query([a-z-]+).xml`, proxy(SERVICE_URI, opts));
19
+ };
@@ -0,0 +1,16 @@
1
+ const proxy = require('express-http-proxy');
2
+
3
+ const SERVICE_URI = process.env.SITEMAPS_URI;
4
+ if (!SERVICE_URI) throw new Error('Missing required environment variable: SITEMAPS_URI.');
5
+
6
+ module.exports = (app, tenantContext) => {
7
+ const opts = {
8
+ proxyReqPathResolver: ({ originalUrl }) => originalUrl,
9
+ proxyReqOptDecorator: (reqOpts, req) => {
10
+ const headers = { ...reqOpts.headers, ...tenantContext };
11
+ headers['x-forwarded-proto'] = req.protocol;
12
+ return { ...reqOpts, headers };
13
+ },
14
+ };
15
+ app.use('/sitemap*', proxy(SERVICE_URI, opts));
16
+ };
@@ -0,0 +1,19 @@
1
+ const loadWebsite = require('@mindful-web/web-common/website-context');
2
+ const { asyncRoute } = require('@mindful-web/utils');
3
+ const { setDayjsLocale } = require('@mindful-web/dayjs/utils');
4
+
5
+ module.exports = (coreConfig) => asyncRoute(async (req, res, next) => {
6
+ const { apollo } = res.locals;
7
+ const websiteContext = await loadWebsite(apollo);
8
+ coreConfig.setWebsiteContext(websiteContext);
9
+
10
+ const locale = coreConfig.website('date.locale');
11
+ // Set marko core date config.
12
+ req.app.locals.markoCoreDate = {
13
+ timezone: coreConfig.website('date.timezone'),
14
+ locale,
15
+ format: coreConfig.website('date.format'),
16
+ };
17
+ setDayjsLocale({ locale });
18
+ next();
19
+ });
package/index.js ADDED
@@ -0,0 +1,8 @@
1
+ if (process.env.MARKO_REQUIRE_PREBUILT_TEMPLATES == null) {
2
+ // force prebuilt templates if env not set
3
+ process.env.MARKO_REQUIRE_PREBUILT_TEMPLATES = true;
4
+ }
5
+
6
+ const startServer = require('./start-server');
7
+
8
+ module.exports = { startServer };