@terreno/feature-flags 57.0.0 → 57.1.0
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/dist/featureFlagModel.d.ts +0 -17
- package/dist/featureFlagModel.js +11 -1
- package/dist/featureFlagsApp.d.ts +2 -1
- package/dist/featureFlagsApp.js +18 -0
- package/package.json +4 -3
- package/src/featureFlagModel.ts +16 -1
- package/src/featureFlagsApp.ts +20 -0
- package/src/tests/featureFlagsApp.test.ts +12 -0
|
@@ -1,22 +1,5 @@
|
|
|
1
1
|
import type { FeatureFlagModel } from "./types";
|
|
2
2
|
export declare const FeatureFlag: FeatureFlagModel;
|
|
3
|
-
/**
|
|
4
|
-
* Pre-configured admin model config for the FeatureFlag model.
|
|
5
|
-
*
|
|
6
|
-
* Pass this directly to `AdminApp({ models: [...] })` so downstream consumers
|
|
7
|
-
* don't have to manually configure displayName, listFields, and routePath.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* import {featureFlagAdminConfig} from "@terreno/feature-flags";
|
|
12
|
-
* import {AdminApp} from "@terreno/admin-backend";
|
|
13
|
-
*
|
|
14
|
-
* new TerrenoApp({userModel: User})
|
|
15
|
-
* .register(new FeatureFlagsApp({segments}))
|
|
16
|
-
* .register(new AdminApp({models: [featureFlagAdminConfig]}))
|
|
17
|
-
* .start();
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
3
|
export declare const featureFlagAdminConfig: {
|
|
21
4
|
displayName: string;
|
|
22
5
|
listFields: string[];
|
package/dist/featureFlagModel.js
CHANGED
|
@@ -171,9 +171,19 @@ exports.FeatureFlag = mongoose_1.default.model("FeatureFlag", featureFlagSchema)
|
|
|
171
171
|
* .start();
|
|
172
172
|
* ```
|
|
173
173
|
*/
|
|
174
|
-
|
|
174
|
+
var featureFlagAdminConfigValue = {
|
|
175
175
|
displayName: "Feature Flags",
|
|
176
176
|
listFields: ["key", "name", "type", "enabled", "archived", "defaultVariant", "created"],
|
|
177
177
|
model: exports.FeatureFlag,
|
|
178
178
|
routePath: "/feature-flags",
|
|
179
179
|
};
|
|
180
|
+
var warnedLegacyAdminConfigs = new WeakSet();
|
|
181
|
+
exports.featureFlagAdminConfig = new Proxy(featureFlagAdminConfigValue, {
|
|
182
|
+
get: function (target, property, receiver) {
|
|
183
|
+
if (!warnedLegacyAdminConfigs.has(target)) {
|
|
184
|
+
warnedLegacyAdminConfigs.add(target);
|
|
185
|
+
api_1.logger.warn("[feature-flags] featureFlagAdminConfig is deprecated. Use new FeatureFlagsApp() and register it with TerrenoApp — see docs/how-to/admin-import-prebuilt.md");
|
|
186
|
+
}
|
|
187
|
+
return Reflect.get(target, property, receiver);
|
|
188
|
+
},
|
|
189
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type TerrenoPlugin } from "@terreno/api";
|
|
1
|
+
import { type AdminContribution, type TerrenoPlugin } from "@terreno/api";
|
|
2
2
|
import type express from "express";
|
|
3
3
|
import type { FeatureFlagsOptions } from "./types";
|
|
4
4
|
/**
|
|
@@ -24,5 +24,6 @@ export declare class FeatureFlagsApp implements TerrenoPlugin {
|
|
|
24
24
|
private segments;
|
|
25
25
|
private mongoProvider?;
|
|
26
26
|
constructor(options?: FeatureFlagsOptions);
|
|
27
|
+
adminContribution(): AdminContribution;
|
|
27
28
|
register(app: express.Application, openApi?: unknown): void;
|
|
28
29
|
}
|
package/dist/featureFlagsApp.js
CHANGED
|
@@ -101,6 +101,24 @@ var FeatureFlagsApp = /** @class */ (function () {
|
|
|
101
101
|
this.options = options !== null && options !== void 0 ? options : {};
|
|
102
102
|
this.segments = (_a = this.options.segments) !== null && _a !== void 0 ? _a : {};
|
|
103
103
|
}
|
|
104
|
+
FeatureFlagsApp.prototype.adminContribution = function () {
|
|
105
|
+
return {
|
|
106
|
+
homeWidgets: [{ displayName: "Flag Overrides", icon: "flag", id: "feature-flags-overrides" }],
|
|
107
|
+
models: [
|
|
108
|
+
{
|
|
109
|
+
admin: {
|
|
110
|
+
defaultSort: "-created",
|
|
111
|
+
displayName: "Feature Flags",
|
|
112
|
+
listFields: ["key", "name", "type", "enabled", "archived", "defaultVariant", "created"],
|
|
113
|
+
searchFields: ["key", "name"],
|
|
114
|
+
sortableFields: ["key", "name", "type", "enabled", "archived", "created"],
|
|
115
|
+
},
|
|
116
|
+
model: featureFlagModel_1.FeatureFlag,
|
|
117
|
+
routePath: "/feature-flags",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
};
|
|
104
122
|
FeatureFlagsApp.prototype.register = function (app, openApi) {
|
|
105
123
|
var _this = this;
|
|
106
124
|
var _a, _b, _c, _d;
|
package/package.json
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@openfeature/server-sdk": "^1.22.0",
|
|
8
|
-
"@terreno/api": "57.
|
|
8
|
+
"@terreno/api": "57.1.0",
|
|
9
9
|
"express": "^5.2.1",
|
|
10
10
|
"lodash": "^4.18.1"
|
|
11
11
|
},
|
|
12
12
|
"description": "Feature flags and A/B testing plugin for @terreno/api",
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@biomejs/biome": "^2.3.6",
|
|
15
|
-
"@terreno/test": "57.
|
|
15
|
+
"@terreno/test": "57.1.0",
|
|
16
16
|
"@types/bun": "^1.3.8",
|
|
17
17
|
"@types/express": "^5.0.6",
|
|
18
18
|
"@types/lodash": "^4.17.17",
|
|
@@ -49,9 +49,10 @@
|
|
|
49
49
|
"lint": "biome check ./src",
|
|
50
50
|
"lint:fix": "biome check --write ./src",
|
|
51
51
|
"test": "bun test",
|
|
52
|
+
"test:agent": "AGENT=1 bun test --only-failures",
|
|
52
53
|
"test:ci": "bun test",
|
|
53
54
|
"test:coverage": "bun run ../scripts/check-coverage.ts"
|
|
54
55
|
},
|
|
55
56
|
"types": "dist/index.d.ts",
|
|
56
|
-
"version": "57.
|
|
57
|
+
"version": "57.1.0"
|
|
57
58
|
}
|
package/src/featureFlagModel.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
findExactlyOne,
|
|
5
5
|
findOneOrNone,
|
|
6
6
|
isDeletedPlugin,
|
|
7
|
+
logger,
|
|
7
8
|
} from "@terreno/api";
|
|
8
9
|
import mongoose from "mongoose";
|
|
9
10
|
import type {FeatureFlagDocument, FeatureFlagModel} from "./types";
|
|
@@ -193,9 +194,23 @@ export const FeatureFlag = mongoose.model<FeatureFlagDocument, FeatureFlagModel>
|
|
|
193
194
|
* .start();
|
|
194
195
|
* ```
|
|
195
196
|
*/
|
|
196
|
-
|
|
197
|
+
const featureFlagAdminConfigValue = {
|
|
197
198
|
displayName: "Feature Flags",
|
|
198
199
|
listFields: ["key", "name", "type", "enabled", "archived", "defaultVariant", "created"],
|
|
199
200
|
model: FeatureFlag,
|
|
200
201
|
routePath: "/feature-flags",
|
|
201
202
|
};
|
|
203
|
+
|
|
204
|
+
const warnedLegacyAdminConfigs = new WeakSet<object>();
|
|
205
|
+
|
|
206
|
+
export const featureFlagAdminConfig = new Proxy(featureFlagAdminConfigValue, {
|
|
207
|
+
get(target, property, receiver) {
|
|
208
|
+
if (!warnedLegacyAdminConfigs.has(target)) {
|
|
209
|
+
warnedLegacyAdminConfigs.add(target);
|
|
210
|
+
logger.warn(
|
|
211
|
+
"[feature-flags] featureFlagAdminConfig is deprecated. Use new FeatureFlagsApp() and register it with TerrenoApp — see docs/how-to/admin-import-prebuilt.md"
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return Reflect.get(target, property, receiver);
|
|
215
|
+
},
|
|
216
|
+
});
|
package/src/featureFlagsApp.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {OpenFeature} from "@openfeature/server-sdk";
|
|
2
2
|
import {
|
|
3
|
+
type AdminContribution,
|
|
3
4
|
APIError,
|
|
4
5
|
asyncHandler,
|
|
5
6
|
authenticateMiddleware,
|
|
@@ -66,6 +67,25 @@ export class FeatureFlagsApp implements TerrenoPlugin {
|
|
|
66
67
|
this.segments = this.options.segments ?? {};
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
adminContribution(): AdminContribution {
|
|
71
|
+
return {
|
|
72
|
+
homeWidgets: [{displayName: "Flag Overrides", icon: "flag", id: "feature-flags-overrides"}],
|
|
73
|
+
models: [
|
|
74
|
+
{
|
|
75
|
+
admin: {
|
|
76
|
+
defaultSort: "-created",
|
|
77
|
+
displayName: "Feature Flags",
|
|
78
|
+
listFields: ["key", "name", "type", "enabled", "archived", "defaultVariant", "created"],
|
|
79
|
+
searchFields: ["key", "name"],
|
|
80
|
+
sortableFields: ["key", "name", "type", "enabled", "archived", "created"],
|
|
81
|
+
},
|
|
82
|
+
model: FeatureFlag as Model<FeatureFlagDocument>,
|
|
83
|
+
routePath: "/feature-flags",
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
69
89
|
register(app: express.Application, openApi?: unknown): void {
|
|
70
90
|
const basePath = this.options.basePath ?? "/feature-flags";
|
|
71
91
|
const openFeatureDomain = this.options.openFeatureDomain ?? "feature-flags";
|
|
@@ -48,6 +48,18 @@ describe("FeatureFlagsApp", () => {
|
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
describe("construction", () => {
|
|
51
|
+
it("contributes FeatureFlag admin metadata and the overrides home widget", () => {
|
|
52
|
+
const contribution = new FeatureFlagsApp().adminContribution();
|
|
53
|
+
|
|
54
|
+
expect(contribution.models).toHaveLength(1);
|
|
55
|
+
expect(contribution.models?.[0]?.model).toBe(FeatureFlag);
|
|
56
|
+
expect(contribution.models?.[0]?.routePath).toBe("/feature-flags");
|
|
57
|
+
expect(contribution.models?.[0]?.admin.displayName).toBe("Feature Flags");
|
|
58
|
+
expect(contribution.homeWidgets).toEqual([
|
|
59
|
+
{displayName: "Flag Overrides", icon: "flag", id: "feature-flags-overrides"},
|
|
60
|
+
]);
|
|
61
|
+
});
|
|
62
|
+
|
|
51
63
|
it("defaults basePath to /feature-flags and segments to an empty object", async () => {
|
|
52
64
|
app = buildApp();
|
|
53
65
|
adminAgent = await authAsUser(app, "admin");
|