@brandtg/flapjack 1.1.0 → 1.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.
- package/dist/model.d.ts +75 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +139 -27
- package/package.json +1 -1
package/dist/model.d.ts
CHANGED
|
@@ -89,6 +89,19 @@ export declare class FeatureFlagModel {
|
|
|
89
89
|
* ```
|
|
90
90
|
*/
|
|
91
91
|
getByName(name: string): Promise<FeatureFlag | null>;
|
|
92
|
+
/**
|
|
93
|
+
* Retrieves multiple feature flags by their names.
|
|
94
|
+
*
|
|
95
|
+
* @param names - Array of feature flag names to retrieve
|
|
96
|
+
* @returns Array of feature flags found (may be shorter than input if some names don't exist)
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const flags = await model.getManyByName(["feature1", "feature2", "feature3"]);
|
|
101
|
+
* console.log(`Found ${flags.length} flags`);
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
getManyByName(names: string[]): Promise<FeatureFlag[]>;
|
|
92
105
|
/**
|
|
93
106
|
* Retrieves multiple feature flags by their IDs.
|
|
94
107
|
*
|
|
@@ -161,6 +174,15 @@ export declare class FeatureFlagModel {
|
|
|
161
174
|
* Checks if a user belongs to any of the specified groups
|
|
162
175
|
*/
|
|
163
176
|
private isActiveForGroups;
|
|
177
|
+
/**
|
|
178
|
+
* Evaluates a feature flag for a user based on flag configuration.
|
|
179
|
+
* This is a stateless helper that performs the actual flag evaluation logic.
|
|
180
|
+
*/
|
|
181
|
+
evaluateFlagForUser(flag: FeatureFlag, { user, roles, groups, }: {
|
|
182
|
+
user?: string;
|
|
183
|
+
roles?: string[];
|
|
184
|
+
groups?: string[];
|
|
185
|
+
}): Promise<boolean>;
|
|
164
186
|
/**
|
|
165
187
|
* Computes the hash value for a user ID using MurmurHash3.
|
|
166
188
|
*
|
|
@@ -223,6 +245,59 @@ export declare class FeatureFlagModel {
|
|
|
223
245
|
roles?: string[];
|
|
224
246
|
groups?: string[];
|
|
225
247
|
}): Promise<boolean>;
|
|
248
|
+
/**
|
|
249
|
+
* Checks if multiple feature flags are active for a user based on configured rules.
|
|
250
|
+
*
|
|
251
|
+
* @param params - Parameters for flag evaluation
|
|
252
|
+
* @param params.names - Optional array of feature flag names to check. If not provided, checks all flags.
|
|
253
|
+
* @param params.user - Optional user ID
|
|
254
|
+
* @param params.roles - Optional list of roles the user has
|
|
255
|
+
* @param params.groups - Optional list of groups the user belongs to
|
|
256
|
+
* @returns Record mapping flag names to their active status (true/false)
|
|
257
|
+
*
|
|
258
|
+
* @remarks
|
|
259
|
+
* This method fetches all flags in a single query for efficiency.
|
|
260
|
+
* If names is provided, only those flags are checked. Non-existent flags are marked as false.
|
|
261
|
+
* If names is not provided, all flags in the database are checked.
|
|
262
|
+
* Evaluation order for each flag (first match wins):
|
|
263
|
+
* 1. Everyone override (if set to true/false, returns immediately)
|
|
264
|
+
* 2. User ID is in the users list
|
|
265
|
+
* 3. User belongs to any group in the groups list
|
|
266
|
+
* 4. User has any role in the roles list
|
|
267
|
+
* 5. User falls within the percentage rollout (based on consistent hashing)
|
|
268
|
+
* 6. Default: returns false
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* // Check specific flags
|
|
273
|
+
* const results = await model.areActiveForUser({
|
|
274
|
+
* names: ["feature1", "feature2", "feature3"],
|
|
275
|
+
* user: "user_123",
|
|
276
|
+
* roles: ["admin"],
|
|
277
|
+
* groups: ["beta_testers"],
|
|
278
|
+
* });
|
|
279
|
+
*
|
|
280
|
+
* // Check all flags
|
|
281
|
+
* const allResults = await model.areActiveForUser({
|
|
282
|
+
* user: "user_123",
|
|
283
|
+
* roles: ["admin"],
|
|
284
|
+
* groups: ["beta_testers"],
|
|
285
|
+
* });
|
|
286
|
+
*
|
|
287
|
+
* if (results["feature1"]) {
|
|
288
|
+
* // Show feature1
|
|
289
|
+
* }
|
|
290
|
+
* if (results["feature2"]) {
|
|
291
|
+
* // Show feature2
|
|
292
|
+
* }
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
areActiveForUser({ names, user, roles, groups, }: {
|
|
296
|
+
names?: string[];
|
|
297
|
+
user?: string;
|
|
298
|
+
roles?: string[];
|
|
299
|
+
groups?: string[];
|
|
300
|
+
}): Promise<Record<string, boolean>>;
|
|
226
301
|
}
|
|
227
302
|
type CreateGroupInput = Omit<FeatureFlagGroup, "id" | "created" | "modified">;
|
|
228
303
|
type UpdateGroupChanges = Partial<Omit<FeatureFlagGroup, "id" | "created" | "modified">>;
|
package/dist/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,wBAAwB,EACxB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AAItC,UAAU,SAAS;IACjB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CAC/D;AAkBD,KAAK,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,SAAS,GAAG,UAAU,CAAC,CAAC;AACpE,KAAK,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC;AA0B/E;;;;;;;;;;;GAWG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,EAAE,CAAY;IACtB,OAAO,CAAC,aAAa,CAAC,CAA2B;IAEjD;;;;;;;;;;;OAWG;gBACS,EAAE,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,wBAAwB;IAKnE;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAuCtD;;;;;;;;;;;;;OAaG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAOtD;;;;;;;;;;;;;OAaG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAO1D;;;;;;;;;;;OAWG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAQpD;;;;;;;;;;;;;OAaG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAMpC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAiD9B;;;;;;;;;;;;;OAaG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1C;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;;;;;;;;;;;;;;;;OAkBG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACG,eAAe,CAAC,EACpB,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,MAAM,GACP,EAAE;QACD,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB,GAAG,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
package/dist/model.js
CHANGED
|
@@ -166,6 +166,25 @@ export class FeatureFlagModel {
|
|
|
166
166
|
return null;
|
|
167
167
|
return mapRow(res.rows[0]);
|
|
168
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Retrieves multiple feature flags by their names.
|
|
171
|
+
*
|
|
172
|
+
* @param names - Array of feature flag names to retrieve
|
|
173
|
+
* @returns Array of feature flags found (may be shorter than input if some names don't exist)
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* const flags = await model.getManyByName(["feature1", "feature2", "feature3"]);
|
|
178
|
+
* console.log(`Found ${flags.length} flags`);
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
async getManyByName(names) {
|
|
182
|
+
if (names.length === 0)
|
|
183
|
+
return [];
|
|
184
|
+
const sql = `SELECT ${COLUMNS.join(", ")} FROM ${TABLE} WHERE name = ANY($1)`;
|
|
185
|
+
const res = await this.db.query(sql, [names]);
|
|
186
|
+
return res.rows.map(mapRow);
|
|
187
|
+
}
|
|
169
188
|
/**
|
|
170
189
|
* Retrieves multiple feature flags by their IDs.
|
|
171
190
|
*
|
|
@@ -300,6 +319,42 @@ export class FeatureFlagModel {
|
|
|
300
319
|
return false;
|
|
301
320
|
return flagGroups.some((group) => userGroups.includes(group));
|
|
302
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* Evaluates a feature flag for a user based on flag configuration.
|
|
324
|
+
* This is a stateless helper that performs the actual flag evaluation logic.
|
|
325
|
+
*/
|
|
326
|
+
async evaluateFlagForUser(flag, { user, roles, groups, }) {
|
|
327
|
+
// Everyone Override: If everyone is true or false, return that value immediately
|
|
328
|
+
if (flag.everyone !== undefined && flag.everyone !== null) {
|
|
329
|
+
return flag.everyone;
|
|
330
|
+
}
|
|
331
|
+
// User-Specific Check: If user ID is in the users array, return true
|
|
332
|
+
if (user && flag.users && flag.users.includes(user)) {
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
// Group Check: If any of the user's groups match any group in the groups array, return true
|
|
336
|
+
if (groups && this.isActiveForGroups(groups, flag.groups)) {
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
// Role Check: If any of the user's roles match any role in the roles array, return true
|
|
340
|
+
if (flag.roles && roles) {
|
|
341
|
+
for (const role of roles) {
|
|
342
|
+
if (flag.roles.includes(role)) {
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// Percentage Check: If percentage rollout applies to this user, return rollout result
|
|
348
|
+
if (user && flag.percent && flag.percent > 0) {
|
|
349
|
+
const userHash = await this.hashUserId(user);
|
|
350
|
+
const bucket = userHash % 100;
|
|
351
|
+
if (bucket < flag.percent) {
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Default: Return false
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
303
358
|
/**
|
|
304
359
|
* Computes the hash value for a user ID using MurmurHash3.
|
|
305
360
|
*
|
|
@@ -374,36 +429,93 @@ export class FeatureFlagModel {
|
|
|
374
429
|
return expiredResult;
|
|
375
430
|
}
|
|
376
431
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
432
|
+
return this.evaluateFlagForUser(flag, { user, roles, groups });
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Checks if multiple feature flags are active for a user based on configured rules.
|
|
436
|
+
*
|
|
437
|
+
* @param params - Parameters for flag evaluation
|
|
438
|
+
* @param params.names - Optional array of feature flag names to check. If not provided, checks all flags.
|
|
439
|
+
* @param params.user - Optional user ID
|
|
440
|
+
* @param params.roles - Optional list of roles the user has
|
|
441
|
+
* @param params.groups - Optional list of groups the user belongs to
|
|
442
|
+
* @returns Record mapping flag names to their active status (true/false)
|
|
443
|
+
*
|
|
444
|
+
* @remarks
|
|
445
|
+
* This method fetches all flags in a single query for efficiency.
|
|
446
|
+
* If names is provided, only those flags are checked. Non-existent flags are marked as false.
|
|
447
|
+
* If names is not provided, all flags in the database are checked.
|
|
448
|
+
* Evaluation order for each flag (first match wins):
|
|
449
|
+
* 1. Everyone override (if set to true/false, returns immediately)
|
|
450
|
+
* 2. User ID is in the users list
|
|
451
|
+
* 3. User belongs to any group in the groups list
|
|
452
|
+
* 4. User has any role in the roles list
|
|
453
|
+
* 5. User falls within the percentage rollout (based on consistent hashing)
|
|
454
|
+
* 6. Default: returns false
|
|
455
|
+
*
|
|
456
|
+
* @example
|
|
457
|
+
* ```typescript
|
|
458
|
+
* // Check specific flags
|
|
459
|
+
* const results = await model.areActiveForUser({
|
|
460
|
+
* names: ["feature1", "feature2", "feature3"],
|
|
461
|
+
* user: "user_123",
|
|
462
|
+
* roles: ["admin"],
|
|
463
|
+
* groups: ["beta_testers"],
|
|
464
|
+
* });
|
|
465
|
+
*
|
|
466
|
+
* // Check all flags
|
|
467
|
+
* const allResults = await model.areActiveForUser({
|
|
468
|
+
* user: "user_123",
|
|
469
|
+
* roles: ["admin"],
|
|
470
|
+
* groups: ["beta_testers"],
|
|
471
|
+
* });
|
|
472
|
+
*
|
|
473
|
+
* if (results["feature1"]) {
|
|
474
|
+
* // Show feature1
|
|
475
|
+
* }
|
|
476
|
+
* if (results["feature2"]) {
|
|
477
|
+
* // Show feature2
|
|
478
|
+
* }
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
async areActiveForUser({ names, user, roles, groups, }) {
|
|
482
|
+
let flags;
|
|
483
|
+
let requestedNames;
|
|
484
|
+
if (names === undefined) {
|
|
485
|
+
// If no names provided, get all flags
|
|
486
|
+
flags = await this.list();
|
|
487
|
+
requestedNames = flags.map((flag) => flag.name);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
// If names provided, fetch only those flags
|
|
491
|
+
flags = await this.getManyByName(names);
|
|
492
|
+
requestedNames = names;
|
|
493
|
+
}
|
|
494
|
+
const flagMap = new Map(flags.map((flag) => [flag.name, flag]));
|
|
495
|
+
const result = {};
|
|
496
|
+
for (const name of requestedNames) {
|
|
497
|
+
const flag = flagMap.get(name);
|
|
498
|
+
if (!flag) {
|
|
499
|
+
result[name] = false;
|
|
500
|
+
continue;
|
|
395
501
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
502
|
+
// If the flag has expired, trigger event
|
|
503
|
+
if (this.eventHandlers?.onExpired &&
|
|
504
|
+
flag.expires &&
|
|
505
|
+
flag.expires <= new Date()) {
|
|
506
|
+
const expiredResult = await this.eventHandlers.onExpired({ flag });
|
|
507
|
+
if (expiredResult !== undefined) {
|
|
508
|
+
result[name] = expiredResult;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
403
511
|
}
|
|
512
|
+
result[name] = await this.evaluateFlagForUser(flag, {
|
|
513
|
+
user,
|
|
514
|
+
roles,
|
|
515
|
+
groups,
|
|
516
|
+
});
|
|
404
517
|
}
|
|
405
|
-
|
|
406
|
-
return false;
|
|
518
|
+
return result;
|
|
407
519
|
}
|
|
408
520
|
}
|
|
409
521
|
const GROUP_TABLE = "flapjack.feature_flag_group";
|