@commonpub/server 2.45.0 → 2.45.1

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.
@@ -8,6 +8,8 @@ export { authenticateApiKey } from './auth.js';
8
8
  export type { AuthResult, AuthSuccess, AuthRejected, AuthFailure } from './auth.js';
9
9
  export { createApiKey, listApiKeys, revokeApiKey, getApiKeyById, logApiKeyUsage, touchLastUsed, } from './adminOps.js';
10
10
  export type { CreateApiKeyResult } from './adminOps.js';
11
+ export { getApiKeyUsageStats } from './usage.js';
12
+ export type { ApiKeyUsageStats } from './usage.js';
11
13
  export { toPublicUser, isPublicUser, toPublicContentSummary, toPublicContentDetail, isPublicContent, toPublicHub, isPublicHub, toAdminApiKeyView, toPublicLearningPath, isPublicLearningPath, toPublicEvent, isPublicEvent, toPublicContest, isPublicContest, toPublicVideo, isPublicVideo, toPublicDocSite, isPublicDocSite, toPublicTag, } from './serializers.js';
12
14
  export type { PublicUser, PublicUserRow, PublicContentSummary, PublicContentDetail, PublicContentRow, PublicHub, PublicHubRow, PublicInstance, AdminApiKeyView, PublicLearningPath, PublicLearningPathRow, PublicEvent, PublicEventRow, PublicContest, PublicContestRow, PublicVideo, PublicVideoRow, PublicDocSite, PublicDocSiteRow, PublicTag, PublicTagRow, } from './serializers.js';
13
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/publicApi/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACtF,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,EACL,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,WAAW,EACX,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,YAAY,GACb,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/publicApi/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACtF,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,EACL,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,WAAW,EACX,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,YAAY,GACb,MAAM,kBAAkB,CAAC"}
@@ -3,5 +3,6 @@ export { generateApiKey, hashApiKey, compareKeyHash, extractPrefix } from './key
3
3
  export { apiKeyRateLimit, ApiKeyRateLimit } from './rateLimit.js';
4
4
  export { authenticateApiKey } from './auth.js';
5
5
  export { createApiKey, listApiKeys, revokeApiKey, getApiKeyById, logApiKeyUsage, touchLastUsed, } from './adminOps.js';
