Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fb198e7
Initial formatting
hans-lizihan Nov 13, 2025
bc94992
Initial formatting + linting
hans-lizihan Nov 13, 2025
32ce172
Github actions
hans-lizihan Nov 13, 2025
fce257e
no-var
hans-lizihan Nov 13, 2025
2fdf905
Merged conflicts
hans-lizihan Nov 14, 2025
d1ea57b
Correct export
hans-lizihan Nov 14, 2025
bdeaa59
Fixed
hans-lizihan Nov 14, 2025
064f4af
extract var for test values
joshua-koehler Nov 14, 2025
29b2d3b
mark old runtime rules as legacy
joshua-koehler Nov 14, 2025
fbde335
succint flag setup to one line
joshua-koehler Nov 14, 2025
76d8393
DRY tests with helper - more succint
joshua-koehler Nov 14, 2025
89fea7f
DRY context creation for runtime
joshua-koehler Nov 14, 2025
a8033d4
use random string for clarity on wrong values
joshua-koehler Nov 14, 2025
748324f
DRY fallback
joshua-koehler Nov 14, 2025
43b344f
runtime rule negative case ❌
joshua-koehler Nov 14, 2025
9c31468
add stopgap positive test case (doesn't fail)
joshua-koehler Nov 14, 2025
1278be3
import jsonLogic and evaluate runtime rule ✅
joshua-koehler Nov 14, 2025
c095d50
caseinsensitive to parameters
joshua-koehler Nov 14, 2025
08cd7db
case-insensitivity ✅
joshua-koehler Nov 14, 2025
0c9ffcf
add complex rule test-cases ✅
joshua-koehler Nov 14, 2025
6706908
consistent runtime rule test names
joshua-koehler Nov 14, 2025
6fd7958
add error handling for garbled jsonlogic
joshua-koehler Nov 17, 2025
558b2d9
add multi-condition case-insensitive check
joshua-koehler Nov 17, 2025
6d17f73
Merge branch 'master' of github.com:mixpanel/mixpanel-node into runti…
joshua-koehler Nov 17, 2025
c6b4031
pretty
joshua-koehler Nov 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions lib/flags/local_flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
* */

const FeatureFlagsProvider = require("./flags");
const { normalizedHash } = require("./utils");
const {
normalizedHash,
lowercaseAllKeysAndValues,
lowercaseLeafNodes,
} = require("./utils");
const { apply } = require("json-logic-js");

class LocalFeatureFlagsProvider extends FeatureFlagsProvider {
/**
Expand Down Expand Up @@ -316,13 +321,39 @@ class LocalFeatureFlagsProvider extends FeatureFlagsProvider {
};
}

_extractRuntimeParameters(context) {
const customProperties = context.custom_properties;
if (!customProperties || typeof customProperties !== "object") {
return null;
}
return lowercaseAllKeysAndValues(customProperties);
}

_isRuntimeRuleSatisfied(rollout, context) {
try {
return apply(
lowercaseLeafNodes(rollout.runtime_evaluation_rule),
this._extractRuntimeParameters(context),
);
} catch (error) {
this.logger?.error(`Error evaluating runtime rule: ${error.message}`);
return false;
}
}

_isRuntimeEvaluationSatisfied(rollout, context) {
if (!rollout.runtime_evaluation_definition) {
if (rollout.runtime_evaluation_rule) {
return this._isRuntimeRuleSatisfied(rollout, context);
} else if (rollout.runtime_evaluation_definition) {
return this._isLegacyRuntimeEvaluationSatisfied(rollout, context);
} else {
return true;
}
}

const customProperties = context.custom_properties;
if (!customProperties || typeof customProperties !== "object") {
_isLegacyRuntimeEvaluationSatisfied(rollout, context) {
const customProperties = this._extractRuntimeParameters(context);
if (!customProperties) {
return false;
}

Expand Down
41 changes: 41 additions & 0 deletions lib/flags/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,51 @@ function generateTraceparent() {
return `${version}-${traceId}-${parentId}-${traceFlags}`;
}

function lowercaseAllKeysAndValues(obj) {
if (obj === null || obj === undefined) {
return obj;
} else if (typeof obj === "string") {
return obj.toLowerCase();
} else if (typeof obj === "object") {
if (Array.isArray(obj)) {
return obj.map(lowercaseAllKeysAndValues);
} else {
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [
k.toLowerCase(),
lowercaseAllKeysAndValues(v),
]),
);
}
} else {
return obj;
}
}

function lowercaseLeafNodes(obj) {
if (obj === null || obj === undefined) {
return obj;
} else if (typeof obj === "string") {
return obj.toLowerCase();
} else if (typeof obj === "object") {
if (Array.isArray(obj)) {
return obj.map(lowercaseLeafNodes);
} else {
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, lowercaseLeafNodes(v)]),
);
}
} else {
return obj;
}
}

module.exports = {
EXPOSURE_EVENT,
REQUEST_HEADERS,
normalizedHash,
prepareCommonQueryParams,
generateTraceparent,
lowercaseAllKeysAndValues,
lowercaseLeafNodes,
};
14 changes: 13 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"vitest": "^4.0.8"
},
"dependencies": {
"https-proxy-agent": "7.0.6"
"https-proxy-agent": "7.0.6",
"json-logic-js": "^2.0.5"
}
}
Loading
Loading