@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 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
- declare const version = "0.0.0";
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
- declare const version = "0.0.0";
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.0",
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",