@lssm/lib.feature-flags 0.0.0-canary-20251217054315 → 0.0.0-canary-20251217060433

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,200 @@
1
+ import * as _lssm_lib_schema257 from "@lssm/lib.schema";
2
+ import { ModuleSchemaContribution } from "@lssm/lib.schema";
3
+
4
+ //#region src/entities/index.d.ts
5
+ /**
6
+ * Feature flag status enum.
7
+ */
8
+ declare const FlagStatusEnum: _lssm_lib_schema257.EntityEnumDef;
9
+ /**
10
+ * Targeting rule operator enum.
11
+ */
12
+ declare const RuleOperatorEnum: _lssm_lib_schema257.EntityEnumDef;
13
+ /**
14
+ * Experiment status enum.
15
+ */
16
+ declare const ExperimentStatusEnum: _lssm_lib_schema257.EntityEnumDef;
17
+ /**
18
+ * FeatureFlag entity - defines a feature flag.
19
+ */
20
+ declare const FeatureFlagEntity: _lssm_lib_schema257.EntitySpec<{
21
+ id: _lssm_lib_schema257.EntityScalarField;
22
+ key: _lssm_lib_schema257.EntityScalarField;
23
+ name: _lssm_lib_schema257.EntityScalarField;
24
+ description: _lssm_lib_schema257.EntityScalarField;
25
+ status: _lssm_lib_schema257.EntityEnumField;
26
+ defaultValue: _lssm_lib_schema257.EntityScalarField;
27
+ variants: _lssm_lib_schema257.EntityScalarField;
28
+ orgId: _lssm_lib_schema257.EntityScalarField;
29
+ tags: _lssm_lib_schema257.EntityScalarField;
30
+ metadata: _lssm_lib_schema257.EntityScalarField;
31
+ createdAt: _lssm_lib_schema257.EntityScalarField;
32
+ updatedAt: _lssm_lib_schema257.EntityScalarField;
33
+ targetingRules: _lssm_lib_schema257.EntityRelationField;
34
+ experiments: _lssm_lib_schema257.EntityRelationField;
35
+ evaluations: _lssm_lib_schema257.EntityRelationField;
36
+ }>;
37
+ /**
38
+ * FlagTargetingRule entity - conditions for targeting.
39
+ */
40
+ declare const FlagTargetingRuleEntity: _lssm_lib_schema257.EntitySpec<{
41
+ id: _lssm_lib_schema257.EntityScalarField;
42
+ flagId: _lssm_lib_schema257.EntityScalarField;
43
+ name: _lssm_lib_schema257.EntityScalarField;
44
+ priority: _lssm_lib_schema257.EntityScalarField;
45
+ enabled: _lssm_lib_schema257.EntityScalarField;
46
+ attribute: _lssm_lib_schema257.EntityScalarField;
47
+ operator: _lssm_lib_schema257.EntityEnumField;
48
+ value: _lssm_lib_schema257.EntityScalarField;
49
+ rolloutPercentage: _lssm_lib_schema257.EntityScalarField;
50
+ serveValue: _lssm_lib_schema257.EntityScalarField;
51
+ serveVariant: _lssm_lib_schema257.EntityScalarField;
52
+ createdAt: _lssm_lib_schema257.EntityScalarField;
53
+ updatedAt: _lssm_lib_schema257.EntityScalarField;
54
+ flag: _lssm_lib_schema257.EntityRelationField;
55
+ }>;
56
+ /**
57
+ * Experiment entity - A/B test configuration.
58
+ */
59
+ declare const ExperimentEntity: _lssm_lib_schema257.EntitySpec<{
60
+ id: _lssm_lib_schema257.EntityScalarField;
61
+ key: _lssm_lib_schema257.EntityScalarField;
62
+ name: _lssm_lib_schema257.EntityScalarField;
63
+ description: _lssm_lib_schema257.EntityScalarField;
64
+ hypothesis: _lssm_lib_schema257.EntityScalarField;
65
+ flagId: _lssm_lib_schema257.EntityScalarField;
66
+ status: _lssm_lib_schema257.EntityEnumField;
67
+ variants: _lssm_lib_schema257.EntityScalarField;
68
+ metrics: _lssm_lib_schema257.EntityScalarField;
69
+ audiencePercentage: _lssm_lib_schema257.EntityScalarField;
70
+ audienceFilter: _lssm_lib_schema257.EntityScalarField;
71
+ scheduledStartAt: _lssm_lib_schema257.EntityScalarField;
72
+ scheduledEndAt: _lssm_lib_schema257.EntityScalarField;
73
+ startedAt: _lssm_lib_schema257.EntityScalarField;
74
+ endedAt: _lssm_lib_schema257.EntityScalarField;
75
+ winningVariant: _lssm_lib_schema257.EntityScalarField;
76
+ results: _lssm_lib_schema257.EntityScalarField;
77
+ orgId: _lssm_lib_schema257.EntityScalarField;
78
+ createdAt: _lssm_lib_schema257.EntityScalarField;
79
+ updatedAt: _lssm_lib_schema257.EntityScalarField;
80
+ flag: _lssm_lib_schema257.EntityRelationField;
81
+ assignments: _lssm_lib_schema257.EntityRelationField;
82
+ }>;
83
+ /**
84
+ * ExperimentAssignment entity - tracks which variant a subject is assigned to.
85
+ */
86
+ declare const ExperimentAssignmentEntity: _lssm_lib_schema257.EntitySpec<{
87
+ id: _lssm_lib_schema257.EntityScalarField;
88
+ experimentId: _lssm_lib_schema257.EntityScalarField;
89
+ subjectType: _lssm_lib_schema257.EntityScalarField;
90
+ subjectId: _lssm_lib_schema257.EntityScalarField;
91
+ variant: _lssm_lib_schema257.EntityScalarField;
92
+ bucket: _lssm_lib_schema257.EntityScalarField;
93
+ context: _lssm_lib_schema257.EntityScalarField;
94
+ assignedAt: _lssm_lib_schema257.EntityScalarField;
95
+ experiment: _lssm_lib_schema257.EntityRelationField;
96
+ }>;
97
+ /**
98
+ * FlagEvaluation entity - evaluation log for analytics.
99
+ */
100
+ declare const FlagEvaluationEntity: _lssm_lib_schema257.EntitySpec<{
101
+ id: _lssm_lib_schema257.EntityScalarField;
102
+ flagId: _lssm_lib_schema257.EntityScalarField;
103
+ flagKey: _lssm_lib_schema257.EntityScalarField;
104
+ subjectType: _lssm_lib_schema257.EntityScalarField;
105
+ subjectId: _lssm_lib_schema257.EntityScalarField;
106
+ result: _lssm_lib_schema257.EntityScalarField;
107
+ variant: _lssm_lib_schema257.EntityScalarField;
108
+ matchedRuleId: _lssm_lib_schema257.EntityScalarField;
109
+ reason: _lssm_lib_schema257.EntityScalarField;
110
+ context: _lssm_lib_schema257.EntityScalarField;
111
+ evaluatedAt: _lssm_lib_schema257.EntityScalarField;
112
+ flag: _lssm_lib_schema257.EntityRelationField;
113
+ }>;
114
+ /**
115
+ * All feature flag entities for schema composition.
116
+ */
117
+ declare const featureFlagEntities: (_lssm_lib_schema257.EntitySpec<{
118
+ id: _lssm_lib_schema257.EntityScalarField;
119
+ key: _lssm_lib_schema257.EntityScalarField;
120
+ name: _lssm_lib_schema257.EntityScalarField;
121
+ description: _lssm_lib_schema257.EntityScalarField;
122
+ status: _lssm_lib_schema257.EntityEnumField;
123
+ defaultValue: _lssm_lib_schema257.EntityScalarField;
124
+ variants: _lssm_lib_schema257.EntityScalarField;
125
+ orgId: _lssm_lib_schema257.EntityScalarField;
126
+ tags: _lssm_lib_schema257.EntityScalarField;
127
+ metadata: _lssm_lib_schema257.EntityScalarField;
128
+ createdAt: _lssm_lib_schema257.EntityScalarField;
129
+ updatedAt: _lssm_lib_schema257.EntityScalarField;
130
+ targetingRules: _lssm_lib_schema257.EntityRelationField;
131
+ experiments: _lssm_lib_schema257.EntityRelationField;
132
+ evaluations: _lssm_lib_schema257.EntityRelationField;
133
+ }> | _lssm_lib_schema257.EntitySpec<{
134
+ id: _lssm_lib_schema257.EntityScalarField;
135
+ flagId: _lssm_lib_schema257.EntityScalarField;
136
+ name: _lssm_lib_schema257.EntityScalarField;
137
+ priority: _lssm_lib_schema257.EntityScalarField;
138
+ enabled: _lssm_lib_schema257.EntityScalarField;
139
+ attribute: _lssm_lib_schema257.EntityScalarField;
140
+ operator: _lssm_lib_schema257.EntityEnumField;
141
+ value: _lssm_lib_schema257.EntityScalarField;
142
+ rolloutPercentage: _lssm_lib_schema257.EntityScalarField;
143
+ serveValue: _lssm_lib_schema257.EntityScalarField;
144
+ serveVariant: _lssm_lib_schema257.EntityScalarField;
145
+ createdAt: _lssm_lib_schema257.EntityScalarField;
146
+ updatedAt: _lssm_lib_schema257.EntityScalarField;
147
+ flag: _lssm_lib_schema257.EntityRelationField;
148
+ }> | _lssm_lib_schema257.EntitySpec<{
149
+ id: _lssm_lib_schema257.EntityScalarField;
150
+ key: _lssm_lib_schema257.EntityScalarField;
151
+ name: _lssm_lib_schema257.EntityScalarField;
152
+ description: _lssm_lib_schema257.EntityScalarField;
153
+ hypothesis: _lssm_lib_schema257.EntityScalarField;
154
+ flagId: _lssm_lib_schema257.EntityScalarField;
155
+ status: _lssm_lib_schema257.EntityEnumField;
156
+ variants: _lssm_lib_schema257.EntityScalarField;
157
+ metrics: _lssm_lib_schema257.EntityScalarField;
158
+ audiencePercentage: _lssm_lib_schema257.EntityScalarField;
159
+ audienceFilter: _lssm_lib_schema257.EntityScalarField;
160
+ scheduledStartAt: _lssm_lib_schema257.EntityScalarField;
161
+ scheduledEndAt: _lssm_lib_schema257.EntityScalarField;
162
+ startedAt: _lssm_lib_schema257.EntityScalarField;
163
+ endedAt: _lssm_lib_schema257.EntityScalarField;
164
+ winningVariant: _lssm_lib_schema257.EntityScalarField;
165
+ results: _lssm_lib_schema257.EntityScalarField;
166
+ orgId: _lssm_lib_schema257.EntityScalarField;
167
+ createdAt: _lssm_lib_schema257.EntityScalarField;
168
+ updatedAt: _lssm_lib_schema257.EntityScalarField;
169
+ flag: _lssm_lib_schema257.EntityRelationField;
170
+ assignments: _lssm_lib_schema257.EntityRelationField;
171
+ }> | _lssm_lib_schema257.EntitySpec<{
172
+ id: _lssm_lib_schema257.EntityScalarField;
173
+ experimentId: _lssm_lib_schema257.EntityScalarField;
174
+ subjectType: _lssm_lib_schema257.EntityScalarField;
175
+ subjectId: _lssm_lib_schema257.EntityScalarField;
176
+ variant: _lssm_lib_schema257.EntityScalarField;
177
+ bucket: _lssm_lib_schema257.EntityScalarField;
178
+ context: _lssm_lib_schema257.EntityScalarField;
179
+ assignedAt: _lssm_lib_schema257.EntityScalarField;
180
+ experiment: _lssm_lib_schema257.EntityRelationField;
181
+ }> | _lssm_lib_schema257.EntitySpec<{
182
+ id: _lssm_lib_schema257.EntityScalarField;
183
+ flagId: _lssm_lib_schema257.EntityScalarField;
184
+ flagKey: _lssm_lib_schema257.EntityScalarField;
185
+ subjectType: _lssm_lib_schema257.EntityScalarField;
186
+ subjectId: _lssm_lib_schema257.EntityScalarField;
187
+ result: _lssm_lib_schema257.EntityScalarField;
188
+ variant: _lssm_lib_schema257.EntityScalarField;
189
+ matchedRuleId: _lssm_lib_schema257.EntityScalarField;
190
+ reason: _lssm_lib_schema257.EntityScalarField;
191
+ context: _lssm_lib_schema257.EntityScalarField;
192
+ evaluatedAt: _lssm_lib_schema257.EntityScalarField;
193
+ flag: _lssm_lib_schema257.EntityRelationField;
194
+ }>)[];
195
+ /**
196
+ * Module schema contribution for feature flags.
197
+ */
198
+ declare const featureFlagsSchemaContribution: ModuleSchemaContribution;
199
+ //#endregion
200
+ export { ExperimentAssignmentEntity, ExperimentEntity, ExperimentStatusEnum, FeatureFlagEntity, FlagEvaluationEntity, FlagStatusEnum, FlagTargetingRuleEntity, RuleOperatorEnum, featureFlagEntities, featureFlagsSchemaContribution };
@@ -0,0 +1,162 @@
1
+ //#region src/evaluation/index.d.ts
2
+ /**
3
+ * Feature flag evaluation engine.
4
+ *
5
+ * Provides deterministic evaluation of feature flags based on targeting rules
6
+ * and experiment assignments.
7
+ */
8
+ interface EvaluationContext {
9
+ /** User identifier */
10
+ userId?: string;
11
+ /** Organization identifier */
12
+ orgId?: string;
13
+ /** User's plan (free, pro, enterprise, etc.) */
14
+ plan?: string;
15
+ /** User segment or cohort */
16
+ segment?: string;
17
+ /** Session identifier for anonymous users */
18
+ sessionId?: string;
19
+ /** Additional custom attributes */
20
+ attributes?: Record<string, unknown>;
21
+ }
22
+ interface FeatureFlag {
23
+ id: string;
24
+ key: string;
25
+ status: 'OFF' | 'ON' | 'GRADUAL';
26
+ defaultValue: boolean;
27
+ variants?: VariantConfig[];
28
+ }
29
+ interface TargetingRule {
30
+ id: string;
31
+ priority: number;
32
+ enabled: boolean;
33
+ attribute: string;
34
+ operator: RuleOperator;
35
+ value: unknown;
36
+ rolloutPercentage?: number;
37
+ serveValue?: boolean;
38
+ serveVariant?: string;
39
+ }
40
+ interface Experiment {
41
+ id: string;
42
+ key: string;
43
+ status: 'DRAFT' | 'RUNNING' | 'PAUSED' | 'COMPLETED' | 'CANCELLED';
44
+ variants: ExperimentVariant[];
45
+ audiencePercentage: number;
46
+ audienceFilter?: Record<string, unknown>;
47
+ }
48
+ interface VariantConfig {
49
+ key: string;
50
+ name: string;
51
+ description?: string;
52
+ weight?: number;
53
+ }
54
+ interface ExperimentVariant {
55
+ key: string;
56
+ name: string;
57
+ percentage: number;
58
+ }
59
+ interface EvaluationResult {
60
+ enabled: boolean;
61
+ variant?: string;
62
+ reason: EvaluationReason;
63
+ ruleId?: string;
64
+ experimentId?: string;
65
+ }
66
+ type EvaluationReason = 'FLAG_OFF' | 'FLAG_ON' | 'DEFAULT_VALUE' | 'RULE_MATCH' | 'PERCENTAGE_ROLLOUT' | 'EXPERIMENT_VARIANT' | 'FLAG_NOT_FOUND';
67
+ type RuleOperator = 'EQ' | 'NEQ' | 'IN' | 'NIN' | 'CONTAINS' | 'NOT_CONTAINS' | 'GT' | 'GTE' | 'LT' | 'LTE' | 'PERCENTAGE';
68
+ /**
69
+ * Simple hash function for consistent bucketing.
70
+ * Uses a deterministic algorithm so the same input always produces the same bucket.
71
+ */
72
+ declare function hashToBucket(value: string, seed?: string): number;
73
+ /**
74
+ * Get subject identifier from context for consistent hashing.
75
+ */
76
+ declare function getSubjectId(context: EvaluationContext): string;
77
+ /**
78
+ * Evaluate a single targeting rule condition.
79
+ */
80
+ declare function evaluateRuleCondition(rule: TargetingRule, context: EvaluationContext): boolean;
81
+ interface FlagRepository {
82
+ getFlag(key: string, orgId?: string): Promise<FeatureFlag | null>;
83
+ getRules(flagId: string): Promise<TargetingRule[]>;
84
+ getActiveExperiment(flagId: string): Promise<Experiment | null>;
85
+ getExperimentAssignment(experimentId: string, subjectType: string, subjectId: string): Promise<string | null>;
86
+ saveExperimentAssignment(experimentId: string, subjectType: string, subjectId: string, variant: string, bucket: number): Promise<void>;
87
+ }
88
+ interface EvaluationLogger {
89
+ log(evaluation: {
90
+ flagId: string;
91
+ flagKey: string;
92
+ subjectType: string;
93
+ subjectId: string;
94
+ result: boolean;
95
+ variant?: string;
96
+ reason: string;
97
+ ruleId?: string;
98
+ experimentId?: string;
99
+ context?: EvaluationContext;
100
+ }): void;
101
+ }
102
+ interface FlagEvaluatorOptions {
103
+ repository: FlagRepository;
104
+ logger?: EvaluationLogger;
105
+ /** Whether to log evaluations (default: false for performance) */
106
+ logEvaluations?: boolean;
107
+ }
108
+ /**
109
+ * Feature flag evaluator.
110
+ *
111
+ * Evaluates flags based on:
112
+ * 1. Flag status (OFF/ON/GRADUAL)
113
+ * 2. Targeting rules (in priority order)
114
+ * 3. Experiments (if running)
115
+ * 4. Default value (fallback)
116
+ */
117
+ declare class FlagEvaluator {
118
+ private repository;
119
+ private logger?;
120
+ private logEvaluations;
121
+ constructor(options: FlagEvaluatorOptions);
122
+ /**
123
+ * Evaluate a feature flag.
124
+ */
125
+ evaluate(key: string, context: EvaluationContext): Promise<EvaluationResult>;
126
+ /**
127
+ * Evaluate experiment and assign variant.
128
+ */
129
+ private evaluateExperiment;
130
+ /**
131
+ * Assign a variant based on bucket and variant percentages.
132
+ */
133
+ private assignVariant;
134
+ /**
135
+ * Create evaluation result.
136
+ */
137
+ private makeResult;
138
+ /**
139
+ * Log evaluation and return result.
140
+ */
141
+ private logAndReturn;
142
+ }
143
+ /**
144
+ * In-memory flag repository for testing and development.
145
+ */
146
+ declare class InMemoryFlagRepository implements FlagRepository {
147
+ private flags;
148
+ private rules;
149
+ private experiments;
150
+ private assignments;
151
+ addFlag(flag: FeatureFlag): void;
152
+ addRule(flagId: string, rule: TargetingRule): void;
153
+ addExperiment(experiment: Experiment, flagId: string): void;
154
+ getFlag(key: string): Promise<FeatureFlag | null>;
155
+ getRules(flagId: string): Promise<TargetingRule[]>;
156
+ getActiveExperiment(flagId: string): Promise<Experiment | null>;
157
+ getExperimentAssignment(experimentId: string, subjectType: string, subjectId: string): Promise<string | null>;
158
+ saveExperimentAssignment(experimentId: string, subjectType: string, subjectId: string, variant: string): Promise<void>;
159
+ clear(): void;
160
+ }
161
+ //#endregion
162
+ export { EvaluationContext, EvaluationLogger, EvaluationReason, EvaluationResult, Experiment, ExperimentVariant, FeatureFlag, FlagEvaluator, FlagEvaluatorOptions, FlagRepository, InMemoryFlagRepository, RuleOperator, TargetingRule, VariantConfig, evaluateRuleCondition, getSubjectId, hashToBucket };