@velajs/feature-flags 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/feature-flags.service-CNOZ1DhZ.js +343 -0
- package/dist/feature-flags.service-CNOZ1DhZ.js.map +1 -0
- package/dist/index.d.ts +115 -12
- package/dist/index.js +114 -15
- package/dist/index.js.map +1 -0
- package/dist/memory.driver-C-5Y2b7_.d.ts +235 -0
- package/dist/testing/index.d.ts +11 -11
- package/dist/testing/index.js +28 -34
- package/dist/testing/index.js.map +1 -0
- package/package.json +53 -39
- package/dist/decorators/feature-flag.decorator.d.ts +0 -35
- package/dist/decorators/feature-flag.decorator.js +0 -26
- package/dist/drivers/driver.d.ts +0 -21
- package/dist/drivers/driver.js +0 -13
- package/dist/drivers/memory.driver.d.ts +0 -35
- package/dist/drivers/memory.driver.js +0 -50
- package/dist/drivers/registry.d.ts +0 -24
- package/dist/drivers/registry.js +0 -51
- package/dist/feature-flags.error.d.ts +0 -14
- package/dist/feature-flags.error.js +0 -15
- package/dist/feature-flags.module.d.ts +0 -21
- package/dist/feature-flags.module.js +0 -63
- package/dist/feature-flags.service.d.ts +0 -83
- package/dist/feature-flags.service.js +0 -208
- package/dist/feature-flags.tokens.d.ts +0 -16
- package/dist/feature-flags.tokens.js +0 -10
- package/dist/feature-flags.types.d.ts +0 -71
- package/dist/feature-flags.types.js +0 -3
- package/dist/guards/feature-flag.guard.d.ts +0 -24
- package/dist/guards/feature-flag.guard.js +0 -52
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { moduleToken } from "@velajs/vela";
|
|
2
|
-
/**
|
|
3
|
-
* Injection tokens for the feature-flags module. Named on the
|
|
4
|
-
* `vela:feature-flags:<thing>` convention so identity is stable across
|
|
5
|
-
* refactors and consumers can `@Inject(FEATURE_FLAG_TOKENS.Service)`.
|
|
6
|
-
*/ export const FEATURE_FLAG_TOKENS = {
|
|
7
|
-
/** The resolved {@link FeatureFlagsOptions} (module options token). */ Options: moduleToken('vela:feature-flags:options'),
|
|
8
|
-
/** The injectable {@link FeatureFlagsService}. */ Service: moduleToken('vela:feature-flags:service'),
|
|
9
|
-
/** The {@link FeatureFlagDriverRegistry} built from the options' drivers. */ DriverRegistry: moduleToken('vela:feature-flags:driver-registry')
|
|
10
|
-
};
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import type { RequestContext } from '@velajs/vela';
|
|
2
|
-
import type { FeatureFlagDriver } from './drivers/driver';
|
|
3
|
-
/**
|
|
4
|
-
* A value a feature flag can resolve to. Mirrors the four evaluation methods
|
|
5
|
-
* on {@link FeatureFlagDriver}.
|
|
6
|
-
*/
|
|
7
|
-
export type FlagValue = boolean | string | number | object;
|
|
8
|
-
/**
|
|
9
|
-
* A free-form evaluation context handed to a driver (for targeting: user id,
|
|
10
|
-
* plan, country, …). Drivers that don't do targeting ignore it.
|
|
11
|
-
*/
|
|
12
|
-
export type FlagContext = Record<string, unknown>;
|
|
13
|
-
/**
|
|
14
|
-
* Augment this interface to get typed flag keys on the service and the
|
|
15
|
-
* `@FeatureFlag()` decorator.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```ts
|
|
19
|
-
* declare module '@velajs/feature-flags' {
|
|
20
|
-
* interface FeatureFlagRegistry {
|
|
21
|
-
* 'new-checkout': boolean;
|
|
22
|
-
* 'checkout-flow': string;
|
|
23
|
-
* }
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export interface FeatureFlagRegistry {
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* A flag key. Narrows to the declared {@link FeatureFlagRegistry} keys when the
|
|
31
|
-
* app augments it; falls back to `string` otherwise.
|
|
32
|
-
*/
|
|
33
|
-
export type FlagKey = keyof FeatureFlagRegistry extends never ? string : keyof FeatureFlagRegistry & string;
|
|
34
|
-
/**
|
|
35
|
-
* A declared set of flags and their default values.
|
|
36
|
-
*
|
|
37
|
-
* Drivers have no enumeration API, so the flags you intend to evaluate as a
|
|
38
|
-
* batch (via {@link FeatureFlagsService.all}) must be declared once here. Each
|
|
39
|
-
* default also doubles as the type hint used to pick the evaluation method.
|
|
40
|
-
*/
|
|
41
|
-
export type FlagManifest = Record<string, FlagValue>;
|
|
42
|
-
/** Why an evaluation returned the value it did. */
|
|
43
|
-
export type FlagEvaluationReason = 'STATIC' | 'DEFAULT' | 'ERROR';
|
|
44
|
-
/** A flag value plus the metadata the service synthesizes around a driver read. */
|
|
45
|
-
export interface FlagEvaluationDetails<T extends FlagValue = FlagValue> {
|
|
46
|
-
flagKey: string;
|
|
47
|
-
value: T;
|
|
48
|
-
reason: FlagEvaluationReason;
|
|
49
|
-
errorMessage?: string;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Feature-flags module configuration.
|
|
53
|
-
*/
|
|
54
|
-
export interface FeatureFlagsOptions {
|
|
55
|
-
/**
|
|
56
|
-
* The drivers this app can evaluate against. When omitted, a single
|
|
57
|
-
* in-memory {@link MemoryFlagDriver} named `"memory"` is used (all flags
|
|
58
|
-
* resolve to their declared defaults).
|
|
59
|
-
*/
|
|
60
|
-
drivers?: FeatureFlagDriver[];
|
|
61
|
-
/** Name of the driver the injected service targets. Defaults to `drivers[0].name`. */
|
|
62
|
-
default?: string;
|
|
63
|
-
/** Declared flags + defaults. Powers manifest defaults and {@link FeatureFlagsService.all}. */
|
|
64
|
-
manifest?: FlagManifest;
|
|
65
|
-
/**
|
|
66
|
-
* Resolves a per-request evaluation context (for example `{ userId }`) merged
|
|
67
|
-
* into every evaluation. Per-call context passed to a method overrides these.
|
|
68
|
-
* Receives the current request context; skipped outside request scope.
|
|
69
|
-
*/
|
|
70
|
-
context?: (ctx: RequestContext) => FlagContext | Promise<FlagContext>;
|
|
71
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type CanActivate, type ExecutionContext } from '@velajs/vela';
|
|
2
|
-
import type { FeatureFlagsService } from '../feature-flags.service';
|
|
3
|
-
/**
|
|
4
|
-
* Route gate for `@FeatureFlag()`. Reads the handler/controller metadata, then
|
|
5
|
-
* `getBooleanValue(key)`; when the flag is off it throws `NotFoundException`
|
|
6
|
-
* (the route appears hidden) or `ForbiddenException` per the decorator option.
|
|
7
|
-
* Handlers with no `@FeatureFlag()` metadata pass through untouched, so the
|
|
8
|
-
* guard is safe to register app-wide (`FeatureFlagsModule.forRoot({ isGlobal:
|
|
9
|
-
* true })`) or per-route via `@UseGuards(FeatureFlagGuard)`.
|
|
10
|
-
*
|
|
11
|
-
* It does NOT inject `REQUEST_CONTEXT` — that would make the guard request-
|
|
12
|
-
* scoped and break lazy-module materialization (which constructs every provider
|
|
13
|
-
* once, at first use, possibly outside a request). Instead it reads the request
|
|
14
|
-
* context off the per-request child container carried on the Hono context, so
|
|
15
|
-
* the module's `context` resolver still runs for the gate decision.
|
|
16
|
-
*/
|
|
17
|
-
export declare class FeatureFlagGuard implements CanActivate {
|
|
18
|
-
private readonly flags;
|
|
19
|
-
private readonly reflector;
|
|
20
|
-
constructor(flags: FeatureFlagsService);
|
|
21
|
-
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
22
|
-
/** The current request context, via the child container on the Hono context. */
|
|
23
|
-
private requestContext;
|
|
24
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
}
|
|
7
|
-
function _ts_metadata(k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
}
|
|
10
|
-
function _ts_param(paramIndex, decorator) {
|
|
11
|
-
return function(target, key) {
|
|
12
|
-
decorator(target, key, paramIndex);
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
import { ForbiddenException, Inject, Injectable, NotFoundException, REQUEST_CONTEXT, Reflector } from "@velajs/vela";
|
|
16
|
-
import { FEATURE_FLAG_METADATA } from "../decorators/feature-flag.decorator.js";
|
|
17
|
-
import { FEATURE_FLAG_TOKENS } from "../feature-flags.tokens.js";
|
|
18
|
-
export class FeatureFlagGuard {
|
|
19
|
-
flags;
|
|
20
|
-
reflector = new Reflector();
|
|
21
|
-
constructor(flags){
|
|
22
|
-
this.flags = flags;
|
|
23
|
-
}
|
|
24
|
-
async canActivate(context) {
|
|
25
|
-
const meta = this.reflector.getAllAndOverride(FEATURE_FLAG_METADATA, context);
|
|
26
|
-
if (!meta) return true;
|
|
27
|
-
const requestContext = this.requestContext(context);
|
|
28
|
-
const flags = requestContext ? this.flags.forRequest(requestContext) : this.flags;
|
|
29
|
-
const enabled = await flags.getBooleanValue(meta.key);
|
|
30
|
-
if (enabled) return true;
|
|
31
|
-
if (meta.onDisabled === 'forbidden') {
|
|
32
|
-
throw new ForbiddenException(`Feature "${meta.key}" is not enabled.`);
|
|
33
|
-
}
|
|
34
|
-
throw new NotFoundException();
|
|
35
|
-
}
|
|
36
|
-
/** The current request context, via the child container on the Hono context. */ requestContext(context) {
|
|
37
|
-
try {
|
|
38
|
-
const container = context.getContext().get('container');
|
|
39
|
-
return container?.resolve(REQUEST_CONTEXT);
|
|
40
|
-
} catch {
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
FeatureFlagGuard = _ts_decorate([
|
|
46
|
-
Injectable(),
|
|
47
|
-
_ts_param(0, Inject(FEATURE_FLAG_TOKENS.Service)),
|
|
48
|
-
_ts_metadata("design:type", Function),
|
|
49
|
-
_ts_metadata("design:paramtypes", [
|
|
50
|
-
typeof FeatureFlagsService === "undefined" ? Object : FeatureFlagsService
|
|
51
|
-
])
|
|
52
|
-
], FeatureFlagGuard);
|