first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
# targeting.ts — Targeting Rule Evaluation
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Provides the `evaluateTargeting` function that evaluates an ordered list of
targeting rules against a set of user attributes. The function implements AND
semantics — every rule in the list must pass for the user to be considered
eligible for the experiment. This single-function module is intentionally
small and pure: it has no side effects, no I/O, no external dependencies, and
is trivially unit-testable.
Targeting rules are the primary mechanism for gating experiment exposure to
specific user segments. Common use cases include restricting to paid users,
specific geographic regions, device types, or beta-program membership.
## Features
- Eight comparison operators: `eq`, `neq`, `in`, `notIn`, `gt`, `lt`, `gte`, `lte`
- Numeric ordering operators (`gt`, `lt`, `gte`, `lte`) require both sides to
be numbers; any type mismatch returns `false` rather than throwing
- `in` / `notIn` accept any array on the right-hand side
- An empty rules array always returns `true` (no restriction)
- Absent attributes evaluate to `undefined` and fail equality/ordering tests
gracefully without exceptions
## Usage: Basic Example
```ts
import { evaluateTargeting } from '@suaveplan/ab-testing/targeting';
const eligible = evaluateTargeting(
[{ attribute: 'plan', operator: 'eq', value: 'premium' }],
{ plan: 'premium', country: 'US' }
);
console.log(eligible); // true
```
## Usage: Advanced Example
```ts
import { evaluateTargeting } from '@suaveplan/ab-testing/targeting';
// Multi-rule targeting: premium users in North America with high session count
const rules = [
{ attribute: 'plan', operator: 'eq' as const, value: 'premium' },
{ attribute: 'country', operator: 'in' as const, value: ['US', 'CA', 'MX'] },
{ attribute: 'sessionCount', operator: 'gte' as const, value: 10 },
{ attribute: 'blocklisted', operator: 'neq' as const, value: true },
];
const user1 = { plan: 'premium', country: 'CA', sessionCount: 15, blocklisted: false };
const user2 = { plan: 'free', country: 'US', sessionCount: 30, blocklisted: false };
console.log(evaluateTargeting(rules, user1)); // true (all 4 rules pass)
console.log(evaluateTargeting(rules, user2)); // false (plan !== 'premium')
```
## API Reference
### `evaluateTargeting(rules, attributes): boolean`
- **`rules`** — `ReadonlyArray<TargetingRule>` — ordered list of predicates
- **`attributes`** — `UserAttributes` (`Record<string, string | number | boolean>`)
- **Returns** — `boolean` — `true` iff every rule is satisfied (or `rules` is empty)
#### Supported operators
| Operator | Description | RHS type |
|---|---|---|
| `eq` | Strict equality (`===`) | any |
| `neq` | Strict inequality (`!==`) | any |
| `in` | LHS is contained in RHS array | `unknown[]` |
| `notIn` | LHS is not contained in RHS array | `unknown[]` |
| `gt` | LHS > RHS | `number` |
| `lt` | LHS < RHS | `number` |
| `gte` | LHS >= RHS | `number` |
| `lte` | LHS <= RHS | `number` |
## Implementation Notes
All comparisons are intentionally strict (`===` / `!==`) to avoid surprising
truthy/falsy coercions. When the RHS is not of the expected type for ordering
operators (e.g. a string is passed as the threshold for `gt`), the function
returns `false` rather than throwing, making it safe to evaluate partially
invalid rule sets without crashing the assignment pipeline.
The `in` / `notIn` operators use `Array.isArray` to check the RHS type before
calling `Array.prototype.includes`. When the RHS is not an array, the rule
evaluates to `false`.