Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/brave-waves-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@namehash/ens-referrals": minor
"ensapi": minor
---

Added `status` field to referral program API responses (`ReferrerLeaderboardPage`, `ReferrerEditionMetricsRanked`, `ReferrerEditionMetricsUnranked`) indicating whether a program is "Scheduled", "Active", or "Closed" based on the program's timing relative to `accurateAsOf`.
5 changes: 5 additions & 0 deletions .changeset/clever-frogs-detect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ensnode/ensnode-sdk": patch
---

Added `isIndefinitelyStored()` method to SWRCache for detecting caches configured with infinite TTL and no proactive revalidation.
5 changes: 5 additions & 0 deletions .changeset/lemon-moose-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ensapi": minor
---

Implemented automatic cache upgrade to indefinite storage for immutably closed referral program editions. Caches safely transition from regular SWR to immutable storage with zero-data-loss initialization, atomic race prevention, and graceful failure handling.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const supportedOmnichainIndexingStatuses: OmnichainIndexingStatusId[] = [
* @param editionConfig - The edition configuration
* @returns A function that builds the leaderboard for the given edition
*/
function createEditionLeaderboardBuilder(
export function createEditionLeaderboardBuilder(
editionConfig: ReferralProgramEditionConfig,
): () => Promise<ReferrerLeaderboard> {
return async (): Promise<ReferrerLeaderboard> => {
Expand Down Expand Up @@ -120,6 +120,10 @@ let cachedInstance: ReferralLeaderboardEditionsCacheMap | null = null;
* ensuring that if one edition fails to refresh, other editions' previously successful
* data remains available.
*
* All caches are initially created with normal refresh behavior. Caches are dynamically upgraded
* to immutable storage (infinite TTL, no proactive revalidation) by the middleware after an edition
* has been closed for more than the safety window based on accurate indexing timestamps.
*
* @param editionConfigSet - The referral program edition config set to initialize caches for
* @returns A map from edition slug to its dedicated SWRCache
*/
Expand All @@ -134,6 +138,8 @@ export function initializeReferralLeaderboardEditionsCaches(
const caches: ReferralLeaderboardEditionsCacheMap = new Map();

for (const [editionSlug, editionConfig] of editionConfigSet) {
// All editions start with normal refresh behavior
// They will be dynamically upgraded to immutable storage by the middleware
const cache = new SWRCache({
fn: createEditionLeaderboardBuilder(editionConfig),
ttl: minutesToSeconds(1),
Expand Down
7 changes: 7 additions & 0 deletions apps/ensapi/src/handlers/ensanalytics-api-v1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
deserializeReferrerMetricsEditionsResponse,
ReferralProgramEditionConfigSetResponseCodes,
type ReferralProgramEditionSlug,
ReferralProgramStatuses,
ReferrerEditionMetricsTypeIds,
type ReferrerLeaderboard,
ReferrerLeaderboardPageResponseCodes,
Expand Down Expand Up @@ -118,6 +119,7 @@ describe("/v1/ensanalytics", () => {
responseCode: ReferrerLeaderboardPageResponseCodes.Ok,
data: {
...populatedReferrerLeaderboard,
status: ReferralProgramStatuses.Active,
pageContext: {
endIndex: 9,
hasNext: true,
Expand All @@ -139,6 +141,7 @@ describe("/v1/ensanalytics", () => {
responseCode: ReferrerLeaderboardPageResponseCodes.Ok,
data: {
...populatedReferrerLeaderboard,
status: ReferralProgramStatuses.Active,
pageContext: {
endIndex: 19,
hasNext: true,
Expand All @@ -159,6 +162,7 @@ describe("/v1/ensanalytics", () => {
responseCode: ReferrerLeaderboardPageResponseCodes.Ok,
data: {
...populatedReferrerLeaderboard,
status: ReferralProgramStatuses.Active,
pageContext: {
endIndex: 28,
hasNext: false,
Expand Down Expand Up @@ -223,6 +227,7 @@ describe("/v1/ensanalytics", () => {
responseCode: ReferrerLeaderboardPageResponseCodes.Ok,
data: {
...emptyReferralLeaderboard,
status: ReferralProgramStatuses.Active,
pageContext: {
hasNext: false,
hasPrev: false,
Expand Down Expand Up @@ -364,13 +369,15 @@ describe("/v1/ensanalytics", () => {
referrer: expectedMetrics,
aggregatedMetrics: populatedReferrerLeaderboard.aggregatedMetrics,
accurateAsOf: expectedAccurateAsOf,
status: ReferralProgramStatuses.Active,
},
"2026-03": {
type: ReferrerEditionMetricsTypeIds.Ranked,
rules: populatedReferrerLeaderboard.rules,
referrer: expectedMetrics,
aggregatedMetrics: populatedReferrerLeaderboard.aggregatedMetrics,
accurateAsOf: expectedAccurateAsOf,
status: ReferralProgramStatuses.Active,
},
},
} satisfies ReferrerMetricsEditionsResponseOk;
Expand Down
Loading
Loading