ghost 6.61.0 → 6.63.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 (619) hide show
  1. package/components/ghost-storage-base-3.0.0.tgz +0 -0
  2. package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
  3. package/components/tryghost-adapter-base-jobs-0.0.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-redirects-0.0.0.tgz +0 -0
  5. package/components/tryghost-adapter-base-route-settings-0.0.0.tgz +0 -0
  6. package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
  7. package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
  8. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  9. package/components/tryghost-checkout-0.0.0.tgz +0 -0
  10. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  11. package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
  12. package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
  13. package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
  14. package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
  15. package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
  16. package/components/tryghost-kg-default-transforms-1.3.4.tgz +0 -0
  17. package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
  18. package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
  19. package/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
  20. package/components/tryghost-kg-utils-1.1.4.tgz +0 -0
  21. package/components/tryghost-limit-service-0.0.0.tgz +0 -0
  22. package/components/tryghost-metafield-types-0.0.0.tgz +0 -0
  23. package/components/tryghost-nql-string-0.0.0.tgz +0 -0
  24. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  25. package/content/settings/README.md +1 -1
  26. package/content/themes/casper/.gitignore +28 -0
  27. package/content/themes/casper/assets/built/casper.js +1 -1
  28. package/content/themes/casper/assets/built/screen.css +1 -1
  29. package/content/themes/casper/assets/css/screen.css +2 -1
  30. package/content/themes/casper/assets/js/lightbox.js +63 -46
  31. package/content/themes/casper/package.json +6 -6
  32. package/content/themes/casper/page.hbs +1 -0
  33. package/content/themes/casper/post.hbs +1 -0
  34. package/content/themes/source/.gitignore +28 -0
  35. package/content/themes/source/assets/built/screen.css +1 -1
  36. package/content/themes/source/assets/built/source.js +1 -1
  37. package/content/themes/source/assets/css/screen.css +2 -1
  38. package/content/themes/source/assets/js/lightbox.js +62 -45
  39. package/content/themes/source/assets/js/main.js +2 -2
  40. package/content/themes/source/package.json +4 -4
  41. package/content/themes/source/partials/feature-image.hbs +1 -0
  42. package/content/themes/source/partials/post-card.hbs +1 -1
  43. package/core/boot.js +61 -27
  44. package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
  45. package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
  46. package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
  47. package/core/built/admin/assets/{about-Bve7IJS2.js → about-C1C3s5-g.js} +1 -1
  48. package/core/built/admin/assets/accordion-CxGsDKwa.js +1 -0
  49. package/core/built/admin/assets/account-migration-CbUhW6gk.js +1 -0
  50. package/core/built/admin/assets/activitypub/{account-migration-C-aej4x_.js → account-migration-KA6Jjf9L.js} +16 -16
  51. package/core/built/admin/assets/activitypub/activitypub.js +9 -9
  52. package/core/built/admin/assets/activitypub/{avatar-DLPL3Abs.js → avatar-DVJF5bxP.js} +2 -2
  53. package/core/built/admin/assets/activitypub/{avatar-flipboard-C9iDY-QV.js → avatar-flipboard-csQaNeYK.js} +2 -2
  54. package/core/built/admin/assets/activitypub/{bluesky-sharing-BXkA5mqV.js → bluesky-sharing-C7nTDMvw.js} +37 -37
  55. package/core/built/admin/assets/activitypub/{content-formatters-CHcyMFk4.js → content-formatters-CLcjaBwV.js} +4 -4
  56. package/core/built/admin/assets/activitypub/{copy-DIAOQoCZ.js → copy-DcOh8kXw.js} +2 -2
  57. package/core/built/admin/assets/activitypub/{domain-B3ihkPde.js → domain-fZ-X8i4-.js} +121 -121
  58. package/core/built/admin/assets/activitypub/{edit-profile-DsZM3rTX.js → edit-profile-BqMLQV88.js} +40 -40
  59. package/core/built/admin/assets/activitypub/{explore-BodNrZgR.js → explore-B4yPoP8E.js} +27 -27
  60. package/core/built/admin/assets/activitypub/{feed-PwH1iJ84.js → feed-BRC_mvAe.js} +51 -51
  61. package/core/built/admin/assets/activitypub/{field-D06-kmOJ.js → field-COacNgOt.js} +3 -3
  62. package/core/built/admin/assets/activitypub/{hash-Bm3WxYN4.js → hash-C7u-irQQ.js} +2 -2
  63. package/core/built/admin/assets/activitypub/inbox-BW-yvUoN.js +1284 -0
  64. package/core/built/admin/assets/activitypub/{inbox-d8oJRTf4.js → inbox-CbTTdDQ3.js} +2 -2
  65. package/core/built/admin/assets/activitypub/label-kPMmYI7l.js +16 -0
  66. package/core/built/admin/assets/activitypub/layout-BL4_jtuV.js +1 -0
  67. package/core/built/admin/assets/activitypub/{moderation-D1Yapsod.js → moderation-CuidJzc0.js} +91 -91
  68. package/core/built/admin/assets/activitypub/{note-C5zjqq5C.js → note-CAMRRSqD.js} +24 -24
  69. package/core/built/admin/assets/activitypub/{notifications-B9p8eCHD.js → notifications-BmNlXGgp.js} +51 -51
  70. package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-Bqg7fh_L.js} +2 -2
  71. package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-Dmun9jr_.js} +2 -2
  72. package/core/built/admin/assets/activitypub/{preferences-BCqUdC3v.js → preferences--oH19wf9.js} +1519 -1519
  73. package/core/built/admin/assets/activitypub/{profile-BRCWoFem.js → profile-DH_tQx2D.js} +185 -185
  74. package/core/built/admin/assets/activitypub/{reply-DYK5vVqb.js → reply-Cap9PxSH.js} +2 -2
  75. package/core/built/admin/assets/activitypub/{routes-BSXT992i.js → routes-DdyY9uFF.js} +744 -735
  76. package/core/built/admin/assets/activitypub/{separator-BbQqTm-p.js → separator-CAxxu8VV.js} +3 -3
  77. package/core/built/admin/assets/activitypub/settings-B6EEcVkW.js +315 -0
  78. package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-BYps63oh.js} +2 -2
  79. package/core/built/admin/assets/activitypub/{step-1-B-YfsVeO.js → step-1-CKjR2KAm.js} +6 -6
  80. package/core/built/admin/assets/activitypub/{step-2-DtPQzlTH.js → step-2-B6PKfOUQ.js} +6 -6
  81. package/core/built/admin/assets/activitypub/{step-3-D6BFMXL_.js → step-3-C-qBbcUo.js} +11 -11
  82. package/core/built/admin/assets/activitypub/{tabs-GpNecvfB.js → tabs-DLhZtVde.js} +306 -306
  83. package/core/built/admin/assets/activitypub/{topic-filter-BPDeQQys.js → topic-filter-DsUOuu0k.js} +3 -3
  84. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-BoVOxXkV.js → use-activity-pub-queries-CX9snsLs.js} +3 -3
  85. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Bmk5h4lW.js → use-navigate-with-base-path-DsJTGDSS.js} +988 -959
  86. package/core/built/admin/assets/activitypub/{use-reply-chain-data-wVBX7swM.js → use-reply-chain-data-AJi9zkzm.js} +30 -30
  87. package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-inweyKL5.js} +192 -164
  88. package/core/built/admin/assets/activitypub/{x-DbQZOLiI.js → x-DR8AT3-4.js} +2 -2
  89. package/core/built/admin/assets/add-integration-modal-BT_onDJy.js +1 -0
  90. package/core/built/admin/assets/add-newsletter-modal-Cx1kQpiY.js +1 -0
  91. package/core/built/admin/assets/add-recommendation-modal-B5nvAhvr.js +1 -0
  92. package/core/built/admin/assets/analytics-DjoJWPI7.js +1 -0
  93. package/core/built/admin/assets/{announcement-bar-modal-DM3cYOpo.js → announcement-bar-modal-Dwd0EGFP.js} +1 -1
  94. package/core/built/admin/assets/{api-keys-3-0vJC3Y.js → api-keys-BGPzLHzA.js} +1 -1
  95. package/core/built/admin/assets/{api-keys-BLm2NDBh.js → api-keys-BoeacM-s.js} +1 -1
  96. package/core/built/admin/assets/{audience-9mwU5TW6.js → audience-ceV3XVHq.js} +1 -1
  97. package/core/built/admin/assets/automated-emails-BLesE41L.js +1 -0
  98. package/core/built/admin/assets/{automations-sAcJ1334.js → automations-BN4u3GR8.js} +1 -1
  99. package/core/built/admin/assets/automations-C-ZTUwW3.js +1 -0
  100. package/core/built/admin/assets/bluesky-sharing-vzh-oPXL.js +1 -0
  101. package/core/built/admin/assets/{breadcrumb-DLiqCyFc.js → breadcrumb-CaLk2b7D.js} +1 -1
  102. package/core/built/admin/assets/{button-B2jcu6bk.js → button-Dvcv1QSR.js} +1 -1
  103. package/core/built/admin/assets/calendar-Bl9RLcZX.js +1 -0
  104. package/core/built/admin/assets/{chart-helpers-Fo3bUL3K.js → chart-helpers-FHywU0pj.js} +1 -1
  105. package/core/built/admin/assets/{checkbox-BfKktMph.js → checkbox-BtayFtjg.js} +1 -1
  106. package/core/built/admin/assets/chunk.254.035b85ec456ebbd7336b.js +440 -0
  107. package/core/built/admin/assets/{chunk.524.60ca4692d91c6022042f.js → chunk.524.e6975095fccdf22d90f8.js} +5 -5
  108. package/core/built/admin/assets/{chunk.582.525c7617c2d9e94c940a.js → chunk.582.98b485f9b2802f540897.js} +6 -6
  109. package/core/built/admin/assets/{chunk.492.f24d855d7e3f3aad261c.js → chunk.901.4ccc639821020230bcca.js} +9949 -7921
  110. package/core/built/admin/assets/{code-editor-view-DCQJxsfU.js → code-editor-view-C3ZfoF1X.js} +1 -1
  111. package/core/built/admin/assets/{code-editor-view-CYVu4EW6.js → code-editor-view-CAyRWy1s.js} +1 -1
  112. package/core/built/admin/assets/color-picker-G4kGR7rp.js +3 -0
  113. package/core/built/admin/assets/color-picker-field-DQFVTNnT.js +1 -0
  114. package/core/built/admin/assets/combobox-BnYzgEB4.js +1 -0
  115. package/core/built/admin/assets/command-C_vyTikI.js +1 -0
  116. package/core/built/admin/assets/comments-aBrxfnZf.js +1 -0
  117. package/core/built/admin/assets/{config-DOMQDZGZ.js → config-kSHvwdTG.js} +1 -1
  118. package/core/built/admin/assets/confirmation-context-DwXX_Y5h.js +1 -0
  119. package/core/built/admin/assets/{content-api-modal-CyQEC3fr.js → content-api-modal-D2G0nJP6.js} +1 -1
  120. package/core/built/admin/assets/context-menu-DOVB6yaz.js +1 -0
  121. package/core/built/admin/assets/{copy-field-B3M1s78L.js → copy-field-DCJwh9qf.js} +1 -1
  122. package/core/built/admin/assets/create-ghost-browse-value-source-5C53jJaX.js +1 -0
  123. package/core/built/admin/assets/custom-field-type-option-BAuW0F-E.js +1 -0
  124. package/core/built/admin/assets/custom-integration-modal-AbJGVyKc.js +1 -0
  125. package/core/built/admin/assets/{date-range-select-DD2RKkgB.js → date-range-select-BY3K-ukj.js} +1 -1
  126. package/core/built/admin/assets/design-and-theme-modal-BvEy4_pC.js +2 -0
  127. package/core/built/admin/assets/dirty-confirm-dialog-DVPuGz3U.js +1 -0
  128. package/core/built/admin/assets/{disabled-sources-indicator-Cvy47bE2.js → disabled-sources-indicator-Cy7Zp4c8.js} +1 -1
  129. package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
  130. package/core/built/admin/assets/domain-Dl61QGuk.js +1 -0
  131. package/core/built/admin/assets/dropzone-Dtz5Rmjt.js +5 -0
  132. package/core/built/admin/assets/edit-profile-DNJSMDwm.js +1 -0
  133. package/core/built/admin/assets/editor-DbAen9zf.js +8 -0
  134. package/core/built/admin/assets/editor-screen-BFWThIai.js +26 -0
  135. package/core/built/admin/assets/email-sending-status-context-CWDOD1FN.js +1 -0
  136. package/core/built/admin/assets/email-sending-status-provider-DCPkDICt.js +1 -0
  137. package/core/built/admin/assets/emails-vFMk4yYl.js +1 -0
  138. package/core/built/admin/assets/{embed-signup-form-modal-DeBMLxlL.js → embed-signup-form-modal-DGqsORxS.js} +1 -1
  139. package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
  140. package/core/built/admin/assets/explore-nnRr1Fja.js +1 -0
  141. package/core/built/admin/assets/feature-flag-overrides-context-DQjdJFAk.js +1 -0
  142. package/core/built/admin/assets/feature-image-placeholder-BrIHmPs8.js +1 -0
  143. package/core/built/admin/assets/feed-BNUcNu-W.js +1 -0
  144. package/core/built/admin/assets/feedback-DJ4Zb9rZ.js +1 -0
  145. package/core/built/admin/assets/{field-Cj8lmDOo.js → field-C93_Mg6j.js} +1 -1
  146. package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
  147. package/core/built/admin/assets/filter-sources-CGJb4C5r.js +1 -0
  148. package/core/built/admin/assets/filters--kKP-EC8.js +1 -0
  149. package/core/built/admin/assets/filters-DxA_a4FP.js +1 -0
  150. package/core/built/admin/assets/first-promoter-modal-BYDtrz2S.js +1 -0
  151. package/core/built/admin/assets/focus-koenig-editor-on-bottom-click-BbSnGOtK.js +1 -0
  152. package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8fd5bb799356bbefb254210ba7e1236d.css} +1 -1
  153. package/core/built/admin/assets/{ghost-3894eedcc6968f658578c0abfe942aab.js → ghost-b4e8a403baba61905cd7560e30b9732d.js} +63 -44
  154. package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-cac0cb2d5bb78e9bd14d8d1c2768ed45.css} +1 -1
  155. package/core/built/admin/assets/gift-link-modal-B7u5bD4e.js +1 -0
  156. package/core/built/admin/assets/{gift-links-DLDS7ljO.js → gift-links-CfLSnst2.js} +1 -1
  157. package/core/built/admin/assets/{growth-D6mhcx3q.js → growth-Cd1uO9d2.js} +1 -1
  158. package/core/built/admin/assets/growth-aG32xfdE.js +3 -0
  159. package/core/built/admin/assets/history-modal-Df8lW8h-.js +1 -0
  160. package/core/built/admin/assets/hooks-Cy_-oZ4o.js +2 -0
  161. package/core/built/admin/assets/{html-field-C8qVGGC1.js → html-field-DA4eU7eq.js} +1 -1
  162. package/core/built/admin/assets/{images-h8VZEQ9k.js → images-KXmyO3Ss.js} +1 -1
  163. package/core/built/admin/assets/{inbox-BYd1M06Q.js → inbox-gJHG7_xd.js} +14 -14
  164. package/core/built/admin/assets/index-BHHXtR5C.css +2 -0
  165. package/core/built/admin/assets/index-CgMCwsxN.js +4 -0
  166. package/core/built/admin/assets/index.es-CY6-yuw9.js +1 -0
  167. package/core/built/admin/assets/{input-group-D8sCXRF5.js → input-group-BE8rM2y1.js} +1 -1
  168. package/core/built/admin/assets/{integrations-Bjbu86Z0.js → integrations-B4kuRBFY.js} +1 -1
  169. package/core/built/admin/assets/invite-user-modal-B4CuNcx4.js +1 -0
  170. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
  171. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
  172. package/core/built/admin/assets/koenig-lexical/style.css +1 -1
  173. package/core/built/admin/assets/{koenig-lexical-_-IsVI7E.js → koenig-lexical-CGXb0F8o.js} +3 -3
  174. package/core/built/admin/assets/koenig-loader-BeM5rFPX.js +2 -0
  175. package/core/built/admin/assets/{kpi-card-DZQk_0W8.js → kpi-card-B21aToe8.js} +1 -1
  176. package/core/built/admin/assets/{kpi-card-DW_2y3ug.js → kpi-card-pz6Wv4Ae.js} +1 -1
  177. package/core/built/admin/assets/{kpi-helpers-PueTKuA6.js → kpi-helpers-Dq5jelmP.js} +1 -1
  178. package/core/built/admin/assets/{kpi-tabs-CojDs-Qz.js → kpi-tabs-DEZHpKUt.js} +1 -1
  179. package/core/built/admin/assets/{label-DjbT91GM.js → label-OLCzze8N.js} +1 -1
  180. package/core/built/admin/assets/label-picker-BigOvMPV.js +1 -0
  181. package/core/built/admin/assets/{labels-CH3Kn8RV.js → labels-Dr0SgUQD.js} +1 -1
  182. package/core/built/admin/assets/layout-DUTL8SH5.js +1 -0
  183. package/core/built/admin/assets/lib-7QPTI0FS.js +1 -0
  184. package/core/built/admin/assets/link-helpers-BRAg9SCj.js +1 -0
  185. package/core/built/admin/assets/links-BDHPTlyj.js +1 -0
  186. package/core/built/admin/assets/member-custom-fields-TRTHCAz9.js +1 -0
  187. package/core/built/admin/assets/member-detail-b6dRwc3C.js +1 -0
  188. package/core/built/admin/assets/members-Czt5lJSc.js +4 -0
  189. package/core/built/admin/assets/moderation-ZWefD9uH.js +1 -0
  190. package/core/built/admin/assets/{multi-select-combobox-B6LiRzDO.js → multi-select-combobox-CT13MTo-.js} +1 -1
  191. package/core/built/admin/assets/navigation-modal-C8FEhBK5.js +1 -0
  192. package/core/built/admin/assets/newsletter-5VYW4RyJ.js +1 -0
  193. package/core/built/admin/assets/newsletter-detail-modal-ChjC0ZqH.js +1 -0
  194. package/core/built/admin/assets/{newsletter-emails-CFeLlt4z.js → newsletter-emails-DZH6I-PY.js} +1 -1
  195. package/core/built/admin/assets/newsletters-DOC9KBcX.js +1 -0
  196. package/core/built/admin/assets/newsletters-Rq1M3GD-.js +1 -0
  197. package/core/built/admin/assets/note-DIV-Pojr.js +1 -0
  198. package/core/built/admin/assets/notifications-s20-H49V.js +1 -0
  199. package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
  200. package/core/built/admin/assets/{offers-9J1CSiLy.js → offers--e2nGvkW.js} +1 -1
  201. package/core/built/admin/assets/offers-container-modal-BmG5M5Tv.js +1 -0
  202. package/core/built/admin/assets/onboarding-CUuy9unR.js +1 -0
  203. package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-pXyct0Jm.js} +1 -1
  204. package/core/built/admin/assets/{onboarding-route-Dmc4IPm3.js → onboarding-route-CK4pcXoR.js} +1 -1
  205. package/core/built/admin/assets/overview-CaPsciMs.js +1 -0
  206. package/core/built/admin/assets/overview-a8GfcsKX.js +1 -0
  207. package/core/built/admin/assets/{page-header-BR_nbIPp.js → page-header-DM_KyoFI.js} +1 -1
  208. package/core/built/admin/assets/pagemenu-vgZVUVKR.js +1 -0
  209. package/core/built/admin/assets/pages-CjDY2CBI.js +1 -0
  210. package/core/built/admin/assets/pages-route-BzKZYdV5.js +1 -0
  211. package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
  212. package/core/built/admin/assets/{pintura-modal-BR9hEvS8.js → pintura-modal-DExCF1ii.js} +1 -1
  213. package/core/built/admin/assets/portal-frame-Cqanidq4.js +1 -0
  214. package/core/built/admin/assets/portal-modal-oinBgA27.js +1 -0
  215. package/core/built/admin/assets/post-analytics-C5oJ1dWV.js +1 -0
  216. package/core/built/admin/assets/post-analytics-header-OATo3X_r.js +1 -0
  217. package/core/built/admin/assets/post-analytics-provider-tOpIVGT5.js +1 -0
  218. package/core/built/admin/assets/post-helpers-C88JBa4D.js +1 -0
  219. package/core/built/admin/assets/post-share-modal-DvhC1XgV.js +1 -0
  220. package/core/built/admin/assets/post-utils-DKF4mfuo.js +1 -0
  221. package/core/built/admin/assets/posts-list-screen-o4ZjbgS3.js +2 -0
  222. package/core/built/admin/assets/posts-pCPrhQeR.js +1 -0
  223. package/core/built/admin/assets/posts-route-9F--xdIb.js +1 -0
  224. package/core/built/admin/assets/preferences--vNubsqD.js +5 -0
  225. package/core/built/admin/assets/{preview-modal-C-BL-F9k.js → preview-modal-YYbzlYdO.js} +1 -1
  226. package/core/built/admin/assets/profile-BllKV3dR.js +1 -0
  227. package/core/built/admin/assets/{radio-group-Bgz60i81.js → radio-group-DL8GI8rt.js} +1 -1
  228. package/core/built/admin/assets/{referrers-CnhCMWCs.js → referrers-D8oHPmDB.js} +1 -1
  229. package/core/built/admin/assets/router-provider-BSvTXgZY.js +1 -0
  230. package/core/built/admin/assets/schemas-BoYdB6YU.js +64 -0
  231. package/core/built/admin/assets/select-v5YbA3Mw.js +1 -0
  232. package/core/built/admin/assets/settings-PEsZupw1.js +4 -0
  233. package/core/built/admin/assets/{settings-breadcrumbs-CyP_9zTo.js → settings-breadcrumbs-NwPnCTC7.js} +1 -1
  234. package/core/built/admin/assets/settings-u_s1CRkr.js +1 -0
  235. package/core/built/admin/assets/share-modal-SskCmVGL.js +1 -0
  236. package/core/built/admin/assets/slack-modal-XxSJiYgo.js +1 -0
  237. package/core/built/admin/assets/{sort-button-Cc-Z96sA.js → sort-button-Cx1KtINE.js} +1 -1
  238. package/core/built/admin/assets/{source-icon-v6PUnmyM.js → source-icon-Bdp9Im_5.js} +1 -1
  239. package/core/built/admin/assets/stats-D9PDLS3x.js +1 -0
  240. package/core/built/admin/assets/stats-view-W2g6Jsd-.js +1 -0
  241. package/core/built/admin/assets/{step-1-DSRp2vBj.js → step-1-BQYzvBzr.js} +1 -1
  242. package/core/built/admin/assets/{step-2-COqv2g0u.js → step-2-xES32xJV.js} +1 -1
  243. package/core/built/admin/assets/{step-3-6W1NMVQc.js → step-3-DA_XK5kW.js} +2 -2
  244. package/core/built/admin/assets/{stripe-button-D2K42Uty.js → stripe-button-CVsLHelt.js} +1 -1
  245. package/core/built/admin/assets/stripe-connect-modal-ClmLOMGS.js +1 -0
  246. package/core/built/admin/assets/style-Wd9nQubI.css +1 -0
  247. package/core/built/admin/assets/{table-B2pIKjVh.js → table-BenqVupI.js} +1 -1
  248. package/core/built/admin/assets/{tabs-SaW_UT-Q.js → tabs-eBBlxPp8.js} +1 -1
  249. package/core/built/admin/assets/tag-detail-Ce8Se2qd.js +2 -0
  250. package/core/built/admin/assets/tag-picker-C3UR-uJ-.js +1 -0
  251. package/core/built/admin/assets/tags-B-kJxCs7.js +1 -0
  252. package/core/built/admin/assets/{tags-zTFiKRpb.js → tags-ChfdwJyS.js} +1 -1
  253. package/core/built/admin/assets/testimonials-modal-9Q6fT06V.js +1 -0
  254. package/core/built/admin/assets/tier-detail-modal-CDyYdqK7.js +1 -0
  255. package/core/built/admin/assets/tiers-BCpIOGQr.js +1 -0
  256. package/core/built/admin/assets/{toggle-group-EM9WpESu.js → toggle-group-CviIkyok.js} +1 -1
  257. package/core/built/admin/assets/{topic-filter-DY4gNHn2.js → topic-filter-I2jCBGxm.js} +1 -1
  258. package/core/built/admin/assets/{transistor-modal-CpyPG-MH.js → transistor-modal-p53u3W8y.js} +1 -1
  259. package/core/built/admin/assets/{trend-badge-ByMkuAuH.js → trend-badge-CideVzQd.js} +1 -1
  260. package/core/built/admin/assets/{unsplash-modal-Cv2Q6GtY.js → unsplash-modal-DY8UcKcE.js} +1 -1
  261. package/core/built/admin/assets/{use-analytics-data-CHvjMYuT.js → use-analytics-data-DAIGcr2f.js} +1 -1
  262. package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
  263. package/core/built/admin/assets/{use-check-theme-limit-error-Qv4SVXqw.js → use-check-theme-limit-error-DRUjK4YM.js} +1 -1
  264. package/core/built/admin/assets/use-filter-params-JkZhIS8L.js +1 -0
  265. package/core/built/admin/assets/{use-filterable-api-CzXcpUh8.js → use-filterable-api-BVEVMrhZ.js} +1 -1
  266. package/core/built/admin/assets/use-growth-stats-937CUj6j.js +1 -0
  267. package/core/built/admin/assets/use-host-limits-D0Dv3tKA.js +1 -0
  268. package/core/built/admin/assets/{use-limiter-cwJvsNBo.js → use-limiter-CohWfzvK.js} +1 -1
  269. package/core/built/admin/assets/{use-navigate-with-base-path-BHPA228f.js → use-navigate-with-base-path-BkxcPj5l.js} +1 -1
  270. package/core/built/admin/assets/use-pintura-config-xgytjU35.js +1 -0
  271. package/core/built/admin/assets/{use-pintura-editor-BDBXWUYq.js → use-pintura-editor-CaV1mbfO.js} +1 -1
  272. package/core/built/admin/assets/{use-post-referrers-DbY-mzci.js → use-post-referrers-BCQI7fDg.js} +1 -1
  273. package/core/built/admin/assets/use-reply-chain-data-CYRhoaxY.js +1 -0
  274. package/core/built/admin/assets/{use-router-history-entry-Bg6BhBQQ.js → use-router-history-entry-NOKcd--l.js} +1 -1
  275. package/core/built/admin/assets/{use-setting-group-VM7FQwMY.js → use-setting-group-bLKMwoBT.js} +1 -1
  276. package/core/built/admin/assets/use-settings-navigation-B-qrriKD.js +1 -0
  277. package/core/built/admin/assets/{use-simple-pagination-Dum6Irbs.js → use-simple-pagination-CNPd6Rf6.js} +1 -1
  278. package/core/built/admin/assets/use-staff-users-pRIMIyiW.js +1 -0
  279. package/core/built/admin/assets/use-tinybird-query-CmdbCS9X.js +1 -0
  280. package/core/built/admin/assets/use-tinybird-token-KLne235s.js +1 -0
  281. package/core/built/admin/assets/{use-unsaved-changes-guard-BAy0RANR.js → use-unsaved-changes-guard-7-ug0JdH.js} +1 -1
  282. package/core/built/admin/assets/use-upgrade-route-Dm_qqKr0.js +1 -0
  283. package/core/built/admin/assets/{use-url-input-Df5QzNa7.js → use-url-input-fvp-TpPx.js} +1 -1
  284. package/core/built/admin/assets/user-detail-modal-D3KlGYv-.js +1 -0
  285. package/core/built/admin/assets/users-DVNWrqg9.js +1 -0
  286. package/core/built/admin/assets/{vendor-5753232c7d6ffb3c44e1eb0a02133953.js → vendor-2dd263291938d407802568d3357ec69e.js} +19 -17
  287. package/core/built/admin/assets/{virtual-list-DEx8WgiO.js → virtual-list-CZ3RK2Yf.js} +1 -1
  288. package/core/built/admin/assets/web-ClEJsCAj.js +2 -0
  289. package/core/built/admin/assets/web-X9rdnrtq.js +1 -0
  290. package/core/built/admin/assets/{zapier-modal-Cw3BTBUu.js → zapier-modal-DfVhV17j.js} +1 -1
  291. package/core/built/admin/index.html +23 -27
  292. package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
  293. package/core/frontend/helpers/cancel_link.js +2 -2
  294. package/core/frontend/helpers/pagination.js +2 -2
  295. package/core/frontend/helpers/social_accounts.js +2 -2
  296. package/core/frontend/public/ghost.css +1 -1
  297. package/core/frontend/public/ghost.min.css +1 -1
  298. package/core/frontend/services/sitemap/user-map-generator.js +9 -2
  299. package/core/server/adapters/jobs/InMemoryJobsBackend.js +74 -29
  300. package/core/server/api/endpoints/authentication.js +1 -2
  301. package/core/server/api/endpoints/authors-public.js +15 -5
  302. package/core/server/api/endpoints/emails.js +13 -0
  303. package/core/server/api/endpoints/index.js +10 -2
  304. package/core/server/api/endpoints/mail.js +1 -1
  305. package/core/server/api/endpoints/member-metafields-members.js +23 -0
  306. package/core/server/api/endpoints/member-metafields.js +102 -0
  307. package/core/server/api/endpoints/members-account.js +42 -0
  308. package/core/server/api/endpoints/members.js +4 -4
  309. package/core/server/api/endpoints/newsletters-public.js +10 -1
  310. package/core/server/api/endpoints/pages-public.js +15 -5
  311. package/core/server/api/endpoints/posts-public.js +15 -5
  312. package/core/server/api/endpoints/posts.js +3 -3
  313. package/core/server/api/endpoints/tags-public.js +22 -3
  314. package/core/server/api/endpoints/tiers-checkout-config.js +2 -2
  315. package/core/server/api/endpoints/tiers-public.js +38 -1
  316. package/core/server/api/endpoints/users.js +2 -2
  317. package/core/server/api/endpoints/utils/api-filter-utils.js +170 -3
  318. package/core/server/api/endpoints/utils/public-cache-keys.js +3 -0
  319. package/core/server/api/endpoints/utils/serializers/input/authors.js +2 -0
  320. package/core/server/api/endpoints/utils/serializers/input/members.js +20 -9
  321. package/core/server/api/endpoints/utils/serializers/input/pages.js +2 -0
  322. package/core/server/api/endpoints/utils/serializers/input/posts.js +2 -0
  323. package/core/server/api/endpoints/utils/serializers/input/tags.js +2 -0
  324. package/core/server/api/endpoints/utils/serializers/output/emails.js +7 -0
  325. package/core/server/api/endpoints/utils/serializers/output/index.js +6 -2
  326. package/core/server/api/endpoints/utils/serializers/output/member-metafields.js +18 -0
  327. package/core/server/api/endpoints/utils/serializers/output/members-account.js +19 -0
  328. package/core/server/api/endpoints/utils/serializers/output/members-csv-transform.js +1 -1
  329. package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
  330. package/core/server/api/endpoints/utils/serializers/output/tiers.js +10 -2
  331. package/core/server/api/endpoints/utils/serializers/output/users.js +0 -10
  332. package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
  333. package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
  334. package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
  335. package/core/server/data/exporter/table-lists.js +3 -3
  336. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  337. package/core/server/data/migrations/utils/migrations.js +1 -1
  338. package/core/server/data/migrations/versions/6.53/2026-07-15-20-22-53-add-members-custom-field-values.js +1 -1
  339. package/core/server/data/migrations/versions/6.57/2026-08-04-18-00-00-store-custom-field-values-as-leaf-rows.js +10 -1
  340. package/core/server/data/migrations/versions/6.63/2026-09-03-10-07-03-rename-custom-field-tables-to-metafields.js +169 -0
  341. package/core/server/data/migrations/versions/6.63/2026-09-03-11-03-31-remove-member-custom-field-read-permissions.js +30 -0
  342. package/core/server/data/schema/fixtures/fixtures.json +0 -11
  343. package/core/server/data/schema/lib/default-index-name.js +8 -11
  344. package/core/server/data/schema/schema.js +18 -18
  345. package/core/server/data/seeders/README.md +48 -0
  346. package/core/server/data/tinybird/pipes/mv_hits.pipe +86 -50
  347. package/core/server/lib/db-types/count.js +16 -0
  348. package/core/server/lib/image/image-size.js +24 -0
  349. package/core/server/lib/package-json/parse.js +2 -2
  350. package/core/server/lib/validate-password.js +81 -120
  351. package/core/server/models/action.js +4 -4
  352. package/core/server/models/base/plugins/filtered-collection.js +16 -0
  353. package/core/server/models/member.js +10 -21
  354. package/core/server/models/post.js +2 -2
  355. package/core/server/models/relations/authors.js +2 -16
  356. package/core/server/models/user.js +10 -3
  357. package/core/server/services/auth/passwordreset.js +13 -0
  358. package/core/server/services/automations/automations-api.js +1 -1
  359. package/core/server/services/automations/database-automations-repository.js +11 -4
  360. package/core/server/services/comments/comments-controller.js +30 -9
  361. package/core/server/services/comments/comments-service.js +55 -5
  362. package/core/server/services/content-import/csv/formula.js +12 -0
  363. package/core/server/services/content-import/csv/index.js +6 -1
  364. package/core/server/services/content-import/csv/parse.js +27 -6
  365. package/core/server/services/content-import/csv/serialize.js +13 -0
  366. package/core/server/services/content-import/import/completion-email.js +164 -0
  367. package/core/server/services/content-import/import/errors-file.js +36 -0
  368. package/core/server/services/content-import/import/importer.js +160 -53
  369. package/core/server/services/content-import/import/local-media-url.js +63 -0
  370. package/core/server/services/content-import/import/media.js +254 -0
  371. package/core/server/services/content-import/import/post-data.js +0 -1
  372. package/core/server/services/content-import/import/post-link.js +11 -0
  373. package/core/server/services/content-import/import/post-repository.js +25 -3
  374. package/core/server/services/content-import/import/reader.js +9 -2
  375. package/core/server/services/content-import/import/report.js +34 -0
  376. package/core/server/services/content-import/import/row.js +0 -2
  377. package/core/server/services/content-import/import/schema.js +1 -0
  378. package/core/server/services/content-import/import/staged-file.js +29 -0
  379. package/core/server/services/content-import/import/store.js +25 -2
  380. package/core/server/services/content-import/index.js +52 -6
  381. package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
  382. package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
  383. package/core/server/services/custom-redirects/redirects-service.js +1 -1
  384. package/core/server/services/custom-redirects/validation.js +1 -1
  385. package/core/server/services/email-address/email-address-parser.js +30 -38
  386. package/core/server/services/email-address/email-address-service.js +37 -4
  387. package/core/server/services/email-analytics/index.js +2 -7
  388. package/core/server/services/email-service/CONTEXT.md +37 -0
  389. package/core/server/services/email-service/README.md +42 -0
  390. package/core/server/services/email-service/batch-sending-service.js +2 -4
  391. package/core/server/services/email-service/email-controller.js +18 -2
  392. package/core/server/services/email-service/email-renderer.js +14 -4
  393. package/core/server/services/email-service/email-service-wrapper.js +3 -9
  394. package/core/server/services/email-service/mailgun-email-provider.js +20 -9
  395. package/core/server/services/email-service/sending-status-schema.js +21 -0
  396. package/core/server/services/email-service/sending-status-serializers.js +33 -0
  397. package/core/server/services/email-service/sending-status-service.js +47 -0
  398. package/core/server/services/email-service/sending-status.js +111 -0
  399. package/core/server/services/email-suppression-list/email-suppression-list.js +0 -33
  400. package/core/server/services/email-suppression-list/mailgun-email-suppression-list.js +6 -7
  401. package/core/server/services/gifts/README.md +2 -2
  402. package/core/server/services/gifts/constants.js +1 -1
  403. package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
  404. package/core/server/services/gifts/gift-email-service.js +0 -1
  405. package/core/server/services/gifts/gift-service.js +19 -57
  406. package/core/server/services/gifts/index.js +3 -5
  407. package/core/server/services/gifts/jobs/index.js +4 -4
  408. package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
  409. package/core/server/services/invitations/accept.js +4 -2
  410. package/core/server/services/jobs/job-service.js +0 -9
  411. package/core/server/services/jobs-service/index.js +8 -0
  412. package/core/server/services/jobs-service/jobs-service.js +52 -3
  413. package/core/server/services/jobs-service/register-job-handlers.js +32 -11
  414. package/core/server/services/mail/ghost-mailer.js +4 -4
  415. package/core/server/services/member-welcome-emails/service.js +7 -7
  416. package/core/server/services/members/account-service.js +98 -0
  417. package/core/server/services/members/api.js +4 -3
  418. package/core/server/services/members/import-export/csv/parse.js +0 -7
  419. package/core/server/services/members/import-export/export/exporter.js +20 -20
  420. package/core/server/services/members/import-export/import/completion-email.js +8 -11
  421. package/core/server/services/members/import-export/import/importer.js +13 -13
  422. package/core/server/services/members/import-export/import/row.js +0 -3
  423. package/core/server/services/members/import-export/index.js +10 -17
  424. package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
  425. package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
  426. package/core/server/services/members/jobs/index.js +48 -24
  427. package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
  428. package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
  429. package/core/server/services/members/members-api/members-api.js +26 -8
  430. package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
  431. package/core/server/services/members/members-api/repositories/member-repository.js +4 -4
  432. package/core/server/services/members/members-api/services/member-bread-service.js +62 -84
  433. package/core/server/services/members/members-api/services/payments-service.js +1 -1
  434. package/core/server/services/members/members-ssr.js +18 -0
  435. package/core/server/services/members/middleware.js +95 -81
  436. package/core/server/services/members/service.js +71 -47
  437. package/core/server/services/members/utils.js +9 -0
  438. package/core/server/services/members-metafields/access.js +28 -0
  439. package/core/server/services/{members-custom-fields → members-metafields}/actions.js +5 -5
  440. package/core/server/services/members-metafields/bindings-service.js +147 -0
  441. package/core/server/services/members-metafields/codec.js +14 -0
  442. package/core/server/services/{members-custom-fields → members-metafields}/config.js +1 -1
  443. package/core/server/services/{members-custom-fields → members-metafields}/definitions-service.js +68 -22
  444. package/core/server/services/members-metafields/filter.js +181 -0
  445. package/core/server/services/{members-custom-fields → members-metafields}/index.js +16 -7
  446. package/core/server/services/{members-custom-fields → members-metafields}/key.js +2 -1
  447. package/core/server/services/{members-custom-fields → members-metafields}/models.js +5 -5
  448. package/core/server/services/members-metafields/namespaces.js +34 -0
  449. package/core/server/services/{members-custom-fields → members-metafields}/queries.js +1 -1
  450. package/core/server/services/{members-custom-fields → members-metafields}/schema.js +16 -12
  451. package/core/server/services/members-metafields/serializers.js +22 -0
  452. package/core/server/services/{members-custom-fields → members-metafields}/values-service.js +80 -48
  453. package/core/server/services/mentions/mention-controller.js +23 -21
  454. package/core/server/services/mentions/mention-sending-service.js +26 -9
  455. package/core/server/services/mentions/process-webmention-job.js +16 -0
  456. package/core/server/services/mentions/send-webmentions-job.js +18 -0
  457. package/core/server/services/mentions/service.js +7 -33
  458. package/core/server/services/route-settings/validation-errors.js +1 -1
  459. package/core/server/services/route-settings/yaml-parser.js +1 -1
  460. package/core/server/services/settings/settings-service.js +1 -8
  461. package/core/server/services/settings-helpers/settings-helpers.js +4 -6
  462. package/core/server/services/slack-ping/slack-ping-service.js +1 -1
  463. package/core/server/services/staff/staff-service-emails.js +2 -2
  464. package/core/server/services/stripe/config.js +14 -8
  465. package/core/server/services/stripe/service.js +10 -1
  466. package/core/server/services/stripe/services/checkout/completed-session.js +2 -2
  467. package/core/server/services/stripe/services/checkout/session-options.js +18 -15
  468. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +28 -7
  469. package/core/server/services/stripe/stripe-api.js +2 -0
  470. package/core/server/services/stripe/stripe-service.js +24 -14
  471. package/core/server/services/stripe/webhook-controller.js +10 -0
  472. package/core/server/services/tier-checkout-config/codec.js +11 -7
  473. package/core/server/services/tier-checkout-config/index.js +2 -1
  474. package/core/server/services/tier-checkout-config/models.js +11 -5
  475. package/core/server/services/tier-checkout-config/queries.js +12 -12
  476. package/core/server/services/tier-checkout-config/serializers.js +73 -10
  477. package/core/server/services/tier-checkout-config/service.js +14 -13
  478. package/core/server/services/tiers/service.js +3 -3
  479. package/core/server/services/update-check/index.js +13 -13
  480. package/core/server/services/update-check/jobs/update-check-job.js +7 -0
  481. package/core/server/services/update-check/update-check-service.js +2 -2
  482. package/core/server/services/url/router-filter.js +8 -10
  483. package/core/server/services/users.js +1 -19
  484. package/core/server/web/admin/controller.js +1 -1
  485. package/core/server/web/api/endpoints/admin/routes.js +20 -16
  486. package/core/server/web/members/account/index.js +2 -0
  487. package/core/server/web/members/account/routes.js +46 -0
  488. package/core/server/web/members/app.js +4 -18
  489. package/core/shared/config/defaults.json +1 -1
  490. package/core/shared/config/env/config.testing-mysql.json +1 -1
  491. package/core/shared/labs.js +7 -2
  492. package/package.json +42 -41
  493. package/pnpm-lock.yaml +1159 -582
  494. package/pnpm-workspace.yaml +18 -15
  495. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  496. package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
  497. package/core/built/admin/assets/Combination-5fYEzgbs.js +0 -41
  498. package/core/built/admin/assets/account-migration-DRhAehfw.js +0 -1
  499. package/core/built/admin/assets/activitypub/inbox-BluD2ucT.js +0 -1284
  500. package/core/built/admin/assets/activitypub/label-FHSh6ZAw.js +0 -16
  501. package/core/built/admin/assets/activitypub/layout-Cq4NG0Xr.js +0 -1
  502. package/core/built/admin/assets/activitypub/settings-DQDkr06X.js +0 -315
  503. package/core/built/admin/assets/add-integration-modal-BC0jExDZ.js +0 -1
  504. package/core/built/admin/assets/add-newsletter-modal-DchTkA7l.js +0 -1
  505. package/core/built/admin/assets/add-recommendation-modal-DMvaJZKp.js +0 -1
  506. package/core/built/admin/assets/alert-dialog-QhXzdHfc.js +0 -1
  507. package/core/built/admin/assets/analytics-No1DDY3A.js +0 -1
  508. package/core/built/admin/assets/automated-emails-te1D5kq-.js +0 -1
  509. package/core/built/admin/assets/automations-DpUNUdcZ.js +0 -1
  510. package/core/built/admin/assets/bluesky-sharing-Cjrv_f62.js +0 -1
  511. package/core/built/admin/assets/chunk.896.435fe0637944d4a69810.js +0 -366
  512. package/core/built/admin/assets/color-picker-BTY_NdEm.js +0 -3
  513. package/core/built/admin/assets/color-picker-field-CPlkzOH0.js +0 -1
  514. package/core/built/admin/assets/combobox-DrMtv_4P.js +0 -1
  515. package/core/built/admin/assets/command-ZdgYJpoI.js +0 -1
  516. package/core/built/admin/assets/comments-kidj60-h.js +0 -1
  517. package/core/built/admin/assets/confirmation-context-BhbmQQEl.js +0 -1
  518. package/core/built/admin/assets/custom-field-type-option-CsGIZk1J.js +0 -10
  519. package/core/built/admin/assets/custom-integration-modal-BY37O_9X.js +0 -1
  520. package/core/built/admin/assets/design-and-theme-modal-DUSKM4uC.js +0 -22
  521. package/core/built/admin/assets/dialog-B44iRwlc.js +0 -1
  522. package/core/built/admin/assets/dirty-confirm-dialog-BxgQgQ6H.js +0 -1
  523. package/core/built/admin/assets/dist-Cy8tfrp_.js +0 -1
  524. package/core/built/admin/assets/domain-Ca6KhoQt.js +0 -1
  525. package/core/built/admin/assets/dropzone-Bb-5zQTk.js +0 -5
  526. package/core/built/admin/assets/edit-profile-BdupLlus.js +0 -1
  527. package/core/built/admin/assets/editor-BP883Lpn.js +0 -8
  528. package/core/built/admin/assets/explore-FB-CimXw.js +0 -1
  529. package/core/built/admin/assets/feed-C1GxsmI2.js +0 -1
  530. package/core/built/admin/assets/filter-sources-D5n5bFA2.js +0 -1
  531. package/core/built/admin/assets/filters-DJEzkMUK.js +0 -1
  532. package/core/built/admin/assets/filters-MZXvdH5D.js +0 -1
  533. package/core/built/admin/assets/first-promoter-modal-CGTGLCr5.js +0 -1
  534. package/core/built/admin/assets/gift-link-modal-B6v0tnRN.js +0 -1
  535. package/core/built/admin/assets/growth-BGAJD1rs.js +0 -3
  536. package/core/built/admin/assets/history-modal-iKwUY3XR.js +0 -1
  537. package/core/built/admin/assets/hooks-CuEZV2-q.js +0 -2
  538. package/core/built/admin/assets/index-DjQe-e5s.js +0 -4
  539. package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
  540. package/core/built/admin/assets/index.es-VihPwfeH.js +0 -1
  541. package/core/built/admin/assets/input--W-rCTrX.js +0 -1
  542. package/core/built/admin/assets/invite-user-modal-MdImLCaJ.js +0 -1
  543. package/core/built/admin/assets/koenig-loader-DYZpm6El.js +0 -2
  544. package/core/built/admin/assets/label-picker-cB51xl1r.js +0 -1
  545. package/core/built/admin/assets/layout-c_B_1hax.js +0 -1
  546. package/core/built/admin/assets/link-helpers-MVDdnFCY.js +0 -1
  547. package/core/built/admin/assets/loading-indicator-BpFWTVgh.js +0 -1
  548. package/core/built/admin/assets/member-custom-fields-qs0dIkxM.js +0 -1
  549. package/core/built/admin/assets/member-detail-B6uec2a6.js +0 -1
  550. package/core/built/admin/assets/members-BQF3CqhI.js +0 -2
  551. package/core/built/admin/assets/moderation-DY4wF1Q3.js +0 -1
  552. package/core/built/admin/assets/navigation-modal-DX-gNF3X.js +0 -1
  553. package/core/built/admin/assets/newsletter-CyQA7m3m.js +0 -1
  554. package/core/built/admin/assets/newsletter-detail-modal-BDrptuxn.js +0 -1
  555. package/core/built/admin/assets/newsletters-DXuNmC42.js +0 -1
  556. package/core/built/admin/assets/newsletters-DhNigJUh.js +0 -1
  557. package/core/built/admin/assets/note-Cgo2LCJ6.js +0 -1
  558. package/core/built/admin/assets/notifications-BC50AMku.js +0 -1
  559. package/core/built/admin/assets/offers-container-modal-DWycIMzT.js +0 -1
  560. package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
  561. package/core/built/admin/assets/overview-CVbFtn-k.js +0 -1
  562. package/core/built/admin/assets/overview-YKj7SZaK.js +0 -1
  563. package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
  564. package/core/built/admin/assets/popover-CCy0h5rq.js +0 -1
  565. package/core/built/admin/assets/portal-frame-dc4XKr0e.js +0 -1
  566. package/core/built/admin/assets/portal-modal-BvvdF_B9.js +0 -1
  567. package/core/built/admin/assets/post-analytics-DX470WRG.js +0 -1
  568. package/core/built/admin/assets/post-analytics-header-CXpJmdDv.js +0 -1
  569. package/core/built/admin/assets/post-analytics-provider-CLfKGWZy.js +0 -1
  570. package/core/built/admin/assets/post-helpers-C5OQMBoi.js +0 -1
  571. package/core/built/admin/assets/post-share-modal-Cl0NXRJr.js +0 -1
  572. package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
  573. package/core/built/admin/assets/preferences-DO0UUWFp.js +0 -5
  574. package/core/built/admin/assets/profile-CxT-0l4d.js +0 -1
  575. package/core/built/admin/assets/router-provider-B0gZyiGJ.js +0 -1
  576. package/core/built/admin/assets/schemas-4UPic-oD.js +0 -64
  577. package/core/built/admin/assets/select-DuDUFdPq.js +0 -1
  578. package/core/built/admin/assets/settings-BjCii7BM.js +0 -1
  579. package/core/built/admin/assets/settings-b8kNzZSQ.js +0 -4
  580. package/core/built/admin/assets/share-modal-BV70mr9k.js +0 -1
  581. package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
  582. package/core/built/admin/assets/slack-modal-Be2_KK-z.js +0 -1
  583. package/core/built/admin/assets/stats-C4reGh9O.js +0 -1
  584. package/core/built/admin/assets/stats-view-DP9pQ62k.js +0 -1
  585. package/core/built/admin/assets/stripe-connect-modal-Z-UT_BGc.js +0 -1
  586. package/core/built/admin/assets/tag-detail-Dc0nTOtU.js +0 -2
  587. package/core/built/admin/assets/tags-BLaXBwnb.js +0 -1
  588. package/core/built/admin/assets/testimonials-modal-sFwRnNLh.js +0 -1
  589. package/core/built/admin/assets/tier-detail-modal-BCFpWwUS.js +0 -1
  590. package/core/built/admin/assets/tiers-Nd_z4BZY.js +0 -1
  591. package/core/built/admin/assets/use-filter-params-CAvfDvf1.js +0 -1
  592. package/core/built/admin/assets/use-growth-stats-D6mZXGhK.js +0 -1
  593. package/core/built/admin/assets/use-host-limits-DZtR08oa.js +0 -1
  594. package/core/built/admin/assets/use-pintura-config-CzTfnufz.js +0 -1
  595. package/core/built/admin/assets/use-reply-chain-data-BeQwz8oF.js +0 -1
  596. package/core/built/admin/assets/use-settings-navigation-BbrSUVcf.js +0 -1
  597. package/core/built/admin/assets/use-staff-users-cZg4ugOF.js +0 -1
  598. package/core/built/admin/assets/use-tinybird-query-B1IMyAcv.js +0 -39
  599. package/core/built/admin/assets/use-tinybird-token-Bow0Zwn8.js +0 -1
  600. package/core/built/admin/assets/use-upgrade-route-DhRSo7at.js +0 -1
  601. package/core/built/admin/assets/user-detail-modal-yipSoQfv.js +0 -1
  602. package/core/built/admin/assets/users-5msE1WMs.js +0 -1
  603. package/core/built/admin/assets/web-CKcXAu86.js +0 -1
  604. package/core/built/admin/assets/web-DR4TqM3E.js +0 -2
  605. package/core/server/api/endpoints/member-custom-fields.js +0 -90
  606. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +0 -20
  607. package/core/server/services/email-suppression-list/in-memory-email-suppression-list.js +0 -39
  608. package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
  609. package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
  610. package/core/server/services/members-custom-fields/bindings-service.js +0 -119
  611. package/core/server/services/members-custom-fields/codec.js +0 -15
  612. package/core/server/services/members-custom-fields/filter.js +0 -199
  613. package/core/server/services/members-custom-fields/serializers.js +0 -24
  614. package/core/server/services/stripe/services/checkout/allowed-countries.js +0 -267
  615. package/core/server/services/stripe/services/checkout/field-ports.js +0 -34
  616. package/core/server/services/tier-checkout-config/destinations.js +0 -17
  617. package/core/server/services/update-check/run-update-check.js +0 -63
  618. /package/core/built/admin/assets/{chunk.492.f24d855d7e3f3aad261c.js.LICENSE.txt → chunk.901.4ccc639821020230bcca.js.LICENSE.txt} +0 -0
  619. /package/core/server/services/{members-custom-fields → members-metafields}/storage.js +0 -0
