11// src/modules/creators/creators.stats.ts
2- // Helper for formatting public creator stats in API responses.
2+ // Mapper for shaping public creator stats in API responses.
33
44import { CreatorMetrics } from '../../types/profile.types' ;
55
6+ /**
7+ * Public field names exposed by the stats mapper.
8+ * Single source of truth for what gets included in public stats responses.
9+ */
10+ export const CREATOR_STATS_FIELDS = [
11+ 'holderCount' ,
12+ 'totalSupply' ,
13+ 'totalVolume' ,
14+ 'lastActivityAt' ,
15+ ] as const ;
16+
17+ export type CreatorStatsField = ( typeof CREATOR_STATS_FIELDS ) [ number ] ;
18+
619/**
720 * Public-facing creator stats shape.
821 *
@@ -17,27 +30,45 @@ export interface PublicCreatorStats {
1730}
1831
1932/**
20- * Format a CreatorMetrics object into a public stats response.
33+ * Maps each public stats field to its corresponding internal CreatorMetrics key.
34+ * Currently 1:1, but the indirection lets internal field names change
35+ * without breaking the public API contract.
36+ *
37+ * Uses `as const satisfies` to retain literal types for type-safe indexing
38+ * while enforcing that all public fields map to valid CreatorMetrics keys.
39+ */
40+ const CREATOR_STATS_FIELD_MAP = {
41+ holderCount : 'holderCount' ,
42+ totalSupply : 'totalSupply' ,
43+ totalVolume : 'totalVolume' ,
44+ lastActivityAt : 'lastActivityAt' ,
45+ } as const satisfies Record < CreatorStatsField , keyof CreatorMetrics > ;
46+
47+ /**
48+ * Map a CreatorMetrics object into a public stats response.
2149 *
22- * Centralizes the public stats shape so all creator endpoints
23- * return a consistent structure .
50+ * Uses CREATOR_STATS_FIELD_MAP to build the output, ensuring only
51+ * mapped fields are included. Optional fields are omitted when undefined .
2452 *
2553 * @param metrics - Internal creator metrics
2654 * @returns Public stats object safe for API responses
2755 *
2856 * @example
29- * serializePublicCreatorStats ({ holderCount: 10, totalSupply: 100, totalVolume: 500 })
57+ * mapPublicCreatorStats ({ holderCount: 10, totalSupply: 100, totalVolume: 500 })
3058 * // => { holderCount: 10, totalSupply: 100, totalVolume: 500 }
3159 */
32- export function serializePublicCreatorStats (
60+ export function mapPublicCreatorStats (
3361 metrics : CreatorMetrics
3462) : PublicCreatorStats {
3563 return {
36- holderCount : metrics . holderCount ,
37- totalSupply : metrics . totalSupply ,
38- totalVolume : metrics . totalVolume ,
39- ...( metrics . lastActivityAt !== undefined
40- ? { lastActivityAt : metrics . lastActivityAt }
64+ holderCount : metrics [ CREATOR_STATS_FIELD_MAP . holderCount ] ,
65+ totalSupply : metrics [ CREATOR_STATS_FIELD_MAP . totalSupply ] ,
66+ totalVolume : metrics [ CREATOR_STATS_FIELD_MAP . totalVolume ] ,
67+ ...( metrics [ CREATOR_STATS_FIELD_MAP . lastActivityAt ] !== undefined
68+ ? {
69+ lastActivityAt :
70+ metrics [ CREATOR_STATS_FIELD_MAP . lastActivityAt ] ,
71+ }
4172 : { } ) ,
4273 } ;
4374}
0 commit comments