ghost 6.33.0 → 6.34.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 (31) hide show
  1. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
  2. package/core/built/admin/assets/admin-x-settings/{code-editor-view-ClWZH2b9.mjs → code-editor-view-B9Y9-ria.mjs} +2 -2
  3. package/core/built/admin/assets/admin-x-settings/{index-DFPdw8A9.mjs → index-D5IkCdkn.mjs} +2 -2
  4. package/core/built/admin/assets/admin-x-settings/{index-hTRteIub.mjs → index-WNL04L8u.mjs} +2 -2
  5. package/core/built/admin/assets/admin-x-settings/{index-BvKUS_Ix.mjs → index-bwPWeQa9.mjs} +5 -5
  6. package/core/built/admin/assets/admin-x-settings/{modals-H4owEPK6.mjs → modals-D-vFoCmN.mjs} +5917 -5925
  7. package/core/built/admin/assets/{chunk.526.96b1ceeb47f193bbd5cf.js → chunk.289.799159a53c663e5c4afd.js} +3 -3
  8. package/core/built/admin/assets/{chunk.524.3015bfad0b069d85881d.js → chunk.524.fd32ec309de4906c5734.js} +4 -4
  9. package/core/built/admin/assets/{chunk.582.21a5a8ae91c8e92e76cd.js → chunk.582.696652c545ccf71958b8.js} +6 -6
  10. package/core/built/admin/assets/{ghost-f48d0d808daca3e7828effda55ce351d.js → ghost-2b736ae44ae91e9b1034ed7f4041ed5c.js} +2 -2
  11. package/core/built/admin/index.html +4 -4
  12. package/core/frontend/public/admin-auth/admin-auth.min.js +1 -1
  13. package/core/frontend/src/admin-auth/message-handler.js +49 -91
  14. package/core/server/adapters/lib/redis/AdapterCacheRedis.js +61 -4
  15. package/core/server/api/endpoints/authentication.js +5 -4
  16. package/core/server/api/endpoints/users.js +28 -3
  17. package/core/server/data/seeders/importers/members-importer.js +1 -13
  18. package/core/server/lib/get-inbox-links.js +6 -2
  19. package/core/server/lib/get-inbox-links.ts +7 -6
  20. package/core/server/models/session.js +5 -4
  21. package/core/server/models/user.js +5 -4
  22. package/core/server/services/auth/session/session-service.js +29 -0
  23. package/core/server/services/email-suppression-list/mailgun-email-suppression-list.js +18 -14
  24. package/core/server/services/gifts/gift-service-wrapper.js +17 -0
  25. package/core/server/services/gifts/gift-service.js +21 -9
  26. package/core/server/services/gifts/gift-service.ts +28 -12
  27. package/core/server/services/members/members-api/services/geolocation-service.js +5 -1
  28. package/core/server/services/members/members-api/services/member-bread-service.js +5 -0
  29. package/core/server/services/oembed/oembed-service.js +12 -0
  30. package/package.json +1 -1
  31. package/pnpm-lock.yaml +57 -57
