@stigg/node-server-sdk 4.10.0 → 4.12.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.
Files changed (95) hide show
  1. package/dist/api/entitlements/entitlementsApi.d.ts +3 -4
  2. package/dist/api/entitlements/entitlementsApi.js +3 -8
  3. package/dist/client.d.ts +11 -1
  4. package/dist/client.js +26 -4
  5. package/dist/clientInitialization.js +8 -7
  6. package/dist/configuration.d.ts +2 -21
  7. package/dist/configuration.js +1 -1
  8. package/dist/models.d.ts +30 -6
  9. package/dist/models.js +12 -2
  10. package/dist/services/ApiCacheMapper.d.ts +15 -0
  11. package/dist/services/ApiCacheMapper.js +96 -0
  12. package/dist/services/EdgeApiClient.d.ts +1 -2
  13. package/dist/services/EdgeApiClient.js +1 -7
  14. package/dist/services/LegacyEventPayloadMapper.d.ts +15 -0
  15. package/dist/services/LegacyEventPayloadMapper.js +102 -0
  16. package/dist/services/cache/CacheMapper.d.ts +16 -0
  17. package/dist/services/cache/CacheMapper.js +3 -0
  18. package/dist/services/cache/RedisSingleExecutionService/RedisSingleExecution.d.ts +3 -3
  19. package/dist/services/cache/RedisSingleExecutionService/RedisSingleExecution.js +4 -3
  20. package/dist/services/cache/accessDeniedReasonMapper.d.ts +3 -0
  21. package/dist/services/cache/accessDeniedReasonMapper.js +16 -0
  22. package/dist/services/cache/cacheKeysHelpers.d.ts +9 -0
  23. package/dist/services/cache/cacheKeysHelpers.js +55 -0
  24. package/dist/services/cache/cacheService.d.ts +10 -28
  25. package/dist/services/cache/entities/cachedEntitlement.d.ts +20 -0
  26. package/dist/services/cache/entities/cachedEntitlement.js +53 -0
  27. package/dist/services/cache/entities/calculatedEntitlement.d.ts +34 -0
  28. package/dist/services/cache/entities/calculatedEntitlement.js +3 -0
  29. package/dist/services/cache/entities/entitlementQuery.d.ts +8 -0
  30. package/dist/services/cache/entities/entitlementQuery.js +3 -0
  31. package/dist/services/cache/entities/entitlementsMap.d.ts +33 -0
  32. package/dist/services/cache/entities/entitlementsMap.js +92 -0
  33. package/dist/services/cache/entities/index.d.ts +6 -0
  34. package/dist/services/cache/entities/index.js +12 -0
  35. package/dist/services/cache/entities/usageData.d.ts +11 -0
  36. package/dist/services/cache/entities/usageData.js +9 -0
  37. package/dist/services/cache/extractWithDependencies.d.ts +12 -0
  38. package/dist/services/cache/extractWithDependencies.js +37 -0
  39. package/dist/services/cache/freshness/EntitlementsFreshener.d.ts +11 -0
  40. package/dist/services/cache/freshness/EntitlementsFreshener.js +27 -0
  41. package/dist/services/cache/freshness/transformers/CreditAccessPropagator.d.ts +15 -0
  42. package/dist/services/cache/freshness/transformers/CreditAccessPropagator.js +67 -0
  43. package/dist/services/cache/freshness/transformers/UsagePeriodReset.d.ts +11 -0
  44. package/dist/services/cache/freshness/transformers/UsagePeriodReset.js +45 -0
  45. package/dist/services/cache/inMemoryCacheService.d.ts +19 -14
  46. package/dist/services/cache/inMemoryCacheService.js +44 -69
  47. package/dist/services/cache/index.d.ts +13 -0
  48. package/dist/services/cache/index.js +38 -0
  49. package/dist/services/cache/redis/distributedLocks.d.ts +4 -3
  50. package/dist/services/cache/redis/distributedLocks.js +5 -4
  51. package/dist/services/cache/redisCacheService.constants.d.ts +1 -1
  52. package/dist/services/cache/redisCacheService.constants.js +3 -3
  53. package/dist/services/cache/redisCacheService.d.ts +54 -17
  54. package/dist/services/cache/redisCacheService.js +293 -159
  55. package/dist/services/cache/types/cacheInstrumentation.d.ts +37 -0
  56. package/dist/services/cache/types/cacheInstrumentation.js +3 -0
  57. package/dist/services/cache/types/cacheResponse.d.ts +26 -0
  58. package/dist/services/cache/types/cacheResponse.js +19 -0
  59. package/dist/services/cache/types/cacheServiceParams.d.ts +20 -0
  60. package/dist/services/cache/types/cacheServiceParams.js +3 -0
  61. package/dist/services/cache/types/entitlementFeature.d.ts +19 -0
  62. package/dist/services/cache/types/entitlementFeature.js +3 -0
  63. package/dist/services/cache/types/entitlementsMapTransformer.d.ts +4 -0
  64. package/dist/services/cache/types/entitlementsMapTransformer.js +3 -0
  65. package/dist/services/cache/types/logger.d.ts +6 -0
  66. package/dist/services/cache/types/logger.js +3 -0
  67. package/dist/services/cache/types/redisConfiguration.d.ts +39 -0
  68. package/dist/services/cache/types/redisConfiguration.js +14 -0
  69. package/dist/services/entitlementDecisionService.d.ts +14 -2
  70. package/dist/services/entitlementDecisionService.js +41 -14
  71. package/dist/services/entitlementsService.d.ts +26 -23
  72. package/dist/services/entitlementsService.js +126 -110
  73. package/dist/services/entitlementsService.utils.d.ts +1 -28
  74. package/dist/services/entitlementsService.utils.js +1 -17
  75. package/dist/services/eventEmitter.d.ts +1 -1
  76. package/dist/services/eventEmitterCacheInstrumentation.d.ts +9 -0
  77. package/dist/services/eventEmitterCacheInstrumentation.js +19 -0
  78. package/dist/services/inMemoryEntitlementsService.d.ts +5 -6
  79. package/dist/services/inMemoryEntitlementsService.js +52 -59
  80. package/dist/services/redisEntitlementsService.d.ts +5 -4
  81. package/dist/services/redisEntitlementsService.js +2 -2
  82. package/dist/types.d.ts +2 -0
  83. package/dist/utils/ModelMapper.d.ts +8 -7
  84. package/dist/utils/ModelMapper.js +17 -3
  85. package/dist/{services/cache → utils}/calculateUsagePeriod.js +1 -1
  86. package/package.json +18 -1
  87. package/dist/services/cache/cachedEntitlement.d.ts +0 -29
  88. package/dist/services/cache/cachedEntitlement.js +0 -10
  89. package/dist/services/cacheInstrumentation.d.ts +0 -18
  90. package/dist/services/cacheInstrumentation.js +0 -19
  91. package/dist/utils/CacheMapper.d.ts +0 -6
  92. package/dist/utils/CacheMapper.js +0 -57
  93. package/dist/utils/cacheKeysHelpers.d.ts +0 -7
  94. package/dist/utils/cacheKeysHelpers.js +0 -42
  95. /package/dist/{services/cache → utils}/calculateUsagePeriod.d.ts +0 -0
