@stigg/node-server-sdk 4.11.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 (84) hide show
  1. package/dist/api/entitlements/entitlementsApi.d.ts +1 -2
  2. package/dist/api/entitlements/entitlementsApi.js +1 -6
  3. package/dist/clientInitialization.js +8 -7
  4. package/dist/configuration.d.ts +2 -21
  5. package/dist/configuration.js +1 -1
  6. package/dist/models.d.ts +4 -14
  7. package/dist/models.js +1 -1
  8. package/dist/services/ApiCacheMapper.d.ts +15 -0
  9. package/dist/services/ApiCacheMapper.js +96 -0
  10. package/dist/services/LegacyEventPayloadMapper.d.ts +1 -1
  11. package/dist/services/LegacyEventPayloadMapper.js +1 -3
  12. package/dist/services/cache/CacheMapper.d.ts +16 -0
  13. package/dist/services/cache/CacheMapper.js +3 -0
  14. package/dist/services/cache/RedisSingleExecutionService/RedisSingleExecution.d.ts +3 -3
  15. package/dist/services/cache/RedisSingleExecutionService/RedisSingleExecution.js +4 -3
  16. package/dist/services/cache/accessDeniedReasonMapper.d.ts +3 -0
  17. package/dist/services/cache/accessDeniedReasonMapper.js +16 -0
  18. package/dist/{utils → services/cache}/cacheKeysHelpers.d.ts +3 -2
  19. package/dist/services/cache/cacheKeysHelpers.js +55 -0
  20. package/dist/services/cache/cacheService.d.ts +10 -25
  21. package/dist/services/cache/entities/cachedEntitlement.d.ts +5 -2
  22. package/dist/services/cache/entities/cachedEntitlement.js +32 -7
  23. package/dist/services/cache/entities/calculatedEntitlement.d.ts +16 -15
  24. package/dist/services/cache/entities/entitlementsMap.d.ts +15 -4
  25. package/dist/services/cache/entities/entitlementsMap.js +34 -24
  26. package/dist/services/cache/entities/index.d.ts +1 -1
  27. package/dist/services/cache/entities/index.js +2 -3
  28. package/dist/services/cache/entities/usageData.d.ts +8 -4
  29. package/dist/services/cache/entities/usageData.js +7 -1
  30. package/dist/services/cache/extractWithDependencies.d.ts +12 -0
  31. package/dist/services/cache/extractWithDependencies.js +37 -0
  32. package/dist/services/cache/freshness/EntitlementsFreshener.d.ts +11 -0
  33. package/dist/services/cache/freshness/EntitlementsFreshener.js +27 -0
  34. package/dist/services/cache/freshness/transformers/CreditAccessPropagator.d.ts +15 -0
  35. package/dist/services/cache/freshness/transformers/CreditAccessPropagator.js +67 -0
  36. package/dist/services/cache/freshness/transformers/UsagePeriodReset.d.ts +11 -0
  37. package/dist/services/cache/freshness/transformers/UsagePeriodReset.js +45 -0
  38. package/dist/services/cache/inMemoryCacheService.d.ts +18 -13
  39. package/dist/services/cache/inMemoryCacheService.js +41 -57
  40. package/dist/services/cache/index.d.ts +13 -0
  41. package/dist/services/cache/index.js +38 -0
  42. package/dist/services/cache/redis/distributedLocks.d.ts +4 -3
  43. package/dist/services/cache/redis/distributedLocks.js +5 -4
  44. package/dist/services/cache/redisCacheService.constants.d.ts +1 -1
  45. package/dist/services/cache/redisCacheService.constants.js +3 -3
  46. package/dist/services/cache/redisCacheService.d.ts +43 -17
  47. package/dist/services/cache/redisCacheService.js +233 -169
  48. package/dist/services/cache/types/cacheInstrumentation.d.ts +37 -0
  49. package/dist/services/cache/types/cacheInstrumentation.js +3 -0
  50. package/dist/services/cache/types/cacheResponse.d.ts +26 -0
  51. package/dist/services/cache/types/cacheResponse.js +19 -0
  52. package/dist/services/cache/types/cacheServiceParams.d.ts +20 -0
  53. package/dist/services/cache/types/cacheServiceParams.js +3 -0
  54. package/dist/services/cache/types/entitlementFeature.d.ts +19 -0
  55. package/dist/services/cache/types/entitlementFeature.js +3 -0
  56. package/dist/services/cache/types/entitlementsMapTransformer.d.ts +4 -0
  57. package/dist/services/cache/types/entitlementsMapTransformer.js +3 -0
  58. package/dist/services/cache/types/logger.d.ts +6 -0
  59. package/dist/services/cache/types/logger.js +3 -0
  60. package/dist/services/cache/types/redisConfiguration.d.ts +39 -0
  61. package/dist/services/cache/types/redisConfiguration.js +14 -0
  62. package/dist/services/entitlementDecisionService.d.ts +1 -1
  63. package/dist/services/entitlementDecisionService.js +5 -5
  64. package/dist/services/entitlementsService.d.ts +21 -19
  65. package/dist/services/entitlementsService.js +57 -91
  66. package/dist/services/entitlementsService.utils.d.ts +0 -26
  67. package/dist/services/entitlementsService.utils.js +1 -17
  68. package/dist/services/eventEmitter.d.ts +1 -1
  69. package/dist/services/eventEmitterCacheInstrumentation.d.ts +9 -0
  70. package/dist/services/eventEmitterCacheInstrumentation.js +19 -0
  71. package/dist/services/inMemoryEntitlementsService.d.ts +5 -6
  72. package/dist/services/inMemoryEntitlementsService.js +36 -53
  73. package/dist/services/redisEntitlementsService.d.ts +5 -4
  74. package/dist/services/redisEntitlementsService.js +2 -2
  75. package/dist/types.d.ts +1 -0
  76. package/dist/utils/ModelMapper.d.ts +1 -1
  77. package/dist/{services/cache → utils}/calculateUsagePeriod.js +1 -1
  78. package/package.json +18 -1
  79. package/dist/services/cacheInstrumentation.d.ts +0 -18
  80. package/dist/services/cacheInstrumentation.js +0 -19
  81. package/dist/utils/CacheMapper.d.ts +0 -13
  82. package/dist/utils/CacheMapper.js +0 -95
  83. package/dist/utils/cacheKeysHelpers.js +0 -42
  84. /package/dist/{services/cache → utils}/calculateUsagePeriod.d.ts +0 -0