@@ -1,7 +1,7 @@
1
- (globalThis.webpackChunk_ember_auto_import_=globalThis.webpackChunk_ember_auto_import_||[]).push([[526],{45525(e,t,r){var o={"./af":46930,"./af.js":46930,"./ar":71470,"./ar-dz":59197,"./ar-dz.js":59197,"./ar-kw":1997,"./ar-kw.js":1997,"./ar-ly":73852,"./ar-ly.js":73852,"./ar-ma":68077,"./ar-ma.js":68077,"./ar-sa":65943,"./ar-sa.js":65943,"./ar-tn":48353,"./ar-tn.js":48353,"./ar.js":71470,"./az":32742,"./az.js":32742,"./be":81632,"./be.js":81632,"./bg":45674,"./bg.js":45674,"./bm":2024,"./bm.js":2024,"./bn":32161,"./bn.js":32161,"./bo":12434,"./bo.js":12434,"./br":78437,"./br.js":78437,"./bs":47718,"./bs.js":47718,"./ca":48037,"./ca.js":48037,"./cs":98816,"./cs.js":98816,"./cv":51232,"./cv.js":51232,"./cy":86013,"./cy.js":86013,"./da":75014,"./da.js":75014,"./de":48442,"./de-at":54258,"./de-at.js":54258,"./de-ch":17668,"./de-ch.js":17668,"./de.js":48442,"./dv":47607,"./dv.js":47607,"./el":5460,"./el.js":5460,"./en-SG":14981,"./en-SG.js":14981,"./en-au":91597,"./en-au.js":91597,"./en-ca":88471,"./en-ca.js":88471,"./en-gb":19358,"./en-gb.js":19358,"./en-ie":29013,"./en-ie.js":29013,"./en-il":85438,"./en-il.js":85438,"./en-nz":67383,"./en-nz.js":67383,"./eo":19933,"./eo.js":19933,"./es":49641,"./es-do":40055,"./es-do.js":40055,"./es-us":87790,"./es-us.js":87790,"./es.js":49641,"./et":75004,"./et.js":75004,"./eu":56643,"./eu.js":56643,"./fa":58296,"./fa.js":58296,"./fi":16208,"./fi.js":16208,"./fo":85990,"./fo.js":85990,"./fr":54081,"./fr-ca":94230,"./fr-ca.js":94230,"./fr-ch":97277,"./fr-ch.js":97277,"./fr.js":54081,"./fy":85728,"./fy.js":85728,"./ga":61057,"./ga.js":61057,"./gd":77918,"./gd.js":77918,"./gl":19478,"./gl.js":19478,"./gom-latn":21368,"./gom-latn.js":21368,"./gu":18573,"./gu.js":18573,"./he":45582,"./he.js":45582,"./hi":74394,"./hi.js":74394,"./hr":79423,"./hr.js":79423,"./hu":88926,"./hu.js":88926,"./hy-am":11609,"./hy-am.js":11609,"./id":75520,"./id.js":75520,"./is":37093,"./is.js":37093,"./it":48528,"./it-ch":63338,"./it-ch.js":63338,"./it.js":48528,"./ja":89252,"./ja.js":89252,"./jv":39969,"./jv.js":39969,"./ka":29245,"./ka.js":29245,"./kk":19667,"./kk.js":19667,"./km":28761,"./km.js":28761,"./kn":94464,"./kn.js":94464,"./ko":35767,"./ko.js":35767,"./ku":23889,"./ku.js":23889,"./ky":91269,"./ky.js":91269,"./lb":36763,"./lb.js":36763,"./lo":17472,"./lo.js":17472,"./lt":46897,"./lt.js":46897,"./lv":24911,"./lv.js":24911,"./me":75691,"./me.js":75691,"./mi":64999,"./mi.js":64999,"./mk":99977,"./mk.js":99977,"./ml":60028,"./ml.js":60028,"./mn":71494,"./mn.js":71494,"./mr":59506,"./mr.js":59506,"./ms":27137,"./ms-my":52732,"./ms-my.js":52732,"./ms.js":27137,"./mt":42068,"./mt.js":42068,"./my":60439,"./my.js":60439,"./nb":51081,"./nb.js":51081,"./ne":60604,"./ne.js":60604,"./nl":92619,"./nl-be":10629,"./nl-be.js":10629,"./nl.js":92619,"./nn":35757,"./nn.js":35757,"./pa-in":30184,"./pa-in.js":30184,"./pl":79917,"./pl.js":79917,"./pt":89781,"./pt-br":75358,"./pt-br.js":75358,"./pt.js":89781,"./ro":39010,"./ro.js":39010,"./ru":77472,"./ru.js":77472,"./sd":1002,"./sd.js":1002,"./se":13785,"./se.js":13785,"./si":95933,"./si.js":95933,"./sk":15675,"./sk.js":15675,"./sl":85170,"./sl.js":85170,"./sq":15429,"./sq.js":15429,"./sr":69340,"./sr-cyrl":82611,"./sr-cyrl.js":82611,"./sr.js":69340,"./ss":67331,"./ss.js":67331,"./sv":50160,"./sv.js":50160,"./sw":74311,"./sw.js":74311,"./ta":93654,"./ta.js":93654,"./te":93258,"./te.js":93258,"./tet":77100,"./tet.js":77100,"./tg":95040,"./tg.js":95040,"./th":46173,"./th.js":46173,"./tl-ph":59562,"./tl-ph.js":59562,"./tlh":6533,"./tlh.js":6533,"./tr":82883,"./tr.js":82883,"./tzl":83143,"./tzl.js":83143,"./tzm":76272,"./tzm-latn":86256,"./tzm-latn.js":86256,"./tzm.js":76272,"./ug-cn":75035,"./ug-cn.js":75035,"./uk":28241,"./uk.js":28241,"./ur":62858,"./ur.js":62858,"./uz":95442,"./uz-latn":81554,"./uz-latn.js":81554,"./uz.js":95442,"./vi":88352,"./vi.js":88352,"./x-pseudo":66900,"./x-pseudo.js":66900,"./yo":91889,"./yo.js":91889,"./zh-cn":58101,"./zh-cn.js":58101,"./zh-hk":43641,"./zh-hk.js":43641,"./zh-tw":63921,"./zh-tw.js":63921}
1
+ (globalThis.webpackChunk_ember_auto_import_=globalThis.webpackChunk_ember_auto_import_||[]).push([[289],{45525(e,t,r){var o={"./af":46930,"./af.js":46930,"./ar":71470,"./ar-dz":59197,"./ar-dz.js":59197,"./ar-kw":1997,"./ar-kw.js":1997,"./ar-ly":73852,"./ar-ly.js":73852,"./ar-ma":68077,"./ar-ma.js":68077,"./ar-sa":65943,"./ar-sa.js":65943,"./ar-tn":48353,"./ar-tn.js":48353,"./ar.js":71470,"./az":32742,"./az.js":32742,"./be":81632,"./be.js":81632,"./bg":45674,"./bg.js":45674,"./bm":2024,"./bm.js":2024,"./bn":32161,"./bn.js":32161,"./bo":12434,"./bo.js":12434,"./br":78437,"./br.js":78437,"./bs":47718,"./bs.js":47718,"./ca":48037,"./ca.js":48037,"./cs":98816,"./cs.js":98816,"./cv":51232,"./cv.js":51232,"./cy":86013,"./cy.js":86013,"./da":75014,"./da.js":75014,"./de":48442,"./de-at":54258,"./de-at.js":54258,"./de-ch":17668,"./de-ch.js":17668,"./de.js":48442,"./dv":47607,"./dv.js":47607,"./el":5460,"./el.js":5460,"./en-SG":14981,"./en-SG.js":14981,"./en-au":91597,"./en-au.js":91597,"./en-ca":88471,"./en-ca.js":88471,"./en-gb":19358,"./en-gb.js":19358,"./en-ie":29013,"./en-ie.js":29013,"./en-il":85438,"./en-il.js":85438,"./en-nz":67383,"./en-nz.js":67383,"./eo":19933,"./eo.js":19933,"./es":49641,"./es-do":40055,"./es-do.js":40055,"./es-us":87790,"./es-us.js":87790,"./es.js":49641,"./et":75004,"./et.js":75004,"./eu":56643,"./eu.js":56643,"./fa":58296,"./fa.js":58296,"./fi":16208,"./fi.js":16208,"./fo":85990,"./fo.js":85990,"./fr":54081,"./fr-ca":94230,"./fr-ca.js":94230,"./fr-ch":97277,"./fr-ch.js":97277,"./fr.js":54081,"./fy":85728,"./fy.js":85728,"./ga":61057,"./ga.js":61057,"./gd":77918,"./gd.js":77918,"./gl":19478,"./gl.js":19478,"./gom-latn":21368,"./gom-latn.js":21368,"./gu":18573,"./gu.js":18573,"./he":45582,"./he.js":45582,"./hi":74394,"./hi.js":74394,"./hr":79423,"./hr.js":79423,"./hu":88926,"./hu.js":88926,"./hy-am":11609,"./hy-am.js":11609,"./id":75520,"./id.js":75520,"./is":37093,"./is.js":37093,"./it":48528,"./it-ch":63338,"./it-ch.js":63338,"./it.js":48528,"./ja":89252,"./ja.js":89252,"./jv":39969,"./jv.js":39969,"./ka":29245,"./ka.js":29245,"./kk":19667,"./kk.js":19667,"./km":28761,"./km.js":28761,"./kn":94464,"./kn.js":94464,"./ko":35767,"./ko.js":35767,"./ku":23889,"./ku.js":23889,"./ky":91269,"./ky.js":91269,"./lb":36763,"./lb.js":36763,"./lo":17472,"./lo.js":17472,"./lt":46897,"./lt.js":46897,"./lv":24911,"./lv.js":24911,"./me":75691,"./me.js":75691,"./mi":64999,"./mi.js":64999,"./mk":99977,"./mk.js":99977,"./ml":60028,"./ml.js":60028,"./mn":71494,"./mn.js":71494,"./mr":59506,"./mr.js":59506,"./ms":27137,"./ms-my":52732,"./ms-my.js":52732,"./ms.js":27137,"./mt":42068,"./mt.js":42068,"./my":60439,"./my.js":60439,"./nb":51081,"./nb.js":51081,"./ne":60604,"./ne.js":60604,"./nl":92619,"./nl-be":10629,"./nl-be.js":10629,"./nl.js":92619,"./nn":35757,"./nn.js":35757,"./pa-in":30184,"./pa-in.js":30184,"./pl":79917,"./pl.js":79917,"./pt":89781,"./pt-br":75358,"./pt-br.js":75358,"./pt.js":89781,"./ro":39010,"./ro.js":39010,"./ru":77472,"./ru.js":77472,"./sd":1002,"./sd.js":1002,"./se":13785,"./se.js":13785,"./si":95933,"./si.js":95933,"./sk":15675,"./sk.js":15675,"./sl":85170,"./sl.js":85170,"./sq":15429,"./sq.js":15429,"./sr":69340,"./sr-cyrl":82611,"./sr-cyrl.js":82611,"./sr.js":69340,"./ss":67331,"./ss.js":67331,"./sv":50160,"./sv.js":50160,"./sw":74311,"./sw.js":74311,"./ta":93654,"./ta.js":93654,"./te":93258,"./te.js":93258,"./tet":77100,"./tet.js":77100,"./tg":95040,"./tg.js":95040,"./th":46173,"./th.js":46173,"./tl-ph":59562,"./tl-ph.js":59562,"./tlh":6533,"./tlh.js":6533,"./tr":82883,"./tr.js":82883,"./tzl":83143,"./tzl.js":83143,"./tzm":76272,"./tzm-latn":86256,"./tzm-latn.js":86256,"./tzm.js":76272,"./ug-cn":75035,"./ug-cn.js":75035,"./uk":28241,"./uk.js":28241,"./ur":62858,"./ur.js":62858,"./uz":95442,"./uz-latn":81554,"./uz-latn.js":81554,"./uz.js":95442,"./vi":88352,"./vi.js":88352,"./x-pseudo":66900,"./x-pseudo.js":66900,"./yo":91889,"./yo.js":91889,"./zh-cn":58101,"./zh-cn.js":58101,"./zh-hk":43641,"./zh-hk.js":43641,"./zh-tw":63921,"./zh-tw.js":63921}
2
2
  function n(e){var t=l(e)
3
3
  return r(t)}function l(e){if(!r.o(o,e)){var t=new Error("Cannot find module '"+e+"'")
4
- throw t.code="MODULE_NOT_FOUND",t}return o[e]}n.keys=function(){return Object.keys(o)},n.resolve=l,e.exports=n,n.id=45525},60366(){},21901(){},20140(e,t){window._eai_r=require,window._eai_d=define},77906(e,t,r){"use strict"
4
+ throw t.code="MODULE_NOT_FOUND",t}return o[e]}n.keys=function(){return Object.keys(o)},n.resolve=l,e.exports=n,n.id=45525},60366(){},21901(){},82459(e,t){window._eai_r=require,window._eai_d=define},77906(e,t,r){"use strict"
5
5
  Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})
6
6
  const o="ConfigResponseType",n=o,l=r(44963).createQuery({dataType:o,path:"/config/"})
7
7
  t.configDataType=n,t.hasSendingDomain=e=>{var t,r
@@ -585,4 +585,4 @@ if(!e)throw new Error("useFocusContext must be used within a FocusProvider")
585
585
  return e},u=({fetchKoenigLexical:e,darkMode:t,children:r})=>{const[c,d]=(0,l.useState)(!1)
586
586
  return(0,o.jsx)(i.Provider,{value:{isAnyTextFieldFocused:c,setFocusState:e=>{d(e)},fetchKoenigLexical:e,darkMode:t},children:(0,o.jsxs)(a.y,{children:[(0,o.jsx)(s.l$,{}),(0,o.jsx)(n.Ay.Provider,{children:r})]})})}}}])
587
587
 
