@flaghoist/core 0.1.0 → 0.1.2
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 +45 -0
- package/dist/index.cjs +7 -8
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +6 -6
- package/package.json +17 -1
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @flaghoist/core
|
|
2
|
+
|
|
3
|
+
The evaluation engine behind Flaghoist. Flag schema, targeting rules, percentage rollouts, and the
|
|
4
|
+
storage and auth interfaces the rest of the packages build on.
|
|
5
|
+
|
|
6
|
+
Zero dependencies, and no knowledge of HTTP or of where flags are stored.
|
|
7
|
+
|
|
8
|
+
You usually get this as a dependency of `@flaghoist/server` rather than installing it yourself.
|
|
9
|
+
Install it directly if you are writing a storage adapter, or if you want to evaluate flags in
|
|
10
|
+
process without running a server.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @flaghoist/core
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { evaluate, createFlag } from '@flaghoist/core'
|
|
18
|
+
|
|
19
|
+
const flag = createFlag('new-checkout', {
|
|
20
|
+
enabled: true,
|
|
21
|
+
rollout: { percentage: 25 },
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const result = evaluate(flag.flag, { targetingKey: 'user-123', plan: 'pro' })
|
|
25
|
+
// { value: true, reason: 'SPLIT', ... }
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## How evaluation works
|
|
29
|
+
|
|
30
|
+
Rules are ordered and the first match wins, with conditions inside a rule combined with AND. If no
|
|
31
|
+
rule matches, the percentage rollout decides.
|
|
32
|
+
|
|
33
|
+
Rollouts bucket users with SHA-256 over the targeting key, so the same user always lands in the same
|
|
34
|
+
place. Going from 10 percent to 20 percent adds people without reshuffling the ones already in.
|
|
35
|
+
|
|
36
|
+
Flags are boolean. There are no multivariate values, and evaluation returns a reason so you can tell
|
|
37
|
+
why you got what you got.
|
|
38
|
+
|
|
39
|
+
## Status
|
|
40
|
+
|
|
41
|
+
Pre-alpha, built and maintained by one person. The API can still change without notice, and
|
|
42
|
+
production use is not recommended yet. If you try it and something breaks, an issue is genuinely
|
|
43
|
+
useful.
|
|
44
|
+
|
|
45
|
+
Apache-2.0. Part of [Flaghoist](https://github.com/flaghoist/flaghoist).
|
package/dist/index.cjs
CHANGED
|
@@ -33,8 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
matchCondition: () => matchCondition,
|
|
34
34
|
matchesAllConditions: () => matchesAllConditions,
|
|
35
35
|
parseFlag: () => parseFlag,
|
|
36
|
-
stickyBucket: () => stickyBucket
|
|
37
|
-
version: () => version
|
|
36
|
+
stickyBucket: () => stickyBucket
|
|
38
37
|
});
|
|
39
38
|
module.exports = __toCommonJS(index_exports);
|
|
40
39
|
|
|
@@ -62,7 +61,8 @@ var LIMITS = {
|
|
|
62
61
|
maxRules: 100,
|
|
63
62
|
maxConditionsPerRule: 50,
|
|
64
63
|
maxListItems: 1e3,
|
|
65
|
-
maxValueLength: 1024
|
|
64
|
+
maxValueLength: 1024,
|
|
65
|
+
maxDescriptionLength: 2048
|
|
66
66
|
};
|
|
67
67
|
var FLAG_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
68
68
|
var FORBIDDEN_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
@@ -250,6 +250,9 @@ function parseFlag(input) {
|
|
|
250
250
|
if (typeof o.enabled !== "boolean") return null;
|
|
251
251
|
const rollout = asRecord(o.rollout);
|
|
252
252
|
const percentage = rollout && typeof rollout.percentage === "number" ? clampPercentage(rollout.percentage) : 0;
|
|
253
|
+
if (typeof o.description === "string" && o.description.length > LIMITS.maxDescriptionLength) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
253
256
|
const rawRules = Array.isArray(o.rules) ? o.rules : [];
|
|
254
257
|
if (rawRules.length > LIMITS.maxRules) return null;
|
|
255
258
|
const rules = rawRules.map(parseRule).filter((r) => r !== null);
|
|
@@ -277,9 +280,6 @@ function createFlag(input) {
|
|
|
277
280
|
metadata: { createdBy: identity, createdAt: now, updatedBy: identity, updatedAt: now }
|
|
278
281
|
};
|
|
279
282
|
}
|
|
280
|
-
|
|
281
|
-
// src/index.ts
|
|
282
|
-
var version = "0.0.0";
|
|
283
283
|
// Annotate the CommonJS export names for ESM import in node:
|
|
284
284
|
0 && (module.exports = {
|
|
285
285
|
FLAG_KEY_RULE,
|
|
@@ -295,6 +295,5 @@ var version = "0.0.0";
|
|
|
295
295
|
matchCondition,
|
|
296
296
|
matchesAllConditions,
|
|
297
297
|
parseFlag,
|
|
298
|
-
stickyBucket
|
|
299
|
-
version
|
|
298
|
+
stickyBucket
|
|
300
299
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -117,6 +117,7 @@ declare const LIMITS: {
|
|
|
117
117
|
readonly maxConditionsPerRule: 50;
|
|
118
118
|
readonly maxListItems: 1000;
|
|
119
119
|
readonly maxValueLength: 1024;
|
|
120
|
+
readonly maxDescriptionLength: 2048;
|
|
120
121
|
};
|
|
121
122
|
/**
|
|
122
123
|
* Attribute names that resolve onto the prototype chain rather than to real data. They are
|
|
@@ -185,6 +186,4 @@ interface CreateFlagInput {
|
|
|
185
186
|
*/
|
|
186
187
|
declare function createFlag(input: CreateFlagInput): FeatureFlag;
|
|
187
188
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
export { type AttributeValue, type AuthContext, type AuthVerifier, type Condition, type ConditionValue, type CreateFlagInput, type EvaluationContext, type EvaluationReason, type EvaluationResult, FLAG_KEY_RULE, FORBIDDEN_ATTRIBUTES, type FeatureFlag, type FlagMetadata, LIMITS, type Operator, type RuleResult, type StorageAdapter, type TargetingRule, clampPercentage, compareSemver, createFlag, evaluate, evaluateAll, isInRollout, isValidFlagKey, matchCondition, matchesAllConditions, parseFlag, stickyBucket, version };
|
|
189
|
+
export { type AttributeValue, type AuthContext, type AuthVerifier, type Condition, type ConditionValue, type CreateFlagInput, type EvaluationContext, type EvaluationReason, type EvaluationResult, FLAG_KEY_RULE, FORBIDDEN_ATTRIBUTES, type FeatureFlag, type FlagMetadata, LIMITS, type Operator, type RuleResult, type StorageAdapter, type TargetingRule, clampPercentage, compareSemver, createFlag, evaluate, evaluateAll, isInRollout, isValidFlagKey, matchCondition, matchesAllConditions, parseFlag, stickyBucket };
|
package/dist/index.d.ts
CHANGED
|
@@ -117,6 +117,7 @@ declare const LIMITS: {
|
|
|
117
117
|
readonly maxConditionsPerRule: 50;
|
|
118
118
|
readonly maxListItems: 1000;
|
|
119
119
|
readonly maxValueLength: 1024;
|
|
120
|
+
readonly maxDescriptionLength: 2048;
|
|
120
121
|
};
|
|
121
122
|
/**
|
|
122
123
|
* Attribute names that resolve onto the prototype chain rather than to real data. They are
|
|
@@ -185,6 +186,4 @@ interface CreateFlagInput {
|
|
|
185
186
|
*/
|
|
186
187
|
declare function createFlag(input: CreateFlagInput): FeatureFlag;
|
|
187
188
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
export { type AttributeValue, type AuthContext, type AuthVerifier, type Condition, type ConditionValue, type CreateFlagInput, type EvaluationContext, type EvaluationReason, type EvaluationResult, FLAG_KEY_RULE, FORBIDDEN_ATTRIBUTES, type FeatureFlag, type FlagMetadata, LIMITS, type Operator, type RuleResult, type StorageAdapter, type TargetingRule, clampPercentage, compareSemver, createFlag, evaluate, evaluateAll, isInRollout, isValidFlagKey, matchCondition, matchesAllConditions, parseFlag, stickyBucket, version };
|
|
189
|
+
export { type AttributeValue, type AuthContext, type AuthVerifier, type Condition, type ConditionValue, type CreateFlagInput, type EvaluationContext, type EvaluationReason, type EvaluationResult, FLAG_KEY_RULE, FORBIDDEN_ATTRIBUTES, type FeatureFlag, type FlagMetadata, LIMITS, type Operator, type RuleResult, type StorageAdapter, type TargetingRule, clampPercentage, compareSemver, createFlag, evaluate, evaluateAll, isInRollout, isValidFlagKey, matchCondition, matchesAllConditions, parseFlag, stickyBucket };
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,8 @@ var LIMITS = {
|
|
|
22
22
|
maxRules: 100,
|
|
23
23
|
maxConditionsPerRule: 50,
|
|
24
24
|
maxListItems: 1e3,
|
|
25
|
-
maxValueLength: 1024
|
|
25
|
+
maxValueLength: 1024,
|
|
26
|
+
maxDescriptionLength: 2048
|
|
26
27
|
};
|
|
27
28
|
var FLAG_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
28
29
|
var FORBIDDEN_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
@@ -210,6 +211,9 @@ function parseFlag(input) {
|
|
|
210
211
|
if (typeof o.enabled !== "boolean") return null;
|
|
211
212
|
const rollout = asRecord(o.rollout);
|
|
212
213
|
const percentage = rollout && typeof rollout.percentage === "number" ? clampPercentage(rollout.percentage) : 0;
|
|
214
|
+
if (typeof o.description === "string" && o.description.length > LIMITS.maxDescriptionLength) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
213
217
|
const rawRules = Array.isArray(o.rules) ? o.rules : [];
|
|
214
218
|
if (rawRules.length > LIMITS.maxRules) return null;
|
|
215
219
|
const rules = rawRules.map(parseRule).filter((r) => r !== null);
|
|
@@ -237,9 +241,6 @@ function createFlag(input) {
|
|
|
237
241
|
metadata: { createdBy: identity, createdAt: now, updatedBy: identity, updatedAt: now }
|
|
238
242
|
};
|
|
239
243
|
}
|
|
240
|
-
|
|
241
|
-
// src/index.ts
|
|
242
|
-
var version = "0.0.0";
|
|
243
244
|
export {
|
|
244
245
|
FLAG_KEY_RULE,
|
|
245
246
|
FORBIDDEN_ATTRIBUTES,
|
|
@@ -254,6 +255,5 @@ export {
|
|
|
254
255
|
matchCondition,
|
|
255
256
|
matchesAllConditions,
|
|
256
257
|
parseFlag,
|
|
257
|
-
stickyBucket
|
|
258
|
-
version
|
|
258
|
+
stickyBucket
|
|
259
259
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flaghoist/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Flag schema, evaluation engine, and storage/auth interfaces for Flaghoist. Zero dependencies.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -29,6 +29,22 @@
|
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"feature-flags",
|
|
34
|
+
"feature-toggles",
|
|
35
|
+
"evaluation",
|
|
36
|
+
"targeting",
|
|
37
|
+
"percentage-rollout"
|
|
38
|
+
],
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/flaghoist/flaghoist.git",
|
|
42
|
+
"directory": "packages/core"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/flaghoist/flaghoist#readme",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/flaghoist/flaghoist/issues"
|
|
47
|
+
},
|
|
32
48
|
"scripts": {
|
|
33
49
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
34
50
|
"test": "vitest run --passWithNoTests",
|