Flag context
The evaluation context a flag decision is made against: the principal the request acts for, the attributes a targeting rule reads, and the targeting key that places the principal in a percentage rollout.
b.flag.context.create(input?) #
Freeze an operator-built evaluation context. Copies the own enumerable keys of input, dropping any key that would reach a prototype, and returns the result frozen. Raises flag/bad-context when input is not a plain object or when targetingKey is present and not a string.
var b = require("blamejs");
var ctx = b.flag.context.create({ targetingKey: "alice", role: "admin" });
ctx.role; // → "admin"
Object.isFrozen(ctx); // → true
b.flag.context.merge(base, overlay) #
Layer one evaluation context over another and freeze the result. A key present in overlay wins; a key only in base is carried through. Both sides are read for own enumerable keys alone, so neither can reach a prototype.
var b = require("blamejs");
var ctx = b.flag.context.merge({ role: "guest", locale: "en" },
{ role: "admin" });
ctx.role; // → "admin"
ctx.locale; // → "en"
b.flag.context.fromRequest(req, opts?) #
{
userKey: string, // use this as the targetingKey verbatim
actorKey: function, // (actor) → the name, where the actor's shape is the operator's
tenantKey: string, // overrides the tenant read from the actor
extra: object, // merged into the context
trustedProxies: string[], // CIDRs whose forwarded headers are honored
forwardedHeaders: string[], // named forwarded headers to read
clientIpResolver: function, // (req) → the client address
}
Build the evaluation context for a flag decision from a request. Reads the principal from req.user, the locale from Accept-Language and the agent from User-Agent, and returns a frozen context carrying targetingKey alongside userId, role, email, tenantId, locale and userAgent where the request supplies them. A targeting rule reads any path through that context, so attribute: "role" resolves role.
targetingKey places the principal in a percentage rollout and separates one principal's cached decision from another's. It is b.requestHelpers.actorIdentityKey of the actor, which tags the field the name came from, so { id: "x" } and { sub: "x" } are two principals. opts.userKey replaces it outright. An actor carrying no name that resolver reads, and an unauthenticated request, are keyed by the client address through b.requestHelpers.trustedClientIp, so a forwarded header moves that key only where the operator declared the proxy it arrives through.
var b = require("blamejs");
var ctx = b.flag.context.fromRequest({
user: { sub: "alice", role: "admin" },
headers: { "accept-language": "en-GB,en;q=0.9" },
});
ctx.userId; // → "alice"
ctx.role; // → "admin"
ctx.locale; // → "en-GB"
b.flag.context.bucketOf(targetingKey, flagKey) #
Place a principal in a percentage rollout for one flag: a number from 0 up to 100, two decimal places, from SHA3-512 over the flag key and the targeting key together. The flag key participates, so a principal in the first decile of one rollout is not thereby in the first decile of every rollout. The same pair always answers the same number, and a rollout of p percent admits the principal when the bucket is below p. Either argument missing or empty answers 0.
var b = require("blamejs");
b.flag.context.bucketOf("alice", "beta"); // → 25.04
b.flag.context.bucketOf("", "beta"); // → 0