588
- //# sourceMappingURL=chunk.526.96b1ceeb47f193bbd5cf.map
588
+ //# sourceMappingURL=chunk.289.799159a53c663e5c4afd.map
@@ -1,6 +1,6 @@
1
1
  var __ember_auto_import__;(()=>{var e,r,t,n,o,i={32186(e){"use strict"
2
2
  e.exports=require("@ember/test-waiters")},80032(e){"use strict"
3
- e.exports=require("ember-tracked-storage-polyfill")},80681(e,r,t){e.exports=function(){var e=_eai_d,r=_eai_r
3
+ e.exports=require("ember-tracked-storage-polyfill")},44910(e,r,t){e.exports=function(){var e=_eai_d,r=_eai_r
4
4
  function n(e){return e&&e.__esModule?e:Object.assign({default:e},e)}window.emberAutoImportDynamic=function(e){return 1===arguments.length?r("_eai_dyn_"+e):r("_eai_dynt_"+e)(Array.prototype.slice.call(arguments,1))},window.emberAutoImportSync=function(e){return r("_eai_sync_"+e)(Array.prototype.slice.call(arguments,1))},e("@sentry/browser",[],function(){return n(t(77931))}),e("@sentry/core",[],function(){return n(t(80630))}),e("@sentry/integrations",[],function(){return n(t(92549))}),e("@sentry/replay",[],function(){return n(t(3586))}),e("@sentry/utils",[],function(){return n(t(67342))}),e("@tryghost/admin-x-framework/hooks",[],function(){return n(t(79220))}),e("@tryghost/color-utils",[],function(){return n(t(5569))}),e("@tryghost/kg-clean-basic-html",[],function(){return n(t(78339))}),e("@tryghost/kg-converters",[],function(){return n(t(70053))}),e("@tryghost/limit-service",[],function(){return n(t(64528))}),e("@tryghost/members-csv/lib/unparse",[],function(){return n(t(42369))}),e("@tryghost/nql",[],function(){return n(t(76442))}),e("@tryghost/nql-lang",[],function(){return n(t(66800))}),e("@tryghost/string",[],function(){return n(t(29897))}),e("@tryghost/timezone-data",[],function(){return n(t(96140))}),e("element-resize-detector",[],function(){return n(t(16012))}),e("ember-assign-helper/helpers/assign",[],function(){return n(t(146))}),e("ember-css-transitions/modifiers/css-transition",["@ember/test-waiters"],function(){return n(t(35471))}),e("ember-keyboard/helpers/if-key.js",[],function(){return n(t(65305))}),e("ember-keyboard/helpers/on-key.js",[],function(){return n(t(4111))}),e("ember-keyboard/modifiers/on-key.js",[],function(){return n(t(98590))}),e("ember-keyboard/services/keyboard.js",[],function(){return n(t(88863))}),e("ember-modifier",[],function(){return n(t(7607))}),e("ember-moment/helpers/-base",[],function(){return n(t(65601))}),e("ember-moment/helpers/is-after",[],function(){return n(t(33080))}),e("ember-moment/helpers/is-before",[],function(){return n(t(97083))}),e("ember-moment/helpers/is-between",[],function(){return n(t(33470))}),e("ember-moment/helpers/is-same",[],function(){return n(t(27430))}),e("ember-moment/helpers/is-same-or-after",[],function(){return n(t(30029))}),e("ember-moment/helpers/is-same-or-before",[],function(){return n(t(4528))}),e("ember-moment/helpers/moment",[],function(){return n(t(51367))}),e("ember-moment/helpers/moment-add",[],function(){return n(t(91717))}),e("ember-moment/helpers/moment-calendar",[],function(){return n(t(61150))}),e("ember-moment/helpers/moment-diff",[],function(){return n(t(45027))}),e("ember-moment/helpers/moment-duration",[],function(){return n(t(22664))}),e("ember-moment/helpers/moment-format",[],function(){return n(t(41431))}),e("ember-moment/helpers/moment-from",[],function(){return n(t(35200))}),e("ember-moment/helpers/moment-from-now",[],function(){return n(t(1141))}),e("ember-moment/helpers/moment-subtract",[],function(){return n(t(6392))}),e("ember-moment/helpers/moment-to",[],function(){return n(t(44429))}),e("ember-moment/helpers/moment-to-date",[],function(){return n(t(2794))}),e("ember-moment/helpers/moment-to-now",[],function(){return n(t(91412))}),e("ember-moment/helpers/now",[],function(){return n(t(17371))}),e("ember-moment/helpers/unix",[],function(){return n(t(37145))}),e("ember-moment/helpers/utc",[],function(){return n(t(83333))}),e("ember-moment/services/moment",[],function(){return n(t(51004))}),e("fast-deep-equal",[],function(){return n(t(52369))}),e("flexsearch",[],function(){return n(t(1850))}),e("focus-trap",[],function(){return n(t(26479))}),e("intersection-observer-admin",[],function(){return n(t(72959))}),e("microdiff",[],function(){return n(t(75917))}),e("moment-timezone",[],function(){return n(t(60104))}),e("papaparse",[],function(){return n(t(62034))}),e("raf-pool",[],function(){return n(t(33795))}),e("react",[],function(){return n(t(14523))}),e("react-dom",[],function(){return n(t(35740))}),e("react-dom/client",[],function(){return n(t(10437))}),e("react/jsx-runtime",[],function(){return n(t(34475))}),e("tooltip.js",[],function(){return n(t(92376))}),e("tracked-built-ins",["ember-tracked-storage-polyfill"],function(){return n(t(41284))}),e("validator",[],function(){return n(t(44267))}),e("_eai_dyn_@sentry/browser",[],function(){return Promise.resolve().then(t.bind(t,77931))})}()}},u={}
5
5
  function s(e){var r=u[e]
6
6
  if(void 0!==r)return r.exports
@@ -39,8 +39,8 @@ var r=(r,t)=>{var n,o,[i,u,m]=t,a=0
39
39
  if(i.some(r=>0!==e[r])){for(n in u)s.o(u,n)&&(s.m[n]=u[n])
40
40
  if(m)var c=m(s)}for(r&&r(t);a<i.length;a++)o=i[a],s.o(e,o)&&e[o]&&e[o][0](),e[o]=0
41
41
  return s.O(c)},t=globalThis.webpackChunk_ember_auto_import_=globalThis.webpackChunk_ember_auto_import_||[]
42
- t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),s.nc=void 0,s.O(void 0,[567,526],()=>s(s.s=20140))
43
- var m=s.O(void 0,[567,526],()=>s(s.s=80681))
42
+ t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),s.nc=void 0,s.O(void 0,[567,289],()=>s(s.s=82459))
43
+ var m=s.O(void 0,[567,289],()=>s(s.s=44910))
44
44
  m=s.O(m),__ember_auto_import__=m})()
45
45
 