@@ -7,26 +7,35 @@ exports.RedisCacheService = void 0;
7
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
17
  const distributedLocks_1 = require("./redis/distributedLocks");
18
+ const accessDeniedReasonMapper_1 = require("./accessDeniedReasonMapper");
15
19
  const GRACE_CONNECT_TIMEOUT_MS = 250;
16
20
  const READY_STATUSES = ['connect', 'ready'];
17
21
  class RedisCacheService {
18
- constructor(options, loggerService, cacheInstrumentation) {
22
+ constructor(options, loggerService, cacheInstrumentation, cacheMapper) {
19
23
  this.loggerService = loggerService;
20
24
  this.cacheInstrumentation = cacheInstrumentation;
21
- 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;
22
28
  const { environmentPrefix, ttl = redisCacheService_constants_1.DEFAULT_TTL_SECS, distributedEntitlementsFetching = {} } = redisOptions;
23
29
  this.redisClient = new ioredis_1.default(redisOptions);
24
- 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;
25
33
  this.environmentPrefix = environmentPrefix;
26
34
  this.ttl = ttl;
27
35
  this.redisClient.on('error', (err) => {
36
+ var _a, _b;
28
37
  this.loggerService.error('Redis client error: ', err);
29
- 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' });
30
39
  });
31
40
  this.redisClient.on('connect', () => {
32
41
  this.loggerService.log('Redis client connected!');
@@ -47,7 +56,12 @@ class RedisCacheService {
47
56
  */
48
57
  waitForInitialization() {
49
58
  return new Promise((resolve) => {
50
- // 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
+ }
51
65
  if (this.isClientConnected()) {
52
66
  resolve();
53
67
  return;
@@ -81,102 +95,106 @@ class RedisCacheService {
81
95
  isClientConnected() {
82
96
  return READY_STATUSES.includes(this.redisClient.status);
83
97
  }
84
- async updateUsage({ customerId, resourceId, entitlementReference, usage, }) {
85
- return this.executeSafely('updateUsage', null, async () => {
86
- // Credit entitlement usage updates are not supported in Redis cache yet - will be implemented in another ticket
87
- if (entitlementReference.type !== entities_1.EntitlementType.Feature) {
88
- return null;
89
- }
90
- // Only update usage if the entitlement exists in cache
91
- const { cacheMiss, entitlements } = await this.getCustomerEntitlementsWithoutUsage(customerId, resourceId !== null && resourceId !== void 0 ? resourceId : undefined);
92
- if (cacheMiss || !entitlements) {
93
- return null;
94
- }
95
- const entitlement = entitlements.get(entitlementReference);
96
- if (!entitlement || !(0, entities_1.isFeatureEntitlement)(entitlement)) {
97
- return null;
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;
98
110
  }
99
- const item = this.getFeatureUsageItemToUpdate({
111
+ const item = this.getUsageItemToUpdate({
100
112
  customerId,
101
113
  resourceId,
102
- featureId: entitlementReference.id,
114
+ entitlementReference,
103
115
  usage,
116
+ usageTimestamp,
104
117
  });
105
118
  await this.updateCacheItems([item]);
106
- return this.mergeEntitlementWithUsage(entitlement, usage);
107
119
  });
108
120
  }
109
- getFeatureUsageItemToUpdate({ customerId, resourceId, featureId, usage, }) {
110
- const { currentUsage, usagePeriodStart, usagePeriodEnd, updatedAt } = usage;
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;
111
127
  const value = {
112
128
  currentUsage,
113
129
  usagePeriodStart,
114
130
  usagePeriodEnd,
115
131
  };
116
132
  return {
117
- messageTimestamp: new Date(updatedAt),
118
- key: (0, cacheKeysHelpers_1.buildRedisUsageKey)(this.environmentPrefix, customerId, featureId, resourceId),
133
+ messageTimestamp: usageTimestamp,
134
+ key: (0, cacheKeysHelpers_1.buildRedisUsageKey)(this.environmentPrefix, customerId, entitlementReference, resourceId),
119
135
  value,
120
136
  };
121
137
  }
122
- async setCustomer(customerId, customerEntitlements, accessDeniedReason, resourceId, entitlementsTimestamp) {
123
- 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);
124
143
  const lockKey = (0, cacheKeysHelpers_1.buildLockKey)(this.environmentPrefix, customerId, resourceId);
125
144
  await this.distributedLocks.using(lockKey, async () => {
126
- const { customerKey, metadataKey } = (0, cacheKeysHelpers_1.buildRedisCustomerKey)(this.environmentPrefix, customerId, resourceId);
127
145
  const entitlementsItem = {
128
146
  messageTimestamp: new Date(entitlementsTimestamp),
129
147
  key: customerKey,
130
- value: customerEntitlements.toJSON(),
148
+ value: entitlements.toJSON(),
149
+ };
150
+ const metadata = {
151
+ accessDeniedReason: (0, accessDeniedReasonMapper_1.mapAccessDeniedReason)(accessDeniedReason),
131
152
  };
132
- const metadata = { accessDeniedReason };
133
153
  const metadataItem = {
134
154
  messageTimestamp: new Date(entitlementsTimestamp),
135
155
  key: metadataKey,
136
156
  value: metadata,
137
157
  };
138
- const featureUsagesItems = this.extractFeatureUsagesToUpdate({
158
+ const usagesItems = this.extractUsagesToUpdate({
139
159
  customerId,
140
160
  resourceId,
141
- customerEntitlements,
161
+ entitlements,
162
+ usageUpdatedAtMap,
142
163
  });
143
- await this.updateCacheItems([entitlementsItem, metadataItem, ...featureUsagesItems]);
164
+ await this.updateCacheItems([entitlementsItem, metadataItem, ...usagesItems]);
144
165
  });
166
+ return freshenedEntitlements;
145
167
  });
146
168
  }
147
- extractFeatureUsagesToUpdate({ customerId, resourceId, customerEntitlements, }) {
148
- return (0, lodash_1.compact)(new Array(...customerEntitlements.values()).filter(entities_1.isMeteredFeatureEntitlement).map((entitlement) => {
149
- const { calculatedEntitlement: { feature }, usageData: { currentUsage, usagePeriodStart, usagePeriodEnd, updatedAt: featureUsageTimestamp }, } = entitlement;
150
- if ((0, lodash_1.isEmpty)(feature === null || feature === void 0 ? void 0 : feature.id)) {
151
- this.loggerService.error(`entitlement without feature id`, {
152
- customerId,
153
- resourceId,
154
- });
155
- return;
156
- }
157
- const featureId = feature.id;
158
- if (!featureUsageTimestamp) {
159
- this.loggerService.error(`Usage timestamp for feature is missing`, {
160
- customerId,
161
- resourceId,
162
- featureId,
163
- });
164
- return;
165
- }
166
- return this.getFeatureUsageItemToUpdate({
169
+ extractUsagesToUpdate({ customerId, resourceId, entitlements, usageUpdatedAtMap, }) {
170
+ return (0, lodash_1.compact)(entitlements
171
+ .values()
172
+ .filter((entitlement) => entitlement.isUsageTrackable())
173
+ .map((entitlement) => {
174
+ const entitlementReference = entitlement.getEntitlementQuery();
175
+ const usageTimestamp = this.getUsageTimestamp(usageUpdatedAtMap, entitlementReference);
176
+ return this.getUsageItemToUpdate({
167
177
  customerId,
168
178
  resourceId,
169
- featureId,
170
- usage: {
171
- currentUsage,
172
- usagePeriodStart,
173
- usagePeriodEnd,
174
- updatedAt: featureUsageTimestamp,
175
- },
179
+ entitlementReference,
180
+ usage: entitlement.usageData,
181
+ usageTimestamp,
176
182
  });
177
183
  }));
178
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
+ }
179
196
  async getCustomerEntitlementsWithoutUsage(customerId, resourceId) {
197
+ var _a, _b, _c, _d;
180
198
  const { customerKey, metadataKey } = (0, cacheKeysHelpers_1.buildRedisCustomerKey)(this.environmentPrefix, customerId, resourceId);
181
199
  const keysToFetch = [customerKey, metadataKey];
182
200
  if (resourceId) {
@@ -197,12 +215,12 @@ class RedisCacheService {
197
215
  const globalEntitlementsTimestamp = this.parseTimestamp(globalEntitlementsTimestampValue);
198
216
  const globalCustomerMissing = this.isGlobalCustomerMissingInCache(customerId, resourceId, entitlements, entitlementsTimestamp, globalEntitlementsTimestamp);
199
217
  if (!entitlements || globalCustomerMissing) {
200
- this.cacheInstrumentation.trackMiss({ customerId, resourceId, globalCustomerMissing });
201
- 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);
202
220
  }
203
221
  this.loggerService.debug(`Found entitlements in persisted cache for customer`, { customerId, resourceId });
204
- this.cacheInstrumentation.trackHit({ customerId, resourceId });
205
- 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);
206
224
  }
207
225
  // resource entitlements are affected by global entitlements, so if global
208
226
  // entitlements are missing or newer, we should refetch since the cache is stale
@@ -227,99 +245,140 @@ class RedisCacheService {
227
245
  });
228
246
  return true;
229
247
  }
230
- async getCustomerEntitlements(customerId, resourceId) {
231
- 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;
232
254
  const response = await this.getCustomerEntitlementsWithoutUsage(customerId, resourceId);
233
255
  if (response.cacheMiss) {
234
256
  return response;
235
257
  }
236
- const { entitlements, accessDeniedReason } = response;
237
- const meteredFeatureIds = entitlements
238
- .values()
239
- .filter(entities_1.isMeteredFeatureEntitlement)
240
- .map(({ calculatedEntitlement }) => calculatedEntitlement.feature.id);
241
- if (!(0, lodash_1.isEmpty)(meteredFeatureIds)) {
242
- const featuresUsageByFeatureKey = await this.getFeaturesUsage(this.environmentPrefix, customerId, resourceId, meteredFeatureIds);
243
- const foundFeatureIds = Array.from(featuresUsageByFeatureKey.keys());
244
- const missingFeatureIds = (0, lodash_1.difference)(meteredFeatureIds, foundFeatureIds);
245
- if (!(0, lodash_1.isEmpty)(missingFeatureIds)) {
246
- 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.`, {
247
301
  customerId,
248
- resourceId,
249
- missingFeatureIds,
302
+ entitlementRef,
250
303
  });
251
- this.cacheInstrumentation.trackMiss({ customerId, resourceId });
252
- return entitlementsService_utils_1.entitlementsResponseMapper.cacheMiss();
253
304
  }
254
- featuresUsageByFeatureKey.forEach((usageValue, featureId) => {
255
- const cachedEntitlement = entitlements.get({
256
- type: entities_1.EntitlementType.Feature,
257
- id: featureId,
258
- });
259
- if (cachedEntitlement && (0, entities_1.isFeatureEntitlement)(cachedEntitlement)) {
260
- entitlements.set(this.mergeEntitlementWithUsage(cachedEntitlement, usageValue));
261
- }
262
- else if (!cachedEntitlement) {
263
- this.loggerService.log(`Found usage for a feature the customer is not entitled to.`, {
264
- customerId,
265
- featureId,
266
- });
267
- }
268
- });
269
- }
270
- this.cacheInstrumentation.trackHit({ customerId, resourceId });
271
- return entitlementsService_utils_1.entitlementsResponseMapper.cacheHit(entitlements, accessDeniedReason);
272
- });
305
+ });
306
+ }
307
+ return entitlements;
273
308
  }
274
- async getFeaturesUsage(environmentPrefix, customerId, resourceId, meteredFeatureIds) {
275
- 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));
276
311
  const usageValues = await this.redisClient.mget(keysToFetch);
277
- const featureIdToFeatureUsage = new Map();
312
+ const usageByEntitlementKey = new Map();
278
313
  // Redis guarantees returning values in the same order of the keys so this is legit!
279
- meteredFeatureIds.forEach((featureId, index) => {
280
- const featureUsageValue = usageValues[index];
281
- if (featureUsageValue === null) {
282
- 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}`);
283
318
  return;
284
319
  }
285
- featureIdToFeatureUsage.set(featureId, this.migrateUsageData(JSON.parse(featureUsageValue)));
320
+ usageByEntitlementKey.set(entities_1.EntitlementsMap.getUniqueKey(ref), this.migrateUsageData(JSON.parse(usageValue)));
286
321
  });
287
- return featureIdToFeatureUsage;
322
+ return usageByEntitlementKey;
288
323
  }
289
324
  clearCache() {
290
325
  return;
291
326
  }
292
327
  async updateCacheItems(items) {
328
+ var _a, _b, _c, _d;
293
329
  if ((0, lodash_1.isEmpty)(items)) {
294
330
  return;
295
331
  }
296
- const latestTimestampByKey = await this.getKeysLatestTimestamp(items.map((item) => item.key));
297
- const itemsToUpdate = [];
298
- items.forEach(({ messageTimestamp, key, value }) => {
299
- const latestTimestamp = latestTimestampByKey.get(key);
300
- if (!latestTimestamp ||
301
- messageTimestamp.getTime() === entitlementsService_utils_1.DATE_IN_FAR_PAST.getTime() ||
302
- latestTimestamp.getTime() <= messageTimestamp.getTime()) {
303
- const writeableValue = typeof value === 'string' ? value : JSON.stringify(value);
304
- itemsToUpdate.push({ key, value: writeableValue });
305
- itemsToUpdate.push({ key: `${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`, value: messageTimestamp.getTime() });
306
- }
307
- else {
308
- this.loggerService.log('Cache data timestamp is after message timestamp, skipping key update', {
309
- messageTimestamp,
310
- latestTimestamp,
311
- 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),
312
339
  });
340
+ return;
313
341
  }
314
- });
315
- if ((0, lodash_1.isEmpty)(itemsToUpdate)) {
316
- 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);
317
371
  }
318
- const batch = this.redisClient.multi();
319
- itemsToUpdate.forEach(({ key, value }) => {
320
- batch.set(key, value, 'EX', this.ttl);
321
- });
322
- 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);
323
382
  }
324
383
  async getKeysLatestTimestamp(keys) {
325
384
  const timestampKeys = keys.map((key) => `${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`);
@@ -345,43 +404,38 @@ class RedisCacheService {
345
404
  await this.distributedLocks.cleanup();
346
405
  await ((_a = this.distributedRefetchEntitlementsService) === null || _a === void 0 ? void 0 : _a.cleanup());
347
406
  }
348
- async getCustomerEntitlement(query, customerId, resourceId) {
349
- return this.executeSafely('getCustomerEntitlement', {
350
- cacheMiss: true,
351
- accessDeniedReason: undefined,
352
- entitlement: null,
353
- globalCustomerMissing: false,
354
- }, async () => {
355
- const { entitlements, accessDeniedReason, cacheMiss, globalCustomerMissing } = await this.getCustomerEntitlementsWithoutUsage(customerId, resourceId);
356
- const entitlement = !cacheMiss ? (entitlements === null || entitlements === void 0 ? void 0 : entitlements.get(query)) || null : null;
357
- const result = { cacheMiss, accessDeniedReason, entitlement, globalCustomerMissing };
358
- if (!entitlement || !(0, entities_1.isMeteredFeatureEntitlement)(entitlement)) {
359
- return result;
360
- }
361
- const featureId = query.id;
362
- const featuresUsageByFeatureKey = await this.getFeaturesUsage(this.environmentPrefix, customerId, resourceId, [
363
- featureId,
364
- ]);
365
- const cachedFeatureUsage = featuresUsageByFeatureKey.get(featureId);
366
- if ((0, lodash_1.isNil)(cachedFeatureUsage)) {
367
- this.loggerService.error('Failed to find metered feature usage - considering it as cache miss', {
368
- customerId,
369
- resourceId,
370
- 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}`];
371
415
  });
372
- return {
373
- cacheMiss: true,
374
- accessDeniedReason: undefined,
375
- entitlement: null,
376
- globalCustomerMissing: false,
377
- };
416
+ await this.redisClient.del(keysToDelete);
378
417
  }
379
- return Object.assign(Object.assign({}, result), { entitlement: this.mergeEntitlementWithUsage(entitlement, cachedFeatureUsage) });
380
418
  });
381
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
+ }
382
427
  mergeEntitlementWithUsage(entitlement, cachedUsage) {
383
- const { calculatedEntitlement, usageData } = entitlement;
384
- return new entities_1.CachedEntitlement(calculatedEntitlement, Object.assign(Object.assign({}, usageData), cachedUsage));
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);
385
439
  }
386
440
  /**
387
441
  * Migrates old cache format to new format.
@@ -400,6 +454,11 @@ class RedisCacheService {
400
454
  }
401
455
  // 2. Add type discriminator if missing (old cache only had Feature entitlements)
402
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
+ }
403
462
  entry.calculatedEntitlement.type = entities_1.EntitlementType.Feature;
404
463
  }
405
464
  // 3. Move fields from usageData to calculatedEntitlement (for Feature type)
@@ -439,6 +498,10 @@ class RedisCacheService {
439
498
  return usageData;
440
499
  }
441
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
+ }
442
505
  if (!this.isClientConnected()) {
443
506
  return defaultValue;
444
507
  }
@@ -452,4 +515,5 @@ class RedisCacheService {
452
515
  }
453
516
  }
454
517
  exports.RedisCacheService = RedisCacheService;
455
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkaXNDYWNoZVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvY2FjaGUvcmVkaXNDYWNoZVNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0EseUNBUW9CO0FBQ3BCLHNEQUE0QjtBQUM1QixtQ0FBNkU7QUFHN0UsbUVBQXVHO0FBQ3ZHLCtFQUE0RTtBQUM1RSw0RUFLc0M7QUFDdEMsK0VBS3VDO0FBRXZDLCtEQUE0RDtBQW1CNUQsTUFBTSx3QkFBd0IsR0FBRyxHQUFHLENBQUM7QUFFckMsTUFBTSxjQUFjLEdBQWEsQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7QUFFdEQsTUFBYSxpQkFBaUI7SUFRNUIsWUFDRSxPQUFzQyxFQUNyQixhQUE0QixFQUM1QixvQkFBMEM7UUFEMUMsa0JBQWEsR0FBYixhQUFhLENBQWU7UUFDNUIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtRQUUzRCxNQUFNLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxtQkFBbUIsRUFBRSxHQUFHLE9BQU8sQ0FBQztRQUM3RCxNQUFNLEVBQUUsaUJBQWlCLEVBQUUsR0FBRyxHQUFHLDhDQUFnQixFQUFFLCtCQUErQixHQUFHLEVBQUUsRUFBRSxHQUFHLFlBQVksQ0FBQztRQUV6RyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksaUJBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUMzQyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxtQ0FBZ0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLGFBQWEsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3BHLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxpQkFBaUIsQ0FBQztRQUMzQyxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUVmLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO1lB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
518
+ RedisCacheService.DELETE_CHUNK_SIZE = 1000;
519
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkaXNDYWNoZVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvY2FjaGUvcmVkaXNDYWNoZVNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBUUEseUNBQThHO0FBRTlHLHNEQUE0QjtBQUM1QixtQ0FBd0U7QUFFeEUsbUVBQXdGO0FBQ3hGLHlEQUE2RjtBQUM3RiwrRUFBNEU7QUFDNUUseURBSytCO0FBQy9CLHVFQUFvRTtBQUVwRSw2RUFBMEU7QUFDMUUsK0VBTXVDO0FBQ3ZDLCtEQUE0RDtBQUc1RCx5RUFBbUU7QUFpQm5FLE1BQU0sd0JBQXdCLEdBQUcsR0FBRyxDQUFDO0FBRXJDLE1BQU0sY0FBYyxHQUFhLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBRXRELE1BQWEsaUJBQWlCO0lBYTVCLFlBQ0UsT0FBZ0MsRUFDZixhQUF5QixFQUN6QixvQkFBMEMsRUFDMUMsV0FBK0I7UUFGL0Isa0JBQWEsR0FBYixhQUFhLENBQVk7UUFDekIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtRQUMxQyxnQkFBVyxHQUFYLFdBQVcsQ0FBb0I7UUFSakMsWUFBTyxHQUFHLElBQUksNkNBQXFCLEVBQUUsQ0FBQztRQVVyRCxNQUFNLEVBQ0osS0FBSyxFQUFFLFlBQVksRUFDbkIsbUJBQW1CLEdBQUcsNkRBQStCLEVBQ3JELGlCQUFpQixHQUFHLHNDQUFpQixDQUFDLE1BQU0sRUFDNUMsWUFBWSxFQUNaLGVBQWUsR0FBRyxLQUFLLEdBQ3hCLEdBQUcsT0FBTyxDQUFDO1FBQ1osTUFBTSxFQUFFLGlCQUFpQixFQUFFLEdBQUcsR0FBRyw4Q0FBZ0IsRUFBRSwrQkFBK0IsR0FBRyxFQUFFLEVBQUUsR0FBRyxZQUFZLENBQUM7UUFFekcsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLGlCQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLGdCQUFnQixHQUFH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