@@ -4,30 +4,38 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.RedisCacheService = void 0;
7
- const cachedEntitlement_1 = __importDefault(require("./cachedEntitlement"));
7
+ const entities_1 = require("./entities");
8
8
  const ioredis_1 = __importDefault(require("ioredis"));
9
9
  const lodash_1 = require("lodash");
10
- const cacheKeysHelpers_1 = require("../../utils/cacheKeysHelpers");
10
+ const redisConfiguration_1 = require("./types/redisConfiguration");
11
+ const cacheKeysHelpers_1 = require("./cacheKeysHelpers");
11
12
  const RedisSingleExecutionService_1 = require("./RedisSingleExecutionService");
12
- const entitlementsService_utils_1 = require("../entitlementsService.utils");
13
+ const cacheResponse_1 = require("./types/cacheResponse");
14
+ const extractWithDependencies_1 = require("./extractWithDependencies");
15
+ const EntitlementsFreshener_1 = require("./freshness/EntitlementsFreshener");
13
16
  const redisCacheService_constants_1 = require("./redisCacheService.constants");
14
- const featureTypes_1 = require("../../utils/featureTypes");
15
17
  const distributedLocks_1 = require("./redis/distributedLocks");
18
+ const accessDeniedReasonMapper_1 = require("./accessDeniedReasonMapper");
16
19
  const GRACE_CONNECT_TIMEOUT_MS = 250;
17
20
  const READY_STATUSES = ['connect', 'ready'];
