@nestarc/feature-flag 0.3.0 → 0.4.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 +114 -6
- package/dist/admin/feature-flag-admin.controller.d.ts +3 -1
- package/dist/admin/feature-flag-admin.controller.js +12 -0
- package/dist/admin/feature-flag-admin.controller.js.map +1 -1
- package/dist/admin/feature-flag-admin.dto.d.ts +8 -0
- package/dist/admin/feature-flag-admin.dto.js +24 -1
- package/dist/admin/feature-flag-admin.dto.js.map +1 -1
- package/dist/events/feature-flag.events.d.ts +35 -2
- package/dist/events/feature-flag.events.js +1 -0
- package/dist/events/feature-flag.events.js.map +1 -1
- package/dist/flag-registry.d.ts +24 -0
- package/dist/flag-registry.js +62 -0
- package/dist/flag-registry.js.map +1 -0
- package/dist/guards/feature-flag.guard.js +5 -1
- package/dist/guards/feature-flag.guard.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/evaluation-context.interface.d.ts +2 -0
- package/dist/interfaces/evaluation-details.interface.d.ts +29 -0
- package/dist/interfaces/evaluation-details.interface.js +3 -0
- package/dist/interfaces/evaluation-details.interface.js.map +1 -0
- package/dist/interfaces/feature-flag-options.interface.d.ts +3 -0
- package/dist/interfaces/feature-flag.interface.d.ts +9 -0
- package/dist/interfaces/flag-registry.interface.d.ts +17 -0
- package/dist/interfaces/flag-registry.interface.js +3 -0
- package/dist/interfaces/flag-registry.interface.js.map +1 -0
- package/dist/openfeature.d.ts +26 -0
- package/dist/openfeature.js +96 -0
- package/dist/openfeature.js.map +1 -0
- package/dist/services/feature-flag.service.d.ts +14 -7
- package/dist/services/feature-flag.service.js +103 -24
- package/dist/services/feature-flag.service.js.map +1 -1
- package/dist/services/flag-evaluator.service.d.ts +7 -8
- package/dist/services/flag-evaluator.service.js +62 -10
- package/dist/services/flag-evaluator.service.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/test-feature-flag.module.d.ts +21 -0
- package/dist/testing/test-feature-flag.module.js +78 -19
- package/dist/testing/test-feature-flag.module.js.map +1 -1
- package/package.json +13 -1
|
@@ -23,6 +23,8 @@ export interface FeatureFlagGuardOptions {
|
|
|
23
23
|
statusCode?: number;
|
|
24
24
|
/** Response body when flag is OFF */
|
|
25
25
|
fallback?: Record<string, unknown>;
|
|
26
|
+
/** Invocation-level default when the guard cannot find or evaluate the flag. Default: false */
|
|
27
|
+
defaultValue?: boolean;
|
|
26
28
|
}
|
|
27
29
|
export interface FeatureFlagWithOverrides {
|
|
28
30
|
id: string;
|
|
@@ -48,3 +50,10 @@ export interface FlagOverride {
|
|
|
48
50
|
export interface RemoveOverrideInput {
|
|
49
51
|
attributes: TargetingAttributes;
|
|
50
52
|
}
|
|
53
|
+
export interface FlagMutationMetadata {
|
|
54
|
+
actorId?: string;
|
|
55
|
+
actorType?: string;
|
|
56
|
+
reason?: string;
|
|
57
|
+
requestId?: string;
|
|
58
|
+
correlationId?: string;
|
|
59
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BucketBy } from './evaluation-details.interface';
|
|
2
|
+
export type FeatureFlagType = 'release' | 'experiment' | 'ops' | 'permission';
|
|
3
|
+
export interface FeatureFlagLifecycleMetadata {
|
|
4
|
+
type?: FeatureFlagType;
|
|
5
|
+
owner?: string;
|
|
6
|
+
tags?: readonly string[];
|
|
7
|
+
expiresAt?: string | Date;
|
|
8
|
+
staleAt?: string | Date;
|
|
9
|
+
}
|
|
10
|
+
export interface FlagDefinition extends FeatureFlagLifecycleMetadata {
|
|
11
|
+
defaultValue: boolean;
|
|
12
|
+
description?: string;
|
|
13
|
+
bucketBy?: BucketBy;
|
|
14
|
+
trackExposure?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export type FlagRegistry = Record<string, FlagDefinition>;
|
|
17
|
+
export type FlagKey<TFlags extends FlagRegistry> = Extract<keyof TFlags, string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flag-registry.interface.js","sourceRoot":"","sources":["../../src/interfaces/flag-registry.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FeatureFlagService } from './services/feature-flag.service';
|
|
2
|
+
export interface OpenFeatureBooleanProviderOptions {
|
|
3
|
+
name?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface OpenFeatureEvaluationContext {
|
|
6
|
+
targetingKey?: unknown;
|
|
7
|
+
userId?: unknown;
|
|
8
|
+
tenantId?: unknown;
|
|
9
|
+
environment?: unknown;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface OpenFeatureBooleanResolutionDetails {
|
|
13
|
+
value: boolean;
|
|
14
|
+
reason: string;
|
|
15
|
+
variant?: string;
|
|
16
|
+
errorCode?: string;
|
|
17
|
+
errorMessage?: string;
|
|
18
|
+
flagMetadata: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface OpenFeatureBooleanProvider {
|
|
21
|
+
metadata: {
|
|
22
|
+
name: string;
|
|
23
|
+
};
|
|
24
|
+
resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: OpenFeatureEvaluationContext): Promise<OpenFeatureBooleanResolutionDetails>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createOpenFeatureBooleanProvider(service: FeatureFlagService, options?: OpenFeatureBooleanProviderOptions): OpenFeatureBooleanProvider;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createOpenFeatureBooleanProvider = createOpenFeatureBooleanProvider;
|
|
4
|
+
const targeting_attributes_1 = require("./utils/targeting-attributes");
|
|
5
|
+
function createOpenFeatureBooleanProvider(service, options = {}) {
|
|
6
|
+
return {
|
|
7
|
+
metadata: {
|
|
8
|
+
name: options.name ?? '@nestarc/feature-flag',
|
|
9
|
+
},
|
|
10
|
+
resolveBooleanEvaluation: async (flagKey, defaultValue, context) => {
|
|
11
|
+
try {
|
|
12
|
+
const details = await service.evaluateBoolean(flagKey, toEvaluationContext(context), { defaultValue });
|
|
13
|
+
return toOpenFeatureResolution(details);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
return {
|
|
17
|
+
value: defaultValue,
|
|
18
|
+
reason: 'ERROR',
|
|
19
|
+
errorCode: error instanceof Error ? error.constructor.name : 'Error',
|
|
20
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
21
|
+
flagMetadata: {
|
|
22
|
+
source: 'default',
|
|
23
|
+
localReason: 'ERROR',
|
|
24
|
+
defaultUsed: true,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function toEvaluationContext(context) {
|
|
32
|
+
const attributes = {};
|
|
33
|
+
for (const [key, value] of Object.entries(context)) {
|
|
34
|
+
if (isKnownContextKey(key)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if ((0, targeting_attributes_1.isTargetingAttributeValue)(value)) {
|
|
38
|
+
attributes[key] = value;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
targetingKey: readString(context.targetingKey),
|
|
43
|
+
userId: readString(context.userId),
|
|
44
|
+
tenantId: readString(context.tenantId),
|
|
45
|
+
environment: readString(context.environment) ?? undefined,
|
|
46
|
+
attributes,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function toOpenFeatureResolution(details) {
|
|
50
|
+
return {
|
|
51
|
+
value: details.value,
|
|
52
|
+
reason: mapOpenFeatureReason(details.reason),
|
|
53
|
+
errorCode: details.errorCode,
|
|
54
|
+
errorMessage: details.errorMessage,
|
|
55
|
+
flagMetadata: {
|
|
56
|
+
source: details.source,
|
|
57
|
+
localReason: details.reason,
|
|
58
|
+
defaultUsed: details.defaultUsed,
|
|
59
|
+
matchedOverrideId: details.matchedOverrideId,
|
|
60
|
+
bucket: details.bucket,
|
|
61
|
+
targetingKey: details.targetingKey,
|
|
62
|
+
evaluationTimeMs: details.evaluationTimeMs,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function mapOpenFeatureReason(reason) {
|
|
67
|
+
switch (reason) {
|
|
68
|
+
case 'OVERRIDE_MATCH':
|
|
69
|
+
return 'TARGETING_MATCH';
|
|
70
|
+
case 'PERCENTAGE_MATCH':
|
|
71
|
+
case 'PERCENTAGE_MISS':
|
|
72
|
+
return 'SPLIT';
|
|
73
|
+
case 'FLAG_NOT_FOUND':
|
|
74
|
+
case 'PERCENTAGE_NO_TARGETING_KEY':
|
|
75
|
+
return 'DEFAULT';
|
|
76
|
+
case 'ERROR':
|
|
77
|
+
return 'ERROR';
|
|
78
|
+
case 'ARCHIVED':
|
|
79
|
+
return 'DISABLED';
|
|
80
|
+
case 'GLOBAL':
|
|
81
|
+
return 'STATIC';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function isKnownContextKey(key) {
|
|
85
|
+
return (key === 'targetingKey' ||
|
|
86
|
+
key === 'userId' ||
|
|
87
|
+
key === 'tenantId' ||
|
|
88
|
+
key === 'environment');
|
|
89
|
+
}
|
|
90
|
+
function readString(value) {
|
|
91
|
+
if (value === null) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=openfeature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openfeature.js","sourceRoot":"","sources":["../src/openfeature.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { FeatureFlagModuleOptions } from '../interfaces/feature-flag-options.interface';
|
|
2
|
-
import { CreateFeatureFlagInput, UpdateFeatureFlagInput, SetOverrideInput, RemoveOverrideInput, FeatureFlagWithOverrides } from '../interfaces/feature-flag.interface';
|
|
2
|
+
import { CreateFeatureFlagInput, UpdateFeatureFlagInput, SetOverrideInput, RemoveOverrideInput, FeatureFlagWithOverrides, FlagMutationMetadata } from '../interfaces/feature-flag.interface';
|
|
3
3
|
import { EvaluationContext } from '../interfaces/evaluation-context.interface';
|
|
4
4
|
import { CacheAdapter } from '../interfaces/cache-adapter.interface';
|
|
5
5
|
import { FeatureFlagRepository } from '../interfaces/feature-flag-repository.interface';
|
|
6
6
|
import { FlagEvaluatorService } from './flag-evaluator.service';
|
|
7
7
|
import { FlagContextResolver } from './flag-context-resolver';
|
|
8
8
|
import { FlagEventPublisher } from './flag-event-publisher';
|
|
9
|
+
import { BooleanEvaluationDetails, EvaluateBooleanOptions } from '../interfaces/evaluation-details.interface';
|
|
9
10
|
export declare class FeatureFlagService {
|
|
10
11
|
private readonly options;
|
|
11
12
|
private readonly repository;
|
|
@@ -15,16 +16,17 @@ export declare class FeatureFlagService {
|
|
|
15
16
|
private readonly eventPublisher;
|
|
16
17
|
constructor(options: FeatureFlagModuleOptions, repository: FeatureFlagRepository, cacheAdapter: CacheAdapter, evaluator: FlagEvaluatorService, contextResolver: FlagContextResolver, eventPublisher: FlagEventPublisher);
|
|
17
18
|
private get cacheTtlMs();
|
|
18
|
-
isEnabled(flagKey: string, explicitContext?: EvaluationContext): Promise<boolean>;
|
|
19
|
+
isEnabled(flagKey: string, explicitContext?: EvaluationContext, evaluationOptions?: EvaluateBooleanOptions): Promise<boolean>;
|
|
20
|
+
evaluateBoolean(flagKey: string, explicitContext?: EvaluationContext, evaluationOptions?: EvaluateBooleanOptions): Promise<BooleanEvaluationDetails>;
|
|
19
21
|
evaluateAll(explicitContext?: EvaluationContext): Promise<Record<string, boolean>>;
|
|
20
|
-
create(input: CreateFeatureFlagInput): Promise<FeatureFlagWithOverrides>;
|
|
21
|
-
update(key: string, input: UpdateFeatureFlagInput): Promise<FeatureFlagWithOverrides>;
|
|
22
|
-
archive(key: string): Promise<FeatureFlagWithOverrides>;
|
|
23
|
-
setOverride(key: string, input: SetOverrideInput): Promise<void>;
|
|
22
|
+
create(input: CreateFeatureFlagInput, metadata?: FlagMutationMetadata): Promise<FeatureFlagWithOverrides>;
|
|
23
|
+
update(key: string, input: UpdateFeatureFlagInput, metadata?: FlagMutationMetadata): Promise<FeatureFlagWithOverrides>;
|
|
24
|
+
archive(key: string, metadata?: FlagMutationMetadata): Promise<FeatureFlagWithOverrides>;
|
|
25
|
+
setOverride(key: string, input: SetOverrideInput, metadata?: FlagMutationMetadata): Promise<void>;
|
|
24
26
|
findAll(): Promise<FeatureFlagWithOverrides[]>;
|
|
25
27
|
invalidateCache(): Promise<void>;
|
|
26
28
|
findByKey(key: string): Promise<FeatureFlagWithOverrides>;
|
|
27
|
-
removeOverride(key: string, input: RemoveOverrideInput): Promise<void>;
|
|
29
|
+
removeOverride(key: string, input: RemoveOverrideInput, metadata?: FlagMutationMetadata): Promise<void>;
|
|
28
30
|
private normalizeOverrideAttributes;
|
|
29
31
|
/**
|
|
30
32
|
* Best-effort cache invalidation for mutation paths.
|
|
@@ -34,4 +36,9 @@ export declare class FeatureFlagService {
|
|
|
34
36
|
private safeInvalidateCache;
|
|
35
37
|
private resolveFlag;
|
|
36
38
|
private resolveAllFlags;
|
|
39
|
+
private defaultDetails;
|
|
40
|
+
private resolveDefaultValue;
|
|
41
|
+
private shouldTrackExposure;
|
|
42
|
+
private emitEvaluation;
|
|
43
|
+
private emitExposure;
|
|
37
44
|
}
|
|
@@ -33,23 +33,38 @@ let FeatureFlagService = class FeatureFlagService {
|
|
|
33
33
|
get cacheTtlMs() {
|
|
34
34
|
return this.options.cacheTtlMs ?? 30_000;
|
|
35
35
|
}
|
|
36
|
-
async isEnabled(flagKey, explicitContext) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
const context = this.contextResolver.resolve(explicitContext);
|
|
36
|
+
async isEnabled(flagKey, explicitContext, evaluationOptions = {}) {
|
|
37
|
+
return (await this.evaluateBoolean(flagKey, explicitContext, evaluationOptions)).value;
|
|
38
|
+
}
|
|
39
|
+
async evaluateBoolean(flagKey, explicitContext, evaluationOptions = {}) {
|
|
42
40
|
const startTime = Date.now();
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
flagKey
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
let context = {};
|
|
42
|
+
try {
|
|
43
|
+
context = this.contextResolver.resolve(explicitContext);
|
|
44
|
+
const flag = await this.resolveFlag(flagKey);
|
|
45
|
+
const registryDefinition = this.options.flags?.[flagKey];
|
|
46
|
+
const details = flag
|
|
47
|
+
? {
|
|
48
|
+
...this.evaluator.evaluate(flag, context, {
|
|
49
|
+
bucketBy: registryDefinition?.bucketBy,
|
|
50
|
+
}),
|
|
51
|
+
evaluationTimeMs: Date.now() - startTime,
|
|
52
|
+
}
|
|
53
|
+
: this.defaultDetails(flagKey, 'FLAG_NOT_FOUND', startTime, evaluationOptions);
|
|
54
|
+
this.emitEvaluation(details, context, evaluationOptions);
|
|
55
|
+
if (this.shouldTrackExposure(flagKey, flag, evaluationOptions)) {
|
|
56
|
+
this.emitExposure(details, context, evaluationOptions);
|
|
57
|
+
}
|
|
58
|
+
return details;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const details = this.defaultDetails(flagKey, 'ERROR', startTime, evaluationOptions, error);
|
|
62
|
+
this.emitEvaluation(details, context, evaluationOptions);
|
|
63
|
+
if (this.shouldTrackExposure(flagKey, null, evaluationOptions)) {
|
|
64
|
+
this.emitExposure(details, context, evaluationOptions);
|
|
65
|
+
}
|
|
66
|
+
return details;
|
|
67
|
+
}
|
|
53
68
|
}
|
|
54
69
|
async evaluateAll(explicitContext) {
|
|
55
70
|
const flags = await this.resolveAllFlags();
|
|
@@ -60,25 +75,37 @@ let FeatureFlagService = class FeatureFlagService {
|
|
|
60
75
|
}
|
|
61
76
|
return result;
|
|
62
77
|
}
|
|
63
|
-
async create(input) {
|
|
78
|
+
async create(input, metadata = {}) {
|
|
64
79
|
const flag = await this.repository.createFlag(input);
|
|
65
80
|
await this.safeInvalidateCache();
|
|
66
|
-
this.eventPublisher.emit(feature_flag_events_1.FeatureFlagEvents.CREATED, {
|
|
81
|
+
this.eventPublisher.emit(feature_flag_events_1.FeatureFlagEvents.CREATED, {
|
|
82
|
+
flagKey: input.key,
|
|
83
|
+
action: 'created',
|
|
84
|
+
...metadata,
|
|
85
|
+
});
|
|
67
86
|
return flag;
|
|
68
87
|
}
|
|
69
|
-
async update(key, input) {
|
|
88
|
+
async update(key, input, metadata = {}) {
|
|
70
89
|
const flag = await this.repository.updateFlag(key, input);
|
|
71
90
|
await this.safeInvalidateCache(key);
|
|
72
|
-
this.eventPublisher.emit(feature_flag_events_1.FeatureFlagEvents.UPDATED, {
|
|
91
|
+
this.eventPublisher.emit(feature_flag_events_1.FeatureFlagEvents.UPDATED, {
|
|
92
|
+
flagKey: key,
|
|
93
|
+
action: 'updated',
|
|
94
|
+
...metadata,
|
|
95
|
+
});
|
|
73
96
|
return flag;
|
|
74
97
|
}
|
|
75
|
-
async archive(key) {
|
|
98
|
+
async archive(key, metadata = {}) {
|
|
76
99
|
const flag = await this.repository.archiveFlag(key);
|
|
77
100
|
await this.safeInvalidateCache(key);
|
|
78
|
-
this.eventPublisher.emit(feature_flag_events_1.FeatureFlagEvents.ARCHIVED, {
|
|
101
|
+
this.eventPublisher.emit(feature_flag_events_1.FeatureFlagEvents.ARCHIVED, {
|
|
102
|
+
flagKey: key,
|
|
103
|
+
action: 'archived',
|
|
104
|
+
...metadata,
|
|
105
|
+
});
|
|
79
106
|
return flag;
|
|
80
107
|
}
|
|
81
|
-
async setOverride(key, input) {
|
|
108
|
+
async setOverride(key, input, metadata = {}) {
|
|
82
109
|
const attributes = this.normalizeOverrideAttributes(input.attributes);
|
|
83
110
|
const priority = input.priority ?? 0;
|
|
84
111
|
const flagId = await this.repository.findFlagIdByKey(key);
|
|
@@ -103,6 +130,7 @@ let FeatureFlagService = class FeatureFlagService {
|
|
|
103
130
|
enabled: input.enabled,
|
|
104
131
|
priority,
|
|
105
132
|
action: 'set',
|
|
133
|
+
...metadata,
|
|
106
134
|
});
|
|
107
135
|
}
|
|
108
136
|
async findAll() {
|
|
@@ -119,7 +147,7 @@ let FeatureFlagService = class FeatureFlagService {
|
|
|
119
147
|
}
|
|
120
148
|
return flag;
|
|
121
149
|
}
|
|
122
|
-
async removeOverride(key, input) {
|
|
150
|
+
async removeOverride(key, input, metadata = {}) {
|
|
123
151
|
const attributes = this.normalizeOverrideAttributes(input.attributes);
|
|
124
152
|
const flagId = await this.repository.findFlagIdByKey(key);
|
|
125
153
|
if (!flagId) {
|
|
@@ -135,6 +163,7 @@ let FeatureFlagService = class FeatureFlagService {
|
|
|
135
163
|
flagKey: key,
|
|
136
164
|
attributes,
|
|
137
165
|
action: 'removed',
|
|
166
|
+
...metadata,
|
|
138
167
|
});
|
|
139
168
|
}
|
|
140
169
|
normalizeOverrideAttributes(input) {
|
|
@@ -179,6 +208,52 @@ let FeatureFlagService = class FeatureFlagService {
|
|
|
179
208
|
await this.cacheAdapter.setAll(flags, this.cacheTtlMs);
|
|
180
209
|
return flags;
|
|
181
210
|
}
|
|
211
|
+
defaultDetails(flagKey, reason, startTime, evaluationOptions, error) {
|
|
212
|
+
const defaultValue = this.resolveDefaultValue(flagKey, evaluationOptions);
|
|
213
|
+
const details = {
|
|
214
|
+
flagKey,
|
|
215
|
+
value: defaultValue,
|
|
216
|
+
result: defaultValue,
|
|
217
|
+
source: 'default',
|
|
218
|
+
reason,
|
|
219
|
+
defaultUsed: true,
|
|
220
|
+
evaluationTimeMs: Date.now() - startTime,
|
|
221
|
+
};
|
|
222
|
+
if (error) {
|
|
223
|
+
details.errorCode = error instanceof Error ? error.constructor.name : 'Error';
|
|
224
|
+
details.errorMessage = error instanceof Error ? error.message : String(error);
|
|
225
|
+
}
|
|
226
|
+
return details;
|
|
227
|
+
}
|
|
228
|
+
resolveDefaultValue(flagKey, evaluationOptions) {
|
|
229
|
+
return (evaluationOptions.defaultValue ??
|
|
230
|
+
this.options.flags?.[flagKey]?.defaultValue ??
|
|
231
|
+
this.options.defaultOnMissing ??
|
|
232
|
+
false);
|
|
233
|
+
}
|
|
234
|
+
shouldTrackExposure(flagKey, flag, evaluationOptions) {
|
|
235
|
+
return (evaluationOptions.trackExposure ??
|
|
236
|
+
this.options.flags?.[flagKey]?.trackExposure ??
|
|
237
|
+
readBooleanMetadata(flag?.metadata, 'trackExposure') ??
|
|
238
|
+
false);
|
|
239
|
+
}
|
|
240
|
+
emitEvaluation(details, context, evaluationOptions) {
|
|
241
|
+
const event = {
|
|
242
|
+
...details,
|
|
243
|
+
evaluationTimeMs: details.evaluationTimeMs ?? 0,
|
|
244
|
+
};
|
|
245
|
+
if (evaluationOptions.includeContextInEvent ?? true) {
|
|
246
|
+
event.context = context;
|
|
247
|
+
}
|
|
248
|
+
this.eventPublisher.emit(feature_flag_events_1.FeatureFlagEvents.EVALUATED, event);
|
|
249
|
+
}
|
|
250
|
+
emitExposure(details, context, evaluationOptions) {
|
|
251
|
+
const event = { ...details };
|
|
252
|
+
if (evaluationOptions.includeContextInEvent === true) {
|
|
253
|
+
event.context = context;
|
|
254
|
+
}
|
|
255
|
+
this.eventPublisher.emit(feature_flag_events_1.FeatureFlagEvents.EXPOSED, event);
|
|
256
|
+
}
|
|
182
257
|
};
|
|
183
258
|
exports.FeatureFlagService = FeatureFlagService;
|
|
184
259
|
exports.FeatureFlagService = FeatureFlagService = __decorate([
|
|
@@ -190,4 +265,8 @@ exports.FeatureFlagService = FeatureFlagService = __decorate([
|
|
|
190
265
|
flag_context_resolver_1.FlagContextResolver,
|
|
191
266
|
flag_event_publisher_1.FlagEventPublisher])
|
|
192
267
|
], FeatureFlagService);
|
|
268
|
+
function readBooleanMetadata(metadata, key) {
|
|
269
|
+
const value = metadata?.[key];
|
|
270
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
271
|
+
}
|
|
193
272
|
//# sourceMappingURL=feature-flag.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-flag.service.js","sourceRoot":"","sources":["../../src/services/feature-flag.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA4F;AAC5F,sEAAgH;
|
|
1
|
+
{"version":3,"file":"feature-flag.service.js","sourceRoot":"","sources":["../../src/services/feature-flag.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { FeatureFlagWithOverrides } from '../interfaces/feature-flag.interface';
|
|
2
2
|
import { EvaluationContext } from '../interfaces/evaluation-context.interface';
|
|
3
|
-
import {
|
|
4
|
-
type
|
|
5
|
-
export interface EvaluationResult {
|
|
6
|
-
result: boolean;
|
|
7
|
-
source: EvaluationSource;
|
|
8
|
-
}
|
|
3
|
+
import { BooleanEvaluationDetails, FlagEvaluatorOptions } from '../interfaces/evaluation-details.interface';
|
|
4
|
+
export type EvaluationResult = BooleanEvaluationDetails;
|
|
9
5
|
export declare class FlagEvaluatorService {
|
|
10
|
-
evaluate(flag: FeatureFlagWithOverrides, context: EvaluationContext): EvaluationResult;
|
|
6
|
+
evaluate(flag: FeatureFlagWithOverrides, context: EvaluationContext, options?: FlagEvaluatorOptions): EvaluationResult;
|
|
11
7
|
private findMatchingOverride;
|
|
8
|
+
private resolveTargetingKey;
|
|
9
|
+
private getMetadataBucketBy;
|
|
10
|
+
private readBucketValue;
|
|
11
|
+
private result;
|
|
12
12
|
}
|
|
13
|
-
export {};
|
|
@@ -11,26 +11,29 @@ const common_1 = require("@nestjs/common");
|
|
|
11
11
|
const hash_1 = require("../utils/hash");
|
|
12
12
|
const targeting_attributes_1 = require("../utils/targeting-attributes");
|
|
13
13
|
let FlagEvaluatorService = class FlagEvaluatorService {
|
|
14
|
-
evaluate(flag, context) {
|
|
14
|
+
evaluate(flag, context, options = {}) {
|
|
15
15
|
if (flag.archivedAt) {
|
|
16
|
-
return
|
|
16
|
+
return this.result(flag.key, false, 'global', 'ARCHIVED');
|
|
17
17
|
}
|
|
18
18
|
const override = this.findMatchingOverride(flag.overrides, context);
|
|
19
19
|
if (override) {
|
|
20
|
-
return
|
|
20
|
+
return this.result(flag.key, override.enabled, 'override', 'OVERRIDE_MATCH', {
|
|
21
|
+
matchedOverrideId: override.id,
|
|
22
|
+
});
|
|
21
23
|
}
|
|
22
24
|
if (flag.percentage > 0) {
|
|
23
25
|
if (flag.percentage === 100) {
|
|
24
|
-
return
|
|
26
|
+
return this.result(flag.key, true, 'percentage', 'PERCENTAGE_MATCH');
|
|
25
27
|
}
|
|
26
|
-
const
|
|
27
|
-
if (!
|
|
28
|
-
return
|
|
28
|
+
const targetingKey = this.resolveTargetingKey(flag, context, options.bucketBy);
|
|
29
|
+
if (!targetingKey) {
|
|
30
|
+
return this.result(flag.key, flag.enabled, 'global', 'PERCENTAGE_NO_TARGETING_KEY');
|
|
29
31
|
}
|
|
30
|
-
const bucket = (0, hash_1.murmurhash3)(flag.key +
|
|
31
|
-
|
|
32
|
+
const bucket = (0, hash_1.murmurhash3)(flag.key + targetingKey) % 100;
|
|
33
|
+
const enabled = bucket < flag.percentage;
|
|
34
|
+
return this.result(flag.key, enabled, 'percentage', enabled ? 'PERCENTAGE_MATCH' : 'PERCENTAGE_MISS', { bucket, targetingKey });
|
|
32
35
|
}
|
|
33
|
-
return
|
|
36
|
+
return this.result(flag.key, flag.enabled, 'global', 'GLOBAL');
|
|
34
37
|
}
|
|
35
38
|
findMatchingOverride(overrides, context) {
|
|
36
39
|
const contextAttributes = context.attributes ?? {};
|
|
@@ -38,11 +41,60 @@ let FlagEvaluatorService = class FlagEvaluatorService {
|
|
|
38
41
|
.filter((override) => (0, targeting_attributes_1.matchesTargetingAttributes)(override.attributes, contextAttributes))
|
|
39
42
|
.sort(compareOverrides)[0] ?? null);
|
|
40
43
|
}
|
|
44
|
+
resolveTargetingKey(flag, context, bucketBy) {
|
|
45
|
+
if (context.targetingKey) {
|
|
46
|
+
return context.targetingKey;
|
|
47
|
+
}
|
|
48
|
+
const configuredBucketBy = bucketBy ?? this.getMetadataBucketBy(flag.metadata);
|
|
49
|
+
if (configuredBucketBy) {
|
|
50
|
+
const configuredValue = this.readBucketValue(context, configuredBucketBy);
|
|
51
|
+
if (configuredValue) {
|
|
52
|
+
return configuredValue;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return context.userId ?? context.tenantId ?? '';
|
|
56
|
+
}
|
|
57
|
+
getMetadataBucketBy(metadata) {
|
|
58
|
+
const bucketBy = metadata.bucketBy;
|
|
59
|
+
return typeof bucketBy === 'string' && bucketBy.length > 0 ? bucketBy : undefined;
|
|
60
|
+
}
|
|
61
|
+
readBucketValue(context, bucketBy) {
|
|
62
|
+
if (bucketBy === 'userId') {
|
|
63
|
+
return context.userId ?? '';
|
|
64
|
+
}
|
|
65
|
+
if (bucketBy === 'tenantId') {
|
|
66
|
+
return context.tenantId ?? '';
|
|
67
|
+
}
|
|
68
|
+
if (bucketBy === 'environment') {
|
|
69
|
+
return context.environment ?? '';
|
|
70
|
+
}
|
|
71
|
+
if (bucketBy === 'targetingKey') {
|
|
72
|
+
return context.targetingKey ?? '';
|
|
73
|
+
}
|
|
74
|
+
return stringifyBucketValue(context.attributes?.[bucketBy]);
|
|
75
|
+
}
|
|
76
|
+
result(flagKey, value, source, reason, details = {}) {
|
|
77
|
+
return {
|
|
78
|
+
flagKey,
|
|
79
|
+
value,
|
|
80
|
+
result: value,
|
|
81
|
+
source,
|
|
82
|
+
reason,
|
|
83
|
+
defaultUsed: false,
|
|
84
|
+
...details,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
41
87
|
};
|
|
42
88
|
exports.FlagEvaluatorService = FlagEvaluatorService;
|
|
43
89
|
exports.FlagEvaluatorService = FlagEvaluatorService = __decorate([
|
|
44
90
|
(0, common_1.Injectable)()
|
|
45
91
|
], FlagEvaluatorService);
|
|
92
|
+
function stringifyBucketValue(value) {
|
|
93
|
+
if (value === undefined || value === null) {
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
return String(value);
|
|
97
|
+
}
|
|
46
98
|
function compareOverrides(a, b) {
|
|
47
99
|
const specificityDelta = Object.keys(b.attributes).length - Object.keys(a.attributes).length;
|
|
48
100
|
if (specificityDelta !== 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flag-evaluator.service.js","sourceRoot":"","sources":["../../src/services/flag-evaluator.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;
|
|
1
|
+
{"version":3,"file":"flag-evaluator.service.js","sourceRoot":"","sources":["../../src/services/flag-evaluator.service.ts"],"names":[],"mappings":"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"}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { TestFeatureFlagModule } from './test-feature-flag.module';
|
|
1
|
+
export { TestFeatureFlagController, TestFeatureFlagModule, TestFeatureFlagRegistryOptions, } from './test-feature-flag.module';
|
package/dist/testing/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TestFeatureFlagModule = void 0;
|
|
3
|
+
exports.TestFeatureFlagModule = exports.TestFeatureFlagController = void 0;
|
|
4
4
|
var test_feature_flag_module_1 = require("./test-feature-flag.module");
|
|
5
|
+
Object.defineProperty(exports, "TestFeatureFlagController", { enumerable: true, get: function () { return test_feature_flag_module_1.TestFeatureFlagController; } });
|
|
5
6
|
Object.defineProperty(exports, "TestFeatureFlagModule", { enumerable: true, get: function () { return test_feature_flag_module_1.TestFeatureFlagModule; } });
|
|
6
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":";;;AAAA,uEAIoC;AAHlC,qIAAA,yBAAyB,OAAA;AACzB,iIAAA,qBAAqB,OAAA"}
|
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import { FeatureFlagWithOverrides } from '../interfaces/feature-flag.interface';
|
|
3
|
+
import { BooleanEvaluationDetails, EvaluateBooleanOptions } from '../interfaces/evaluation-details.interface';
|
|
4
|
+
import { FlagKey, FlagRegistry } from '../interfaces/flag-registry.interface';
|
|
2
5
|
export declare class TestFeatureFlagModule {
|
|
3
6
|
static register(flags?: Record<string, boolean>): DynamicModule;
|
|
7
|
+
static registerRegistry<TFlags extends FlagRegistry>(flags: TFlags, options?: TestFeatureFlagRegistryOptions<TFlags>): DynamicModule;
|
|
8
|
+
private static createModule;
|
|
9
|
+
}
|
|
10
|
+
export interface TestFeatureFlagRegistryOptions<TFlags extends FlagRegistry> {
|
|
11
|
+
overrides?: Partial<Record<FlagKey<TFlags>, boolean>>;
|
|
12
|
+
}
|
|
13
|
+
export declare class TestFeatureFlagController<TFlags extends FlagRegistry = FlagRegistry> {
|
|
14
|
+
private readonly defaults;
|
|
15
|
+
private values;
|
|
16
|
+
constructor(defaults: Record<string, boolean>, overrides?: Partial<Record<FlagKey<TFlags>, boolean>>);
|
|
17
|
+
set<K extends FlagKey<TFlags>>(key: K, value: boolean): void;
|
|
18
|
+
reset(): void;
|
|
19
|
+
isEnabled(key: string, options?: EvaluateBooleanOptions): boolean;
|
|
20
|
+
evaluateAll(): Record<string, boolean>;
|
|
21
|
+
getDetails(key: string, options?: EvaluateBooleanOptions): BooleanEvaluationDetails;
|
|
22
|
+
findFlag(key: string): FeatureFlagWithOverrides;
|
|
23
|
+
findAll(): FeatureFlagWithOverrides[];
|
|
24
|
+
private getValue;
|
|
4
25
|
}
|