@terreno/feature-flags 57.0.0 → 57.2.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.
@@ -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[];
@@ -171,9 +171,19 @@ exports.FeatureFlag = mongoose_1.default.model("FeatureFlag", featureFlagSchema)
171
171
  * .start();
172
172
  * ```
173
173
  */
174
- exports.featureFlagAdminConfig = {
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
  }
@@ -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,15 +5,15 @@
5
5
  },
6
6
  "dependencies": {
7
7
  "@openfeature/server-sdk": "^1.22.0",
8
- "@terreno/api": "57.0.0",
8
+ "@terreno/api": "57.2.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.0.0",
16
- "@types/bun": "^1.3.8",
15
+ "@terreno/test": "57.2.0",
16
+ "@types/bun": "^1.4.0",
17
17
  "@types/express": "^5.0.6",
18
18
  "@types/lodash": "^4.17.17",
19
19
  "@types/supertest": "^7.2.0",
@@ -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.0.0"
57
+ "version": "57.2.0"
57
58
  }
@@ -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
- export const featureFlagAdminConfig = {
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
+ });
@@ -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");