18
21
  class RedisCacheService {
19
- constructor(options, loggerService, cacheInstrumentation) {
22
+ constructor(options, loggerService, cacheInstrumentation, cacheMapper) {
20
23
  this.loggerService = loggerService;
21
24
  this.cacheInstrumentation = cacheInstrumentation;
22
- const { redis: redisOptions, entitlementsTimeout } = options;
25
+ this.cacheMapper = cacheMapper;
26
+ this.freshen = new EntitlementsFreshener_1.EntitlementsFreshener();
27
+ const { redis: redisOptions, entitlementsTimeout = redisCacheService_constants_1.DEFAULT_ENTITLEMENTS_TIMEOUT_MS, cacheUpdatePolicy = redisConfiguration_1.CacheUpdatePolicy.UPSERT, lockSettings, directExecution = false, } = options;
23
28
  const { environmentPrefix, ttl = redisCacheService_constants_1.DEFAULT_TTL_SECS, distributedEntitlementsFetching = {} } = redisOptions;
24
29
  this.redisClient = new ioredis_1.default(redisOptions);
25
- this.distributedLocks = new distributedLocks_1.DistributedLocks(this.redisClient, loggerService, cacheInstrumentation);
30
+ this.distributedLocks = new distributedLocks_1.DistributedLocks(this.redisClient, loggerService, cacheInstrumentation, lockSettings);
31
+ this.directExecution = directExecution;
32
+ this.cacheUpdatePolicy = cacheUpdatePolicy;
26
33
  this.environmentPrefix = environmentPrefix;
27
34
  this.ttl = ttl;
28
35
  this.redisClient.on('error', (err) => {
36
+ var _a, _b;
29
37
  this.loggerService.error('Redis client error: ', err);
30
- this.cacheInstrumentation.trackRedisClientError({ error: err, clientName: 'redis' });
38
+ (_b = (_a = this.cacheInstrumentation).trackRedisClientError) === null || _b === void 0 ? void 0 : _b.call(_a, { error: err, clientName: 'redis' });
31
39
  });
32
40
  this.redisClient.on('connect', () => {
33
41
  this.loggerService.log('Redis client connected!');
@@ -48,7 +56,12 @@ class RedisCacheService {
48
56
  */
49
57
  waitForInitialization() {
50
58
  return new Promise((resolve) => {
51
- // If already connected, resolve immediately
59
+ // for trigger connection for lazyConnect option
60
+ if (this.redisClient.status === 'wait') {
61
+ this.redisClient.connect().catch(() => {
62
+ /* no-op: errors are handled in the 'error' event listener */
63
+ });
64
+ }
52
65
  if (this.isClientConnected()) {
53
66
  resolve();
54
67
  return;
@@ -82,85 +95,106 @@ class RedisCacheService {
82
95
  isClientConnected() {
83
96
  return READY_STATUSES.includes(this.redisClient.status);
84
97
  }
85
- async updateFeatureUsage(params) {
86
- return this.executeSafely('updateFeatureUsage', false, async () => {
87
- const item = this.getFeatureUsageItemToUpdate(params);
98
+ async updateUsage({ customerId, resourceId, entitlementReference, usage, usageTimestamp, }) {
99
+ return this.executeSafely('updateUsage', undefined, async () => {
100
+ // Only update usage if the customer's entitlements exist in cache
101
+ const { customerKey } = (0, cacheKeysHelpers_1.buildRedisCustomerKey)(this.environmentPrefix, customerId, resourceId);
102
+ const customerExists = await this.keyExists(customerKey);
103
+ if (!customerExists) {
104
+ this.loggerService.debug(`Skipping usage update - customer entitlements not found in cache`, {
105
+ customerId,
106
+ resourceId,
107
+ entitlementReference,
108
+ });
109
+ return;
110
+ }
111
+ const item = this.getUsageItemToUpdate({
112
+ customerId,
113
+ resourceId,
114
+ entitlementReference,
115
+ usage,
116
+ usageTimestamp,
117
+ });
88
118
  await this.updateCacheItems([item]);
89
- return true;
90
119
  });
91
120
  }
92
- getFeatureUsageItemToUpdate({ featureId, currentUsage, customerId, usagePeriodStart, usagePeriodEnd, resourceId, timestamp, }) {
121
+ async keyExists(key) {
122
+ const result = await this.redisClient.exists(`${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`);
123
+ return result === 1;
124
+ }
125
+ getUsageItemToUpdate({ customerId, resourceId, entitlementReference, usage, usageTimestamp, }) {
126
+ const { currentUsage, usagePeriodStart, usagePeriodEnd } = usage;
93
127
  const value = {
94
128
  currentUsage,
95
129
  usagePeriodStart,
96
130
  usagePeriodEnd,
97
131
  };
98
132
  return {
99
- messageTimestamp: timestamp,
100
- key: (0, cacheKeysHelpers_1.buildRedisUsageKey)(this.environmentPrefix, customerId, featureId, resourceId),
133
+ messageTimestamp: usageTimestamp,
134
+ key: (0, cacheKeysHelpers_1.buildRedisUsageKey)(this.environmentPrefix, customerId, entitlementReference, resourceId),
101
135
  value,
102
136
  };
103
137
  }
104
- async setCustomer(customerId, customerEntitlements, accessDeniedReason, resourceId, entitlementsTimestamp, featureIdToUsageTimestamp) {
105
- return this.executeSafely('setCustomer', undefined, async () => {
138
+ async setCustomer({ customerId, resourceId, entitlements: entitlementsInput, accessDeniedReason, entitlementsTimestamp, }) {
139
+ const { entitlements, usageUpdatedAtMap } = entities_1.EntitlementsMap.fromInput(this.cacheMapper, entitlementsInput);
140
+ const freshenedEntitlements = this.freshen.transform(entitlements);
141
+ return this.executeSafely('setCustomer', freshenedEntitlements, async () => {
142
+ const { customerKey, metadataKey } = (0, cacheKeysHelpers_1.buildRedisCustomerKey)(this.environmentPrefix, customerId, resourceId);
106
143
  const lockKey = (0, cacheKeysHelpers_1.buildLockKey)(this.environmentPrefix, customerId, resourceId);
107
144
  await this.distributedLocks.using(lockKey, async () => {
108
- const { customerKey, metadataKey } = (0, cacheKeysHelpers_1.buildRedisCustomerKey)(this.environmentPrefix, customerId, resourceId);
109
145
  const entitlementsItem = {
110
146
  messageTimestamp: new Date(entitlementsTimestamp),
111
147
  key: customerKey,
112
- value: Object.fromEntries(customerEntitlements),
148
+ value: entitlements.toJSON(),
149
+ };
150
+ const metadata = {
151
+ accessDeniedReason: (0, accessDeniedReasonMapper_1.mapAccessDeniedReason)(accessDeniedReason),
113
152
  };
114
- const metadata = { accessDeniedReason };
115
153
  const metadataItem = {
116
154
  messageTimestamp: new Date(entitlementsTimestamp),
117
155
  key: metadataKey,
118
156
  value: metadata,
119
157
  };
120
- const featureUsagesItems = this.extractFeatureUsagesToUpdate({
158
+ const usagesItems = this.extractUsagesToUpdate({
121
159
  customerId,
122
160
  resourceId,
123
- customerEntitlements,
124
- featureIdToUsageTimestamp,
161
+ entitlements,
162
+ usageUpdatedAtMap,
125
163
  });
126
- await this.updateCacheItems([entitlementsItem, metadataItem, ...featureUsagesItems]);
164
+ await this.updateCacheItems([entitlementsItem, metadataItem, ...usagesItems]);
127
165
  });
166
+ return freshenedEntitlements;
128
167
  });
129
168
  }
130
- extractFeatureUsagesToUpdate({ customerId, resourceId, customerEntitlements, featureIdToUsageTimestamp, }) {
131
- return (0, lodash_1.compact)(new Array(...customerEntitlements.values())
132
- .filter(({ calculatedEntitlement }) => (0, featureTypes_1.isMetered)(calculatedEntitlement.feature))
169
+ extractUsagesToUpdate({ customerId, resourceId, entitlements, usageUpdatedAtMap, }) {
170
+ return (0, lodash_1.compact)(entitlements
171
+ .values()
172
+ .filter((entitlement) => entitlement.isUsageTrackable())
133
173
  .map((entitlement) => {
134
- const { calculatedEntitlement: { feature }, featureUsage: { currentUsage, usagePeriodStart, usagePeriodEnd }, } = entitlement;
135
- if ((0, lodash_1.isEmpty)(feature === null || feature === void 0 ? void 0 : feature.id)) {
136
- this.loggerService.error(`entitlement without feature id`, {
137
- customerId,
138
- resourceId,
139
- });
140
- return;
141
- }
142
- const featureId = feature.id;
143
- const featureUsageTimestamp = featureIdToUsageTimestamp.get(featureId);
144
- if (!featureUsageTimestamp) {
145
- this.loggerService.error(`Usage timestamp for feature is missing`, {
146
- customerId,
147
- resourceId,
148
- featureId,
149
- });
150
- return;
151
- }
152
- return this.getFeatureUsageItemToUpdate({
174
+ const entitlementReference = entitlement.getEntitlementQuery();
175
+ const usageTimestamp = this.getUsageTimestamp(usageUpdatedAtMap, entitlementReference);
176
+ return this.getUsageItemToUpdate({
153
177
  customerId,
154
178
  resourceId,
155
- featureId,
156
- currentUsage,
157
- usagePeriodStart,
158
- usagePeriodEnd,
159
- timestamp: new Date(featureUsageTimestamp),
179
+ entitlementReference,
180
+ usage: entitlement.usageData,
181
+ usageTimestamp,
160
182
  });
161
183
  }));
162
184
  }
185
+ getUsageTimestamp(usageUpdatedAtMap, entitlementReference) {
186
+ const key = entities_1.EntitlementsMap.getUniqueKey(entitlementReference);
187
+ const usageTimestamp = usageUpdatedAtMap.get(key);
188
+ if (!usageTimestamp) {
189
+ this.loggerService.error('Usage timestamp not found for entitlement, using current time', {
190
+ entitlementReference,
191
+ });
192
+ return new Date();
193
+ }
194
+ return usageTimestamp;
195
+ }
163
196
  async getCustomerEntitlementsWithoutUsage(customerId, resourceId) {
197
+ var _a, _b, _c, _d;
164
198
  const { customerKey, metadataKey } = (0, cacheKeysHelpers_1.buildRedisCustomerKey)(this.environmentPrefix, customerId, resourceId);
165
199
  const keysToFetch = [customerKey, metadataKey];
166
200
  if (resourceId) {
@@ -170,7 +204,7 @@ class RedisCacheService {
170
204
  }
171
205
  const [entitlementsRaw, metadataValue, entitlementsTimestampValue, globalEntitlementsTimestampValue] = await this.redisClient.mget(keysToFetch);
172
206
  const entitlements = !(0, lodash_1.isNil)(entitlementsRaw) && !(0, lodash_1.isEmpty)(entitlementsRaw)
173
- ? new Map(Object.entries(JSON.parse(entitlementsRaw)))
207
+ ? entities_1.EntitlementsMap.fromJSON(this.migrateOldCacheFormat(JSON.parse(entitlementsRaw)))
174
208
  : null;
175
209
  let accessDeniedReason = null;
176
210
  if (!(0, lodash_1.isNil)(metadataValue) && !(0, lodash_1.isEmpty)(metadataValue)) {
@@ -181,12 +215,12 @@ class RedisCacheService {
181
215
  const globalEntitlementsTimestamp = this.parseTimestamp(globalEntitlementsTimestampValue);
182
216
  const globalCustomerMissing = this.isGlobalCustomerMissingInCache(customerId, resourceId, entitlements, entitlementsTimestamp, globalEntitlementsTimestamp);
183
217
  if (!entitlements || globalCustomerMissing) {
184
- this.cacheInstrumentation.trackMiss({ customerId, resourceId, globalCustomerMissing });
185
- return entitlementsService_utils_1.entitlementsResponseMapper.cacheMiss(globalCustomerMissing);
218
+ (_b = (_a = this.cacheInstrumentation).trackMiss) === null || _b === void 0 ? void 0 : _b.call(_a, { customerId, resourceId, globalCustomerMissing });
219
+ return cacheResponse_1.entitlementsResponseMapper.cacheMiss(globalCustomerMissing);
186
220
  }
187
221
  this.loggerService.debug(`Found entitlements in persisted cache for customer`, { customerId, resourceId });
188
- this.cacheInstrumentation.trackHit({ customerId, resourceId });
189
- return entitlementsService_utils_1.entitlementsResponseMapper.cacheHit(entitlements, accessDeniedReason);
222
+ (_d = (_c = this.cacheInstrumentation).trackHit) === null || _d === void 0 ? void 0 : _d.call(_c, { customerId, resourceId });
223
+ return cacheResponse_1.entitlementsResponseMapper.cacheHit(entitlements, accessDeniedReason);
190
224
  }
191
225
  // resource entitlements are affected by global entitlements, so if global
192
226
  // entitlements are missing or newer, we should refetch since the cache is stale
@@ -211,95 +245,140 @@ class RedisCacheService {
211
245
  });
212
246
  return true;
213
247
  }
214
- async getCustomerEntitlements(customerId, resourceId) {
215
- return this.executeSafely('getCustomerEntitlements', entitlementsService_utils_1.entitlementsResponseMapper.cacheMiss(), async () => {
248
+ async getCustomerEntitlements(params) {
249
+ return this.getCached('getCustomerEntitlements', params);
250
+ }
251
+ async getCached(operationName, { customerId, resourceId }, extract) {
252
+ return this.executeSafely(operationName, cacheResponse_1.entitlementsResponseMapper.cacheMiss(), async () => {
253
+ var _a, _b, _c, _d;
216
254
  const response = await this.getCustomerEntitlementsWithoutUsage(customerId, resourceId);
217
255
  if (response.cacheMiss) {
218
256
  return response;
219
257
  }
220
- const { entitlements, accessDeniedReason } = response;
221
- const meteredFeatureIds = Array.from(entitlements.values())
222
- .filter(({ calculatedEntitlement }) => (0, featureTypes_1.isMetered)(calculatedEntitlement.feature))
223
- .map(({ calculatedEntitlement }) => calculatedEntitlement.feature.id);
224
- if (!(0, lodash_1.isEmpty)(meteredFeatureIds)) {
225
- const featuresUsageByFeatureKey = await this.getFeaturesUsage(this.environmentPrefix, customerId, resourceId, meteredFeatureIds);
226
- const foundFeatureIds = Array.from(featuresUsageByFeatureKey.keys());
227
- const missingFeatureIds = (0, lodash_1.difference)(meteredFeatureIds, foundFeatureIds);
228
- if (!(0, lodash_1.isEmpty)(missingFeatureIds)) {
229
- this.loggerService.error(`Failed to find metered features usage - considering it as cache miss`, {
258
+ const { entitlements: entitlementsWithoutUsage, accessDeniedReason } = response;
259
+ const extracted = extract ? extract.transform(entitlementsWithoutUsage) : entitlementsWithoutUsage;
260
+ const withUsage = await this.fetchAndMergeUsage(customerId, resourceId, extracted);
261
+ if (!withUsage) {
262
+ (_b = (_a = this.cacheInstrumentation).trackMiss) === null || _b === void 0 ? void 0 : _b.call(_a, { customerId, resourceId });
263
+ return cacheResponse_1.entitlementsResponseMapper.cacheMiss();
264
+ }
265
+ const entitlements = this.freshen.transform(withUsage);
266
+ (_d = (_c = this.cacheInstrumentation).trackHit) === null || _d === void 0 ? void 0 : _d.call(_c, { customerId, resourceId });
267
+ return cacheResponse_1.entitlementsResponseMapper.cacheHit(entitlements, accessDeniedReason);
268
+ });
269
+ }
270
+ /**
271
+ * Fetches usage for all trackable entitlements and merges it into the map.
272
+ * Returns null if any trackable entitlement is missing usage (cache miss).
273
+ */
274
+ async fetchAndMergeUsage(customerId, resourceId, entitlements) {
275
+ const usageTrackableRefs = entitlements
276
+ .values()
277
+ .filter((ent) => ent.isUsageTrackable())
278
+ .map((ent) => ent.getEntitlementQuery());
279
+ if (!(0, lodash_1.isEmpty)(usageTrackableRefs)) {
280
+ const usageByKey = await this.getUsages(this.environmentPrefix, customerId, resourceId, usageTrackableRefs);
281
+ const missingRefs = usageTrackableRefs.filter((ref) => !usageByKey.has(entities_1.EntitlementsMap.getUniqueKey(ref)));
282
+ if (!(0, lodash_1.isEmpty)(missingRefs)) {
283
+ this.loggerService.error(`Failed to find usage - considering it as cache miss`, {
284
+ customerId,
285
+ resourceId,
286
+ missingRefs,
287
+ });
288
+ return null;
289
+ }
290
+ usageTrackableRefs.forEach((entitlementRef) => {
291
+ const usageValue = usageByKey.get(entities_1.EntitlementsMap.getUniqueKey(entitlementRef));
292
+ if (!usageValue) {
293
+ return;
294
+ }
295
+ const cachedEntitlement = entitlements.get(entitlementRef);
296
+ if (cachedEntitlement) {
297
+ entitlements.set(this.mergeEntitlementWithUsage(cachedEntitlement, usageValue));
298
+ }
299
+ else {
300
+ this.loggerService.log(`Found usage for an entitlement the customer is not entitled to.`, {
230
301
  customerId,
231
- resourceId,
232
- missingFeatureIds,
302
+ entitlementRef,
233
303
  });
234
- this.cacheInstrumentation.trackMiss({ customerId, resourceId });
235
- return entitlementsService_utils_1.entitlementsResponseMapper.cacheMiss();
236
304
  }
237
- featuresUsageByFeatureKey.forEach((usageValue, featureKey) => {
238
- const cachedEntitlement = entitlements.get(featureKey);
239
- if (cachedEntitlement) {
240
- entitlements.set(featureKey, this.mergeEntitlementWithUsage(cachedEntitlement, usageValue));
241
- }
242
- else {
243
- this.loggerService.log(`Found usage for a feature the customer is not entitled to.`, {
244
- customerId,
245
- featureKey,
246
- });
247
- }
248
- });
249
- }
250
- this.cacheInstrumentation.trackHit({ customerId, resourceId });
251
- return entitlementsService_utils_1.entitlementsResponseMapper.cacheHit(entitlements, accessDeniedReason);
252
- });
305
+ });
306
+ }
307
+ return entitlements;
253
308
  }
254
- async getFeaturesUsage(environmentPrefix, customerId, resourceId, meteredFeatureIds) {
255
- const keysToFetch = meteredFeatureIds.map((featureId) => (0, cacheKeysHelpers_1.buildRedisUsageKey)(environmentPrefix, customerId, featureId, resourceId));
309
+ async getUsages(environmentPrefix, customerId, resourceId, entitlementReferences) {
310
+ const keysToFetch = entitlementReferences.map((ref) => (0, cacheKeysHelpers_1.buildRedisUsageKey)(environmentPrefix, customerId, ref, resourceId));
256
311
  const usageValues = await this.redisClient.mget(keysToFetch);
257
- const featureIdToFeatureUsage = new Map();
312
+ const usageByEntitlementKey = new Map();
258
313
  // Redis guarantees returning values in the same order of the keys so this is legit!
259
- meteredFeatureIds.forEach((featureId, index) => {
260
- const featureUsageValue = usageValues[index];
261
- if (featureUsageValue === null) {
262
- this.loggerService.log(`Failed to find usage for metered feature: ${featureId}`);
314
+ entitlementReferences.forEach((ref, index) => {
315
+ const usageValue = usageValues[index];
316
+ if (usageValue === null) {
317
+ this.loggerService.log(`Failed to find usage for entitlement: ${ref.type}:${ref.id}`);
263
318
  return;
264
319
  }
265
- featureIdToFeatureUsage.set(featureId, JSON.parse(featureUsageValue));
320
+ usageByEntitlementKey.set(entities_1.EntitlementsMap.getUniqueKey(ref), this.migrateUsageData(JSON.parse(usageValue)));
266
321
  });
267
- return featureIdToFeatureUsage;
322
+ return usageByEntitlementKey;
268
323
  }
269
324
  clearCache() {
270
325
  return;
271
326
  }
272
327
  async updateCacheItems(items) {
328
+ var _a, _b, _c, _d;
273
329
  if ((0, lodash_1.isEmpty)(items)) {
274
330
  return;
275
331
  }
276
- const latestTimestampByKey = await this.getKeysLatestTimestamp(items.map((item) => item.key));
277
- const itemsToUpdate = [];
278
- items.forEach(({ messageTimestamp, key, value }) => {
279
- const latestTimestamp = latestTimestampByKey.get(key);
280
- if (!latestTimestamp ||
281
- messageTimestamp.getTime() === entitlementsService_utils_1.DATE_IN_FAR_PAST.getTime() ||
282
- latestTimestamp.getTime() <= messageTimestamp.getTime()) {
283
- const writeableValue = typeof value === 'string' ? value : JSON.stringify(value);
284
- itemsToUpdate.push({ key, value: writeableValue });
285
- itemsToUpdate.push({ key: `${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`, value: messageTimestamp.getTime() });
286
- }
287
- else {
288
- this.loggerService.log('Cache data timestamp is after message timestamp, skipping key update', {
289
- messageTimestamp,
290
- latestTimestamp,
291
- key,
332
+ const startTime = Date.now();
333
+ try {
334
+ const latestTimestampByKey = await this.getKeysLatestTimestamp(items.map((item) => item.key));
335
+ // Check if we should skip writing based on cache policy
336
+ if (this.shouldSkipWriting(items, latestTimestampByKey)) {
337
+ this.loggerService.log(`Cache data does not exist - skipping according to cache policy (${this.cacheUpdatePolicy})`, {
338
+ keys: items.map((item) => item.key),
292
339
  });
340
+ return;
293
341
  }
294
- });
295
- if ((0, lodash_1.isEmpty)(itemsToUpdate)) {
296
- return;
342
+ const itemsToUpdate = [];
343
+ items.forEach(({ messageTimestamp, key, value }) => {
344
+ const latestTimestamp = latestTimestampByKey.get(key);
345
+ if (!latestTimestamp ||
346
+ messageTimestamp.getTime() === cacheResponse_1.DATE_IN_FAR_PAST.getTime() ||
347
+ latestTimestamp.getTime() <= messageTimestamp.getTime()) {
348
+ const writeableValue = typeof value === 'string' ? value : JSON.stringify(value);
349
+ itemsToUpdate.push({ key, value: writeableValue });
350
+ itemsToUpdate.push({ key: `${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`, value: messageTimestamp.getTime() });
351
+ }
352
+ else {
353
+ this.loggerService.log('Cache data timestamp is after message timestamp, skipping key update', {
354
+ messageTimestamp,
355
+ latestTimestamp,
356
+ key,
357
+ });
358
+ }
359
+ });
360
+ if ((0, lodash_1.isEmpty)(itemsToUpdate)) {
361
+ return;
362
+ }
363
+ const batch = this.redisClient.multi();
364
+ itemsToUpdate.forEach(({ key, value }) => {
365
+ batch.set(key, value, 'EX', this.ttl);
366
+ });
367
+ await batch.exec();
368
+ // Track write duration
369
+ const durationSeconds = (Date.now() - startTime) / 1000;
370
+ (_b = (_a = this.cacheInstrumentation).trackWriteDuration) === null || _b === void 0 ? void 0 : _b.call(_a, 'updateCacheItems', durationSeconds);
297
371
  }
298
- const batch = this.redisClient.multi();
299
- itemsToUpdate.forEach(({ key, value }) => {
300
- batch.set(key, value, 'EX', this.ttl);
301
- });
302
- await batch.exec();
372
+ catch (error) {
373
+ (_d = (_c = this.cacheInstrumentation).trackWriteError) === null || _d === void 0 ? void 0 : _d.call(_c, 'updateCacheItems');
374
+ throw error;
375
+ }
376
+ }
377
+ shouldSkipWriting(items, latestTimestampByKey) {
378
+ if (this.cacheUpdatePolicy === redisConfiguration_1.CacheUpdatePolicy.UPSERT) {
379
+ return false;
380
+ }
381
+ return !items.some(({ key }) => latestTimestampByKey.get(key) !== undefined);
303
382
  }
304
383
  async getKeysLatestTimestamp(keys) {
305
384
  const timestampKeys = keys.map((key) => `${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`);
@@ -325,50 +404,104 @@ class RedisCacheService {
325
404
  await this.distributedLocks.cleanup();
326
405
  await ((_a = this.distributedRefetchEntitlementsService) === null || _a === void 0 ? void 0 : _a.cleanup());
327
406
  }
328
- async getCustomerEntitlement(featureId, customerId, resourceId) {
329
- return this.executeSafely('getCustomerEntitlement', {
330
- cacheMiss: true,
331
- accessDeniedReason: undefined,
332
- entitlement: null,
333
- globalCustomerMissing: false,
334
- }, async () => {
335
- const { entitlements, accessDeniedReason, cacheMiss, globalCustomerMissing } = await this.getCustomerEntitlementsWithoutUsage(customerId, resourceId);
336
- const entitlement = !cacheMiss ? (entitlements === null || entitlements === void 0 ? void 0 : entitlements.get(featureId)) || null : null;
337
- const result = { cacheMiss, accessDeniedReason, entitlement, globalCustomerMissing };
338
- if (!entitlement || !(0, featureTypes_1.isMetered)(entitlement === null || entitlement === void 0 ? void 0 : entitlement.calculatedEntitlement.feature)) {
339
- return result;
340
- }
341
- const featuresUsageByFeatureKey = await this.getFeaturesUsage(this.environmentPrefix, customerId, resourceId, [
342
- featureId,
343
- ]);
344
- const cachedFeatureUsage = featuresUsageByFeatureKey.get(featureId);
345
- if ((0, lodash_1.isNil)(cachedFeatureUsage)) {
346
- this.loggerService.error('Failed to find metered feature usage - considering it as cache miss', {
347
- customerId,
348
- resourceId,
349
- featureId,
407
+ async purge(customers) {
408
+ const customersArray = Array.isArray(customers) ? customers : [customers];
409
+ return this.executeSafely('purge', undefined, async () => {
410
+ for (const customerChunk of (0, lodash_1.chunk)(customersArray, RedisCacheService.DELETE_CHUNK_SIZE)) {
411
+ const keysToDelete = customerChunk.flatMap(({ customerId, resourceId }) => {
412
+ this.loggerService.log(`Invalidating entitlements cache`, { customerId, resourceId });
413
+ const { customerKey, metadataKey } = (0, cacheKeysHelpers_1.buildRedisCustomerKey)(this.environmentPrefix, customerId, resourceId);
414
+ return [customerKey, `${customerKey}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`, metadataKey, `${metadataKey}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`];
350
415
  });
351
- return {
352
- cacheMiss: true,
353
- accessDeniedReason: undefined,
354
- entitlement: null,
355
- globalCustomerMissing: false,
356
- };
416
+ await this.redisClient.del(keysToDelete);
357
417
  }
358
- return Object.assign(Object.assign({}, result), { entitlement: this.mergeEntitlementWithUsage(entitlement, cachedFeatureUsage) });
359
418
  });
360
419
  }
420
+ async getCustomerEntitlement(params) {
421
+ const { query } = params;
422
+ const extractor = new extractWithDependencies_1.ExtractWithDependencies(query);
423
+ const { entitlements, accessDeniedReason, cacheMiss, globalCustomerMissing } = await this.getCached('getCustomerEntitlement', params, extractor);
424
+ const entitlement = !cacheMiss ? (entitlements === null || entitlements === void 0 ? void 0 : entitlements.get(query)) || null : null;
425
+ return { cacheMiss, accessDeniedReason, entitlement, globalCustomerMissing };
426
+ }
361
427
  mergeEntitlementWithUsage(entitlement, cachedUsage) {
362
- const { calculatedEntitlement, featureUsage } = entitlement;
363
- // backwards compatibility for old items that have nextResetDate instead of usagePeriodEnd
364
- if (!(0, lodash_1.isNil)(cachedUsage.nextResetDate) && (0, lodash_1.isNil)(cachedUsage.usagePeriodEnd)) {
365
- cachedUsage = (0, lodash_1.merge)((0, lodash_1.omit)(cachedUsage, 'nextResetDate'), {
366
- usagePeriodEnd: cachedUsage.nextResetDate,
367
- });
428
+ return new entities_1.CachedEntitlement(entitlement.calculatedEntitlement, cachedUsage);
429
+ }
430
+ /**
431
+ * Returns Redis server info for the specified section (e.g., 'memory', 'stats').
432
+ * Throws if the client is not connected.
433
+ */
434
+ async getServerInfo(section) {
435
+ if (!this.isClientConnected()) {
436
+ throw new Error('Redis client is not connected');
437
+ }
438
+ return this.redisClient.info(section);
439
+ }
440
+ /**
441
+ * Migrates old cache format to new format.
442
+ * Handles: featureUsage→usageData rename, adds type discriminator, moves fields,
443
+ * adds updatedAt, adds displayName fallback, nextResetDate→usagePeriodEnd.
444
+ */
445
+ migrateOldCacheFormat(cacheData) {
446
+ for (const [key, value] of Object.entries(cacheData)) {
447
+ const entry = value;
448
+ if (!(entry === null || entry === void 0 ? void 0 : entry.calculatedEntitlement))
449
+ continue;
450
+ // 1. Rename featureUsage → usageData
451
+ if (entry.featureUsage && !entry.usageData) {
452
+ entry.usageData = entry.featureUsage;
453
+ delete entry.featureUsage;
454
+ }
455
+ // 2. Add type discriminator if missing (old cache only had Feature entitlements)
456
+ if (!entry.calculatedEntitlement.type) {
457
+ // Skip malformed entries that don't have a feature object - they can't be valid Feature entitlements
458
+ if (!entry.calculatedEntitlement.feature) {
459
+ delete cacheData[key];
460
+ continue;
461
+ }
462
+ entry.calculatedEntitlement.type = entities_1.EntitlementType.Feature;
463
+ }
464
+ // 3. Move fields from usageData to calculatedEntitlement (for Feature type)
465
+ if (entry.usageData && entry.calculatedEntitlement.type === entities_1.EntitlementType.Feature) {
466
+ const fieldsToMove = ['usagePeriodAnchor', 'resetPeriod', 'resetPeriodConfiguration'];
467
+ for (const field of fieldsToMove) {
468
+ if (entry.usageData[field] !== undefined && entry.calculatedEntitlement[field] === undefined) {
469
+ entry.calculatedEntitlement[field] = entry.usageData[field];
470
+ delete entry.usageData[field];
471
+ }
472
+ }
473
+ }
474
+ // 4. Add updatedAt if missing
475
+ if (entry.usageData && !entry.usageData.updatedAt) {
476
+ entry.usageData.updatedAt = Date.now();
477
+ }
478
+ // 5. Add displayName fallback if missing
479
+ if (entry.calculatedEntitlement.feature && !entry.calculatedEntitlement.feature.displayName) {
480
+ entry.calculatedEntitlement.feature.displayName = entry.calculatedEntitlement.feature.id;
481
+ }
482
+ // 6. Migrate usageData (nextResetDate → usagePeriodEnd)
483
+ if (entry.usageData) {
484
+ entry.usageData = this.migrateUsageData(entry.usageData);
485
+ }
486
+ cacheData[key] = entry;
368
487
  }
369
- return new cachedEntitlement_1.default(calculatedEntitlement, Object.assign(Object.assign({}, featureUsage), cachedUsage));
488
+ return cacheData;
489
+ }
490
+ /**
491
+ * Migrates old usage data format.
492
+ * Handles backward compatibility for old items that have nextResetDate instead of usagePeriodEnd.
493
+ */
494
+ migrateUsageData(usageData) {
495
+ if (!(0, lodash_1.isNil)(usageData.nextResetDate) && (0, lodash_1.isNil)(usageData.usagePeriodEnd)) {
496
+ return Object.assign(Object.assign({}, (0, lodash_1.omit)(usageData, 'nextResetDate')), { usagePeriodEnd: usageData.nextResetDate });
497
+ }
498
+ return usageData;
370
499
  }
371
500
  async executeSafely(operationName, defaultValue, operation) {
501
+ // When directExecution is enabled, run operations directly without safety wrapper
502
+ if (this.directExecution) {
503
+ return operation();
504
+ }
372
505
  if (!this.isClientConnected()) {
373
506
  return defaultValue;
374
507
  }
@@ -382,4 +515,5 @@ class RedisCacheService {
382
515
  }
383
516
  }
384
517
  exports.RedisCacheService = RedisCacheService;
385
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkaXNDYWNoZVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvY2FjaGUvcmVkaXNDYWNoZVNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0EsNEVBQXNFO0FBQ3RFLHNEQUE0QjtBQUM1QixtQ0FBb0Y7QUFHcEYsbUVBQXVHO0FBQ3ZHLCtFQUE0RTtBQUM1RSw0RUFLc0M7QUFDdEMsK0VBT3VDO0FBQ3ZDLDJEQUFxRDtBQUVyRCwrREFBNEQ7QUFrQjVELE1BQU0sd0JBQXdCLEdBQUcsR0FBRyxDQUFDO0FBRXJDLE1BQU0sY0FBYyxHQUFhLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBRXRELE1BQWEsaUJBQWlCO0lBUTVCLFlBQ0UsT0FBc0MsRUFDckIsYUFBNEIsRUFDNUIsb0JBQTBDO1FBRDFDLGtCQUFhLEdBQWIsYUFBYSxDQUFlO1FBQzVCLHlCQUFvQixHQUFwQixvQkFBb0IsQ0FBc0I7UUFFM0QsTUFBTSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsbUJBQW1CLEVBQUUsR0FBRyxPQUFPLENBQUM7UUFDN0QsTUFBTSxFQUFFLGlCQUFpQixFQUFFLEdBQUcsR0FBRyw4Q0FBZ0IsRUFBRSwrQkFBK0IsR0FBRyxFQUFFLEVBQUUsR0FBRyxZQUFZLENBQUM7UUFFekcsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLGlCQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksbUNBQWdCLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxhQUFhLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztRQUNwRyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsaUJBQWlCLENBQUM7UUFDM0MsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFFZixJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFH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
518
+ RedisCacheService.DELETE_CHUNK_SIZE = 1000;
519
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkaXNDYWNoZVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvY2FjaGUvcmVkaXNDYWNoZVNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBUUEseUNBQThHO0FBRTlHLHNEQUE0QjtBQUM1QixtQ0FBd0U7QUFFeEUsbUVBQXdGO0FBQ3hGLHlEQUE2RjtBQUM3RiwrRUFBNEU7QUFDNUUseURBSytCO0FBQy9CLHVFQUFvRTtBQUVwRSw2RUFBMEU7QUFDMUUsK0VBTXVDO0FBQ3ZDLCtEQUE0RDtBQUc1RCx5RUFBbUU7QUFpQm5FLE1BQU0sd0JBQXdCLEdBQUcsR0FBRyxDQUFDO0FBRXJDLE1BQU0sY0FBYyxHQUFhLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBRXRELE1BQWEsaUJBQWlCO0lBYTVCLFlBQ0UsT0FBZ0MsRUFDZixhQUF5QixFQUN6QixvQkFBMEMsRUFDMUMsV0FBK0I7UUFGL0Isa0JBQWEsR0FBYixhQUFhLENBQVk7UUFDekIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtRQUMxQyxnQkFBVyxHQUFYLFdBQVcsQ0FBb0I7UUFSakMsWUFBTyxHQUFHLElBQUksNkNBQXFCLEVBQUUsQ0FBQztRQVVyRCxNQUFNLEVBQ0osS0FBSyxFQUFFLFlBQVksRUFDbkIsbUJBQW1CLEdBQUcsNkRBQStCLEVBQ3JELGlCQUFpQixHQUFHLHNDQUFpQixDQUFDLE1BQU0sRUFDNUMsWUFBWSxFQUNaLGVBQWUsR0FBRyxLQUFLLEdBQ3hCLEdBQUcsT0FBTyxDQUFDO1FBQ1osTUFBTSxFQUFFLGlCQUFpQixFQUFFLEdBQUcsR0FBRyw4Q0FBZ0IsRUFBRSwrQkFBK0IsR0FBRyxFQUFFLEVBQUUsR0FBRyxZQUFZLENBQUM7UUFFekcsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLGlCQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLGdCQUFnQixHQUFH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