-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathanalytics.requireFeatureFlag.js
More file actions
58 lines (50 loc) · 1.97 KB
/
Copy pathanalytics.requireFeatureFlag.js
File metadata and controls
58 lines (50 loc) · 1.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* Module dependencies
*/
import FeatureFlagsService from '../services/analytics.featureFlags.service.js';
import responses from '../../../lib/helpers/responses.js';
/**
* Returns Express middleware that gates access based on a PostHog feature flag.
*
* The middleware evaluates the flag for the authenticated user, passing
* organisation context when available. Behaviour by scenario:
*
* - Flag enabled -> next()
* - Flag disabled -> 403
* - Analytics not configured (no PostHog key) -> next() (fail-open so
* projects not using PostHog are never blocked)
*
* @param {string} flagName - PostHog feature flag key
* @returns {Function} Express middleware function
*/
function requireFeatureFlag(flagName) {
return async function requireFeatureFlagMiddleware(req, res, next) {
const distinctId = req.user?._id ? String(req.user._id) : undefined;
if (!distinctId) {
return responses.error(res, 401, 'Unauthorized', 'Authentication required to evaluate feature flag')();
}
try {
const options = {};
if (req.organization?._id) {
options.groups = { company: String(req.organization._id) };
}
const enabled = await FeatureFlagsService.isEnabled(flagName, distinctId, options);
// isEnabled returns false both when the flag is off AND when analytics
// is not configured. Distinguish by checking getVariant: undefined
// means not configured (fail-open), while false/string means configured.
if (!enabled) {
const variant = await FeatureFlagsService.getVariant(flagName, distinctId, options);
// undefined -> analytics not configured -> fail-open
if (variant === undefined) return next();
return responses.error(res, 403, 'Forbidden', 'Feature not available on your current plan')({
type: 'FEATURE_FLAG_DISABLED',
flag: flagName,
});
}
return next();
} catch (err) {
return next(err);
}
};
}
export default requireFeatureFlag;