@datadog/openfeature-node-server 0.1.0-preview.10
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/README.md +3 -0
- package/cjs/configuration/evaluateForSubject.d.ts +7 -0
- package/cjs/configuration/evaluateForSubject.d.ts.map +1 -0
- package/cjs/configuration/evaluateForSubject.js +159 -0
- package/cjs/configuration/evaluateForSubject.js.map +1 -0
- package/cjs/configuration/evaluation.d.ts +5 -0
- package/cjs/configuration/evaluation.d.ts.map +1 -0
- package/cjs/configuration/evaluation.js +40 -0
- package/cjs/configuration/evaluation.js.map +1 -0
- package/cjs/configuration/ufc-v1.d.ts +53 -0
- package/cjs/configuration/ufc-v1.d.ts.map +1 -0
- package/cjs/configuration/ufc-v1.js +19 -0
- package/cjs/configuration/ufc-v1.js.map +1 -0
- package/cjs/index.d.ts +3 -0
- package/cjs/index.d.ts.map +1 -0
- package/cjs/index.js +20 -0
- package/cjs/index.js.map +1 -0
- package/cjs/provider.d.ts +52 -0
- package/cjs/provider.d.ts.map +1 -0
- package/cjs/provider.js +128 -0
- package/cjs/provider.js.map +1 -0
- package/cjs/rules/rules.d.ts +51 -0
- package/cjs/rules/rules.d.ts.map +1 -0
- package/cjs/rules/rules.js +71 -0
- package/cjs/rules/rules.js.map +1 -0
- package/cjs/shards/matchesShard.d.ts +4 -0
- package/cjs/shards/matchesShard.d.ts.map +1 -0
- package/cjs/shards/matchesShard.js +16 -0
- package/cjs/shards/matchesShard.js.map +1 -0
- package/cjs/shards/sharders.d.ts +12 -0
- package/cjs/shards/sharders.d.ts.map +1 -0
- package/cjs/shards/sharders.js +30 -0
- package/cjs/shards/sharders.js.map +1 -0
- package/esm/configuration/evaluateForSubject.d.ts +7 -0
- package/esm/configuration/evaluateForSubject.d.ts.map +1 -0
- package/esm/configuration/evaluateForSubject.js +155 -0
- package/esm/configuration/evaluateForSubject.js.map +1 -0
- package/esm/configuration/evaluation.d.ts +5 -0
- package/esm/configuration/evaluation.d.ts.map +1 -0
- package/esm/configuration/evaluation.js +37 -0
- package/esm/configuration/evaluation.js.map +1 -0
- package/esm/configuration/ufc-v1.d.ts +53 -0
- package/esm/configuration/ufc-v1.d.ts.map +1 -0
- package/esm/configuration/ufc-v1.js +16 -0
- package/esm/configuration/ufc-v1.js.map +1 -0
- package/esm/index.d.ts +3 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +4 -0
- package/esm/index.js.map +1 -0
- package/esm/provider.d.ts +52 -0
- package/esm/provider.d.ts.map +1 -0
- package/esm/provider.js +124 -0
- package/esm/provider.js.map +1 -0
- package/esm/rules/rules.d.ts +51 -0
- package/esm/rules/rules.d.ts.map +1 -0
- package/esm/rules/rules.js +67 -0
- package/esm/rules/rules.js.map +1 -0
- package/esm/shards/matchesShard.d.ts +4 -0
- package/esm/shards/matchesShard.d.ts.map +1 -0
- package/esm/shards/matchesShard.js +13 -0
- package/esm/shards/matchesShard.js.map +1 -0
- package/esm/shards/sharders.d.ts +12 -0
- package/esm/shards/sharders.d.ts.map +1 -0
- package/esm/shards/sharders.js +24 -0
- package/esm/shards/sharders.js.map +1 -0
- package/package.json +55 -0
package/esm/provider.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createExposureEvent, LRUInMemoryAssignmentCache, } from '@datadog/flagging-core';
|
|
2
|
+
import { OpenFeatureEventEmitter, ProviderEvents } from '@openfeature/server-sdk';
|
|
3
|
+
import { evaluate } from './configuration/evaluation';
|
|
4
|
+
export class DatadogNodeServerProvider {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.options = options;
|
|
7
|
+
this.metadata = {
|
|
8
|
+
name: 'datadog-node-server',
|
|
9
|
+
};
|
|
10
|
+
this.runsOn = 'server';
|
|
11
|
+
this.hooks = [];
|
|
12
|
+
this.events = new OpenFeatureEventEmitter();
|
|
13
|
+
this.exposureCache = new LRUInMemoryAssignmentCache(50000);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Used by dd-source-js
|
|
17
|
+
*/
|
|
18
|
+
getConfiguration() {
|
|
19
|
+
return this.configuration;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Used by dd-source-js
|
|
23
|
+
*/
|
|
24
|
+
setConfiguration(configuration) {
|
|
25
|
+
var _a, _b;
|
|
26
|
+
const prevCreatedAt = (_a = this.configuration) === null || _a === void 0 ? void 0 : _a.createdAt;
|
|
27
|
+
if (this.configuration && this.configuration !== configuration) {
|
|
28
|
+
this.events.emit(ProviderEvents.ConfigurationChanged);
|
|
29
|
+
const newCreatedAt = configuration === null || configuration === void 0 ? void 0 : configuration.createdAt;
|
|
30
|
+
if (prevCreatedAt !== newCreatedAt) {
|
|
31
|
+
(_b = this.exposureCache) === null || _b === void 0 ? void 0 : _b.clear();
|
|
32
|
+
}
|
|
33
|
+
this.configuration = configuration;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.configuration = configuration;
|
|
37
|
+
if (this.resolveInitialization) {
|
|
38
|
+
this.resolveInitialization();
|
|
39
|
+
this.resolveInitialization = undefined;
|
|
40
|
+
this.rejectInitialization = undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Used by dd-source-js
|
|
45
|
+
*/
|
|
46
|
+
setError(error) {
|
|
47
|
+
if (this.rejectInitialization) {
|
|
48
|
+
this.rejectInitialization(error);
|
|
49
|
+
this.resolveInitialization = undefined;
|
|
50
|
+
this.rejectInitialization = undefined;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.events.emit(ProviderEvents.Error, { error });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Used by the OpenFeature SDK to set the status based on initialization.
|
|
58
|
+
* Status of 'PROVIDER_READY' is emitted with a resolved promise.
|
|
59
|
+
* Status of 'PROVIDER_ERROR' is emitted with a rejected promise.
|
|
60
|
+
*
|
|
61
|
+
* Since we aren't loading the configuration in this Provider, we will simulate
|
|
62
|
+
* loading functionality via resolveInitialization and rejectInitialization.
|
|
63
|
+
* See setConfiguration and setError for more details.
|
|
64
|
+
*/
|
|
65
|
+
async initialize() {
|
|
66
|
+
var _a;
|
|
67
|
+
if (this.configuration) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
await new Promise((resolve, reject) => {
|
|
71
|
+
this.resolveInitialization = resolve;
|
|
72
|
+
this.rejectInitialization = reject;
|
|
73
|
+
});
|
|
74
|
+
await ((_a = this.exposureCache) === null || _a === void 0 ? void 0 : _a.init());
|
|
75
|
+
}
|
|
76
|
+
async resolveBooleanEvaluation(flagKey, defaultValue, context, _logger) {
|
|
77
|
+
const resolutionDetails = evaluate(this.configuration, 'boolean', flagKey, defaultValue, context, _logger);
|
|
78
|
+
this.handleExposure(flagKey, context, resolutionDetails);
|
|
79
|
+
return resolutionDetails;
|
|
80
|
+
}
|
|
81
|
+
async resolveStringEvaluation(flagKey, defaultValue, context, _logger) {
|
|
82
|
+
const resolutionDetails = evaluate(this.configuration, 'string', flagKey, defaultValue, context, _logger);
|
|
83
|
+
this.handleExposure(flagKey, context, resolutionDetails);
|
|
84
|
+
return resolutionDetails;
|
|
85
|
+
}
|
|
86
|
+
async resolveNumberEvaluation(flagKey, defaultValue, context, _logger) {
|
|
87
|
+
const resolutionDetails = evaluate(this.configuration, 'number', flagKey, defaultValue, context, _logger);
|
|
88
|
+
this.handleExposure(flagKey, context, resolutionDetails);
|
|
89
|
+
return resolutionDetails;
|
|
90
|
+
}
|
|
91
|
+
async resolveObjectEvaluation(flagKey, defaultValue, context, _logger) {
|
|
92
|
+
// type safety: OpenFeature interface requires us to return a
|
|
93
|
+
// specific T for *any* value of T (which could be any subtype of
|
|
94
|
+
// JsonValue). We can't even theoretically implement it in a
|
|
95
|
+
// type-sound way because there's no runtime information passed to
|
|
96
|
+
// learn what type the user expects. So it's up to the user to
|
|
97
|
+
// make sure they pass the appropriate type.
|
|
98
|
+
const resolutionDetails = evaluate(this.configuration, 'object', flagKey, defaultValue, context, _logger);
|
|
99
|
+
this.handleExposure(flagKey, context, resolutionDetails);
|
|
100
|
+
return resolutionDetails;
|
|
101
|
+
}
|
|
102
|
+
handleExposure(flagKey, context, resolutionDetails) {
|
|
103
|
+
var _a, _b, _c;
|
|
104
|
+
const timestamp = Date.now();
|
|
105
|
+
const evalutationDetails = {
|
|
106
|
+
...resolutionDetails,
|
|
107
|
+
flagKey: flagKey,
|
|
108
|
+
flagMetadata: (_a = resolutionDetails.flagMetadata) !== null && _a !== void 0 ? _a : {},
|
|
109
|
+
};
|
|
110
|
+
const exposureEvent = createExposureEvent(context, evalutationDetails);
|
|
111
|
+
if (!exposureEvent) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const hasLoggedAssignment = (_b = this.exposureCache) === null || _b === void 0 ? void 0 : _b.has(exposureEvent);
|
|
115
|
+
if (hasLoggedAssignment) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (this.options.exposureChannel.hasSubscribers) {
|
|
119
|
+
this.options.exposureChannel.publish({ ...exposureEvent, timestamp });
|
|
120
|
+
(_c = this.exposureCache) === null || _c === void 0 ? void 0 : _c.set(exposureEvent);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { EvaluationContext, EvaluationContextValue } from '@openfeature/server-sdk';
|
|
2
|
+
export type ConditionValueType = EvaluationContextValue | EvaluationContextValue[];
|
|
3
|
+
export declare enum OperatorType {
|
|
4
|
+
MATCHES = "MATCHES",
|
|
5
|
+
NOT_MATCHES = "NOT_MATCHES",
|
|
6
|
+
GTE = "GTE",
|
|
7
|
+
GT = "GT",
|
|
8
|
+
LTE = "LTE",
|
|
9
|
+
LT = "LT",
|
|
10
|
+
ONE_OF = "ONE_OF",
|
|
11
|
+
NOT_ONE_OF = "NOT_ONE_OF",
|
|
12
|
+
IS_NULL = "IS_NULL"
|
|
13
|
+
}
|
|
14
|
+
type NumericOperator = OperatorType.GTE | OperatorType.GT | OperatorType.LTE | OperatorType.LT;
|
|
15
|
+
type MatchesCondition = {
|
|
16
|
+
operator: OperatorType.MATCHES;
|
|
17
|
+
attribute: string;
|
|
18
|
+
value: string;
|
|
19
|
+
};
|
|
20
|
+
type NotMatchesCondition = {
|
|
21
|
+
operator: OperatorType.NOT_MATCHES;
|
|
22
|
+
attribute: string;
|
|
23
|
+
value: string;
|
|
24
|
+
};
|
|
25
|
+
type OneOfCondition = {
|
|
26
|
+
operator: OperatorType.ONE_OF;
|
|
27
|
+
attribute: string;
|
|
28
|
+
value: string[];
|
|
29
|
+
};
|
|
30
|
+
type NotOneOfCondition = {
|
|
31
|
+
operator: OperatorType.NOT_ONE_OF;
|
|
32
|
+
attribute: string;
|
|
33
|
+
value: string[];
|
|
34
|
+
};
|
|
35
|
+
type NumericCondition = {
|
|
36
|
+
operator: NumericOperator;
|
|
37
|
+
attribute: string;
|
|
38
|
+
value: number;
|
|
39
|
+
};
|
|
40
|
+
type NullCondition = {
|
|
41
|
+
operator: OperatorType.IS_NULL;
|
|
42
|
+
attribute: string;
|
|
43
|
+
value: boolean;
|
|
44
|
+
};
|
|
45
|
+
export type Condition = MatchesCondition | NotMatchesCondition | OneOfCondition | NotOneOfCondition | NumericCondition | NullCondition;
|
|
46
|
+
export interface Rule {
|
|
47
|
+
conditions: Condition[];
|
|
48
|
+
}
|
|
49
|
+
export declare function matchesRule(rule: Rule, subjectAttributes: EvaluationContext): boolean;
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/rules/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAExF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG,sBAAsB,EAAE,CAAA;AAElF,oBAAY,YAAY;IACtB,OAAO,YAAY;IACnB,WAAW,gBAAgB;IAC3B,GAAG,QAAQ;IACX,EAAE,OAAO;IACT,GAAG,QAAQ;IACX,EAAE,OAAO;IACT,MAAM,WAAW;IACjB,UAAU,eAAe;IACzB,OAAO,YAAY;CACpB;AAED,KAAK,eAAe,GAAG,YAAY,CAAC,GAAG,GAAG,YAAY,CAAC,EAAE,GAAG,YAAY,CAAC,GAAG,GAAG,YAAY,CAAC,EAAE,CAAA;AAE9F,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,YAAY,CAAC,OAAO,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,YAAY,CAAC,WAAW,CAAA;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,QAAQ,EAAE,YAAY,CAAC,MAAM,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAA;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB,CAAA;AAED,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,YAAY,CAAC,OAAO,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,MAAM,SAAS,GACjB,gBAAgB,GAChB,mBAAmB,GACnB,cAAc,GACd,iBAAiB,GACjB,gBAAgB,GAChB,aAAa,CAAA;AAEjB,MAAM,WAAW,IAAI;IACnB,UAAU,EAAE,SAAS,EAAE,CAAA;CACxB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,OAAO,CAIrF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export var OperatorType;
|
|
2
|
+
(function (OperatorType) {
|
|
3
|
+
OperatorType["MATCHES"] = "MATCHES";
|
|
4
|
+
OperatorType["NOT_MATCHES"] = "NOT_MATCHES";
|
|
5
|
+
OperatorType["GTE"] = "GTE";
|
|
6
|
+
OperatorType["GT"] = "GT";
|
|
7
|
+
OperatorType["LTE"] = "LTE";
|
|
8
|
+
OperatorType["LT"] = "LT";
|
|
9
|
+
OperatorType["ONE_OF"] = "ONE_OF";
|
|
10
|
+
OperatorType["NOT_ONE_OF"] = "NOT_ONE_OF";
|
|
11
|
+
OperatorType["IS_NULL"] = "IS_NULL";
|
|
12
|
+
})(OperatorType || (OperatorType = {}));
|
|
13
|
+
export function matchesRule(rule, subjectAttributes) {
|
|
14
|
+
const conditionEvaluations = evaluateRuleConditions(subjectAttributes, rule.conditions);
|
|
15
|
+
// TODO: short-circuit return when false condition is found
|
|
16
|
+
return !conditionEvaluations.includes(false);
|
|
17
|
+
}
|
|
18
|
+
function evaluateRuleConditions(subjectAttributes, conditions) {
|
|
19
|
+
return conditions.map((condition) => evaluateCondition(subjectAttributes, condition));
|
|
20
|
+
}
|
|
21
|
+
function evaluateCondition(subjectAttributes, condition) {
|
|
22
|
+
const value = subjectAttributes[condition.attribute];
|
|
23
|
+
if (condition.operator === OperatorType.IS_NULL) {
|
|
24
|
+
if (condition.value) {
|
|
25
|
+
return value === null || value === undefined;
|
|
26
|
+
}
|
|
27
|
+
return value !== null && value !== undefined;
|
|
28
|
+
}
|
|
29
|
+
if (value !== null && value !== undefined) {
|
|
30
|
+
switch (condition.operator) {
|
|
31
|
+
case OperatorType.GTE:
|
|
32
|
+
case OperatorType.GT:
|
|
33
|
+
case OperatorType.LTE:
|
|
34
|
+
case OperatorType.LT: {
|
|
35
|
+
const comparator = (a, b) => condition.operator === OperatorType.GTE
|
|
36
|
+
? a >= b
|
|
37
|
+
: condition.operator === OperatorType.GT
|
|
38
|
+
? a > b
|
|
39
|
+
: condition.operator === OperatorType.LTE
|
|
40
|
+
? a <= b
|
|
41
|
+
: a < b;
|
|
42
|
+
return compareNumber(value, condition.value, comparator);
|
|
43
|
+
}
|
|
44
|
+
case OperatorType.MATCHES:
|
|
45
|
+
// ReDoS mitigation should happen on user input to avoid event loop saturation (https://datadoghq.atlassian.net/browse/FFL-1060)
|
|
46
|
+
return new RegExp(condition.value).test(String(value)); // dd-iac-scan ignore-line
|
|
47
|
+
case OperatorType.NOT_MATCHES:
|
|
48
|
+
// ReDoS mitigation should happen on user input to avoid event loop saturation (https://datadoghq.atlassian.net/browse/FFL-1060)
|
|
49
|
+
return !new RegExp(condition.value).test(String(value)); // dd-iac-scan ignore-line
|
|
50
|
+
case OperatorType.ONE_OF:
|
|
51
|
+
return isOneOf(value.toString(), condition.value);
|
|
52
|
+
case OperatorType.NOT_ONE_OF:
|
|
53
|
+
return isNotOneOf(value.toString(), condition.value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
function isOneOf(attributeValue, conditionValues) {
|
|
59
|
+
return conditionValues.includes(attributeValue);
|
|
60
|
+
}
|
|
61
|
+
function isNotOneOf(attributeValue, conditionValues) {
|
|
62
|
+
return !isOneOf(attributeValue, conditionValues);
|
|
63
|
+
}
|
|
64
|
+
function compareNumber(attributeValue, conditionValue, compareFn) {
|
|
65
|
+
return compareFn(Number(attributeValue), Number(conditionValue));
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/rules/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchesShard.d.ts","sourceRoot":"","sources":["../../src/shards/matchesShard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAc,MAAM,yBAAyB,CAAA;AAChE,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,YAAY,CAAA;AAErD,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,OAAO,GAAG,OAAO,CAI/F"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MD5Sharder } from './sharders';
|
|
2
|
+
export function matchesShard(shard, subjectKey, customSharder) {
|
|
3
|
+
const sharder = customSharder !== null && customSharder !== void 0 ? customSharder : new MD5Sharder();
|
|
4
|
+
const assignedShard = sharder.getShard(hashKey(shard.salt, subjectKey), shard.totalShards);
|
|
5
|
+
return shard.ranges.some((range) => isInShardRange(assignedShard, range));
|
|
6
|
+
}
|
|
7
|
+
function isInShardRange(shard, range) {
|
|
8
|
+
return range.start <= shard && shard < range.end;
|
|
9
|
+
}
|
|
10
|
+
function hashKey(salt, subjectKey) {
|
|
11
|
+
return `${salt}-${subjectKey}`;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=matchesShard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchesShard.js","sourceRoot":"","sources":["../../src/shards/matchesShard.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAgB,MAAM,YAAY,CAAA;AAErD,MAAM,UAAU,YAAY,CAAC,KAAY,EAAE,UAAkB,EAAE,aAAuB;IACpF,MAAM,OAAO,GAAG,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,IAAI,UAAU,EAAE,CAAA;IACjD,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,CAAA;IAC1F,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAA;AAC3E,CAAC;AAED,SAAS,cAAc,CAAC,KAAa,EAAE,KAAiB;IACtD,OAAO,KAAK,CAAC,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,GAAG,CAAA;AAClD,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,UAAkB;IAC/C,OAAO,GAAG,IAAI,IAAI,UAAU,EAAE,CAAA;AAChC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare abstract class Sharder {
|
|
2
|
+
abstract getShard(input: string, totalShards: number): number;
|
|
3
|
+
}
|
|
4
|
+
export declare class MD5Sharder extends Sharder {
|
|
5
|
+
getShard(input: string, totalShards: number): number;
|
|
6
|
+
}
|
|
7
|
+
export declare class DeterministicSharder extends Sharder {
|
|
8
|
+
private lookup;
|
|
9
|
+
constructor(lookup: Record<string, number>);
|
|
10
|
+
getShard(input: string, _totalShards: number): number;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=sharders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sharders.d.ts","sourceRoot":"","sources":["../../src/shards/sharders.ts"],"names":[],"mappings":"AAEA,8BAAsB,OAAO;IAC3B,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;CAC9D;AAED,qBAAa,UAAW,SAAQ,OAAO;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;CAOrD;AAED,qBAAa,oBAAqB,SAAQ,OAAO;IAK/C,OAAO,CAAC,MAAM,CAAwB;gBAE1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAM1C,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;CAGtD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getMD5Hash } from '@datadog/flagging-core';
|
|
2
|
+
export class Sharder {
|
|
3
|
+
}
|
|
4
|
+
export class MD5Sharder extends Sharder {
|
|
5
|
+
getShard(input, totalShards) {
|
|
6
|
+
const hashOutput = getMD5Hash(input);
|
|
7
|
+
// get the first 4 bytes of the md5 hex string and parse it using base 16
|
|
8
|
+
// (8 hex characters represent 4 bytes, e.g. 0xffffffff represents the max 4-byte integer)
|
|
9
|
+
const intFromHash = parseInt(hashOutput.slice(0, 8), 16);
|
|
10
|
+
return intFromHash % totalShards;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class DeterministicSharder extends Sharder {
|
|
14
|
+
constructor(lookup) {
|
|
15
|
+
super();
|
|
16
|
+
this.lookup = lookup;
|
|
17
|
+
}
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
19
|
+
getShard(input, _totalShards) {
|
|
20
|
+
var _a;
|
|
21
|
+
return (_a = this.lookup[input]) !== null && _a !== void 0 ? _a : 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=sharders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sharders.js","sourceRoot":"","sources":["../../src/shards/sharders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAEnD,MAAM,OAAgB,OAAO;CAE5B;AAED,MAAM,OAAO,UAAW,SAAQ,OAAO;IACrC,QAAQ,CAAC,KAAa,EAAE,WAAmB;QACzC,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;QACpC,yEAAyE;QACzE,0FAA0F;QAC1F,MAAM,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACxD,OAAO,WAAW,GAAG,WAAW,CAAA;IAClC,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,OAAO;IAO/C,YAAY,MAA8B;QACxC,KAAK,EAAE,CAAA;QACP,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAED,6DAA6D;IAC7D,QAAQ,CAAC,KAAa,EAAE,YAAoB;;QAC1C,OAAO,MAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAI,CAAC,CAAA;IAChC,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@datadog/openfeature-node-server",
|
|
3
|
+
"version": "0.1.0-preview.10",
|
|
4
|
+
"description": "React Native bindings for OpenFeature (wraps @datadog/flagging-core)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/DataDog/openfeature-js-client#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/DataDog/openfeature-js-client.git",
|
|
10
|
+
"directory": "packages/node-server"
|
|
11
|
+
},
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18.0.0"
|
|
14
|
+
},
|
|
15
|
+
"main": "cjs/index.js",
|
|
16
|
+
"module": "esm/index.js",
|
|
17
|
+
"types": "cjs/index.d.ts",
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"files": [
|
|
20
|
+
"cjs/",
|
|
21
|
+
"esm/",
|
|
22
|
+
"*.d.ts"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"prepack": "yarn build",
|
|
29
|
+
"pack": "yarn pack",
|
|
30
|
+
"build": "run-p build:cjs build:esm",
|
|
31
|
+
"build:cjs": "rm -rf cjs && tsc -p tsconfig.cjs.json && yarn replace-build-env cjs",
|
|
32
|
+
"build:esm": "rm -rf esm && tsc -p tsconfig.esm.json && yarn replace-build-env esm",
|
|
33
|
+
"replace-build-env": "node ../../scripts/build/replace-build-env.js",
|
|
34
|
+
"clean": "rm -rf dist cjs esm",
|
|
35
|
+
"test": "jest --passWithNoTests",
|
|
36
|
+
"typecheck": "tsc --noEmit"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@datadog/flagging-core": "0.1.0-preview.10",
|
|
40
|
+
"@openfeature/server-sdk": "~1.18.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@openfeature/server-sdk": "~1.18.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@openfeature/core": "^1.9.0",
|
|
47
|
+
"@types/jest": "^30.0.0",
|
|
48
|
+
"@types/node": "^18.0.0",
|
|
49
|
+
"jest": "^30.0.4",
|
|
50
|
+
"npm-run-all": "^4.1.5",
|
|
51
|
+
"ts-jest": "^29.4.0",
|
|
52
|
+
"ts-loader": "^9.5.2",
|
|
53
|
+
"typescript": "^5.5.0"
|
|
54
|
+
}
|
|
55
|
+
}
|