@molecule/api-resource-feature-flag
v1.0.1
Published
Feature-flag CRUD with targeting rules, environments, and on/off/killed/scheduled states. Extracted from the feature-flag-manager flagship.
Maintainers
Readme
@molecule/api-resource-feature-flag
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
@molecule/api-resource-feature-flag — feature-flag CRUD + targeting
rules + environment-scoped rollout state.
Extracted from the feature-flag-manager flagship. Flags carry a
key (e.g. new-checkout-flow), a flag_type (boolean / multivariate
/ string / number), an is_enabled master switch, a rollout_percentage
(0-100), and a state (on / off / killed / scheduled). Targeting rules
attach to a flag and are evaluated in priority order.
Quick Start
import { createFeatureFlagRouter } from '@molecule/api-resource-feature-flag'
app.use('/flags', createFeatureFlagRouter())import { listFlagsForUser, createFlagForUser } from '@molecule/api-resource-feature-flag'
const flag = await createFlagForUser(userId, {
key: 'new-checkout-flow',
name: 'New checkout flow',
flag_type: 'boolean',
rollout_percentage: 5,
})Type
resource
Installation
npm install @molecule/api-resource-feature-flag @molecule/api-bonds-default-express @molecule/api-database @molecule/api-i18n @molecule/api-middleware-validation express zod
npm install -D @types/expressAPI
Interfaces
FeatureFlagRow
Database row shape for a feature flag definition.
interface FeatureFlagRow {
id: string
user_id: string
project_id: string | null
key: string
name: string
description: string | null
flag_type: FlagType
default_value: unknown
rollout_percentage: number
is_enabled: boolean
state: FlagState
environment: string
stale_days: number
created_at: string | Date
updated_at: string | Date
}FeatureFlagTargetingRuleRow
Database row shape for a targeting rule that overrides a flag's value for matching users.
interface FeatureFlagTargetingRuleRow {
id: string
flag_id: string
attribute: string
operator: string
value: unknown
serve_value: unknown
priority: number
description: string | null
created_at: string | Date
}Types
FlagState
Lifecycle state of a feature flag (active, disabled, killed, or time-gated).
type FlagState = 'on' | 'off' | 'killed' | 'scheduled'FlagType
Discriminates the value type carried by a feature flag.
type FlagType = 'boolean' | 'multivariate' | 'string' | 'number'Functions
addRuleToFlag(flagId, userId, data)
Appends a new targeting rule to a flag owned by the user and returns the persisted rule row.
function addRuleToFlag(
flagId: string,
userId: string,
data: {
attribute: string
operator: string
value?: unknown
serve_value?: unknown
priority?: number
description?: string
},
): Promise<FeatureFlagTargetingRuleRow | null>createFeatureFlagRouter()
Creates and returns an Express Router with all feature-flag and targeting-rule endpoints.
function createFeatureFlagRouter(): RoutercreateFlagForUser(userId, data)
Creates a new feature flag owned by the given user and returns the persisted row.
function createFlagForUser(
userId: string,
data: {
project_id?: string
key: string
name: string
description?: string
flag_type?: FlagType
default_value?: unknown
rollout_percentage?: number
is_enabled?: boolean
environment?: string
stale_days?: number
},
): Promise<FeatureFlagRow>deleteFlagForUser(flagId, userId)
Deletes a feature flag owned by the user, returning true on success or false if not found.
function deleteFlagForUser(flagId: string, userId: string): Promise<boolean>deleteRule(ruleId, flagId, userId)
Deletes a targeting rule from a flag owned by the user, returning true on success or false if not found.
function deleteRule(ruleId: string, flagId: string, userId: string): Promise<boolean>getFlagForUser(flagId, userId)
Fetches a single feature flag by ID, returning null if it does not exist or is not owned by the user.
function getFlagForUser(flagId: string, userId: string): Promise<FeatureFlagRow | null>listFlagsForUser(userId, opts?)
Returns a paginated list of feature flags owned by the given user, with optional project/environment/state filters.
function listFlagsForUser(
userId: string,
opts?: {
page?: number
limit?: number
project_id?: string
environment?: string
state?: FlagState
},
): Promise<{ data: FeatureFlagRow[]; total: number; page: number; limit: number }>listRulesForFlag(flagId, userId)
Returns all targeting rules for a flag in priority order, or null if the flag is not found or not owned by the user.
function listRulesForFlag(
flagId: string,
userId: string,
): Promise<FeatureFlagTargetingRuleRow[] | null>updateFlagForUser(flagId, userId, patch)
Applies a partial patch to a feature flag owned by the user and returns the updated row, or null if not found.
function updateFlagForUser(
flagId: string,
userId: string,
patch: Partial<{
name: string
description: string
default_value: unknown
rollout_percentage: number
is_enabled: boolean
state: FlagState
environment: string
stale_days: number
}>,
): Promise<FeatureFlagRow | null>Constants
FLAG_STATES
Allowed lifecycle states for a feature flag.
const FLAG_STATES: readonly ['on', 'off', 'killed', 'scheduled']FLAG_TYPES
Allowed value types for a feature flag.
const FLAG_TYPES: readonly ['boolean', 'multivariate', 'string', 'number']flagCreateSchema
Zod schema for validating a feature flag creation payload.
const flagCreateSchema: z.ZodObject<
{
project_id: z.ZodOptional<z.ZodString>
key: z.ZodString
name: z.ZodString
description: z.ZodOptional<z.ZodString>
flag_type: z.ZodOptional<
z.ZodEnum<{
string: 'string'
number: 'number'
boolean: 'boolean'
multivariate: 'multivariate'
}>
>
default_value: z.ZodOptional<z.ZodUnknown>
rollout_percentage: z.ZodOptional<z.ZodNumber>
is_enabled: z.ZodOptional<z.ZodBoolean>
environment: z.ZodOptional<z.ZodString>
stale_days: z.ZodOptional<z.ZodNumber>
},
z.core.$strip
>flagListQuerySchema
Zod schema for validating feature flag list query parameters.
const flagListQuerySchema: z.ZodObject<
{
page: z.ZodDefault<z.ZodCoercedNumber<unknown>>
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>
project_id: z.ZodOptional<z.ZodString>
environment: z.ZodOptional<z.ZodString>
state: z.ZodOptional<
z.ZodEnum<{ on: 'on'; off: 'off'; killed: 'killed'; scheduled: 'scheduled' }>
>
},
z.core.$strip
>flagUpdateSchema
Zod schema for validating a feature flag update payload.
const flagUpdateSchema: z.ZodObject<
{
name: z.ZodOptional<z.ZodString>
description: z.ZodOptional<z.ZodString>
default_value: z.ZodOptional<z.ZodUnknown>
rollout_percentage: z.ZodOptional<z.ZodNumber>
is_enabled: z.ZodOptional<z.ZodBoolean>
state: z.ZodOptional<
z.ZodEnum<{ on: 'on'; off: 'off'; killed: 'killed'; scheduled: 'scheduled' }>
>
environment: z.ZodOptional<z.ZodString>
stale_days: z.ZodOptional<z.ZodNumber>
},
z.core.$strip
>ruleSchema
Zod schema for validating a targeting rule on a feature flag.
const ruleSchema: z.ZodObject<
{
attribute: z.ZodString
operator: z.ZodString
value: z.ZodOptional<z.ZodUnknown>
serve_value: z.ZodOptional<z.ZodUnknown>
priority: z.ZodOptional<z.ZodNumber>
description: z.ZodOptional<z.ZodString>
},
z.core.$strip
>Injection Notes
Requirements
Peer dependencies:
@molecule/api-bonds-default-express^1.0.1@molecule/api-database^1.0.1@molecule/api-i18n^1.0.1@molecule/api-middleware-validation^1.0.1express^5.0.0zod^4.0.0
Runtime Dependencies
@molecule/api-bonds-default-express@molecule/api-database@molecule/api-i18n@molecule/api-middleware-validationexpresszod
Tables: src/__setup__/feature_flags.sql creates feature_flags +
feature_flag_targeting_rules. An mlcl-scaffolded API replays
__setup__/*.sql automatically on migrate; anywhere else run it once —
nothing at runtime creates the tables.
Flags are OWNER-SCOPED rows, not app-global config: every service function
is …ForUser(userId, …) and the router reads the caller from
res.locals.session (mount it behind your global auth middleware — without
a session every request 401s). One user's flags are invisible to another;
for team-/app-wide flags, evaluate against a shared owning account or wrap
the service with your own scoping.
This package STORES flags + targeting rules; it does NOT evaluate them.
There is no /evaluate endpoint or client SDK — resolve a flag for an end
user in your app code: fetch the flag + rules, apply rules in priority
order, and honor is_enabled, state, and rollout_percentage.