46
- //# sourceMappingURL=chunk.524.3015bfad0b069d85881d.map
46
+ //# sourceMappingURL=chunk.524.fd32ec309de4906c5734.map
@@ -1,9 +1,9 @@
1
1
  var __ember_auto_import__;(()=>{var e,r,t,n,o,E={32186(e){"use strict"
2
2
  e.exports=require("@ember/test-waiters")},80032(e){"use strict"
3
- e.exports=require("ember-tracked-storage-polyfill")},80681(e,r,t){e.exports=function(){var e=_eai_d,r=_eai_r
4
- function n(e){return e&&e.__esModule?e:Object.assign({default:e},e)}window.emberAutoImportDynamic=function(e){return 1===arguments.length?r("_eai_dyn_"+e):r("_eai_dynt_"+e)(Array.prototype.slice.call(arguments,1))},window.emberAutoImportSync=function(e){return r("_eai_sync_"+e)(Array.prototype.slice.call(arguments,1))},e("@sentry/browser",EAI_DISCOVERED_EXTERNALS("@sentry/browser"),function(){return n(t(77931))}),e("@sentry/core",EAI_DISCOVERED_EXTERNALS("@sentry/core"),function(){return n(t(80630))}),e("@sentry/integrations",EAI_DISCOVERED_EXTERNALS("@sentry/integrations"),function(){return n(t(92549))}),e("@sentry/replay",EAI_DISCOVERED_EXTERNALS("@sentry/replay"),function(){return n(t(3586))}),e("@sentry/utils",EAI_DISCOVERED_EXTERNALS("@sentry/utils"),function(){return n(t(67342))}),e("@tryghost/admin-x-framework/hooks",EAI_DISCOVERED_EXTERNALS("@tryghost/admin-x-framework/hooks"),function(){return n(t(79220))}),e("@tryghost/color-utils",EAI_DISCOVERED_EXTERNALS("@tryghost/color-utils"),function(){return n(t(5569))}),e("@tryghost/kg-clean-basic-html",EAI_DISCOVERED_EXTERNALS("@tryghost/kg-clean-basic-html"),function(){return n(t(78339))}),e("@tryghost/kg-converters",EAI_DISCOVERED_EXTERNALS("@tryghost/kg-converters"),function(){return n(t(70053))}),e("@tryghost/limit-service",EAI_DISCOVERED_EXTERNALS("@tryghost/limit-service"),function(){return n(t(64528))}),e("@tryghost/members-csv/lib/unparse",EAI_DISCOVERED_EXTERNALS("@tryghost/members-csv/lib/unparse"),function(){return n(t(42369))}),e("@tryghost/nql",EAI_DISCOVERED_EXTERNALS("@tryghost/nql"),function(){return n(t(76442))}),e("@tryghost/nql-lang",EAI_DISCOVERED_EXTERNALS("@tryghost/nql-lang"),function(){return n(t(66800))}),e("@tryghost/string",EAI_DISCOVERED_EXTERNALS("@tryghost/string"),function(){return n(t(29897))}),e("@tryghost/timezone-data",EAI_DISCOVERED_EXTERNALS("@tryghost/timezone-data"),function(){return n(t(96140))}),e("element-resize-detector",EAI_DISCOVERED_EXTERNALS("element-resize-detector"),function(){return n(t(16012))}),e("ember-assign-helper/helpers/assign",EAI_DISCOVERED_EXTERNALS("ember-assign-helper/helpers/assign"),function(){return n(t(146))}),e("ember-css-transitions/modifiers/css-transition",EAI_DISCOVERED_EXTERNALS("ember-css-transitions/modifiers/css-transition"),function(){return n(t(35471))}),e("ember-keyboard/helpers/if-key.js",EAI_DISCOVERED_EXTERNALS("ember-keyboard/helpers/if-key.js"),function(){return n(t(65305))}),e("ember-keyboard/helpers/on-key.js",EAI_DISCOVERED_EXTERNALS("ember-keyboard/helpers/on-key.js"),function(){return n(t(4111))}),e("ember-keyboard/modifiers/on-key.js",EAI_DISCOVERED_EXTERNALS("ember-keyboard/modifiers/on-key.js"),function(){return n(t(98590))}),e("ember-keyboard/services/keyboard.js",EAI_DISCOVERED_EXTERNALS("ember-keyboard/services/keyboard.js"),function(){return n(t(88863))}),e("ember-modifier",EAI_DISCOVERED_EXTERNALS("ember-modifier"),function(){return n(t(7607))}),e("ember-moment/helpers/-base",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/-base"),function(){return n(t(65601))}),e("ember-moment/helpers/is-after",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-after"),function(){return n(t(33080))}),e("ember-moment/helpers/is-before",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-before"),function(){return n(t(97083))}),e("ember-moment/helpers/is-between",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-between"),function(){return n(t(33470))}),e("ember-moment/helpers/is-same",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-same"),function(){return n(t(27430))}),e("ember-moment/helpers/is-same-or-after",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-same-or-after"),function(){return n(t(30029))}),e("ember-moment/helpers/is-same-or-before",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-same-or-before"),function(){return n(t(4528))}),e("ember-moment/helpers/moment",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment"),function(){return n(t(51367))}),e("ember-moment/helpers/moment-add",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-add"),function(){return n(t(91717))}),e("ember-moment/helpers/moment-calendar",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-calendar"),function(){return n(t(61150))}),e("ember-moment/helpers/moment-diff",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-diff"),function(){return n(t(45027))}),e("ember-moment/helpers/moment-duration",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-duration"),function(){return n(t(22664))}),e("ember-moment/helpers/moment-format",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-format"),function(){return n(t(41431))}),e("ember-moment/helpers/moment-from",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-from"),function(){return n(t(35200))}),e("ember-moment/helpers/moment-from-now",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-from-now"),function(){return n(t(1141))}),e("ember-moment/helpers/moment-subtract",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-subtract"),function(){return n(t(6392))}),e("ember-moment/helpers/moment-to",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-to"),function(){return n(t(44429))}),e("ember-moment/helpers/moment-to-date",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-to-date"),function(){return n(t(2794))}),e("ember-moment/helpers/moment-to-now",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-to-now"),function(){return n(t(91412))}),e("ember-moment/helpers/now",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/now"),function(){return n(t(17371))}),e("ember-moment/helpers/unix",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/unix"),function(){return n(t(37145))}),e("ember-moment/helpers/utc",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/utc"),function(){return n(t(83333))}),e("ember-moment/services/moment",EAI_DISCOVERED_EXTERNALS("ember-moment/services/moment"),function(){return n(t(51004))}),e("fast-deep-equal",EAI_DISCOVERED_EXTERNALS("fast-deep-equal"),function(){return n(t(52369))}),e("flexsearch",EAI_DISCOVERED_EXTERNALS("flexsearch"),function(){return n(t(1850))}),e("focus-trap",EAI_DISCOVERED_EXTERNALS("focus-trap"),function(){return n(t(26479))}),e("intersection-observer-admin",EAI_DISCOVERED_EXTERNALS("intersection-observer-admin"),function(){return n(t(72959))}),e("microdiff",EAI_DISCOVERED_EXTERNALS("microdiff"),function(){return n(t(75917))}),e("moment-timezone",EAI_DISCOVERED_EXTERNALS("moment-timezone"),function(){return n(t(60104))}),e("papaparse",EAI_DISCOVERED_EXTERNALS("papaparse"),function(){return n(t(62034))}),e("raf-pool",EAI_DISCOVERED_EXTERNALS("raf-pool"),function(){return n(t(33795))}),e("react",EAI_DISCOVERED_EXTERNALS("react"),function(){return n(t(14523))}),e("react-dom",EAI_DISCOVERED_EXTERNALS("react-dom"),function(){return n(t(35740))}),e("react-dom/client",EAI_DISCOVERED_EXTERNALS("react-dom/client"),function(){return n(t(10437))}),e("react/jsx-runtime",EAI_DISCOVERED_EXTERNALS("react/jsx-runtime"),function(){return n(t(34475))}),e("tooltip.js",EAI_DISCOVERED_EXTERNALS("tooltip.js"),function(){return n(t(92376))}),e("tracked-built-ins",EAI_DISCOVERED_EXTERNALS("tracked-built-ins"),function(){return n(t(41284))}),e("validator",EAI_DISCOVERED_EXTERNALS("validator"),function(){return n(t(44267))}),e("_eai_dyn_@sentry/browser",[],function(){return Promise.resolve().then(t.bind(t,77931))})}()},13351(e,r,t){e.exports=function(){_eai_d
3
+ e.exports=require("ember-tracked-storage-polyfill")},44910(e,r,t){e.exports=function(){var e=_eai_d,r=_eai_r
4
+ function n(e){return e&&e.__esModule?e:Object.assign({default:e},e)}window.emberAutoImportDynamic=function(e){return 1===arguments.length?r("_eai_dyn_"+e):r("_eai_dynt_"+e)(Array.prototype.slice.call(arguments,1))},window.emberAutoImportSync=function(e){return r("_eai_sync_"+e)(Array.prototype.slice.call(arguments,1))},e("@sentry/browser",EAI_DISCOVERED_EXTERNALS("@sentry/browser"),function(){return n(t(77931))}),e("@sentry/core",EAI_DISCOVERED_EXTERNALS("@sentry/core"),function(){return n(t(80630))}),e("@sentry/integrations",EAI_DISCOVERED_EXTERNALS("@sentry/integrations"),function(){return n(t(92549))}),e("@sentry/replay",EAI_DISCOVERED_EXTERNALS("@sentry/replay"),function(){return n(t(3586))}),e("@sentry/utils",EAI_DISCOVERED_EXTERNALS("@sentry/utils"),function(){return n(t(67342))}),e("@tryghost/admin-x-framework/hooks",EAI_DISCOVERED_EXTERNALS("@tryghost/admin-x-framework/hooks"),function(){return n(t(79220))}),e("@tryghost/color-utils",EAI_DISCOVERED_EXTERNALS("@tryghost/color-utils"),function(){return n(t(5569))}),e("@tryghost/kg-clean-basic-html",EAI_DISCOVERED_EXTERNALS("@tryghost/kg-clean-basic-html"),function(){return n(t(78339))}),e("@tryghost/kg-converters",EAI_DISCOVERED_EXTERNALS("@tryghost/kg-converters"),function(){return n(t(70053))}),e("@tryghost/limit-service",EAI_DISCOVERED_EXTERNALS("@tryghost/limit-service"),function(){return n(t(64528))}),e("@tryghost/members-csv/lib/unparse",EAI_DISCOVERED_EXTERNALS("@tryghost/members-csv/lib/unparse"),function(){return n(t(42369))}),e("@tryghost/nql",EAI_DISCOVERED_EXTERNALS("@tryghost/nql"),function(){return n(t(76442))}),e("@tryghost/nql-lang",EAI_DISCOVERED_EXTERNALS("@tryghost/nql-lang"),function(){return n(t(66800))}),e("@tryghost/string",EAI_DISCOVERED_EXTERNALS("@tryghost/string"),function(){return n(t(29897))}),e("@tryghost/timezone-data",EAI_DISCOVERED_EXTERNALS("@tryghost/timezone-data"),function(){return n(t(96140))}),e("element-resize-detector",EAI_DISCOVERED_EXTERNALS("element-resize-detector"),function(){return n(t(16012))}),e("ember-assign-helper/helpers/assign",EAI_DISCOVERED_EXTERNALS("ember-assign-helper/helpers/assign"),function(){return n(t(146))}),e("ember-css-transitions/modifiers/css-transition",EAI_DISCOVERED_EXTERNALS("ember-css-transitions/modifiers/css-transition"),function(){return n(t(35471))}),e("ember-keyboard/helpers/if-key.js",EAI_DISCOVERED_EXTERNALS("ember-keyboard/helpers/if-key.js"),function(){return n(t(65305))}),e("ember-keyboard/helpers/on-key.js",EAI_DISCOVERED_EXTERNALS("ember-keyboard/helpers/on-key.js"),function(){return n(t(4111))}),e("ember-keyboard/modifiers/on-key.js",EAI_DISCOVERED_EXTERNALS("ember-keyboard/modifiers/on-key.js"),function(){return n(t(98590))}),e("ember-keyboard/services/keyboard.js",EAI_DISCOVERED_EXTERNALS("ember-keyboard/services/keyboard.js"),function(){return n(t(88863))}),e("ember-modifier",EAI_DISCOVERED_EXTERNALS("ember-modifier"),function(){return n(t(7607))}),e("ember-moment/helpers/-base",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/-base"),function(){return n(t(65601))}),e("ember-moment/helpers/is-after",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-after"),function(){return n(t(33080))}),e("ember-moment/helpers/is-before",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-before"),function(){return n(t(97083))}),e("ember-moment/helpers/is-between",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-between"),function(){return n(t(33470))}),e("ember-moment/helpers/is-same",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-same"),function(){return n(t(27430))}),e("ember-moment/helpers/is-same-or-after",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-same-or-after"),function(){return n(t(30029))}),e("ember-moment/helpers/is-same-or-before",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/is-same-or-before"),function(){return n(t(4528))}),e("ember-moment/helpers/moment",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment"),function(){return n(t(51367))}),e("ember-moment/helpers/moment-add",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-add"),function(){return n(t(91717))}),e("ember-moment/helpers/moment-calendar",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-calendar"),function(){return n(t(61150))}),e("ember-moment/helpers/moment-diff",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-diff"),function(){return n(t(45027))}),e("ember-moment/helpers/moment-duration",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-duration"),function(){return n(t(22664))}),e("ember-moment/helpers/moment-format",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-format"),function(){return n(t(41431))}),e("ember-moment/helpers/moment-from",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-from"),function(){return n(t(35200))}),e("ember-moment/helpers/moment-from-now",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-from-now"),function(){return n(t(1141))}),e("ember-moment/helpers/moment-subtract",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-subtract"),function(){return n(t(6392))}),e("ember-moment/helpers/moment-to",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-to"),function(){return n(t(44429))}),e("ember-moment/helpers/moment-to-date",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-to-date"),function(){return n(t(2794))}),e("ember-moment/helpers/moment-to-now",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/moment-to-now"),function(){return n(t(91412))}),e("ember-moment/helpers/now",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/now"),function(){return n(t(17371))}),e("ember-moment/helpers/unix",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/unix"),function(){return n(t(37145))}),e("ember-moment/helpers/utc",EAI_DISCOVERED_EXTERNALS("ember-moment/helpers/utc"),function(){return n(t(83333))}),e("ember-moment/services/moment",EAI_DISCOVERED_EXTERNALS("ember-moment/services/moment"),function(){return n(t(51004))}),e("fast-deep-equal",EAI_DISCOVERED_EXTERNALS("fast-deep-equal"),function(){return n(t(52369))}),e("flexsearch",EAI_DISCOVERED_EXTERNALS("flexsearch"),function(){return n(t(1850))}),e("focus-trap",EAI_DISCOVERED_EXTERNALS("focus-trap"),function(){return n(t(26479))}),e("intersection-observer-admin",EAI_DISCOVERED_EXTERNALS("intersection-observer-admin"),function(){return n(t(72959))}),e("microdiff",EAI_DISCOVERED_EXTERNALS("microdiff"),function(){return n(t(75917))}),e("moment-timezone",EAI_DISCOVERED_EXTERNALS("moment-timezone"),function(){return n(t(60104))}),e("papaparse",EAI_DISCOVERED_EXTERNALS("papaparse"),function(){return n(t(62034))}),e("raf-pool",EAI_DISCOVERED_EXTERNALS("raf-pool"),function(){return n(t(33795))}),e("react",EAI_DISCOVERED_EXTERNALS("react"),function(){return n(t(14523))}),e("react-dom",EAI_DISCOVERED_EXTERNALS("react-dom"),function(){return n(t(35740))}),e("react-dom/client",EAI_DISCOVERED_EXTERNALS("react-dom/client"),function(){return n(t(10437))}),e("react/jsx-runtime",EAI_DISCOVERED_EXTERNALS("react/jsx-runtime"),function(){return n(t(34475))}),e("tooltip.js",EAI_DISCOVERED_EXTERNALS("tooltip.js"),function(){return n(t(92376))}),e("tracked-built-ins",EAI_DISCOVERED_EXTERNALS("tracked-built-ins"),function(){return n(t(41284))}),e("validator",EAI_DISCOVERED_EXTERNALS("validator"),function(){return n(t(44267))}),e("_eai_dyn_@sentry/browser",[],function(){return Promise.resolve().then(t.bind(t,77931))})}()},81328(e,r,t){e.exports=function(){_eai_d
5
5
  var e=_eai_r
6
- window.emberAutoImportDynamic=function(r){return 1===arguments.length?e("_eai_dyn_"+r):e("_eai_dynt_"+r)(Array.prototype.slice.call(arguments,1))},window.emberAutoImportSync=function(r){return e("_eai_sync_"+r)(Array.prototype.slice.call(arguments,1))},t(80681)}()}},m={}
6
+ window.emberAutoImportDynamic=function(r){return 1===arguments.length?e("_eai_dyn_"+r):e("_eai_dynt_"+r)(Array.prototype.slice.call(arguments,1))},window.emberAutoImportSync=function(r){return e("_eai_sync_"+r)(Array.prototype.slice.call(arguments,1))},t(44910)}()}},m={}
7
7
  function i(e){var r=m[e]
8
8
  if(void 0!==r)return r.exports
9
9
  var t=m[e]={id:e,loaded:!1,exports:{}}
@@ -41,8 +41,8 @@ var r=(r,t)=>{var n,o,[E,m,s]=t,u=0
41
41
  if(E.some(r=>0!==e[r])){for(n in m)i.o(m,n)&&(i.m[n]=m[n])
42
42
  if(s)var a=s(i)}for(r&&r(t);u<E.length;u++)o=E[u],i.o(e,o)&&e[o]&&e[o][0](),e[o]=0
43
43
  return i.O(a)},t=globalThis.webpackChunk_ember_auto_import_=globalThis.webpackChunk_ember_auto_import_||[]
44
- t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),i.nc=void 0,i.O(void 0,[567,526],()=>i(i.s=20140))
45
- var s=i.O(void 0,[567,526],()=>i(i.s=13351))
44
+ t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),i.nc=void 0,i.O(void 0,[567,289],()=>i(i.s=82459))
45
+ var s=i.O(void 0,[567,289],()=>i(i.s=81328))
46
46
  s=i.O(s),__ember_auto_import__=s})()