@@ -3,13 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.CustomFieldDefinitionsService = void 0;
6
+ exports.MetafieldDefinitionsService = void 0;
7
7
  const bson_objectid_1 = __importDefault(require("bson-objectid"));
8
8
  const errors_1 = __importDefault(require("@tryghost/errors"));
9
9
  const zod_1 = require("zod");
10
- const custom_field_types_1 = require("@tryghost/custom-field-types");
10
+ const metafield_types_1 = require("@tryghost/metafield-types");
11
+ const identity_1 = require("@tryghost/metafield-types/identity");
11
12
  const codec_1 = require("./codec");
13
+ const namespaces_1 = require("./namespaces");
12
14
  const schema_1 = require("./schema");
15
+ const access_1 = require("./access");
13
16
  const queries_1 = require("./queries");
14
17
  const key_1 = require("./key");
15
18
  // The same NQL -> knex bridge Bookshelf's filter plugin uses, applied directly to
@@ -17,7 +20,7 @@ const key_1 = require("./key");
17
20
  // turns that into parametrised WHERE clauses. Neither needs a Bookshelf model.
18
21
  const nql = require('@tryghost/nql');
19
22
  const knexify = require('@tryghost/mongo-knex');
20
- const TABLE = 'members_custom_fields';
23
+ const TABLE = 'members_metafields';
21
24
  // Column limits come from the canonical schema — the same source the migration and
