@featurevisor/sdk 1.35.2 → 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.
Files changed (86) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -381
  3. package/coverage/clover.xml +707 -643
  4. package/coverage/coverage-final.json +11 -9
  5. package/coverage/lcov-report/{segments.ts.html → bucketer.ts.html} +155 -77
  6. package/coverage/lcov-report/child.ts.html +940 -0
  7. package/coverage/lcov-report/conditions.ts.html +107 -158
  8. package/coverage/lcov-report/datafileReader.ts.html +763 -103
  9. package/coverage/lcov-report/emitter.ts.html +77 -59
  10. package/coverage/lcov-report/evaluate.ts.html +689 -416
  11. package/coverage/lcov-report/events.ts.html +334 -0
  12. package/coverage/lcov-report/helpers.ts.html +184 -0
  13. package/coverage/lcov-report/{feature.ts.html → hooks.ts.html} +90 -237
  14. package/coverage/lcov-report/index.html +119 -89
  15. package/coverage/lcov-report/instance.ts.html +341 -773
  16. package/coverage/lcov-report/logger.ts.html +64 -64
  17. package/coverage/lcov.info +1433 -1223
  18. package/dist/bucketer.d.ts +11 -0
  19. package/dist/child.d.ts +26 -0
  20. package/dist/compareVersions.d.ts +4 -0
  21. package/dist/conditions.d.ts +4 -4
  22. package/dist/datafileReader.d.ts +26 -6
  23. package/dist/emitter.d.ts +8 -9
  24. package/dist/evaluate.d.ts +31 -29
  25. package/dist/events.d.ts +5 -0
  26. package/dist/helpers.d.ts +5 -0
  27. package/dist/hooks.d.ts +45 -0
  28. package/dist/index.d.ts +3 -2
  29. package/dist/index.js +1 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +1 -1
  32. package/dist/index.mjs.gz +0 -0
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/instance.d.ts +40 -72
  35. package/dist/logger.d.ts +6 -5
  36. package/dist/murmurhash.d.ts +1 -0
  37. package/jest.config.js +2 -0
  38. package/lib/bucketer.d.ts +11 -0
  39. package/lib/child.d.ts +26 -0
  40. package/lib/compareVersions.d.ts +4 -0
  41. package/lib/conditions.d.ts +4 -4
  42. package/lib/datafileReader.d.ts +26 -6
  43. package/lib/emitter.d.ts +8 -9
  44. package/lib/evaluate.d.ts +31 -29
  45. package/lib/events.d.ts +5 -0
  46. package/lib/helpers.d.ts +5 -0
  47. package/lib/hooks.d.ts +45 -0
  48. package/lib/index.d.ts +3 -2
  49. package/lib/instance.d.ts +40 -72
  50. package/lib/logger.d.ts +6 -5
  51. package/lib/murmurhash.d.ts +1 -0
  52. package/package.json +3 -5
  53. package/src/bucketer.spec.ts +165 -0
  54. package/src/bucketer.ts +84 -0
  55. package/src/child.spec.ts +267 -0
  56. package/src/child.ts +285 -0
  57. package/src/compareVersions.ts +93 -0
  58. package/src/conditions.spec.ts +563 -353
  59. package/src/conditions.ts +46 -63
  60. package/src/datafileReader.spec.ts +396 -84
  61. package/src/datafileReader.ts +280 -60
  62. package/src/emitter.spec.ts +27 -86
  63. package/src/emitter.ts +38 -32
  64. package/src/evaluate.ts +349 -258
  65. package/src/events.spec.ts +154 -0
  66. package/src/events.ts +83 -0
  67. package/src/helpers.ts +33 -0
  68. package/src/hooks.ts +88 -0
  69. package/src/index.ts +3 -2
  70. package/src/instance.spec.ts +305 -489
  71. package/src/instance.ts +247 -391
  72. package/src/logger.spec.ts +212 -134
  73. package/src/logger.ts +36 -36
  74. package/src/murmurhash.ts +71 -0
  75. package/coverage/lcov-report/bucket.ts.html +0 -502
  76. package/dist/bucket.d.ts +0 -30
  77. package/dist/feature.d.ts +0 -16
  78. package/dist/segments.d.ts +0 -5
  79. package/lib/bucket.d.ts +0 -30
  80. package/lib/feature.d.ts +0 -16
  81. package/lib/segments.d.ts +0 -5
  82. package/src/bucket.spec.ts +0 -37
  83. package/src/bucket.ts +0 -139
  84. package/src/feature.ts +0 -137
  85. package/src/segments.spec.ts +0 -468
  86. package/src/segments.ts +0 -58