47
47
 
48
- //# sourceMappingURL=chunk.582.21a5a8ae91c8e92e76cd.map
48
+ //# sourceMappingURL=chunk.582.696652c545ccf71958b8.map
@@ -4227,6 +4227,6 @@ this.passwordChange(e),e.hasValidated.addObject("password"),Ember.isBlank(t)&&(e
4227
4227
  e.default=n.create()}),define("ghost-admin/validators/webhook",["exports","ghost-admin/validators/base","validator"],function(e,t,i){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
4228
4228
  e.default=t.default.create({properties:["name","event","targetUrl","secret"],name(e){Ember.isBlank(e.name)?(e.errors.add("name","Please enter a name"),e.hasValidated.pushObject("name"),this.invalidate()):i.default.isLength(e.name,{max:191})||(e.errors.add("name","Name is too long, max 191 chars"),e.hasValidated.pushObject("name"),this.invalidate())},event(e){Ember.isBlank(e.event)&&(e.errors.add("event","Please select an event"),e.hasValidated.pushObject("event"),this.invalidate())},targetUrl(e){Ember.isBlank(e.targetUrl)?e.errors.add("targetUrl","Please enter a target URL"):i.default.isURL(e.targetUrl||"",{require_protocol:!1})?i.default.isLength(e.targetUrl,{max:2e3})||e.errors.add("targetUrl","Target URL is too long, max 2000 chars"):e.errors.add("targetUrl","Please enter a valid URL"),e.hasValidated.pushObject("targetUrl"),e.errors.has("targetUrl")&&this.invalidate()},secret(e){Ember.isBlank(e.secret)||i.default.isLength(e.secret,{max:191})||(e.errors.add("secret","Secret is too long, max 191 chars"),e.hasValidated.pushObject("secret"),this.invalidate())}})}),define("ghost-admin/views/application",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
4229
4229
  e.default=Ember.Component.extend({})}),define("ghost-admin/config/environment",[],function(){try{var e="ghost-admin/config/environment",t=document.querySelector('meta[name="'+e+'"]').getAttribute("content"),i={default:JSON.parse(decodeURIComponent(t))}
4230
- return Object.defineProperty(i,"__esModule",{value:!0}),i}catch(r){throw new Error('Could not read config from meta tag with name "'+e+'".')}}),runningTests||require("ghost-admin/app").default.create({version:"6.33",name:"ghost-admin"})
4230
+ return Object.defineProperty(i,"__esModule",{value:!0}),i}catch(r){throw new Error('Could not read config from meta tag with name "'+e+'".')}}),runningTests||require("ghost-admin/app").default.create({version:"6.34",name:"ghost-admin"})
4231
4231
 
