@guidelytech/flags 0.0.0-stage → 0.7.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/LICENSE +21 -0
- package/README.md +134 -2
- package/dist/chunk-OY4QS3WL.js +804 -0
- package/dist/chunk-OY4QS3WL.js.map +1 -0
- package/dist/chunk-ZTY7K7P2.js +988 -0
- package/dist/chunk-ZTY7K7P2.js.map +1 -0
- package/dist/cli.cjs +1920 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +229 -0
- package/dist/cli.js.map +1 -0
- package/dist/evaluate.cjs +835 -0
- package/dist/evaluate.cjs.map +1 -0
- package/dist/evaluate.d.cts +283 -0
- package/dist/evaluate.d.ts +283 -0
- package/dist/evaluate.js +57 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/index.cjs +1884 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +314 -0
- package/dist/index.d.ts +314 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/evaluate.ts","../src/hash.ts","../src/values.ts","../src/types.ts"],"sourcesContent":["/**\n * Pure, synchronous flag evaluation — the reference implementation of docs/feature-flags-spec.md §3.\n * No I/O: give it a payload and attributes, get a result. Used by every TypeScript SDK and by the\n * Guidely server for remote evaluation and the dashboard's test panel.\n */\nimport { hashBucket, hashConfidential, utf8 } from \"./hash\";\nimport type { AttributeCondition, Attributes, Condition, EvaluationResult, ExperimentRule, FlagComparisonOperator, FlagDefinition, FlagRule, FlagsPayload, JsonValue, RuleSchedule, StickyAssignments, StickyBucketStore } from \"./types\";\nimport { arrayOf, compareSemver, instantOf, isOn, jsonEquals, jsonTypeOf, numberOf, parseSemver, textOf } from \"./values\";\n\nexport * from \"./types\";\nexport { hashBucket, sha256Hex, hashConfidential, hashConfidentialAffix, fnv1a32 } from \"./hash\";\nexport { textOf, numberOf, parseSemver, compareSemver, instantOf, jsonEquals, isOn } from \"./values\";\n\nexport interface EvaluateOptions {\n /** Evaluation time (default: now). */\n now?: Date | number | string;\n /** Sticky bucketing store; experiments keep a user's variation across config changes. */\n stickyBuckets?: StickyBucketStore;\n}\n\nconst MAX_DEPTH = 32;\n\nclass CycleError extends Error {}\n\ninterface Ctx {\n payload: FlagsPayload;\n attributes: Attributes;\n now: number;\n sticky?: StickyBucketStore;\n stack: string[];\n}\n\nfunction nowOf(now: EvaluateOptions[\"now\"]): number {\n if (now === undefined) return Date.now();\n if (typeof now === \"number\") return now;\n if (now instanceof Date) return now.getTime();\n return instantOf(now) ?? Date.now();\n}\n\n/** Attribute by literal key, then by dot path. `null` counts as missing (`undefined`). */\nexport function lookupAttribute(attributes: Attributes, name: string): unknown {\n if (Object.prototype.hasOwnProperty.call(attributes, name)) return attributes[name] ?? undefined;\n if (!name.includes(\".\")) return undefined;\n let cur: unknown = attributes;\n for (const part of name.split(\".\")) {\n if (cur && typeof cur === \"object\" && !Array.isArray(cur) && Object.prototype.hasOwnProperty.call(cur, part)) cur = (cur as Record<string, unknown>)[part];\n else return undefined;\n }\n return cur ?? undefined;\n}\n\n/** Text form of a hashing attribute, or `undefined` when missing or empty. */\nfunction hashValueOf(attributes: Attributes, name: string): string | undefined {\n const t = textOf(lookupAttribute(attributes, name));\n return t === undefined || t === \"\" ? undefined : t;\n}\n\nexport function isScheduleActive(schedule: RuleSchedule | undefined, now: number): boolean {\n if (!schedule) return true;\n if (schedule.start) {\n const start = instantOf(schedule.start);\n if (start === undefined || now < start) return false;\n }\n if (schedule.end) {\n const end = instantOf(schedule.end);\n if (end === undefined || now >= end) return false;\n }\n return true;\n}\n\nfunction clamp01(n: unknown): number {\n return typeof n === \"number\" && Number.isFinite(n) ? Math.min(1, Math.max(0, n)) : 0;\n}\n\nexport function effectiveCoverage(rule: { coverage: number; ramp?: Array<{ at: string; coverage: number }> }, now: number): number {\n let coverage = clamp01(rule.coverage);\n let latest = -Infinity;\n for (const step of rule.ramp ?? []) {\n const at = instantOf(step.at);\n if (at !== undefined && at <= now && at >= latest) {\n latest = at;\n coverage = clamp01(step.coverage);\n }\n }\n return coverage;\n}\n\nconst regexCache = new Map<string, RegExp | null>();\nfunction compile(pattern: string, ci: boolean): RegExp | null {\n const k = `${ci ? \"i\" : \"-\"}:${pattern}`;\n let re = regexCache.get(k);\n if (re === undefined) {\n try {\n re = new RegExp(pattern, ci ? \"i\" : \"\");\n } catch {\n re = null;\n }\n if (regexCache.size > 500) regexCache.clear();\n regexCache.set(k, re);\n }\n return re;\n}\n\nfunction lower(s: string, ci: boolean | undefined) {\n return ci ? s.toLowerCase() : s;\n}\n\nfunction textValues(values: JsonValue[], ci: boolean | undefined): string[] {\n const out: string[] = [];\n for (const v of values) {\n const t = textOf(v);\n if (t !== undefined) out.push(lower(t, ci));\n }\n return out;\n}\n\nfunction affixMatches(salt: string, text: string, values: JsonValue[], suffix: boolean): boolean {\n const bytes = utf8(text);\n return values.some((v) => {\n if (typeof v !== \"string\") return false;\n const sep = v.indexOf(\"_\");\n if (sep <= 0) return false;\n const n = Number(v.slice(0, sep));\n if (!Number.isInteger(n) || n < 0 || n > bytes.length) return false;\n const part = suffix ? bytes.slice(bytes.length - n) : bytes.slice(0, n);\n return hashConfidential(salt, part) === v.slice(sep + 1);\n });\n}\n\nfunction evalAttribute(ctx: Ctx, c: AttributeCondition): boolean {\n const raw = lookupAttribute(ctx.attributes, c.attribute);\n const values = Array.isArray(c.values) ? c.values : [];\n const op = c.operator;\n if (op === \"notExists\") return raw === undefined;\n if (raw === undefined) return false;\n const ci = c.caseInsensitive;\n switch (op) {\n case \"exists\":\n return true;\n case \"isType\":\n return jsonTypeOf(raw) === values[0];\n case \"isTrue\":\n return raw === true || (typeof raw === \"string\" && raw.toLowerCase() === \"true\");\n case \"isFalse\":\n return raw === false || (typeof raw === \"string\" && raw.toLowerCase() === \"false\");\n case \"equals\":\n case \"notEquals\":\n case \"in\":\n case \"notIn\":\n case \"contains\":\n case \"notContains\":\n case \"startsWith\":\n case \"notStartsWith\":\n case \"endsWith\":\n case \"notEndsWith\": {\n const t0 = textOf(raw);\n if (t0 === undefined) return false;\n const t = lower(t0, ci);\n const vs = textValues(values, ci);\n switch (op) {\n case \"equals\":\n return vs.length > 0 && t === vs[0];\n case \"notEquals\":\n return vs.length > 0 && t !== vs[0];\n case \"in\":\n return vs.includes(t);\n case \"notIn\":\n return !vs.includes(t);\n case \"contains\":\n return vs.some((v) => t.includes(v));\n case \"notContains\":\n return !vs.some((v) => t.includes(v));\n case \"startsWith\":\n return vs.some((v) => t.startsWith(v));\n case \"notStartsWith\":\n return !vs.some((v) => t.startsWith(v));\n case \"endsWith\":\n return vs.some((v) => t.endsWith(v));\n default:\n return !vs.some((v) => t.endsWith(v));\n }\n }\n case \"regex\":\n case \"notRegex\": {\n const t = textOf(raw);\n if (t === undefined) return false;\n const res: RegExp[] = [];\n for (const v of values) {\n const re = typeof v === \"string\" ? compile(v, !!ci) : null;\n if (!re) return false;\n res.push(re);\n }\n const any = res.some((re) => re.test(t));\n return op === \"regex\" ? any : !any;\n }\n case \"numEquals\":\n case \"numNotEquals\":\n case \"gt\":\n case \"gte\":\n case \"lt\":\n case \"lte\": {\n const a = numberOf(raw);\n const b = numberOf(values[0]);\n if (a === undefined || b === undefined) return false;\n if (op === \"numEquals\") return a === b;\n if (op === \"numNotEquals\") return a !== b;\n if (op === \"gt\") return a > b;\n if (op === \"gte\") return a >= b;\n if (op === \"lt\") return a < b;\n return a <= b;\n }\n case \"semverEquals\":\n case \"semverNotEquals\":\n case \"semverGt\":\n case \"semverGte\":\n case \"semverLt\":\n case \"semverLte\":\n case \"semverIn\":\n case \"semverNotIn\": {\n const a = parseSemver(raw);\n if (!a) return false;\n const bs = values.map(parseSemver);\n if (bs.some((b) => !b)) return false;\n if (op === \"semverIn\") return bs.some((b) => compareSemver(a, b!) === 0);\n if (op === \"semverNotIn\") return !bs.some((b) => compareSemver(a, b!) === 0);\n if (!bs[0]) return false;\n const d = compareSemver(a, bs[0]);\n if (op === \"semverEquals\") return d === 0;\n if (op === \"semverNotEquals\") return d !== 0;\n if (op === \"semverGt\") return d > 0;\n if (op === \"semverGte\") return d >= 0;\n if (op === \"semverLt\") return d < 0;\n return d <= 0;\n }\n case \"before\":\n case \"after\": {\n const a = instantOf(raw);\n const b = instantOf(values[0]);\n if (a === undefined || b === undefined) return false;\n return op === \"before\" ? a < b : a > b;\n }\n case \"arrayContainsAny\":\n case \"arrayNotContainsAny\":\n case \"arrayContainsAll\": {\n const arr = arrayOf(raw);\n if (!arr) return false;\n const elems = textValues(arr as JsonValue[], ci);\n const vs = textValues(values, ci);\n if (op === \"arrayContainsAll\") return vs.every((v) => elems.includes(v));\n const any = vs.some((v) => elems.includes(v));\n return op === \"arrayContainsAny\" ? any : !any;\n }\n case \"equalsHashed\":\n case \"notEqualsHashed\":\n case \"inHashed\":\n case \"notInHashed\":\n case \"startsWithHashed\":\n case \"notStartsWithHashed\":\n case \"endsWithHashed\":\n case \"notEndsWithHashed\": {\n const t = textOf(raw);\n if (t === undefined) return false;\n const salt = ctx.payload.salt ?? \"\";\n if (op === \"startsWithHashed\" || op === \"notStartsWithHashed\" || op === \"endsWithHashed\" || op === \"notEndsWithHashed\") {\n const any = affixMatches(salt, t, values, op === \"endsWithHashed\" || op === \"notEndsWithHashed\");\n return op.startsWith(\"not\") ? !any : any;\n }\n const h = hashConfidential(salt, t);\n if (op === \"equalsHashed\") return typeof values[0] === \"string\" && h === values[0];\n if (op === \"notEqualsHashed\") return typeof values[0] === \"string\" && h !== values[0];\n if (op === \"inHashed\") return values.includes(h);\n return !values.includes(h);\n }\n case \"arrayContainsAnyHashed\":\n case \"arrayNotContainsAnyHashed\": {\n const arr = arrayOf(raw);\n if (!arr) return false;\n const salt = ctx.payload.salt ?? \"\";\n const any = arr.some((e) => {\n const t = textOf(e);\n return t !== undefined && values.includes(hashConfidential(salt, t));\n });\n return op === \"arrayContainsAnyHashed\" ? any : !any;\n }\n default:\n return false;\n }\n}\n\nfunction enter<T>(ctx: Ctx, frame: string, fn: () => T): T {\n if (ctx.stack.includes(frame)) throw new CycleError(`Cycle detected: ${[...ctx.stack, frame].join(\" → \")}`);\n if (ctx.stack.length >= MAX_DEPTH) throw new CycleError(`Flag references nest deeper than ${MAX_DEPTH} levels: ${ctx.stack.join(\" → \")}`);\n ctx.stack.push(frame);\n try {\n return fn();\n } finally {\n ctx.stack.pop();\n }\n}\n\nfunction segmentMatches(ctx: Ctx, key: string): boolean | undefined {\n const seg = ctx.payload.segments?.[key];\n if (!seg) return undefined;\n return enter(ctx, `segment:${key}`, () => {\n if (seg.kind === \"list\") {\n const t = textOf(lookupAttribute(ctx.attributes, seg.attribute));\n if (t === undefined) return false;\n const needle = seg.hashed ? hashConfidential(ctx.payload.salt ?? \"\", t) : t;\n return Array.isArray(seg.values) && seg.values.includes(needle);\n }\n if (seg.kind === \"conditions\") return allMatch(ctx, seg.conditions);\n return false;\n });\n}\n\nfunction compareFlag(op: FlagComparisonOperator, actual: unknown, expected: JsonValue | undefined): boolean {\n switch (op) {\n case \"isOn\":\n return isOn(actual);\n case \"isOff\":\n return !isOn(actual);\n case \"equals\":\n return jsonEquals(actual, expected ?? null);\n case \"notEquals\":\n return !jsonEquals(actual, expected ?? null);\n default:\n return false;\n }\n}\n\n/** Value of a referenced flag, or `undefined` when it does not exist. */\nfunction referencedValue(ctx: Ctx, key: string): { value: unknown } | undefined {\n const res = evalFlag(ctx, key);\n return res.reason === \"FLAG_NOT_FOUND\" ? undefined : { value: res.value };\n}\n\nfunction conditionMatches(ctx: Ctx, c: Condition): boolean {\n if (!c || typeof c !== \"object\") return false;\n switch (c.kind) {\n case \"attribute\":\n return evalAttribute(ctx, c);\n case \"segment\": {\n const m = segmentMatches(ctx, c.segment);\n if (m === undefined) return false;\n if (c.operator === \"in\") return m;\n if (c.operator === \"notIn\") return !m;\n return false;\n }\n case \"flag\": {\n const ref = referencedValue(ctx, c.flag);\n return ref ? compareFlag(c.operator, ref.value, c.value) : false;\n }\n case \"group\": {\n const list = Array.isArray(c.conditions) ? c.conditions : [];\n let r: boolean;\n if (c.op === \"and\") r = allMatch(ctx, list);\n else if (c.op === \"or\") r = list.some((x) => conditionMatches(ctx, x));\n else return false;\n return c.negate ? !r : r;\n }\n default:\n return false;\n }\n}\n\nfunction allMatch(ctx: Ctx, conditions: Condition[] | undefined): boolean {\n if (!conditions) return true;\n for (const c of conditions) if (!conditionMatches(ctx, c)) return false;\n return true;\n}\n\nfunction base(flag: FlagDefinition, value: JsonValue | undefined, reason: EvaluationResult[\"reason\"]): EvaluationResult {\n return { key: flag.key, value: value === undefined ? null : value, reason, inExperiment: false };\n}\n\nfunction stickyDocKey(attribute: string, value: string) {\n return `${attribute}||${value}`;\n}\n\nfunction runExperiment(ctx: Ctx, flag: FlagDefinition, rule: ExperimentRule): EvaluationResult | undefined {\n const variations = Array.isArray(rule.variations) ? rule.variations : [];\n if (!variations.length) return undefined;\n let hashAttribute = rule.hashAttribute;\n let hv = hashValueOf(ctx.attributes, rule.hashAttribute);\n const fallbackValue = rule.fallbackAttribute ? hashValueOf(ctx.attributes, rule.fallbackAttribute) : undefined;\n if (hv === undefined && rule.fallbackAttribute && fallbackValue !== undefined) {\n hashAttribute = rule.fallbackAttribute;\n hv = fallbackValue;\n }\n if (hv === undefined) return undefined;\n\n const bucketVersion = rule.bucketVersion ?? 0;\n const useSticky = !!ctx.sticky && !rule.disableStickyBucketing;\n let index = -1;\n const bucket = hashBucket(rule.seed, hv);\n let stickyUsed = false;\n if (useSticky) {\n const merged: StickyAssignments = {};\n if (rule.fallbackAttribute && fallbackValue !== undefined) Object.assign(merged, ctx.sticky!.get(stickyDocKey(rule.fallbackAttribute, fallbackValue)) ?? {});\n const primary = hashValueOf(ctx.attributes, rule.hashAttribute);\n if (primary !== undefined) Object.assign(merged, ctx.sticky!.get(stickyDocKey(rule.hashAttribute, primary)) ?? {});\n const prefix = `${rule.key}__`;\n const minVersion = rule.minBucketVersion ?? 0;\n for (const k of Object.keys(merged)) {\n if (!k.startsWith(prefix)) continue;\n const v = Number(k.slice(prefix.length));\n if (Number.isInteger(v) && v < minVersion) return undefined; // blocked from re-entering\n }\n const assigned = merged[`${prefix}${bucketVersion}`];\n if (assigned !== undefined) {\n const i = variations.findIndex((v) => v.id === assigned);\n if (i >= 0) {\n index = i;\n stickyUsed = true;\n }\n }\n }\n if (index < 0) {\n if (rule.namespace) {\n const n = hashBucket(`__${rule.namespace.id}`, hv);\n if (!(n >= rule.namespace.start && n < rule.namespace.end)) return undefined;\n }\n const coverage = clamp01(rule.coverage);\n let cum = 0;\n for (let i = 0; i < variations.length; i++) {\n const w = Math.max(0, Number(variations[i]!.weight) || 0);\n const start = cum;\n const end = cum + coverage * w;\n cum += w;\n if (bucket >= start && bucket < end) {\n index = i;\n break;\n }\n }\n if (index < 0) return undefined;\n if (useSticky) {\n const docKey = stickyDocKey(hashAttribute, hv);\n const doc = { ...(ctx.sticky!.get(docKey) ?? {}) };\n doc[`${rule.key}__${bucketVersion}`] = variations[index]!.id;\n ctx.sticky!.set(docKey, doc);\n }\n }\n const variation = variations[index]!;\n return {\n key: flag.key,\n value: variation.value === undefined ? null : variation.value,\n reason: \"EXPERIMENT\",\n ruleId: rule.id,\n variationId: variation.id,\n inExperiment: true,\n experiment: { key: rule.key, name: rule.name, variationId: variation.id, variationName: variation.name, variationIndex: index, hashAttribute, hashValue: hv, bucket, stickyBucketUsed: stickyUsed },\n };\n}\n\nfunction applyRule(ctx: Ctx, flag: FlagDefinition, rule: FlagRule): EvaluationResult | undefined {\n switch (rule.type) {\n case \"force\":\n return { ...base(flag, rule.value, \"RULE_MATCH\"), ruleId: rule.id, ...(rule.variationId ? { variationId: rule.variationId } : {}) };\n case \"rollout\": {\n const hv = hashValueOf(ctx.attributes, rule.hashAttribute);\n if (hv === undefined) return undefined;\n if (hashBucket(rule.seed, hv) >= effectiveCoverage(rule, ctx.now)) return undefined;\n return { ...base(flag, rule.value, \"RULE_MATCH\"), ruleId: rule.id, ...(rule.variationId ? { variationId: rule.variationId } : {}) };\n }\n case \"split\": {\n const hv = hashValueOf(ctx.attributes, rule.hashAttribute);\n if (hv === undefined || !Array.isArray(rule.buckets)) return undefined;\n const n = hashBucket(rule.seed, hv);\n let cum = 0;\n for (const b of rule.buckets) {\n cum += Math.max(0, Number(b.weight) || 0);\n if (n < cum) return { ...base(flag, b.value, \"RULE_MATCH\"), ruleId: rule.id, ...(b.variationId ? { variationId: b.variationId } : {}) };\n }\n return undefined;\n }\n case \"experiment\":\n return runExperiment(ctx, flag, rule);\n default:\n return undefined;\n }\n}\n\nfunction evalFlag(ctx: Ctx, key: string): EvaluationResult {\n const flag = ctx.payload.flags?.[key];\n if (!flag) return { key, value: null, reason: \"FLAG_NOT_FOUND\", inExperiment: false };\n return enter(ctx, `flag:${key}`, () => {\n if (!flag.enabled) return base(flag, flag.offValue, \"DISABLED\");\n for (const p of flag.prerequisites ?? []) {\n const ref = referencedValue(ctx, p.flag);\n if (!ref || !compareFlag(p.operator, ref.value, p.value)) return base(flag, flag.offValue, \"PREREQUISITE_FAILED\");\n }\n for (const h of ctx.payload.holdouts ?? []) {\n if (!Array.isArray(h.flags) || !h.flags.includes(key)) continue;\n const hv = hashValueOf(ctx.attributes, h.hashAttribute);\n if (hv !== undefined && hashBucket(h.seed, hv) < clamp01(h.coverage)) return base(flag, flag.defaultValue, \"HOLDOUT\");\n }\n for (const rule of flag.rules ?? []) {\n if (!rule || !isScheduleActive(rule.schedule, ctx.now)) continue;\n if (!allMatch(ctx, rule.conditions)) continue;\n const res = applyRule(ctx, flag, rule);\n if (res) return res;\n }\n return base(flag, flag.defaultValue, \"DEFAULT\");\n });\n}\n\n/** Evaluate one flag. Never throws: problems come back as reason `ERROR`. */\nexport function evaluateFlag(payload: FlagsPayload, key: string, attributes: Attributes = {}, options: EvaluateOptions = {}): EvaluationResult {\n const ctx: Ctx = { payload, attributes: attributes ?? {}, now: nowOf(options.now), sticky: options.stickyBuckets, stack: [] };\n try {\n return evalFlag(ctx, key);\n } catch (err) {\n return { key, value: null, reason: \"ERROR\", inExperiment: false, errorMessage: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/** Evaluate every flag in the payload. */\nexport function evaluateAllFlags(payload: FlagsPayload, attributes: Attributes = {}, options: EvaluateOptions = {}): Record<string, EvaluationResult> {\n const out: Record<string, EvaluationResult> = {};\n for (const key of Object.keys(payload.flags ?? {})) out[key] = evaluateFlag(payload, key, attributes, options);\n return out;\n}\n","/** Hashing shared by every Guidely flag SDK (docs/feature-flags-spec.md §3.4, §3.3). Synchronous and dependency-free so it runs in browsers, React Native, Node and edge runtimes alike. */\n\nexport function utf8(input: string): Uint8Array {\n const out: number[] = [];\n for (let i = 0; i < input.length; i++) {\n let c = input.charCodeAt(i);\n if (c >= 0xd800 && c <= 0xdbff && i + 1 < input.length) {\n const d = input.charCodeAt(i + 1);\n if (d >= 0xdc00 && d <= 0xdfff) {\n c = 0x10000 + ((c - 0xd800) << 10) + (d - 0xdc00);\n i++;\n }\n }\n if (c >= 0xd800 && c <= 0xdfff) c = 0xfffd; // lone surrogate\n if (c < 0x80) out.push(c);\n else if (c < 0x800) out.push(0xc0 | (c >> 6), 0x80 | (c & 63));\n else if (c < 0x10000) out.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 63), 0x80 | (c & 63));\n else out.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 63), 0x80 | ((c >> 6) & 63), 0x80 | (c & 63));\n }\n return Uint8Array.from(out);\n}\n\nexport function decodeUtf8(bytes: Uint8Array): string {\n if (typeof TextDecoder !== \"undefined\") return new TextDecoder().decode(bytes);\n let s = \"\";\n for (let i = 0; i < bytes.length; ) {\n const b = bytes[i++]!;\n let c: number;\n if (b < 0x80) c = b;\n else if (b < 0xe0) c = ((b & 31) << 6) | (bytes[i++]! & 63);\n else if (b < 0xf0) c = ((b & 15) << 12) | ((bytes[i++]! & 63) << 6) | (bytes[i++]! & 63);\n else c = ((b & 7) << 18) | ((bytes[i++]! & 63) << 12) | ((bytes[i++]! & 63) << 6) | (bytes[i++]! & 63);\n s += String.fromCodePoint(c);\n }\n return s;\n}\n\nexport function fnv1a32(bytes: Uint8Array): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < bytes.length; i++) {\n h ^= bytes[i]!;\n h = Math.imul(h, 0x01000193) >>> 0;\n }\n return h >>> 0;\n}\n\n/** Deterministic bucket in [0, 1) with 4 decimals (GrowthBook hash v2 for ASCII input). */\nexport function hashBucket(seed: string, value: string): number {\n const inner = fnv1a32(utf8(seed + value));\n return (fnv1a32(utf8(String(inner))) % 10000) / 10000;\n}\n\nconst K = new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\n\n/** Lowercase hex SHA-256 of the UTF-8 bytes of `input`. */\nexport function sha256Hex(input: string | Uint8Array): string {\n const msg = typeof input === \"string\" ? utf8(input) : input;\n const bitLen = msg.length * 8;\n const padded = new Uint8Array(((msg.length + 9 + 63) >> 6) << 6);\n padded.set(msg);\n padded[msg.length] = 0x80;\n const view = new DataView(padded.buffer);\n view.setUint32(padded.length - 8, Math.floor(bitLen / 0x100000000));\n view.setUint32(padded.length - 4, bitLen >>> 0);\n const h = new Uint32Array([0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]);\n const w = new Uint32Array(64);\n for (let off = 0; off < padded.length; off += 64) {\n for (let i = 0; i < 16; i++) w[i] = view.getUint32(off + i * 4);\n for (let i = 16; i < 64; i++) {\n const a = w[i - 15]!, b = w[i - 2]!;\n const s0 = ((a >>> 7) | (a << 25)) ^ ((a >>> 18) | (a << 14)) ^ (a >>> 3);\n const s1 = ((b >>> 17) | (b << 15)) ^ ((b >>> 19) | (b << 13)) ^ (b >>> 10);\n w[i] = (w[i - 16]! + s0 + w[i - 7]! + s1) >>> 0;\n }\n let a = h[0]!, b = h[1]!, c = h[2]!, d = h[3]!, e = h[4]!, f = h[5]!, g = h[6]!, hh = h[7]!;\n for (let i = 0; i < 64; i++) {\n const S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));\n const ch = (e & f) ^ (~e & g);\n const t1 = (hh + S1 + ch + K[i]! + w[i]!) >>> 0;\n const S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));\n const maj = (a & b) ^ (a & c) ^ (b & c);\n const t2 = (S0 + maj) >>> 0;\n hh = g;\n g = f;\n f = e;\n e = (d + t1) >>> 0;\n d = c;\n c = b;\n b = a;\n a = (t1 + t2) >>> 0;\n }\n h[0] = (h[0]! + a) >>> 0;\n h[1] = (h[1]! + b) >>> 0;\n h[2] = (h[2]! + c) >>> 0;\n h[3] = (h[3]! + d) >>> 0;\n h[4] = (h[4]! + e) >>> 0;\n h[5] = (h[5]! + f) >>> 0;\n h[6] = (h[6]! + g) >>> 0;\n h[7] = (h[7]! + hh) >>> 0;\n }\n let hex = \"\";\n for (let i = 0; i < 8; i++) hex += h[i]!.toString(16).padStart(8, \"0\");\n return hex;\n}\n\n/** `H(x)` for the hashed operators: SHA-256 of `salt + value`. */\nexport function hashConfidential(salt: string, value: string | Uint8Array): string {\n if (typeof value === \"string\") return sha256Hex(salt + value);\n const s = utf8(salt);\n const joined = new Uint8Array(s.length + value.length);\n joined.set(s);\n joined.set(value, s.length);\n return sha256Hex(joined);\n}\n\n/** Comparison value for the hashed prefix/suffix operators: `\"<byteLength>_<H(part)>\"`. */\nexport function hashConfidentialAffix(salt: string, part: string): string {\n return `${utf8(part).length}_${hashConfidential(salt, part)}`;\n}\n","/** Value conversions used by the condition operators (docs/feature-flags-spec.md §3.2–3.3). */\n\n/** Text form of a scalar, or `undefined` for arrays, objects, null and non-finite numbers. */\nexport function textOf(v: unknown): string | undefined {\n if (typeof v === \"string\") return v;\n if (typeof v === \"boolean\") return v ? \"true\" : \"false\";\n if (typeof v === \"number\") {\n if (!Number.isFinite(v)) return undefined;\n if (Number.isInteger(v) && Math.abs(v) < 1e21) return v.toFixed(0);\n return String(v);\n }\n if (typeof v === \"bigint\") return v.toString();\n return undefined;\n}\n\nconst NUMERIC = /^[+-]?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/;\n\nexport function numberOf(v: unknown): number | undefined {\n if (typeof v === \"number\") return Number.isFinite(v) ? v : undefined;\n if (typeof v === \"string\") {\n const s = v.trim();\n if (!NUMERIC.test(s)) return undefined;\n const n = Number(s);\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\n/** Elements of an array attribute (or a string holding a JSON array). */\nexport function arrayOf(v: unknown): unknown[] | undefined {\n if (Array.isArray(v)) return v;\n if (typeof v === \"string\") {\n const s = v.trim();\n if (!s.startsWith(\"[\")) return undefined;\n try {\n const parsed: unknown = JSON.parse(s);\n return Array.isArray(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\nexport interface SemVer {\n major: number;\n minor: number;\n patch: number;\n pre: string[];\n}\n\nconst SEMVER = /^[vV]?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/;\n\nexport function parseSemver(v: unknown): SemVer | undefined {\n const s = typeof v === \"number\" ? textOf(v) : typeof v === \"string\" ? v.trim() : undefined;\n if (s === undefined) return undefined;\n const m = SEMVER.exec(s);\n if (!m) return undefined;\n return { major: Number(m[1]), minor: Number(m[2] ?? 0), patch: Number(m[3] ?? 0), pre: m[4] ? m[4].split(\".\") : [] };\n}\n\nfunction cmp(a: number, b: number): number {\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/** SemVer 2.0 precedence: -1, 0 or 1. */\nexport function compareSemver(a: SemVer, b: SemVer): number {\n const c = cmp(a.major, b.major) || cmp(a.minor, b.minor) || cmp(a.patch, b.patch);\n if (c) return c;\n // A release outranks its pre-releases.\n if (!a.pre.length || !b.pre.length) return a.pre.length ? -1 : b.pre.length ? 1 : 0;\n for (let i = 0; i < Math.max(a.pre.length, b.pre.length); i++) {\n const x = a.pre[i], y = b.pre[i];\n if (x === undefined) return -1;\n if (y === undefined) return 1;\n const xn = /^\\d+$/.test(x), yn = /^\\d+$/.test(y);\n if (xn && yn) {\n const d = cmp(Number(x), Number(y));\n if (d) return d;\n } else if (xn) return -1;\n else if (yn) return 1;\n else if (x !== y) return x < y ? -1 : 1;\n }\n return 0;\n}\n\nfunction daysInMonth(year: number, month: number): number {\n if (month === 2) return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0 ? 29 : 28;\n return [4, 6, 9, 11].includes(month) ? 30 : 31;\n}\n\n/** Days since 1970-01-01 in the proleptic Gregorian calendar (H. Hinnant's days_from_civil); unlike Date.UTC, years 0–99 are literal. */\nfunction daysFromCivil(year: number, month: number, day: number): number {\n const y = month <= 2 ? year - 1 : year;\n const era = Math.floor(y / 400);\n const yoe = y - era * 400;\n const doy = Math.floor((153 * (month + (month > 2 ? -3 : 9)) + 2) / 5) + day - 1;\n const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;\n return era * 146097 + doe - 719468;\n}\n\nconst ISO = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[Tt ](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d+))?)?(Z|z|[+-]\\d{2}:\\d{2})?)?$/;\n\n/** Milliseconds since the epoch: numbers are Unix seconds, strings ISO 8601, Date objects as-is. */\nexport function instantOf(v: unknown): number | undefined {\n if (v instanceof Date) return Number.isNaN(v.getTime()) ? undefined : v.getTime();\n if (typeof v === \"number\") return Number.isFinite(v) ? v * 1000 : undefined;\n if (typeof v !== \"string\") return undefined;\n const m = ISO.exec(v.trim());\n if (!m) return undefined;\n const [, y, mo, d, h = \"0\", mi = \"0\", s = \"0\", frac, tz] = m;\n const month = Number(mo), day = Number(d), hour = Number(h), minute = Number(mi), second = Number(s);\n const year = Number(y);\n if (month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month) || hour > 23 || minute > 59 || second > 59) return undefined;\n let ms = (daysFromCivil(year, month, day) * 86400 + hour * 3600 + minute * 60 + second) * 1000 + (frac ? Math.floor(Number(`0.${frac}`) * 1000) : 0);\n if (tz && tz !== \"Z\" && tz !== \"z\") {\n const sign = tz[0] === \"-\" ? -1 : 1;\n ms -= sign * (Number(tz.slice(1, 3)) * 60 + Number(tz.slice(4, 6))) * 60_000;\n }\n return ms;\n}\n\n/** JSON deep equality; numbers compare numerically, object keys unordered. */\nexport function jsonEquals(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null || a === undefined || b === undefined) return (a ?? null) === (b ?? null);\n if (typeof a === \"number\" && typeof b === \"number\") return a === b;\n if (Array.isArray(a)) return Array.isArray(b) && a.length === b.length && a.every((x, i) => jsonEquals(x, b[i]));\n if (typeof a === \"object\" && typeof b === \"object\" && !Array.isArray(b)) {\n const ka = Object.keys(a as object).filter((k) => (a as Record<string, unknown>)[k] !== undefined);\n const kb = Object.keys(b as object).filter((k) => (b as Record<string, unknown>)[k] !== undefined);\n return ka.length === kb.length && ka.every((k) => Object.prototype.hasOwnProperty.call(b, k) && jsonEquals((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]));\n }\n return false;\n}\n\n/** `isOn`: anything except null, false, 0 and \"\". */\nexport function isOn(v: unknown): boolean {\n return !(v === null || v === undefined || v === false || v === 0 || v === \"\");\n}\n\nexport function jsonTypeOf(v: unknown): string | undefined {\n if (v === null || v === undefined) return undefined;\n if (Array.isArray(v)) return \"array\";\n if (typeof v === \"object\") return \"object\";\n if (typeof v === \"string\" || typeof v === \"number\" || typeof v === \"boolean\") return typeof v;\n return undefined;\n}\n","/**\n * Wire format of the feature-flag payload served by `GET /api/v1/sdk/flags` and the results of\n * evaluating it. See docs/feature-flags-spec.md for the semantics; every SDK shares them.\n */\n\nexport type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };\nexport type Attributes = Record<string, unknown>;\n\nexport type FlagValueType = \"boolean\" | \"string\" | \"number\" | \"json\";\n\nexport interface FlagsPayload {\n schemaVersion: 1;\n projectId: string;\n environment: string;\n /** Bumps on every change that affects this environment. */\n version: number;\n generatedAt: string;\n /** Salt for the hashed (confidential) operators. */\n salt: string;\n flags: Record<string, FlagDefinition>;\n segments: Record<string, SegmentDefinition>;\n holdouts?: HoldoutDefinition[];\n}\n\n/** What `GET /flags` returns when the environment encrypts its payload. */\nexport interface EncryptedFlagsPayload {\n schemaVersion: 1;\n projectId: string;\n environment: string;\n version: number;\n generatedAt: string;\n encryptedPayload: string;\n}\n\nexport interface FlagDefinition {\n key: string;\n type: FlagValueType;\n version: number;\n /** Environment kill switch. */\n enabled: boolean;\n /** Served when the flag is disabled or a prerequisite fails. */\n offValue: JsonValue;\n /** Served when the flag is enabled and no rule serves a value. */\n defaultValue: JsonValue;\n prerequisites?: Prerequisite[];\n rules?: FlagRule[];\n}\n\nexport type FlagComparisonOperator = \"isOn\" | \"isOff\" | \"equals\" | \"notEquals\";\n\nexport interface Prerequisite {\n flag: string;\n operator: FlagComparisonOperator;\n value?: JsonValue;\n}\n\nexport interface RuleSchedule {\n start?: string | null;\n end?: string | null;\n}\n\ninterface RuleBase {\n id: string;\n description?: string;\n /** All must match; absent or empty means everyone. */\n conditions?: Condition[];\n schedule?: RuleSchedule;\n}\n\nexport interface ForceRule extends RuleBase {\n type: \"force\";\n value: JsonValue;\n variationId?: string;\n}\n\nexport interface RampStep {\n at: string;\n coverage: number;\n}\n\nexport interface RolloutRule extends RuleBase {\n type: \"rollout\";\n value: JsonValue;\n variationId?: string;\n hashAttribute: string;\n seed: string;\n /** Share of matching users (0–1) that get `value`; the rest fall through. */\n coverage: number;\n /** Scheduled ramp: the coverage of the last step whose `at` has passed applies. */\n ramp?: RampStep[];\n}\n\nexport interface SplitBucket {\n weight: number;\n value: JsonValue;\n variationId?: string;\n}\n\nexport interface SplitRule extends RuleBase {\n type: \"split\";\n hashAttribute: string;\n seed: string;\n buckets: SplitBucket[];\n}\n\nexport interface ExperimentVariation {\n id: string;\n name?: string;\n value: JsonValue;\n weight: number;\n}\n\nexport interface ExperimentNamespace {\n id: string;\n start: number;\n end: number;\n}\n\nexport interface ExperimentRule extends RuleBase {\n type: \"experiment\";\n key: string;\n name?: string;\n hashAttribute: string;\n fallbackAttribute?: string;\n seed: string;\n coverage: number;\n variations: ExperimentVariation[];\n namespace?: ExperimentNamespace;\n bucketVersion?: number;\n minBucketVersion?: number;\n disableStickyBucketing?: boolean;\n}\n\nexport type FlagRule = ForceRule | RolloutRule | SplitRule | ExperimentRule;\nexport type FlagRuleType = FlagRule[\"type\"];\n\nexport const TEXT_OPERATORS = [\"equals\", \"notEquals\", \"in\", \"notIn\", \"contains\", \"notContains\", \"startsWith\", \"notStartsWith\", \"endsWith\", \"notEndsWith\", \"regex\", \"notRegex\"] as const;\nexport const NUMBER_OPERATORS = [\"numEquals\", \"numNotEquals\", \"gt\", \"gte\", \"lt\", \"lte\"] as const;\nexport const SEMVER_OPERATORS = [\"semverEquals\", \"semverNotEquals\", \"semverGt\", \"semverGte\", \"semverLt\", \"semverLte\", \"semverIn\", \"semverNotIn\"] as const;\nexport const DATE_OPERATORS = [\"before\", \"after\"] as const;\nexport const ARRAY_OPERATORS = [\"arrayContainsAny\", \"arrayNotContainsAny\", \"arrayContainsAll\"] as const;\nexport const BOOLEAN_OPERATORS = [\"isTrue\", \"isFalse\"] as const;\nexport const PRESENCE_OPERATORS = [\"exists\", \"notExists\", \"isType\"] as const;\nexport const HASHED_OPERATORS = [\"equalsHashed\", \"notEqualsHashed\", \"inHashed\", \"notInHashed\", \"startsWithHashed\", \"notStartsWithHashed\", \"endsWithHashed\", \"notEndsWithHashed\", \"arrayContainsAnyHashed\", \"arrayNotContainsAnyHashed\"] as const;\n\nexport const ATTRIBUTE_OPERATORS = [...TEXT_OPERATORS, ...NUMBER_OPERATORS, ...SEMVER_OPERATORS, ...DATE_OPERATORS, ...ARRAY_OPERATORS, ...BOOLEAN_OPERATORS, ...PRESENCE_OPERATORS, ...HASHED_OPERATORS] as const;\nexport type AttributeOperator = (typeof ATTRIBUTE_OPERATORS)[number];\n\nexport interface AttributeCondition {\n kind: \"attribute\";\n attribute: string;\n operator: AttributeOperator;\n values?: JsonValue[];\n caseInsensitive?: boolean;\n}\n\nexport interface SegmentCondition {\n kind: \"segment\";\n operator: \"in\" | \"notIn\";\n segment: string;\n}\n\nexport interface FlagCondition {\n kind: \"flag\";\n flag: string;\n operator: FlagComparisonOperator;\n value?: JsonValue;\n}\n\nexport interface GroupCondition {\n kind: \"group\";\n op: \"and\" | \"or\";\n negate?: boolean;\n conditions: Condition[];\n}\n\nexport type Condition = AttributeCondition | SegmentCondition | FlagCondition | GroupCondition;\n\nexport interface ConditionSegment {\n key: string;\n kind: \"conditions\";\n conditions: Condition[];\n}\n\nexport interface ListSegment {\n key: string;\n kind: \"list\";\n attribute: string;\n values: string[];\n hashed?: boolean;\n}\n\nexport type SegmentDefinition = ConditionSegment | ListSegment;\n\nexport interface HoldoutDefinition {\n key: string;\n hashAttribute: string;\n seed: string;\n coverage: number;\n flags: string[];\n}\n\nexport type EvaluationReason = \"FLAG_NOT_FOUND\" | \"DISABLED\" | \"PREREQUISITE_FAILED\" | \"HOLDOUT\" | \"RULE_MATCH\" | \"EXPERIMENT\" | \"DEFAULT\" | \"OVERRIDE\" | \"ERROR\";\n\nexport interface ExperimentAssignment {\n key: string;\n name?: string;\n variationId: string;\n variationName?: string;\n variationIndex: number;\n hashAttribute: string;\n hashValue: string;\n bucket: number;\n stickyBucketUsed: boolean;\n}\n\nexport interface EvaluationResult<T = JsonValue> {\n key: string;\n value: T | null;\n reason: EvaluationReason;\n ruleId?: string;\n variationId?: string;\n inExperiment: boolean;\n experiment?: ExperimentAssignment;\n errorMessage?: string;\n}\n\n/** Sticky bucket documents: `\"<attribute>||<value>\"` → `{ \"<experimentKey>__<bucketVersion>\": variationId }`. */\nexport type StickyAssignments = Record<string, string>;\n\nexport interface StickyBucketStore {\n get(docKey: string): StickyAssignments | null | undefined;\n set(docKey: string, assignments: StickyAssignments): void;\n}\n\n/** Response of `POST /api/v1/sdk/flags/evaluate`. */\nexport interface RemoteEvaluationResponse {\n version: number;\n flags: Record<string, EvaluationResult>;\n}\n\n/** Body of `POST /api/v1/sdk/flags/events`. */\nexport interface FlagEventsBatch {\n sdk?: { name: string; version: string };\n usage?: Array<{ flag: string; variationId?: string; value?: string; count: number }>;\n exposures?: Array<{ experiment: string; flag?: string; variationId: string; hashAttribute: string; hashValue: string; userId?: string; anonymousId?: string; timestamp: string }>;\n}\n"],"mappings":"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","names":["a","b"]}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire format of the feature-flag payload served by `GET /api/v1/sdk/flags` and the results of
|
|
3
|
+
* evaluating it. See docs/feature-flags-spec.md for the semantics; every SDK shares them.
|
|
4
|
+
*/
|
|
5
|
+
type JsonValue = null | boolean | number | string | JsonValue[] | {
|
|
6
|
+
[key: string]: JsonValue;
|
|
7
|
+
};
|
|
8
|
+
type Attributes = Record<string, unknown>;
|
|
9
|
+
type FlagValueType = "boolean" | "string" | "number" | "json";
|
|
10
|
+
interface FlagsPayload {
|
|
11
|
+
schemaVersion: 1;
|
|
12
|
+
projectId: string;
|
|
13
|
+
environment: string;
|
|
14
|
+
/** Bumps on every change that affects this environment. */
|
|
15
|
+
version: number;
|
|
16
|
+
generatedAt: string;
|
|
17
|
+
/** Salt for the hashed (confidential) operators. */
|
|
18
|
+
salt: string;
|
|
19
|
+
flags: Record<string, FlagDefinition>;
|
|
20
|
+
segments: Record<string, SegmentDefinition>;
|
|
21
|
+
holdouts?: HoldoutDefinition[];
|
|
22
|
+
}
|
|
23
|
+
/** What `GET /flags` returns when the environment encrypts its payload. */
|
|
24
|
+
interface EncryptedFlagsPayload {
|
|
25
|
+
schemaVersion: 1;
|
|
26
|
+
projectId: string;
|
|
27
|
+
environment: string;
|
|
28
|
+
version: number;
|
|
29
|
+
generatedAt: string;
|
|
30
|
+
encryptedPayload: string;
|
|
31
|
+
}
|
|
32
|
+
interface FlagDefinition {
|
|
33
|
+
key: string;
|
|
34
|
+
type: FlagValueType;
|
|
35
|
+
version: number;
|
|
36
|
+
/** Environment kill switch. */
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
/** Served when the flag is disabled or a prerequisite fails. */
|
|
39
|
+
offValue: JsonValue;
|
|
40
|
+
/** Served when the flag is enabled and no rule serves a value. */
|
|
41
|
+
defaultValue: JsonValue;
|
|
42
|
+
prerequisites?: Prerequisite[];
|
|
43
|
+
rules?: FlagRule[];
|
|
44
|
+
}
|
|
45
|
+
type FlagComparisonOperator = "isOn" | "isOff" | "equals" | "notEquals";
|
|
46
|
+
interface Prerequisite {
|
|
47
|
+
flag: string;
|
|
48
|
+
operator: FlagComparisonOperator;
|
|
49
|
+
value?: JsonValue;
|
|
50
|
+
}
|
|
51
|
+
interface RuleSchedule {
|
|
52
|
+
start?: string | null;
|
|
53
|
+
end?: string | null;
|
|
54
|
+
}
|
|
55
|
+
interface RuleBase {
|
|
56
|
+
id: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
/** All must match; absent or empty means everyone. */
|
|
59
|
+
conditions?: Condition[];
|
|
60
|
+
schedule?: RuleSchedule;
|
|
61
|
+
}
|
|
62
|
+
interface ForceRule extends RuleBase {
|
|
63
|
+
type: "force";
|
|
64
|
+
value: JsonValue;
|
|
65
|
+
variationId?: string;
|
|
66
|
+
}
|
|
67
|
+
interface RampStep {
|
|
68
|
+
at: string;
|
|
69
|
+
coverage: number;
|
|
70
|
+
}
|
|
71
|
+
interface RolloutRule extends RuleBase {
|
|
72
|
+
type: "rollout";
|
|
73
|
+
value: JsonValue;
|
|
74
|
+
variationId?: string;
|
|
75
|
+
hashAttribute: string;
|
|
76
|
+
seed: string;
|
|
77
|
+
/** Share of matching users (0–1) that get `value`; the rest fall through. */
|
|
78
|
+
coverage: number;
|
|
79
|
+
/** Scheduled ramp: the coverage of the last step whose `at` has passed applies. */
|
|
80
|
+
ramp?: RampStep[];
|
|
81
|
+
}
|
|
82
|
+
interface SplitBucket {
|
|
83
|
+
weight: number;
|
|
84
|
+
value: JsonValue;
|
|
85
|
+
variationId?: string;
|
|
86
|
+
}
|
|
87
|
+
interface SplitRule extends RuleBase {
|
|
88
|
+
type: "split";
|
|
89
|
+
hashAttribute: string;
|
|
90
|
+
seed: string;
|
|
91
|
+
buckets: SplitBucket[];
|
|
92
|
+
}
|
|
93
|
+
interface ExperimentVariation {
|
|
94
|
+
id: string;
|
|
95
|
+
name?: string;
|
|
96
|
+
value: JsonValue;
|
|
97
|
+
weight: number;
|
|
98
|
+
}
|
|
99
|
+
interface ExperimentNamespace {
|
|
100
|
+
id: string;
|
|
101
|
+
start: number;
|
|
102
|
+
end: number;
|
|
103
|
+
}
|
|
104
|
+
interface ExperimentRule extends RuleBase {
|
|
105
|
+
type: "experiment";
|
|
106
|
+
key: string;
|
|
107
|
+
name?: string;
|
|
108
|
+
hashAttribute: string;
|
|
109
|
+
fallbackAttribute?: string;
|
|
110
|
+
seed: string;
|
|
111
|
+
coverage: number;
|
|
112
|
+
variations: ExperimentVariation[];
|
|
113
|
+
namespace?: ExperimentNamespace;
|
|
114
|
+
bucketVersion?: number;
|
|
115
|
+
minBucketVersion?: number;
|
|
116
|
+
disableStickyBucketing?: boolean;
|
|
117
|
+
}
|
|
118
|
+
type FlagRule = ForceRule | RolloutRule | SplitRule | ExperimentRule;
|
|
119
|
+
type FlagRuleType = FlagRule["type"];
|
|
120
|
+
declare const TEXT_OPERATORS: readonly ["equals", "notEquals", "in", "notIn", "contains", "notContains", "startsWith", "notStartsWith", "endsWith", "notEndsWith", "regex", "notRegex"];
|
|
121
|
+
declare const NUMBER_OPERATORS: readonly ["numEquals", "numNotEquals", "gt", "gte", "lt", "lte"];
|
|
122
|
+
declare const SEMVER_OPERATORS: readonly ["semverEquals", "semverNotEquals", "semverGt", "semverGte", "semverLt", "semverLte", "semverIn", "semverNotIn"];
|
|
123
|
+
declare const DATE_OPERATORS: readonly ["before", "after"];
|
|
124
|
+
declare const ARRAY_OPERATORS: readonly ["arrayContainsAny", "arrayNotContainsAny", "arrayContainsAll"];
|
|
125
|
+
declare const BOOLEAN_OPERATORS: readonly ["isTrue", "isFalse"];
|
|
126
|
+
declare const PRESENCE_OPERATORS: readonly ["exists", "notExists", "isType"];
|
|
127
|
+
declare const HASHED_OPERATORS: readonly ["equalsHashed", "notEqualsHashed", "inHashed", "notInHashed", "startsWithHashed", "notStartsWithHashed", "endsWithHashed", "notEndsWithHashed", "arrayContainsAnyHashed", "arrayNotContainsAnyHashed"];
|
|
128
|
+
declare const ATTRIBUTE_OPERATORS: readonly ["equals", "notEquals", "in", "notIn", "contains", "notContains", "startsWith", "notStartsWith", "endsWith", "notEndsWith", "regex", "notRegex", "numEquals", "numNotEquals", "gt", "gte", "lt", "lte", "semverEquals", "semverNotEquals", "semverGt", "semverGte", "semverLt", "semverLte", "semverIn", "semverNotIn", "before", "after", "arrayContainsAny", "arrayNotContainsAny", "arrayContainsAll", "isTrue", "isFalse", "exists", "notExists", "isType", "equalsHashed", "notEqualsHashed", "inHashed", "notInHashed", "startsWithHashed", "notStartsWithHashed", "endsWithHashed", "notEndsWithHashed", "arrayContainsAnyHashed", "arrayNotContainsAnyHashed"];
|
|
129
|
+
type AttributeOperator = (typeof ATTRIBUTE_OPERATORS)[number];
|
|
130
|
+
interface AttributeCondition {
|
|
131
|
+
kind: "attribute";
|
|
132
|
+
attribute: string;
|
|
133
|
+
operator: AttributeOperator;
|
|
134
|
+
values?: JsonValue[];
|
|
135
|
+
caseInsensitive?: boolean;
|
|
136
|
+
}
|
|
137
|
+
interface SegmentCondition {
|
|
138
|
+
kind: "segment";
|
|
139
|
+
operator: "in" | "notIn";
|
|
140
|
+
segment: string;
|
|
141
|
+
}
|
|
142
|
+
interface FlagCondition {
|
|
143
|
+
kind: "flag";
|
|
144
|
+
flag: string;
|
|
145
|
+
operator: FlagComparisonOperator;
|
|
146
|
+
value?: JsonValue;
|
|
147
|
+
}
|
|
148
|
+
interface GroupCondition {
|
|
149
|
+
kind: "group";
|
|
150
|
+
op: "and" | "or";
|
|
151
|
+
negate?: boolean;
|
|
152
|
+
conditions: Condition[];
|
|
153
|
+
}
|
|
154
|
+
type Condition = AttributeCondition | SegmentCondition | FlagCondition | GroupCondition;
|
|
155
|
+
interface ConditionSegment {
|
|
156
|
+
key: string;
|
|
157
|
+
kind: "conditions";
|
|
158
|
+
conditions: Condition[];
|
|
159
|
+
}
|
|
160
|
+
interface ListSegment {
|
|
161
|
+
key: string;
|
|
162
|
+
kind: "list";
|
|
163
|
+
attribute: string;
|
|
164
|
+
values: string[];
|
|
165
|
+
hashed?: boolean;
|
|
166
|
+
}
|
|
167
|
+
type SegmentDefinition = ConditionSegment | ListSegment;
|
|
168
|
+
interface HoldoutDefinition {
|
|
169
|
+
key: string;
|
|
170
|
+
hashAttribute: string;
|
|
171
|
+
seed: string;
|
|
172
|
+
coverage: number;
|
|
173
|
+
flags: string[];
|
|
174
|
+
}
|
|
175
|
+
type EvaluationReason = "FLAG_NOT_FOUND" | "DISABLED" | "PREREQUISITE_FAILED" | "HOLDOUT" | "RULE_MATCH" | "EXPERIMENT" | "DEFAULT" | "OVERRIDE" | "ERROR";
|
|
176
|
+
interface ExperimentAssignment {
|
|
177
|
+
key: string;
|
|
178
|
+
name?: string;
|
|
179
|
+
variationId: string;
|
|
180
|
+
variationName?: string;
|
|
181
|
+
variationIndex: number;
|
|
182
|
+
hashAttribute: string;
|
|
183
|
+
hashValue: string;
|
|
184
|
+
bucket: number;
|
|
185
|
+
stickyBucketUsed: boolean;
|
|
186
|
+
}
|
|
187
|
+
interface EvaluationResult<T = JsonValue> {
|
|
188
|
+
key: string;
|
|
189
|
+
value: T | null;
|
|
190
|
+
reason: EvaluationReason;
|
|
191
|
+
ruleId?: string;
|
|
192
|
+
variationId?: string;
|
|
193
|
+
inExperiment: boolean;
|
|
194
|
+
experiment?: ExperimentAssignment;
|
|
195
|
+
errorMessage?: string;
|
|
196
|
+
}
|
|
197
|
+
/** Sticky bucket documents: `"<attribute>||<value>"` → `{ "<experimentKey>__<bucketVersion>": variationId }`. */
|
|
198
|
+
type StickyAssignments = Record<string, string>;
|
|
199
|
+
interface StickyBucketStore {
|
|
200
|
+
get(docKey: string): StickyAssignments | null | undefined;
|
|
201
|
+
set(docKey: string, assignments: StickyAssignments): void;
|
|
202
|
+
}
|
|
203
|
+
/** Response of `POST /api/v1/sdk/flags/evaluate`. */
|
|
204
|
+
interface RemoteEvaluationResponse {
|
|
205
|
+
version: number;
|
|
206
|
+
flags: Record<string, EvaluationResult>;
|
|
207
|
+
}
|
|
208
|
+
/** Body of `POST /api/v1/sdk/flags/events`. */
|
|
209
|
+
interface FlagEventsBatch {
|
|
210
|
+
sdk?: {
|
|
211
|
+
name: string;
|
|
212
|
+
version: string;
|
|
213
|
+
};
|
|
214
|
+
usage?: Array<{
|
|
215
|
+
flag: string;
|
|
216
|
+
variationId?: string;
|
|
217
|
+
value?: string;
|
|
218
|
+
count: number;
|
|
219
|
+
}>;
|
|
220
|
+
exposures?: Array<{
|
|
221
|
+
experiment: string;
|
|
222
|
+
flag?: string;
|
|
223
|
+
variationId: string;
|
|
224
|
+
hashAttribute: string;
|
|
225
|
+
hashValue: string;
|
|
226
|
+
userId?: string;
|
|
227
|
+
anonymousId?: string;
|
|
228
|
+
timestamp: string;
|
|
229
|
+
}>;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
declare function fnv1a32(bytes: Uint8Array): number;
|
|
233
|
+
/** Deterministic bucket in [0, 1) with 4 decimals (GrowthBook hash v2 for ASCII input). */
|
|
234
|
+
declare function hashBucket(seed: string, value: string): number;
|
|
235
|
+
/** Lowercase hex SHA-256 of the UTF-8 bytes of `input`. */
|
|
236
|
+
declare function sha256Hex(input: string | Uint8Array): string;
|
|
237
|
+
/** `H(x)` for the hashed operators: SHA-256 of `salt + value`. */
|
|
238
|
+
declare function hashConfidential(salt: string, value: string | Uint8Array): string;
|
|
239
|
+
/** Comparison value for the hashed prefix/suffix operators: `"<byteLength>_<H(part)>"`. */
|
|
240
|
+
declare function hashConfidentialAffix(salt: string, part: string): string;
|
|
241
|
+
|
|
242
|
+
/** Value conversions used by the condition operators (docs/feature-flags-spec.md §3.2–3.3). */
|
|
243
|
+
/** Text form of a scalar, or `undefined` for arrays, objects, null and non-finite numbers. */
|
|
244
|
+
declare function textOf(v: unknown): string | undefined;
|
|
245
|
+
declare function numberOf(v: unknown): number | undefined;
|
|
246
|
+
interface SemVer {
|
|
247
|
+
major: number;
|
|
248
|
+
minor: number;
|
|
249
|
+
patch: number;
|
|
250
|
+
pre: string[];
|
|
251
|
+
}
|
|
252
|
+
declare function parseSemver(v: unknown): SemVer | undefined;
|
|
253
|
+
/** SemVer 2.0 precedence: -1, 0 or 1. */
|
|
254
|
+
declare function compareSemver(a: SemVer, b: SemVer): number;
|
|
255
|
+
/** Milliseconds since the epoch: numbers are Unix seconds, strings ISO 8601, Date objects as-is. */
|
|
256
|
+
declare function instantOf(v: unknown): number | undefined;
|
|
257
|
+
/** JSON deep equality; numbers compare numerically, object keys unordered. */
|
|
258
|
+
declare function jsonEquals(a: unknown, b: unknown): boolean;
|
|
259
|
+
/** `isOn`: anything except null, false, 0 and "". */
|
|
260
|
+
declare function isOn(v: unknown): boolean;
|
|
261
|
+
|
|
262
|
+
interface EvaluateOptions {
|
|
263
|
+
/** Evaluation time (default: now). */
|
|
264
|
+
now?: Date | number | string;
|
|
265
|
+
/** Sticky bucketing store; experiments keep a user's variation across config changes. */
|
|
266
|
+
stickyBuckets?: StickyBucketStore;
|
|
267
|
+
}
|
|
268
|
+
/** Attribute by literal key, then by dot path. `null` counts as missing (`undefined`). */
|
|
269
|
+
declare function lookupAttribute(attributes: Attributes, name: string): unknown;
|
|
270
|
+
declare function isScheduleActive(schedule: RuleSchedule | undefined, now: number): boolean;
|
|
271
|
+
declare function effectiveCoverage(rule: {
|
|
272
|
+
coverage: number;
|
|
273
|
+
ramp?: Array<{
|
|
274
|
+
at: string;
|
|
275
|
+
coverage: number;
|
|
276
|
+
}>;
|
|
277
|
+
}, now: number): number;
|
|
278
|
+
/** Evaluate one flag. Never throws: problems come back as reason `ERROR`. */
|
|
279
|
+
declare function evaluateFlag(payload: FlagsPayload, key: string, attributes?: Attributes, options?: EvaluateOptions): EvaluationResult;
|
|
280
|
+
/** Evaluate every flag in the payload. */
|
|
281
|
+
declare function evaluateAllFlags(payload: FlagsPayload, attributes?: Attributes, options?: EvaluateOptions): Record<string, EvaluationResult>;
|
|
282
|
+
|
|
283
|
+
export { ARRAY_OPERATORS, ATTRIBUTE_OPERATORS, type AttributeCondition, type AttributeOperator, type Attributes, BOOLEAN_OPERATORS, type Condition, type ConditionSegment, DATE_OPERATORS, type EncryptedFlagsPayload, type EvaluateOptions, type EvaluationReason, type EvaluationResult, type ExperimentAssignment, type ExperimentNamespace, type ExperimentRule, type ExperimentVariation, type FlagComparisonOperator, type FlagCondition, type FlagDefinition, type FlagEventsBatch, type FlagRule, type FlagRuleType, type FlagValueType, type FlagsPayload, type ForceRule, type GroupCondition, HASHED_OPERATORS, type HoldoutDefinition, type JsonValue, type ListSegment, NUMBER_OPERATORS, PRESENCE_OPERATORS, type Prerequisite, type RampStep, type RemoteEvaluationResponse, type RolloutRule, type RuleSchedule, SEMVER_OPERATORS, type SegmentCondition, type SegmentDefinition, type SplitBucket, type SplitRule, type StickyAssignments, type StickyBucketStore, TEXT_OPERATORS, compareSemver, effectiveCoverage, evaluateAllFlags, evaluateFlag, fnv1a32, hashBucket, hashConfidential, hashConfidentialAffix, instantOf, isOn, isScheduleActive, jsonEquals, lookupAttribute, numberOf, parseSemver, sha256Hex, textOf };
|