@plyaz/core 1.0.3 → 1.1.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.
- package/README.md +33 -21
- package/dist/base/cache/index.d.ts.map +1 -1
- package/dist/base/cache/strategies/memory.d.ts.map +1 -1
- package/dist/base/cache/strategies/redis.d.ts.map +1 -1
- package/dist/domain/featureFlags/provider.d.ts.map +1 -1
- package/dist/frontend/featureFlags/hooks/useFeatureFlagProvider.d.ts +1 -1
- package/dist/frontend/featureFlags/hooks/useFeatureFlagProvider.d.ts.map +1 -1
- package/dist/frontend/featureFlags/providers/FeatureFlagProviderHelpers.d.ts +2 -16
- package/dist/frontend/featureFlags/providers/FeatureFlagProviderHelpers.d.ts.map +1 -1
- package/dist/frontend/featureFlags/providers/types.d.ts +21 -0
- package/dist/frontend/featureFlags/providers/types.d.ts.map +1 -0
- package/dist/index.cjs +23 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +24 -31
- package/dist/index.mjs.map +1 -1
- package/dist/utils/common/hash.d.ts +14 -3
- package/dist/utils/common/hash.d.ts.map +1 -1
- package/dist/utils/common/values.d.ts.map +1 -1
- package/dist/utils/featureFlags/context.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CACHE_MAX_SIZE_DEFAULT, CACHE_CLEANUP_INTERVAL_DEFAULT, FILE_CHECK_INTERVAL_DEFAULT, FEATURE_FLAG_FILE_PATHS, FEATURE_FLAG_CACHE_TTL_DEFAULT, FEATURES } from '@plyaz/config';
|
|
1
|
+
import { CACHE_MAX_SIZE_DEFAULT, CACHE_CLEANUP_INTERVAL_DEFAULT, TIME_CONSTANTS, FORMAT_CONSTANTS, FILE_CHECK_INTERVAL_DEFAULT, FEATURE_FLAG_FILE_PATHS, FEATURE_FLAG_CACHE_TTL_DEFAULT, MATH_CONSTANTS, ISO_STANDARDS, FEATURES, FNV_CONSTANTS, HASH_SEED_CONSTANTS } from '@plyaz/config';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { promisify } from 'util';
|
|
@@ -23,24 +23,21 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
23
23
|
};
|
|
24
24
|
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
25
25
|
var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
|
|
26
|
-
|
|
27
|
-
// src/utils/common/hash.ts
|
|
28
26
|
function hashString(str) {
|
|
29
|
-
|
|
30
|
-
let hash =
|
|
27
|
+
if (str.length === 0) return 0;
|
|
28
|
+
let hash = FNV_CONSTANTS.FNV_32_OFFSET;
|
|
31
29
|
for (let i = 0; i < str.length; i++) {
|
|
32
|
-
|
|
33
|
-
hash = (hash
|
|
34
|
-
hash = hash & hash;
|
|
30
|
+
hash ^= str.charCodeAt(i);
|
|
31
|
+
hash = Math.imul(hash, FNV_CONSTANTS.FNV_32_PRIME) >>> 0;
|
|
35
32
|
}
|
|
36
|
-
return
|
|
33
|
+
return hash >>> 0;
|
|
37
34
|
}
|
|
38
35
|
__name(hashString, "hashString");
|
|
39
36
|
function isInRollout(identifier, percentage) {
|
|
40
|
-
if (percentage >=
|
|
37
|
+
if (percentage >= MATH_CONSTANTS.PERCENTAGE_MAX) return true;
|
|
41
38
|
if (percentage <= 0) return false;
|
|
42
39
|
const hash = hashString(identifier);
|
|
43
|
-
return hash %
|
|
40
|
+
return hash % MATH_CONSTANTS.PERCENTAGE_MAX < percentage;
|
|
44
41
|
}
|
|
45
42
|
__name(isInRollout, "isInRollout");
|
|
46
43
|
function createRolloutIdentifier(featureKey, userId) {
|
|
@@ -69,23 +66,22 @@ var HashUtils = {
|
|
|
69
66
|
* @param totalBuckets - Total number of buckets (default: 100)
|
|
70
67
|
* @returns true if identifier is in the bucket range
|
|
71
68
|
*/
|
|
72
|
-
isInBucketRange: /* @__PURE__ */ __name((identifier, startBucket, endBucket, totalBuckets =
|
|
69
|
+
isInBucketRange: /* @__PURE__ */ __name((identifier, startBucket, endBucket, totalBuckets = MATH_CONSTANTS.PERCENTAGE_MAX) => {
|
|
73
70
|
const bucket = hashString(identifier) % totalBuckets;
|
|
74
71
|
return bucket >= startBucket && bucket <= endBucket;
|
|
75
72
|
}, "isInBucketRange"),
|
|
76
73
|
/**
|
|
77
74
|
* Creates a deterministic random seed from a string.
|
|
75
|
+
* Uses the improved hash function and ensures the seed is within
|
|
76
|
+
* the safe range for JavaScript's Math.random seeding.
|
|
78
77
|
*
|
|
79
78
|
* @param str - String to convert to seed
|
|
80
|
-
* @returns Deterministic seed value
|
|
79
|
+
* @returns Deterministic seed value (0 to 2^31-1)
|
|
81
80
|
*/
|
|
82
81
|
createSeed: /* @__PURE__ */ __name((str) => {
|
|
83
|
-
|
|
84
|
-
return hashString(str) % SAFE_INT;
|
|
82
|
+
return hashString(str) % HASH_SEED_CONSTANTS.MAX_SAFE_SEED;
|
|
85
83
|
}, "createSeed")
|
|
86
84
|
};
|
|
87
|
-
|
|
88
|
-
// src/utils/common/values.ts
|
|
89
85
|
function isStringFalsy(value) {
|
|
90
86
|
if (value === "") return true;
|
|
91
87
|
const lower = value.toLowerCase().trim();
|
|
@@ -151,7 +147,7 @@ var ValueUtils = {
|
|
|
151
147
|
*/
|
|
152
148
|
isValidPercentage: /* @__PURE__ */ __name((value) => {
|
|
153
149
|
if (typeof value !== "number") return false;
|
|
154
|
-
return !isNaN(value) && isFinite(value) && value >= 0 && value <=
|
|
150
|
+
return !isNaN(value) && isFinite(value) && value >= 0 && value <= MATH_CONSTANTS.PERCENTAGE_MAX;
|
|
155
151
|
}, "isValidPercentage"),
|
|
156
152
|
/**
|
|
157
153
|
* Clamps a number to a specific range.
|
|
@@ -197,8 +193,6 @@ var ValueUtils = {
|
|
|
197
193
|
return current;
|
|
198
194
|
}, "getNestedProperty")
|
|
199
195
|
};
|
|
200
|
-
|
|
201
|
-
// src/utils/featureFlags/context.ts
|
|
202
196
|
var FeatureFlagContextBuilder = class _FeatureFlagContextBuilder {
|
|
203
197
|
static {
|
|
204
198
|
__name(this, "FeatureFlagContextBuilder");
|
|
@@ -394,7 +388,7 @@ var ContextUtils = {
|
|
|
394
388
|
if (context.platform && !["web", "mobile", "desktop"].includes(context.platform)) {
|
|
395
389
|
errors.push("Platform must be web, mobile, or desktop");
|
|
396
390
|
}
|
|
397
|
-
if (context.country && context.country.length !==
|
|
391
|
+
if (context.country && context.country.length !== ISO_STANDARDS.ISO_COUNTRY_CODE_LENGTH) {
|
|
398
392
|
errors.push("Country must be a 2-letter ISO country code");
|
|
399
393
|
}
|
|
400
394
|
return {
|
|
@@ -1113,6 +1107,9 @@ var MemoryCacheStrategy = class {
|
|
|
1113
1107
|
this.cleanupTimer = setInterval(() => {
|
|
1114
1108
|
this.cleanupExpiredEntries();
|
|
1115
1109
|
}, this.cleanupInterval);
|
|
1110
|
+
if (this.cleanupTimer && typeof this.cleanupTimer.unref === "function") {
|
|
1111
|
+
this.cleanupTimer.unref();
|
|
1112
|
+
}
|
|
1116
1113
|
}
|
|
1117
1114
|
/**
|
|
1118
1115
|
* Removes expired entries from the cache.
|
|
@@ -1161,8 +1158,6 @@ var MemoryCacheStrategy = class {
|
|
|
1161
1158
|
}
|
|
1162
1159
|
}
|
|
1163
1160
|
};
|
|
1164
|
-
|
|
1165
|
-
// src/base/cache/strategies/redis.ts
|
|
1166
1161
|
var RedisCacheStrategy = class {
|
|
1167
1162
|
/**
|
|
1168
1163
|
* Creates a new Redis cache strategy.
|
|
@@ -1200,7 +1195,7 @@ var RedisCacheStrategy = class {
|
|
|
1200
1195
|
const redisKey = this.buildRedisKey(key);
|
|
1201
1196
|
const serializedEntry = JSON.stringify(entry);
|
|
1202
1197
|
const ttlMs = entry.expiresAt - Date.now();
|
|
1203
|
-
const ttlSeconds = Math.max(1, Math.ceil(ttlMs /
|
|
1198
|
+
const ttlSeconds = Math.max(1, Math.ceil(ttlMs / TIME_CONSTANTS.MILLISECONDS_PER_SECOND));
|
|
1204
1199
|
await this.client.set(redisKey, serializedEntry, "EX", ttlSeconds);
|
|
1205
1200
|
this.stats.setCount++;
|
|
1206
1201
|
}
|
|
@@ -1371,7 +1366,7 @@ var CacheManager = class {
|
|
|
1371
1366
|
const finalTtl = ttl ?? this.config.ttl;
|
|
1372
1367
|
const entry = {
|
|
1373
1368
|
data: value,
|
|
1374
|
-
expiresAt: Date.now() + finalTtl *
|
|
1369
|
+
expiresAt: Date.now() + finalTtl * TIME_CONSTANTS.MILLISECONDS_PER_SECOND,
|
|
1375
1370
|
createdAt: Date.now()
|
|
1376
1371
|
};
|
|
1377
1372
|
await this.strategy.set(key, entry);
|
|
@@ -1464,8 +1459,6 @@ var CacheManager = class {
|
|
|
1464
1459
|
await this.strategy.dispose?.();
|
|
1465
1460
|
}
|
|
1466
1461
|
};
|
|
1467
|
-
|
|
1468
|
-
// src/domain/featureFlags/provider.ts
|
|
1469
1462
|
var FeatureFlagProvider = class {
|
|
1470
1463
|
/**
|
|
1471
1464
|
* Creates a new feature flag provider.
|
|
@@ -1700,7 +1693,7 @@ var FeatureFlagProvider = class {
|
|
|
1700
1693
|
void this.refresh().catch((error) => {
|
|
1701
1694
|
this.log("Auto-refresh failed:", error);
|
|
1702
1695
|
});
|
|
1703
|
-
}, this.config.refreshInterval *
|
|
1696
|
+
}, this.config.refreshInterval * TIME_CONSTANTS.MILLISECONDS_PER_SECOND);
|
|
1704
1697
|
}
|
|
1705
1698
|
}
|
|
1706
1699
|
/**
|
|
@@ -2344,7 +2337,7 @@ var FileFeatureFlagProvider = class extends FeatureFlagProvider {
|
|
|
2344
2337
|
};
|
|
2345
2338
|
let content;
|
|
2346
2339
|
if (format === "json") {
|
|
2347
|
-
content = JSON.stringify(defaultData, null,
|
|
2340
|
+
content = JSON.stringify(defaultData, null, FORMAT_CONSTANTS.JSON_INDENT_SPACES);
|
|
2348
2341
|
} else {
|
|
2349
2342
|
content = yaml.stringify(defaultData);
|
|
2350
2343
|
}
|
|
@@ -2452,7 +2445,7 @@ var FileFeatureFlagProvider = class extends FeatureFlagProvider {
|
|
|
2452
2445
|
try {
|
|
2453
2446
|
let content;
|
|
2454
2447
|
if (format === "json") {
|
|
2455
|
-
content = JSON.stringify(fileData, null,
|
|
2448
|
+
content = JSON.stringify(fileData, null, FORMAT_CONSTANTS.JSON_INDENT_SPACES);
|
|
2456
2449
|
} else {
|
|
2457
2450
|
content = yaml.stringify(fileData);
|
|
2458
2451
|
}
|
|
@@ -3990,7 +3983,7 @@ function useFeatureFlagProviderStatus() {
|
|
|
3990
3983
|
isInitialized: context.isInitialized,
|
|
3991
3984
|
isLoading: context.isLoading,
|
|
3992
3985
|
error: context.error,
|
|
3993
|
-
lastUpdated: context.lastUpdated
|
|
3986
|
+
lastUpdated: context.lastUpdated ? new Date(context.lastUpdated) : void 0
|
|
3994
3987
|
};
|
|
3995
3988
|
}
|
|
3996
3989
|
__name(useFeatureFlagProviderStatus, "useFeatureFlagProviderStatus");
|