4232
- //# sourceMappingURL=ghost-e34e2651a023624971bed7e7f5687582.map
4232
+ //# sourceMappingURL=ghost-c66899846bf5d36c7b3fa1d7032132d9.map
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <link rel="stylesheet" href="./assets/vendor-0ede59da8efb5e28fa929557f7ff7154.css">
5
5
  <link rel="stylesheet" href="./assets/ghost-5834d05a5f9db6427f698f778ba9f61c.css">
6
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%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%226.33%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%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%223f1ed7f146%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%22dc57b89058%22%2C%22activitypubFilename%22%3A%22activitypub.js%22%2C%22activitypubHash%22%3A%221acc3317bc%22%2C%22postsFilename%22%3A%22posts.js%22%2C%22postsHash%22%3A%2261e829dd18%22%2C%22statsFilename%22%3A%22stats.js%22%2C%22statsHash%22%3A%224ca3594205%22%2C%22activitypubRemoteConfigUrl%22%3A%22%2F.ghost%2Factivitypub%2Fstable%2Fclient-config%22%7D">
6
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%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%226.34%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%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%223f1ed7f146%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%22d188ff0207%22%2C%22activitypubFilename%22%3A%22activitypub.js%22%2C%22activitypubHash%22%3A%221acc3317bc%22%2C%22postsFilename%22%3A%22posts.js%22%2C%22postsHash%22%3A%2261e829dd18%22%2C%22statsFilename%22%3A%22stats.js%22%2C%22statsHash%22%3A%224ca3594205%22%2C%22activitypubRemoteConfigUrl%22%3A%22%2F.ghost%2Factivitypub%2Fstable%2Fclient-config%22%7D">
7
7
 
8
8
  <meta charset="UTF-8" />
9
9
 
@@ -39,8 +39,8 @@
39
39
  <div id="ember-notifications-wormhole"></div>
40
40
  <script src="./assets/vendor-32b8ef7b02092ccf89d9146a6c5f29f9.js"></script>
41
41
  <script src="./assets/chunk.567.a7e3a52b7e53a0c8c557.js"></script>
42
- <script src="./assets/chunk.526.96b1ceeb47f193bbd5cf.js"></script>
43
- <script src="./assets/chunk.524.3015bfad0b069d85881d.js"></script>
44
- <script src="./assets/ghost-f48d0d808daca3e7828effda55ce351d.js"></script>
42
+ <script src="./assets/chunk.289.799159a53c663e5c4afd.js"></script>
43
+ <script src="./assets/chunk.524.fd32ec309de4906c5734.js"></script>
44
+ <script src="./assets/ghost-2b736ae44ae91e9b1034ed7f4041ed5c.js"></script>
45
45
  </body>
46
46
  </html>
@@ -1 +1 @@
1
- "use strict";const adminUrl=window.location.href.replace("auth-frame/","")+"api/admin",siteOrigin="{{SITE_ORIGIN}}";window.addEventListener("message",async function(a){if(a.origin!==siteOrigin){console.warn("Ignored message to admin auth iframe because of mismatch in origin","expected",siteOrigin,"got",a.origin,"with data",a.data);return}let n=null;try{n=JSON.parse(a.data)}catch(t){console.error(t)}function e(t,s){a.source.postMessage(JSON.stringify({uid:n.uid,error:t,result:s}),siteOrigin)}if(n.action==="browseComments")try{const{postId:t,params:s}=n,o=await(await fetch(adminUrl+`/comments/post/${t}/?${new URLSearchParams(s).toString()}`)).json();e(null,o)}catch(t){e(t,null)}if(n.action==="getReplies")try{const{commentId:t,params:s}=n,o=await(await fetch(adminUrl+`/comments/${t}/replies/?${new URLSearchParams(s).toString()}`)).json();e(null,o)}catch(t){e(t,null)}if(n.action==="readComment")try{const{commentId:t,params:s}=n,o=await(await fetch(adminUrl+"/comments/"+t+"/?"+new URLSearchParams(s).toString())).json();e(null,o)}catch(t){e(t,null)}if(n.action==="getUser")try{const s=await(await fetch(adminUrl+"/users/me/?include=roles")).json();e(null,s)}catch(t){e(t,null)}if(n.action==="hideComment")try{const s=await(await fetch(adminUrl+"/comments/"+n.id+"/",{method:"PUT",body:JSON.stringify({comments:[{id:n.id,status:"hidden"}]}),headers:{"Content-Type":"application/json"}})).json();e(null,s)}catch(t){e(t,null)}if(n.action==="showComment")try{const s=await(await fetch(adminUrl+"/comments/"+n.id+"/",{method:"PUT",body:JSON.stringify({comments:[{id:n.id,status:"published"}]}),headers:{"Content-Type":"application/json"}})).json();e(null,s)}catch(t){e(t,null)}});
1
+ "use strict";const adminUrl=window.location.href.replace("auth-frame/","")+"api/admin",siteOrigin="{{SITE_ORIGIN}}";function id(e){if(typeof e!="string"||!/^[a-f0-9]{24}$/i.test(e))throw new Error("Invalid identifier");return e}function qs(e){const t=new URLSearchParams(e).toString();return t?"?"+t:""}function setCommentStatus(e,t){const s=id(e);return fetch(`${adminUrl}/comments/${s}/`,{method:"PUT",body:JSON.stringify({comments:[{id:s,status:t}]}),headers:{"Content-Type":"application/json"}})}const actions={browseComments:e=>fetch(`${adminUrl}/comments/post/${id(e.postId)}/${qs(e.params)}`),getReplies:e=>fetch(`${adminUrl}/comments/${id(e.commentId)}/replies/${qs(e.params)}`),readComment:e=>fetch(`${adminUrl}/comments/${id(e.commentId)}/${qs(e.params)}`),getUser:()=>fetch(`${adminUrl}/users/me/?include=roles`),hideComment:e=>setCommentStatus(e.id,"hidden"),showComment:e=>setCommentStatus(e.id,"published")};window.addEventListener("message",async function(e){if(e.origin!==siteOrigin){console.warn("Ignored message to admin auth iframe because of mismatch in origin","expected",siteOrigin,"got",e.origin,"with data",e.data);return}let t;try{t=JSON.parse(e.data)}catch(n){console.error("Admin auth iframe failed to parse message from site origin:",e.data,n);return}function s(n,o){e.source.postMessage(JSON.stringify({uid:t.uid,error:n?n.message:null,result:o}),siteOrigin)}const i=actions[t.action];if(i)try{const o=await(await i(t)).json();s(null,o)}catch(n){s(n,null)}});
@@ -3,114 +3,72 @@ const adminUrl = window.location.href.replace('auth-frame/', '') + 'api/admin';
3
3
  // At compile time, we'll replace the value with the actual origin.
