ghost 5.82.3 → 5.82.4
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.
- package/components/{tryghost-adapter-cache-memory-ttl-5.82.3.tgz → tryghost-adapter-cache-memory-ttl-5.82.4.tgz} +0 -0
- package/components/{tryghost-adapter-cache-redis-5.82.3.tgz → tryghost-adapter-cache-redis-5.82.4.tgz} +0 -0
- package/components/{tryghost-adapter-manager-5.82.3.tgz → tryghost-adapter-manager-5.82.4.tgz} +0 -0
- package/components/{tryghost-announcement-bar-settings-5.82.3.tgz → tryghost-announcement-bar-settings-5.82.4.tgz} +0 -0
- package/components/{tryghost-api-framework-5.82.3.tgz → tryghost-api-framework-5.82.4.tgz} +0 -0
- package/components/{tryghost-api-version-compatibility-service-5.82.3.tgz → tryghost-api-version-compatibility-service-5.82.4.tgz} +0 -0
- package/components/{tryghost-audience-feedback-5.82.3.tgz → tryghost-audience-feedback-5.82.4.tgz} +0 -0
- package/components/tryghost-bookshelf-repository-5.82.4.tgz +0 -0
- package/components/{tryghost-bootstrap-socket-5.82.3.tgz → tryghost-bootstrap-socket-5.82.4.tgz} +0 -0
- package/components/tryghost-collections-5.82.4.tgz +0 -0
- package/components/{tryghost-constants-5.82.3.tgz → tryghost-constants-5.82.4.tgz} +0 -0
- package/components/{tryghost-custom-theme-settings-service-5.82.3.tgz → tryghost-custom-theme-settings-service-5.82.4.tgz} +0 -0
- package/components/{tryghost-data-generator-5.82.3.tgz → tryghost-data-generator-5.82.4.tgz} +0 -0
- package/components/tryghost-domain-events-5.82.4.tgz +0 -0
- package/components/tryghost-donations-5.82.4.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.82.4.tgz +0 -0
- package/components/{tryghost-email-addresses-5.82.3.tgz → tryghost-email-addresses-5.82.4.tgz} +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.82.4.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.82.4.tgz +0 -0
- package/components/tryghost-email-content-generator-5.82.4.tgz +0 -0
- package/components/{tryghost-email-events-5.82.3.tgz → tryghost-email-events-5.82.4.tgz} +0 -0
- package/components/tryghost-email-service-5.82.4.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.82.4.tgz +0 -0
- package/components/{tryghost-express-dynamic-redirects-5.82.3.tgz → tryghost-express-dynamic-redirects-5.82.4.tgz} +0 -0
- package/components/tryghost-external-media-inliner-5.82.4.tgz +0 -0
- package/components/tryghost-extract-api-key-5.82.4.tgz +0 -0
- package/components/tryghost-ghost-5.82.4.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.82.4.tgz +0 -0
- package/components/tryghost-i18n-5.82.4.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.82.4.tgz +0 -0
- package/components/tryghost-importer-revue-5.82.4.tgz +0 -0
- package/components/tryghost-in-memory-repository-5.82.4.tgz +0 -0
- package/components/{tryghost-job-manager-5.82.3.tgz → tryghost-job-manager-5.82.4.tgz} +0 -0
- package/components/tryghost-link-redirects-5.82.4.tgz +0 -0
- package/components/{tryghost-link-replacer-5.82.3.tgz → tryghost-link-replacer-5.82.4.tgz} +0 -0
- package/components/{tryghost-link-tracking-5.82.3.tgz → tryghost-link-tracking-5.82.4.tgz} +0 -0
- package/components/{tryghost-magic-link-5.82.3.tgz → tryghost-magic-link-5.82.4.tgz} +0 -0
- package/components/{tryghost-mail-events-5.82.3.tgz → tryghost-mail-events-5.82.4.tgz} +0 -0
- package/components/tryghost-mailgun-client-5.82.4.tgz +0 -0
- package/components/{tryghost-member-attribution-5.82.3.tgz → tryghost-member-attribution-5.82.4.tgz} +0 -0
- package/components/tryghost-member-events-5.82.4.tgz +0 -0
- package/components/{tryghost-members-api-5.82.3.tgz → tryghost-members-api-5.82.4.tgz} +0 -0
- package/components/tryghost-members-csv-5.82.4.tgz +0 -0
- package/components/{tryghost-members-events-service-5.82.3.tgz → tryghost-members-events-service-5.82.4.tgz} +0 -0
- package/components/{tryghost-members-importer-5.82.3.tgz → tryghost-members-importer-5.82.4.tgz} +0 -0
- package/components/{tryghost-members-offers-5.82.3.tgz → tryghost-members-offers-5.82.4.tgz} +0 -0
- package/components/{tryghost-members-payments-5.82.3.tgz → tryghost-members-payments-5.82.4.tgz} +0 -0
- package/components/{tryghost-members-ssr-5.82.3.tgz → tryghost-members-ssr-5.82.4.tgz} +0 -0
- package/components/{tryghost-members-stripe-service-5.82.3.tgz → tryghost-members-stripe-service-5.82.4.tgz} +0 -0
- package/components/{tryghost-mentions-email-report-5.82.3.tgz → tryghost-mentions-email-report-5.82.4.tgz} +0 -0
- package/components/tryghost-milestones-5.82.4.tgz +0 -0
- package/components/tryghost-minifier-5.82.4.tgz +0 -0
- package/components/{tryghost-model-to-domain-event-interceptor-5.82.3.tgz → tryghost-model-to-domain-event-interceptor-5.82.4.tgz} +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.82.4.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.82.4.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.82.4.tgz +0 -0
- package/components/{tryghost-mw-session-from-token-5.82.3.tgz → tryghost-mw-session-from-token-5.82.4.tgz} +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.82.4.tgz +0 -0
- package/components/tryghost-mw-version-match-5.82.4.tgz +0 -0
- package/components/{tryghost-mw-vhost-5.82.3.tgz → tryghost-mw-vhost-5.82.4.tgz} +0 -0
- package/components/tryghost-nql-filter-expansions-5.82.4.tgz +0 -0
- package/components/tryghost-oembed-service-5.82.4.tgz +0 -0
- package/components/tryghost-package-json-5.82.4.tgz +0 -0
- package/components/{tryghost-post-events-5.82.3.tgz → tryghost-post-events-5.82.4.tgz} +0 -0
- package/components/{tryghost-post-revisions-5.82.3.tgz → tryghost-post-revisions-5.82.4.tgz} +0 -0
- package/components/tryghost-posts-service-5.82.4.tgz +0 -0
- package/components/tryghost-recommendations-5.82.4.tgz +0 -0
- package/components/tryghost-referrers-5.82.4.tgz +0 -0
- package/components/{tryghost-security-5.82.3.tgz → tryghost-security-5.82.4.tgz} +0 -0
- package/components/{tryghost-session-service-5.82.3.tgz → tryghost-session-service-5.82.4.tgz} +0 -0
- package/components/tryghost-settings-path-manager-5.82.4.tgz +0 -0
- package/components/tryghost-slack-notifications-5.82.4.tgz +0 -0
- package/components/tryghost-staff-service-5.82.4.tgz +0 -0
- package/components/tryghost-stats-service-5.82.4.tgz +0 -0
- package/components/tryghost-tiers-5.82.4.tgz +0 -0
- package/components/tryghost-update-check-service-5.82.4.tgz +0 -0
- package/components/{tryghost-verification-trigger-5.82.3.tgz → tryghost-verification-trigger-5.82.4.tgz} +0 -0
- package/components/{tryghost-version-notifications-data-service-5.82.3.tgz → tryghost-version-notifications-data-service-5.82.4.tgz} +0 -0
- package/components/tryghost-webmentions-5.82.4.tgz +0 -0
- package/core/boot.js +6 -0
- package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +6990 -0
- package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +1 -1
- package/core/built/admin/assets/admin-x-demo/{index-aad00baa.mjs → index-e36f9f54.mjs} +3 -3
- package/core/built/admin/assets/admin-x-demo/{modals-925b7c32.mjs → modals-54e6eae1.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-09fb8166.mjs → CodeEditorView-834e7ac8.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-7c9fce83.mjs → index-957ece55.mjs} +94 -87
- package/core/built/admin/assets/admin-x-settings/{index-55c46922.mjs → index-f994fb82.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{modals-e97cff0c.mjs → modals-5264a854.mjs} +1033 -1000
- package/core/built/admin/assets/{chunk.524.7e89297e3fe4765e1581.js → chunk.524.bd8238874f4b73f48c54.js} +5 -5
- package/core/built/admin/assets/{chunk.582.d279749c1357df54ae8e.js → chunk.582.0c6120fa7382f5d485e0.js} +4 -4
- package/core/built/admin/assets/{chunk.682.9acd39e8ae4d98006602.js → chunk.799.51e503059770581f528f.js} +297 -275
- package/core/built/admin/assets/{ghost-804748f2e71b6155946284e9658bddd0.js → ghost-0723ddb4afa369fc0303017c40ffffe0.js} +233 -217
- package/core/built/admin/assets/koenig-lexical/index.css +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +8463 -8375
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +126 -126
- package/core/built/admin/assets/{vendor-f9bad0b8c0149699f84c0bd9d325068e.js → vendor-5ef343f0a55366497ef903095548a0d5.js} +5 -5
- package/core/built/admin/index.html +5 -5
- package/core/server/services/Users.js +52 -40
- package/core/server/services/link-redirection/LinkRedirectRepository.js +106 -7
- package/core/server/services/link-redirection/index.js +6 -1
- package/core/server/services/xmlrpc.js +0 -2
- package/core/shared/labs.js +3 -3
- package/package.json +151 -151
- package/yarn.lock +406 -313
- package/components/tryghost-bookshelf-repository-5.82.3.tgz +0 -0
- package/components/tryghost-collections-5.82.3.tgz +0 -0
- package/components/tryghost-domain-events-5.82.3.tgz +0 -0
- package/components/tryghost-donations-5.82.3.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.82.3.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.82.3.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.82.3.tgz +0 -0
- package/components/tryghost-email-content-generator-5.82.3.tgz +0 -0
- package/components/tryghost-email-service-5.82.3.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.82.3.tgz +0 -0
- package/components/tryghost-external-media-inliner-5.82.3.tgz +0 -0
- package/components/tryghost-extract-api-key-5.82.3.tgz +0 -0
- package/components/tryghost-ghost-5.82.3.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.82.3.tgz +0 -0
- package/components/tryghost-i18n-5.82.3.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.82.3.tgz +0 -0
- package/components/tryghost-importer-revue-5.82.3.tgz +0 -0
- package/components/tryghost-in-memory-repository-5.82.3.tgz +0 -0
- package/components/tryghost-link-redirects-5.82.3.tgz +0 -0
- package/components/tryghost-mailgun-client-5.82.3.tgz +0 -0
- package/components/tryghost-member-events-5.82.3.tgz +0 -0
- package/components/tryghost-members-csv-5.82.3.tgz +0 -0
- package/components/tryghost-milestones-5.82.3.tgz +0 -0
- package/components/tryghost-minifier-5.82.3.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.82.3.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.82.3.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.82.3.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.82.3.tgz +0 -0
- package/components/tryghost-mw-version-match-5.82.3.tgz +0 -0
- package/components/tryghost-nql-filter-expansions-5.82.3.tgz +0 -0
- package/components/tryghost-oembed-service-5.82.3.tgz +0 -0
- package/components/tryghost-package-json-5.82.3.tgz +0 -0
- package/components/tryghost-posts-service-5.82.3.tgz +0 -0
- package/components/tryghost-recommendations-5.82.3.tgz +0 -0
- package/components/tryghost-referrers-5.82.3.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.82.3.tgz +0 -0
- package/components/tryghost-slack-notifications-5.82.3.tgz +0 -0
- package/components/tryghost-staff-service-5.82.3.tgz +0 -0
- package/components/tryghost-stats-service-5.82.3.tgz +0 -0
- package/components/tryghost-tiers-5.82.3.tgz +0 -0
- package/components/tryghost-update-check-service-5.82.3.tgz +0 -0
- package/components/tryghost-webmentions-5.82.3.tgz +0 -0
- /package/core/built/admin/assets/{chunk.682.9acd39e8ae4d98006602.js.LICENSE.txt → chunk.799.51e503059770581f528f.js.LICENSE.txt} +0 -0
|
@@ -7030,11 +7030,11 @@ if(h&&!1!==d.startTransactionOnPageLoad&&!1!==d.instrumentPageLoad){const r=e.re
|
|
|
7030
7030
|
u=i(p,{name:`route:${r.name}`,origin:"auto.pageload.ember",attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]:"route"},tags:{url:h,toRoute:r.name,"routing.instrumentation":"@sentry/ember"}})}const f=(e,t)=>{t||(u?.end(),o().off("end",f))}
|
|
7031
7031
|
!1===d.startTransactionOnLocationChange&&!1===d.instrumentNavigation||(e.on("routeWillChange",(r=>{const{fromRoute:n,toRoute:i}=function(e,t){const r=e?.from?.name
|
|
7032
7032
|
return{fromRoute:r,toRoute:e?.to?.name||t.currentRouteName}}(r,e)
|
|
7033
|
-
u?.end(),u=s(p,{name:`route:${i}`,origin:"auto.navigation.ember",attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]:"route"},tags:{fromRoute:n,toRoute:i,"routing.instrumentation":"@sentry/ember"}}),c=(0,t.startInactiveSpan)({attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:"auto.ui.ember"},op:"ui.ember.transition",name:`route:${n} -> route:${i}
|
|
7033
|
+
u?.end(),u=s(p,{name:`route:${i}`,origin:"auto.navigation.ember",attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]:"route"},tags:{fromRoute:n,toRoute:i,"routing.instrumentation":"@sentry/ember"}}),c=(0,t.startInactiveSpan)({attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:"auto.ui.ember"},op:"ui.ember.transition",name:`route:${n} -> route:${i}`,onlyIfParent:!0})})),e.on("routeDidChange",(()=>{c&&u&&(c.end(),a?u.end():o().on("end",f))})))}function a(e,t){const n={payload:e,now:(0,r.timestampInSeconds)()}
|
|
7034
7034
|
t[e.object]=n}function l(e,n,i,o){const s=n[e.object]
|
|
7035
7035
|
if(!s)return
|
|
7036
7036
|
const a=(0,r.timestampInSeconds)()
|
|
7037
|
-
1e3*(a-s.now)>=o&&(0,t.startInactiveSpan)({name:e.containerKey||e.object,op:i,origin:"auto.ui.ember",startTimestamp:s.now})?.end(a)}function u(e){const n="@sentry/ember:initial-load-start",i="@sentry/ember:initial-load-end",{HAS_PERFORMANCE:o,HAS_PERFORMANCE_TIMING:s}=function(){const e=window.performance,t=Boolean(e&&e.clearMarks&&e.clearMeasures),n=Boolean(e.measure&&e.getEntriesByName&&void 0!==r.browserPerformanceTimeOrigin)
|
|
7037
|
+
1e3*(a-s.now)>=o&&(0,t.startInactiveSpan)({name:e.containerKey||e.object,op:i,origin:"auto.ui.ember",startTimestamp:s.now,onlyIfParent:!0})?.end(a)}function u(e){const n="@sentry/ember:initial-load-start",i="@sentry/ember:initial-load-end",{HAS_PERFORMANCE:o,HAS_PERFORMANCE_TIMING:s}=function(){const e=window.performance,t=Boolean(e&&e.clearMarks&&e.clearMeasures),n=Boolean(e.measure&&e.getEntriesByName&&void 0!==r.browserPerformanceTimeOrigin)
|
|
7038
7038
|
return{HAS_PERFORMANCE:t,HAS_PERFORMANCE_TIMING:n}}()
|
|
7039
7039
|
if(!o)return
|
|
7040
7040
|
const{performance:a}=window
|
|
@@ -7043,7 +7043,7 @@ if(!s||void 0===r.browserPerformanceTimeOrigin)return
|
|
|
7043
7043
|
const l="@sentry/ember:initial-load",u=a.getEntriesByName(n).length>0,c=a.getEntriesByName(i).length>0
|
|
7044
7044
|
if(!u||!c)return
|
|
7045
7045
|
a.measure(l,n,i)
|
|
7046
|
-
const d=a.getEntriesByName(l)[0],h=(d.startTime+r.browserPerformanceTimeOrigin)/1e3,p=h+d.duration/1e3;(0,t.startInactiveSpan)({op:"ui.ember.init",name:"init",attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:"auto.ui.ember"},startTimestamp:h})?.end(p),a.clearMarks(n),a.clearMarks(i),a.clearMeasures(l)}async function c(e){const i=n(),c=i.browserTracingOptions||i.sentry.browserTracingOptions||{},{browserTracingIntegration:d,startBrowserTracingNavigationSpan:h,startBrowserTracingPageLoadSpan:p}=await emberAutoImportDynamic("@sentry/browser"),f=d({idleTimeout:i.transitionTimeout||5e3,...c,instrumentNavigation:!1,instrumentPageLoad:!1}),m=(0,t.getClient)()
|
|
7046
|
+
const d=a.getEntriesByName(l)[0],h=(d.startTime+r.browserPerformanceTimeOrigin)/1e3,p=h+d.duration/1e3;(0,t.startInactiveSpan)({op:"ui.ember.init",name:"init",attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:"auto.ui.ember"},onlyIfParent:!0,startTimestamp:h})?.end(p),a.clearMarks(n),a.clearMarks(i),a.clearMeasures(l)}async function c(e){const i=n(),c=i.browserTracingOptions||i.sentry.browserTracingOptions||{},{browserTracingIntegration:d,startBrowserTracingNavigationSpan:h,startBrowserTracingPageLoadSpan:p}=await emberAutoImportDynamic("@sentry/browser"),f=d({idleTimeout:i.transitionTimeout||5e3,...c,instrumentNavigation:!1,instrumentPageLoad:!1}),m=(0,t.getClient)()
|
|
7047
7047
|
m&&m.addIntegration&&m.addIntegration(f),function(e,t,r,n){const i=e.lookup("router:main")
|
|
7048
7048
|
let o=e.lookup("service:router")
|
|
7049
7049
|
o.externalRouter&&(o=o.externalRouter)
|
|
@@ -7057,7 +7057,7 @@ o().on("begin",((e,n)=>{if(n)return
|
|
|
7057
7057
|
if(!(0,t.getActiveSpan)())return
|
|
7058
7058
|
a&&a.end(),s=(0,r.timestampInSeconds)()
|
|
7059
7059
|
const o=e=>{if(s){const n=(0,r.timestampInSeconds)()
|
|
7060
|
-
1e3*(n-s)>=(i??5)&&(0,t.startInactiveSpan)({attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:"auto.ui.ember"},name:"runloop",op:`ui.ember.runloop.${e}`,startTimestamp:s})?.end(n),s=void 0}(0,t.getActiveSpan)()&&(s=(0,r.timestampInSeconds)())}
|
|
7060
|
+
1e3*(n-s)>=(i??5)&&(0,t.startInactiveSpan)({attributes:{[t.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:"auto.ui.ember"},name:"runloop",op:`ui.ember.runloop.${e}`,startTimestamp:s,onlyIfParent:!0})?.end(n),s=void 0}(0,t.getActiveSpan)()&&(s=(0,r.timestampInSeconds)())}
|
|
7061
7061
|
l.forEach((e=>{Ember.run.scheduleOnce(e,null,o,e)}))})),o().on("end",((e,t)=>{t||a&&(a.end(),a=void 0)}))}(i),function(e){const{disableInstrumentComponents:t,minimumComponentRenderDuration:r,enableComponentDefinitions:n}=e
|
|
7062
7062
|
if(t)return
|
|
7063
7063
|
const i=r??2,o={},s={}
|
|
@@ -9924,4 +9924,4 @@ e.default=class{constructor(e){if(this._data=new t.default,e)for(let t=0;t<e.len
|
|
|
9924
9924
|
return this}get(e){let t=this._data[e]
|
|
9925
9925
|
return t===r.UNDEFINED_KEY?void 0:t}set(e,t){return this._data[e]=t,this}delete(e){return this._data[e]=r.UNDEFINED_KEY,!0}}}))
|
|
9926
9926
|
|
|
9927
|
-
//# sourceMappingURL=vendor-
|
|
9927
|
+
//# sourceMappingURL=vendor-5b3c871639e8269236f1a32144698b0d.map
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<title>Ghost Admin</title>
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22editorUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.82%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%2C%22editorFilename%22%3A%22koenig-lexical.umd.js%22%2C%22editorHash%22%3A%
|
|
11
|
+
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22editorUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.82%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%2C%22editorFilename%22%3A%22koenig-lexical.umd.js%22%2C%22editorHash%22%3A%22d4e7286cae%22%2C%22adminXDemoFilename%22%3A%22admin-x-demo.js%22%2C%22adminXDemoHash%22%3A%221338bf2f0d%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%227898cabecf%22%2C%22adminXActivitypubFilename%22%3A%22admin-x-activitypub.js%22%2C%22adminXActivitypubHash%22%3A%22f5c6e4344f%22%7D" />
|
|
12
12
|
|
|
13
13
|
<meta name="HandheldFriendly" content="True" />
|
|
14
14
|
<meta name="MobileOptimized" content="320" />
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
|
|
57
57
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
58
58
|
|
|
59
|
-
<script src="assets/vendor-
|
|
60
|
-
<script src="assets/chunk.
|
|
61
|
-
<script src="assets/chunk.524.
|
|
62
|
-
<script src="assets/ghost-
|
|
59
|
+
<script src="assets/vendor-5ef343f0a55366497ef903095548a0d5.js"></script>
|
|
60
|
+
<script src="assets/chunk.799.51e503059770581f528f.js"></script>
|
|
61
|
+
<script src="assets/chunk.524.bd8238874f4b73f48c54.js"></script>
|
|
62
|
+
<script src="assets/ghost-0723ddb4afa369fc0303017c40ffffe0.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const ObjectId = require('bson-objectid').default;
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @TODO: pass these in as dependencies
|
|
6
7
|
*/
|
|
7
8
|
const {PostRevisions} = require('@tryghost/post-revisions');
|
|
9
|
+
const DomainEvents = require('@tryghost/domain-events/lib/DomainEvents');
|
|
10
|
+
const {PostsBulkAddTagsEvent} = require('@tryghost/post-events');
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* @typedef {Object} IdbBackup
|
|
@@ -76,8 +79,7 @@ class Users {
|
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
async assignTagToUserPosts({id, context, transacting}) {
|
|
79
|
-
//
|
|
80
|
-
// in following format: `#{author_slug}`
|
|
82
|
+
// get author slug
|
|
81
83
|
const author = await this.models.User.findOne({
|
|
82
84
|
id
|
|
83
85
|
}, {
|
|
@@ -85,13 +87,27 @@ class Users {
|
|
|
85
87
|
context,
|
|
86
88
|
transacting
|
|
87
89
|
});
|
|
90
|
+
|
|
91
|
+
// get list of posts that need the tag assigned
|
|
92
|
+
const userPosts = await this.models.Base.knex('posts_authors')
|
|
93
|
+
.transacting(transacting)
|
|
94
|
+
.where('author_id', id)
|
|
95
|
+
.select('post_id');
|
|
96
|
+
let usersPostIds = userPosts.map(p => p.post_id);
|
|
97
|
+
|
|
98
|
+
if (usersPostIds.length === 0) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// create an internal tag to assign to reassigned posts
|
|
103
|
+
// in following format: `#{author_slug}`
|
|
104
|
+
let createdTag = false;
|
|
88
105
|
let tag = await this.models.Tag.findOne({
|
|
89
106
|
slug: `hash-${author.get('slug')}`
|
|
90
107
|
}, {
|
|
91
108
|
context,
|
|
92
109
|
transacting
|
|
93
110
|
});
|
|
94
|
-
|
|
95
111
|
if (!tag) {
|
|
96
112
|
tag = await this.models.Tag.add({
|
|
97
113
|
slug: `#${author.get('slug')}`
|
|
@@ -99,45 +115,38 @@ class Users {
|
|
|
99
115
|
context,
|
|
100
116
|
transacting
|
|
101
117
|
});
|
|
118
|
+
createdTag = true;
|
|
102
119
|
}
|
|
103
120
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
.
|
|
107
|
-
.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// a tag to multiple posts as the "sort_order" needs custom
|
|
115
|
-
// logic to be run for each post.
|
|
116
|
-
// Rewrite this bit if/when we hit a performance bottleneck here
|
|
117
|
-
for (const postId of usersPostIds) {
|
|
118
|
-
const post = await this.models.Post.findOne({
|
|
119
|
-
id: postId,
|
|
120
|
-
status: 'all'
|
|
121
|
-
}, {
|
|
122
|
-
id: postId,
|
|
123
|
-
withRelated: ['tags'],
|
|
124
|
-
context,
|
|
125
|
-
transacting
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// check if tag already assigned to the post
|
|
129
|
-
const existingTagSlugs = post.relations.tags.models.map(t => t.get('slug'));
|
|
130
|
-
|
|
131
|
-
if (!existingTagSlugs.includes(tag.get('slug'))) {
|
|
132
|
-
await this.models.Post.edit({
|
|
133
|
-
tags: [...post.relations.tags.models, tag]
|
|
134
|
-
}, {
|
|
135
|
-
id: postId,
|
|
136
|
-
context,
|
|
137
|
-
transacting
|
|
138
|
-
});
|
|
139
|
-
}
|
|
121
|
+
// filter out posts that already have the tag if we didn't need to create one
|
|
122
|
+
if (!createdTag) {
|
|
123
|
+
const tagId = tag.get('id');
|
|
124
|
+
const taggedPostIds = await this.models.Base.knex('posts_tags')
|
|
125
|
+
.transacting(transacting)
|
|
126
|
+
.where('tag_id', tagId)
|
|
127
|
+
.select('post_id');
|
|
128
|
+
usersPostIds = userPosts
|
|
129
|
+
.map(p => p.post_id)
|
|
130
|
+
.filter(p => !taggedPostIds.includes(p));
|
|
140
131
|
}
|
|
132
|
+
|
|
133
|
+
// assign tag to posts
|
|
134
|
+
// do bulk insert for performance reasons
|
|
135
|
+
// - go ahead and assign sort_order 0 to all of them
|
|
136
|
+
await this.models.Base.knex('posts_tags')
|
|
137
|
+
.transacting(transacting)
|
|
138
|
+
.insert(usersPostIds.map(postId => ({
|
|
139
|
+
id: (new ObjectId()).toHexString(),
|
|
140
|
+
post_id: postId,
|
|
141
|
+
tag_id: tag.get('id'),
|
|
142
|
+
sort_order: 0
|
|
143
|
+
})));
|
|
144
|
+
|
|
145
|
+
// manually add an entry in the Actions table that specifies the number of posts edited; see #bulkAddTags for similar logic
|
|
146
|
+
await this.models.Post.addActions('edited', usersPostIds, {transacting, context});
|
|
147
|
+
|
|
148
|
+
// dispatch event to ensure collections are updated
|
|
149
|
+
DomainEvents.dispatch(PostsBulkAddTagsEvent.create(usersPostIds));
|
|
141
150
|
}
|
|
142
151
|
|
|
143
152
|
/**
|
|
@@ -159,26 +168,29 @@ class Users {
|
|
|
159
168
|
return this.models.Base.transaction(async (t) => {
|
|
160
169
|
frameOptions.transacting = t;
|
|
161
170
|
|
|
171
|
+
// null author field for users' post revisions
|
|
162
172
|
const postRevisions = new PostRevisions({
|
|
163
173
|
model: this.models.PostRevision
|
|
164
174
|
});
|
|
165
|
-
|
|
166
175
|
await postRevisions.removeAuthorFromRevisions(frameOptions.id, {
|
|
167
176
|
transacting: frameOptions.transacting
|
|
168
177
|
});
|
|
169
178
|
|
|
179
|
+
// create a #author-slug tag and assign it to their posts
|
|
170
180
|
await this.assignTagToUserPosts({
|
|
171
181
|
id: frameOptions.id,
|
|
172
182
|
context: frameOptions.context,
|
|
173
183
|
transacting: frameOptions.transacting
|
|
174
184
|
});
|
|
175
185
|
|
|
186
|
+
// reassign posts to owner user
|
|
176
187
|
await this.models.Post.reassignByAuthor({
|
|
177
188
|
id: frameOptions.id,
|
|
178
189
|
context: frameOptions.context,
|
|
179
190
|
transacting: frameOptions.transacting
|
|
180
191
|
});
|
|
181
192
|
|
|
193
|
+
// delete user
|
|
182
194
|
try {
|
|
183
195
|
await this.models.ApiKey.destroy({
|
|
184
196
|
...frameOptions,
|
|
@@ -1,27 +1,51 @@
|
|
|
1
1
|
const LinkRedirect = require('@tryghost/link-redirects').LinkRedirect;
|
|
2
2
|
const ObjectID = require('bson-objectid').default;
|
|
3
|
+
const debug = require('@tryghost/debug')('LinkRedirectRepository');
|
|
3
4
|
|
|
4
5
|
module.exports = class LinkRedirectRepository {
|
|
5
6
|
/** @type {Object} */
|
|
6
7
|
#LinkRedirect;
|
|
7
8
|
/** @type {Object} */
|
|
8
9
|
#urlUtils;
|
|
10
|
+
/** @type {Boolean} */
|
|
11
|
+
#cacheEnabled;
|
|
12
|
+
/** @type {Object} */
|
|
13
|
+
#cache;
|
|
9
14
|
|
|
10
15
|
/**
|
|
11
16
|
* @param {object} deps
|
|
12
|
-
* @param {object} deps.LinkRedirect Bookshelf Model
|
|
17
|
+
* @param {object} deps.LinkRedirect - Bookshelf Model
|
|
13
18
|
* @param {object} deps.urlUtils
|
|
19
|
+
* @param {object} deps.cacheAdapter - Cache Adapter instance, or null if cache is disabled
|
|
20
|
+
* @param {object} deps.EventRegistry
|
|
14
21
|
*/
|
|
15
22
|
constructor(deps) {
|
|
23
|
+
debug('Creating LinkRedirectRepository');
|
|
16
24
|
this.#LinkRedirect = deps.LinkRedirect;
|
|
17
25
|
this.#urlUtils = deps.urlUtils;
|
|
26
|
+
this.#cache = null;
|
|
27
|
+
if (deps.cacheAdapter !== null) {
|
|
28
|
+
debug('Caching enabled with adapter:', deps.cacheAdapter.constructor.name);
|
|
29
|
+
this.#cache = deps.cacheAdapter;
|
|
30
|
+
// This is a bit of a blunt instrument, but it's the best we can do for now
|
|
31
|
+
// It covers all the cases we would need to invalidate the links cache
|
|
32
|
+
// We need to invalidate the cache when:
|
|
33
|
+
// - a redirect is edited
|
|
34
|
+
// - a site's subdirectory is changed (rare)
|
|
35
|
+
// - analytics settings are changed
|
|
36
|
+
deps.EventRegistry.on('site.changed', () => {
|
|
37
|
+
this.#cache.reset();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
18
40
|
}
|
|
19
41
|
|
|
20
42
|
/**
|
|
43
|
+
* Save a new LinkRedirect to the DB
|
|
21
44
|
* @param {InstanceType<LinkRedirect>} linkRedirect
|
|
22
45
|
* @returns {Promise<void>}
|
|
23
46
|
*/
|
|
24
47
|
async save(linkRedirect) {
|
|
48
|
+
debug('Saving link redirect', linkRedirect.from.pathname, '->', linkRedirect.to.href);
|
|
25
49
|
const model = await this.#LinkRedirect.add({
|
|
26
50
|
// Only store the pathname (no support for variable query strings)
|
|
27
51
|
from: this.stripSubdirectoryFromPath(linkRedirect.from.pathname),
|
|
@@ -29,17 +53,31 @@ module.exports = class LinkRedirectRepository {
|
|
|
29
53
|
}, {});
|
|
30
54
|
|
|
31
55
|
linkRedirect.link_id = ObjectID.createFromHexString(model.id);
|
|
56
|
+
if (this.#cache) {
|
|
57
|
+
debug('Caching new link redirect', linkRedirect.from.pathname);
|
|
58
|
+
this.#cache.set(linkRedirect.from.pathname, this.#serialize(linkRedirect));
|
|
59
|
+
}
|
|
32
60
|
}
|
|
33
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Trim the leading slash from a URL path
|
|
64
|
+
* @param {string} url
|
|
65
|
+
* @returns {string} url without leading slash
|
|
66
|
+
*/
|
|
34
67
|
#trimLeadingSlash(url) {
|
|
35
68
|
return url.replace(/^\//, '');
|
|
36
69
|
}
|
|
37
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Returns a LinkRedirect object from a model
|
|
73
|
+
* @param {object} model - Bookshelf model instance
|
|
74
|
+
* @returns {InstanceType<LinkRedirect>} LinkRedirect
|
|
75
|
+
*/
|
|
38
76
|
fromModel(model) {
|
|
39
77
|
// Store if link has been edited
|
|
40
78
|
// Note: in some edge cases updated_at is set directly after created_at, sometimes with a second difference, so we need to check for that
|
|
41
79
|
const edited = model.get('updated_at')?.getTime() > (model.get('created_at')?.getTime() + 1000);
|
|
42
|
-
|
|
80
|
+
|
|
43
81
|
return new LinkRedirect({
|
|
44
82
|
id: model.id,
|
|
45
83
|
from: new URL(this.#trimLeadingSlash(model.get('from')), this.#urlUtils.urlFor('home', true)),
|
|
@@ -48,6 +86,43 @@ module.exports = class LinkRedirectRepository {
|
|
|
48
86
|
});
|
|
49
87
|
}
|
|
50
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Create a LinkRedirect object from a JSON object (e.g. from the cache)
|
|
91
|
+
* @param {object} serialized
|
|
92
|
+
* @param {string} serialized.link_id - string representation of ObjectID
|
|
93
|
+
* @param {string} serialized.from - path of the URL
|
|
94
|
+
* @param {string} serialized.to - URL to redirect to
|
|
95
|
+
* @param {boolean} serialized.edited - whether the link has been edited
|
|
96
|
+
* @returns {InstanceType<LinkRedirect>} LinkRedirect
|
|
97
|
+
*/
|
|
98
|
+
#fromSerialized(serialized) {
|
|
99
|
+
return new LinkRedirect({
|
|
100
|
+
id: serialized.link_id,
|
|
101
|
+
from: new URL(this.#trimLeadingSlash(serialized.from), this.#urlUtils.urlFor('home', true)),
|
|
102
|
+
to: new URL(serialized.to),
|
|
103
|
+
edited: serialized.edited
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Serialize a LinkRedirect object to a plain object (e.g. for caching)
|
|
109
|
+
* @param {InstanceType<LinkRedirect>} linkRedirect
|
|
110
|
+
* @returns {object} - serialized LinkRedirect
|
|
111
|
+
*/
|
|
112
|
+
#serialize(linkRedirect) {
|
|
113
|
+
return {
|
|
114
|
+
link_id: linkRedirect.link_id.toHexString(),
|
|
115
|
+
from: linkRedirect.from.pathname,
|
|
116
|
+
to: linkRedirect.to.href,
|
|
117
|
+
edited: linkRedirect.edited
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get all LinkRedirects from the DB, with optional filters
|
|
123
|
+
* @param {object} options - options passed directly to LinkRedirect.findAll
|
|
124
|
+
* @returns {Promise<InstanceType<LinkRedirect>[]>} array of LinkRedirects
|
|
125
|
+
*/
|
|
51
126
|
async getAll(options) {
|
|
52
127
|
const collection = await this.#LinkRedirect.findAll(options);
|
|
53
128
|
|
|
@@ -60,6 +135,11 @@ module.exports = class LinkRedirectRepository {
|
|
|
60
135
|
return result;
|
|
61
136
|
}
|
|
62
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Get all LinkRedirect IDs from the DB, with optional filters
|
|
140
|
+
* @param {object} options - options passed directly to LinkRedirect.getFilteredCollectionQuery
|
|
141
|
+
* @returns {Promise<string[]>} array of LinkRedirect IDs
|
|
142
|
+
*/
|
|
63
143
|
async getFilteredIds(options) {
|
|
64
144
|
const linkRows = await this.#LinkRedirect.getFilteredCollectionQuery(options)
|
|
65
145
|
.select('redirects.id')
|
|
@@ -68,25 +148,44 @@ module.exports = class LinkRedirectRepository {
|
|
|
68
148
|
}
|
|
69
149
|
|
|
70
150
|
/**
|
|
71
|
-
*
|
|
151
|
+
* Get a LinkRedirect by its URL
|
|
72
152
|
* @param {URL} url
|
|
73
|
-
* @returns {Promise<InstanceType<LinkRedirect>|undefined>}
|
|
153
|
+
* @returns {Promise<InstanceType<LinkRedirect>|undefined>} LinkRedirect
|
|
74
154
|
*/
|
|
75
155
|
async getByURL(url) {
|
|
156
|
+
debug('Getting link redirect for', url.pathname);
|
|
76
157
|
// Strip subdirectory from path
|
|
77
158
|
const from = this.stripSubdirectoryFromPath(url.pathname);
|
|
78
159
|
|
|
79
|
-
|
|
160
|
+
if (this.#cache) {
|
|
161
|
+
const cachedLink = await this.#cache.get(from);
|
|
162
|
+
// Cache hit, serve from cache
|
|
163
|
+
if (cachedLink) {
|
|
164
|
+
debug('Cache hit for', from);
|
|
165
|
+
return this.#fromSerialized(cachedLink);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Cache miss, fetch from the DB
|
|
170
|
+
const linkRedirectModel = await this.#LinkRedirect.findOne({
|
|
80
171
|
from
|
|
81
172
|
}, {});
|
|
82
173
|
|
|
83
|
-
if (
|
|
84
|
-
|
|
174
|
+
if (linkRedirectModel) {
|
|
175
|
+
const linkRedirect = this.fromModel(linkRedirectModel);
|
|
176
|
+
if (this.#cache) {
|
|
177
|
+
debug('Cache miss for', from, '. Caching');
|
|
178
|
+
// Cache the link
|
|
179
|
+
this.#cache.set(from, this.#serialize(linkRedirect));
|
|
180
|
+
}
|
|
181
|
+
return linkRedirect;
|
|
85
182
|
}
|
|
86
183
|
}
|
|
87
184
|
|
|
88
185
|
/**
|
|
89
186
|
* Convert root relative URLs to subdirectory relative URLs
|
|
187
|
+
* @param {string} path
|
|
188
|
+
* @returns {string} path without subdirectory
|
|
90
189
|
*/
|
|
91
190
|
stripSubdirectoryFromPath(path) {
|
|
92
191
|
// Bit weird, but only way to do it with the urlUtils atm
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const urlUtils = require('../../../shared/url-utils');
|
|
2
2
|
const LinkRedirectRepository = require('./LinkRedirectRepository');
|
|
3
|
+
const adapterManager = require('../adapter-manager');
|
|
4
|
+
const config = require('../../../shared/config');
|
|
5
|
+
const EventRegistry = require('../../lib/common/events');
|
|
3
6
|
|
|
4
7
|
class LinkRedirectsServiceWrapper {
|
|
5
8
|
async init() {
|
|
@@ -15,7 +18,9 @@ class LinkRedirectsServiceWrapper {
|
|
|
15
18
|
|
|
16
19
|
this.linkRedirectRepository = new LinkRedirectRepository({
|
|
17
20
|
LinkRedirect: models.Redirect,
|
|
18
|
-
urlUtils
|
|
21
|
+
urlUtils,
|
|
22
|
+
cacheAdapter: config.get('hostSettings:linkRedirectsPublicCache:enabled') ? adapterManager.getAdapter('cache:linkRedirectsPublic') : null,
|
|
23
|
+
EventRegistry
|
|
19
24
|
});
|
|
20
25
|
|
|
21
26
|
// Expose the service
|
|
@@ -7,7 +7,6 @@ const tpl = require('@tryghost/tpl');
|
|
|
7
7
|
const logging = require('@tryghost/logging');
|
|
8
8
|
const request = require('@tryghost/request');
|
|
9
9
|
const settingsCache = require('../../shared/settings-cache');
|
|
10
|
-
const sentry = require('../../shared/sentry');
|
|
11
10
|
|
|
12
11
|
// Used to receive post.published model event
|
|
13
12
|
const events = require('../lib/common/events');
|
|
@@ -110,7 +109,6 @@ function ping(post) {
|
|
|
110
109
|
});
|
|
111
110
|
}
|
|
112
111
|
logging.error(error);
|
|
113
|
-
sentry.captureException(error);
|
|
114
112
|
});
|
|
115
113
|
});
|
|
116
114
|
}
|
package/core/shared/labs.js
CHANGED
|
@@ -34,6 +34,8 @@ const BETA_FEATURES = [
|
|
|
34
34
|
'additionalPaymentMethods',
|
|
35
35
|
'i18n',
|
|
36
36
|
'activitypub',
|
|
37
|
+
'internalLinking',
|
|
38
|
+
'stripeAutomaticTax',
|
|
37
39
|
'webmentions'
|
|
38
40
|
];
|
|
39
41
|
|
|
@@ -43,7 +45,6 @@ const ALPHA_FEATURES = [
|
|
|
43
45
|
'urlCache',
|
|
44
46
|
'lexicalMultiplayer',
|
|
45
47
|
'websockets',
|
|
46
|
-
'stripeAutomaticTax',
|
|
47
48
|
'emailCustomization',
|
|
48
49
|
'mailEvents',
|
|
49
50
|
'collectionsCard',
|
|
@@ -52,8 +53,7 @@ const ALPHA_FEATURES = [
|
|
|
52
53
|
'lexicalIndicators',
|
|
53
54
|
// 'adminXOffers',
|
|
54
55
|
'adminXDemo',
|
|
55
|
-
'membersSpamPrevention'
|
|
56
|
-
'internalLinking'
|
|
56
|
+
'membersSpamPrevention'
|
|
57
57
|
];
|
|
58
58
|
|
|
59
59
|
module.exports.GA_KEYS = [...GA_FEATURES];
|