@actuate-media/cms-core 0.57.0 → 0.58.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.
- package/dist/__tests__/api/stats-seo-cache.test.js +1 -1
- package/dist/__tests__/api/stats-seo-cache.test.js.map +1 -1
- package/dist/__tests__/auth/oauth.test.js +3 -1
- package/dist/__tests__/auth/oauth.test.js.map +1 -1
- package/dist/__tests__/auth/reset.test.js +1 -0
- package/dist/__tests__/auth/reset.test.js.map +1 -1
- package/dist/__tests__/auth/user-admin.test.js +14 -12
- package/dist/__tests__/auth/user-admin.test.js.map +1 -1
- package/dist/__tests__/db/model-types-freshness.test.d.ts +2 -0
- package/dist/__tests__/db/model-types-freshness.test.d.ts.map +1 -0
- package/dist/__tests__/db/model-types-freshness.test.js +46 -0
- package/dist/__tests__/db/model-types-freshness.test.js.map +1 -0
- package/dist/__tests__/scheduling/scheduling.test.js +8 -6
- package/dist/__tests__/scheduling/scheduling.test.js.map +1 -1
- package/dist/__tests__/server-site.test.js +3 -1
- package/dist/__tests__/server-site.test.js.map +1 -1
- package/dist/__tests__/setup/index.test.js +21 -10
- package/dist/__tests__/setup/index.test.js.map +1 -1
- package/dist/actions.d.ts +2 -1
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +15 -8
- package/dist/actions.js.map +1 -1
- package/dist/api/guarded-db.d.ts +14 -0
- package/dist/api/guarded-db.d.ts.map +1 -0
- package/dist/api/guarded-db.js +58 -0
- package/dist/api/guarded-db.js.map +1 -0
- package/dist/api/handler-factory.d.ts.map +1 -1
- package/dist/api/handler-factory.js +2 -1
- package/dist/api/handler-factory.js.map +1 -1
- package/dist/api/handlers.d.ts +5 -3
- package/dist/api/handlers.d.ts.map +1 -1
- package/dist/api/handlers.js +54 -13068
- package/dist/api/handlers.js.map +1 -1
- package/dist/api/route-helpers.d.ts +321 -0
- package/dist/api/route-helpers.d.ts.map +1 -0
- package/dist/api/route-helpers.js +1307 -0
- package/dist/api/route-helpers.js.map +1 -0
- package/dist/api/routes/ai-seo.d.ts +3 -0
- package/dist/api/routes/ai-seo.d.ts.map +1 -0
- package/dist/api/routes/ai-seo.js +377 -0
- package/dist/api/routes/ai-seo.js.map +1 -0
- package/dist/api/routes/ai-settings.d.ts +3 -0
- package/dist/api/routes/ai-settings.d.ts.map +1 -0
- package/dist/api/routes/ai-settings.js +764 -0
- package/dist/api/routes/ai-settings.js.map +1 -0
- package/dist/api/routes/auth.d.ts +3 -0
- package/dist/api/routes/auth.d.ts.map +1 -0
- package/dist/api/routes/auth.js +787 -0
- package/dist/api/routes/auth.js.map +1 -0
- package/dist/api/routes/collab.d.ts +3 -0
- package/dist/api/routes/collab.d.ts.map +1 -0
- package/dist/api/routes/collab.js +426 -0
- package/dist/api/routes/collab.js.map +1 -0
- package/dist/api/routes/dashboard.d.ts +7 -0
- package/dist/api/routes/dashboard.d.ts.map +1 -0
- package/dist/api/routes/dashboard.js +540 -0
- package/dist/api/routes/dashboard.js.map +1 -0
- package/dist/api/routes/documents.d.ts +3 -0
- package/dist/api/routes/documents.d.ts.map +1 -0
- package/dist/api/routes/documents.js +180 -0
- package/dist/api/routes/documents.js.map +1 -0
- package/dist/api/routes/folders.d.ts +3 -0
- package/dist/api/routes/folders.d.ts.map +1 -0
- package/dist/api/routes/folders.js +195 -0
- package/dist/api/routes/folders.js.map +1 -0
- package/dist/api/routes/forms.d.ts +3 -0
- package/dist/api/routes/forms.d.ts.map +1 -0
- package/dist/api/routes/forms.js +661 -0
- package/dist/api/routes/forms.js.map +1 -0
- package/dist/api/routes/globals.d.ts +3 -0
- package/dist/api/routes/globals.d.ts.map +1 -0
- package/dist/api/routes/globals.js +133 -0
- package/dist/api/routes/globals.js.map +1 -0
- package/dist/api/routes/media.d.ts +3 -0
- package/dist/api/routes/media.d.ts.map +1 -0
- package/dist/api/routes/media.js +521 -0
- package/dist/api/routes/media.js.map +1 -0
- package/dist/api/routes/meta.d.ts +3 -0
- package/dist/api/routes/meta.d.ts.map +1 -0
- package/dist/api/routes/meta.js +96 -0
- package/dist/api/routes/meta.js.map +1 -0
- package/dist/api/routes/page-templates.d.ts +3 -0
- package/dist/api/routes/page-templates.d.ts.map +1 -0
- package/dist/api/routes/page-templates.js +265 -0
- package/dist/api/routes/page-templates.js.map +1 -0
- package/dist/api/routes/presence.d.ts +3 -0
- package/dist/api/routes/presence.d.ts.map +1 -0
- package/dist/api/routes/presence.js +35 -0
- package/dist/api/routes/presence.js.map +1 -0
- package/dist/api/routes/preview.d.ts +3 -0
- package/dist/api/routes/preview.d.ts.map +1 -0
- package/dist/api/routes/preview.js +111 -0
- package/dist/api/routes/preview.js.map +1 -0
- package/dist/api/routes/redirects.d.ts +3 -0
- package/dist/api/routes/redirects.d.ts.map +1 -0
- package/dist/api/routes/redirects.js +790 -0
- package/dist/api/routes/redirects.js.map +1 -0
- package/dist/api/routes/saved-sections.d.ts +3 -0
- package/dist/api/routes/saved-sections.d.ts.map +1 -0
- package/dist/api/routes/saved-sections.js +1036 -0
- package/dist/api/routes/saved-sections.js.map +1 -0
- package/dist/api/routes/scheduling.d.ts +3 -0
- package/dist/api/routes/scheduling.d.ts.map +1 -0
- package/dist/api/routes/scheduling.js +373 -0
- package/dist/api/routes/scheduling.js.map +1 -0
- package/dist/api/routes/sections.d.ts +3 -0
- package/dist/api/routes/sections.d.ts.map +1 -0
- package/dist/api/routes/sections.js +500 -0
- package/dist/api/routes/sections.js.map +1 -0
- package/dist/api/routes/security-center.d.ts +3 -0
- package/dist/api/routes/security-center.d.ts.map +1 -0
- package/dist/api/routes/security-center.js +71 -0
- package/dist/api/routes/security-center.js.map +1 -0
- package/dist/api/routes/seo-public.d.ts +14 -0
- package/dist/api/routes/seo-public.d.ts.map +1 -0
- package/dist/api/routes/seo-public.js +930 -0
- package/dist/api/routes/seo-public.js.map +1 -0
- package/dist/api/routes/seo.d.ts +8 -0
- package/dist/api/routes/seo.d.ts.map +1 -0
- package/dist/api/routes/seo.js +848 -0
- package/dist/api/routes/seo.js.map +1 -0
- package/dist/api/routes/system.d.ts +3 -0
- package/dist/api/routes/system.d.ts.map +1 -0
- package/dist/api/routes/system.js +340 -0
- package/dist/api/routes/system.js.map +1 -0
- package/dist/api/routes/url-resolution.d.ts +3 -0
- package/dist/api/routes/url-resolution.d.ts.map +1 -0
- package/dist/api/routes/url-resolution.js +457 -0
- package/dist/api/routes/url-resolution.js.map +1 -0
- package/dist/api/routes/users.d.ts +3 -0
- package/dist/api/routes/users.d.ts.map +1 -0
- package/dist/api/routes/users.js +1162 -0
- package/dist/api/routes/users.js.map +1 -0
- package/dist/api/routes/webhooks.d.ts +3 -0
- package/dist/api/routes/webhooks.d.ts.map +1 -0
- package/dist/api/routes/webhooks.js +338 -0
- package/dist/api/routes/webhooks.js.map +1 -0
- package/dist/auth/invites.d.ts +9 -8
- package/dist/auth/invites.d.ts.map +1 -1
- package/dist/auth/invites.js.map +1 -1
- package/dist/auth/oauth.d.ts +2 -1
- package/dist/auth/oauth.d.ts.map +1 -1
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/reset.d.ts +3 -2
- package/dist/auth/reset.d.ts.map +1 -1
- package/dist/auth/reset.js +5 -2
- package/dist/auth/reset.js.map +1 -1
- package/dist/auth/session.d.ts +3 -2
- package/dist/auth/session.d.ts.map +1 -1
- package/dist/auth/session.js.map +1 -1
- package/dist/auth/team.d.ts +4 -3
- package/dist/auth/team.d.ts.map +1 -1
- package/dist/auth/team.js.map +1 -1
- package/dist/auth/user-admin.d.ts +6 -5
- package/dist/auth/user-admin.d.ts.map +1 -1
- package/dist/auth/user-admin.js.map +1 -1
- package/dist/content-health/cron.d.ts +2 -1
- package/dist/content-health/cron.d.ts.map +1 -1
- package/dist/content-health/cron.js.map +1 -1
- package/dist/cron/index.d.ts +2 -1
- package/dist/cron/index.d.ts.map +1 -1
- package/dist/cron/index.js +2 -0
- package/dist/cron/index.js.map +1 -1
- package/dist/db/client-types.d.ts +75 -0
- package/dist/db/client-types.d.ts.map +1 -0
- package/dist/db/client-types.js +2 -0
- package/dist/db/client-types.js.map +1 -0
- package/dist/db/model-types.d.ts +564 -0
- package/dist/db/model-types.d.ts.map +1 -0
- package/dist/db/model-types.js +14 -0
- package/dist/db/model-types.js.map +1 -0
- package/dist/diagnostics/api-metrics.d.ts.map +1 -1
- package/dist/diagnostics/api-metrics.js.map +1 -1
- package/dist/forms/entries.d.ts.map +1 -1
- package/dist/forms/entries.js.map +1 -1
- package/dist/forms/files.d.ts.map +1 -1
- package/dist/forms/files.js.map +1 -1
- package/dist/forms/service.d.ts.map +1 -1
- package/dist/forms/service.js.map +1 -1
- package/dist/forms/submission.d.ts.map +1 -1
- package/dist/forms/submission.js.map +1 -1
- package/dist/forms/webhooks.d.ts.map +1 -1
- package/dist/forms/webhooks.js.map +1 -1
- package/dist/graphql/index.d.ts.map +1 -1
- package/dist/graphql/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/scheduling/index.d.ts +2 -1
- package/dist/scheduling/index.d.ts.map +1 -1
- package/dist/scheduling/index.js.map +1 -1
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js.map +1 -1
- package/dist/security/audit.d.ts.map +1 -1
- package/dist/security/audit.js.map +1 -1
- package/dist/security/reauth.d.ts +2 -1
- package/dist/security/reauth.d.ts.map +1 -1
- package/dist/security/reauth.js.map +1 -1
- package/dist/seo/audit-runner.d.ts +3 -2
- package/dist/seo/audit-runner.d.ts.map +1 -1
- package/dist/seo/audit-runner.js.map +1 -1
- package/dist/server-site.d.ts +2 -1
- package/dist/server-site.d.ts.map +1 -1
- package/dist/server-site.js.map +1 -1
- package/dist/setup/index.d.ts +4 -3
- package/dist/setup/index.d.ts.map +1 -1
- package/dist/setup/index.js.map +1 -1
- package/dist/webhooks/index.d.ts +5 -5
- package/dist/webhooks/index.d.ts.map +1 -1
- package/dist/webhooks/index.js +8 -1
- package/dist/webhooks/index.js.map +1 -1
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import { getActuateConfig } from '../../config/runtime.js';
|
|
2
|
+
import { guardedDb } from '../guarded-db.js';
|
|
3
|
+
import { json, internalError, logSafeQueryFailure, safeCount, safeFindMany, isSecretMissing, requireAuth, } from '../route-helpers.js';
|
|
4
|
+
/**
|
|
5
|
+
* Short-TTL cache for the dashboard's average SEO score.
|
|
6
|
+
*
|
|
7
|
+
* `/stats` otherwise reads the `data` JSON of up to 200 published
|
|
8
|
+
* documents and scores each one on every load — the single heaviest
|
|
9
|
+
* part of the endpoint. The score barely moves minute-to-minute, so we
|
|
10
|
+
* cache it per content-scope (the JSON-stringified Prisma `where`, which
|
|
11
|
+
* encodes the registered collection allowlist) for a short window.
|
|
12
|
+
*
|
|
13
|
+
* Module-level so it survives across requests within a warm isolate;
|
|
14
|
+
* a cold start simply recomputes once. Keyed by scope so multi-config
|
|
15
|
+
* isolates never read each other's score.
|
|
16
|
+
*/
|
|
17
|
+
let dashboardSeoCache = null;
|
|
18
|
+
const DASHBOARD_SEO_CACHE_TTL_MS = 60_000;
|
|
19
|
+
/** Test-only: reset the SEO score cache so cases don't bleed into each other. */
|
|
20
|
+
export function __resetDashboardSeoCache() {
|
|
21
|
+
dashboardSeoCache = null;
|
|
22
|
+
}
|
|
23
|
+
/** Cheap meta-completeness score used by /stats and the SEO summary surface. */
|
|
24
|
+
export function computeLightSeoScore(data) {
|
|
25
|
+
let score = 0;
|
|
26
|
+
if (data.metaTitle || data.seoTitle)
|
|
27
|
+
score += 25;
|
|
28
|
+
if (data.metaDescription || data.seoDescription)
|
|
29
|
+
score += 25;
|
|
30
|
+
if (data.canonical)
|
|
31
|
+
score += 25;
|
|
32
|
+
if (data.schemaType)
|
|
33
|
+
score += 25;
|
|
34
|
+
return score;
|
|
35
|
+
}
|
|
36
|
+
export function registerDashboardRoutes(router) {
|
|
37
|
+
const db = guardedDb;
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Stats route
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
const EMPTY_STATS = {
|
|
42
|
+
totalDocuments: 0,
|
|
43
|
+
totalMedia: 0,
|
|
44
|
+
totalUsers: 0,
|
|
45
|
+
formCount: 0,
|
|
46
|
+
avgSeoScore: 0,
|
|
47
|
+
webhookCount: 0,
|
|
48
|
+
webhookActiveCount: 0,
|
|
49
|
+
collectionCounts: {},
|
|
50
|
+
statusCounts: {},
|
|
51
|
+
recentDocuments: [],
|
|
52
|
+
};
|
|
53
|
+
const EMPTY_DELIVERY_STATS = {
|
|
54
|
+
hasData: false,
|
|
55
|
+
requests24h: 0,
|
|
56
|
+
requestsPrev24h: 0,
|
|
57
|
+
deltaPercent: null,
|
|
58
|
+
errorRate: 0,
|
|
59
|
+
errorCount: 0,
|
|
60
|
+
avgLatencyMs: 0,
|
|
61
|
+
p95LatencyMs: 0,
|
|
62
|
+
maxLatencyMs: 0,
|
|
63
|
+
webhookCount: 0,
|
|
64
|
+
webhookActiveCount: 0,
|
|
65
|
+
};
|
|
66
|
+
const EMPTY_CONTENT_HEALTH = {
|
|
67
|
+
score: 100,
|
|
68
|
+
label: 'Good',
|
|
69
|
+
counts: {
|
|
70
|
+
MISSING_META_DESCRIPTION: 0,
|
|
71
|
+
MISSING_ALT_TEXT: 0,
|
|
72
|
+
BROKEN_INTERNAL_LINK: 0,
|
|
73
|
+
OUTDATED_CONTENT: 0,
|
|
74
|
+
},
|
|
75
|
+
totalIssues: 0,
|
|
76
|
+
lastScanAt: null,
|
|
77
|
+
};
|
|
78
|
+
async function safeGroupBy(model, by, where) {
|
|
79
|
+
if (!model || typeof model !== 'object')
|
|
80
|
+
return [];
|
|
81
|
+
let groupByFn;
|
|
82
|
+
try {
|
|
83
|
+
groupByFn = model.groupBy;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
if (typeof groupByFn !== 'function')
|
|
89
|
+
return [];
|
|
90
|
+
try {
|
|
91
|
+
return await groupByFn.call(model, { by, where: where ?? {}, _count: { _all: true } });
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
logSafeQueryFailure('safeGroupBy', err);
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Average SEO score across published content, cached per content-scope
|
|
100
|
+
* for `DASHBOARD_SEO_CACHE_TTL_MS`. On a cache hit this returns without
|
|
101
|
+
* touching the database — avoiding the 200-document `data` read + scan
|
|
102
|
+
* that dominates `/stats`. Failures from `safeFindMany` surface as an
|
|
103
|
+
* empty list (score 0) and are not cached, so a transient DB blip
|
|
104
|
+
* doesn't pin a stale 0.
|
|
105
|
+
*/
|
|
106
|
+
async function getCachedAvgSeoScore(model, where) {
|
|
107
|
+
const key = JSON.stringify(where);
|
|
108
|
+
const now = Date.now();
|
|
109
|
+
if (dashboardSeoCache && dashboardSeoCache.key === key && dashboardSeoCache.expires > now) {
|
|
110
|
+
return dashboardSeoCache.value;
|
|
111
|
+
}
|
|
112
|
+
const docs = await safeFindMany(model, {
|
|
113
|
+
where,
|
|
114
|
+
select: { data: true },
|
|
115
|
+
take: 200,
|
|
116
|
+
});
|
|
117
|
+
let value = 0;
|
|
118
|
+
if (docs.length > 0) {
|
|
119
|
+
const total = docs.reduce((sum, doc) => sum + computeLightSeoScore(doc.data ?? {}), 0);
|
|
120
|
+
value = Math.round(total / docs.length);
|
|
121
|
+
}
|
|
122
|
+
dashboardSeoCache = { key, value, expires: now + DASHBOARD_SEO_CACHE_TTL_MS };
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Collection slugs that are written by the benchmark suite and a few
|
|
127
|
+
* other internal/test fixtures. Documents in these collections are
|
|
128
|
+
* never editor-facing content and should never appear in the
|
|
129
|
+
* dashboard's stats, counts, or recent-activity feed.
|
|
130
|
+
*
|
|
131
|
+
* This list is the fallback when the consumer ships collection
|
|
132
|
+
* definitions only to the admin client (e.g. `apps/dev`) and
|
|
133
|
+
* `getActuateConfig()?.collections` is therefore empty on the
|
|
134
|
+
* server. Production consumers normally pass `collections` to
|
|
135
|
+
* `handleActuateAPI({ config })`, in which case the registered
|
|
136
|
+
* slugs become the allowlist and this denylist is unused.
|
|
137
|
+
*/
|
|
138
|
+
const INTERNAL_COLLECTION_SLUGS = ['benchmarks', 'bench'];
|
|
139
|
+
/**
|
|
140
|
+
* Build the Prisma `where` clause for "user-facing content".
|
|
141
|
+
*
|
|
142
|
+
* - If the CMS config registered collections, restrict to those
|
|
143
|
+
* slugs — anything else is orphan/test data.
|
|
144
|
+
* - Otherwise fall back to excluding the internal denylist.
|
|
145
|
+
*
|
|
146
|
+
* Always excludes soft-deleted rows. Callers can spread additional
|
|
147
|
+
* filters on top (`status: 'PUBLISHED'`, etc.).
|
|
148
|
+
*/
|
|
149
|
+
function userContentWhere(extra = {}) {
|
|
150
|
+
const cfg = getActuateConfig();
|
|
151
|
+
const registered = Object.keys(cfg?.collections ?? {});
|
|
152
|
+
const collectionFilter = registered.length > 0 ? { in: registered } : { notIn: [...INTERNAL_COLLECTION_SLUGS] };
|
|
153
|
+
return { deletedAt: null, collection: collectionFilter, ...extra };
|
|
154
|
+
}
|
|
155
|
+
router.get('/stats', async (request) => {
|
|
156
|
+
try {
|
|
157
|
+
if (!isSecretMissing()) {
|
|
158
|
+
const auth = await requireAuth(request);
|
|
159
|
+
if (auth.error)
|
|
160
|
+
return auth.error;
|
|
161
|
+
}
|
|
162
|
+
let d;
|
|
163
|
+
try {
|
|
164
|
+
d = db();
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return json({ data: EMPTY_STATS });
|
|
168
|
+
}
|
|
169
|
+
// `userContentWhere()` filters out benchmark / orphan / internal
|
|
170
|
+
// collections so the dashboard surfaces editor content only. See
|
|
171
|
+
// the helper above for the allowlist-vs-denylist behaviour.
|
|
172
|
+
const contentWhere = userContentWhere();
|
|
173
|
+
const publishedContentWhere = userContentWhere({ status: 'PUBLISHED' });
|
|
174
|
+
const [docResult, mediaResult, userResult, recentResult, collGroupResult, statusGroupResult, formResult, seoScoreResult, webhookTotalResult, webhookActiveResult,] = await Promise.allSettled([
|
|
175
|
+
safeCount(d.document, contentWhere),
|
|
176
|
+
safeCount(d.media),
|
|
177
|
+
safeCount(d.user),
|
|
178
|
+
safeFindMany(d.document, {
|
|
179
|
+
// Prisma 7's `'join'` strategy folds the User relation into a
|
|
180
|
+
// single LATERAL SQL query so the dashboard read costs one
|
|
181
|
+
// round-trip instead of two. On the production Vercel Function
|
|
182
|
+
// -> Prisma Postgres path that saves ~80 ms (one full network
|
|
183
|
+
// RTT) on every dashboard load.
|
|
184
|
+
relationLoadStrategy: 'join',
|
|
185
|
+
where: contentWhere,
|
|
186
|
+
orderBy: { updatedAt: 'desc' },
|
|
187
|
+
take: 20,
|
|
188
|
+
select: {
|
|
189
|
+
id: true,
|
|
190
|
+
title: true,
|
|
191
|
+
status: true,
|
|
192
|
+
collection: true,
|
|
193
|
+
updatedAt: true,
|
|
194
|
+
createdById: true,
|
|
195
|
+
createdBy: { select: { name: true, email: true } },
|
|
196
|
+
},
|
|
197
|
+
}),
|
|
198
|
+
safeGroupBy(d.document, ['collection'], contentWhere),
|
|
199
|
+
safeGroupBy(d.document, ['status'], contentWhere),
|
|
200
|
+
safeCount(d.formSubmission),
|
|
201
|
+
// Cached per content-scope so the 200-doc SEO read+scan runs at
|
|
202
|
+
// most once per TTL window across warm requests.
|
|
203
|
+
getCachedAvgSeoScore(d.document, publishedContentWhere),
|
|
204
|
+
// Cheap counts so the dashboard's "Content Delivery" tile doesn't need
|
|
205
|
+
// a second round-trip. `webhookEndpoint` may not exist on every host,
|
|
206
|
+
// so `safeCount` swallows missing-model errors and returns 0.
|
|
207
|
+
safeCount(d.webhookEndpoint),
|
|
208
|
+
safeCount(d.webhookEndpoint, { active: true }),
|
|
209
|
+
]);
|
|
210
|
+
const collectionCounts = {};
|
|
211
|
+
if (collGroupResult.status === 'fulfilled') {
|
|
212
|
+
for (const g of collGroupResult.value)
|
|
213
|
+
collectionCounts[g.collection] = g._count._all;
|
|
214
|
+
}
|
|
215
|
+
const statusCounts = {};
|
|
216
|
+
if (statusGroupResult.status === 'fulfilled') {
|
|
217
|
+
for (const g of statusGroupResult.value)
|
|
218
|
+
statusCounts[g.status] = g._count._all;
|
|
219
|
+
}
|
|
220
|
+
const avgSeoScore = seoScoreResult.status === 'fulfilled' ? seoScoreResult.value : 0;
|
|
221
|
+
const recentDocs = recentResult.status === 'fulfilled'
|
|
222
|
+
? recentResult.value.map((doc) => ({
|
|
223
|
+
id: doc.id,
|
|
224
|
+
title: doc.title,
|
|
225
|
+
status: doc.status,
|
|
226
|
+
collection: doc.collection,
|
|
227
|
+
updatedAt: doc.updatedAt,
|
|
228
|
+
author: doc.createdBy?.name ?? doc.createdBy?.email ?? doc.createdById,
|
|
229
|
+
}))
|
|
230
|
+
: [];
|
|
231
|
+
return json({
|
|
232
|
+
data: {
|
|
233
|
+
totalDocuments: docResult.status === 'fulfilled' ? docResult.value : 0,
|
|
234
|
+
totalMedia: mediaResult.status === 'fulfilled' ? mediaResult.value : 0,
|
|
235
|
+
totalUsers: userResult.status === 'fulfilled' ? userResult.value : 0,
|
|
236
|
+
formCount: formResult.status === 'fulfilled' ? formResult.value : 0,
|
|
237
|
+
avgSeoScore,
|
|
238
|
+
webhookCount: webhookTotalResult.status === 'fulfilled' ? webhookTotalResult.value : 0,
|
|
239
|
+
webhookActiveCount: webhookActiveResult.status === 'fulfilled' ? webhookActiveResult.value : 0,
|
|
240
|
+
collectionCounts,
|
|
241
|
+
statusCounts,
|
|
242
|
+
recentDocuments: recentDocs,
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
return json({ data: EMPTY_STATS });
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
// Content Health — backs the dashboard "Content Health" issue rows
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
//
|
|
254
|
+
// Aggregates rows from `actuate_content_issues` (populated nightly by
|
|
255
|
+
// /cron/content-health) by `type`, returning the totals the dashboard
|
|
256
|
+
// surfaces. We also compute an overall content-health score so the
|
|
257
|
+
// big number + progress bar stay consistent with the per-row counts.
|
|
258
|
+
//
|
|
259
|
+
// Score model:
|
|
260
|
+
// - Start at 100.
|
|
261
|
+
// - Subtract 5 per missing-meta-description issue.
|
|
262
|
+
// - Subtract 2 per missing-alt image.
|
|
263
|
+
// - Subtract 10 per broken internal link.
|
|
264
|
+
// - Subtract 3 per outdated document.
|
|
265
|
+
// Floor at 0. The weights reflect SEO impact (broken links and
|
|
266
|
+
// missing meta hit hardest) and are kept here, not in the DB, so we
|
|
267
|
+
// can tune them without a migration.
|
|
268
|
+
router.get('/stats/content-health', async (request) => {
|
|
269
|
+
try {
|
|
270
|
+
if (!isSecretMissing()) {
|
|
271
|
+
const auth = await requireAuth(request);
|
|
272
|
+
if (auth.error)
|
|
273
|
+
return auth.error;
|
|
274
|
+
}
|
|
275
|
+
let d;
|
|
276
|
+
try {
|
|
277
|
+
d = db();
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return json({ data: EMPTY_CONTENT_HEALTH });
|
|
281
|
+
}
|
|
282
|
+
if (!d?.contentIssue) {
|
|
283
|
+
return json({ data: EMPTY_CONTENT_HEALTH });
|
|
284
|
+
}
|
|
285
|
+
let rows = [];
|
|
286
|
+
try {
|
|
287
|
+
rows = await d.contentIssue.groupBy({
|
|
288
|
+
by: ['type'],
|
|
289
|
+
_sum: { count: true },
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return json({ data: EMPTY_CONTENT_HEALTH });
|
|
294
|
+
}
|
|
295
|
+
const counts = {
|
|
296
|
+
MISSING_META_DESCRIPTION: 0,
|
|
297
|
+
MISSING_ALT_TEXT: 0,
|
|
298
|
+
BROKEN_INTERNAL_LINK: 0,
|
|
299
|
+
OUTDATED_CONTENT: 0,
|
|
300
|
+
};
|
|
301
|
+
for (const r of rows) {
|
|
302
|
+
counts[r.type] = r._sum.count ?? 0;
|
|
303
|
+
}
|
|
304
|
+
// Read-out via locals so TS narrows away the Record<string,..>
|
|
305
|
+
// indexed-access undefined union — we know the keys are present
|
|
306
|
+
// because we initialised them above.
|
|
307
|
+
const cMeta = counts['MISSING_META_DESCRIPTION'] ?? 0;
|
|
308
|
+
const cAlt = counts['MISSING_ALT_TEXT'] ?? 0;
|
|
309
|
+
const cLinks = counts['BROKEN_INTERNAL_LINK'] ?? 0;
|
|
310
|
+
const cOutdated = counts['OUTDATED_CONTENT'] ?? 0;
|
|
311
|
+
// Penalty model — see comment above.
|
|
312
|
+
let score = 100;
|
|
313
|
+
score -= cMeta * 5;
|
|
314
|
+
score -= cAlt * 2;
|
|
315
|
+
score -= cLinks * 10;
|
|
316
|
+
score -= cOutdated * 3;
|
|
317
|
+
score = Math.max(0, Math.min(100, score));
|
|
318
|
+
// Last scan timestamp — useful for the dashboard to display
|
|
319
|
+
// "Last scanned X minutes ago" so editors don't think the
|
|
320
|
+
// numbers are live.
|
|
321
|
+
let lastScanAt = null;
|
|
322
|
+
try {
|
|
323
|
+
const latest = await d.contentIssue.findFirst({
|
|
324
|
+
orderBy: { lastSeenAt: 'desc' },
|
|
325
|
+
select: { lastSeenAt: true },
|
|
326
|
+
});
|
|
327
|
+
lastScanAt = latest?.lastSeenAt ?? null;
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
/* ignore — empty table or stale schema */
|
|
331
|
+
}
|
|
332
|
+
return json({
|
|
333
|
+
data: {
|
|
334
|
+
score,
|
|
335
|
+
label: score >= 70 ? 'Good' : score >= 40 ? 'Fair' : 'Poor',
|
|
336
|
+
counts,
|
|
337
|
+
totalIssues: cMeta + cAlt + cLinks + cOutdated,
|
|
338
|
+
lastScanAt: lastScanAt?.toISOString() ?? null,
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
return json({ data: EMPTY_CONTENT_HEALTH });
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
// ---------------------------------------------------------------------------
|
|
347
|
+
// Delivery API metrics — backs the dashboard "Delivery API" tiles
|
|
348
|
+
// ---------------------------------------------------------------------------
|
|
349
|
+
//
|
|
350
|
+
// Reads from `actuate_api_request_metrics` (per-minute pre-aggregated
|
|
351
|
+
// counters populated by `recordApiRequest` in handler-factory.ts) and
|
|
352
|
+
// folds the last 24h into the four scalars the dashboard surfaces:
|
|
353
|
+
//
|
|
354
|
+
// - requests24h, requestsPrev24h (delta = "+12% vs yesterday")
|
|
355
|
+
// - errorRate (4xx + 5xx as fraction of total)
|
|
356
|
+
// - avgLatencyMs, p95LatencyMs (latter via histogram merge)
|
|
357
|
+
// - webhooks (total + active count)
|
|
358
|
+
//
|
|
359
|
+
// The endpoint returns a complete, never-undefined object even when
|
|
360
|
+
// the metrics table is empty — the dashboard distinguishes
|
|
361
|
+
// "no traffic yet" from "table missing" via the boolean `hasData`
|
|
362
|
+
// field so it can render an empty state without an extra round-trip.
|
|
363
|
+
router.get('/stats/api-delivery', async (request) => {
|
|
364
|
+
try {
|
|
365
|
+
if (!isSecretMissing()) {
|
|
366
|
+
const auth = await requireAuth(request);
|
|
367
|
+
if (auth.error)
|
|
368
|
+
return auth.error;
|
|
369
|
+
}
|
|
370
|
+
let d;
|
|
371
|
+
try {
|
|
372
|
+
d = db();
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
return json({ data: EMPTY_DELIVERY_STATS });
|
|
376
|
+
}
|
|
377
|
+
if (!d?.apiRequestMetric) {
|
|
378
|
+
return json({ data: EMPTY_DELIVERY_STATS });
|
|
379
|
+
}
|
|
380
|
+
const now = new Date();
|
|
381
|
+
const since24h = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
382
|
+
const sincePrev24h = new Date(now.getTime() - 48 * 60 * 60 * 1000);
|
|
383
|
+
const [currentResult, prevResult, webhookTotalResult, webhookActiveResult] = await Promise.allSettled([
|
|
384
|
+
safeFindMany(d.apiRequestMetric, {
|
|
385
|
+
where: { bucketStart: { gte: since24h } },
|
|
386
|
+
select: {
|
|
387
|
+
statusBucket: true,
|
|
388
|
+
count: true,
|
|
389
|
+
sumLatencyMs: true,
|
|
390
|
+
maxLatencyMs: true,
|
|
391
|
+
latencyHistogram: true,
|
|
392
|
+
},
|
|
393
|
+
}),
|
|
394
|
+
safeFindMany(d.apiRequestMetric, {
|
|
395
|
+
where: { bucketStart: { gte: sincePrev24h, lt: since24h } },
|
|
396
|
+
select: { count: true },
|
|
397
|
+
}),
|
|
398
|
+
safeCount(d.webhookEndpoint),
|
|
399
|
+
safeCount(d.webhookEndpoint, { active: true }),
|
|
400
|
+
]);
|
|
401
|
+
const currentRows = currentResult.status === 'fulfilled' ? currentResult.value : [];
|
|
402
|
+
const prevRows = prevResult.status === 'fulfilled' ? prevResult.value : [];
|
|
403
|
+
let total = 0;
|
|
404
|
+
let errorTotal = 0; // 4xx + 5xx
|
|
405
|
+
let sumLatency = 0;
|
|
406
|
+
let maxLatency = 0;
|
|
407
|
+
// Histogram merge for p95 — fixed 12-bucket array (see
|
|
408
|
+
// diagnostics/api-metrics.ts `HISTOGRAM_LENGTH`).
|
|
409
|
+
const mergedHistogram = new Array(12).fill(0);
|
|
410
|
+
for (const row of currentRows) {
|
|
411
|
+
total += row.count;
|
|
412
|
+
if (row.statusBucket === '4xx' || row.statusBucket === '5xx')
|
|
413
|
+
errorTotal += row.count;
|
|
414
|
+
sumLatency += row.sumLatencyMs;
|
|
415
|
+
if (row.maxLatencyMs > maxLatency)
|
|
416
|
+
maxLatency = row.maxLatencyMs;
|
|
417
|
+
const h = row.latencyHistogram;
|
|
418
|
+
if (Array.isArray(h)) {
|
|
419
|
+
for (let i = 0; i < mergedHistogram.length; i++) {
|
|
420
|
+
const v = h[i];
|
|
421
|
+
const current = mergedHistogram[i] ?? 0;
|
|
422
|
+
if (typeof v === 'number')
|
|
423
|
+
mergedHistogram[i] = current + v;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const prevTotal = prevRows.reduce((s, r) => s + r.count, 0);
|
|
428
|
+
const delta = prevTotal === 0 ? null : Math.round(((total - prevTotal) / prevTotal) * 1000) / 10; // 1-decimal %
|
|
429
|
+
const errorRate = total === 0 ? 0 : errorTotal / total;
|
|
430
|
+
const avgLatency = total === 0 ? 0 : sumLatency / total;
|
|
431
|
+
// p95: walk the merged histogram cumulatively, return the upper
|
|
432
|
+
// bound of the bucket that crosses the 0.95 watermark.
|
|
433
|
+
const LATENCY_BUCKET_UPPER = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024];
|
|
434
|
+
let p95Latency = 0;
|
|
435
|
+
if (total > 0) {
|
|
436
|
+
const target = total * 0.95;
|
|
437
|
+
let acc = 0;
|
|
438
|
+
for (let i = 0; i < mergedHistogram.length; i++) {
|
|
439
|
+
acc += mergedHistogram[i] ?? 0;
|
|
440
|
+
if (acc >= target) {
|
|
441
|
+
p95Latency =
|
|
442
|
+
i < LATENCY_BUCKET_UPPER.length
|
|
443
|
+
? LATENCY_BUCKET_UPPER[i]
|
|
444
|
+
: LATENCY_BUCKET_UPPER[LATENCY_BUCKET_UPPER.length - 1] * 2;
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const webhookTotal = webhookTotalResult.status === 'fulfilled' ? webhookTotalResult.value : 0;
|
|
450
|
+
const webhookActive = webhookActiveResult.status === 'fulfilled' ? webhookActiveResult.value : 0;
|
|
451
|
+
return json({
|
|
452
|
+
data: {
|
|
453
|
+
hasData: total > 0,
|
|
454
|
+
requests24h: total,
|
|
455
|
+
requestsPrev24h: prevTotal,
|
|
456
|
+
deltaPercent: delta,
|
|
457
|
+
errorRate: Math.round(errorRate * 10000) / 10000, // 4-dec precision
|
|
458
|
+
errorCount: errorTotal,
|
|
459
|
+
avgLatencyMs: Math.round(avgLatency * 10) / 10,
|
|
460
|
+
p95LatencyMs: p95Latency,
|
|
461
|
+
maxLatencyMs: Math.round(maxLatency * 10) / 10,
|
|
462
|
+
webhookCount: webhookTotal,
|
|
463
|
+
webhookActiveCount: webhookActive,
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
catch {
|
|
468
|
+
return json({ data: EMPTY_DELIVERY_STATS });
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
// ---------------------------------------------------------------------------
|
|
472
|
+
// Global search
|
|
473
|
+
// ---------------------------------------------------------------------------
|
|
474
|
+
router.get('/search/global', async (request) => {
|
|
475
|
+
try {
|
|
476
|
+
const auth = await requireAuth(request);
|
|
477
|
+
if (auth.error)
|
|
478
|
+
return auth.error;
|
|
479
|
+
const url = new URL(request.url, 'http://localhost');
|
|
480
|
+
const q = (url.searchParams.get('q') ?? '').trim();
|
|
481
|
+
if (!q)
|
|
482
|
+
return json({ data: { documents: [], media: [], users: [] } });
|
|
483
|
+
const d = db();
|
|
484
|
+
// Documents and media are visible to all signed-in users; the user
|
|
485
|
+
// directory is gated to EDITOR+ so a CLIENT can't enumerate the team
|
|
486
|
+
// (or harvest emails for spear-phishing).
|
|
487
|
+
const canSeeUserDirectory = auth.session.role === 'ADMIN' || auth.session.role === 'EDITOR';
|
|
488
|
+
const [documents, media, users] = await Promise.all([
|
|
489
|
+
safeFindMany(d.document, {
|
|
490
|
+
where: {
|
|
491
|
+
deletedAt: null,
|
|
492
|
+
OR: [
|
|
493
|
+
{ title: { contains: q, mode: 'insensitive' } },
|
|
494
|
+
{ plainText: { contains: q, mode: 'insensitive' } },
|
|
495
|
+
],
|
|
496
|
+
},
|
|
497
|
+
take: 10,
|
|
498
|
+
orderBy: { updatedAt: 'desc' },
|
|
499
|
+
select: {
|
|
500
|
+
id: true,
|
|
501
|
+
title: true,
|
|
502
|
+
slug: true,
|
|
503
|
+
collection: true,
|
|
504
|
+
status: true,
|
|
505
|
+
updatedAt: true,
|
|
506
|
+
},
|
|
507
|
+
}),
|
|
508
|
+
safeFindMany(d.media, {
|
|
509
|
+
where: {
|
|
510
|
+
OR: [
|
|
511
|
+
{ filename: { contains: q, mode: 'insensitive' } },
|
|
512
|
+
{ altText: { contains: q, mode: 'insensitive' } },
|
|
513
|
+
],
|
|
514
|
+
},
|
|
515
|
+
take: 5,
|
|
516
|
+
orderBy: { createdAt: 'desc' },
|
|
517
|
+
select: { id: true, filename: true, altText: true, mimeType: true, storageKey: true },
|
|
518
|
+
}),
|
|
519
|
+
canSeeUserDirectory
|
|
520
|
+
? safeFindMany(d.user, {
|
|
521
|
+
where: {
|
|
522
|
+
isActive: true,
|
|
523
|
+
OR: [
|
|
524
|
+
{ name: { contains: q, mode: 'insensitive' } },
|
|
525
|
+
{ email: { contains: q, mode: 'insensitive' } },
|
|
526
|
+
],
|
|
527
|
+
},
|
|
528
|
+
take: 5,
|
|
529
|
+
select: { id: true, name: true, email: true, role: true },
|
|
530
|
+
})
|
|
531
|
+
: Promise.resolve([]),
|
|
532
|
+
]);
|
|
533
|
+
return json({ data: { documents, media, users } });
|
|
534
|
+
}
|
|
535
|
+
catch (err) {
|
|
536
|
+
return internalError(err);
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/api/routes/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../../src/api/routes/documents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AA2B7C,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgM9D"}
|