22
25
  // Bookshelf models read — so the service can never drift from the database. The
23
26
  // name cap turns an over-long input into a clean 422 (not a DB error), and the key
@@ -47,7 +50,7 @@ const FieldName = zod_1.z
47
50
  // The backend mints the key from the name, so create takes just a name and type.
48
51
  const AddFieldInput = zod_1.z.object({
49
52
  name: FieldName,
50
- type: custom_field_types_1.FieldTypeSchema,
53
+ type: metafield_types_1.FieldTypeSchema,
51
54
  });
52
55
  // A bound on the work one request can ask for, separate from how many definitions
53
56
  // a site may hold in total. Every definition in a batch costs several queries
@@ -76,9 +79,9 @@ const EditFieldInput = zod_1.z.object({
76
79
  name: FieldName.optional(),
77
80
  status: schema_1.FieldStatusSchema.optional(),
78
81
  key: zod_1.z.string().optional(),
79
- type: custom_field_types_1.FieldTypeSchema.optional(),
82
+ type: metafield_types_1.FieldTypeSchema.optional(),
80
83
  });
81
- class CustomFieldDefinitionsService {
84
+ class MetafieldDefinitionsService {
82
85
  knex;
83
86
  recordAction;
84
87
  getMaxDefinitions;
@@ -92,7 +95,21 @@ class CustomFieldDefinitionsService {
92
95
  // restart. Where the number comes from is the caller's business.
93
96
  this.getMaxDefinitions = getMaxDefinitions;
94
97
  }
95
- async browse(options = {}) {
98
+ async hasAnyActive() {
99
+ const [field] = await this.list((0, queries_1.activeFields)(this.knex).limit(1));
100
+ return Boolean(field);
101
+ }
102
+ /**
103
+ * The fields table has no namespace column: every row in it belongs to the publisher's
104
+ * `custom` namespace, so no other namespace can have a stored field.
105
+ */
106
+ isStored(namespace) {
107
+ return namespace === identity_1.CUSTOM_NAMESPACE;
108
+ }
109
+ async browse(options = {}, audience = access_1.ADMIN) {
110
+ if (options.namespace !== undefined && !this.isStored(options.namespace)) {
111
+ return [];
112
+ }
96
113
  // Archived fields are hidden by default: most surfaces (member details, the
97
114
  // filter picker, the importer) only ever want active fields. A caller-
98
115
  // supplied `filter` can widen that — Settings pulls active and archived
@@ -103,7 +120,7 @@ class CustomFieldDefinitionsService {
103
120
  const query = options.filter
104
121
  ? applyFilter(this.knex(TABLE), options.filter)
105
122
  : (0, queries_1.activeFields)(this.knex);
106
- return this.list(query);
123
+ return (0, access_1.readableFields)(audience, await this.list(query));
107
124
  }
108
125
  /**
109
126
  * Decode a definition query into the domain, in the publisher's order.
@@ -113,10 +130,10 @@ class CustomFieldDefinitionsService {
113
130
  */
114
131
  async list(query) {
115
132
  const rows = await (0, queries_1.inFieldOrder)(query).select('*');
116
- return rows.map((row) => zod_1.z.decode(codec_1.customFieldCodec, row));
133
+ return rows.map((row) => zod_1.z.decode(codec_1.metafieldCodec, row));
117
134
  }
118
- async read(key) {
119
- const [field] = await this.list((0, queries_1.fieldByKey)(this.knex, key));
135
+ async read(namespace, key) {
136
+ const [field] = this.isStored(namespace) ? await this.list((0, queries_1.fieldByKey)(this.knex, key)) : [];
120
137
  if (!field) {
121
138
  throw new errors_1.default.NotFoundError({ message: 'Custom field not found.' });
122
139
  }
@@ -132,7 +149,8 @@ class CustomFieldDefinitionsService {
132
149
  * batch, so two items sharing a name are caught and two items deriving the same
133
150
  * key get distinct ones, exactly as if they had arrived as separate requests.
134
151
  */
135
- async add(context, input) {
152
+ async add(context, namespace, input) {
153
+ (0, namespaces_1.assertDefinable)(namespace);
136
154
  const requestedCount = Array.isArray(input) ? input.length : 0;
137
155
  const parsed = AddFieldsInput.safeParse(input);
138
156
  if (!parsed.success) {
@@ -252,7 +270,7 @@ class CustomFieldDefinitionsService {
252
270
  /** `read` for a caller that is deciding rather than serving: absent is an answer. */
253
271
  async findByKey(key, { executor = this.knex } = {}) {
254
272
  const row = await executor(TABLE).where('key', key).first();
255
- return row ? zod_1.z.decode(codec_1.customFieldCodec, row) : null;
273
+ return row ? zod_1.z.decode(codec_1.metafieldCodec, row) : null;
256
274
  }
257
275
  /** The same entry `add` writes. Only the caller knows its transaction committed. */
258
276
  async recordCreated(context, fields) {
@@ -310,7 +328,8 @@ class CustomFieldDefinitionsService {
310
328
  * fresh rank, so a move is well-defined even where every rank is still the default.
311
329
  * Returns every definition, archived included, matching what the request named.
312
330
  */
313
- async reorder(context, input) {
331
+ async reorder(context, namespace, input) {
332
+ (0, namespaces_1.assertDefinable)(namespace);
314
333
  const parsed = ReorderInput.safeParse(input);
315
334
  if (!parsed.success) {
316
335
  const issue = parsed.error.issues[0];
@@ -374,7 +393,7 @@ class CustomFieldDefinitionsService {
374
393
  async readMany(db, keys) {
375
394
  const rows = await db(TABLE).whereIn('key', keys).select('*');
376
395
  const byKey = new Map(rows.map((row) => [row.key, row]));
377
- return keys.map((key) => zod_1.z.decode(codec_1.customFieldCodec, byKey.get(key)));
396
+ return keys.map((key) => zod_1.z.decode(codec_1.metafieldCodec, byKey.get(key)));
378
397
  }
379
398
  /**
380
399
  * Pick a free key from the name's base: `base`, then `base_2`, `base_3`, ...
@@ -429,7 +448,10 @@ class CustomFieldDefinitionsService {
429
448
  });
430
449
  }
431
450
  }
432
- async edit(context, key, input) {
451
+ async edit(context, namespace, key, input) {
452
+ if (!this.isStored(namespace)) {
453
+ throw new errors_1.default.NotFoundError({ message: 'Custom field not found.' });
454
+ }
433
455
  const parsed = EditFieldInput.safeParse(input);
434
456
  if (!parsed.success) {
435
457
  throw new errors_1.default.ValidationError({
@@ -438,7 +460,7 @@ class CustomFieldDefinitionsService {
438
460
  });
439
461
  }
440
462
  const patch = parsed.data;
441
- const existing = await this.read(key);
463
+ const existing = await this.read(identity_1.CUSTOM_NAMESPACE, key);
442
464
  // Key and type are immutable after creation: values are addressed by key
443
465
  // and interpreted by type, so changing either would silently orphan or
444
466
  // corrupt stored values. Reject a differing value rather than ignore it.
@@ -492,7 +514,7 @@ class CustomFieldDefinitionsService {
492
514
  details: { primary_name: patch.name ?? existing.name, key },
493
515
  });
494
516
  }
495
- return this.read(key);
517
+ return this.read(identity_1.CUSTOM_NAMESPACE, key);
496
518
  }
497
519
  /**
498
520
  * Permanently delete a field and every member value attached to it (the FK
@@ -501,7 +523,10 @@ class CustomFieldDefinitionsService {
501
523
  * which makes accidental data loss a deliberate two-step. Archiving is the
502
524
  * reversible soft state (see `edit` with a status change).
503
525
  */
504
- async destroy(context, key) {
526
+ async destroy(context, namespace, key) {
527
+ if (!this.isStored(namespace)) {
528
+ throw new errors_1.default.NotFoundError({ message: 'Custom field not found.' });
529
+ }
505
530
  const field = await this.knex(TABLE).where('key', key).first();
506
531
  if (!field) {
507
532
  throw new errors_1.default.NotFoundError({ message: 'Custom field not found.' });
@@ -520,7 +545,7 @@ class CustomFieldDefinitionsService {
520
545
  });
521
546
  }
522
547
  }
523
- exports.CustomFieldDefinitionsService = CustomFieldDefinitionsService;
548
+ exports.MetafieldDefinitionsService = MetafieldDefinitionsService;
524
549
  /**
525
550
  * The shape a stated key has to have. Minting derives one that is usable by
526
551
  * construction, so this is the check that path never needed: a caller stating its own
@@ -581,6 +606,24 @@ function applyFilter(query, filter) {
581
606
  let mongoQuery;
582
607
  try {
583
608
  mongoQuery = nql(filter).toJSON();
609
+ }
610
+ catch (err) {
611
+ throw new errors_1.default.BadRequestError({
612
+ message: 'Could not parse the filter parameter.',
613
+ property: 'filter',
614
+ err: err,
615
+ });
616
+ }
617
+ // The table has no `namespace` column, so mongo-knex would compile this into SQL against a
618
+ // column that does not exist. Refuse it at the edge, naming the URL as the way to pick a
619
+ // namespace, rather than surface a database error.
620
+ if (filterReferencesAttribute(mongoQuery, 'namespace')) {
621
+ throw new errors_1.default.BadRequestError({
622
+ message: 'Filtering on namespace is not supported. Scope by the namespace route instead.',
623
+ property: 'filter',
624
+ });
625
+ }
626
+ try {
584
627
  knexify(query, mongoQuery, { tableName: TABLE });
585
628
  }
586
629
  catch (err) {
@@ -599,12 +642,15 @@ function applyFilter(query, filter) {
599
642
  // $and/$or/$nor combinators — so a status filter at any nesting counts as the
600
643
  // caller opting in to (or out of) archived fields.
601
644
  function filterReferencesStatus(query) {
645
+ return filterReferencesAttribute(query, 'status');
646
+ }
647
+ function filterReferencesAttribute(query, attribute) {
602
648
  return Object.entries(query).some(([key, value]) => {
603
- if (key === 'status') {
649
+ if (key === attribute) {
604
650
  return true;
605
651
  }
606
652
  if ((key === '$and' || key === '$or' || key === '$nor') && Array.isArray(value)) {
607
- return value.some((sub) => filterReferencesStatus(sub));
653
+ return value.some((sub) => filterReferencesAttribute(sub, attribute));
608
654
  }
609
655
  return false;
610
656
  });
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.METAFIELDS_RELATION = void 0;
7
+ exports.createMetafieldsFilterTransformer = createMetafieldsFilterTransformer;
8
+ // Translates the metafield clauses of a members filter into a query over the
9
+ // values table. A metafield is a publisher-defined field on a member; it is
10
+ // addressed as `namespace.key`, and a composite value such as an address names
11
+ // one of its parts by appending it: `namespace.key.part`.
12
+ //
13
+ // (metafields.key:'custom.company'+metafields.value:'Ghost')
14
+ // (metafields.key:'custom.shipping_address.country'+metafields.value:'GB')
15
+ // metafields.key:'custom.company' // has a value
16
+ // metafields.key:-'custom.shipping_address.country' // that part is not set
17
+ //
18
+ // The values table holds one row per stored value: `metafield_key`, `path`
19
+ // (empty for a plain field, the part's name for one part of a composite) and
20
+ // `value_text`. A filter addresses those columns directly, so each one becomes a
21
+ // single $elemMatch over them — positive asserts a matching row exists, $not
22
+ // asserts none does — with no lookup against the field definitions.
23
+ const errors_1 = __importDefault(require("@tryghost/errors"));
24
+ const identity_1 = require("@tryghost/metafield-types/identity");
25
+ const RELATION = 'metafields';
26
+ const PREFIX = `${RELATION}.`;
27
+ const KEY_ATTRIBUTE = `${PREFIX}key`;
28
+ const VALUE_ATTRIBUTE = `${PREFIX}value`;
29
+ const ROOT_PATH = '';
30
+ // Only recurse into plain objects/arrays; a RegExp, Date, etc. is a leaf value that
31
+ // must pass through by reference (recursing would strip a regex to `{}`).
32
+ function isPlainObject(value) {
33
+ return (typeof value === 'object' &&
34
+ value !== null &&
35
+ !Array.isArray(value) &&
36
+ (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null));
37
+ }
38
+ function isMetafieldClause(node) {
39
+ if (!isPlainObject(node)) {
40
+ return false;
41
+ }
42
+ const keys = Object.keys(node);
43
+ return keys.length === 1 && keys[0].startsWith(PREFIX);
44
+ }
45
+ // A grouped compound: an $and whose clauses all target the relation and name exactly one
46
+ // `key`. Its clauses describe one leaf row.
47
+ //
48
+ // Exactly one, not at least one: two whole-field filters ANDed together arrive as a flat
49
+ // `key:'a'+key:'b'`, since a bare key clause needs no group of its own. That is two
50
+ // filters — a member with a value for both — not one leaf that is somehow both fields, so
51
+ // it has to fall through and be transformed a clause at a time.
52
+ function isMetafieldCompound(clauses) {
53
+ if (!Array.isArray(clauses) || clauses.length < 2 || !clauses.every(isMetafieldClause)) {
54
+ return false;
55
+ }
56
+ return clauses.filter((clause) => Object.keys(clause)[0] === KEY_ATTRIBUTE).length === 1;
57
+ }
58
+ // NQL compiles every negation in this grammar to `{$ne: <string>}`, so a negated clause
59
+ // can arrive in no other shape.
60
+ function negatedString(value) {
61
+ return isPlainObject(value) && typeof value.$ne === 'string' ? value.$ne : null;
62
+ }
63
+ const ANY_PATH = null;
64
+ // A stored key never contains a dot, so a full dotted identity is a key no stored
65
+ // row can equal.
66
+ function unmatchableLeaf(identity) {
67
+ return { key: (0, identity_1.formatIdentity)(identity), path: identity.partPath };
68
+ }
69
+ function parseLeafAddress(raw) {
70
+ const identity = typeof raw === 'string' ? (0, identity_1.parseIdentity)(raw) : null;
71
+ if (!identity) {
72
+ throw new errors_1.default.BadRequestError({
73
+ message: `A metafield filter names a field as namespace.key, for example (${KEY_ATTRIBUTE}:'custom.company'+${VALUE_ATTRIBUTE}:'Ghost').`,
74
+ });
75
+ }
76
+ if (identity.namespace !== identity_1.CUSTOM_NAMESPACE) {
77
+ return unmatchableLeaf(identity);
78
+ }
79
+ return { key: identity.key, path: identity.partPath };
80
+ }
81
+ function createMetafieldsFilterTransformer() {
82
+ // One (maybe-negated) $elemMatch over the leaf columns: positive is "a leaf pinned
83
+ // by these matches", `$not` is "no leaf does".
84
+ function buildElemMatch(target, value, negate) {
85
+ const match = { metafield_key: target.key };
86
+ if (value !== undefined) {
87
+ match.path = target.path ?? ROOT_PATH;
88
+ match.value_text = value;
89
+ }
90
+ else if (target.path !== ANY_PATH) {
91
+ match.path = target.path;
92
+ }
93
+ if (negate) {
94
+ return { [RELATION]: { $not: { $elemMatch: match } } };
95
+ }
96
+ return { [RELATION]: { $elemMatch: match } };
97
+ }
98
+ function toElemMatch(clauses) {
99
+ let target;
100
+ let value;
101
+ let hasValue = false;
102
+ for (const clause of clauses) {
103
+ const [attribute, clauseValue] = Object.entries(clause)[0];
104
+ if (attribute === KEY_ATTRIBUTE) {
105
+ if (negatedString(clauseValue) !== null) {
106
+ throw new errors_1.default.BadRequestError({
107
+ message: `A negated "${KEY_ATTRIBUTE}" stands alone; it cannot be grouped with a value.`,
108
+ });
109
+ }
110
+ target = parseLeafAddress(clauseValue);
111
+ }
112
+ else if (attribute === VALUE_ATTRIBUTE) {
113
+ if (hasValue) {
114
+ throw new errors_1.default.BadRequestError({
115
+ message: `A metafield filter takes one "${VALUE_ATTRIBUTE}" clause.`,
116
+ });
117
+ }
118
+ hasValue = true;
119
+ value = clauseValue;
120
+ }
121
+ else {
122
+ throw new errors_1.default.BadRequestError({
123
+ message: `Unsupported metafield filter clause "${attribute}".`,
124
+ });
125
+ }
126
+ }
127
+ if (!target) {
128
+ throw new errors_1.default.BadRequestError({
129
+ message: `A metafield filter needs a "${KEY_ATTRIBUTE}" clause.`,
130
+ });
131
+ }
132
+ return buildElemMatch(target, hasValue ? value : undefined, false);
133
+ }
134
+ function fromKeyClause(value) {
135
+ const negatedKey = negatedString(value);
136
+ if (negatedKey !== null) {
137
+ return buildElemMatch(parseLeafAddress(negatedKey), undefined, true);
138
+ }
139
+ return buildElemMatch(parseLeafAddress(value), undefined, false);
140
+ }
141
+ function transform(node) {
142
+ if (Array.isArray(node)) {
143
+ return node.map(transform);
144
+ }
145
+ if (!isPlainObject(node)) {
146
+ return node;
147
+ }
148
+ if (isMetafieldCompound(node.$and)) {
149
+ return toElemMatch(node.$and);
150
+ }
151
+ const out = {};
152
+ for (const [key, value] of Object.entries(node)) {
153
+ if (key === KEY_ATTRIBUTE) {
154
+ Object.assign(out, fromKeyClause(value));
155
+ }
156
+ else if (key.startsWith(PREFIX)) {
157
+ throw new errors_1.default.BadRequestError({
158
+ message: `A "${key}" filter must be grouped with its "${KEY_ATTRIBUTE}" clause, for example (${KEY_ATTRIBUTE}:'custom.a_field'+${VALUE_ATTRIBUTE}:'a value').`,
159
+ });
160
+ }
161
+ else {
162
+ out[key] = transform(value);
163
+ }
164
+ }
165
+ return out;
166
+ }
167
+ return (query) => transform(query);
168
+ }
169
+ /**
170
+ * The Member filter relation that exposes metafield values. A member has many leaf
171
+ * rows (one per field, or per part of a composite field), and a predicate asks whether
172
+ * one of them matches, so this joins the values table on member_id and mongo-knex emits
173
+ * it as a correlated `members.id IN (…)` subquery — composing with every other member
174
+ * filter.
175
+ */
176
+ exports.METAFIELDS_RELATION = {
177
+ tableName: 'members_metafield_values',
178
+ tableNameAs: RELATION,
179
+ type: 'oneToOne',
180
+ joinFrom: 'member_id',
181
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.bindings = exports.values = exports.definitions = exports.actingContext = void 0;
3
+ exports.bindings = exports.values = exports.definitions = exports.readableFields = exports.canWrite = exports.MEMBERS = exports.INTERNAL = exports.ADMIN = exports.actingContext = void 0;
4
4
  exports.init = init;
5
5
  const definitions_service_1 = require("./definitions-service");
6
6
  const values_service_1 = require("./values-service");
@@ -9,6 +9,15 @@ const actions_1 = require("./actions");
9
9
  const config_1 = require("./config");
10
10
  var actions_2 = require("./actions");
11
11
  Object.defineProperty(exports, "actingContext", { enumerable: true, get: function () { return actions_2.actingContext; } });
12
+ // Which door a request came through, which is what decides how much of a member's
13
+ // answers it may see or change. Required wherever that is asked, so a new caller
14
+ // has to name itself rather than inherit an answer by default.
15
+ var access_1 = require("./access");
16
+ Object.defineProperty(exports, "ADMIN", { enumerable: true, get: function () { return access_1.ADMIN; } });
17
+ Object.defineProperty(exports, "INTERNAL", { enumerable: true, get: function () { return access_1.INTERNAL; } });
18
+ Object.defineProperty(exports, "MEMBERS", { enumerable: true, get: function () { return access_1.MEMBERS; } });
19
+ Object.defineProperty(exports, "canWrite", { enumerable: true, get: function () { return access_1.canWrite; } });
20
+ Object.defineProperty(exports, "readableFields", { enumerable: true, get: function () { return access_1.readableFields; } });
12
21
  function init() {
13
22
  // The three are constructed together below, so checking all of them keeps the "all or
14
23
  // none" invariant explicit rather than trusting one to stand in for the rest.
@@ -17,25 +26,25 @@ function init() {
17
26
  }
18
27
  const { knex } = require('../../data/db');
19
28
  const models = require('../../models');
20
- const recordAction = ({ context, verb, subject, details }) => (0, actions_1.recordCustomFieldAction)({ Action: models.Action, context, verb, subject, details });
29
+ const recordAction = ({ context, verb, subject, details }) => (0, actions_1.recordMetafieldAction)({ Action: models.Action, context, verb, subject, details });
21
30
  // Resolved here, not in the service: reading config is this module's job, and
22
31
  // the service is handed a number. A getter rather than a value because the
23
32
  // ceiling is an operator setting that can change between requests, and a Ghost
24
33
  // container holds no state across them.
25
34
  const config = require('../../../shared/config');
26
- exports.definitions = new definitions_service_1.CustomFieldDefinitionsService({
35
+ exports.definitions = new definitions_service_1.MetafieldDefinitionsService({
27
36
  knex,
28
37
  recordAction,
29
- getMaxDefinitions: () => (0, config_1.resolveMaxDefinitions)(config.get('members:customFields:maxDefinitions')),
38
+ getMaxDefinitions: () => (0, config_1.resolveMaxDefinitions)(config.get('members:metafields:maxDefinitions')),
30
39
  });
31
40
  // The values service reads the field definitions straight from the table, so
32
41
  // it needs knex and the same ceiling — no handle on the definitions service.
33
- exports.values = new values_service_1.CustomFieldValuesService({
42
+ exports.values = new values_service_1.MetafieldValuesService({
34
43
  knex,
35
- getMaxDefinitions: () => (0, config_1.resolveMaxDefinitions)(config.get('members:customFields:maxDefinitions')),
44
+ getMaxDefinitions: () => (0, config_1.resolveMaxDefinitions)(config.get('members:metafields:maxDefinitions')),
36
45
  });
37
46
  // Built after the values, which is what a binding routes into. It has no handle on the
38
47
  // definitions: making a field is not part of binding to one, so a caller that needs both
39
48
  // asks for both.
40
- exports.bindings = new bindings_service_1.CustomFieldBindingsService({ knex, values: exports.values });
49
+ exports.bindings = new bindings_service_1.MetafieldBindingsService({ knex, values: exports.values });
41
50
  }
@@ -2,11 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KEY_CHARACTERS = void 0;
4
4
  exports.mintableKey = mintableKey;
5
+ const identity_1 = require("@tryghost/metafield-types/identity");
5
6
  // Neither package ships types.
6
7
  const { stripInvisibleChars } = require('@tryghost/string');
7
8
  const unidecode = require('unidecode');
8
9
  /** Every character a key may contain. Nothing else survives minting. */
9
- exports.KEY_CHARACTERS = /^[a-z0-9_]+$/;
10
+ exports.KEY_CHARACTERS = identity_1.IDENTITY_SEGMENT;
10
11
  /**
11
12
  * Mint the key a field is addressed by, from the name a publisher chose.
12
13
  *
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CustomField = void 0;
3
+ exports.Metafield = void 0;
4
4
  const zod_1 = require("zod");
5
- const custom_field_types_1 = require("@tryghost/custom-field-types");
5
+ const metafield_types_1 = require("@tryghost/metafield-types");
6
6
  const schema_1 = require("./schema");
7
- // The domain shape of a field definition (camelCase; distinct from the DB row).
8
- exports.CustomField = zod_1.z.object({
7
+ exports.Metafield = zod_1.z.object({
9
8
  id: zod_1.z.string(),
9
+ namespace: zod_1.z.string(),
10
10
  key: zod_1.z.string(),
11
11
  name: zod_1.z.string(),
12
- type: custom_field_types_1.FieldTypeSchema,
12
+ type: metafield_types_1.FieldTypeSchema,
13
13
  status: schema_1.FieldStatusSchema,
14
14
  createdAt: zod_1.z.date(),
15
15
  updatedAt: zod_1.z.date().nullable(),
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.definableByPublisher = definableByPublisher;
7
+ exports.assertDefinable = assertDefinable;
8
+ const errors_1 = __importDefault(require("@tryghost/errors"));
9
+ const identity_1 = require("@tryghost/metafield-types/identity");
10
+ /**
11
+ * Who may define fields in a namespace.
12
+ *
13
+ * This is a property of the namespace, not of whoever is asking, so it is settled before
14
+ * any question about the caller. Asking the caller first gets the order wrong in a way
15
+ * that shows: a request to define a field in a namespace nobody owns would be refused for
16
+ * want of a permission, telling the caller to go and get one, when no permission would
17
+ * have helped.
18
+ *
19
+ * The publisher owns `custom` and nothing owns anything else yet. An app owning its own
20
+ * namespace resolves here too, and will not resolve to a permission at all: the caller
21
+ * has to *be* that app rather than hold a role, which is why the staff permission stays
22
+ * named after the publisher's fields rather than after metafields at large.
23
+ */
24
+ function definableByPublisher(namespace) {
25
+ return namespace === identity_1.CUSTOM_NAMESPACE;
26
+ }
27
+ function assertDefinable(namespace) {
28
+ if (!definableByPublisher(namespace)) {
29
+ throw new errors_1.default.ValidationError({
30
+ message: `Fields cannot be defined in the "${namespace}" namespace.`,
31
+ property: 'namespace',
32
+ });
33
+ }
34
+ }
@@ -4,7 +4,7 @@ exports.activeFields = activeFields;
4
4
  exports.fieldByKey = fieldByKey;
5
5
  exports.inFieldOrder = inFieldOrder;
6
6
  const schema_1 = require("./schema");
7
- const FIELDS_TABLE = 'members_custom_fields';
7
+ const FIELDS_TABLE = 'members_metafields';
8
8
  // Archived fields must stay out of every read and write, and nothing in the database
9
9
  // enforces that — no constraint stops a value row referencing an archived field. A query
10
10
  // that forgets the filter is a silent bug, so the filter lives in one place.
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DbBoundField = exports.DbCustomFieldBinding = exports.DbCustomFieldLeaf = exports.DbCustomFieldValue = exports.WrittenBy = exports.DbCustomField = exports.FieldStatusSchema = exports.FIELD_STATUS = void 0;
3
+ exports.DbBoundField = exports.DbMetafieldBinding = exports.DbMetafieldLeaf = exports.DbMetafieldValue = exports.WrittenBy = exports.DbMetafield = exports.FieldStatusSchema = exports.FIELD_STATUS = void 0;
4
4
  const zod_1 = require("zod");
5
- const custom_field_types_1 = require("@tryghost/custom-field-types");
5
+ const metafield_types_1 = require("@tryghost/metafield-types");
6
6
  const date_1 = require("../../lib/db-types/date");
7
7
  // `archived` is soft: the field drops out of the values path but stays in the definition
8
8
  // list so it can be renamed, restored or deleted. Mirrors schema.js's `isIn` on the
@@ -11,11 +11,11 @@ exports.FIELD_STATUS = { active: 'active', archived: 'archived' };
11
11
  exports.FieldStatusSchema = zod_1.z.enum([exports.FIELD_STATUS.active, exports.FIELD_STATUS.archived]);
12
12
  // The single source for the read projection and the knex table type below. `type` parses
13
13
  // as the field-type enum, so the row carries the narrow type and no codec needs a cast.
14
- exports.DbCustomField = zod_1.z.object({
14
+ exports.DbMetafield = zod_1.z.object({
15
15
  id: zod_1.z.string(),
16
16
  key: zod_1.z.string(),
17
17
  name: zod_1.z.string(),
18
- type: custom_field_types_1.FieldTypeSchema,
18
+ type: metafield_types_1.FieldTypeSchema,
19
19
  status: exports.FieldStatusSchema,
20
20
  created_at: date_1.DbDate,
21
21
  updated_at: date_1.DbDate.nullable(),
@@ -23,7 +23,7 @@ exports.DbCustomField = zod_1.z.object({
23
23
  /**
24
24
  * How a value arrived, not who caused it: who edited a member's fields is already an
25
25
  * action, and Stripe is not a person. `type` is the namespace that makes `id` resolvable —
26
- * `users`, `integrations`, `members_custom_field_bindings` — so the one writer that
26
+ * `users`, `integrations`, `members_metafield_bindings` — so the one writer that
27
27
  * resolves in no table is the one with no id to give.
28
28
  */
29
29
  exports.WrittenBy = zod_1.z.discriminatedUnion('type', [
@@ -31,12 +31,16 @@ exports.WrittenBy = zod_1.z.discriminatedUnion('type', [
31
31
  zod_1.z.object({ type: zod_1.z.literal('integration'), id: zod_1.z.string() }),
32
32
  zod_1.z.object({ type: zod_1.z.literal('binding'), id: zod_1.z.string() }),
33
33
  zod_1.z.object({ type: zod_1.z.literal('import'), id: zod_1.z.null() }),
34
+ // A member writing their own answers. Resolvable in `members`, like the others,
35
+ // and the only writer whose changes leave nothing in the staff action log: that
36
+ // log records what staff did.
37
+ zod_1.z.object({ type: zod_1.z.literal('member'), id: zod_1.z.string() }),
34
38
  ]);
35
39
  // One part of a member's value. What a `path` means is storage.ts's business, so the row
36
40
  // carries it as a plain string.
37
- exports.DbCustomFieldValue = zod_1.z.object({
41
+ exports.DbMetafieldValue = zod_1.z.object({
38
42
  id: zod_1.z.string(),
39
- custom_field_key: zod_1.z.string(),
43
+ metafield_key: zod_1.z.string(),
40
44
  member_id: zod_1.z.string(),
41
45
  path: zod_1.z.string(),
42
46
  // Nullable like the column, though nothing here writes a null: a part with no value
@@ -55,18 +59,18 @@ exports.DbCustomFieldValue = zod_1.z.object({
55
59
  // `type` takes no part in the assembly and is here as a gate: a value whose type has left
56
60
  // the catalog is one the definitions list no longer returns either, so failing to parse
57
61
  // is what drops it.
58
- exports.DbCustomFieldLeaf = zod_1.z.object({
62
+ exports.DbMetafieldLeaf = zod_1.z.object({
59
63
  member_id: zod_1.z.string(),
60
64
  key: zod_1.z.string(),
61
- type: custom_field_types_1.FieldTypeSchema,
65
+ type: metafield_types_1.FieldTypeSchema,
62
66
  path: zod_1.z.string(),
63
67
  value_text: zod_1.z.string(),
64
68
  });
65
- exports.DbCustomFieldBinding = zod_1.z.object({
69
+ exports.DbMetafieldBinding = zod_1.z.object({
66
70
  id: zod_1.z.string(),
67
71
  product_id: zod_1.z.string(),
68
72
  port: zod_1.z.string(),
69
- custom_field_key: zod_1.z.string(),
73
+ metafield_key: zod_1.z.string(),
70
74
  created_at: date_1.DbDate,
71
75
  updated_at: date_1.DbDate.nullable(),
72
76
  });
@@ -74,5 +78,5 @@ exports.DbCustomFieldBinding = zod_1.z.object({
74
78
  exports.DbBoundField = zod_1.z.object({
75
79
  binding_id: zod_1.z.string(),
76
80
  key: zod_1.z.string(),
77
- type: custom_field_types_1.FieldTypeSchema,
81
+ type: metafield_types_1.FieldTypeSchema,
78
82
  });
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toMetafieldsResponse = void 0;
4
+ const zod_1 = require("zod");
5
+ const case_keys_1 = require("../../lib/case-keys");
6
+ const models_1 = require("./models");
7
+ const MetafieldResource = zod_1.z.object({
8
+ namespace: zod_1.z.string(),
9
+ key: zod_1.z.string(),
10
+ name: zod_1.z.string(),
11
+ type: zod_1.z.string(),
12
+ status: zod_1.z.string(),
13
+ created_at: zod_1.z.date(),
14
+ updated_at: zod_1.z.date().nullable(),
15
+ });
16
+ const MetafieldsResponse = zod_1.z.object({ members_metafields: zod_1.z.array(MetafieldResource) });
17
+ exports.toMetafieldsResponse = zod_1.z
18
+ .array(models_1.Metafield)
19
+ .transform((fields) => ({
20
+ members_metafields: fields.map((field) => (0, case_keys_1.snakeKeys)(field)),
21
+ }))
22
+ .pipe(MetafieldsResponse);