ghost 5.82.11 → 5.83.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 (186) hide show
  1. package/components/tryghost-adapter-cache-memory-ttl-5.83.0.tgz +0 -0
  2. package/components/tryghost-adapter-cache-redis-5.83.0.tgz +0 -0
  3. package/components/{tryghost-adapter-manager-5.82.11.tgz → tryghost-adapter-manager-5.83.0.tgz} +0 -0
  4. package/components/tryghost-announcement-bar-settings-5.83.0.tgz +0 -0
  5. package/components/{tryghost-api-framework-5.82.11.tgz → tryghost-api-framework-5.83.0.tgz} +0 -0
  6. package/components/tryghost-api-version-compatibility-service-5.83.0.tgz +0 -0
  7. package/components/tryghost-audience-feedback-5.83.0.tgz +0 -0
  8. package/components/tryghost-bookshelf-repository-5.83.0.tgz +0 -0
  9. package/components/tryghost-bootstrap-socket-5.83.0.tgz +0 -0
  10. package/components/tryghost-collections-5.83.0.tgz +0 -0
  11. package/components/tryghost-constants-5.83.0.tgz +0 -0
  12. package/components/tryghost-custom-theme-settings-service-5.83.0.tgz +0 -0
  13. package/components/tryghost-data-generator-5.83.0.tgz +0 -0
  14. package/components/tryghost-domain-events-5.83.0.tgz +0 -0
  15. package/components/tryghost-donations-5.83.0.tgz +0 -0
  16. package/components/tryghost-dynamic-routing-events-5.83.0.tgz +0 -0
  17. package/components/tryghost-email-addresses-5.83.0.tgz +0 -0
  18. package/components/tryghost-email-analytics-provider-mailgun-5.83.0.tgz +0 -0
  19. package/components/tryghost-email-analytics-service-5.83.0.tgz +0 -0
  20. package/components/tryghost-email-content-generator-5.83.0.tgz +0 -0
  21. package/components/tryghost-email-events-5.83.0.tgz +0 -0
  22. package/components/tryghost-email-service-5.83.0.tgz +0 -0
  23. package/components/tryghost-email-suppression-list-5.83.0.tgz +0 -0
  24. package/components/tryghost-express-dynamic-redirects-5.83.0.tgz +0 -0
  25. package/components/tryghost-external-media-inliner-5.83.0.tgz +0 -0
  26. package/components/tryghost-extract-api-key-5.83.0.tgz +0 -0
  27. package/components/tryghost-ghost-5.83.0.tgz +0 -0
  28. package/components/tryghost-html-to-plaintext-5.83.0.tgz +0 -0
  29. package/components/tryghost-i18n-5.83.0.tgz +0 -0
  30. package/components/tryghost-importer-handler-content-files-5.83.0.tgz +0 -0
  31. package/components/tryghost-importer-revue-5.83.0.tgz +0 -0
  32. package/components/tryghost-in-memory-repository-5.83.0.tgz +0 -0
  33. package/components/{tryghost-job-manager-5.82.11.tgz → tryghost-job-manager-5.83.0.tgz} +0 -0
  34. package/components/tryghost-link-redirects-5.83.0.tgz +0 -0
  35. package/components/tryghost-link-replacer-5.83.0.tgz +0 -0
  36. package/components/tryghost-link-tracking-5.83.0.tgz +0 -0
  37. package/components/tryghost-magic-link-5.83.0.tgz +0 -0
  38. package/components/tryghost-mail-events-5.83.0.tgz +0 -0
  39. package/components/tryghost-mailgun-client-5.83.0.tgz +0 -0
  40. package/components/tryghost-member-attribution-5.83.0.tgz +0 -0
  41. package/components/tryghost-member-events-5.83.0.tgz +0 -0
  42. package/components/{tryghost-members-api-5.82.11.tgz → tryghost-members-api-5.83.0.tgz} +0 -0
  43. package/components/tryghost-members-csv-5.83.0.tgz +0 -0
  44. package/components/tryghost-members-events-service-5.83.0.tgz +0 -0
  45. package/components/{tryghost-members-importer-5.82.11.tgz → tryghost-members-importer-5.83.0.tgz} +0 -0
  46. package/components/{tryghost-members-offers-5.82.11.tgz → tryghost-members-offers-5.83.0.tgz} +0 -0
  47. package/components/tryghost-members-payments-5.83.0.tgz +0 -0
  48. package/components/tryghost-members-ssr-5.83.0.tgz +0 -0
  49. package/components/tryghost-members-stripe-service-5.83.0.tgz +0 -0
  50. package/components/tryghost-mentions-email-report-5.83.0.tgz +0 -0
  51. package/components/tryghost-milestones-5.83.0.tgz +0 -0
  52. package/components/tryghost-minifier-5.83.0.tgz +0 -0
  53. package/components/tryghost-model-to-domain-event-interceptor-5.83.0.tgz +0 -0
  54. package/components/tryghost-mw-api-version-mismatch-5.83.0.tgz +0 -0
  55. package/components/tryghost-mw-cache-control-5.83.0.tgz +0 -0
  56. package/components/tryghost-mw-error-handler-5.83.0.tgz +0 -0
  57. package/components/tryghost-mw-session-from-token-5.83.0.tgz +0 -0
  58. package/components/tryghost-mw-update-user-last-seen-5.83.0.tgz +0 -0
  59. package/components/tryghost-mw-version-match-5.83.0.tgz +0 -0
  60. package/components/tryghost-mw-vhost-5.83.0.tgz +0 -0
  61. package/components/tryghost-nql-filter-expansions-5.83.0.tgz +0 -0
  62. package/components/tryghost-oembed-service-5.83.0.tgz +0 -0
  63. package/components/tryghost-package-json-5.83.0.tgz +0 -0
  64. package/components/tryghost-post-events-5.83.0.tgz +0 -0
  65. package/components/tryghost-post-revisions-5.83.0.tgz +0 -0
  66. package/components/tryghost-posts-service-5.83.0.tgz +0 -0
  67. package/components/tryghost-recommendations-5.83.0.tgz +0 -0
  68. package/components/tryghost-referrers-5.83.0.tgz +0 -0
  69. package/components/{tryghost-security-5.82.11.tgz → tryghost-security-5.83.0.tgz} +0 -0
  70. package/components/tryghost-session-service-5.83.0.tgz +0 -0
  71. package/components/tryghost-settings-path-manager-5.83.0.tgz +0 -0
  72. package/components/tryghost-slack-notifications-5.83.0.tgz +0 -0
  73. package/components/{tryghost-staff-service-5.82.11.tgz → tryghost-staff-service-5.83.0.tgz} +0 -0
  74. package/components/tryghost-stats-service-5.83.0.tgz +0 -0
  75. package/components/tryghost-tiers-5.83.0.tgz +0 -0
  76. package/components/tryghost-update-check-service-5.83.0.tgz +0 -0
  77. package/components/tryghost-verification-trigger-5.83.0.tgz +0 -0
  78. package/components/{tryghost-version-notifications-data-service-5.82.11.tgz → tryghost-version-notifications-data-service-5.83.0.tgz} +0 -0
  79. package/components/tryghost-webmentions-5.83.0.tgz +0 -0
  80. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +128 -127
  81. package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +2 -2
  82. package/core/built/admin/assets/admin-x-demo/{index-f680a5a7.mjs → index-ca021c9d.mjs} +464 -455
  83. package/core/built/admin/assets/admin-x-demo/{modals-18b8ce29.mjs → modals-0eb36d36.mjs} +2 -2
  84. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-f473955a.mjs → CodeEditorView-d8e0ec68.mjs} +2 -2
  85. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
  86. package/core/built/admin/assets/admin-x-settings/{index-3a6e3da7.mjs → index-7b657428.mjs} +1913 -1883
  87. package/core/built/admin/assets/admin-x-settings/{index-1a183093.mjs → index-a83dd4fa.mjs} +3586 -3427
  88. package/core/built/admin/assets/admin-x-settings/{modals-8d753de7.mjs → modals-1155e24d.mjs} +3315 -3276
  89. package/core/built/admin/assets/{chunk.799.4deb46f52edfd88977f5.js → chunk.509.d6d53e741bc279357eaf.js} +2359 -1963
  90. package/core/built/admin/assets/{chunk.524.712c85d7aae3325b5222.js → chunk.524.8204e0b9f49cec9eed57.js} +5 -5
  91. package/core/built/admin/assets/chunk.582.19e6edf39eacb732f2ab.js +37 -0
  92. package/core/built/admin/assets/{ghost-c52d8f1cb59e0b63db510a03624bd6c5.js → ghost-d8a21c3ed32505399e33675d8cb7d044.js} +188 -169
  93. package/core/built/admin/assets/{ghost-2d96bdf18f0c86e478dcec5a49c8b52b.css → ghost-da77ec7395d5e861b94d529e8157ed3f.css} +1 -1
  94. package/core/built/admin/assets/{ghost-dark-8c426702a34c5696f15d0e2921bdb19a.css → ghost-dark-e5e7c4c3fcaa12ca01df563d1bcbac20.css} +1 -1
  95. package/core/built/admin/assets/koenig-lexical/index.css +1 -1
  96. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14555 -14119
  97. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +128 -128
  98. package/core/built/admin/assets/{vendor-88d17cd9936471fdffa306a04f70e996.js → vendor-0d51bbe51e0393cca143d7b52d073d8a.js} +22 -18
  99. package/core/built/admin/index.html +6 -6
  100. package/core/frontend/utils/images.js +4 -0
  101. package/core/frontend/web/middleware/frontend-caching.js +77 -0
  102. package/core/frontend/web/middleware/index.js +1 -0
  103. package/core/frontend/web/site.js +16 -14
  104. package/core/server/api/endpoints/utils/serializers/input/posts.js +40 -1
  105. package/core/server/data/migrations/versions/5.83/2024-05-28-02-20-55-add-show-subhead-column-newsletters.js +9 -0
  106. package/core/server/data/schema/schema.js +1 -0
  107. package/core/server/models/newsletter.js +2 -1
  108. package/core/server/services/members/middleware.js +69 -0
  109. package/core/server/web/api/middleware/upload.js +32 -3
  110. package/core/server/web/members/app.js +8 -1
  111. package/core/shared/labs.js +4 -1
  112. package/core/shared/sentry.js +0 -1
  113. package/package.json +172 -173
  114. package/yarn.lock +696 -743
  115. package/components/tryghost-adapter-cache-memory-ttl-5.82.11.tgz +0 -0
  116. package/components/tryghost-adapter-cache-redis-5.82.11.tgz +0 -0
  117. package/components/tryghost-announcement-bar-settings-5.82.11.tgz +0 -0
  118. package/components/tryghost-api-version-compatibility-service-5.82.11.tgz +0 -0
  119. package/components/tryghost-audience-feedback-5.82.11.tgz +0 -0
  120. package/components/tryghost-bookshelf-repository-5.82.11.tgz +0 -0
  121. package/components/tryghost-bootstrap-socket-5.82.11.tgz +0 -0
  122. package/components/tryghost-collections-5.82.11.tgz +0 -0
  123. package/components/tryghost-constants-5.82.11.tgz +0 -0
  124. package/components/tryghost-custom-theme-settings-service-5.82.11.tgz +0 -0
  125. package/components/tryghost-data-generator-5.82.11.tgz +0 -0
  126. package/components/tryghost-domain-events-5.82.11.tgz +0 -0
  127. package/components/tryghost-donations-5.82.11.tgz +0 -0
  128. package/components/tryghost-dynamic-routing-events-5.82.11.tgz +0 -0
  129. package/components/tryghost-email-addresses-5.82.11.tgz +0 -0
  130. package/components/tryghost-email-analytics-provider-mailgun-5.82.11.tgz +0 -0
  131. package/components/tryghost-email-analytics-service-5.82.11.tgz +0 -0
  132. package/components/tryghost-email-content-generator-5.82.11.tgz +0 -0
  133. package/components/tryghost-email-events-5.82.11.tgz +0 -0
  134. package/components/tryghost-email-service-5.82.11.tgz +0 -0
  135. package/components/tryghost-email-suppression-list-5.82.11.tgz +0 -0
  136. package/components/tryghost-express-dynamic-redirects-5.82.11.tgz +0 -0
  137. package/components/tryghost-external-media-inliner-5.82.11.tgz +0 -0
  138. package/components/tryghost-extract-api-key-5.82.11.tgz +0 -0
  139. package/components/tryghost-ghost-5.82.11.tgz +0 -0
  140. package/components/tryghost-html-to-plaintext-5.82.11.tgz +0 -0
  141. package/components/tryghost-i18n-5.82.11.tgz +0 -0
  142. package/components/tryghost-importer-handler-content-files-5.82.11.tgz +0 -0
  143. package/components/tryghost-importer-revue-5.82.11.tgz +0 -0
  144. package/components/tryghost-in-memory-repository-5.82.11.tgz +0 -0
  145. package/components/tryghost-link-redirects-5.82.11.tgz +0 -0
  146. package/components/tryghost-link-replacer-5.82.11.tgz +0 -0
  147. package/components/tryghost-link-tracking-5.82.11.tgz +0 -0
  148. package/components/tryghost-magic-link-5.82.11.tgz +0 -0
  149. package/components/tryghost-mail-events-5.82.11.tgz +0 -0
  150. package/components/tryghost-mailgun-client-5.82.11.tgz +0 -0
  151. package/components/tryghost-member-attribution-5.82.11.tgz +0 -0
  152. package/components/tryghost-member-events-5.82.11.tgz +0 -0
  153. package/components/tryghost-members-csv-5.82.11.tgz +0 -0
  154. package/components/tryghost-members-events-service-5.82.11.tgz +0 -0
  155. package/components/tryghost-members-payments-5.82.11.tgz +0 -0
  156. package/components/tryghost-members-ssr-5.82.11.tgz +0 -0
  157. package/components/tryghost-members-stripe-service-5.82.11.tgz +0 -0
  158. package/components/tryghost-mentions-email-report-5.82.11.tgz +0 -0
  159. package/components/tryghost-milestones-5.82.11.tgz +0 -0
  160. package/components/tryghost-minifier-5.82.11.tgz +0 -0
  161. package/components/tryghost-model-to-domain-event-interceptor-5.82.11.tgz +0 -0
  162. package/components/tryghost-mw-api-version-mismatch-5.82.11.tgz +0 -0
  163. package/components/tryghost-mw-cache-control-5.82.11.tgz +0 -0
  164. package/components/tryghost-mw-error-handler-5.82.11.tgz +0 -0
  165. package/components/tryghost-mw-session-from-token-5.82.11.tgz +0 -0
  166. package/components/tryghost-mw-update-user-last-seen-5.82.11.tgz +0 -0
  167. package/components/tryghost-mw-version-match-5.82.11.tgz +0 -0
  168. package/components/tryghost-mw-vhost-5.82.11.tgz +0 -0
  169. package/components/tryghost-nql-filter-expansions-5.82.11.tgz +0 -0
  170. package/components/tryghost-oembed-service-5.82.11.tgz +0 -0
  171. package/components/tryghost-package-json-5.82.11.tgz +0 -0
  172. package/components/tryghost-post-events-5.82.11.tgz +0 -0
  173. package/components/tryghost-post-revisions-5.82.11.tgz +0 -0
  174. package/components/tryghost-posts-service-5.82.11.tgz +0 -0
  175. package/components/tryghost-recommendations-5.82.11.tgz +0 -0
  176. package/components/tryghost-referrers-5.82.11.tgz +0 -0
  177. package/components/tryghost-session-service-5.82.11.tgz +0 -0
  178. package/components/tryghost-settings-path-manager-5.82.11.tgz +0 -0
  179. package/components/tryghost-slack-notifications-5.82.11.tgz +0 -0
  180. package/components/tryghost-stats-service-5.82.11.tgz +0 -0
  181. package/components/tryghost-tiers-5.82.11.tgz +0 -0
  182. package/components/tryghost-update-check-service-5.82.11.tgz +0 -0
  183. package/components/tryghost-verification-trigger-5.82.11.tgz +0 -0
  184. package/components/tryghost-webmentions-5.82.11.tgz +0 -0
  185. package/core/built/admin/assets/chunk.582.8b9145c6796c52912f7b.js +0 -11
  186. /package/core/built/admin/assets/{chunk.799.4deb46f52edfd88977f5.js.LICENSE.txt → chunk.509.d6d53e741bc279357eaf.js.LICENSE.txt} +0 -0
