@stigg/cache-runtime 2.0.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.
@@ -0,0 +1,31 @@
1
+ import { LogConfiguration } from './services/loggerService';
2
+ import { CreditEntitlementsFallback, EntitlementsFallback } from '@stigg/entitlements-runtime';
3
+ import { SlimLogger } from '@stigg/cache-core';
4
+ import { StiggRedisOptions } from '@stigg/cache-redis-store';
5
+ export declare const DEFAULT_TIMEOUT: number;
6
+ export declare const DEFAULT_ENTITLEMENTS_TIMEOUT: number;
7
+ type ClientConfiguration = {
8
+ apiKey: string;
9
+ baseUri?: string;
10
+ baseEdgeUri?: string;
11
+ wsUrl?: string;
12
+ logConfiguration?: LogConfiguration;
13
+ realtimeUpdatesEnabled?: boolean;
14
+ enableEdge?: boolean;
15
+ redis?: StiggRedisOptions;
16
+ entitlementsFallback?: EntitlementsFallback;
17
+ creditEntitlementsFallback?: CreditEntitlementsFallback;
18
+ memoryCacheMaxSizeBytes?: number;
19
+ clientName?: string;
20
+ clientVersion?: string;
21
+ enableRemoteConfig?: boolean;
22
+ timeout?: number;
23
+ entitlementsTimeout?: number;
24
+ offline?: boolean;
25
+ };
26
+ declare function getConfiguration(configuration: Partial<ClientConfiguration>): Required<ClientConfiguration>;
27
+ /**
28
+ * We are validating here configuration that is required in order to initiate a new client, otherwise we return error
29
+ */
30
+ declare function validateConfiguration(configuration: Partial<ClientConfiguration>, loggerService: SlimLogger): void;
31
+ export { getConfiguration, ClientConfiguration, validateConfiguration };
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_ENTITLEMENTS_TIMEOUT = exports.DEFAULT_TIMEOUT = void 0;
7
+ exports.getConfiguration = getConfiguration;
8
+ exports.validateConfiguration = validateConfiguration;
9
+ const loggerService_1 = require("./services/loggerService");
10
+ const lodash_1 = require("lodash");
11
+ const v8_1 = __importDefault(require("v8"));
12
+ exports.DEFAULT_TIMEOUT = 60 * 1000;
13
+ exports.DEFAULT_ENTITLEMENTS_TIMEOUT = 10 * 1000;
14
+ const LOCALHOST_IPS = ['localhost', '127.0.0.1', '::1'];
15
+ function getDefaultMemoryCacheMaxSizeBytes() {
16
+ return v8_1.default.getHeapStatistics().total_available_size * 0.75;
17
+ }
18
+ const defaults = () => {
19
+ const baseUri = 'https://api.stigg.io';
20
+ return {
21
+ baseUri,
22
+ wsUrl: getWsUrl(baseUri),
23
+ baseEdgeUri: getBaseEdgeApiUri(baseUri),
24
+ logConfiguration: {
25
+ logger: console,
26
+ logLevel: loggerService_1.LogLevel.ERROR,
27
+ },
28
+ timeout: exports.DEFAULT_TIMEOUT,
29
+ entitlementsTimeout: exports.DEFAULT_ENTITLEMENTS_TIMEOUT,
30
+ realtimeUpdatesEnabled: true,
31
+ enableEdge: true,
32
+ memoryCacheMaxSizeBytes: getDefaultMemoryCacheMaxSizeBytes(),
33
+ enableRemoteConfig: true,
34
+ };
35
+ };
36
+ const defaultRedisOptions = () => ({
37
+ commandTimeout: 60000,
38
+ retryStrategy: (times) => {
39
+ const baseDelay = Math.min(2 ** times * 100, 8000);
40
+ const jitter = Math.floor(Math.random() * 500);
41
+ return baseDelay + jitter;
42
+ },
43
+ });
44
+ function getConfiguration(configuration) {
45
+ const defaultConfig = defaults();
46
+ const wsUrl = configuration.wsUrl
47
+ ? configuration.wsUrl
48
+ : configuration.baseUri
49
+ ? getWsUrl(configuration.baseUri)
50
+ : defaultConfig.wsUrl;
51
+ const baseEdgeUri = configuration.baseEdgeUri
52
+ ? configuration.baseEdgeUri
53
+ : configuration.baseUri
54
+ ? getBaseEdgeApiUri(configuration.baseUri)
55
+ : defaultConfig.baseEdgeUri;
56
+ const redis = configuration.redis ? (0, lodash_1.merge)(defaultRedisOptions(), configuration.redis) : undefined;
57
+ return (0, lodash_1.merge)(defaultConfig, configuration, { wsUrl, baseEdgeUri, redis });
58
+ }
59
+ function getWsUrl(apiUrl) {
60
+ const url = new URL(apiUrl);
61
+ if (url.protocol === 'http:') {
62
+ url.protocol = 'ws:';
63
+ }
64
+ else if (url.protocol === 'https:') {
65
+ url.protocol = 'wss:';
66
+ }
67
+ // Remove last char since URL.toString() adds a redundant backslash
68
+ return url.toString().slice(0, -1);
69
+ }
70
+ function getBaseEdgeApiUri(apiUrl) {
71
+ const url = new URL(apiUrl);
72
+ if (LOCALHOST_IPS.includes(url.hostname)) {
73
+ url.port = '3060';
74
+ }
75
+ else {
76
+ url.hostname = `edge.${url.hostname}`;
77
+ }
78
+ // Remove last char since URL.toString() adds a redundant backslash
79
+ return url.toString().slice(0, -1);
80
+ }
81
+ /**
82
+ * We are validating here configuration that is required in order to initiate a new client, otherwise we return error
83
+ */
84
+ function validateConfiguration(configuration, loggerService) {
85
+ if (!configuration.apiKey) {
86
+ const error = 'You must configure the client with an API key';
87
+ loggerService.error(error);
88
+ throw new Error(error);
89
+ }
90
+ }
91
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlndXJhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jb25maWd1cmF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQXdIUyw0Q0FBZ0I7QUFBdUIsc0RBQXFCO0FBeEhyRSw0REFBc0U7QUFDdEUsbUNBQStCO0FBRS9CLDRDQUFvQjtBQUlQLFFBQUEsZUFBZSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDNUIsUUFBQSw0QkFBNEIsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBRXRELE1BQU0sYUFBYSxHQUFHLENBQUMsV0FBVyxFQUFFLFdBQVcsRUFBRSxLQUFLLENBQUMsQ0FBQztBQXNCeEQsU0FBUyxpQ0FBaUM7SUFDeEMsT0FBTyxZQUFFLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxvQkFBb0IsR0FBRyxJQUFJLENBQUM7QUFDNUQsQ0FBQztBQUVELE1BQU0sUUFBUSxHQUFHLEdBQWlDLEVBQUU7SUFDbEQsTUFBTSxPQUFPLEdBQUcsc0JBQXNCLENBQUM7SUFDdkMsT0FBTztRQUNMLE9BQU87UUFDUCxLQUFLLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQztRQUN4QixXQUFXLEVBQUUsaUJBQWlCLENBQUMsT0FBTyxDQUFDO1FBQ3ZDLGdCQUFnQixFQUFFO1lBQ2hCLE1BQU0sRUFBRSxPQUFPO1lBQ2YsUUFBUSxFQUFFLHdCQUFRLENBQUMsS0FBSztTQUN6QjtRQUNELE9BQU8sRUFBRSx1QkFBZTtRQUN4QixtQkFBbUIsRUFBRSxvQ0FBNEI7UUFDakQsc0JBQXNCLEVBQUUsSUFBSTtRQUM1QixVQUFVLEVBQUUsSUFBSTtRQUNoQix1QkFBdUIsRUFBRSxpQ0FBaUMsRUFBRTtRQUM1RCxrQkFBa0IsRUFBRSxJQUFJO0tBQ3pCLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRixNQUFNLG1CQUFtQixHQUFHLEdBQStCLEVBQUUsQ0FBQyxDQUFDO0lBQzdELGNBQWMsRUFBRSxLQUFNO0lBQ3RCLGFBQWEs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
@@ -0,0 +1,11 @@
1
+ export { EntitlementsService } from './services/entitlementsService';
2
+ export { InMemoryEntitlementsService } from './services/inMemoryEntitlementsService';
3
+ export { InMemoryLruCacheService } from './services/inMemoryLruCacheService';
4
+ export { InitializationHooks } from './services/initializationStateTracker';
5
+ export { buildEntitlementsCache, CacheRuntime } from './services/cacheRuntime';
6
+ export { CreditConsumptionInput, CreditConsumptionResult, EntitlementsRuntimeHooks, EntitlementsState, EntitlementsTransport, EntitlementsUpdatedEvent, PackagePublishedEvent, TransportObservable, UsageEventInput, UsageMeasurementBulkInput, UsageMeasurementInput, UsageMeasurementResult, UsageUpdatedEvent, } from './types/transport';
7
+ export { ClassifiedError, TransportErrorClassifier } from './types/errors';
8
+ export { toEntitlementQuery } from './utils/entitlementQuery';
9
+ export { RuntimeError, RuntimeErrorHandler, RuntimeErrorHooks } from './services/runtimeErrorHandler';
10
+ export { ClientConfiguration, getConfiguration, validateConfiguration } from './configuration';
11
+ export { LogConfiguration, Logger, LoggerService, LogLevel } from './services/loggerService';
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LogLevel = exports.LoggerService = exports.validateConfiguration = exports.getConfiguration = exports.RuntimeErrorHandler = exports.RuntimeError = exports.toEntitlementQuery = exports.CacheRuntime = exports.buildEntitlementsCache = exports.InMemoryLruCacheService = exports.InMemoryEntitlementsService = exports.EntitlementsService = void 0;
4
+ var entitlementsService_1 = require("./services/entitlementsService");
5
+ Object.defineProperty(exports, "EntitlementsService", { enumerable: true, get: function () { return entitlementsService_1.EntitlementsService; } });
6
+ var inMemoryEntitlementsService_1 = require("./services/inMemoryEntitlementsService");
7
+ Object.defineProperty(exports, "InMemoryEntitlementsService", { enumerable: true, get: function () { return inMemoryEntitlementsService_1.InMemoryEntitlementsService; } });
8
+ var inMemoryLruCacheService_1 = require("./services/inMemoryLruCacheService");
9
+ Object.defineProperty(exports, "InMemoryLruCacheService", { enumerable: true, get: function () { return inMemoryLruCacheService_1.InMemoryLruCacheService; } });
10
+ var cacheRuntime_1 = require("./services/cacheRuntime");
11
+ Object.defineProperty(exports, "buildEntitlementsCache", { enumerable: true, get: function () { return cacheRuntime_1.buildEntitlementsCache; } });
12
+ Object.defineProperty(exports, "CacheRuntime", { enumerable: true, get: function () { return cacheRuntime_1.CacheRuntime; } });
13
+ var entitlementQuery_1 = require("./utils/entitlementQuery");
14
+ Object.defineProperty(exports, "toEntitlementQuery", { enumerable: true, get: function () { return entitlementQuery_1.toEntitlementQuery; } });
15
+ var runtimeErrorHandler_1 = require("./services/runtimeErrorHandler");
16
+ Object.defineProperty(exports, "RuntimeError", { enumerable: true, get: function () { return runtimeErrorHandler_1.RuntimeError; } });
17
+ Object.defineProperty(exports, "RuntimeErrorHandler", { enumerable: true, get: function () { return runtimeErrorHandler_1.RuntimeErrorHandler; } });
18
+ var configuration_1 = require("./configuration");
19
+ Object.defineProperty(exports, "getConfiguration", { enumerable: true, get: function () { return configuration_1.getConfiguration; } });
20
+ Object.defineProperty(exports, "validateConfiguration", { enumerable: true, get: function () { return configuration_1.validateConfiguration; } });
21
+ var loggerService_1 = require("./services/loggerService");
22
+ Object.defineProperty(exports, "LoggerService", { enumerable: true, get: function () { return loggerService_1.LoggerService; } });
23
+ Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return loggerService_1.LogLevel; } });
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsc0VBQXFFO0FBQTVELDBIQUFBLG1CQUFtQixPQUFBO0FBQzVCLHNGQUFxRjtBQUE1RSwwSUFBQSwyQkFBMkIsT0FBQTtBQUNwQyw4RUFBNkU7QUFBcEUsa0lBQUEsdUJBQXVCLE9BQUE7QUFFaEMsd0RBQStFO0FBQXRFLHNIQUFBLHNCQUFzQixPQUFBO0FBQUUsNEdBQUEsWUFBWSxPQUFBO0FBb0I3Qyw2REFBOEQ7QUFBckQsc0hBQUEsa0JBQWtCLE9BQUE7QUFFM0Isc0VBQXNHO0FBQTdGLG1IQUFBLFlBQVksT0FBQTtBQUFFLDBIQUFBLG1CQUFtQixPQUFBO0FBRTFDLGlEQUErRjtBQUFqRSxpSEFBQSxnQkFBZ0IsT0FBQTtBQUFFLHNIQUFBLHFCQUFxQixPQUFBO0FBRXJFLDBEQUE2RjtBQUExRCw4R0FBQSxhQUFhLE9BQUE7QUFBRSx5R0FBQSxRQUFRLE9BQUEifQ==
@@ -0,0 +1,66 @@
1
+ import { CacheInstrumentation, CacheMapper, SlimLogger } from '@stigg/cache-core';
2
+ import { RedisCacheService } from '@stigg/cache-redis-store';
3
+ import { EntitlementFallbacks } from '@stigg/entitlements-runtime';
4
+ import { ClientConfiguration } from '../configuration';
5
+ import { CacheableInput, EntitlementsRuntimeHooks, EntitlementsTransport } from '../types/transport';
6
+ import { EntitlementsService } from './entitlementsService';
7
+ import { InitializationHooks } from './initializationStateTracker';
8
+ import { RuntimeErrorHooks } from './runtimeErrorHandler';
9
+ import { InMemoryLruCacheService } from './inMemoryLruCacheService';
10
+ /**
11
+ * Discriminated so the caller cannot land on a cache/service mismatch: only the in-memory store
12
+ * takes runtime hooks, and only it has anything to clear when the transport reconnects.
13
+ */
14
+ export type EntitlementsCache<Input> = {
15
+ onTransportConnected: () => void;
16
+ } & ({
17
+ kind: 'redis';
18
+ cacheService: RedisCacheService<Input>;
19
+ } | {
20
+ kind: 'memory';
21
+ cacheService: InMemoryLruCacheService<Input>;
22
+ });
23
+ export type EntitlementsCacheParams<Input> = {
24
+ configuration: Required<ClientConfiguration>;
25
+ loggerService: SlimLogger;
26
+ instrumentation: CacheInstrumentation;
27
+ cacheMapper: CacheMapper<Input>;
28
+ };
29
+ /**
30
+ * Built before the transport, because a reconnecting transport has to clear the in-memory store.
31
+ */
32
+ export declare function buildEntitlementsCache<Input>({ configuration, loggerService, instrumentation, cacheMapper, }: EntitlementsCacheParams<Input>): EntitlementsCache<Input>;
33
+ export type CacheRuntimeParams<Input extends CacheableInput, TPackagePublished> = {
34
+ configuration: Required<ClientConfiguration>;
35
+ loggerService: SlimLogger;
36
+ cache: EntitlementsCache<Input>;
37
+ transport: EntitlementsTransport<Input, TPackagePublished>;
38
+ hooks: EntitlementsRuntimeHooks<Input, TPackagePublished>;
39
+ errorHooks: RuntimeErrorHooks;
40
+ initializationHooks: InitializationHooks;
41
+ };
42
+ /** A class rather than a returned pair: the lifecycle shares the transport and error handler the reads use. */
43
+ export declare class CacheRuntime<Input extends CacheableInput, TPackagePublished = unknown> {
44
+ readonly entitlementsService: EntitlementsService<Input, TPackagePublished>;
45
+ readonly fallbacks: EntitlementFallbacks;
46
+ private readonly errorHandler;
47
+ private readonly initializationTracker;
48
+ private readonly loggerService;
49
+ private readonly offline;
50
+ private readonly transport;
51
+ /** Both gates fold in `offline`, which reaches the network for nothing. */
52
+ private readonly validatesApiKey;
53
+ private readonly subscribesToUpdates;
54
+ constructor({ configuration, loggerService, cache, transport, hooks, errorHooks, initializationHooks, }: CacheRuntimeParams<Input, TPackagePublished>);
55
+ /**
56
+ * Void because the outcome is observed through `waitForInitialization`. Subscribing precedes the
57
+ * awaits so it is neither deferred behind a round-trip nor skipped when startup fails.
58
+ */
59
+ initialize(): void;
60
+ /**
61
+ * The runtime's own readiness: startup finished. Distinct from `EntitlementsService`'s method of
62
+ * the same name, which reports only that the cache store is ready to be read.
63
+ */
64
+ waitForInitialization(): Promise<void>;
65
+ cleanup(): Promise<void>;
66
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CacheRuntime = void 0;
4
+ exports.buildEntitlementsCache = buildEntitlementsCache;
5
+ const lodash_1 = require("lodash");
6
+ const cache_redis_store_1 = require("@stigg/cache-redis-store");
7
+ const entitlements_runtime_1 = require("@stigg/entitlements-runtime");
8
+ const initializationStateTracker_1 = require("./initializationStateTracker");
9
+ const runtimeErrorHandler_1 = require("./runtimeErrorHandler");
10
+ const inMemoryEntitlementsService_1 = require("./inMemoryEntitlementsService");
11
+ const inMemoryLruCacheService_1 = require("./inMemoryLruCacheService");
12
+ const redisEntitlementsService_1 = require("./redisEntitlementsService");
13
+ /**
14
+ * Built before the transport, because a reconnecting transport has to clear the in-memory store.
15
+ */
16
+ function buildEntitlementsCache({ configuration, loggerService, instrumentation, cacheMapper, }) {
17
+ if (!(0, lodash_1.isEmpty)(configuration.redis)) {
18
+ return {
19
+ kind: 'redis',
20
+ cacheService: new cache_redis_store_1.RedisCacheService(configuration, loggerService, instrumentation, cacheMapper),
21
+ onTransportConnected: () => undefined,
22
+ };
23
+ }
24
+ const cacheService = new inMemoryLruCacheService_1.InMemoryLruCacheService(configuration.memoryCacheMaxSizeBytes, instrumentation, cacheMapper);
25
+ return { kind: 'memory', cacheService, onTransportConnected: cacheService.clearCache };
26
+ }
27
+ /** A class rather than a returned pair: the lifecycle shares the transport and error handler the reads use. */
28
+ class CacheRuntime {
29
+ constructor({ configuration, loggerService, cache, transport, hooks, errorHooks, initializationHooks, }) {
30
+ const { entitlementsTimeout, entitlementsFallback, creditEntitlementsFallback, offline, enableRemoteConfig, realtimeUpdatesEnabled, } = configuration;
31
+ this.loggerService = loggerService;
32
+ this.offline = offline;
33
+ this.transport = transport;
34
+ this.validatesApiKey = enableRemoteConfig && !offline;
35
+ this.subscribesToUpdates = realtimeUpdatesEnabled && !offline;
36
+ this.fallbacks = new entitlements_runtime_1.EntitlementFallbacks({ entitlementsFallback, creditEntitlementsFallback });
37
+ this.errorHandler = new runtimeErrorHandler_1.RuntimeErrorHandler(loggerService, errorHooks, transport.classifier);
38
+ this.initializationTracker = new initializationStateTracker_1.InitializationStateTracker(initializationHooks);
39
+ const evaluator = new entitlements_runtime_1.EntitlementEvaluator(this.fallbacks);
40
+ this.entitlementsService =
41
+ cache.kind === 'redis'
42
+ ? new redisEntitlementsService_1.RedisEntitlementsService(cache.cacheService, transport, loggerService, entitlementsTimeout, evaluator, offline, this.errorHandler)
43
+ : new inMemoryEntitlementsService_1.InMemoryEntitlementsService(cache.cacheService, transport, hooks, loggerService, entitlementsTimeout, evaluator, offline, this.errorHandler);
44
+ }
45
+ /**
46
+ * Void because the outcome is observed through `waitForInitialization`. Subscribing precedes the
47
+ * awaits so it is neither deferred behind a round-trip nor skipped when startup fails.
48
+ */
49
+ initialize() {
50
+ if (this.offline) {
51
+ this.loggerService.log('Initialized in offline mode, only fallback entitlements are being used.');
52
+ }
53
+ this.errorHandler
54
+ .runOrThrow('Failed to load sdk configuration', async () => {
55
+ // Inside the chain so a synchronous throw from subscribing still reaches the tracker,
56
+ // rather than leaving waitForInitialization() pending forever.
57
+ if (this.subscribesToUpdates) {
58
+ this.entitlementsService.init();
59
+ }
60
+ return Promise.all([
61
+ this.entitlementsService.waitForInitialization(),
62
+ this.validatesApiKey ? this.transport.validateApiKey() : undefined,
63
+ ]);
64
+ })
65
+ .then(() => this.initializationTracker.signalSuccessInit())
66
+ .catch((err) => this.initializationTracker.signalFailedInit(err));
67
+ }
68
+ /**
69
+ * The runtime's own readiness: startup finished. Distinct from `EntitlementsService`'s method of
70
+ * the same name, which reports only that the cache store is ready to be read.
71
+ */
72
+ waitForInitialization() {
73
+ return this.initializationTracker.getInitializationPromise();
74
+ }
75
+ cleanup() {
76
+ return Promise.resolve(this.entitlementsService.cleanup());
77
+ }
78
+ }
79
+ exports.CacheRuntime = CacheRuntime;
80
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGVSdW50aW1lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2VzL2NhY2hlUnVudGltZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFnQ0Esd0RBb0JDO0FBcERELG1DQUFpQztBQUVqQyxnRUFBNkQ7QUFDN0Qsc0VBQXlGO0FBSXpGLDZFQUErRjtBQUMvRiwrREFBK0U7QUFDL0UsK0VBQTRFO0FBQzVFLHVFQUFvRTtBQUNwRSx5RUFBc0U7QUFrQnRFOztHQUVHO0FBQ0gsU0FBZ0Isc0JBQXNCLENBQVEsRUFDNUMsYUFBYSxFQUNiLGFBQWEsRUFDYixlQUFlLEVBQ2YsV0FBVyxHQUNvQjtJQUMvQixJQUFJLENBQUMsSUFBQSxnQkFBTyxFQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ2xDLE9BQU87WUFDTCxJQUFJLEVBQUUsT0FBTztZQUNiLFlBQVksRUFBRSxJQUFJLHFDQUFpQixDQUFRLGFBQWEsRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLFdBQVcsQ0FBQztZQUN0RyxvQkFBb0IsRUFBRSxHQUFHLEVBQUUsQ0FBQyxTQUFTO1NBQ3RDLENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxZQUFZLEdBQUcsSUFBSSxpREFBdUIsQ0FDOUMsYUFBYSxDQUFDLHVCQUF1QixFQUNyQyxlQUFlLEVBQ2YsV0FBVyxDQUNaLENBQUM7SUFDRixPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQUUsb0JBQW9CLEVBQUUsWUFBWSxDQUFDLFVBQVUsRUFBRSxDQUFDO0FBQ3pGLENBQUM7QUFZRCwrR0FBK0c7QUFDL0csTUFBYSxZQUFZO0lBYXZCLFlBQVksRUFDVixhQUFhLEVBQ2IsYUFBYSxFQUNiLEtBQUssRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUNMLFVBQVUsRUFDVixtQkFBbUIsR0FDMEI7UUFDN0MsTUFBTSxFQUNKLG1CQUFtQixFQUNuQixvQkFBb0IsRUFDcEIsMEJBQTBCLEVBQzFCLE9BQU8sRUFDUCxrQkFBa0IsRUFDbEIsc0JBQXNCLEdBQ3ZCLEdBQUcsYUFBYSxDQUFDO1FBRWxCLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBYSxDQUFDO1FBQ25DLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBQzNCLElBQUksQ0FBQyxlQUFlLEdBQUcsa0JBQWtCLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDdEQsSUFBSSxDQUFDLG1CQUFtQixHQUFHLHNCQUFzQixJQUFJLENBQUMsT0FBTyxDQUFDO1FBQzlELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSwyQ0FBb0IsQ0FBQyxFQUFFLG9CQUFvQixFQUFFLDBCQUEwQixFQUFFLENBQUMsQ0FBQztRQUNoRyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUkseUNBQW1CLENBQUMsYUFBYSxFQUFFLFVBQVUsRUFBRSxTQUFTLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDN0YsSUFBSSxDQUFDLHFCQUFxQixHQUFHLElBQUksdURBQTBCLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUVqRixNQUFNLFNBQVMsR0FBRyxJQUFJLDJDQUFvQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUUzRCxJQUFJLENBQUMsbUJBQW1CO1lBQ3RCLEtBQUssQ0FBQyxJQUFJLEtBQUssT0FBTztnQkFDcEIsQ0FBQyxDQUFDLElBQUksbURBQXdCLENBQzFCLEtBQUssQ0FBQyxZQUFZLEVBQ2xCLFNBQVMsRUFDVCxhQUFhLEVBQ2IsbUJBQW1CLEVBQ25CLFNBQVMsRUFDVCxPQUFPLEVBQ1AsSUFBSSxDQUFDLFlBQVksQ0FDbEI7Z0JBQ0gsQ0FBQyxDQUFDLElBQUkseURBQTJCLENBQzdCLEtBQUssQ0FBQyxZQUFZLEVBQ2xCLFNBQVMsRUFDVCxLQUFLLEVBQ0wsYUFBYSxFQUNiLG1CQUFtQixFQUNuQixTQUFTLEVBQ1QsT0FBTyxFQUNQLElBQUksQ0FBQyxZQUFZLENBQ2xCLENBQUM7SUFDVixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsVUFBVTtRQUNSLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLHlFQUF5RSxDQUFDLENBQUM7UUFDcEcsQ0FBQztRQUVELElBQUksQ0FBQyxZQUFZO2FBQ2QsVUFBVSxDQUFDLGtDQUFrQyxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ3pELHNGQUFzRjtZQUN0RiwrREFBK0Q7WUFDL0QsSUFBSSxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztnQkFDN0IsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2xDLENBQUM7WUFFRCxPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUM7Z0JBQ2pCLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxxQkFBcUIsRUFBRTtnQkFDaEQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUzthQUNuRSxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUM7YUFDRCxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGlCQUFpQixFQUFFLENBQUM7YUFDMUQsS0FBSyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gscUJBQXFCO1FBQ25CLE9BQU8sSUFBSSxDQUFDLHFCQUFxQixDQUFDLHdCQUF3QixFQUFFLENBQUM7SUFDL0QsQ0FBQztJQUVELE9BQU87UUFDTCxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDN0QsQ0FBQztDQUNGO0FBdEdELG9DQXNHQyJ9
@@ -0,0 +1,81 @@
1
+ import { BooleanEntitlementOptions, CreditEntitlementOptions, EntitlementEvaluation, EntitlementEvaluator, EntitlementReadOptions, EnumEntitlementOptions, MeteredEntitlementOptions, NumericEntitlementOptions } from '@stigg/entitlements-runtime';
2
+ import { CacheService, EntitlementQuery, EntitlementType, EntitlementsMap, EntitlementsResponse, EntitlementsResponseCacheHit, EntitlementsStateAccessDeniedReason, Maybe, SlimLogger } from '@stigg/cache-core';
3
+ import { RuntimeErrorHandler } from './runtimeErrorHandler';
4
+ import { RefetchEntitlementsAfterCacheMissParams, RefetchEntitlementsParams, RefetchEntityEntitlementsAfterCacheMissParams } from './entitlementsService.utils';
5
+ import { CacheableInput, CreditConsumptionInput, CreditConsumptionResult, CustomerEntitlementsEvaluation, EntitlementsTransport, UsageEventInput, UsageMeasurementBulkInput, UsageMeasurementInput, UsageMeasurementResult } from '../types/transport';
6
+ export declare abstract class EntitlementsService<Input extends CacheableInput, TPackagePublished = unknown> {
7
+ protected readonly entitlementsApi: EntitlementsTransport<Input, TPackagePublished>;
8
+ protected readonly loggerService: SlimLogger;
9
+ protected readonly cacheService: CacheService<Input>;
10
+ private readonly entitlementsTimeout;
11
+ protected readonly evaluator: EntitlementEvaluator;
12
+ private readonly offline;
13
+ private readonly errorHandler;
14
+ protected isInitialized: boolean;
15
+ protected constructor(entitlementsApi: EntitlementsTransport<Input, TPackagePublished>, loggerService: SlimLogger, cacheService: CacheService<Input>, entitlementsTimeout: number, evaluator: EntitlementEvaluator, offline: boolean, errorHandler: RuntimeErrorHandler);
16
+ getBooleanEntitlement(customerId: string, featureRefId: string, resourceId?: string, options?: BooleanEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Feature>>;
17
+ protected readBooleanEntitlement(customerId: string, featureRefId: string, resourceId?: string, options?: BooleanEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Feature>>;
18
+ getNumericEntitlement(customerId: string, featureRefId: string, resourceId?: string, options?: NumericEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Feature>>;
19
+ protected readNumericEntitlement(customerId: string, featureRefId: string, resourceId?: string, options?: NumericEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Feature>>;
20
+ getMeteredEntitlement(customerId: string, featureRefId: string, resourceId?: string, options?: MeteredEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Feature>>;
21
+ protected readMeteredEntitlement(customerId: string, featureRefId: string, resourceId?: string, options?: MeteredEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Feature>>;
22
+ getEnumEntitlement(customerId: string, featureRefId: string, resourceId?: string, options?: EnumEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Feature>>;
23
+ protected readEnumEntitlement(customerId: string, featureRefId: string, resourceId?: string, options?: EnumEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Feature>>;
24
+ getCreditEntitlement(customerId: string, currencyId: string, resourceId?: string, options?: CreditEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Credit>>;
25
+ protected readCreditEntitlement(customerId: string, currencyId: string, resourceId?: string, options?: CreditEntitlementOptions): Promise<EntitlementEvaluation<EntitlementType.Credit>>;
26
+ getEntitlement<TType extends EntitlementType>(entitlementReference: EntitlementQuery<TType>, customerRefId: string, resourceId: string | undefined, options?: EntitlementReadOptions): Promise<EntitlementEvaluation<TType>>;
27
+ protected readEntitlement<TType extends EntitlementType>(entitlementReference: EntitlementQuery<TType>, customerRefId: string, resourceId: string | undefined, options?: EntitlementReadOptions): Promise<EntitlementEvaluation<TType>>;
28
+ private getCustomerAndEntitlementFromCacheOrRefetch;
29
+ getCustomerEntitlements(customerId: string, resourceId: string | undefined): Promise<CustomerEntitlementsEvaluation>;
30
+ protected readCustomerEntitlements(customerId: string, resourceId: string | undefined): Promise<CustomerEntitlementsEvaluation>;
31
+ abstract clearCache(): void | Promise<void>;
32
+ abstract init(): void | Promise<void>;
33
+ abstract cleanup(): void | Promise<void>;
34
+ /** Offline never reaches the API, so the measurement is acknowledged locally instead. */
35
+ private offlineMeasurement;
36
+ reportUsage(input: UsageMeasurementInput): Promise<UsageMeasurementResult>;
37
+ reportUsageBulk(input: UsageMeasurementBulkInput): Promise<UsageMeasurementResult[]>;
38
+ /** Passes through: an event has no cache state to maintain, unlike a usage measurement. */
39
+ reportEvent(events: UsageEventInput[]): Promise<void>;
40
+ /** Passes through: the balance is settled server-side, so there is nothing to write through. */
41
+ consumeCreditsAsync(consumptions: CreditConsumptionInput[]): Promise<void>;
42
+ consumeCredits(input: CreditConsumptionInput): Promise<CreditConsumptionResult>;
43
+ protected refetchEntitlementsAfterCacheMiss(params: RefetchEntitlementsAfterCacheMissParams): Promise<EntitlementsResponse>;
44
+ /**
45
+ * Force a refetch and report whether the entitled entity exists at all. `NoActiveSubscription`
46
+ * still counts as existing — the customer is known, they just have nothing active.
47
+ *
48
+ * A failure answers `false` rather than throwing: not knowing and knowing there is nothing are
49
+ * the same answer to the caller, and both hosts wanted it.
50
+ */
51
+ reloadEntitlements(customerId: string, resourceId?: string): Promise<{
52
+ entitledEntityExists: boolean;
53
+ }>;
54
+ protected abstract refetchEntityEntitlementsAfterCacheMiss(params: RefetchEntityEntitlementsAfterCacheMissParams): Promise<EntitlementsResponse>;
55
+ refetchEntitlements({ customerId, resourceId, skipEdge, triggeredBy, }: RefetchEntitlementsParams): Promise<EntitlementsResponseCacheHit>;
56
+ setEntitlementsIfExists(options: {
57
+ entitlements?: Input[] | null;
58
+ customerId: string;
59
+ resourceId: string | undefined;
60
+ }): Promise<EntitlementsMap | null>;
61
+ setEntitlements(params: {
62
+ entitlements: Input[];
63
+ accessDeniedReason: Maybe<EntitlementsStateAccessDeniedReason>;
64
+ customerId: string;
65
+ resourceId: string | undefined;
66
+ }): Promise<EntitlementsMap>;
67
+ protected getEntitlementsUpdatedAtTimestamp({ entitlements, customerId, resourceId, }: {
68
+ entitlements: Input[];
69
+ customerId: string;
70
+ resourceId: Maybe<string>;
71
+ }): Date;
72
+ updateFeatureUsage({ featureId, customerId, resourceId, currentUsage, usagePeriodStart, usagePeriodEnd, credit, timestamp, }: UsageMeasurementResult): Promise<void>;
73
+ private updateCreditBalance;
74
+ /**
75
+ * Reports only whether the cache store is readable. `CacheRuntime`'s method of the same name is
76
+ * the one that reports whether startup as a whole succeeded.
77
+ */
78
+ waitForInitialization(): Promise<void>;
79
+ private isEntitlementExpired;
80
+ private areEntitlementsExpired;
81
+ }