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,107 @@
# `flags/flags` — feature-flagged format-version rollouts
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`flags.ts` wires `@suaveplan/packer` into the `@suaveplan/feature-flags`
ecosystem so future wire-format versions can be rolled out behind
runtime flags without forcing every consumer to upgrade in lockstep.
Today the package writes V1 unconditionally; the flag surface is the
contract that a future V2 codec slots into. The exported
`defaultPackerFlags()` provider is a no-op that returns the V1 default
for every flag, so callers who don't care about rollouts never have to
configure anything.
## Features
- `PACKER_FLAG_KEYS.FORMAT_V2 = "packer.format.v2"` — single source of
truth for the V2 rollout flag key.
- `defaultPackerFlags()` — no-op provider; every flag resolves to its
V1 default (`false` for `packer.format.v2`).
- `resolvePackerFlags(opts)` — adapter that accepts either a raw
`PackerFeatureFlags` provider or a `{ evaluator, context }` bundle
pointing at a `@suaveplan/feature-flags` `Evaluator`.
- `enforceFormatVersionGate(flags, resolver)` — production write-path
helper that throws `PACKER.FORMAT_VERSION_UNSUPPORTED` when V2 is
enabled (V2 codec is a future change).
- Boolean flags only — the package's flag surface is intentionally
small; semver versions are records under `@suaveplan/schema-registry`,
not under feature flags.
## Usage: Basic
```ts
import { Packer } from "@suaveplan/packer";
// No `flags` option — V1 default behaviour.
const packer = new Packer({ encryption: { algorithm: "aes-256-gcm", key } });
const packed = await packer.pack(payload);
```
## Usage: Advanced
```ts
import {
Evaluator,
FlagRegistry,
MemoryProvider,
UserTargetStrategy,
} from "@suaveplan/feature-flags";
import { Packer } from "@suaveplan/packer";
import { PACKER_FLAG_KEYS } from "@suaveplan/packer/flags";
// Roll out V2 to a 1% canary via a feature-flags Evaluator.
const provider = new MemoryProvider();
const registry = new FlagRegistry({ provider });
registry.register({
key: PACKER_FLAG_KEYS.FORMAT_V2,
type: "boolean",
defaultValue: false,
});
const evaluator = new Evaluator({
strategies: [
new UserTargetStrategy({ users: ["canary-1"], value: true }),
],
});
const packer = new Packer({
encryption: { algorithm: "aes-256-gcm", key },
flags: { evaluator, context: { userId: "canary-1" } },
});
// In this canary build the call would throw FORMAT_VERSION_UNSUPPORTED
// until V2 ships.
await packer.pack(payload).catch((err) => {
console.log(err.code); // "PACKER.FORMAT_VERSION_UNSUPPORTED"
});
```
## API Reference
- `defaultPackerFlags(): PackerFeatureFlags`
- No-op provider returning V1 defaults for every flag.
- `resolvePackerFlags(opts?: PackerFlagsOptions): PackerFeatureFlags`
- Adapts either `{ evaluator, context? }` or `{ provider }` into the
internal `PackerFeatureFlags` surface; defaults to
`defaultPackerFlags()` when `opts` is undefined.
- `enforceFormatVersionGate(flags, resolver): void`
- Throws `PackerError(PACKER.FORMAT_VERSION_UNSUPPORTED)` when
`packer.format.v2` resolves to `true`.
- `PACKER_FLAG_KEYS`
- Frozen object exposing every flag key used by the package.
## Implementation Notes
The `Evaluator` adapter constructs a `FlagDefinition` on the fly from
the internal `FLAG_DEFINITIONS` table — this keeps the public surface
flat (callers don't have to register flags themselves) while still
flowing through the canonical evaluation pipeline (strategies, default
reasons, OTel counters wired up by `@suaveplan/feature-flags`). The
provider surface is boolean-only by design; multi-valued flags would be
a different abstraction. The V2 gate is invoked once per `Packer.pack`
call, after option validation and idempotency lookup but before any
expensive pipeline work, so an enabled V2 flag fails fast without
producing partial side effects.