@@ -9298,7 +9298,9 @@ e.default={content:'<g clip-path="url(#social-linkedin_svg__clip0_537_833)"><pat
9298
9298
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9299
9299
  e.default={content:'<circle cx="20" cy="20" r="20" fill="#51B1EF"/><path d="M30.905 14.268a8.63 8.63 0 01-2.49.686 4.36 4.36 0 001.902-2.403 8.602 8.602 0 01-2.753 1.054c-3.512-3.488-8.463.13-7.396 3.969a12.284 12.284 0 01-8.942-4.543c-1.228 2.093-.428 4.667 1.343 5.798a4.31 4.31 0 01-1.965-.544v.055a4.35 4.35 0 003.48 4.263 4.569 4.569 0 01-1.964.074 4.367 4.367 0 004.053 3.023c-1.918 1.46-4.146 2.062-6.42 1.798 9.793 5.767 19.029-1.783 18.998-10.417 0-.187-.004-.374-.012-.561a9 9 0 002.166-2.248" fill="#fff"/>',attrs:{fill:"none",viewBox:"0 0 40 40"}}})),define("ember-svg-jar/inlined/social-x",["exports"],(function(e){"use strict"
9300
9300
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9301
- e.default={content:'<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" class="social-x_svg__x"/>',attrs:{viewBox:"0 0 24 24","aria-hidden":"true"}}})),define("ember-svg-jar/inlined/spinner",["exports"],(function(e){"use strict"
9301
+ e.default={content:'<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" class="social-x_svg__x"/>',attrs:{viewBox:"0 0 24 24","aria-hidden":"true"}}})),define("ember-svg-jar/inlined/sparkle-fill",["exports"],(function(e){"use strict"
9302
+ Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9303
+ e.default={content:'<desc>Reward Stars 3 Streamline Icon: https://streamlinehq.com</desc><path fill="currentColor" fill-rule="evenodd" d="M17.66 1.143a.75.75 0 011.451 0c.33 1.262.693 2.037 1.235 2.61.546.577 1.344 1.027 2.705 1.484a.75.75 0 010 1.422c-1.36.457-2.16.907-2.705 1.484-.542.574-.904 1.348-1.235 2.61a.75.75 0 01-1.45 0c-.331-1.262-.694-2.036-1.236-2.61-.545-.577-1.344-1.027-2.705-1.484a.75.75 0 010-1.422c1.361-.457 2.16-.907 2.705-1.483.542-.574.905-1.35 1.235-2.61zM8.052 5.322a.75.75 0 011.451 0c.595 2.283 1.27 3.774 2.33 4.9 1.062 1.129 2.584 1.967 5.031 2.792a.75.75 0 010 1.422c-2.447.824-3.969 1.663-5.031 2.792-1.06 1.126-1.735 2.617-2.33 4.9a.75.75 0 01-1.451 0c-.596-2.283-1.27-3.774-2.33-4.9C4.659 16.099 3.138 15.26.69 14.436a.75.75 0 010-1.422c2.448-.825 3.97-1.663 5.032-2.792 1.06-1.126 1.734-2.617 2.33-4.9zm11.85 10.147a.75.75 0 00-.725.556c-.24.9-.497 1.421-.863 1.8-.37.384-.926.698-1.923 1.026a.75.75 0 000 1.425c.997.327 1.553.641 1.923 1.025.366.38.623.9.863 1.8a.75.75 0 001.45 0c.24-.9.496-1.42.862-1.8.37-.384.926-.698 1.923-1.025a.75.75 0 000-1.425c-.997-.328-1.553-.642-1.923-1.026-.366-.379-.622-.9-.863-1.8a.75.75 0 00-.724-.556z" clip-rule="evenodd"/>',attrs:{fill:"none",viewBox:"0 0 24 24"}}})),define("ember-svg-jar/inlined/spinner",["exports"],(function(e){"use strict"
9302
9304
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9303
9305
  e.default={content:'<rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="translate(0 -40)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(30 124.641 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.08333333333333333s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(60 84.641 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.16666666666666666s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(90 70 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.25s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(120 61.547 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.3333333333333333s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(150 55.359 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.4166666666666667s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(180 50 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.5s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(-150 44.641 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.5833333333333334s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(-120 38.453 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.6666666666666666s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(-90 30 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.75s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(-60 15.359 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.8333333333333334s" repeatCount="indefinite"/></rect><rect x="46.5" y="40" width="7" height="20" rx="5" ry="5" fill="#fefefe" transform="rotate(-30 -24.641 70)"><animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.9166666666666666s" repeatCount="indefinite"/></rect>',attrs:{viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",class:"spinner_svg__uil-default"}}})),define("ember-svg-jar/inlined/staff",["exports"],(function(e){"use strict"
9304
9306
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
@@ -9326,10 +9328,10 @@ e.default={content:'<path d="M1.061 2.56v6.257a3 3 0 00.878 2.121L13.5 22.5a1.5
9326
9328
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9327
9329
  e.default={content:'<path clip-rule="evenodd" d="M8 2.706a1 1 0 011-1h15a1 1 0 01.707.293l21 21a1 1 0 01-1.414 1.414L23.586 3.706H9a1 1 0 01-1-1z"/><path clip-rule="evenodd" d="M3.172 8.878A4 4 0 016 7.706h12.258a4 4 0 012.827 1.17l18.328 18.327a4.001 4.001 0 01-1.424 6.573l-7.213 2.707-2.71 7.21a4.002 4.002 0 01-6.573 1.424L3.171 26.791A4 4 0 012 23.962V11.706a4 4 0 011.172-2.828zM6 9.706a2 2 0 00-2 2v12.256a2.003 2.003 0 00.585 1.415l18.322 18.326a2 2 0 003.287-.712l2.87-7.637a1 1 0 01.585-.584l7.638-2.866a2 2 0 00.712-3.287L19.67 10.291a2 2 0 00-1.413-.585H6z"/><path d="M12.25 15.956a2 2 0 100 4 2 2 0 000-4"/>',attrs:{fill:"none",viewBox:"0 0 48 48"}}})),define("ember-svg-jar/inlined/thumbs-down",["exports"],(function(e){"use strict"
9328
9330
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9329
- e.default={content:'<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M22 14.429h-3.445a1.905 1.905 0 00-1.543.794l-4.617 7.095a1.622 1.622 0 01-2.783-.233 1.597 1.597 0 01-.103-1.1l.833-3.142a1.867 1.867 0 00-.993-2.164 1.911 1.911 0 00-.833-.193h-4.63A1.881 1.881 0 012.08 13.06v-.011l1.8-6.008v-.016c.733-2.36 1.992-3.97 4.47-3.97 5.933 0 5.594-.684 12.523 2.818.377.188.752.379 1.126.572V16.5"/>',attrs:{fill:"none",viewBox:"0 0 24 24"}}})),define("ember-svg-jar/inlined/thumbs-up",["exports"],(function(e){"use strict"
9331
+ e.default={content:'<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M22 14.429h-3.445a1.905 1.905 0 00-1.543.794l-4.617 7.095a1.622 1.622 0 01-2.783-.233 1.597 1.597 0 01-.103-1.1l.833-3.142a1.867 1.867 0 00-.993-2.164 1.911 1.911 0 00-.833-.193h-4.63A1.881 1.881 0 012.08 13.06v-.011l1.8-6.008v-.016c.733-2.36 1.992-3.97 4.47-3.97 5.933 0 5.594-.684 12.523 2.818.377.188.752.379 1.126.572V16.5"/>',attrs:{fill:"none",viewBox:"0 0 24 24"}}}))
9332
+ define("ember-svg-jar/inlined/thumbs-up",["exports"],(function(e){"use strict"
9330
9333
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9331
- e.default={content:'<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M2.001 10.571h3.443a1.907 1.907 0 001.543-.794l4.618-7.095a1.62 1.62 0 011.992-.537 1.598 1.598 0 01.892 1.871l-.832 3.14a1.867 1.867 0 00.993 2.165c.259.127.544.193.832.194h4.63a1.883 1.883 0 011.807 2.426v.011l-1.8 6.008v.015c-.733 2.36-1.993 3.97-4.47 3.97-5.933 0-5.593.684-12.524-2.818-.375-.188-.75-.38-1.125-.57v-9.89"/>',attrs:{fill:"none",viewBox:"0 0 24 24"}}}))
9332
- define("ember-svg-jar/inlined/trash",["exports"],(function(e){"use strict"
9334
+ e.default={content:'<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M2.001 10.571h3.443a1.907 1.907 0 001.543-.794l4.618-7.095a1.62 1.62 0 011.992-.537 1.598 1.598 0 01.892 1.871l-.832 3.14a1.867 1.867 0 00.993 2.165c.259.127.544.193.832.194h4.63a1.883 1.883 0 011.807 2.426v.011l-1.8 6.008v.015c-.733 2.36-1.993 3.97-4.47 3.97-5.933 0-5.593.684-12.524-2.818-.375-.188-.75-.38-1.125-.57v-9.89"/>',attrs:{fill:"none",viewBox:"0 0 24 24"}}})),define("ember-svg-jar/inlined/trash",["exports"],(function(e){"use strict"
9333
9335
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9334
9336
  e.default={content:'<defs><style>.trash_svg__a{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px}</style></defs><path class="trash_svg__a" d="M17.923 22.308H6.077a1.692 1.692 0 01-1.692-1.693V5.385h15.23v15.23a1.692 1.692 0 01-1.692 1.693zM9.462 17.23v-6.769M14.539 17.23v-6.769M1 5.385h22M14.539 2H9.462a1.692 1.692 0 00-1.693 1.692v1.693h8.462V3.692A1.692 1.692 0 0014.538 2z"/>',attrs:{viewBox:"0 0 24 24",fill:"none"}}})),define("ember-svg-jar/inlined/tumbleweed",["exports"],(function(e){"use strict"
9335
9337
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
@@ -9365,7 +9367,9 @@ e.default={content:'<path d="M12.001 15.75v-12m4.5 4.5l-4.5-4.5-4.5 4.5m15.75 7.
9365
9367
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9366
9368
  e.default={content:'<defs><style>.view-site_svg__a{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px}</style></defs><rect class="view-site_svg__a" x="1.5" y="1.497" width="21" height="21" rx="1.5" ry="1.5"/><path class="view-site_svg__a" d="M1.5 7.497h21m-13.5 15v-15"/>',attrs:{viewBox:"0 0 24 24"}}})),define("ember-svg-jar/inlined/warning-circle-filled",["exports"],(function(e){"use strict"
9367
9369
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9368
- e.default={content:'<g clip-path="url(#warning-circle-filled_svg__clip0_12_38)"><path d="M7 .5a7.14 7.14 0 00-4.976 2.129A6.913 6.913 0 000 7.622 6.872 6.872 0 006.883 14.5H7a7.064 7.064 0 007-7.123A6.867 6.867 0 007 .5zm-.875 9.648A.863.863 0 017 9.25a.892.892 0 01.832 1.196.858.858 0 01-.803.554.893.893 0 01-.904-.852zm.292-2.333v-3.5a.583.583 0 111.166 0v3.5a.583.583 0 11-1.166 0z" fill="currentColor"/></g><defs><clipPath id="warning-circle-filled_svg__clip0_12_38"><path fill="#fff" transform="translate(0 .5)" d="M0 0h14v14H0z"/></clipPath></defs>',attrs:{viewBox:"0 0 14 15",fill:"none"}}})),define("ember-svg-jar/inlined/warning-stroke",["exports"],(function(e){"use strict"
9370
+ e.default={content:'<g clip-path="url(#warning-circle-filled_svg__clip0_12_38)"><path d="M7 .5a7.14 7.14 0 00-4.976 2.129A6.913 6.913 0 000 7.622 6.872 6.872 0 006.883 14.5H7a7.064 7.064 0 007-7.123A6.867 6.867 0 007 .5zm-.875 9.648A.863.863 0 017 9.25a.892.892 0 01.832 1.196.858.858 0 01-.803.554.893.893 0 01-.904-.852zm.292-2.333v-3.5a.583.583 0 111.166 0v3.5a.583.583 0 11-1.166 0z" fill="currentColor"/></g><defs><clipPath id="warning-circle-filled_svg__clip0_12_38"><path fill="#fff" transform="translate(0 .5)" d="M0 0h14v14H0z"/></clipPath></defs>',attrs:{viewBox:"0 0 14 15",fill:"none"}}})),define("ember-svg-jar/inlined/warning-fill",["exports"],(function(e){"use strict"
9371
+ Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9372
+ e.default={content:'<desc>Road Sign Warning Streamline Icon: https://streamlinehq.com</desc><path d="M23.25 23.23a.75.75 0 00.66-1.1l-11.25-21a.78.78 0 00-1.32 0l-11.25 21a.73.73 0 000 .74.73.73 0 00.64.36zM12 20.48A1.5 1.5 0 1113.5 19a1.5 1.5 0 01-1.5 1.48zm0-12.25a1 1 0 011 1v5.47a1 1 0 01-2 0V9.23a1 1 0 011-1z" fill="currentColor"/>',attrs:{viewBox:"0 0 24 24"}}})),define("ember-svg-jar/inlined/warning-stroke",["exports"],(function(e){"use strict"
9369
9373
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9370
9374
  e.default={content:'<path d="M13.313 2.275a1.5 1.5 0 00-2.626 0l-9.75 18A1.5 1.5 0 002.25 22.5h19.5a1.5 1.5 0 001.313-2.225zM12 18a.375.375 0 01.375.375m-.75 0A.375.375 0 0112 18m0 .75a.375.375 0 01-.375-.375m.75 0a.375.375 0 01-.375.375M12 15V8.25" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>',attrs:{viewBox:"0 0 24 24"}}})),define("ember-svg-jar/inlined/warning",["exports"],(function(e){"use strict"
9371
9375
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
@@ -9458,12 +9462,12 @@ this.isDestroying||this.isDestroyed||!r||r(...t)},_cleanupTimers(){Ember.run.can
9458
9462
  function a(e,t={}){const r=Object.keys(e),n=Object.keys(t),i=[].concat(r,n).reduce(((e,t)=>(-1===e.indexOf(t)&&e.push(t),e)),[]),o={...e}
9459
9463
  return i.forEach((i=>{-1!==r.indexOf(i)&&-1!==n.indexOf(i)?o[i]={...e[i],...t[i]}:-1!==n.indexOf(i)&&(o[i]=t[i])})),o}})),define("ember-tooltips/components/ember-tooltip",["exports","ember-tooltips/components/ember-tooltip-base"],(function(e,t){"use strict"
9460
9464
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9461
- e.default=t.default.extend({_tooltipVariantClass:"ember-tooltip"})})),define("ember-tooltips/templates/components/ember-tooltip-base",["exports"],(function(e){"use strict"
9465
+ e.default=t.default.extend({_tooltipVariantClass:"ember-tooltip"})}))
9466
+ define("ember-tooltips/templates/components/ember-tooltip-base",["exports"],(function(e){"use strict"
9462
9467
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9463
9468
  e.default=Ember.HTMLBars.template({id:"wPl1S7tp",block:'{"symbols":["&default"],"statements":[[6,[37,0],[[32,0,["_awaitingTooltipElementRendered"]]],null,[["default","else"],[{"statements":[[2," "],[10,"div"],[12],[2,"\\n"],[6,[37,0],[[32,0,["_shouldRenderContent"]]],null,[["default"],[{"statements":[[6,[37,0],[[27,[32,1]]],null,[["default","else"],[{"statements":[[2," "],[18,1,[[32,0]]],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[1,[32,0,["text"]]],[2,"\\n"]],"parameters":[]}]]]],"parameters":[]}]]],[2," "],[13],[2,"\\n"]],"parameters":[]},{"statements":[[6,[37,2],[[30,[36,1],[[32,0,["_renderElement"]]],null]],[["guid","insertBefore"],["%cursor:0%",[29]]],[["default"],[{"statements":[[2," "],[10,"div"],[12],[2,"\\n"],[6,[37,0],[[27,[32,1]]],null,[["default","else"],[{"statements":[[2," "],[18,1,[[32,0]]],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[1,[32,0,["text"]]],[2,"\\n"]],"parameters":[]}]]],[2," "],[13],[2,"\\n"]],"parameters":[]}]]]],"parameters":[]}]]]],"hasEval":false,"upvars":["if","-in-el-null","in-element"]}',moduleName:"ember-tooltips/templates/components/ember-tooltip-base.hbs"})})),define("ember-tooltips/utils/ember-popover",["exports"],(function(e){"use strict"
9464
9469
  function t(e,t){return!!t&&(t===e||!!t.querySelectorAll(e).length)}function r(e,r,n){return!(!r||!n)&&(!!r.is(e)||!!r.querySelectorAll(e).length&&!t(e,n))}Object.defineProperty(e,"__esModule",{value:!0}),e.isElementElsewhere=function(e,n,i){const o=!t(e,i)
9465
- return!r(e,n,i)&&o},e.isElementInPopover=t,e.isElementInTargetAndNotInPopover=r}))
9466
- define("ember-tracked-storage-polyfill/index",["exports"],(function(e){"use strict"
9470
+ return!r(e,n,i)&&o},e.isElementInPopover=t,e.isElementInTargetAndNotInPopover=r})),define("ember-tracked-storage-polyfill/index",["exports"],(function(e){"use strict"
9467
9471
  Object.defineProperty(e,"__esModule",{value:!0}),e.createStorage=function(e,t=n){return new r(e,t)},e.getValue=function(e){return e._value},e.setValue=function(e,t){const{_isEqual:r,_lastValue:n}=e
9468
9472
  r(t,n)||(e._value=e._lastValue=t)}
9469
9473
  var t=function(e,t,r,n){var i,o=arguments.length,s=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n
@@ -9562,7 +9566,8 @@ const e=this.liquidChildDidRender
9562
9566
  this._waitingFor.push(e)
9563
9567
  let t=this.nearestWithProperty("_isLiquidChild")
9564
9568
  t&&t._waitForMe(e)},_waitForAll(){const e=this._waitingFor
9565
- return this._waitingFor=[],Ember.RSVP.Promise.all(e).then((()=>{if(this._waitingFor.length>0)return this._waitForAll()}))}})})),define("liquid-fire/components/liquid-container",["exports","liquid-fire/mixins/growable","liquid-fire/components/liquid-measured","liquid-fire/templates/components/liquid-container","jquery"],(function(e,t,r,n,i){"use strict"
9569
+ return this._waitingFor=[],Ember.RSVP.Promise.all(e).then((()=>{if(this._waitingFor.length>0)return this._waitForAll()}))}})}))
9570
+ define("liquid-fire/components/liquid-container",["exports","liquid-fire/mixins/growable","liquid-fire/components/liquid-measured","liquid-fire/templates/components/liquid-container","jquery"],(function(e,t,r,n,i){"use strict"
9566
9571
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9567
9572
  e.default=Ember.Component.extend(t.default,{layout:n.default,classNames:["liquid-container"],lockSize(e,t){e.outerWidth(t.width),e.outerHeight(t.height)},unlockSize(){let e=()=>{this.updateAnimatingClass(!1),this.element&&(this.element.style.width="",this.element.style.height="")}
9568
9573
  this._scaling?this._scaling.then(e):e()},updateAnimatingClass(e){this.isDestroyed||(e?this.element.classList.add("liquid-animating"):this.element.classList.remove("liquid-animating"))},didInsertElement(){this._super(...arguments),this._wasInserted=!0},actions:{willTransition(e){if(!this._wasInserted)return
@@ -9581,8 +9586,7 @@ t||(t=(0,r.measure)(n)),n.outerWidth(t.width),n.outerHeight(t.height),n.css({pos
9581
9586
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9582
9587
  let r=Ember.Component.extend({positionalParams:["predicate"],layout:t.default,tagName:"",helperName:"liquid-if"})
9583
9588
  r.reopenClass({positionalParams:["predicate"]})
9584
- e.default=r}))
9585
- define("liquid-fire/components/liquid-measured",["exports","liquid-fire/mutation-observer","liquid-fire/templates/components/liquid-measured","jquery"],(function(e,t,r,n){"use strict"
9589
+ e.default=r})),define("liquid-fire/components/liquid-measured",["exports","liquid-fire/mutation-observer","liquid-fire/templates/components/liquid-measured","jquery"],(function(e,t,r,n){"use strict"
9586
9590
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,e.measure=i
9587
9591
  e.default=Ember.Component.extend({layout:r.default,init(){this._super(...arguments),this._destroyOnUnload=this._destroyOnUnload.bind(this)},didInsertElement(){this._super(...arguments)
9588
9592
  let e=this
@@ -9743,12 +9747,12 @@ e.default=Ember.HTMLBars.template({id:"dS0w+JQh",block:'{"symbols":["container",
9743
9747
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9744
9748
  e.default=Ember.HTMLBars.template({id:"CXFd+X02",block:'{"symbols":["&default"],"statements":[[18,1,[[32,0]]]],"hasEval":false,"upvars":[]}',moduleName:"liquid-fire/templates/components/liquid-container.hbs"})})),define("liquid-fire/templates/components/liquid-if",["exports"],(function(e){"use strict"
9745
9749
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9746
- e.default=Ember.HTMLBars.template({id:"HOnDajqQ",block:'{"symbols":["container","valueVersion","valueVersion","&else","&default"],"statements":[[6,[37,0],[[32,0,["containerless"]]],null,[["default","else"],[{"statements":[[2,"\\n "],[8,"liquid-versions",[],[["@value","@matchContext","@use","@rules","@renderWhenFalse","@class"],[[30,[36,0],[[32,0,["inverted"]],[30,[36,0],[[32,0,["predicate"]],false,true],null],[30,[36,0],[[32,0,["predicate"]],true,false],null]],null],[30,[36,1],null,[["helperName"],[[32,0,["helperName"]]]]],[32,0,["use"]],[32,0,["rules"]],[27,[32,4]],[32,0,["class"]]]],[["default"],[{"statements":[[2,"\\n"],[6,[37,0],[[32,3]],null,[["default","else"],[{"statements":[[2," "],[18,5,null],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[18,4,null],[2,"\\n"]],"parameters":[]}]]],[2," "]],"parameters":[3]}]]],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[8,"liquid-container",[],[["@id","@class","@growDuration","@growPixelsPerSecond","@growEasing","@shrinkDelay","@growDelay","@enableGrowth"],[[32,0,["containerId"]],[32,0,["class"]],[32,0,["growDuration"]],[32,0,["growPixelsPerSecond"]],[32,0,["growEasing"]],[32,0,["shrinkDelay"]],[32,0,["growDelay"]],[32,0,["enableGrowth"]]]],[["default"],[{"statements":[[2,"\\n "],[8,"liquid-versions",[],[["@value","@notify","@matchContext","@use","@rules","@renderWhenFalse"],[[30,[36,0],[[32,0,["inverted"]],[30,[36,0],[[32,0,["predicate"]],false,true],null],[30,[36,0],[[32,0,["predicate"]],true,false],null]],null],[32,1],[30,[36,1],null,[["helperName"],[[32,0,["helperName"]]]]],[32,0,["use"]],[32,0,["rules"]],[27,[32,4]]]],[["default"],[{"statements":[[2,"\\n"],[6,[37,0],[[32,2]],null,[["default","else"],[{"statements":[[2," "],[18,5,null],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[18,4,null],[2,"\\n"]],"parameters":[]}]]],[2," "]],"parameters":[2]}]]],[2,"\\n "]],"parameters":[1]}]]],[2,"\\n"]],"parameters":[]}]]]],"hasEval":false,"upvars":["if","hash"]}',moduleName:"liquid-fire/templates/components/liquid-if.hbs"})})),define("liquid-fire/templates/components/liquid-measured",["exports"],(function(e){"use strict"
9750
+ e.default=Ember.HTMLBars.template({id:"HOnDajqQ",block:'{"symbols":["container","valueVersion","valueVersion","&else","&default"],"statements":[[6,[37,0],[[32,0,["containerless"]]],null,[["default","else"],[{"statements":[[2,"\\n "],[8,"liquid-versions",[],[["@value","@matchContext","@use","@rules","@renderWhenFalse","@class"],[[30,[36,0],[[32,0,["inverted"]],[30,[36,0],[[32,0,["predicate"]],false,true],null],[30,[36,0],[[32,0,["predicate"]],true,false],null]],null],[30,[36,1],null,[["helperName"],[[32,0,["helperName"]]]]],[32,0,["use"]],[32,0,["rules"]],[27,[32,4]],[32,0,["class"]]]],[["default"],[{"statements":[[2,"\\n"],[6,[37,0],[[32,3]],null,[["default","else"],[{"statements":[[2," "],[18,5,null],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[18,4,null],[2,"\\n"]],"parameters":[]}]]],[2," "]],"parameters":[3]}]]],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[8,"liquid-container",[],[["@id","@class","@growDuration","@growPixelsPerSecond","@growEasing","@shrinkDelay","@growDelay","@enableGrowth"],[[32,0,["containerId"]],[32,0,["class"]],[32,0,["growDuration"]],[32,0,["growPixelsPerSecond"]],[32,0,["growEasing"]],[32,0,["shrinkDelay"]],[32,0,["growDelay"]],[32,0,["enableGrowth"]]]],[["default"],[{"statements":[[2,"\\n "],[8,"liquid-versions",[],[["@value","@notify","@matchContext","@use","@rules","@renderWhenFalse"],[[30,[36,0],[[32,0,["inverted"]],[30,[36,0],[[32,0,["predicate"]],false,true],null],[30,[36,0],[[32,0,["predicate"]],true,false],null]],null],[32,1],[30,[36,1],null,[["helperName"],[[32,0,["helperName"]]]]],[32,0,["use"]],[32,0,["rules"]],[27,[32,4]]]],[["default"],[{"statements":[[2,"\\n"],[6,[37,0],[[32,2]],null,[["default","else"],[{"statements":[[2," "],[18,5,null],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[18,4,null],[2,"\\n"]],"parameters":[]}]]],[2," "]],"parameters":[2]}]]],[2,"\\n "]],"parameters":[1]}]]],[2,"\\n"]],"parameters":[]}]]]],"hasEval":false,"upvars":["if","hash"]}',moduleName:"liquid-fire/templates/components/liquid-if.hbs"})}))
9751
+ define("liquid-fire/templates/components/liquid-measured",["exports"],(function(e){"use strict"
9747
9752
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9748
9753
  e.default=Ember.HTMLBars.template({id:"ZXmeP7J9",block:'{"symbols":["&default"],"statements":[[18,1,null],[2,"\\n"]],"hasEval":false,"upvars":[]}',moduleName:"liquid-fire/templates/components/liquid-measured.hbs"})})),define("liquid-fire/templates/components/liquid-outlet",["exports"],(function(e){"use strict"
9749
9754
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9750
- e.default=Ember.HTMLBars.template({id:"GqUo9ITF",block:'{"symbols":["outletState","version"],"statements":[[8,"lf-get-outlet-state",[],[[],[]],[["default"],[{"statements":[[6,[37,5],[[30,[36,4],[[32,1],[32,0,["outletName"]]],null]],[["containerId","versionEquality","matchContext","class","use","rules","containerless","growDuration","growPixelsPerSecond","growEasing","shrinkDelay","growDelay","enableGrowth"],[[32,0,["containerId"]],[32,0,["versionEquality"]],[30,[36,3],null,[["outletName","helperName"],[[32,0,["outletName"]],"liquid-outlet"]]],[32,0,["class"]],[32,0,["use"]],[32,0,["rules"]],[32,0,["containerless"]],[32,0,["growDuration"]],[32,0,["growPixelsPerSecond"]],[32,0,["growEasing"]],[32,0,["shrinkDelay"]],[32,0,["growDelay"]],[32,0,["enableGrowth"]]]],[["default"],[{"statements":[[6,[37,2],null,[["outletState"],[[32,2]]],[["default"],[{"statements":[[1,[30,[36,1],[[30,[36,0],[[32,0,["outletName"]]],null]],null]]],"parameters":[]}]]]],"parameters":[2]}]]]],"parameters":[1]}]]]],"hasEval":false,"upvars":["-outlet","component","-with-dynamic-vars","hash","lf-lock-model","liquid-bind"]}',moduleName:"liquid-fire/templates/components/liquid-outlet.hbs"})}))
9751
- define("liquid-fire/templates/components/liquid-spacer",["exports"],(function(e){"use strict"
9755
+ e.default=Ember.HTMLBars.template({id:"GqUo9ITF",block:'{"symbols":["outletState","version"],"statements":[[8,"lf-get-outlet-state",[],[[],[]],[["default"],[{"statements":[[6,[37,5],[[30,[36,4],[[32,1],[32,0,["outletName"]]],null]],[["containerId","versionEquality","matchContext","class","use","rules","containerless","growDuration","growPixelsPerSecond","growEasing","shrinkDelay","growDelay","enableGrowth"],[[32,0,["containerId"]],[32,0,["versionEquality"]],[30,[36,3],null,[["outletName","helperName"],[[32,0,["outletName"]],"liquid-outlet"]]],[32,0,["class"]],[32,0,["use"]],[32,0,["rules"]],[32,0,["containerless"]],[32,0,["growDuration"]],[32,0,["growPixelsPerSecond"]],[32,0,["growEasing"]],[32,0,["shrinkDelay"]],[32,0,["growDelay"]],[32,0,["enableGrowth"]]]],[["default"],[{"statements":[[6,[37,2],null,[["outletState"],[[32,2]]],[["default"],[{"statements":[[1,[30,[36,1],[[30,[36,0],[[32,0,["outletName"]]],null]],null]]],"parameters":[]}]]]],"parameters":[2]}]]]],"parameters":[1]}]]]],"hasEval":false,"upvars":["-outlet","component","-with-dynamic-vars","hash","lf-lock-model","liquid-bind"]}',moduleName:"liquid-fire/templates/components/liquid-outlet.hbs"})})),define("liquid-fire/templates/components/liquid-spacer",["exports"],(function(e){"use strict"
9752
9756
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9753
9757
  e.default=Ember.HTMLBars.template({id:"4r1Z9TMa",block:'{"symbols":["&default"],"statements":[[8,"liquid-measured",[],[["@didMeasure"],[[30,[36,0],[[32,0],[32,0,["sizeChanged"]]],null]]],[["default"],[{"statements":[[2,"\\n "],[18,1,null],[2,"\\n"]],"parameters":[]}]]]],"hasEval":false,"upvars":["action"]}',moduleName:"liquid-fire/templates/components/liquid-spacer.hbs"})})),define("liquid-fire/templates/components/liquid-sync",["exports"],(function(e){"use strict"
9754
9758
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
@@ -9896,7 +9900,8 @@ e.default=Ember.HTMLBars.template({id:"Qr2N4/XN",block:'{"symbols":["@replaceNod
9896
9900
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9897
9901
  e.default=Ember.HTMLBars.template({id:"P8POU6zX",block:'{"symbols":["stack","item"],"statements":[[10,"div"],[15,0,[31,["liquid-destination ",[32,0,["extraClassesString"]]," ",[30,[36,0],[[32,0,["hasWormholes"]],"has-wormholes"],null]]]],[12],[2,"\\n"],[6,[37,2],[[30,[36,1],[[30,[36,1],[[32,0,["stacks"]]],null]],null]],null,[["default"],[{"statements":[[2," "],[10,"div"],[14,0,"liquid-destination-stack"],[12],[2,"\\n "],[8,"liquid-versions",[],[["@value","@notify","@renderWhenFalse","@name","@matchContext","@stackName"],[[32,1,["lastObject"]],[32,0],true,"liquid-wormhole",[32,0,["matchContext"]],[32,1,["name"]]]],[["default"],[{"statements":[[2,"\\n "],[8,"liquid-append",[],[["@nodes","@replaceNodes","@notify","@click"],[[32,2,["nodes"]],[32,2,["_replaceNodes"]],[32,2,["wormhole"]],[32,2,["wormhole","click"]]]],null],[2,"\\n "]],"parameters":[2]}]]],[2,"\\n "],[13],[2,"\\n"]],"parameters":[1]}]]],[13]],"hasEval":false,"upvars":["if","-track-array","each"]}',moduleName:"liquid-wormhole/templates/components/liquid-destination.hbs"})})),define("liquid-wormhole/templates/components/liquid-wormhole",["exports"],(function(e){"use strict"
9898
9902
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9899
- e.default=Ember.HTMLBars.template({id:"FcVE2XL/",block:'{"symbols":["details","&default"],"statements":[[6,[37,0],[[32,0,["hasSend"]]],null,[["default","else"],[{"statements":[[6,[37,0],[[27,[32,2]]],null,[["default","else"],[{"statements":[[2," "],[8,[32,0,["sendComponent"]],[[16,1,[32,0,["wormholeId"]]],[16,0,[31,[[32,0,["wormholeClass"]]," liquid-wormhole-element"]]]],[[],[]],[["default"],[{"statements":[[2,"\\n "],[18,2,[[32,1]]],[2,"\\n "]],"parameters":[1]}]]],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[8,[32,0,["sendComponent"]],[[16,1,[32,0,["wormholeId"]]],[16,0,[31,[[32,0,["wormholeClass"]]," liquid-wormhole-element"]]]],[[],[]],null],[2,"\\n"]],"parameters":[]}]]]],"parameters":[]},{"statements":[[2," "],[10,"div"],[15,1,[32,0,["wormholeId"]]],[15,0,[31,[[32,0,["wormholeClass"]]," liquid-wormhole-element"]]],[12],[2,"\\n "],[18,2,null],[2,"\\n "],[13],[2,"\\n"]],"parameters":[]}]]]],"hasEval":false,"upvars":["if"]}',moduleName:"liquid-wormhole/templates/components/liquid-wormhole.hbs"})})),define("liquid-wormhole/transitions/wormhole",["exports"],(function(e){"use strict"
9903
+ e.default=Ember.HTMLBars.template({id:"FcVE2XL/",block:'{"symbols":["details","&default"],"statements":[[6,[37,0],[[32,0,["hasSend"]]],null,[["default","else"],[{"statements":[[6,[37,0],[[27,[32,2]]],null,[["default","else"],[{"statements":[[2," "],[8,[32,0,["sendComponent"]],[[16,1,[32,0,["wormholeId"]]],[16,0,[31,[[32,0,["wormholeClass"]]," liquid-wormhole-element"]]]],[[],[]],[["default"],[{"statements":[[2,"\\n "],[18,2,[[32,1]]],[2,"\\n "]],"parameters":[1]}]]],[2,"\\n"]],"parameters":[]},{"statements":[[2," "],[8,[32,0,["sendComponent"]],[[16,1,[32,0,["wormholeId"]]],[16,0,[31,[[32,0,["wormholeClass"]]," liquid-wormhole-element"]]]],[[],[]],null],[2,"\\n"]],"parameters":[]}]]]],"parameters":[]},{"statements":[[2," "],[10,"div"],[15,1,[32,0,["wormholeId"]]],[15,0,[31,[[32,0,["wormholeClass"]]," liquid-wormhole-element"]]],[12],[2,"\\n "],[18,2,null],[2,"\\n "],[13],[2,"\\n"]],"parameters":[]}]]]],"hasEval":false,"upvars":["if"]}',moduleName:"liquid-wormhole/templates/components/liquid-wormhole.hbs"})}))
9904
+ define("liquid-wormhole/transitions/wormhole",["exports"],(function(e){"use strict"
9900
9905
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(e){let r,n,{use:i}=e
9901
9906
  if(this.oldElement&&(r=this.oldElement.find(".liquid-wormhole-element:last-child"),this.oldElement=null,r.length>0)){const e=r.clone()
9902
9907
  e.addClass("liquid-wormhole-temp-element"),t(e),r.css({visibility:"hidden"}),r.find(".liquid-child").css({visibility:"hidden"})
@@ -9911,8 +9916,7 @@ let t=e=>{if(!e)return
9911
9916
  let t=e[0].querySelectorAll("[id]")
9912
9917
  if(t.length)for(let r of t)r.setAttribute("id",`${Ember.guidFor(r)}-${r.id}`)}})),define("perf-primitives/-constants",["exports"],(function(e){"use strict"
9913
9918
  Object.defineProperty(e,"__esModule",{value:!0}),e.UNDEFINED_KEY=e.SMALL_ARRAY_LENGTH=e.LARGE_ARRAY_LENGTH=void 0
9914
- e.SMALL_ARRAY_LENGTH=200,e.LARGE_ARRAY_LENGTH=64e3,e.UNDEFINED_KEY=Object.create(null)}))
9915
- define("perf-primitives/empty-object",["exports"],(function(e){"use strict"
9919
+ e.SMALL_ARRAY_LENGTH=200,e.LARGE_ARRAY_LENGTH=64e3,e.UNDEFINED_KEY=Object.create(null)})),define("perf-primitives/empty-object",["exports"],(function(e){"use strict"
9916
9920
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
9917
9921
  const t=Object.create(null,{constructor:{value:void 0,enumerable:!1,writable:!0}})
9918
9922
  function r(){}r.prototype=t
@@ -9933,4 +9937,4 @@ e.default=class{constructor(e){if(this._data=new t.default,e)for(let t=0;t<e.len
9933
9937
  return this}get(e){let t=this._data[e]
9934
9938
  return t===r.UNDEFINED_KEY?void 0:t}set(e,t){return this._data[e]=t,this}delete(e){return this._data[e]=r.UNDEFINED_KEY,!0}}}))
9935
9939
 
9936
- //# sourceMappingURL=vendor-c767bea8e64198534441e9cbd3fce355.map
9940
+ //# sourceMappingURL=vendor-5c61b705d99db2473e7c778e9f7f0282.map
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22editorUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.82%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%2C%22editorFilename%22%3A%22koenig-lexical.umd.js%22%2C%22editorHash%22%3A%22f6d60da259%22%2C%22adminXDemoFilename%22%3A%22admin-x-demo.js%22%2C%22adminXDemoHash%22%3A%22e3f85eeea3%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%22a21b2b740e%22%2C%22adminXActivitypubFilename%22%3A%22admin-x-activitypub.js%22%2C%22adminXActivitypubHash%22%3A%22ee79721a56%22%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22editorUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.83%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%2C%22editorFilename%22%3A%22koenig-lexical.umd.js%22%2C%22editorHash%22%3A%2206e7453adf%22%2C%22adminXDemoFilename%22%3A%22admin-x-demo.js%22%2C%22adminXDemoHash%22%3A%222de5d3a326%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%22c56b800c39%22%2C%22adminXActivitypubFilename%22%3A%22admin-x-activitypub.js%22%2C%22adminXActivitypubHash%22%3A%22c4fe53c34a%22%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -37,7 +37,7 @@
37
37
  </style>
38
38
 
39
39
  <link integrity="" rel="stylesheet" href="assets/vendor-0ede59da8efb5e28fa929557f7ff7154.css">
40
- <link integrity="" rel="stylesheet" href="assets/ghost-2d96bdf18f0c86e478dcec5a49c8b52b.css" title="light">
40
+ <link integrity="" rel="stylesheet" href="assets/ghost-da77ec7395d5e861b94d529e8157ed3f.css" title="light">
41
41
 
42
42
 
43
43
  </head>
@@ -56,9 +56,9 @@
56
56
 
57
57
  <div id="ember-basic-dropdown-wormhole"></div>
58
58
 
59
- <script src="assets/vendor-88d17cd9936471fdffa306a04f70e996.js"></script>
60
- <script src="assets/chunk.799.4deb46f52edfd88977f5.js"></script>
61
- <script src="assets/chunk.524.712c85d7aae3325b5222.js"></script>
62
- <script src="assets/ghost-c52d8f1cb59e0b63db510a03624bd6c5.js"></script>
59
+ <script src="assets/vendor-0d51bbe51e0393cca143d7b52d073d8a.js"></script>
60
+ <script src="assets/chunk.509.d6d53e741bc279357eaf.js"></script>
61
+ <script src="assets/chunk.524.8204e0b9f49cec9eed57.js"></script>
62
+ <script src="assets/ghost-d8a21c3ed32505399e33675d8cb7d044.js"></script>
63
63
  </body>
64
64
  </html>
@@ -92,6 +92,10 @@ module.exports.getImageWithSize = function getImageWithSize(imagePath, sizeOptio
92
92
  const sizeDirectoryName = prefixIfPresent('w', width) + prefixIfPresent('h', height);
93
93
  const formatPrefix = requestedFormat && imageTransform.canTransformToFormat(requestedFormat) ? `/format/${requestedFormat}` : '';
94
94
 
95
+ if (!imageName) {
96
+ return imgBlogUrl;
97
+ }
98
+
95
99
  return [imgBlogUrl, urlUtils.STATIC_IMAGE_URL_PREFIX, `/size/${sizeDirectoryName}`, formatPrefix, imageName].join('');
96
100
  };
97
101
 
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @file Middleware to set the appropriate cache headers on the frontend
3
+ */
4
+ const config = require('../../../shared/config');
5
+ const shared = require('../../../server/web/shared');
6
+ const {api} = require('../../services/proxy');
7
+
8
+ /**
9
+ * Calculate the member's active tier.
10
+ * @param {object} member - The member object.
11
+ * @param {object} freeTier - The free tier object.
12
+ * @returns {string|null} - The member's active tier, or null if the member has more than one active subscription.
13
+ */
14
+ function calculateMemberTier(member, freeTier) {
15
+ const activeSubscriptions = member.subscriptions.filter(sub => sub.status === 'active');
16
+ if (activeSubscriptions.length === 0) {
17
+ return freeTier;
18
+ }
19
+ if (activeSubscriptions.length === 1) {
20
+ return activeSubscriptions[0].tier;
21
+ }
22
+ return null; // More than one active subscription
23
+ }
24
+
25
+ /**
26
+ * @typedef {function(): Promise<object>} GetFreeTier
27
+ */
28
+
29
+ /**
30
+ * Returns the frontend caching middleware.
31
+ * @param {GetFreeTier} [getFreeTier] - Async function that takes no arguments and resolves to the free tier object.
32
+ * @returns {function} Middleware function.
33
+ */
34
+ const getMiddleware = async (getFreeTier = async () => {
35
+ const {tiers} = await api.tiers.browse();
36
+ return tiers.find(tier => tier.type === 'free');
37
+ }) => {
38
+ const freeTier = await getFreeTier();
39
+ /**
40
+ * Middleware to set cache headers based on site configuration and request properties.
41
+ * @param {import('express').Request} req
42
+ * @param {import('express').Response} res
43
+ * @param {import('express').NextFunction} next
44
+ */
45
+ function setFrontendCacheHeadersMiddleware(req, res, next) {
46
+ // Caching member's content is an experimental feature, enabled via config
47
+ const shouldCacheMembersContent = config.get('cacheMembersContent:enabled');
48
+ // CASE: Never cache if the blog is set to private
49
+ // CASE: Never cache if the request is made by a member and the site is not configured to cache members content
50
+ if (res.isPrivateBlog || (req.member && !shouldCacheMembersContent)) {
51
+ return shared.middleware.cacheControl('private')(req, res, next);
52
+ }
53
+
54
+ // CASE: Cache member's content if this feature is enabled
55
+ if (req.member && shouldCacheMembersContent) {
56
+ // Set the 'cache-control' header to 'public'
57
+ const memberTier = calculateMemberTier(req.member, freeTier);
58
+ if (!memberTier) {
59
+ // Member has more than one active subscription, don't cache the content
60
+ return shared.middleware.cacheControl('private')(req, res, next);
61
+ }
62
+ // The member is either on the free tier or has a single active subscription
63
+ // Cache the content based on the member's tier
64
+ res.set({'X-Member-Cache-Tier': memberTier.id});
65
+ return shared.middleware.cacheControl('public', {maxAge: config.get('caching:frontend:maxAge')})(req, res, next);
66
+ }
67
+ // CASE: Site is not private and the request is not made by a member — cache the content
68
+ return shared.middleware.cacheControl('public', {maxAge: config.get('caching:frontend:maxAge')})(req, res, next);
69
+ }
70
+
71
+ return setFrontendCacheHeadersMiddleware;
72
+ };
73
+
74
+ module.exports = {
75
+ getMiddleware,
76
+ calculateMemberTier // exported for testing
77
+ };
@@ -1,6 +1,7 @@
1
1
  module.exports = {
2
2
  cors: require('./cors'),
3
3
  errorHandler: require('./error-handler'),
4
+ frontendCaching: require('./frontend-caching'),
4
5
  handleImageSizes: require('./handle-image-sizes'),
5
6
  redirectGhostToAdmin: require('./redirect-ghost-to-admin'),
6
7
  serveFavicon: require('./serve-favicon'),
@@ -121,9 +121,6 @@ module.exports = function setupSiteApp(routerConfig) {
121
121
  // Serve site files using the storage adapter
122
122
  siteApp.use(STATIC_FILES_URL_PREFIX, storage.getStorage('files').serve());
123
123
 
124
- // Global handling for member session, ensures a member is logged in to the frontend
125
- siteApp.use(membersService.middleware.loadMemberSession);
126
-
127
124
  // /member/.well-known/* serves files (e.g. jwks.json) so it needs to be mounted before the prettyUrl mw to avoid trailing slashes
128
125
  siteApp.use(
129
126
  '/members/.well-known',
@@ -148,18 +145,23 @@ module.exports = function setupSiteApp(routerConfig) {
148
145
 
149
146
  // Theme static assets/files
150
147
  siteApp.use(mw.staticTheme());
148
+
149
+ // Serve robots.txt if not found in theme
150
+ siteApp.use(mw.servePublicFile('static', 'robots.txt', 'text/plain', config.get('caching:robotstxt:maxAge')));
151
+
151
152
  debug('Static content done');
152
153
 
154
+ // site map - this should probably be refactored to be an internal app
155
+ sitemapHandler(siteApp);
156
+
157
+ // Global handling for member session, ensures a member is logged in to the frontend
158
+ siteApp.use(membersService.middleware.loadMemberSession);
159
+
153
160
  // Theme middleware
154
161
  // This should happen AFTER any shared assets are served, as it only changes things to do with templates
155
162
  siteApp.use(themeMiddleware);
156
163
  debug('Themes done');
157
164
 
158
- // Serve robots.txt if not found in theme
159
- siteApp.use(mw.servePublicFile('static', 'robots.txt', 'text/plain', config.get('caching:robotstxt:maxAge')));
160
-
161
- // site map - this should probably be refactored to be an internal app
162
- sitemapHandler(siteApp);
163
165
  debug('Internal apps done');
164
166
 
165
167
  // Add in all trailing slashes & remove uppercase
@@ -167,12 +169,12 @@ module.exports = function setupSiteApp(routerConfig) {
167
169
  siteApp.use(shared.middleware.prettyUrls);
168
170
 
169
171
  // ### Caching
170
- siteApp.use(function frontendCaching(req, res, next) {
171
- // Site frontend is cacheable UNLESS request made by a member or site is in private mode
172
- if (req.member || res.isPrivateBlog) {
173
- return shared.middleware.cacheControl('private')(req, res, next);
174
- } else {
175
- return shared.middleware.cacheControl('public', {maxAge: config.get('caching:frontend:maxAge')})(req, res, next);
172
+ siteApp.use(async function frontendCaching(req, res, next) {
173
+ try {
174
+ const middleware = await mw.frontendCaching.getMiddleware();
175
+ return middleware(req, res, next);
176
+ } catch {
177
+ return next();
176
178
  }
177
179
  });
178
180
 
@@ -7,6 +7,7 @@ const slugFilterOrder = require('./utils/slug-filter-order');
7
7
  const localUtils = require('../../index');
8
8
  const mobiledoc = require('../../../../../lib/mobiledoc');
9
9
  const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
10
+ const postsSchema = require('../../../../../data/schema').tables.posts;
10
11
  const clean = require('./utils/clean');
11
12
  const lexical = require('../../../../../lib/lexical');
12
13
  const sentry = require('../../../../../../shared/sentry');
@@ -16,6 +17,16 @@ const messages = {
16
17
  failedHtmlToLexical: 'Failed to convert HTML to Lexical'
17
18
  };
18
19
 
20
+ /**
21
+ * Selects all allowed columns for the given frame.
22
+ *
23
+ * NOTE: This doesn't stop them from being FETCHED, just returned in the response. This causes
24
+ * the output serializer to remove them from the data object before returning.
25
+ *
26
+ * NOTE: This is only intended for the Content API. We need these fields within Admin API responses.
27
+ *
28
+ * @param {Object} frame - The frame object.
29
+ */
19
30
  function removeSourceFormats(frame) {
20
31
  if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
21
32
  frame.options.formats = frame.options.formats.filter((format) => {
@@ -24,6 +35,33 @@ function removeSourceFormats(frame) {
24
35
  }
25
36
  }
26
37
 
38
+ /**
39
+ * Selects all allowed columns for the given frame.
40
+ *
41
+ * This removes the lexical and mobiledoc columns from the query. This is a performance improvement as we never intend
42
+ * to expose those columns in the content API and they are very large datasets to be passing around and de/serializing.
43
+ *
44
+ * NOTE: This is only intended for the Content API. We need these fields within Admin API responses.
45
+ *
46
+ * @param {Object} frame - The frame object.
47
+ */
48
+ function selectAllAllowedColumns(frame) {
49
+ if (!frame.options.columns && !frame.options.selectRaw) {
50
+ // Because we're returning columns directly from the table we need to remove info columns like @@UNIQUE_CONSTRAINTS@@
51
+ frame.options.selectRaw = _.keys(_.omit(postsSchema, ['lexical','mobiledoc','@@UNIQUE_CONSTRAINTS@@'])).join(',');
52
+ } else if (frame.options.columns) {
53
+ frame.options.columns = frame.options.columns.filter((column) => {
54
+ return !['mobiledoc', 'lexical'].includes(column);
55
+ });
56
+ } else if (frame.options.selectRaw) {
57
+ frame.options.selectRaw = frame.options.selectRaw.split(',').map((column) => {
58
+ return column.trim();
59
+ }).filter((column) => {
60
+ return !['mobiledoc', 'lexical'].includes(column);
61
+ }).join(',');
62
+ }
63
+ }
64
+
27
65
  /**
28
66
  * Map names of relations to the internal names
29
67
  */
@@ -128,7 +166,8 @@ module.exports = {
128
166
  */
129
167
  if (localUtils.isContentAPI(frame)) {
130
168
  // CASE: the content api endpoint for posts should not return mobiledoc or lexical
131
- removeSourceFormats(frame);
169
+ removeSourceFormats(frame); // remove from the format field
170
+ selectAllAllowedColumns(frame); // remove from any specified column or selectRaw options
132
171
 
133
172
  setDefaultOrder(frame);
134
173
  forceVisibilityColumn(frame);
@@ -0,0 +1,9 @@
1
+ // For information on writing migrations, see https://www.notion.so/ghost/Database-migrations-eb5b78c435d741d2b34a582d57c24253
2
+
3
+ const {createAddColumnMigration} = require('../../utils');
4
+
5
+ module.exports = createAddColumnMigration('newsletters', 'show_subhead', {
6
+ type: 'boolean',
7
+ nullable: false,
8
+ defaultTo: false
9
+ });
@@ -30,6 +30,7 @@ module.exports = {
30
30
  header_image: {type: 'string', maxlength: 2000, nullable: true},
31
31
  show_header_icon: {type: 'boolean', nullable: false, defaultTo: true},
32
32
  show_header_title: {type: 'boolean', nullable: false, defaultTo: true},
33
+ show_subhead: {type: 'boolean', nullable: false, defaultTo: false},
33
34
  title_font_category: {type: 'string', maxlength: 191, nullable: false, defaultTo: 'sans_serif', validations: {isIn: [['serif', 'sans_serif']]}},
34
35
  title_alignment: {type: 'string', maxlength: 191, nullable: false, defaultTo: 'center', validations: {isIn: [['center', 'left']]}},
35
36
  show_feature_image: {type: 'boolean', nullable: false, defaultTo: true},
@@ -29,7 +29,8 @@ const Newsletter = ghostBookshelf.Model.extend({
29
29
  background_color: 'light',
30
30
  border_color: null,
31
31
  title_color: null,
32
- feedback_enabled: false
32
+ feedback_enabled: false,
33
+ show_subhead: false
33
34
  };
34
35
  },
35
36
 
@@ -1,3 +1,4 @@
1
+ const crypto = require('crypto');
1
2
  const _ = require('lodash');
2
3
  const logging = require('@tryghost/logging');
3
4
  const membersService = require('./service');
@@ -11,12 +12,69 @@ const {
11
12
  } = require('./utils');
12
13
  const errors = require('@tryghost/errors');
13
14
  const tpl = require('@tryghost/tpl');
15
+ const onHeaders = require('on-headers');
16
+ const tiersService = require('../tiers/service');
17
+ const config = require('../../../shared/config');
14
18
 
15
19
  const messages = {
16
20
  missingUuid: 'Missing uuid.',
17
21
  invalidUuid: 'Invalid uuid.'
18
22
  };
19
23
 
24
+ const getFreeTier = async function getFreeTier() {
25
+ const response = await tiersService.api.browse();
26
+ const freeTier = response.data.find(tier => tier.type === 'free');
27
+ return freeTier;
28
+ };
29
+
30
+ /**
31
+ * Sets the ghost-access and ghost-access-hmac cookies on the response object
32
+ * @param {object} member - The member object
33
+ * @param {import('express').Response} res - The express response object to set the cookies on
34
+ * @returns
35
+ */
36
+ const setAccessCookies = function setAccessCookies(member = undefined, res, freeTier) {
37
+ if (!member) {
38
+ const accessCookie = `ghost-access=null; Max-Age=0; Path=/; HttpOnly; SameSite=Strict;`;
39
+ const hmacCookie = `ghost-access-hmac=null; Max-Age=0; Path=/; HttpOnly; SameSite=Strict;`;
40
+ const existingCookies = res.getHeader('Set-Cookie') || [];
41
+ const cookiesToSet = [accessCookie, hmacCookie].concat(existingCookies);
42
+
43
+ res.setHeader('Set-Cookie', cookiesToSet);
44
+ return;
45
+ }
46
+ const hmacSecret = config.get('cacheMembersContent:hmacSecret');
47
+ if (!hmacSecret) {
48
+ return;
49
+ }
50
+ const hmacSecretBuffer = Buffer.from(hmacSecret, 'base64');
51
+ if (hmacSecretBuffer.length === 0) {
52
+ return;
53
+ }
54
+ const activeSubscription = member.subscriptions?.find(sub => sub.status === 'active');
55
+
56
+ const cookieTimestamp = Math.floor(Date.now() / 1000); // to mitigate a cookie replay attack
57
+ const memberTier = activeSubscription && activeSubscription.tier.id || freeTier.id;
58
+ const memberTierAndTimestamp = `${memberTier}:${cookieTimestamp}`;
59
+ const memberTierHmac = crypto.createHmac('sha256', hmacSecretBuffer).update(memberTierAndTimestamp).digest('hex');
60
+
61
+ const maxAge = 3600;
62
+ const accessCookie = `ghost-access=${memberTierAndTimestamp}; Max-Age=${maxAge}; Path=/; HttpOnly; SameSite=Strict;`;
63
+ const hmacCookie = `ghost-access-hmac=${memberTierHmac}; Max-Age=${maxAge}; Path=/; HttpOnly; SameSite=Strict;`;
64
+
65
+ const existingCookies = res.getHeader('Set-Cookie') || [];
66
+ const cookiesToSet = [accessCookie, hmacCookie].concat(existingCookies);
67
+ res.setHeader('Set-Cookie', cookiesToSet);
68
+ };
69
+
70
+ const accessInfoSession = async function accessInfoSession(req, res, next) {
71
+ const freeTier = await getFreeTier();
72
+ onHeaders(res, function () {
73
+ setAccessCookies(req.member, res, freeTier);
74
+ });
75
+ next();
76
+ };
77
+
20
78
  // @TODO: This piece of middleware actually belongs to the frontend, not to the member app
21
79
  // Need to figure a way to separate these things (e.g. frontend actually talks to members API)
22
80
  const loadMemberSession = async function loadMemberSession(req, res, next) {
@@ -242,6 +300,16 @@ const createSessionFromMagicLink = async function createSessionFromMagicLink(req
242
300
  // Note: don't reset 'member_login', or that would give an easy way around user enumeration by logging in to a manually created account
243
301
  const subscriptions = member && member.subscriptions || [];
244
302
 
303
+ if (config.get('cacheMembersContent:enabled')) {
304
+ // Set the ghost-access cookies to enable tier-based caching
305
+ try {
306
+ const freeTier = await getFreeTier();
307
+ setAccessCookies(member, res, freeTier);
308
+ } catch {
309
+ // This is a non-critical operation, so we can safely ignore any errors
310
+ }
311
+ }
312
+
245
313
  const action = req.query.action;
246
314
 
247
315
  if (action === 'signup' || action === 'signup-paid' || action === 'subscribe') {
@@ -322,5 +390,6 @@ module.exports = {
322
390
  updateMemberData,
323
391
  updateMemberNewsletters,
324
392
  deleteSession,
393
+ accessInfoSession,
325
394
  deleteSuppression
326
395
  };