@@ -1,99 +1,67 @@
1
- import { Context, DatafileContent, Feature, FeatureKey, InitialFeatures, StickyFeatures, VariableType, VariableValue, VariationValue, VariableKey } from "@featurevisor/types";
1
+ import type { Context, Feature, FeatureKey, StickyFeatures, EvaluatedFeatures, VariableValue, VariationValue, VariableKey, DatafileContent } from "@featurevisor/types";
2
2
  import { Logger, LogLevel } from "./logger";
3
- import { Emitter } from "./emitter";
4
- import { ConfigureBucketKey, ConfigureBucketValue } from "./bucket";
3
+ import { Hook } from "./hooks";
4
+ import { EventCallback, EventName } from "./emitter";
5
5
  import { Evaluation } from "./evaluate";
6
- export type ReadyCallback = () => void;
7
- export type ActivationCallback = (featureName: string, variation: VariationValue, context: Context, captureContext: Context) => void;
8
- export interface Statuses {
9
- ready: boolean;
10
- refreshInProgress: boolean;
6
+ import { FeaturevisorChildInstance } from "./child";
7
+ export interface OverrideOptions {
8
+ sticky?: StickyFeatures;
9
+ defaultVariationValue?: VariationValue;
10
+ defaultVariableValue?: VariableValue;
11
11
  }
12
- export type InterceptContext = (context: Context) => Context;
13
12
  export interface InstanceOptions {
14
- bucketKeySeparator?: string;
15
- configureBucketKey?: ConfigureBucketKey;
16
- configureBucketValue?: ConfigureBucketValue;
17
13
  datafile?: DatafileContent | string;
18
- datafileUrl?: string;
19
- handleDatafileFetch?: (datafileUrl: string) => Promise<DatafileContent>;
20
- initialFeatures?: InitialFeatures;
21
- interceptContext?: InterceptContext;
14
+ context?: Context;
15
+ logLevel?: LogLevel;
22
16
  logger?: Logger;
23
- onActivation?: ActivationCallback;
24
- onReady?: ReadyCallback;
25
- onRefresh?: () => void;
26
- onUpdate?: () => void;
27
- refreshInterval?: number;
28
- stickyFeatures?: StickyFeatures;
17
+ sticky?: StickyFeatures;
18
+ hooks?: Hook[];
29
19
  }
30
- export type DatafileFetchHandler = (datafileUrl: string) => Promise<DatafileContent>;
31
- type FieldType = string | VariableType;
32
- type ValueType = VariableValue;
33
- export declare function getValueByType(value: ValueType, fieldType: FieldType): ValueType;
34
20
  export declare class FeaturevisorInstance {
35
- private bucketKeySeparator;
36
- private configureBucketKey?;
37
- private configureBucketValue?;
38
- private datafileUrl?;
39
- private handleDatafileFetch?;
40
- private initialFeatures?;
41
- private interceptContext?;
21
+ private context;
42
22
  private logger;
43
- private refreshInterval?;
44
- private stickyFeatures?;
23
+ private sticky?;
45
24
  private datafileReader;
25
+ private hooksManager;
46
26
  private emitter;
47
- private statuses;
48
- private intervalId?;
49
- on: Emitter["addListener"];
50
- addListener: Emitter["addListener"];
51
- off: Emitter["removeListener"];
52
- removeListener: Emitter["removeListener"];
53
- removeAllListeners: Emitter["removeAllListeners"];
54
27
  constructor(options: InstanceOptions);
55
- setLogLevels(levels: LogLevel[]): void;
56
- onReady(): Promise<FeaturevisorInstance>;
28
+ setLogLevel(level: LogLevel): void;
57
29
  setDatafile(datafile: DatafileContent | string): void;
58
- setStickyFeatures(stickyFeatures: StickyFeatures | undefined): void;
30
+ setSticky(sticky: StickyFeatures, replace?: boolean): void;
59
31
  getRevision(): string;
60
- getFeature(featureKey: string | Feature): Feature | undefined;
32
+ getFeature(featureKey: string): Feature | undefined;
33
+ addHook(hook: Hook): () => void;
34
+ on(eventName: EventName, callback: EventCallback): () => void;
35
+ close(): void;
61
36
  /**
62
- * Statuses
37
+ * Context
63
38
  */
64
- isReady(): boolean;
65
- /**
66
- * Refresh
67
- */
68
- refresh(): void;
69
- startRefreshing(): void;
70
- stopRefreshing(): void;
39
+ setContext(context: Context, replace?: boolean): void;
40
+ getContext(context?: Context): Context;
41
+ spawn(context?: Context, options?: OverrideOptions): FeaturevisorChildInstance;
71
42
  /**
72
43
  * Flag
73
44
  */
74
- evaluateFlag(featureKey: FeatureKey | Feature, context?: Context): Evaluation;
75
- isEnabled(featureKey: FeatureKey | Feature, context?: Context): boolean;
45
+ private getEvaluationDependencies;
46
+ evaluateFlag(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): Evaluation;
47
+ isEnabled(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): boolean;
76
48
  /**
77
49
  * Variation
78
50
  */
79
- evaluateVariation(featureKey: FeatureKey | Feature, context?: Context): Evaluation;
80
- getVariation(featureKey: FeatureKey | Feature, context?: Context): VariationValue | undefined;
81
- /**
82
- * Activate
83
- */
84
- activate(featureKey: FeatureKey, context?: Context): VariationValue | undefined;
51
+ evaluateVariation(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): Evaluation;
52
+ getVariation(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): VariationValue | null;
85
53
  /**
86
54
  * Variable
87
55
  */
88
- evaluateVariable(featureKey: FeatureKey | Feature, variableKey: VariableKey, context?: Context): Evaluation;
89
- getVariable(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): VariableValue | undefined;
90
- getVariableBoolean(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): boolean | undefined;
91
- getVariableString(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): string | undefined;
92
- getVariableInteger(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): number | undefined;
93
- getVariableDouble(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): number | undefined;
94
- getVariableArray(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): string[] | undefined;
95
- getVariableObject<T>(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): T | undefined;
96
- getVariableJSON<T>(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): T | undefined;
56
+ evaluateVariable(featureKey: FeatureKey, variableKey: VariableKey, context?: Context, options?: OverrideOptions): Evaluation;
57
+ getVariable(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): VariableValue | null;
58
+ getVariableBoolean(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): boolean | null;
59
+ getVariableString(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): string | null;
60
+ getVariableInteger(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): number | null;
61
+ getVariableDouble(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): number | null;
62
+ getVariableArray(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): string[] | null;
63
+ getVariableObject<T>(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): T | null;
64
+ getVariableJSON<T>(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): T | null;
65
+ getAllEvaluations(context?: Context, featureKeys?: string[], options?: OverrideOptions): EvaluatedFeatures;
97
66
  }
98
67
  export declare function createInstance(options: InstanceOptions): FeaturevisorInstance;
99
- export {};
package/dist/logger.d.ts CHANGED
@@ -1,21 +1,22 @@
1
- export type LogLevel = "debug" | "info" | "warn" | "error";
1
+ export type LogLevel = "fatal" | "error" | "warn" | "info" | "debug";
2
2
  export type LogMessage = string;
3
3
  export interface LogDetails {
4
4
  [key: string]: any;
5
5
  }
6
6
  export type LogHandler = (level: LogLevel, message: LogMessage, details?: LogDetails) => void;
7
7
  export interface CreateLoggerOptions {
8
- levels?: LogLevel[];
8
+ level?: LogLevel;
9
9
  handler?: LogHandler;
10
10
  }
11
11
  export declare const loggerPrefix = "[Featurevisor]";
12
- export declare const defaultLogLevels: LogLevel[];
13
12
  export declare const defaultLogHandler: LogHandler;
14
13
  export declare class Logger {
15
- private levels;
14
+ static allLevels: LogLevel[];
15
+ static defaultLevel: LogLevel;
16
+ private level;
16
17
  private handle;
17
18
  constructor(options: CreateLoggerOptions);
18
- setLevels(levels: LogLevel[]): void;
19
+ setLevel(level: LogLevel): void;
19
20
  log(level: LogLevel, message: LogMessage, details?: LogDetails): void;
20
21
  debug(message: LogMessage, details?: LogDetails): void;
21
22
  info(message: LogMessage, details?: LogDetails): void;
@@ -0,0 +1 @@
1
+ export declare function MurmurHashV3(key: any, seed: any): number;
package/jest.config.js CHANGED
@@ -1,4 +1,6 @@
1
1
  module.exports = {
2
2
  preset: "ts-jest",
3
3
  bail: true,
4
+ collectCoverageFrom: ["src/**/*.ts"],
5
+ coveragePathIgnorePatterns: ["src/index.ts", "src/murmurhash.ts", "src/compareVersions.ts"],
4
6
  };
@@ -0,0 +1,11 @@
1
+ import type { BucketKey, Context, FeatureKey, BucketBy } from "@featurevisor/types";
2
+ import { Logger } from "./logger";
3
+ export declare const MAX_BUCKETED_NUMBER = 100000;
4
+ export declare function getBucketedNumber(bucketKey: string): number;
5
+ export interface GetBucketKeyOptions {
6
+ featureKey: FeatureKey;
7
+ bucketBy: BucketBy;
8
+ context: Context;
9
+ logger: Logger;
10
+ }
11
+ export declare function getBucketKey(options: GetBucketKeyOptions): BucketKey;
package/lib/child.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ import type { Context, StickyFeatures, FeatureKey, VariationValue, VariableValue, EvaluatedFeatures } from "@featurevisor/types";
2
+ import { EventName, EventCallback } from "./emitter";
3
+ import type { OverrideOptions } from "./instance";
4
+ export declare class FeaturevisorChildInstance {
5
+ private parent;
6
+ private context;
7
+ private sticky;
8
+ private emitter;
9
+ constructor(options: any);
10
+ on(eventName: EventName, callback: EventCallback): () => void;
11
+ close(): void;
12
+ setContext(context: Context, replace?: boolean): void;
13
+ getContext(context?: Context): Context;
14
+ setSticky(sticky: StickyFeatures, replace?: boolean): void;
15
+ isEnabled(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): boolean;
16
+ getVariation(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): VariationValue | null;
17
+ getVariable(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): VariableValue | null;
18
+ getVariableBoolean(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): boolean | null;
19
+ getVariableString(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): string | null;
20
+ getVariableInteger(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): number | null;
21
+ getVariableDouble(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): number | null;
22
+ getVariableArray(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): string[] | null;
23
+ getVariableObject<T>(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): T | null;
24
+ getVariableJSON<T>(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): T | null;
25
+ getAllEvaluations(context?: Context, featureKeys?: string[], options?: OverrideOptions): EvaluatedFeatures;
26
+ }
@@ -0,0 +1,4 @@
1
+ export declare const semver: RegExp;
2
+ export declare const validateAndParse: (version: string) => RegExpMatchArray;
3
+ export declare const compareSegments: (a: string | string[] | RegExpMatchArray, b: string | string[] | RegExpMatchArray) => 1 | 0 | -1;
4
+ export declare const compareVersions: (v1: string, v2: string) => 1 | 0 | -1;
@@ -1,4 +1,4 @@
1
- import { Context, Condition, PlainCondition } from "@featurevisor/types";
2
- import { Logger } from "./logger";
3
- export declare function conditionIsMatched(condition: PlainCondition, context: Context): boolean;
4
- export declare function allConditionsAreMatched(conditions: Condition[] | Condition, context: Context, logger: Logger): boolean;
1
+ import type { Context, PlainCondition, AttributeValue } from "@featurevisor/types";
2
+ import { GetRegex } from "./datafileReader";
3
+ export declare function getValueFromContext(obj: any, path: any): AttributeValue;
4
+ export declare function conditionIsMatched(condition: PlainCondition, context: Context, getRegex: GetRegex): boolean;
@@ -1,16 +1,36 @@
1
- import { Feature, Segment, DatafileContentV1, DatafileContentV2, Attribute, AttributeKey, SegmentKey, FeatureKey } from "@featurevisor/types";
2
- export declare function parseJsonConditionsIfStringified<T>(record: T, key: string): T;
1
+ import type { Feature, Segment, DatafileContent, SegmentKey, FeatureKey, Context, Traffic, Allocation, GroupSegment, Condition, Force } from "@featurevisor/types";
2
+ import { Logger } from "./logger";
3
+ export type GetRegex = (regexString: string, regexFlags: string) => RegExp;
4
+ export interface DatafileReaderOptions {
5
+ datafile: DatafileContent;
6
+ logger: Logger;
7
+ }
8
+ export interface ForceResult {
9
+ force?: Force;
10
+ forceIndex?: number;
11
+ }
3
12
  export declare class DatafileReader {
4
13
  private schemaVersion;
5
14
  private revision;
6
- private attributes;
7
15
  private segments;
8
16
  private features;
9
- constructor(datafileJson: DatafileContentV1 | DatafileContentV2);
17
+ private logger;
18
+ private regexCache;
19
+ constructor(options: DatafileReaderOptions);
10
20
  getRevision(): string;
11
21
  getSchemaVersion(): string;
12
- getAllAttributes(): Attribute[];
13
- getAttribute(attributeKey: AttributeKey): Attribute | undefined;
14
22
  getSegment(segmentKey: SegmentKey): Segment | undefined;
23
+ getFeatureKeys(): string[];
15
24
  getFeature(featureKey: FeatureKey): Feature | undefined;
25
+ getVariableKeys(featureKey: FeatureKey): string[];
26
+ hasVariations(featureKey: FeatureKey): boolean;
27
+ getRegex(regexString: string, regexFlags?: string): RegExp;
28
+ allConditionsAreMatched(conditions: Condition[] | Condition, context: Context): boolean;
29
+ segmentIsMatched(segment: Segment, context: Context): boolean;
30
+ allSegmentsAreMatched(groupSegments: GroupSegment | GroupSegment[] | "*", context: Context): boolean;
31
+ getMatchedTraffic(traffic: Traffic[], context: Context): Traffic | undefined;
32
+ getMatchedAllocation(traffic: Traffic, bucketValue: number): Allocation | undefined;
33
+ getMatchedForce(featureKey: FeatureKey | Feature, context: Context): ForceResult;
34
+ parseConditionsIfStringified(conditions: Condition | Condition[]): Condition | Condition[];
35
+ parseSegmentsIfStringified(segments: GroupSegment | GroupSegment[]): GroupSegment | GroupSegment[];
16
36
  }
package/lib/emitter.d.ts CHANGED
@@ -1,12 +1,11 @@
1
- export type EventName = "ready" | "refresh" | "update" | "activation";
2
- export interface Listeners {
3
- [key: string]: Function[];
4
- }
1
+ export type EventName = "datafile_set" | "context_set" | "sticky_set";
2
+ export type EventDetails = Record<string, unknown>;
3
+ export type EventCallback = (details: EventDetails) => void;
4
+ export type Listeners = Record<EventName, EventCallback[]> | {};
5
5
  export declare class Emitter {
6
- private _listeners;
6
+ listeners: Listeners;
7
7
  constructor();
8
- addListener(eventName: EventName, fn: Function): void;
9
- removeListener(eventName: EventName, fn: Function): void;
10
- removeAllListeners(eventName?: EventName): void;
11
- emit(eventName: EventName, ...args: any[]): void;
8
+ on(eventName: EventName, callback: EventCallback): () => void;
9
+ trigger(eventName: EventName, details?: EventDetails): void;
10
+ clearAll(): void;
12
11
  }
package/lib/evaluate.d.ts CHANGED
@@ -1,26 +1,28 @@
1
- import { Feature, FeatureKey, Context, BucketKey, BucketValue, RuleKey, Traffic, Force, Required, OverrideFeature, Variation, VariationValue, VariableKey, VariableValue, VariableSchema, StickyFeatures, InitialFeatures } from "@featurevisor/types";
1
+ import type { FeatureKey, Context, BucketKey, BucketValue, RuleKey, Traffic, Force, Required, Variation, VariationValue, VariableKey, VariableValue, VariableSchema, EvaluatedFeature, StickyFeatures } from "@featurevisor/types";
2
2
  import { Logger } from "./logger";
3
+ import { HooksManager } from "./hooks";
3
4
  import { DatafileReader } from "./datafileReader";
4
- import { ConfigureBucketKey, ConfigureBucketValue } from "./bucket";
5
- import type { Statuses, InterceptContext } from "./instance";
6
5
  export declare enum EvaluationReason {
7
- NOT_FOUND = "not_found",
8
- NO_VARIATIONS = "no_variations",
9
- NO_MATCH = "no_match",
10
- DISABLED = "disabled",
11
- REQUIRED = "required",
12
- OUT_OF_RANGE = "out_of_range",
13
- FORCED = "forced",
14
- INITIAL = "initial",
15
- STICKY = "sticky",
16
- RULE = "rule",
17
- ALLOCATED = "allocated",
18
- DEFAULTED = "defaulted",
19
- OVERRIDE = "override",
6
+ FEATURE_NOT_FOUND = "feature_not_found",// feature is not found in datafile
7
+ DISABLED = "disabled",// feature is disabled
8
+ REQUIRED = "required",// required features are not enabled
9
+ OUT_OF_RANGE = "out_of_range",// out of range when mutually exclusive experiments are involved via Groups
10
+ NO_VARIATIONS = "no_variations",// feature has no variations
11
+ VARIATION_DISABLED = "variation_disabled",// feature is disabled, and variation's disabledVariationValue is used
12
+ VARIABLE_NOT_FOUND = "variable_not_found",// variable's schema is not defined in the feature
13
+ VARIABLE_DEFAULT = "variable_default",// default variable value used
14
+ VARIABLE_DISABLED = "variable_disabled",// feature is disabled, and variable's disabledValue is used
15
+ VARIABLE_OVERRIDE = "variable_override",// variable overridden from inside a variation
16
+ NO_MATCH = "no_match",// no rules matched
17
+ FORCED = "forced",// against a forced rule
18
+ STICKY = "sticky",// against a sticky feature
19
+ RULE = "rule",// against a regular rule
20
+ ALLOCATED = "allocated",// regular allocation based on bucketing
20
21
  ERROR = "error"
21
22
  }
22
23
  type EvaluationType = "flag" | "variation" | "variable";
23
24
  export interface Evaluation {
25
+ type: EvaluationType;
24
26
  featureKey: FeatureKey;
25
27
  reason: EvaluationReason;
26
28
  bucketKey?: BucketKey;
@@ -32,28 +34,28 @@ export interface Evaluation {
32
34
  forceIndex?: number;
33
35
  force?: Force;
34
36
  required?: Required[];
35
- sticky?: OverrideFeature;
36
- initial?: OverrideFeature;
37
+ sticky?: EvaluatedFeature;
37
38
  variation?: Variation;
38
39
  variationValue?: VariationValue;
39
40
  variableKey?: VariableKey;
40
41
  variableValue?: VariableValue;
41
42
  variableSchema?: VariableSchema;
42
43
  }
43
- export interface EvaluateOptions {
44
- type: EvaluationType;
45
- featureKey: FeatureKey | Feature;
46
- variableKey?: VariableKey;
44
+ export interface EvaluateDependencies {
47
45
  context: Context;
48
46
  logger: Logger;
47
+ hooksManager: HooksManager;
49
48
  datafileReader: DatafileReader;
50
- statuses?: Statuses;
51
- interceptContext?: InterceptContext;
52
- stickyFeatures?: StickyFeatures;
53
- initialFeatures?: InitialFeatures;
54
- bucketKeySeparator?: string;
55
- configureBucketKey?: ConfigureBucketKey;
56
- configureBucketValue?: ConfigureBucketValue;
49
+ sticky?: StickyFeatures;
50
+ defaultVariationValue?: VariationValue;
51
+ defaultVariableValue?: VariableValue;
52
+ }
53
+ export interface EvaluateParams {
54
+ type: EvaluationType;
55
+ featureKey: FeatureKey;
56
+ variableKey?: VariableKey;
57
57
  }
58
+ export type EvaluateOptions = EvaluateParams & EvaluateDependencies;
59
+ export declare function evaluateWithHooks(opts: EvaluateOptions): Evaluation;
58
60
  export declare function evaluate(options: EvaluateOptions): Evaluation;
59
61
  export {};
@@ -0,0 +1,5 @@
1
+ import type { StickyFeatures } from "@featurevisor/types";
2
+ import type { EventDetails } from "./emitter";
3
+ import type { DatafileReader } from "./datafileReader";
4
+ export declare function getParamsForStickySetEvent(previousStickyFeatures: StickyFeatures, newStickyFeatures: StickyFeatures, replace: any): EventDetails;
5
+ export declare function getParamsForDatafileSetEvent(previousDatafileReader: DatafileReader, newDatafileReader: DatafileReader): EventDetails;
@@ -0,0 +1,5 @@
1
+ import type { VariableType, VariableValue } from "@featurevisor/types";
2
+ type FieldType = string | VariableType;
3
+ type ValueType = VariableValue;
4
+ export declare function getValueByType(value: ValueType, fieldType: FieldType): ValueType;
5
+ export {};
package/lib/hooks.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import type { BucketBy, BucketKey, BucketValue, Context, FeatureKey } from "@featurevisor/types";
2
+ import type { EvaluateOptions, Evaluation } from "./evaluate";
3
+ import type { Logger } from "./logger";
4
+ /**
5
+ * bucketKey
6
+ */
7
+ export interface ConfigureBucketKeyOptions {
8
+ featureKey: FeatureKey;
9
+ context: Context;
10
+ bucketBy: BucketBy;
11
+ bucketKey: string;
12
+ }
13
+ export type ConfigureBucketKey = (options: ConfigureBucketKeyOptions) => BucketKey;
14
+ /**
15
+ * bucketValue
16
+ */
17
+ export interface ConfigureBucketValueOptions {
18
+ featureKey: FeatureKey;
19
+ bucketKey: string;
20
+ context: Context;
21
+ bucketValue: number;
22
+ }
23
+ export type ConfigureBucketValue = (options: ConfigureBucketValueOptions) => BucketValue;
24
+ /**
25
+ * Hooks
26
+ */
27
+ export interface Hook {
28
+ name: string;
29
+ before?: (options: EvaluateOptions) => EvaluateOptions;
30
+ bucketKey?: ConfigureBucketKey;
31
+ bucketValue?: ConfigureBucketValue;
32
+ after?: (evaluation: Evaluation, options: EvaluateOptions) => Evaluation;
33
+ }
34
+ export interface HooksManagerOptions {
35
+ hooks?: Hook[];
36
+ logger: Logger;
37
+ }
38
+ export declare class HooksManager {
39
+ private hooks;
40
+ private logger;
41
+ constructor(options: HooksManagerOptions);
42
+ add(hook: Hook): (() => void) | undefined;
43
+ remove(name: string): void;
44
+ getAll(): Hook[];
45
+ }
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- export * from "./bucket";
1
+ export * from "./bucketer";
2
2
  export * from "./instance";
3
3
  export * from "./logger";
4
4
  export * from "./conditions";
5
- export * from "./emitter";
6
5
  export * from "./evaluate";
6
+ export * from "./datafileReader";
7
+ export * from "./child";
package/lib/instance.d.ts CHANGED
@@ -1,99 +1,67 @@
1
- import { Context, DatafileContent, Feature, FeatureKey, InitialFeatures, StickyFeatures, VariableType, VariableValue, VariationValue, VariableKey } from "@featurevisor/types";
1
+ import type { Context, Feature, FeatureKey, StickyFeatures, EvaluatedFeatures, VariableValue, VariationValue, VariableKey, DatafileContent } from "@featurevisor/types";
2
2
  import { Logger, LogLevel } from "./logger";
3
- import { Emitter } from "./emitter";
4
- import { ConfigureBucketKey, ConfigureBucketValue } from "./bucket";
3
+ import { Hook } from "./hooks";
4
+ import { EventCallback, EventName } from "./emitter";
5
5
  import { Evaluation } from "./evaluate";
6
- export type ReadyCallback = () => void;
7
- export type ActivationCallback = (featureName: string, variation: VariationValue, context: Context, captureContext: Context) => void;
8
- export interface Statuses {
9
- ready: boolean;
10
- refreshInProgress: boolean;
6
+ import { FeaturevisorChildInstance } from "./child";
7
+ export interface OverrideOptions {
8
+ sticky?: StickyFeatures;
9
+ defaultVariationValue?: VariationValue;
10
+ defaultVariableValue?: VariableValue;
11
11
  }
12
- export type InterceptContext = (context: Context) => Context;
13
12
  export interface InstanceOptions {
14
- bucketKeySeparator?: string;
15
- configureBucketKey?: ConfigureBucketKey;
16
- configureBucketValue?: ConfigureBucketValue;
17
13
  datafile?: DatafileContent | string;
18
- datafileUrl?: string;
19
- handleDatafileFetch?: (datafileUrl: string) => Promise<DatafileContent>;
20
- initialFeatures?: InitialFeatures;
21
- interceptContext?: InterceptContext;
14
+ context?: Context;
15
+ logLevel?: LogLevel;
22
16
  logger?: Logger;
23
- onActivation?: ActivationCallback;
24
- onReady?: ReadyCallback;
25
- onRefresh?: () => void;
26
- onUpdate?: () => void;
27
- refreshInterval?: number;
28
- stickyFeatures?: StickyFeatures;
17
+ sticky?: StickyFeatures;
18
+ hooks?: Hook[];
29
19
  }
30
- export type DatafileFetchHandler = (datafileUrl: string) => Promise<DatafileContent>;
31
- type FieldType = string | VariableType;
32
- type ValueType = VariableValue;
33
- export declare function getValueByType(value: ValueType, fieldType: FieldType): ValueType;
34
20
  export declare class FeaturevisorInstance {
35
- private bucketKeySeparator;
36
- private configureBucketKey?;
37
- private configureBucketValue?;
38
- private datafileUrl?;
39
- private handleDatafileFetch?;
40
- private initialFeatures?;
41
- private interceptContext?;
21
+ private context;
42
22
  private logger;
43
- private refreshInterval?;
44
- private stickyFeatures?;
23
+ private sticky?;
45
24
  private datafileReader;
25
+ private hooksManager;
46
26
  private emitter;
47
- private statuses;
48
- private intervalId?;
49
- on: Emitter["addListener"];
50
- addListener: Emitter["addListener"];
51
- off: Emitter["removeListener"];
52
- removeListener: Emitter["removeListener"];
53
- removeAllListeners: Emitter["removeAllListeners"];
54
27
  constructor(options: InstanceOptions);
55
- setLogLevels(levels: LogLevel[]): void;
56
- onReady(): Promise<FeaturevisorInstance>;
28
+ setLogLevel(level: LogLevel): void;
57
29
  setDatafile(datafile: DatafileContent | string): void;
58
- setStickyFeatures(stickyFeatures: StickyFeatures | undefined): void;
30
+ setSticky(sticky: StickyFeatures, replace?: boolean): void;
59
31
  getRevision(): string;
60
- getFeature(featureKey: string | Feature): Feature | undefined;
32
+ getFeature(featureKey: string): Feature | undefined;
33
+ addHook(hook: Hook): () => void;
34
+ on(eventName: EventName, callback: EventCallback): () => void;
35
+ close(): void;
61
36
  /**
62
- * Statuses
37
+ * Context
63
38
  */
64
- isReady(): boolean;
65
- /**
66
- * Refresh
67
- */
68
- refresh(): void;
69
- startRefreshing(): void;
70
- stopRefreshing(): void;
39
+ setContext(context: Context, replace?: boolean): void;
40
+ getContext(context?: Context): Context;
41
+ spawn(context?: Context, options?: OverrideOptions): FeaturevisorChildInstance;
71
42
  /**
72
43
  * Flag
73
44
  */
74
- evaluateFlag(featureKey: FeatureKey | Feature, context?: Context): Evaluation;
75
- isEnabled(featureKey: FeatureKey | Feature, context?: Context): boolean;
45
+ private getEvaluationDependencies;
46
+ evaluateFlag(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): Evaluation;
47
+ isEnabled(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): boolean;
76
48
  /**
77
49
  * Variation
78
50
  */
79
- evaluateVariation(featureKey: FeatureKey | Feature, context?: Context): Evaluation;
80
- getVariation(featureKey: FeatureKey | Feature, context?: Context): VariationValue | undefined;
81
- /**
82
- * Activate
83
- */
84
- activate(featureKey: FeatureKey, context?: Context): VariationValue | undefined;
51
+ evaluateVariation(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): Evaluation;
52
+ getVariation(featureKey: FeatureKey, context?: Context, options?: OverrideOptions): VariationValue | null;
85
53
  /**
86
54
  * Variable
87
55
  */
88
- evaluateVariable(featureKey: FeatureKey | Feature, variableKey: VariableKey, context?: Context): Evaluation;
89
- getVariable(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): VariableValue | undefined;
90
- getVariableBoolean(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): boolean | undefined;
91
- getVariableString(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): string | undefined;
92
- getVariableInteger(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): number | undefined;
93
- getVariableDouble(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): number | undefined;
94
- getVariableArray(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): string[] | undefined;
95
- getVariableObject<T>(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): T | undefined;
96
- getVariableJSON<T>(featureKey: FeatureKey | Feature, variableKey: string, context?: Context): T | undefined;
56
+ evaluateVariable(featureKey: FeatureKey, variableKey: VariableKey, context?: Context, options?: OverrideOptions): Evaluation;
57
+ getVariable(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): VariableValue | null;
58
+ getVariableBoolean(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): boolean | null;
59
+ getVariableString(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): string | null;
60
+ getVariableInteger(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): number | null;
61
+ getVariableDouble(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): number | null;
62
+ getVariableArray(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): string[] | null;
63
+ getVariableObject<T>(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): T | null;
64
+ getVariableJSON<T>(featureKey: FeatureKey, variableKey: string, context?: Context, options?: OverrideOptions): T | null;
65
+ getAllEvaluations(context?: Context, featureKeys?: string[], options?: OverrideOptions): EvaluatedFeatures;
97
66
  }
98
67
  export declare function createInstance(options: InstanceOptions): FeaturevisorInstance;
99
- export {};
package/lib/logger.d.ts CHANGED
@@ -1,21 +1,22 @@
1
- export type LogLevel = "debug" | "info" | "warn" | "error";
1
+ export type LogLevel = "fatal" | "error" | "warn" | "info" | "debug";
2
2
  export type LogMessage = string;
3
3
  export interface LogDetails {
4
4
  [key: string]: any;
5
5
  }
6
6
  export type LogHandler = (level: LogLevel, message: LogMessage, details?: LogDetails) => void;
7
7
  export interface CreateLoggerOptions {
8
- levels?: LogLevel[];
8
+ level?: LogLevel;
9
9
  handler?: LogHandler;
10
10
  }
11
11
  export declare const loggerPrefix = "[Featurevisor]";
12
- export declare const defaultLogLevels: LogLevel[];
13
12
  export declare const defaultLogHandler: LogHandler;
14
13
  export declare class Logger {
15
- private levels;
14
+ static allLevels: LogLevel[];
15
+ static defaultLevel: LogLevel;
16
+ private level;
16
17
  private handle;
17
18
  constructor(options: CreateLoggerOptions);
18
- setLevels(levels: LogLevel[]): void;
19
+ setLevel(level: LogLevel): void;
19
20
  log(level: LogLevel, message: LogMessage, details?: LogDetails): void;
20
21
  debug(message: LogMessage, details?: LogDetails): void;
21
22
  info(message: LogMessage, details?: LogDetails): void;
@@ -0,0 +1 @@
1
+ export declare function MurmurHashV3(key: any, seed: any): number;