@samveys/flags
Dari packages/flags/README.md di repository framework.
Halaman ini belum diterjemahkan. Kamu sedang membaca versi bahasa Inggris.
Feature flags with an OpenFeature-compatible evaluation API and a built-in database provider. No runtime dependencies.
Set up
import { flags } from '@samveys/flags'
export const plugin = flags({ defaultContext: { environment: 'production' } })The plugin binds 'flags' (a FlagClient). Without a provider it reads the table samveys_feature_flags(key, enabled, rollout_percent, variants JSON, rules JSON) from the 'db' binding and creates it on first use. A change in the table is visible to every process on the next evaluation.
Evaluate
import { createDatabaseFlagProvider, createFlagClient } from '@samveys/flags'
import { createDatabaseManager, defineDatabaseConfig, sqlite } from '@samveys/database'
const db = createDatabaseManager(defineDatabaseConfig({ default: 'main', connections: { main: sqlite({ file: ':memory:' }) } }))
const provider = createDatabaseFlagProvider({ database: () => db })
const client = createFlagClient(provider)
export async function example(userId: string) {
await provider.save({ key: 'new-checkout', enabled: true, rolloutPercent: 10 })
const on = await client.getBooleanValue('new-checkout', false, { targetingKey: userId })
const details = await client.getBooleanDetails('new-checkout', false, { targetingKey: userId })
// details: { flagKey, value, variant: 'on' | 'off', reason: 'SPLIT' }
return { on, reason: details.reason }
}getBooleanValue, getStringValue, getNumberValue and getObjectValue return the value; the …Details versions return { flagKey, value, variant, reason, errorCode?, errorMessage? }. Evaluation never throws: an unknown flag, a missing targetingKey for a partial rollout, a wrong type or a failing database returns your default with reason: 'ERROR' and an errorCode (FLAG_NOT_FOUND, TARGETING_KEY_MISSING, TYPE_MISMATCH, GENERAL).
How a flag decides
enabled = false→ your default (reason: 'DISABLED').- The first matching rule wins (
reason: 'TARGETING_MATCH'):{ attribute, operator, value, variant }withequals,notEquals,in,notIn,contains,startsWith,endsWith,gt,gte,lt,lte, tested against the evaluation context. rolloutPercent100 →on; 0 →off.- Otherwise the user's bucket decides (
reason: 'SPLIT'): the first 4 bytes ofSHA-256("<flagKey>:<targetingKey>")as an unsigned integer, modulo 100; the user is in when the bucket is belowrolloutPercent.
The bucket depends only on the flag key and the user, so a user keeps their answer across requests, processes, machines and releases, and raising a rollout from 10 % to 25 % only adds users.
variants maps on / off (and any rule variant) to values: { "on": "dark", "off": "light" } for a string flag. Boolean flags need no variants.
await provider.save({
key: 'beta',
enabled: true,
rolloutPercent: 0,
rules: [{ attribute: 'plan', operator: 'in', value: ['pro', 'team'], variant: 'on' }],
})