6
+ export { getApiKeyUsageStats } from './usage.js';
6
7
  export { toPublicUser, isPublicUser, toPublicContentSummary, toPublicContentDetail, isPublicContent, toPublicHub, isPublicHub, toAdminApiKeyView, toPublicLearningPath, isPublicLearningPath, toPublicEvent, isPublicEvent, toPublicContest, isPublicContest, toPublicVideo, isPublicVideo, toPublicDocSite, isPublicDocSite, toPublicTag, } from './serializers.js';
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/publicApi/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAGtF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EACL,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/publicApi/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAGtF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EACL,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { DB } from '../types.js';
2
+ export interface ApiKeyUsageStats {
3
+ windowDays: number;
4
+ totalRequests: number;
5
+ errorCount: number;
6
+ errorRate: number;
7
+ /** Array of { day: 'YYYY-MM-DD', count: number }, newest first. */
8
+ requestsByDay: Array<{
9
+ day: string;
10
+ count: number;
11
+ }>;
12
+ /** Top endpoints by request count within the window. */
13
+ topEndpoints: Array<{
14
+ endpoint: string;
15
+ count: number;
16
+ p95LatencyMs: number | null;
17
+ }>;
18
+ }
19
+ /**
20
+ * Per-key usage analytics for the admin dashboard. Narrow, indexed queries
21
+ * only — no full-table scans. Uses `count(*) FILTER (WHERE ...)` conditional
22
+ * aggregation so the totals, error counts, and day buckets come from a
23
+ * single round-trip where possible.
24
+ */
25
+ export declare function getApiKeyUsageStats(db: DB, keyId: string, windowDays?: number): Promise<ApiKeyUsageStats>;
26
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/publicApi/usage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,aAAa,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,wDAAwD;IACxD,YAAY,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CACvF;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,EAAE,EACN,KAAK,EAAE,MAAM,EACb,UAAU,SAAI,GACb,OAAO,CAAC,gBAAgB,CAAC,CAiD3B"}
@@ -0,0 +1,56 @@
1
+ import { apiKeyUsage } from '@commonpub/schema';
2
+ import { and, desc, eq, gte, sql } from 'drizzle-orm';
3
+ /**
4
+ * Per-key usage analytics for the admin dashboard. Narrow, indexed queries
5
+ * only — no full-table scans. Uses `count(*) FILTER (WHERE ...)` conditional
6
+ * aggregation so the totals, error counts, and day buckets come from a
7
+ * single round-trip where possible.
8
+ */
9
+ export async function getApiKeyUsageStats(db, keyId, windowDays = 7) {
10
+ const since = new Date(Date.now() - windowDays * 86400_000);
11
+ const base = and(eq(apiKeyUsage.keyId, keyId), gte(apiKeyUsage.timestamp, since));
12
+ const [[totals], byDay, byEndpoint] = await Promise.all([
13
+ db
14
+ .select({
15
+ totalRequests: sql `count(*)::int`,
16
+ errorCount: sql `count(*) FILTER (WHERE ${apiKeyUsage.statusCode} >= 400)::int`,
17
+ })
18
+ .from(apiKeyUsage)
19
+ .where(base),
20
+ db
21
+ .select({
22
+ day: sql `to_char(date_trunc('day', ${apiKeyUsage.timestamp}), 'YYYY-MM-DD')`,
23
+ count: sql `count(*)::int`,
24
+ })
25
+ .from(apiKeyUsage)
26
+ .where(base)
27
+ .groupBy(sql `date_trunc('day', ${apiKeyUsage.timestamp})`)
28
+ .orderBy(desc(sql `date_trunc('day', ${apiKeyUsage.timestamp})`)),
29
+ db
30
+ .select({
31
+ endpoint: apiKeyUsage.endpoint,
32
+ count: sql `count(*)::int`,
33
+ p95LatencyMs: sql `percentile_cont(0.95) within group (order by ${apiKeyUsage.latencyMs})::int`,
34
+ })
35
+ .from(apiKeyUsage)
36
+ .where(base)
37
+ .groupBy(apiKeyUsage.endpoint)
38
+ .orderBy(desc(sql `count(*)`))
39
+ .limit(10),
40
+ ]);
41
+ const totalRequests = totals?.totalRequests ?? 0;
42
+ const errorCount = totals?.errorCount ?? 0;
43
+ return {
44
+ windowDays,
45
+ totalRequests,
46
+ errorCount,
47
+ errorRate: totalRequests > 0 ? errorCount / totalRequests : 0,
48
+ requestsByDay: byDay.map((r) => ({ day: r.day, count: r.count })),
49
+ topEndpoints: byEndpoint.map((r) => ({
50
+ endpoint: r.endpoint,
51
+ count: r.count,
52
+ p95LatencyMs: r.p95LatencyMs,
53
+ })),
54
+ };
55
+ }
56
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/publicApi/usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AActD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAM,EACN,KAAa,EACb,UAAU,GAAG,CAAC;IAEd,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;IAElF,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtD,EAAE;aACC,MAAM,CAAC;YACN,aAAa,EAAE,GAAG,CAAQ,eAAe;YACzC,UAAU,EAAE,GAAG,CAAQ,0BAA0B,WAAW,CAAC,UAAU,eAAe;SACvF,CAAC;aACD,IAAI,CAAC,WAAW,CAAC;aACjB,KAAK,CAAC,IAAI,CAAC;QACd,EAAE;aACC,MAAM,CAAC;YACN,GAAG,EAAE,GAAG,CAAQ,6BAA6B,WAAW,CAAC,SAAS,kBAAkB;YACpF,KAAK,EAAE,GAAG,CAAQ,eAAe;SAClC,CAAC;aACD,IAAI,CAAC,WAAW,CAAC;aACjB,KAAK,CAAC,IAAI,CAAC;aACX,OAAO,CAAC,GAAG,CAAA,qBAAqB,WAAW,CAAC,SAAS,GAAG,CAAC;aACzD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAA,qBAAqB,WAAW,CAAC,SAAS,GAAG,CAAC,CAAC;QAClE,EAAE;aACC,MAAM,CAAC;YACN,QAAQ,EAAE,WAAW,CAAC,QAAQ;YAC9B,KAAK,EAAE,GAAG,CAAQ,eAAe;YACjC,YAAY,EAAE,GAAG,CAAe,gDAAgD,WAAW,CAAC,SAAS,QAAQ;SAC9G,CAAC;aACD,IAAI,CAAC,WAAW,CAAC;aACjB,KAAK,CAAC,IAAI,CAAC;aACX,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC;aAC7B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAQ,UAAU,CAAC,CAAC;aACpC,KAAK,CAAC,EAAE,CAAC;KACb,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,MAAM,EAAE,aAAa,IAAI,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,MAAM,EAAE,UAAU,IAAI,CAAC,CAAC;IAE3C,OAAO;QACL,UAAU;QACV,aAAa;QACb,UAAU;QACV,SAAS,EAAE,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAC7D,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACjE,YAAY,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACnC,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,YAAY,EAAE,CAAC,CAAC,YAAY;SAC7B,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commonpub/server",
3
- "version": "2.45.0",
3
+ "version": "2.45.1",
4
4
  "type": "module",
5
5
  "description": "Framework-agnostic business logic for CommonPub instances",
6
6
  "license": "AGPL-3.0-or-later",
@@ -109,9 +109,9 @@
109
109
  "linkedom": "^0.18.12",
110
110
  "turndown": "^7.2.4",
111
111
  "@commonpub/config": "0.11.0",
112
+ "@commonpub/docs": "0.6.2",
112
113
  "@commonpub/editor": "0.7.9",
113
114
  "@commonpub/infra": "0.5.1",
114
- "@commonpub/docs": "0.6.2",
115
115
  "@commonpub/learning": "0.5.0",
116
116
  "@commonpub/protocol": "0.9.9",
117
117
  "@commonpub/auth": "0.5.1"