@application-kit/feature-flags 0.2.0 → 0.3.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 +12 -0
- package/README.md +12 -26
- package/dist/cjs/nest/feature-flags-root.module.d.ts +5 -0
- package/dist/cjs/nest/feature-flags-root.module.js +27 -0
- package/dist/cjs/nest/index.d.ts +1 -0
- package/dist/cjs/nest/index.js +17 -0
- package/dist/esm/nest/feature-flags-root.module.d.ts +5 -0
- package/dist/esm/nest/feature-flags-root.module.js +24 -0
- package/dist/esm/nest/index.d.ts +1 -0
- package/dist/esm/nest/index.js +1 -0
- package/package.json +19 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @application-kit/feature-flags
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8e10f98: Peer-зависимости принимают Nest 12, `@nestjs/graphql` и `@nestjs/mercurius` 14, `@nestjs/cqrs` 12 и `nestjs-pino` 5. `PinoLoggerConfig` задаёт `forRoutes` явно: с маршрутом nestjs-pino 5 по умолчанию запросы на Fastify не логировались.
|
|
8
|
+
|
|
9
|
+
## 0.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 1032c06: Вход `/nest`: `FeatureFlagsRootModule.forRoot(featureFlags)` разбирает окружение и глобально отдаёт порт `FEATURE_FLAGS`. Класс окружения и конфиг-адаптер в приложении больше не нужны; отказы на неверном `FEATURE_*` прежние. Новый необязательный peer `@nestjs/common` — только для этого входа.
|
|
14
|
+
|
|
3
15
|
## 0.2.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -18,18 +18,18 @@ yarn add @application-kit/feature-flags @libs-for-dev/nestjs-config-module
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Peer: `@libs-for-dev/nestjs-config-module` (подпуть `/parse-boolean` — разбор булевых переменных, без
|
|
21
|
-
зависимостей); `vue` — только для входа `/vue`.
|
|
21
|
+
зависимостей); `vue` — только для входа `/vue`, `@nestjs/common` — только для входа `/nest`.
|
|
22
22
|
|
|
23
23
|
## Входы
|
|
24
24
|
|
|
25
25
|
| Вход | Что внутри | Зависимости |
|
|
26
26
|
|---|---|---|
|
|
27
27
|
| `@application-kit/feature-flags` | `defineFeatureFlags`, реестр `FeatureFlagRegistryInterface`, порт `FeatureFlagsInterface`, токен `FEATURE_FLAGS`, адаптер `EnvironmentFeatureFlags`, ошибки | изоморфно, без Nest и DOM |
|
|
28
|
+
| `@application-kit/feature-flags/nest` | `FeatureFlagsRootModule` | `@nestjs/common` |
|
|
28
29
|
| `@application-kit/feature-flags/vue` | `useFeatureFlag`, ключ `FEATURE_FLAG_STATE`, `parseFeatureFlagState`, `createFeatureFlagChannel` | `vue` |
|
|
29
30
|
| `@application-kit/feature-flags/testing` | `FakeFeatureFlags` | — |
|
|
30
31
|
|
|
31
|
-
Корень грузится и в клиентском бандле (набор нужен разбору SSR-состояния), поэтому
|
|
32
|
-
класс окружения и регистрацию адаптера под токеном делает приложение (пример ниже).
|
|
32
|
+
Корень грузится и в клиентском бандле (набор нужен разбору SSR-состояния), поэтому связка с Nest — отдельный вход.
|
|
33
33
|
|
|
34
34
|
## Набор флагов
|
|
35
35
|
|
|
@@ -75,35 +75,21 @@ export const featureFlags = defineFeatureFlags({
|
|
|
75
75
|
проверки собирают полный список до броска, чтобы отказ назвал все проблемы разом; незнакомая переменная
|
|
76
76
|
проверяется первой — опечатка даёт сразу и лишнее имя, и недостающее.
|
|
77
77
|
|
|
78
|
-
### Связка с Nest
|
|
78
|
+
### Связка с Nest
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
Корневой модуль процесса подключает порт одной строкой:
|
|
81
81
|
|
|
82
82
|
```ts
|
|
83
|
-
import {
|
|
83
|
+
import { FeatureFlagsRootModule } from '@application-kit/feature-flags/nest'
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@IsObject()
|
|
88
|
-
public FEATURE_FLAGS: FeatureFlagState
|
|
89
|
-
|
|
90
|
-
// Конфиг-модуль конструирует класс без аргументов: переменных столько, сколько флагов, и объявлять их
|
|
91
|
-
// по одной `@Expose()` значило бы держать вторую копию набора.
|
|
92
|
-
public constructor(source: Record<string, unknown> = process.env) {
|
|
93
|
-
this.FEATURE_FLAGS = featureFlags.readEnvironment(source)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export class FeatureFlagsConfig extends EnvironmentFeatureFlags {
|
|
98
|
-
public constructor(@Inject(FeatureFlagsEnvironment) environment: FeatureFlagsEnvironment) {
|
|
99
|
-
super(featureFlags, environment.FEATURE_FLAGS)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// провайдер модуля
|
|
104
|
-
{ provide: FEATURE_FLAGS, useExisting: FeatureFlagsConfig }
|
|
85
|
+
@Module({ imports: [FeatureFlagsRootModule.forRoot(featureFlags)] })
|
|
86
|
+
export class CommonModule {}
|
|
105
87
|
```
|
|
106
88
|
|
|
89
|
+
`forRoot` разбирает `process.env` сразу, на импорте модуля-носителя: отказ приходит до сборки графа, а не на первом
|
|
90
|
+
запросе. Поэтому окружение обязано быть готово до импорта: правка из `beforeAll` спеки опоздает. Модуль глобальный:
|
|
91
|
+
`FEATURE_FLAGS` виден всему графу без своей регистрации.
|
|
92
|
+
|
|
107
93
|
## Чтение на сервере
|
|
108
94
|
|
|
109
95
|
Через порт по токену, а не чтением `process.env`:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.FeatureFlagsRootModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const constants_js_1 = require("../constants.js");
|
|
12
|
+
const environment_feature_flags_js_1 = require("../environment-feature-flags.js");
|
|
13
|
+
let FeatureFlagsRootModule = class FeatureFlagsRootModule {
|
|
14
|
+
static forRoot(featureFlags) {
|
|
15
|
+
const state = featureFlags.readEnvironment(process.env);
|
|
16
|
+
return {
|
|
17
|
+
exports: [constants_js_1.FEATURE_FLAGS],
|
|
18
|
+
global: true,
|
|
19
|
+
module: this,
|
|
20
|
+
providers: [{ provide: constants_js_1.FEATURE_FLAGS, useValue: new environment_feature_flags_js_1.EnvironmentFeatureFlags(featureFlags, state) }],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
exports.FeatureFlagsRootModule = FeatureFlagsRootModule;
|
|
25
|
+
exports.FeatureFlagsRootModule = FeatureFlagsRootModule = __decorate([
|
|
26
|
+
(0, common_1.Module)({})
|
|
27
|
+
], FeatureFlagsRootModule);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './feature-flags-root.module.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./feature-flags-root.module.js"), exports);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (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
|
+
import { Module } from '@nestjs/common';
|
|
8
|
+
import { FEATURE_FLAGS } from '../constants.js';
|
|
9
|
+
import { EnvironmentFeatureFlags } from '../environment-feature-flags.js';
|
|
10
|
+
let FeatureFlagsRootModule = class FeatureFlagsRootModule {
|
|
11
|
+
static forRoot(featureFlags) {
|
|
12
|
+
const state = featureFlags.readEnvironment(process.env);
|
|
13
|
+
return {
|
|
14
|
+
exports: [FEATURE_FLAGS],
|
|
15
|
+
global: true,
|
|
16
|
+
module: this,
|
|
17
|
+
providers: [{ provide: FEATURE_FLAGS, useValue: new EnvironmentFeatureFlags(featureFlags, state) }],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
FeatureFlagsRootModule = __decorate([
|
|
22
|
+
Module({})
|
|
23
|
+
], FeatureFlagsRootModule);
|
|
24
|
+
export { FeatureFlagsRootModule };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './feature-flags-root.module.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './feature-flags-root.module.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@application-kit/feature-flags",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Фичефлаги из окружения: набор флагов параметром, порт с адаптером окружения, SSR-состояние для Vue и фейк для спек",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"feature-flags",
|
|
@@ -32,6 +32,16 @@
|
|
|
32
32
|
"default": "./dist/cjs/index.js"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
|
+
"./nest": {
|
|
36
|
+
"import": {
|
|
37
|
+
"types": "./dist/esm/nest/index.d.ts",
|
|
38
|
+
"default": "./dist/esm/nest/index.js"
|
|
39
|
+
},
|
|
40
|
+
"require": {
|
|
41
|
+
"types": "./dist/cjs/nest/index.d.ts",
|
|
42
|
+
"default": "./dist/cjs/nest/index.js"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
35
45
|
"./package.json": "./package.json",
|
|
36
46
|
"./testing": {
|
|
37
47
|
"import": {
|
|
@@ -61,26 +71,32 @@
|
|
|
61
71
|
"dist"
|
|
62
72
|
],
|
|
63
73
|
"scripts": {
|
|
64
|
-
"build": "rm -rf ./dist && node ../../scripts/barrels.mjs create ./src --entry-only=testing,vue && tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json && node ../../scripts/barrels.mjs clean ./src && node ../../scripts/mark-cjs.mjs ./dist/cjs",
|
|
74
|
+
"build": "rm -rf ./dist && node ../../scripts/barrels.mjs create ./src --entry-only=nest,testing,vue && tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json && node ../../scripts/barrels.mjs clean ./src && node ../../scripts/mark-cjs.mjs ./dist/cjs",
|
|
65
75
|
"lint:tsc": "tsc --noEmit --pretty --project .",
|
|
66
76
|
"test:mutation": "stryker run",
|
|
67
77
|
"test:unit": "vitest run"
|
|
68
78
|
},
|
|
69
79
|
"devDependencies": {
|
|
70
80
|
"@libs-for-dev/nestjs-config-module": "3.0.0",
|
|
81
|
+
"@nestjs/common": "^12.0.0",
|
|
82
|
+
"@nestjs/testing": "^12.0.0",
|
|
71
83
|
"@stryker-mutator/core": "^10.0.0",
|
|
72
84
|
"@stryker-mutator/vitest-runner": "^10.0.0",
|
|
73
85
|
"@types/node": "^26.2.0",
|
|
74
86
|
"jsdom": "^30.0.1",
|
|
75
87
|
"typescript": "^6.0.3",
|
|
76
|
-
"vitest": "^
|
|
88
|
+
"vitest": "^5.0.0",
|
|
77
89
|
"vue": "^3.5.41"
|
|
78
90
|
},
|
|
79
91
|
"peerDependencies": {
|
|
80
92
|
"@libs-for-dev/nestjs-config-module": "^3.0.0",
|
|
93
|
+
"@nestjs/common": "^11.0.0 || ^12.0.0",
|
|
81
94
|
"vue": "^3.5.0"
|
|
82
95
|
},
|
|
83
96
|
"peerDependenciesMeta": {
|
|
97
|
+
"@nestjs/common": {
|
|
98
|
+
"optional": true
|
|
99
|
+
},
|
|
84
100
|
"vue": {
|
|
85
101
|
"optional": true
|
|
86
102
|
}
|