first commit
This commit is contained in:
112
docs/security-stack/security/license/src/flags/flags.md
Normal file
112
docs/security-stack/security/license/src/flags/flags.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# `@suaveplan/license` — flags
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Bitmask helpers for the 5-bit `flags` field (`LicenseFlags`) and the
|
||||
19-bit `featureMask` field. The flags field stores up to 5 boolean
|
||||
license states (`TRIAL`, `UPGRADE`, `MACHINE_LOCKED`, `SUBSCRIPTION`,
|
||||
`EDUCATIONAL`); the feature mask stores up to 19 product-specific
|
||||
feature toggles. This module gives type-safe accessors for both: the
|
||||
flag helpers are typed against the `LicenseFlags` enum; the feature
|
||||
helpers validate that the supplied index is within `[0, 18]` and raise
|
||||
`LicenseError(LICENSE.FEATURE_INDEX_OUT_OF_RANGE)` otherwise.
|
||||
|
||||
## Features
|
||||
|
||||
- `hasFlag` / `combineFlags` — flag-bit accessors typed against the
|
||||
`LicenseFlags` enum so misuses surface at compile time.
|
||||
- `hasFeature` / `combineFeatures` / `getEnabledFeatures` — feature-bit
|
||||
accessors with runtime index-range checks.
|
||||
- Out-of-range indices throw a typed `LicenseError`, never a generic
|
||||
`Error` — callers can `instanceof LicenseError` and dispatch on
|
||||
`error.code`.
|
||||
- `getEnabledFeatures` walks only the 19 declared bits, so callers
|
||||
feeding in stray high bits get a clean answer.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
combineFlags,
|
||||
hasFlag,
|
||||
hasFeature,
|
||||
} from "@suaveplan/license/flags/flags";
|
||||
import { LicenseFlags } from "@suaveplan/license/types/license";
|
||||
|
||||
const flags = combineFlags(LicenseFlags.TRIAL, LicenseFlags.SUBSCRIPTION);
|
||||
hasFlag(flags, LicenseFlags.TRIAL); // true
|
||||
hasFeature(0b1010, 1); // true
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Building a payload-shaped feature mask from a domain-specific feature
|
||||
enum, with overflow guard:
|
||||
|
||||
```ts
|
||||
import {
|
||||
combineFeatures,
|
||||
getEnabledFeatures,
|
||||
} from "@suaveplan/license/flags/flags";
|
||||
import { LicenseError } from "@suaveplan/license";
|
||||
|
||||
const enum Feature {
|
||||
Export = 0,
|
||||
BulkOps = 1,
|
||||
AdvancedSearch = 4,
|
||||
AiAssistant = 18,
|
||||
}
|
||||
|
||||
try {
|
||||
const mask = combineFeatures(
|
||||
Feature.Export,
|
||||
Feature.BulkOps,
|
||||
Feature.AdvancedSearch,
|
||||
Feature.AiAssistant
|
||||
);
|
||||
const enabled = getEnabledFeatures(mask); // [0, 1, 4, 18]
|
||||
} catch (e) {
|
||||
if (e instanceof LicenseError && e.code === "LICENSE.FEATURE_INDEX_OUT_OF_RANGE") {
|
||||
// upstream produced an out-of-range index
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `hasFlag(flags: number, flag: LicenseFlags): boolean`
|
||||
|
||||
Test whether `flag` is set in `flags`.
|
||||
|
||||
### `combineFlags(...flags: LicenseFlags[]): number`
|
||||
|
||||
OR-merge multiple flags into a single bitmask.
|
||||
|
||||
### `hasFeature(featureMask: number, featureIndex: number): boolean`
|
||||
|
||||
Test whether feature index `featureIndex` is set. Throws
|
||||
`LicenseError(LICENSE.FEATURE_INDEX_OUT_OF_RANGE)` when `featureIndex`
|
||||
is outside `[0, 18]`.
|
||||
|
||||
### `combineFeatures(...features: number[]): number`
|
||||
|
||||
OR-merge multiple feature indices into a single bitmask. Same range
|
||||
check as `hasFeature`.
|
||||
|
||||
### `getEnabledFeatures(featureMask: number): number[]`
|
||||
|
||||
Enumerate every enabled feature index in ascending order. Bits past
|
||||
index 18 are ignored (consistent with the 19-bit field width).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The 19-feature ceiling matches the 19-bit `featureMask` field in the
|
||||
license payload. The shared `ensureFeatureIndexInRange` helper means
|
||||
the two range-checking call sites stay in lockstep; if the bit budget
|
||||
ever changes, only one constant needs to move. The flag enum uses
|
||||
power-of-two values (`1 << 0`, `1 << 1`, ...) so `combineFlags` is a
|
||||
straight `reduce(|)`.
|
||||
Reference in New Issue
Block a user