@zudojs/feature-flags 1.4.2 → 1.5.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 +9 -1
- package/dist/evaluator/evaluator.core.d.ts +0 -1
- package/dist/evaluator/evaluator.core.js +0 -1
- package/dist/evaluator/evaluatorAttribute.d.ts +0 -1
- package/dist/evaluator/evaluatorAttribute.js +0 -1
- package/dist/evaluator/evaluatorGate.core.d.ts +0 -1
- package/dist/evaluator/evaluatorGate.core.js +0 -1
- package/dist/evaluator/evaluatorPattern.safety.d.ts +0 -1
- package/dist/evaluator/evaluatorPattern.safety.js +0 -1
- package/dist/evaluator/evaluatorRule.core.d.ts +0 -1
- package/dist/evaluator/evaluatorRule.core.js +7 -4
- package/dist/evaluator/index.d.ts +0 -1
- package/dist/evaluator/index.js +0 -1
- package/dist/featureFlagErrors/featureFlagError.base.d.ts +0 -1
- package/dist/featureFlagErrors/featureFlagError.base.js +0 -1
- package/dist/featureFlagErrors/featureFlagError.types.d.ts +0 -1
- package/dist/featureFlagErrors/featureFlagError.types.js +0 -1
- package/dist/featureFlagErrors/index.d.ts +0 -1
- package/dist/featureFlagErrors/index.js +0 -1
- package/dist/featureFlagTypes/featureFlag.interface.d.ts +0 -1
- package/dist/featureFlagTypes/featureFlag.interface.js +0 -1
- package/dist/featureFlagTypes/featureFlagContext.d.ts +0 -1
- package/dist/featureFlagTypes/featureFlagContext.js +0 -1
- package/dist/featureFlagTypes/featureFlagEvaluation.d.ts +0 -1
- package/dist/featureFlagTypes/featureFlagEvaluation.js +0 -1
- package/dist/featureFlagTypes/featureFlagProvider.d.ts +0 -1
- package/dist/featureFlagTypes/featureFlagProvider.js +0 -1
- package/dist/featureFlagTypes/featureFlagRule/featureFlagRule.type.d.ts +15 -1
- package/dist/featureFlagTypes/featureFlagRule/featureFlagRule.type.js +0 -1
- package/dist/featureFlagTypes/featureFlagRule/featureFlagValue.type.d.ts +0 -1
- package/dist/featureFlagTypes/featureFlagRule/featureFlagValue.type.js +0 -1
- package/dist/featureFlagTypes/featureFlagRule/index.d.ts +0 -1
- package/dist/featureFlagTypes/featureFlagRule/index.js +0 -1
- package/dist/featureFlagTypes/index.d.ts +0 -1
- package/dist/featureFlagTypes/index.js +0 -1
- package/dist/featureFlags/featureFlags.cooloff.d.ts +0 -1
- package/dist/featureFlags/featureFlags.cooloff.js +0 -1
- package/dist/featureFlags/featureFlags.core.d.ts +0 -1
- package/dist/featureFlags/featureFlags.core.js +0 -1
- package/dist/featureFlags/featureFlags.dependency.d.ts +0 -1
- package/dist/featureFlags/featureFlags.dependency.js +0 -1
- package/dist/featureFlags/featureFlags.missCache.d.ts +0 -1
- package/dist/featureFlags/featureFlags.missCache.js +0 -1
- package/dist/featureFlags/featureFlags.resolve.d.ts +0 -1
- package/dist/featureFlags/featureFlags.resolve.js +0 -1
- package/dist/featureFlags/index.d.ts +0 -1
- package/dist/featureFlags/index.js +0 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/provider/index.d.ts +0 -1
- package/dist/provider/index.js +0 -1
- package/dist/provider/providerCached.core.d.ts +0 -1
- package/dist/provider/providerCached.core.js +0 -1
- package/dist/provider/providerComposite.core.d.ts +0 -1
- package/dist/provider/providerComposite.core.js +0 -1
- package/dist/provider/providerEnvironment.core.d.ts +0 -1
- package/dist/provider/providerEnvironment.core.js +0 -1
- package/dist/provider/providerMemory.core.d.ts +0 -1
- package/dist/provider/providerMemory.core.js +0 -1
- package/dist/registry/index.d.ts +0 -1
- package/dist/registry/index.js +0 -1
- package/dist/registry/registry.core.d.ts +0 -1
- package/dist/registry/registry.core.js +0 -1
- package/dist/rollout/index.d.ts +1 -2
- package/dist/rollout/index.js +1 -2
- package/dist/rollout/rolloutBucketing.d.ts +15 -1
- package/dist/rollout/rolloutBucketing.js +19 -1
- package/dist/rollout/rolloutHashing.d.ts +0 -1
- package/dist/rollout/rolloutHashing.js +0 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/utils.helper.d.ts +0 -1
- package/dist/utils/utils.helper.js +0 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -105,7 +105,15 @@ default was `true`. For a variant flag, declare the variant to fall back to:
|
|
|
105
105
|
|
|
106
106
|
Rules are evaluated in declaration order and the first match wins. The
|
|
107
107
|
subject for `percentage` and `variant` is `userId`, then `tenantId`, then
|
|
108
|
-
`sessionId`, then `"anonymous"`.
|
|
108
|
+
`sessionId`, then `"anonymous"`. That default splits an organisation whenever
|
|
109
|
+
the context carries both a `userId` and a `tenantId`; pin the subject with
|
|
110
|
+
`bucketBy` to roll out per tenant (or per session):
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
{ type: "percentage", percentage: 10, value: true, bucketBy: "tenantId" }
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
With `bucketBy` set, a context missing that field does not match the rule.
|
|
109
117
|
|
|
110
118
|
Operators: `equals`, `not_equals`, `contains`, `starts_with`, `ends_with`,
|
|
111
119
|
`in`, `not_in`, `greater_than`, `greater_than_or_equal`, `less_than`,
|
|
@@ -35,4 +35,3 @@ export interface EvaluateFlagOptions {
|
|
|
35
35
|
* @returns A structured evaluation result.
|
|
36
36
|
*/
|
|
37
37
|
export declare function evaluateFlag<TValue extends FeatureFlagValue = FeatureFlagValue>(flag: FeatureFlag, context?: FeatureFlagContext, options?: EvaluateFlagOptions): FeatureFlagEvaluation<TValue>;
|
|
38
|
-
//# sourceMappingURL=evaluator.core.d.ts.map
|
|
@@ -28,4 +28,3 @@ export declare function resolvePath(obj: unknown, path: string): unknown;
|
|
|
28
28
|
* @returns Whether the condition matches.
|
|
29
29
|
*/
|
|
30
30
|
export declare function matchAttribute(actual: unknown, operator: FeatureFlagOperator, expected: unknown): boolean;
|
|
31
|
-
//# sourceMappingURL=evaluatorAttribute.d.ts.map
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module evaluator/evaluatorRule
|
|
7
7
|
*/
|
|
8
|
-
import { getBucket, isInRollout } from "../rollout/rolloutBucketing.js";
|
|
8
|
+
import { getBucket, isInRollout, resolveRolloutSubject, } from "../rollout/rolloutBucketing.js";
|
|
9
9
|
import { matchAttribute, resolvePath } from "./evaluatorAttribute.js";
|
|
10
10
|
/** Bucket resolution for variant assignment — 0.01% precision. */
|
|
11
11
|
const VARIANT_BUCKETS = 10_000;
|
|
@@ -42,7 +42,9 @@ export function evaluateRule(rule, context, flagKey) {
|
|
|
42
42
|
return { matched, value: matched ? (rule.result ?? true) : undefined };
|
|
43
43
|
}
|
|
44
44
|
case "percentage": {
|
|
45
|
-
const subject = context
|
|
45
|
+
const subject = resolveRolloutSubject(context, rule.bucketBy);
|
|
46
|
+
if (subject === undefined)
|
|
47
|
+
return { matched: false };
|
|
46
48
|
const matched = isInRollout(flagKey, subject, rule.percentage);
|
|
47
49
|
return { matched, value: matched ? rule.value : undefined };
|
|
48
50
|
}
|
|
@@ -58,7 +60,9 @@ export function evaluateRule(rule, context, flagKey) {
|
|
|
58
60
|
return { matched, value: matched ? rule.value : undefined };
|
|
59
61
|
}
|
|
60
62
|
case "variant": {
|
|
61
|
-
const subject = context
|
|
63
|
+
const subject = resolveRolloutSubject(context, rule.bucketBy);
|
|
64
|
+
if (subject === undefined)
|
|
65
|
+
return { matched: false };
|
|
62
66
|
// Negative or non-finite weights would make the cumulative walk
|
|
63
67
|
// non-monotonic, shifting every downstream variant's band, so they are
|
|
64
68
|
// treated as zero.
|
|
@@ -95,4 +99,3 @@ export function evaluateRule(rule, context, flagKey) {
|
|
|
95
99
|
return { matched: false };
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
|
-
//# sourceMappingURL=evaluatorRule.core.js.map
|
|
@@ -7,4 +7,3 @@ export { resolvePath, matchAttribute } from "./evaluatorAttribute.js";
|
|
|
7
7
|
export { evaluateRule } from "./evaluatorRule.core.js";
|
|
8
8
|
export type { RuleEvaluationResult } from "./evaluatorRule.core.js";
|
|
9
9
|
export { evaluateFlag } from "./evaluator.core.js";
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/evaluator/index.js
CHANGED
|
@@ -35,4 +35,3 @@ export declare class FeatureFlagConfigurationError extends FeatureFlagError {
|
|
|
35
35
|
export declare class FeatureFlagTypeError extends FeatureFlagError {
|
|
36
36
|
constructor(key: string, expected: string, actual: string);
|
|
37
37
|
}
|
|
38
|
-
//# sourceMappingURL=featureFlagError.types.d.ts.map
|
|
@@ -6,4 +6,3 @@
|
|
|
6
6
|
export { FeatureFlagError } from "./featureFlagError.base.js";
|
|
7
7
|
export type { FeatureFlagErrorOptions } from "./featureFlagError.base.js";
|
|
8
8
|
export { FeatureFlagNotFoundError, FeatureFlagProviderError, FeatureFlagEvaluationError, FeatureFlagRuleError, FeatureFlagDependencyError, FeatureFlagConfigurationError, FeatureFlagTypeError, } from "./featureFlagError.types.js";
|
|
9
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -5,4 +5,3 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { FeatureFlagError } from "./featureFlagError.base.js";
|
|
7
7
|
export { FeatureFlagNotFoundError, FeatureFlagProviderError, FeatureFlagEvaluationError, FeatureFlagRuleError, FeatureFlagDependencyError, FeatureFlagConfigurationError, FeatureFlagTypeError, } from "./featureFlagError.types.js";
|
|
8
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -42,11 +42,24 @@ export interface FeatureFlagAttributeRule {
|
|
|
42
42
|
/** The value served when the rule matches. Default: `true`. */
|
|
43
43
|
readonly result?: FeatureFlagValue;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Which context field a rollout hashes on.
|
|
47
|
+
*
|
|
48
|
+
* Without `bucketBy`, the subject is `userId`, then `tenantId`, then
|
|
49
|
+
* `sessionId`, then `"anonymous"` — so for a context carrying both a user
|
|
50
|
+
* and a tenant, members of one tenant land in different buckets. Set
|
|
51
|
+
* `bucketBy: "tenantId"` to roll a flag out per organisation. When the
|
|
52
|
+
* named field is absent from the context the rule does not match, rather
|
|
53
|
+
* than silently bucketing on something else.
|
|
54
|
+
*/
|
|
55
|
+
export type FeatureFlagBucketBy = "userId" | "tenantId" | "sessionId";
|
|
45
56
|
/** Percentage-based rollout — deterministic per subject. */
|
|
46
57
|
export interface FeatureFlagPercentageRule {
|
|
47
58
|
readonly type: "percentage";
|
|
48
59
|
readonly percentage: number;
|
|
49
60
|
readonly value: FeatureFlagValue;
|
|
61
|
+
/** Context field to bucket on; see {@link FeatureFlagBucketBy}. */
|
|
62
|
+
readonly bucketBy?: FeatureFlagBucketBy;
|
|
50
63
|
}
|
|
51
64
|
/** Time-windowed rule — enabled only within a date range. */
|
|
52
65
|
export interface FeatureFlagScheduleRule {
|
|
@@ -59,6 +72,8 @@ export interface FeatureFlagScheduleRule {
|
|
|
59
72
|
export interface FeatureFlagVariantRule {
|
|
60
73
|
readonly type: "variant";
|
|
61
74
|
readonly variants: readonly FeatureFlagVariant[];
|
|
75
|
+
/** Context field to bucket on; see {@link FeatureFlagBucketBy}. */
|
|
76
|
+
readonly bucketBy?: FeatureFlagBucketBy;
|
|
62
77
|
}
|
|
63
78
|
/** A variant with a weight for percentage-based assignment. */
|
|
64
79
|
export interface FeatureFlagVariant {
|
|
@@ -67,4 +82,3 @@ export interface FeatureFlagVariant {
|
|
|
67
82
|
}
|
|
68
83
|
/** Union of all feature flag rule types. */
|
|
69
84
|
export type FeatureFlagRule = FeatureFlagStaticRule | FeatureFlagUserRule | FeatureFlagTenantRule | FeatureFlagAttributeRule | FeatureFlagPercentageRule | FeatureFlagScheduleRule | FeatureFlagVariantRule;
|
|
70
|
-
//# sourceMappingURL=featureFlagRule.type.d.ts.map
|
|
@@ -11,4 +11,3 @@ export type FeatureFlagValue = boolean | string | number | null | Record<string,
|
|
|
11
11
|
export type FeatureFlagState = "active" | "disabled" | "archived" | "draft";
|
|
12
12
|
/** Feature flag visibility scope. */
|
|
13
13
|
export type FeatureFlagVisibility = "server" | "client";
|
|
14
|
-
//# sourceMappingURL=featureFlagValue.type.d.ts.map
|
|
@@ -6,4 +6,3 @@ export type { FeatureFlagContext } from "./featureFlagContext.js";
|
|
|
6
6
|
export type { FeatureFlagMetadata, FeatureFlag, } from "./featureFlag.interface.js";
|
|
7
7
|
export type { FeatureFlagEvaluationReason, FeatureFlagEvaluation, } from "./featureFlagEvaluation.js";
|
|
8
8
|
export type { FeatureFlagProvider, RefreshableFeatureFlagProvider, FeatureFlagChangeListener, Unsubscribe, } from "./featureFlagProvider.js";
|
|
9
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -31,4 +31,3 @@ export declare function isDependencyOn(evaluation: FeatureFlagEvaluation): boole
|
|
|
31
31
|
* @param memo - Results for this context, so a diamond is walked once.
|
|
32
32
|
*/
|
|
33
33
|
export declare function dependenciesOn(flag: FeatureFlag, registry: FeatureFlagRegistry, context: FeatureFlagContext, chain?: Set<string>, memo?: Map<string, boolean>): boolean;
|
|
34
|
-
//# sourceMappingURL=featureFlags.dependency.d.ts.map
|
|
@@ -24,4 +24,3 @@ export declare function resolveDependencies(key: string, registry: FeatureFlagRe
|
|
|
24
24
|
* Merge default context with provided context.
|
|
25
25
|
*/
|
|
26
26
|
export declare function mergeContext(defaultContext: FeatureFlagContext, context?: FeatureFlagContext): FeatureFlagContext;
|
|
27
|
-
//# sourceMappingURL=featureFlags.resolve.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { FeatureFlagError } from "./featureFlagErrors/featureFlagError.base.js";
|
|
|
10
10
|
export type { FeatureFlagErrorOptions } from "./featureFlagErrors/featureFlagError.base.js";
|
|
11
11
|
export { FeatureFlagNotFoundError, FeatureFlagProviderError, FeatureFlagEvaluationError, FeatureFlagRuleError, FeatureFlagDependencyError, FeatureFlagConfigurationError, FeatureFlagTypeError, } from "./featureFlagErrors/featureFlagError.types.js";
|
|
12
12
|
export { hashString } from "./rollout/rolloutHashing.js";
|
|
13
|
-
export { getBucket, isInRollout } from "./rollout/rolloutBucketing.js";
|
|
13
|
+
export { getBucket, isInRollout, resolveRolloutSubject, } from "./rollout/rolloutBucketing.js";
|
|
14
14
|
export { createMemoryProvider } from "./provider/providerMemory.core.js";
|
|
15
15
|
export type { MemoryFeatureFlagProvider } from "./provider/providerMemory.core.js";
|
|
16
16
|
export { createEnvironmentProvider } from "./provider/providerEnvironment.core.js";
|
|
@@ -29,4 +29,3 @@ export { createFeatureFlags } from "./featureFlags/featureFlags.core.js";
|
|
|
29
29
|
export type { FeatureFlags, FeatureFlagsOptions, } from "./featureFlags/featureFlags.core.js";
|
|
30
30
|
export { resolveDependencies, mergeContext, } from "./featureFlags/featureFlags.resolve.js";
|
|
31
31
|
export { isPlainObject, valuesEqual } from "./utils/utils.helper.js";
|
|
32
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export { FeatureFlagError } from "./featureFlagErrors/featureFlagError.base.js";
|
|
|
10
10
|
export { FeatureFlagNotFoundError, FeatureFlagProviderError, FeatureFlagEvaluationError, FeatureFlagRuleError, FeatureFlagDependencyError, FeatureFlagConfigurationError, FeatureFlagTypeError, } from "./featureFlagErrors/featureFlagError.types.js";
|
|
11
11
|
// ─── Rollout ──────────────────────────────────────────────────────────────
|
|
12
12
|
export { hashString } from "./rollout/rolloutHashing.js";
|
|
13
|
-
export { getBucket, isInRollout } from "./rollout/rolloutBucketing.js";
|
|
13
|
+
export { getBucket, isInRollout, resolveRolloutSubject, } from "./rollout/rolloutBucketing.js";
|
|
14
14
|
// ─── Providers ────────────────────────────────────────────────────────────
|
|
15
15
|
export { createMemoryProvider } from "./provider/providerMemory.core.js";
|
|
16
16
|
export { createEnvironmentProvider } from "./provider/providerEnvironment.core.js";
|
|
@@ -27,4 +27,3 @@ export { createFeatureFlags } from "./featureFlags/featureFlags.core.js";
|
|
|
27
27
|
export { resolveDependencies, mergeContext, } from "./featureFlags/featureFlags.resolve.js";
|
|
28
28
|
// ─── Utils ────────────────────────────────────────────────────────────────
|
|
29
29
|
export { isPlainObject, valuesEqual } from "./utils/utils.helper.js";
|
|
30
|
-
//# sourceMappingURL=index.js.map
|
package/dist/provider/index.d.ts
CHANGED
|
@@ -9,4 +9,3 @@ export type { EnvironmentProviderOptions } from "./providerEnvironment.core.js";
|
|
|
9
9
|
export { createCompositeProvider } from "./providerComposite.core.js";
|
|
10
10
|
export { createCachedProvider } from "./providerCached.core.js";
|
|
11
11
|
export type { CachedProviderOptions } from "./providerCached.core.js";
|
|
12
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/provider/index.js
CHANGED
|
@@ -7,4 +7,3 @@ export { createMemoryProvider } from "./providerMemory.core.js";
|
|
|
7
7
|
export { createEnvironmentProvider } from "./providerEnvironment.core.js";
|
|
8
8
|
export { createCompositeProvider } from "./providerComposite.core.js";
|
|
9
9
|
export { createCachedProvider } from "./providerCached.core.js";
|
|
10
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -25,4 +25,3 @@ export interface CachedProviderOptions {
|
|
|
25
25
|
* @returns A provider with in-memory TTL caching.
|
|
26
26
|
*/
|
|
27
27
|
export declare function createCachedProvider(inner: FeatureFlagProvider, options?: CachedProviderOptions): RefreshableFeatureFlagProvider;
|
|
28
|
-
//# sourceMappingURL=providerCached.core.d.ts.map
|
|
@@ -16,4 +16,3 @@ import type { FeatureFlagProvider, RefreshableFeatureFlagProvider } from "../fea
|
|
|
16
16
|
* @returns A composite FeatureFlagProvider.
|
|
17
17
|
*/
|
|
18
18
|
export declare function createCompositeProvider(providers: readonly FeatureFlagProvider[]): RefreshableFeatureFlagProvider;
|
|
19
|
-
//# sourceMappingURL=providerComposite.core.d.ts.map
|
|
@@ -44,4 +44,3 @@ export declare function toEnvironmentFlagKey(key: string): string;
|
|
|
44
44
|
* @returns A provider that reads from environment variables.
|
|
45
45
|
*/
|
|
46
46
|
export declare function createEnvironmentProvider(options?: EnvironmentProviderOptions): RefreshableFeatureFlagProvider;
|
|
47
|
-
//# sourceMappingURL=providerEnvironment.core.d.ts.map
|
|
@@ -30,4 +30,3 @@ export interface MemoryFeatureFlagProvider extends FeatureFlagProvider {
|
|
|
30
30
|
* @returns A FeatureFlagProvider backed by a Map.
|
|
31
31
|
*/
|
|
32
32
|
export declare function createMemoryProvider(flags?: readonly FeatureFlag[]): MemoryFeatureFlagProvider;
|
|
33
|
-
//# sourceMappingURL=providerMemory.core.d.ts.map
|
package/dist/registry/index.d.ts
CHANGED
package/dist/registry/index.js
CHANGED
package/dist/rollout/index.d.ts
CHANGED
package/dist/rollout/index.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module rollout/rolloutBucketing
|
|
8
8
|
*/
|
|
9
|
+
import type { FeatureFlagContext } from "../featureFlagTypes/featureFlagContext.js";
|
|
10
|
+
import type { FeatureFlagBucketBy } from "../featureFlagTypes/featureFlagRule/featureFlagRule.type.js";
|
|
9
11
|
/**
|
|
10
12
|
* Compute a deterministic bucket for a flag rollout.
|
|
11
13
|
*
|
|
@@ -24,4 +26,16 @@ export declare function getBucket(key: string, subject: string, buckets?: number
|
|
|
24
26
|
* @returns Whether the subject is in the rollout.
|
|
25
27
|
*/
|
|
26
28
|
export declare function isInRollout(key: string, subject: string, percentage: number): boolean;
|
|
27
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Pick the identifier a percentage or variant rule buckets on.
|
|
31
|
+
*
|
|
32
|
+
* With `bucketBy` set, only that field counts: `undefined` is returned when
|
|
33
|
+
* the context lacks it, and the caller treats the rule as not matched.
|
|
34
|
+
* Without it, the default chain applies — `userId`, then `tenantId`, then
|
|
35
|
+
* `sessionId`, then `"anonymous"`.
|
|
36
|
+
*
|
|
37
|
+
* @param context - The evaluation context.
|
|
38
|
+
* @param bucketBy - The rule's `bucketBy`, if any.
|
|
39
|
+
* @returns The subject to hash, or `undefined` when a pinned field is absent.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveRolloutSubject(context: FeatureFlagContext, bucketBy?: FeatureFlagBucketBy): string | undefined;
|
|
@@ -39,4 +39,22 @@ export function isInRollout(key, subject, percentage) {
|
|
|
39
39
|
const bucket = getBucket(key, subject, buckets);
|
|
40
40
|
return bucket < threshold;
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Pick the identifier a percentage or variant rule buckets on.
|
|
44
|
+
*
|
|
45
|
+
* With `bucketBy` set, only that field counts: `undefined` is returned when
|
|
46
|
+
* the context lacks it, and the caller treats the rule as not matched.
|
|
47
|
+
* Without it, the default chain applies — `userId`, then `tenantId`, then
|
|
48
|
+
* `sessionId`, then `"anonymous"`.
|
|
49
|
+
*
|
|
50
|
+
* @param context - The evaluation context.
|
|
51
|
+
* @param bucketBy - The rule's `bucketBy`, if any.
|
|
52
|
+
* @returns The subject to hash, or `undefined` when a pinned field is absent.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveRolloutSubject(context, bucketBy) {
|
|
55
|
+
if (bucketBy !== undefined) {
|
|
56
|
+
const pinned = context[bucketBy];
|
|
57
|
+
return typeof pinned === "string" && pinned.length > 0 ? pinned : undefined;
|
|
58
|
+
}
|
|
59
|
+
return context.userId ?? context.tenantId ?? context.sessionId ?? "anonymous";
|
|
60
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/feature-flags",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Feature flag system with deterministic rollouts, rule engine, providers, variants, snapshots, and evaluation context.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@zudojs/errors": "1.
|
|
15
|
-
"@zudojs/types": "1.
|
|
14
|
+
"@zudojs/errors": "1.4.0",
|
|
15
|
+
"@zudojs/types": "1.3.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"typescript": "7.0.2",
|