4
4
  const siteOrigin = '{{SITE_ORIGIN}}';
5
5
 
6
+ function id(value) {
7
+ if (typeof value !== 'string' || !/^[a-f0-9]{24}$/i.test(value)) {
8
+ throw new Error('Invalid identifier');
9
+ }
10
+ return value;
11
+ }
12
+
13
+ function qs(params) {
14
+ const s = new URLSearchParams(params).toString();
15
+ return s ? '?' + s : '';
16
+ }
17
+
18
+ function setCommentStatus(commentId, status) {
19
+ const safeId = id(commentId);
20
+ return fetch(`${adminUrl}/comments/${safeId}/`, {
21
+ method: 'PUT',
22
+ body: JSON.stringify({
23
+ comments: [{id: safeId, status}]
24
+ }),
25
+ headers: {
26
+ 'Content-Type': 'application/json'
27
+ }
28
+ });
29
+ }
30
+
31
+ const actions = {
32
+ browseComments: d => fetch(`${adminUrl}/comments/post/${id(d.postId)}/${qs(d.params)}`),
33
+ getReplies: d => fetch(`${adminUrl}/comments/${id(d.commentId)}/replies/${qs(d.params)}`),
34
+ readComment: d => fetch(`${adminUrl}/comments/${id(d.commentId)}/${qs(d.params)}`),
35
+ getUser: () => fetch(`${adminUrl}/users/me/?include=roles`),
36
+ hideComment: d => setCommentStatus(d.id, 'hidden'),
37
+ showComment: d => setCommentStatus(d.id, 'published')
38
+ };
39
+
6
40
  window.addEventListener('message', async function (event) {
7
41
  if (event.origin !== siteOrigin) {
8
42
  console.warn('Ignored message to admin auth iframe because of mismatch in origin', 'expected', siteOrigin, 'got', event.origin, 'with data', event.data);
9
43
  return;
10
44
  }
11
- let data = null;
45
+
46
+ let data;
12
47
  try {
13
48
  data = JSON.parse(event.data);
14
49
  } catch (err) {
15
- console.error(err);
50
+ console.error('Admin auth iframe failed to parse message from site origin:', event.data, err);
51
+ return;
16
52
  }
17
53
 
18
54
  function respond(error, result) {
19
55
  event.source.postMessage(JSON.stringify({
20
56
  uid: data.uid,
21
- error: error,
22
- result: result
57
+ error: error ? error.message : null,
58
+ result
23
59
  }), siteOrigin);
24
60
  }
25
61
 
26
- if (data.action === 'browseComments') {
27
- try {
28
- const {postId, params} = data;
29
- const res = await fetch(
30
- adminUrl + `/comments/post/${postId}/?${new URLSearchParams(params).toString()}`
31
- );
32
- const json = await res.json();
33
- respond(null, json);
34
- } catch (err) {
35
- respond(err, null);
36
- }
37
- }
38
-
39
- if (data.action === 'getReplies') {
40
- try {
41
- const {commentId, params} = data;
42
- const res = await fetch(
43
- adminUrl + `/comments/${commentId}/replies/?${new URLSearchParams(params).toString()}`
44
- );
45
- const json = await res.json();
46
- respond(null, json);
47
- } catch (err) {
48
- respond(err, null);
49
- }
50
- }
51
-
52
- if (data.action === 'readComment') {
53
- try {
54
- const {commentId, params} = data;
55
- const res = await fetch(adminUrl + '/comments/' + commentId + '/' + '?' + new URLSearchParams(params).toString());
56
- const json = await res.json();
57
- respond(null, json);
58
- } catch (err) {
59
- respond(err, null);
60
- }
61
- }
62
-
63
- if (data.action === 'getUser') {
64
- try {
65
- const res = await fetch(
66
- adminUrl + '/users/me/?include=roles'
67
- );
68
- const json = await res.json();
69
- respond(null, json);
70
- } catch (err) {
71
- respond(err, null);
72
- }
73
- }
74
-
75
- if (data.action === 'hideComment') {
76
- try {
77
- const res = await fetch(adminUrl + '/comments/' + data.id + '/', {
78
- method: 'PUT',
79
- body: JSON.stringify({
80
- comments: [{
81
- id: data.id,
82
- status: 'hidden'
83
- }]
84
- }),
85
- headers: {
86
- 'Content-Type': 'application/json'
87
- }
88
- });
89
- const json = await res.json();
90
- respond(null, json);
91
- } catch (err) {
92
- respond(err, null);
93
- }
62
+ const handler = actions[data.action];
63
+ if (!handler) {
64
+ return;
94
65
  }
95
66
 
96
- if (data.action === 'showComment') {
97
- try {
98
- const res = await fetch(adminUrl + '/comments/' + data.id + '/', {
99
- method: 'PUT',
100
- body: JSON.stringify({
101
- comments: [{
102
- id: data.id,
103
- status: 'published'
104
- }]
105
- }),
106
- headers: {
107
- 'Content-Type': 'application/json'
108
- }
109
- });
110
- const json = await res.json();
111
- respond(null, json);
112
- } catch (err) {
113
- respond(err, null);
114
- }
67
+ try {
68
+ const res = await handler(data);
69
+ const json = await res.json();
70
+ respond(null, json);
71
+ } catch (err) {
72
+ respond(err, null);
115
73
  }
116
74
  });
@@ -2,6 +2,7 @@ const crypto = require('crypto');
2
2
  const BaseCacheAdapter = require('@tryghost/adapter-base-cache');
3
3
  const errors = require('@tryghost/errors');
4
4
  const logging = require('@tryghost/logging');
5
+ const metrics = require('@tryghost/metrics');
5
6
  const debug = require('@tryghost/debug')('redis-cache');
6
7
  const cacheManager = require('cache-manager');
7
8
  const redisStoreFactory = require('./redis-store-factory');
@@ -22,6 +23,7 @@ class AdapterCacheRedis extends BaseCacheAdapter {
22
23
  * @param {number} [config.getTimeoutMilliseconds] - default timeout for cache get operations in *milliseconds*
23
24
  * @param {number} [config.refreshAheadFactor] - 0-1 number to use to determine how old (as a percentage of ttl) an entry should be before refreshing it
24
25
  * @param {string} [config.keyPrefix] - prefix to use when building a unique cache key, e.g.: 'some_id:image-sizes:'
26
+ * @param {string} [config.featureName] - name of the cache feature (e.g. 'postsPublic') used for dashboard filtering
25
27
  * @param {boolean} [config.reuseConnection] - specifies if the redis store/connection should be reused within the process
26
28
  */
27
29
  constructor(config) {
@@ -67,10 +69,24 @@ class AdapterCacheRedis extends BaseCacheAdapter {
67
69
  this.currentlyExecutingBackgroundRefreshes = new Set();
68
70
  this.currentlyExecutingReads = new Map();
69
71
  this._keyPrefix = config.keyPrefix || '';
72
+ this._featureName = config.featureName;
70
73
  this._prefixHashInitInFlight = null;
71
74
  this.redisClient.on('error', this.handleRedisError);
72
75
  }
73
76
 
77
+ /**
78
+ * Underscore-private to survive api-framework's `_.cloneDeep` on the
79
+ * controller (and this adapter). See the "survives deep cloning"
80
+ * suite — `#`-private methods break on clones.
81
+ */
82
+ _metric(name, extra = {}) {
83
+ const value = {...extra};
84
+ if (this._featureName !== undefined) {
85
+ value.feature = this._featureName;
86
+ }
87
+ metrics.metric(name, value);
88
+ }
89
+
74
90
  /**
75
91
  * api-framework's pipeline _.cloneDeep's controllers (and the cache
76
92
  * adapter alongside them). Caching the redis client as `this.redisClient`
@@ -192,16 +208,35 @@ class AdapterCacheRedis extends BaseCacheAdapter {
192
208
  }
193
209
 
194
210
  return new Promise((resolve) => {
211
+ // `lookup` keeps running after the timer fires, so without a
212
+ // single-settlement guard a slow failing redis read would emit
213
+ // both `cache-timeout` and `cache-error` for the same request.
214
+ let settled = false;
195
215
  const timer = setTimeout(() => {
216
+ if (settled) {
217
+ return;
218
+ }
219
+ settled = true;
196
220
  debug('get', key, 'timeout');
221
+ this._metric('cache-timeout');
197
222
  resolve({internalKey: null, result: null});
198
223
  }, this.getTimeoutMilliseconds);
199
224
  lookup.then((value) => {
225
+ if (settled) {
226
+ return;
227
+ }
228
+ settled = true;
200
229
  clearTimeout(timer);
201
230
  resolve(value);
202
- }, () => {
203
- // redis failure during lookup - treat as MISS, same as the timeout path
231
+ }, (err) => {
232
+ if (settled) {
233
+ return;
234
+ }
235
+ settled = true;
204
236
  clearTimeout(timer);
237
+ // redis failure during lookup - treat as MISS, same as the timeout path
238
+ this._metric('cache-error', {operation: 'get'});
239
+ logging.error(err);
205
240
  resolve({internalKey: null, result: null});
206
241
  });
207
242
  });
@@ -216,6 +251,13 @@ class AdapterCacheRedis extends BaseCacheAdapter {
216
251
  try {
217
252
  const {internalKey, result} = await this._lookupWithTimeout(key);
218
253
  debug(`get ${key}: Cache ${result ? 'HIT' : 'MISS'}`);
254
+ if (result) {
255
+ this._metric('cache-hit');
256
+ } else if (internalKey !== null) {
257
+ // A real miss; timeouts and lookup errors (internalKey === null)
258
+ // already emitted their own metric in `_lookupWithTimeout`.
259
+ this._metric('cache-miss');
260
+ }
219
261
  if (!fetchData) {
220
262
  return result;
221
263
  }
@@ -228,11 +270,15 @@ class AdapterCacheRedis extends BaseCacheAdapter {
228
270
  if (!isRefreshing && shouldRefresh) {
229
271
  debug(`Doing background refresh for ${key}`);
230
272
  this.currentlyExecutingBackgroundRefreshes.add(internalKey);
273
+ this._metric('cache-background-refresh-triggered');
274
+ const refreshStart = performance.now();
231
275
  fetchData().then(async (data) => {
232
- await this.set(key, data); // We don't use `internalKey` here because `set` handles it
276
+ await this.set(key, data, {throwOnError: true}); // We don't use `internalKey` here because `set` handles it
233
277
  this.currentlyExecutingBackgroundRefreshes.delete(internalKey);
278
+ this._metric('cache-background-refresh-succeeded', {value: performance.now() - refreshStart});
234
279
  }).catch((error) => {
235
280
  this.currentlyExecutingBackgroundRefreshes.delete(internalKey);
281
+ this._metric('cache-background-refresh-failed');
236
282
  logging.error({
237
283
  message: 'There was an error refreshing cache data in the background',
238
284
  error: error
@@ -256,6 +302,7 @@ class AdapterCacheRedis extends BaseCacheAdapter {
256
302
  debug('set', internalKey);
257
303
  await this.cache.set(internalKey, data);
258
304
  } catch (err) {
305
+ this._metric('cache-error', {operation: 'set'});
259
306
  logging.error(err);
260
307
  }
261
308
  }).catch(() => {
@@ -267,6 +314,7 @@ class AdapterCacheRedis extends BaseCacheAdapter {
267
314
  return resultPromise;
268
315
  }
269
316
  } catch (err) {
317
+ this._metric('cache-error', {operation: 'get'});
270
318
  logging.error(err);
271
319
  }
272
320
  }
@@ -275,14 +323,20 @@ class AdapterCacheRedis extends BaseCacheAdapter {
275
323
  *
276
324
  * @param {string} key
277
325
  * @param {*} value
326
+ * @param {Object} [options]
327
+ * @param {boolean} [options.throwOnError] - if true, rethrow write errors after logging. Used by the background refresh path so success is only emitted after a write that actually succeeded.
278
328
  */
279
- async set(key, value) {
329
+ async set(key, value, {throwOnError = false} = {}) {
280
330
  try {
281
331
  const internalKey = await this._buildKey(key);
282
332
  debug('set', internalKey);
283
333
  return await this.cache.set(internalKey, value);
284
334
  } catch (err) {
335
+ this._metric('cache-error', {operation: 'set'});
285
336
  logging.error(err);
337
+ if (throwOnError) {
338
+ throw err;
339
+ }
286
340
  }
287
341
  }
288
342
 
@@ -295,9 +349,12 @@ class AdapterCacheRedis extends BaseCacheAdapter {
295
349
 
296
350
  async reset() {
297
351
  debug('reset');
352
+ const t0 = performance.now();
298
353
  try {
299
354
  await this.cyclePrefixHash();
355
+ this._metric('cache-reset', {value: performance.now() - t0});
300
356
  } catch (err) {
357
+ this._metric('cache-error', {operation: 'reset'});
301
358
  logging.error(err);
302
359
  }
303
360
  }
@@ -179,11 +179,12 @@ const controller = {
179
179
  });
180
180
  }
181
181
 
182
- const origin = auth.session.getOriginOfRequest(frame.original);
183
- await auth.session.sessionService.assignVerifiedUserToSession({
184
- session: frame.original.session,
182
+ // Rotate the session_id and mint a fresh verified session so that
183
+ // any stolen or cloned copy of the pre-reset cookie is rejected
184
+ // on its next request.
185
+ await auth.session.sessionService.rotateAndAssignVerifiedUserToSession({
186
+ req: frame.original.session.req,
185
187
  user: doResetParams.user,
186
- origin,
187
188
  ip: frame.options.ip
188
189
  });
189
190
 
@@ -30,6 +30,27 @@ function getTargetId(frame) {
30
30
  return frame.options.id === 'me' ? frame.user.id : frame.options.id;
31
31
  }
32
32
 
33
+ // When a user changes their own password we destroy all of their sessions in
34
+ // the model, then rotate the session_id here and mint a fresh verified session
35
+ // for the current browser. Rotating invalidates any cloned or stolen copy of
36
+ // the pre-change cookie.
37
+ async function rotateSessionForSelfPasswordChange(frame, user) {
38
+ const targetUserId = frame.data.password[0].user_id;
39
+ const currentUserId = frame.options.context && frame.options.context.user;
40
+ if (targetUserId !== currentUserId) {
41
+ return;
42
+ }
43
+ const req = frame.original.session && frame.original.session.req;
44
+ if (!req) {
45
+ return;
46
+ }
47
+ await auth.session.sessionService.rotateAndAssignVerifiedUserToSession({
48
+ req,
49
+ user,
50
+ ip: frame.options.ip
51
+ });
52
+ }
53
+
33
54
  async function fetchOrCreatePersonalToken(userId) {
34
55
  const token = await models.ApiKey.findOne({user_id: userId}, {});
35
56
 
@@ -217,6 +238,9 @@ const controller = {
217
238
  headers: {
218
239
  cacheInvalidate: false
219
240
  },
241
+ options: [
242
+ 'ip'
243
+ ],
220
244
  validation: {
221
245
  docName: 'password',
222
246
  data: {
@@ -232,9 +256,10 @@ const controller = {
232
256
  return frame.data.password[0].user_id;
233
257
  }
234
258
  },
235
- query(frame) {
236
- frame.options.skipSessionID = frame.original.session.id;
237
- return models.User.changePassword(frame.data.password[0], frame.options);
259
+ async query(frame) {
260
+ const result = await models.User.changePassword(frame.data.password[0], frame.options);
261
+ await rotateSessionForSelfPasswordChange(frame, result);
262
+ return result;
238
263
  }
239
264
  },
240
265
 
@@ -80,21 +80,9 @@ class MembersImporter extends TableImporter {
80
80
  name: name,
81
81
  expertise: luck(30) ? faker.name.jobTitle() : undefined,
82
82
  geolocation: JSON.stringify({
83
- organization_name: faker.company.name(),
84
- region: faker.address.state(),
85
- accuracy: 50,
86
- asn: parseInt(faker.random.numeric(4)),
87
- organization: `${faker.random.alpha({count: 2, casing: 'upper'})}${faker.random.numeric(4)} ${faker.company.name()}`,
88
- timezone: faker.address.timeZone(),
89
- longitude: faker.address.longitude(),
90
- country_code3: faker.address.countryCode('alpha-3'),
91
- area_code: '0',
92
- ip: faker.internet.ipv4(),
93
- city: faker.address.cityName(),
94
83
  country: faker.address.country(),
95
- continent_code: 'EU',
96
84
  country_code: faker.address.countryCode('alpha-2'),
97
- latitude: faker.address.latitude()
85
+ region: faker.address.state()
98
86
  }),
99
87
  email_count: 0, // Depends on number of emails sent since created_at, the newsletter they're a part of and subscription status
100
88
  email_opened_count: 0,